Open luchr opened 1 year ago
Simple answer about 1,2,3,4 there is a little bit of a mess because when I started the project There was no "theme" class and I couldn't predict the complexity derived from having this attributes in the widget itself, this is the reason why the first widgets (Label, Button, Frame and few more) allows you to change those attributes during the initialisation and through some methods, same if you noticed about the drawing routine, later widgets draw everything in the "paint()" using canvas primitives, older widgets rely in some ultra comlpex specialised methods in the canvas object itself.
After a while I decided to rely mainly on the themes and I didn't modify the old widget to comply with it. Same happened for TTkString, I added this class not long ago and I haven't backported all the old widgets to convert the strings to TTkString.
So far I would like to get rid of all the "style" attributes if possible and use a better way to handle them. I used some hacks here and there to quickly achieve some goals, i.e. the way I abuse "setBorderColor" in the tabwidget to have a uniform color when highlighted. I think the look_and_feel (TTkLookAndFeel?) object may works, maybe any object should have its own LAF derived class to expose all the api required to customize it.
I think the look_and_feel (TTkLookAndFeel?) object may works, maybe any object should have its own LAF derived class to expose all the api required to customize it.
This is a great idea. Then things are decentralized and can be optimized:
Let's make the assumptions
paintEvent
occurs oftenThen there can be one "basis laf" which provides generic laf-hints: a few window backgrounds (modal, non-modal, popup, warning, etc.); a few typical border colors (active border, inactive border) a few text-colors etc. And this basis laf is using the Event-Signal-Mechanism to inform all "listeners"/slots when something has changed.
Every Widget can have a specialized laf class which saves a reference to the "basis laf" and uses the generic hints of the "basis laf" to precompute once many/all of the needed colors, chars, ... laf-parameters, etc. The computation may be expensive, but it's only called very rarely in the event of the construction of the specialized laf-object and if the event "there are changes in the basis laf" occurs. In the paintEvent
the widget can use its specialized/own laf-instance to query for the laf-parameters (or to call laf-functions).
[Every specialized laf-object has a API so that it's possible to overrule the default colors-, chars-, laf-parameters- computations.]
Then the only "Con" point above has vanished. During a paintEvent
there is no indirection and only the (pre-)computed return values of the widget's laf-object are used.
Hello, just a few additional remarks. Looking at the PR #75 and for example the current state of TTkLookAndFeelPBar it looks like we are converging to an (very old) concept: UI delegates, like in Java's swing framework.
In the concrete progress bar example:
βββββββββββββ
βββββββββββββ
=> ββββββ-ββββββ
=> ββββββ\ββββββ
=> ββββββ|ββββββ
=> ββββββ/ββββββ
=> βββββββββββββ
One cannot write one paintEvent
method having all the cases in mind. In the end of this direction, the paintEvent
method is delegated to a look-and-feel "UI". And every look-and-feel(-implementation) has its own way/design.
What do you think about this direction?
I just want to pop on and say I would love to specify border, background, default text colors with escape characters to manage in-line colorization. I'm big in UI and readability and this would be cool. Thank you!
@nickandwolf I'm not sure if I understand what you mean. I understand that if there are some "labels" or some "paragraphs" in the UI, that one might want to have the possibility that some of the words (inside the paragraphs/labels) are red, and some others are green, to make everything more readable. This might be done with inline ANSI-Escape sequences (or other ways). But what type of "in-line colorization" do you have in mind for borders and/or backgrounds. Typically the width/height of the objects that have borders change and so the borders must be computed dynamically. One can think of giving the possibility for some color gradient thingy (please see picture for an example). But all of this cannot be given "in-line" in a "border string". Because every part of the border gets longer or smaller if the object is resized. Same argument for the background ...
@luchr - #issuecomment-1356381197
Hello, just a few additional remarks. Looking at the PR #75 and for example the current state of TTkLookAndFeelPBar it looks like we are converging to an (very old) concept: UI delegates, like in Java's swing framework.
In the concrete progress bar example:
- An other background character (instead of space), like
βββββββββββββ
- A color gradient for the bar
- A little spinner at the current position:
βββββββββββββ
=>ββββββ-ββββββ
=>ββββββ\ββββββ
=>ββββββ|ββββββ
=>ββββββ/ββββββ
=>βββββββββββββ
- Text on the right, on the left or inside the bar
- etc., etc.
One cannot write one
paintEvent
method having all the cases in mind. In the end of this direction, thepaintEvent
method is delegated to a look-and-feel "UI". And every look-and-feel(-implementation) has its own way/design.What do you think about this direction?
I always tried to keep everything simple without adding too many edge cases for customisation and keeping a solid standard behaviour/look. (for this reason I mimic the way QT works/looks) I agree that we cannot write a paintEvent covering all the possible cases, but at the same time I don't want to have a paint event that just forward everything to the lookAndFeel or some other callbacks to allow any possible customisation, for this reason in some cases (i.e. tab buttons) I extended the class rewriting the paint event to provide the look I wanted to achieve.
And unfortunately I am still stuck with the old way UI concept, I never managed to fully understand modern UI frameworks, especially the amount of code, files, abstraction and libraries you need to implement in order to display some basic controls.
@nickandwolf - #issuecomment-1358515339
I just want to pop on and say I would love to specify border, background, default text colors with escape characters to manage in-line colorization. I'm big in UI and readability and this would be cool. Thank you!
can you provide some pictures of your idea?
About the gradient, I was prototyping long ago the color modifier feature to add dynamic color effects automatically. https://github.com/ceccopierangiolieugenio/pyTermTk/blob/f82541b16ec04654e2716f4a81a42599ac128118/TermTk/TTkCore/color.py#L186
i.e. https://github.com/ceccopierangiolieugenio/pyTermTk/blob/f82541b16ec04654e2716f4a81a42599ac128118/demo/ttkode.py#L175-L180 where the gradient is a property of the color itself and the widget does not need to implement any extra routine in the paint method:
Unfortunately I never investigate all the implications and possibilities of this feature and so far only a vertical gradient is available.
@luchr I love that mockup image. Unfortunately I am greatly limited most of the day and cannot create a mockup but that image is amazing.
So I look at Tkinter and video game UI frameworks when it comes to styling. In my current project, I'm finding the information looks cluttered and hard to read despite it being organizationally sound. Here are some of my thoughts.
I do not know exactly how your engine manages text but if it has the ability to render multiple characters on top of each other (like BearLibTerminal), it can allow a greater diversity of stylings.
Many TUIs I'm looking at are not as dynamic as yours @ceccopierangiolieugenio while providing mouse support. You mockup image and code is also very close to what I think the next step is to add stylization. I'm leveraging that to make character sheets and character creators. My current project is for Cyberpunk 2020 and could use more diversity to make sections of it pop. It would also benefit from having a large text renderer (like in your demo program that shows mouse coords).
I am basing this off a PDF character sheet but if you look up 5E D&D character sheets, you can see how the layout is a real test for this library.
EDIT: Originally on my Stats block, I had a label from the host frame over the INT etc frames but when I click on the spinnerbox inside, it covered my label. Making frame focus toggleable would alleviate that when it comes to be stupid fancy.
Experimenting with the gradient modifier:
@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:
or in the big font mouse/key input viewer:
I am actually thinking also to support the sextels in order to have 6 blocks resolution per char.
@ceccopierangiolieugenio Haha just saw this repo. Your result is absolutely hilarious. π€£ When I first started writing my source code editor I had a goofy Idea to do something like this. I use wxPython and Scintilla tho. I think I managed to get A frame, some checkboxes and a couple buttons done in a windowless wxFrame housing a wxSTC editor for the drawing, but nothing like this. I at some point kinda just laughed at it and thought who would ever take this seriously if they changed the font in the editor, plus handling all the absolute positioning coordinates kinda overwhelmed me in the code... Well you seem to be the first to try and tackle a GUI Term/Console style...
My attempt turned out a bit like your AboutBox but without the graphics. Just A title, short description, 3 checkboxes and Yes/No buttons... Nothing to brag about tho. LOL. If I even come across my ol sample I'll have to relook into this. Maybe I could get it working right... haha Any thoughts on possibly expanding to other toolkits? Just curious...
@ceccopierangiolieugenio Haha just saw this repo. Your result is absolutely hilarious. π€£ When I first started writing my source code editor I had a goofy Idea to do something like this. I use wxPython and Scintilla tho. I think I managed to get A frame, some checkboxes and a couple buttons done in a windowless wxFrame housing a wxSTC editor for the drawing, but nothing like this. I at some point kinda just laughed at it and thought who would ever take this seriously if they changed the font in the editor, plus handling all the absolute positioning coordinates kinda overwhelmed me in the code... Well you seem to be the first to try and tackle a GUI Term/Console style...
My attempt turned out a bit like your AboutBox but without the graphics. Just A title, short description, 3 checkboxes and Yes/No buttons... Nothing to brag about tho. LOL. If I even come across my ol sample I'll have to relook into this. Maybe I could get it working right... haha Any thoughts on possibly expanding to other toolkits? Just curious...
Yes, which toolkits have you in mind?
Oh, I dunno... wxpython, pyside/pyqt, tk, kivy, Scintilla. Mostly ones that have cfamily python bindings. I really don't do too much with html css java anymore besides docs. Vulkan/SDL2 would be overkill for something like this but would be awesome to see.
On Fri, Mar 8, 2024, 9:00 AM Pier CeccoPierangioliEugenio < @.***> wrote:
@ceccopierangiolieugenio https://github.com/ceccopierangiolieugenio Haha just saw this repo. Your result is absolutely hilarious. π€£ When I first started writing my source code editor I had a goofy Idea to do something like this. I use wxPython and Scintilla tho. I think I managed to get A frame, some checkboxes and a couple buttons done in a windowless wxFrame housing a wxSTC editor for the drawing, but nothing like this. I at some point kinda just laughed at it and thought who would ever take this seriously if they changed the font in the editor, plus handling all the absolute positioning coordinates kinda overwhelmed me in the code... Well you seem to be the first to try and tackle a GUI Term/Console style...
My attempt turned out a bit like your AboutBox but without the graphics. Just A title, short description, 3 checkboxes and Yes/No buttons... Nothing to brag about tho. LOL. If I even come across my ol sample I'll have to relook into this. Maybe I could get it working right... haha Any thoughts on possibly expanding to other toolkits? Just curious...
Yes, which toolkits have you in mind?
β Reply to this email directly, view it on GitHub https://github.com/ceccopierangiolieugenio/pyTermTk/issues/77#issuecomment-1985848430, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDTXRGAANLXPKF6AHMJU5DYXHG7XAVCNFSM6AAAAAAS3H4DKCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBVHA2DQNBTGA . You are receiving this because you commented.Message ID: @.***>
This is not a bug-report or a report about a missing feature, but a "question/discussion" issue.
This question came up here
Current state
I try to summarize the current state (please correct me, if/when my summary has errors):
TTkCfg
there is an attributetheme
which points to the "current" themeTTkFrame
) check some theme-attributes at construction time (e.g.frameBorderColor
,frameTitleColor
)TTkFrame
) check some theme-attributes at every call topaintEvent
(e.g.TTkCfg.theme.grid
)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
toASCII
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 inTTkCfg.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 everypaintEvent
to ask thelook_and_fool
object for colors, grid-chars, borders-chars, etc. The defaultlook_and_feel
object is a "proxy" that "redirects" all the attribute-getters to the currentTTkCfg.theme
. All the widgets that use the defaultlook_and_feel
object see every change inTTkCfg.theme
immediately (at the next repaint/update). But this scheme allows for other laf-objects: e.g. alook_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 toTTkCfg.theme
.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
.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 missingsetTitleColor
orsetTitleAlign
, etc.) for a widget.Cons: one level of "indirection" (the "laf-Proxy") more at every paint-Event.
[Sorry for the long text.]