After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 634987 - add a switch widget
add a switch widget
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: Other
2.91.x
Other All
: Normal enhancement
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2010-11-16 15:23 UTC by William Jon McCann
Modified: 2010-11-29 13:03 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Add GtkSwitch, a "light-switch" like widget (28.45 KB, patch)
2010-11-27 17:40 UTC, Emmanuele Bassi (:ebassi)
reviewed Details | Review
Add GtkSwitch, a "light-switch" like widget / v2 (30.21 KB, patch)
2010-11-27 19:06 UTC, Emmanuele Bassi (:ebassi)
none Details | Review
Add GtkSwitch, a "light-switch" like widget / v3 (28.72 KB, patch)
2010-11-27 19:18 UTC, Emmanuele Bassi (:ebassi)
none Details | Review
Localized gtkSwitch mockups (18.15 KB, image/png)
2010-11-28 03:58 UTC, Vinicius Depizzol
  Details
updated gtkswitch.c (23.92 KB, text/plain)
2010-11-28 07:12 UTC, Matthias Clasen
  Details
localized GtkSwitch using MEDIUM CIRCLE (U+25CB) (5.58 KB, image/png)
2010-11-28 09:42 UTC, Emmanuele Bassi (:ebassi)
  Details
localized GtkSwitch using LARGE CIRCLE (U+25EF) (5.83 KB, image/png)
2010-11-28 09:43 UTC, Emmanuele Bassi (:ebassi)
  Details
Add GtkSwitch, a "light-switch" like widget / v4 (28.72 KB, patch)
2010-11-29 00:21 UTC, Emmanuele Bassi (:ebassi)
none Details | Review
switch: Add accessibility implementation (6.98 KB, patch)
2010-11-29 00:23 UTC, Emmanuele Bassi (:ebassi)
none Details | Review
Add GtkSwitch, a "light-switch" like widget / v5 (33.70 KB, patch)
2010-11-29 12:48 UTC, Emmanuele Bassi (:ebassi)
committed Details | Review
docs: Add GtkSwitch to the API reference (1.92 KB, patch)
2010-11-29 12:48 UTC, Emmanuele Bassi (:ebassi)
committed Details | Review
switch: Add accessibility implementation (6.98 KB, patch)
2010-11-29 12:49 UTC, Emmanuele Bassi (:ebassi)
committed Details | Review

Description William Jon McCann 2010-11-16 15:23:10 UTC
One pattern we encounter often when designing apps or OS System Settings is an on/off switch to control a feature or service.  A checkbutton is appropriate for boolean settings where a) it represents true or false b) there are no intermediate states between 1 and 0 c) the label text can easily communicate the unchecked state (or it is obvious).  These aren't true for options that start services.  Closer is an on/off radio button pair, however, this doesn't represent the intermediate state well either and it is somewhat visually awkward.

It might be nice to have a switch widget that can represent: on, off, changing.
Comment 1 Emmanuele Bassi (:ebassi) 2010-11-26 22:33:41 UTC
I'm currently implementing this widget, but whilst discussing on IRC, a new requirement popped up - asynchronous support for cancelling a toggle.

now, this requirement is a bit odd, considering that no other UI control currently exposed by gtk+ satisfies it. so I'd love to hear a proper specification for this widget - i.e. how do you define the "changing" state, and how should the switch react to a long running operation.

there's also the matter of defining the toggling interaction: clicking on the uncovered area makes sense for a desktop; there's also the dragging of the slider (with or without a threshold).

finally: animation. do we animate the transition between states?

ideally both the dragging and the animation can be added post-merge: they don't change the main interaction model, nor the API. the cancellability, if it is a requirement, might affect the API instead - so it would be good to have it defined, at least as a simple UX specification from which I can deduce the API.
Comment 2 Emmanuele Bassi (:ebassi) 2010-11-27 17:40:11 UTC
Created attachment 175365 [details] [review]
Add GtkSwitch, a "light-switch" like widget

This is an initial implementation of the "light switch" widget; it has both direct and dragged toggling for the state changes, plus some key handling (pressing Enter will toggle the current state). Graphically, it maps the mockup done by jimmac available here:

http://gitorious.org/gnome-design/gnome-design/blobs/master/mockups/theming/widget-factory.png

It's been a while since I implemented gtk+ widgets, so it might have some brain damage - I apologize for that.

It's lacking the animation between states, though it's not going to be much complicated to add.

I'm still unsure about the :active property - prior art (in the form of the UISwitch control in the UIKit for iOS) would say that the property should be called :on - but set_on() and get_on() are pretty lousy names for accessors, and we do have in gtk+ the concept of "active/inactive".

Reviews are most welcome.
Comment 3 Bastien Nocera 2010-11-27 18:39:20 UTC
Review of attachment 175365 [details] [review]:

Missing addition to docs section.

::: gtk/gtkswitch.c
@@ +231,3 @@
+  if (event->keyval == GDK_KEY_Return ||
+      event->keyval == GDK_KEY_KP_Enter ||
+      event->keyval == GDK_KEY_ISO_Enter)

Make space work as well?

@@ +257,3 @@
+   * the state
+   */
+  layout = gtk_widget_create_pango_layout (widget, _("ON"));

Add context?

@@ +265,3 @@
+   * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state
+   */
+  pango_layout_set_text (layout, _("OFF"), -1);

Here as well.

@@ +294,3 @@
+   * "off" states of the GtkSwitch
+   */
+  layout = gtk_widget_create_pango_layout (widget, _("ON OFF"));

context as well?
By the way, why can't we concatenate this ourselves instead of making translators do it?

@@ +408,3 @@
+  gboolean is_sensitive = gtk_widget_is_sensitive (widget);
+
+  gtk_paint_box (style, cr,

gtk_paint_slider instead? So that it gets the same "dimples" as on scrollbars, and as used in the mockup.

::: gtk/gtkswitch.h
@@ +30,3 @@
+{
+  /*< private >*/
+  GtkWidget parent_instance;

Any reasons why it's not a descendant of GtkToggleButton instead, just like GtkCheckButton?
Comment 4 Emmanuele Bassi (:ebassi) 2010-11-27 18:59:42 UTC
(In reply to comment #3)
> Review of attachment 175365 [details] [review]:
> 
> Missing addition to docs section.

the whole docs stuff is probably going to wait on the finalization of the API, to simplify the patch.

> ::: gtk/gtkswitch.c
> @@ +231,3 @@
> +  if (event->keyval == GDK_KEY_Return ||
> +      event->keyval == GDK_KEY_KP_Enter ||
> +      event->keyval == GDK_KEY_ISO_Enter)
> 
> Make space work as well?

good point.

> @@ +257,3 @@
> +   * the state
> +   */
> +  layout = gtk_widget_create_pango_layout (widget, _("ON"));
> 
> Add context?

fixed

> @@ +265,3 @@
> +   * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state
> +   */
> +  pango_layout_set_text (layout, _("OFF"), -1);
> 
> Here as well.

fixed

> @@ +294,3 @@
> +   * "off" states of the GtkSwitch
> +   */
> +  layout = gtk_widget_create_pango_layout (widget, _("ON OFF"));
> 
> context as well?
> By the way, why can't we concatenate this ourselves instead of making
> translators do it?

fixed

> @@ +408,3 @@
> +  gboolean is_sensitive = gtk_widget_is_sensitive (widget);
> +
> +  gtk_paint_box (style, cr,
> 
> gtk_paint_slider instead? So that it gets the same "dimples" as on scrollbars,
> and as used in the mockup.

ah, yes - good plan.

> ::: gtk/gtkswitch.h
> @@ +30,3 @@
> +{
> +  /*< private >*/
> +  GtkWidget parent_instance;
> 
> Any reasons why it's not a descendant of GtkToggleButton instead, just like
> GtkCheckButton?

a switch is not a button painted differently: you can click it - but the clicks are attached to a particular area of the widget. it also has a handle. in terms of user interaction a switch is more similar to a scrollbar - though not exactly. also, using Button as the super-class would give us all the API of a Button - including the ::clicked signal, which I don't think make sense on a switch.
Comment 5 Emmanuele Bassi (:ebassi) 2010-11-27 19:06:02 UTC
Created attachment 175371 [details] [review]
Add GtkSwitch, a "light-switch" like widget / v2

Fixes after Bastien's review.
Comment 6 Emmanuele Bassi (:ebassi) 2010-11-27 19:18:41 UTC
Created attachment 175375 [details] [review]
Add GtkSwitch, a "light-switch" like widget / v3

Forgot the space key handling, and cleaned up the test.
Comment 7 Vinicius Depizzol 2010-11-28 03:58:25 UTC
Created attachment 175400 [details]
Localized gtkSwitch mockups

Hello. I must say this is an excellent idea.

After looking in the source code for the way the widget works for localized versions, I tried to draw a test of the widget with this WHITE CIRCLE and MEDIUM VERTICAL BAR characters, and I found some issues.

The characters don't have the same height and the same line width. They are also usually not vertically centralized.

Instead of using unicode chars, maybe it can be a good idea to manually render the drawings for the line and circle.

Thank you.
Comment 8 Vinicius Depizzol 2010-11-28 04:04:48 UTC
Additionally, a comment could be added to the translators telling that if there are no translations with 3 or less chars for ON and OFF, they can keep the English version if the people which speaks the translated language are ok with it.

For instance, in [Brazilian] Portuguese there are the words "ligado" and "desligado" for on/off. However I'm sure it would be much better for Brazilians to have the words "ON" and "OFF" right in English than the I/O drawings.
Comment 9 Matthias Clasen 2010-11-28 07:11:38 UTC
Some initial impressions:

- Dragging the slider reveals a blank space and the text only pops in when I've dragged all the way over. We should always draw both labels

- The text should be rendered with a matching state, so that we get white-on-blue for selected, instead of black-on-blue

- There's one place where you still get the translations without context

- Since the widget is taking focus, it should show some focus indication

- Should implement GtkActivatable

I'll attach my modified gtkswitch.c, which implements these things.

Some more notes:

- Do we need a vertical variant ? Probably not...

- Animation should probably wait until we land gtk-style-context

- Is it really intuitive that clicking on the slider does nothing ?
Comment 10 Matthias Clasen 2010-11-28 07:12:21 UTC
Created attachment 175401 [details]
updated gtkswitch.c
Comment 11 Emmanuele Bassi (:ebassi) 2010-11-28 09:22:59 UTC
(In reply to comment #9)
> Some initial impressions:
> 
> - Dragging the slider reveals a blank space and the text only pops in when I've
> dragged all the way over. We should always draw both labels

my rationale for drawing only the "target" label was to avoid confusion, and to save a gtk_paint_layout(); I have no strong feelings about this, though.
 
> Some more notes:
> 
> - Do we need a vertical variant ? Probably not...

I tend to agree.

> - Is it really intuitive that clicking on the slider does nothing ?

my initial version had the toggling on the whole area of the switch; after playing with it a bit more, it felt a bit odd in the case when you press-leave.
Comment 12 Emmanuele Bassi (:ebassi) 2010-11-28 09:41:22 UTC
(In reply to comment #7)
> After looking in the source code for the way the widget works for localized
> versions, I tried to draw a test of the widget with this WHITE CIRCLE and
> MEDIUM VERTICAL BAR characters, and I found some issues.
> 
> The characters don't have the same height and the same line width. They are
> also usually not vertically centralized.

we paint the glyphs separately, so we can center them.

> Instead of using unicode chars, maybe it can be a good idea to manually render
> the drawings for the line and circle.

we cannot separate the cases: if text is left untranslated, we default back to "ON"/"OFF".
Comment 13 Emmanuele Bassi (:ebassi) 2010-11-28 09:42:49 UTC
Created attachment 175403 [details]
localized GtkSwitch using MEDIUM CIRCLE (U+25CB)
Comment 14 Emmanuele Bassi (:ebassi) 2010-11-28 09:43:20 UTC
Created attachment 175404 [details]
localized GtkSwitch using LARGE CIRCLE (U+25EF)
Comment 15 Matthias Clasen 2010-11-28 15:31:52 UTC
A certain risk is that the font might not have these characters. Does e.g. Cantarell have them ? One thing we could do is 

if (strcmp (C_"switch", "ON"), "\342\227\213") == 0)
  /* draw circle */

but of course, then we have the problem of making the drawing code match font characteristics (font size, font weight, etc).
Comment 16 Emmanuele Bassi (:ebassi) 2010-11-28 15:48:13 UTC
(In reply to comment #15)
> A certain risk is that the font might not have these characters. Does e.g.
> Cantarell have them ?

I think most fonts have them, but you're right: there is such risk.

> One thing we could do is 
> 
> if (strcmp (C_"switch", "ON"), "\342\227\213") == 0)
>   /* draw circle */
> 
> but of course, then we have the problem of making the drawing code match font
> characteristics (font size, font weight, etc).

I think MeeGo on netbooks, and looking at the MxToggle/MxGtkLightSwitch code, gave up on localization and just used ❙ and ○ in the background image for the widget.

what I think will happen is that every i18n team will either use the on/off or the single-glyph pair - even for CJK and other non-latin scripts.

the advantage of using a glyph is that we can effectively size the widget using the current font-size settings, and this would be an advantage in case of a11y themes with big fonts.
Comment 17 Matthias Clasen 2010-11-28 16:26:55 UTC
I agree. Lets just go with this for now, then. Should not block the merge, anyway.

One thing I had idly wondered about is whether we need a way to force a minimum height for the slider as well (eg for touchscreens)
Comment 18 Emmanuele Bassi (:ebassi) 2010-11-28 18:47:27 UTC
(In reply to comment #17)

> One thing I had idly wondered about is whether we need a way to force a minimum
> height for the slider as well (eg for touchscreens)

good point; right now there's an hardcoded minimum height, but I can easily add a style property - similar to the :slider-width one.
Comment 19 Matthias Clasen 2010-11-28 21:08:27 UTC
Final few things on my checklist:

- Flipping: do switches in RTL countries go the other way ? I don't know, so I guess we wait until someone tells us that our switches look wrong in Israel.

- A11y: I think we should just add the accessible object inside gtk. Can probably just copy GailToggleButton 1-1. I can look at that tonight, maybe
Comment 20 Emmanuele Bassi (:ebassi) 2010-11-29 00:21:03 UTC
Created attachment 175440 [details] [review]
Add GtkSwitch, a "light-switch" like widget / v4
Comment 21 Emmanuele Bassi (:ebassi) 2010-11-29 00:23:43 UTC
Created attachment 175441 [details] [review]
switch: Add accessibility implementation

Modelled on GailToggleButton.

Untested - I need to enable A11Y, but it's getting late so it'll have to wait until tomorrow :-)
Comment 22 Emmanuele Bassi (:ebassi) 2010-11-29 12:48:44 UTC
Created attachment 175459 [details] [review]
Add GtkSwitch, a "light-switch" like widget / v5

The initial patch with the changes from Matthias.
Comment 23 Emmanuele Bassi (:ebassi) 2010-11-29 12:48:54 UTC
Created attachment 175460 [details] [review]
docs: Add GtkSwitch to the API reference
Comment 24 Emmanuele Bassi (:ebassi) 2010-11-29 12:49:20 UTC
Created attachment 175461 [details] [review]
switch: Add accessibility implementation

Same as attachment 175441 [details] [review], but in order.
Comment 25 Emmanuele Bassi (:ebassi) 2010-11-29 13:02:43 UTC
Attachment 175460 [details] pushed to master
Attachment 175460 [details] pushed as 044040d - docs: Add GtkSwitch to the API reference
Attachment 175461 [details] pushed as ae95cdf - switch: Add accessibility implementation