Discussion: Themes vs Styles vs LookAndFeel
See original GitHub issueThis is not a bug-report or a report about a missing feature, but a “question/discussion” issue.
This question came up here
about the look and feel, I always wondered the possibility to allow some widgets to have a “style” attribute but I never formalised it.
Current state
I try to summarize the current state (please correct me, if/when my summary has errors):
- In
TTkCfg
there is an attributetheme
which points to the “current” theme - Widgets (e.g. a
TTkFrame
) check some theme-attributes at construction time (e.g.frameBorderColor
,frameTitleColor
) - Widgets (e.g. a
TTkFrame
) check some theme-attributes at every call topaintEvent
(e.g.TTkCfg.theme.grid
) - Widgets (e.g. a
TTkFrame
) support by keyword arguments to__init__
to not askTTkCfg.theme
for a color but to use the one explicitly given at construction time with an explicit keyword argument (e.g.titleColor=...
)
Because of 3. it is possible to switch/change the grids, button-boxes, scrollbars, menubars, etc. dynamically (on the fly); which can be seen in the demo where one can switch from UTF-8
to ASCII
theme.
Because of 2. a change in attributes like frameTitleColor
has no effect on the widgets that are already constructed, but has an effect on every widget that is created after the theme-attribute(s) changed.
Because of 4. “many” slots are used (per widget) to save “their” colors (either the explicitly given ones from __init__
or the ones that were found in TTkCfg.theme
by __init__
).
[Some personal note: The asymmetry of 2. and 3. (getting some theme attributes at construction time and some at every paintEvent
) is a little bit … disturbing … for me.]
Proposition/Suggestion
Here is an alternative approach which (in my opinion) simplifies things a bit:
Instead of the many color-slots (per widget) every widget hat only one look_and_feel
(laf) slot. There a (reference to an) object is saved that is used at every paintEvent
to ask the look_and_fool
object for colors, grid-chars, borders-chars, etc. The default look_and_feel
object is a “proxy” that “redirects” all the attribute-getters to the current TTkCfg.theme
. All the widgets that use the default look_and_feel
object see every change in TTkCfg.theme
immediately (at the next repaint/update). But this scheme allows for other laf-objects: e.g. a look_and_feel
-object that gives for some attributes (e.g. frameBorderColor
) some fixed colors that were chosen at the construction time of the laf-object and all the other attributes are proxied to TTkCfg.theme
.
- (laf-resolution at
paintEvent
) So one can have laf-objects that (per default) proxy their attribute requests toTTkCfg.theme
but have the ability to prescribe some attributes directly without askingTTkCfg.theme
. So it’s possible to usemy_frame_laf = LookAndFeelProxy(); my_frame_laf.frameBorderColor = TTkColor.fg("#ff0000#");
as an laf-object for a frame that has (independent of the current theme) a red border, but all the other things (like the chars that are used for the border) are from theTTkCfg.theme
. - (colors, chars, etc. may depend on widget-state; method instead of pure values) Becasue laf-objects are objects (and not only stored color values) this allows for the ability to have methods in an laf-object that “computes” colors/chars taking the current state of the widget into account. This is the part that I used in the progressbar-WIP (often people want colors to depend on the “progress”: one uses a progress bar to show how full something is and want to colorize the event, that this thing is nearly empty, below 10%, with some red color, etc.).
- (feel-parameters and feel-functions) But wait, there is more … [in this commercial spot] 😃 Why do I call this
look_and_feel
and notstyle
? Let’s make an example. Think of aPushButton
(not aTTkButton
) that can be pressed by akeyEvent
(e.g. space or return) and shows it was pressed (via key) for some time and then goes automatically back in the unpressed state. This timing may be controlled by an attribute of an laf-object. So thekeyEvent
sets the pressed state and triggers an update and also starts a Timer to “unpress” the button in the near future. That’s not a style or color but that is a “responsive” feeling.
Pros: less slots per widget; laf-object may “compute” the look-and-feel depending on the state of widget; more parameters possible (without using slots); no additional methods needed at the widgets to prescribe special look-and-feel (e.g. setBorderColor
or the missing setTitleColor
or setTitleAlign
, etc.) for a widget.
Cons: one level of “indirection” (the “laf-Proxy”) more at every paint-Event.
[Sorry for the long text.]
Issue Analytics
- State:
- Created 9 months ago
- Comments:10 (8 by maintainers)
Top GitHub Comments
@nickandwolf Unfortunately there is no way to include tiles or change the font size, what my library produce are the ANSI codes and UTF-8 chars interpreted by the terminal, so any graphical feature is restricted by what the terminal is capable of. (There are some terminals that support images and/or tiles but this is outside the scope of my project, my final goal is to have a terminal UI that may works via ssh/telnet or serial)
Anyway, about the half-step blocks I am already using them in the rasterizer. in this case you have the restriction of 2 colors (bg/fg) per char/tile:
https://github.com/ceccopierangiolieugenio/pyTermTk/blob/789128d740500d29dd5a9a5790b06c337baf66bf/TermTk/TTkWidgets/image.py#L79-L86
or in the big font mouse/key input viewer:
https://github.com/ceccopierangiolieugenio/pyTermTk/blob/789128d740500d29dd5a9a5790b06c337baf66bf/TermTk/TTkTestWidgets/keypressviewfont.py#L202-L210
I am actually thinking also to support the sextels in order to have 6 blocks resolution per char.
Experimenting with the gradient modifier:
Peek 2022-12-21 09-22.webm