Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add widgets to differentiate between Switch and Checkbox #2225

Open
freakboy3742 opened this issue Nov 13, 2023 · 4 comments
Open

Add widgets to differentiate between Switch and Checkbox #2225

freakboy3742 opened this issue Nov 13, 2023 · 4 comments
Labels
enhancement New features, or improvements to existing features.

Comments

@freakboy3742
Copy link
Member

freakboy3742 commented Nov 13, 2023

What is the problem or limitation you are having?

Many platforms have support for both a Switch and a Checkbox widget; however, Toga doesn't currently expose this capability.

Describe the solution you'd like

Two new widgets, plus a change to an existing one:

  • Modify toga.Switch to canonically be a Switch on every platform
  • Add toga.Checkbox, a widget that is explicitly a checkbox on every platform.
  • Add toga.Toggle, a widget that does what Switch currently does - follow UX guidelines on the preferred representation of boolean concepts (checkbox on desktop, toggle on mobile).

The API for Switch, Checkbox and Toggle should be identical. The core should use the existing Switch code as a base class; with 2 subclasses providing the different factory instantiation. The backends will only need to add 1 extra implementation (where available), with the factory redirecting Toggle to the Switch or Checkbox implementation as required.

The documentation should recommend the use of "Toggle".

Describe alternatives you've considered

Retain the status quo - a single Switch widget that follows UX convention.

Rename Switch to Toggle to break the coupling between the widget and the specific implementation.

Additional context

Current platform support:

  • macOS - NSSwitch / NSButton (with checkbox style)
  • GTK - Gtk.Switch / Gtk.CheckButton
  • Windows - No switch in Winforms, but UWP has ToggleSwitch; System.Windows.Forms.CheckBox
  • iOS - UISwitch / no checkbox control; but UISwitch has UISwitchStyleCheckbox, but only honours it under Catalyst.
  • Android - android.widget.Switch / android.widget.Checkbox

So - iOS and Windows are the only holdouts.

Examples of implementations for Switch for Windows and Checkbox on iOS exist; they are mostly "image button without extra chrome that changes image when pressed". While it is possible to fake it, Toga should adhere to platform guidelines, and omit those widget options. This will also serve to encourage the use of the "Toggle" widget.

The transition from Switch to Checkbox will require a backwards compatibility shim on Winforms to warn that toga.Switch will be removed in future.

Thanks to @Kuna42 for the suggestion (#2221)

@freakboy3742 freakboy3742 added the enhancement New features, or improvements to existing features. label Nov 13, 2023
@freakboy3742
Copy link
Member Author

Another idea that came out of a discussion with @mhsmith:

Toga's API has historically tried to present widgets that capture use cases, rather than specific widgets; to that end, instead of literally wrapping Checkbox and Switch and providing a design option to the user, we should find the use case that describes the difference between Checkboxes and Switches in practice.

The Android HIG provides a hint here - it provides both, saying:

  • Checkbox: use checkboxes (instead of switches or radio buttons) if multiple options can be selected from a list
  • Switch: Use switches (not radio buttons) if the items in a list can be independently controlled

This also highlights one of the big feature gaps in Toga - the lack of a RadioButton widget. However, the use case for Radio buttons is effectively the same as "a list of checkboxes".

The reading of the macOS HIG on toggles is broadly compatible with this interpretation.

So - there's effectively a need for 3 widgets in Toga:

  1. A widget for single boolean values. A switch on most platforms; but a checkbox on Windows, and arguably on macOS. This is what Switch is currently; there's an argument to be made it should be renamed "Toggle".
  2. A widget for multiple selections from (MultiSelection? MultipleOptionList?) - a list of checkboxes on all platforms except iOS (which doesn't support checkboxes). On iOS, it would be a list of switches.
  3. A widget for single selections from a fixed list (SingleSelection? SingleOptionList?) - generally a list of radio buttons, but on mobile more likely implemented as a selection pulldown.

The "Selection" name is already in use for selection of a single item from a dynamic list of items, so whatever name we pick for 2 and 3 should be conceptually consistent.

@mhsmith
Copy link
Member

mhsmith commented Nov 13, 2023

This is what Switch is currently; there's an argument to be made it should be renamed "Toggle".

I think Switch is clear enough; I don't remember seeing any of these elements referred to as a "toggle" except in the macOS HIG linked above.

A widget for multiple selections from (MultiSelection? MultipleOptionList?)

I like MultiSelection, because the API would be similar to Selection – maybe even identical, except that value would return a list.

A widget for single selections from a fixed list (SingleSelection? SingleOptionList?) - generally a list of radio buttons, but on mobile more likely implemented as a selection pulldown.

A list of radio buttons takes up much more space than a selection pulldown, which would make it difficult to use the same layout across all platforms. I see that Android has native radio buttons and iOS doesn't, but one alternative for iOS is a table view with a check mark.

As for the API, it would be identical to the existing Selection widget, so I wonder if we can just add it as a boolean constructor flag on that class.

In fact, we could merge both the checkbox-group and radio-group forms into the Selection API using a multiple_select flag similar to the Table.

@mhsmith
Copy link
Member

mhsmith commented Nov 13, 2023

Separately, we could always add a constructor argument to Switch to indicate a preference for one style over the other, without the need to create a whole separate class.

@freakboy3742
Copy link
Member Author

This is what Switch is currently; there's an argument to be made it should be renamed "Toggle".

I think Switch is clear enough; I don't remember seeing any of these elements referred to as a "toggle" except in the macOS HIG linked above.

Agreed that the name isn't one I've seen elsewhere, but that's kind of the point. Asking for a Switch and getting a checkbox is at least a little jarring. It's not a huge deal, and it comes at the cost of some code churn; but, we're also pre-1.0, so I'm OK with some code churn to avoid legacy issues we don't want to live with long term.

A widget for multiple selections from (MultiSelection? MultipleOptionList?)

I like MultiSelection, because the API would be similar to Selection – maybe even identical, except that value would return a list.

Agreed that most of the API should be the same, but I'd argue there's one critical difference between the current Selection and these new widgets: The data source must be static - you can't add/remove items to it over time. I guess this could be accomplished with a wrapper around ListSource that disables the list-mutating APIs.

I see that Android has native radio buttons and iOS doesn't, but one alternative for iOS is a table view with a check mark.

Good idea - I hadn't thought of that. It has the added advantage that the core of the implementation between single and multiple select will be similar.

As for the API, it would be identical to the existing Selection widget, so I wonder if we can just add it as a boolean constructor flag on that class.

In fact, we could merge both the checkbox-group and radio-group forms into the Selection API using a multiple_select flag similar to the Table.
...
Separately, we could always add a constructor argument to Switch to indicate a preference for one style over the other, without the need to create a whole separate class.

Agreed - although, if possible, I'd like to find a way to HIG-driven way to express this, rather than explicitly referring to the form of the widget. "Switch/Checkbox" describes a specific form; if it's something that describes function rather than form, then it's a little less jarring when a platform doesn't satisfy the specific form requested, and it allows us to better adhere to platform HIGs.

For example, the macOS HIG suggests you should "avoid using a switch to control a single detail or a minor setting". On that basis, we could use "role=major" to display a switch, "role=minor" to display a checkbox on macOS, with the default role being minor. The Android HIG says that you shouldn't use checkboxes for standalone options, so no matter the role, we would return Switch.

Of course, the risk is that we develop an unintuitive representation for something that end users end up using as a simple "switch/checkbox" option, and we flooded with Stack Overflow answers that say "set role=major to get a checkbox" (which is sort of true, but is an answer that misses the point) and "how do I get a checkbox" questions on Android, and we end up in a new class of "but I want an on_click handler on Image" discussions.

I guess the middle ground would be to allow both: role = default | minor | major | switch | checkbox which allows us to have a "do the right thing" default and role-based hint, while also allowing a "if you insist, you can steamroll the HIG" option to avoid the interminable support queries. We can do our best to educate why you shouldn't use the literal switch/checkbox options in documentation, and we can raise warnings if you ask for a specific widget on a platform where that widget doesn't exist - maybe even raising an error, giving us an opportunity to point at docs that give a long form description of why forcing the style is a bad idea.


To summarise, this is now the desired end-state:

  • Switch (possibly renamed to Toggle) - for a single boolean option. We add a constructor option to control whether it is a "Switch / Checkbox / Platform Default" (possibly in a role-based way). We could also use this as an opportunity to complete the ValueSource API.
  • Selection - current pull-down widget. Has a read-write data source, single selection only.
  • OptionList / OptionGroup / OptionTable / FixedSelection / StaticSelection (final name tbd) - a "list of options" widget. Data source is read only, there's a multiple_select option in the constructor (matching Table), which controls whether the widget uses radio buttons or checkboxes (or whatever presentation is platform recommended)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

2 participants