RFC: Toga API for style-related operations
See original GitHub issueThis is a request for comment on a design decision we have to make about the APIs exposed by Toga for style-related operations.
The problem
What API should we expose for style-related changes to a widget? Consider the following operations:
- Set the font face, font size and text color of this label
- Set the background color of this widget
- Hide/show this widget (either “don’t display, but retain layout”, or “remove from layout entirely”)
These are all relatively common things for a widget toolkit to need to do. There will inevitably be an API on platform backends for supporting these operations.
However, what is the API that the Toga interface layer should expose? We use Colosseum to apply styles - however, the style API is deliberately abstracted so that you can pass in any style object you want. In theory, you could define your own style objects implementing a different layout approach (e.g., constraint-based layout?) I’m not sure if anyone will actually ever want to do this - but the option exists.
But should we force all style operations through the style API? Or should we also expose a more traditional functional interface for style operations? i.e., would you rather see:
- Fonts:
label.style.set(font=toga.Font(face='Times New Roman', size=12*pt)
; orlabel.font = toga.Font(face='Times New Roman', size=12*pt)
- Background color:
box.style.set(background_color='#abcdef')
; orbox.background_color = '#abcdef'
- Show/Hide:
box.style.set(display=None, visibility=False)
; orbox.hide()
andbox.visible = False
If we do provide both interfaces, we’re faced with some questions:
-
Which one is the “canonical” definition. If I set the font with CSS, then change the font with a widget API, what happens?
- The widget is the canonical definition, but the CSS declaration is updated; or
- The widget is the canonical definition, but the CSS declaration is not updated. CSS is just a way of getting an “initial” style defined; or
- The CSS declaration is canonical. Widgets have no style state; Style objects are expected to expose an API that matches Toga, so if you call
hide()
on a widget, it callshide()
on the style object, which setsdisplay=None
on the style object, which pushes that down to the widget implementation.
-
In documentation and examples, which API do we favour?
I’ve been going back and forth in my mind about this; I’m torn between the purity and internal consistency of using CSS for all style operations, and the simple utility of having methods like hide()
available. I’m interested in hearing other opinions.
Issue Analytics
- State:
- Created 6 years ago
- Comments:10 (7 by maintainers)
I personally favor the CSS approach because I believe consistency and familiarity make API’s easier to learn. Additionally, I think the complexity of the current API can be helped. If the CSS class implemented
__setattr__
and__getattr__
, It would allow an API with similar look and feel to native HTML5 style:label.style.font = toga.Font(face='Times New Roman', size=12*pt)
box.style.background_color='#abcdef'
box.style.display = None
andbox.style.visibility = False
The main purpose would just be to bring back some “simple utility” as well as making those familiar with CSS feel at home 😃
Of course, I would ultimately like to see stylesheets made possible, which includes having ids and class names for widgets. Maybe not so much for example apps, but for larger scale applications where many widgets will share the same theme colors etc., and most widgets will have custom padding/margin.
This leads me to a question: should Toga widgets define their own default styles? For example,
toga.Button
has no default margin, so when one button is placed adjacent to another, they “touch” (at least on GTK). A good portion of the example apps is used avoiding this by adding margin/padding. I would suggest that each widget gives itself default margin and padding, say 10px, so that it “just works” out of the box.Closing this on the basis that the “widget.style.{property} = {value}” approach has effectively been implemented in the 0.3 branch.