-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
Introduce ThemeDB
/ThemeServer
, register theme properties with it to define stable theming API for controls and windows, allow to define theme properties in scripts
#4486
Comments
This would also remove the issue of Window nodes not showing the Theme Overrides section despite having theme properties. Also, theme properties could be added to any potential 3D UI nodes, like the recently-added Label3D. |
My views on this: Short version: I am not particularly against this, but my feeling is that if we do this, we either more or less leave things as is, or should do it all the way and implement #2832. Then figure out how to improve the usability after having eliminated Theme and its categories in favor of just variants. Long version: The thing is that theming in general works pretty well, there are some rough edges but its pretty good. Users are doing all sorts of things with it. It's a very WYSIWYG implementation that is rather simple. This is what is makes me feel less inclined to do further changes to it. My line of thinking is more or less the following:
So based on the above information, what I generally think about here is:
You can imagine that I went over these topics for more than 10 years in my head, but nothing really convinced me more than doing what we are doing now. I understand that there are pain points, but to me all seem like good tradeoffs. I don't believe in perfect solutions, but I do believe that those who pursue them are wrong most of the time. Not saying we should leave things as it is, but the alternative has to be really good to justify it. If we do changes to themeing, also, I think we need to make it easier to scale the UI (like change DPI on the fly). This really is one of the biggest features missing to me. |
I don't think we should remove categories of theme data types. They give nice separation when looking for the property that you need. Likely, this kind of grouping would still be desired even if you did change it to Variants, we would just have to create groups ad-hoc for the UI, and handle a lot of unexpected cases. Granted, current categories are lacking. We have numeric constants that are often used as booleans, and at the same time can't be used for floating point values, which are not rare when theming. Adding more categories would almost certainly make code even less readable with a lot of copy-pasting and opportunities to make a mistake. Maybe theme constants can be a variant, and other types can be as is, focused and easy to find? Constant already sounds ambiguous enough.
I'm cautious about creating new data tables, but if you think it's better to have a dedicated database for themes, that's fine by me. It would probably be even better in practice. My focus was mainly on the API usage, not the backend of it. ClassDB looked like a natural choice, but nothing here is bound to it.
That's what I propose, yes. That we register theme properties in
I agree that it makes more sense to do it as your proposed "configuration" object rather than theme. I am not adamant about this change anyway, so we can reconsider it later. For now I'd like to improve themes, because I think they work fine already, they just need stability. So I only am adamant about my points 1 and 2. |
This is already mostly handled by godotengine/godot#52170 (which was backported to 3.4). If you need Camera2D zoom to not change when changing the UI scale, divide its zoom by the scale factor (in SVG icon/stylebox re-rendering when the scale changes isn't implemented yet though. |
@YuriSizov That may work, there are now static methods in the binder, so you can do things like |
Ok, I've been thinking a bit about implementing point 1 — internal changes to make theme properties first class properties of controls (and windows) and make that part of the theming API more stable. Here's what I envision: 1. We introduce a new
|
I realized that the mock API above doesn't really make it easier to fetch theme properties for docs or the theme editor. In fact, it wouldn't work at all this way, because This was what I wanted to use ClassDB for, but reduz is right, we probably better make a new, dedicated one. Some This also changes PS. An introduction of a theme-related singleton would also allow to move some singleton bits from the Theme resource. Like fallback values, or the default theme reference. I think it's a good idea as well, keeping the resource code clean and purposeful. |
ThemeServer
, register theme properties with it to define stable theming API for controls and windows, allow to define theme properties in scripts
Are these changes in the code and API ? |
@me2beats This proposal changes how controls work with themes, but doesn't change how themes work. It also doesn't remove any existing functionality, just creates a framework for more stable API for controls. Plus some reorganization internally. Additionally it would also expose the same improvements to scripting, so user scripted controls could also benefit from these changes. But once again, the themes themselves don't change, neither their structure, nor their tooling. I just see no reason for that. At least, not as a part of this proposal. |
ThemeServer
, register theme properties with it to define stable theming API for controls and windows, allow to define theme properties in scripts ThemeDB
/ThemeServer
, register theme properties with it to define stable theming API for controls and windows, allow to define theme properties in scripts
@YuriSizov is there a timeline for this whole topic? Seems like the pre-requisites were merged lately so I assume this could be part of 4.2? |
@dotlogix Depends on what it is that you want from this proposal 🙂 A lot of internal work has been done and is a part of the upcoming 4.2. I don't think users would notice these changes much (other than some new docs or overrides available, and some invalid ones being gone). The part about allowing scripts to define theme properties for their GUI classes is not implemented and won't be done for 4.2. So, what interests you here? |
Unfortunately I think it is more the second thing you mentioned. Actually what I want to do is to add some theme properties to my custom container control and also provide the option for theme_overrides. Unfortunately I think there is currently no way of achieving this. Maybe you know a workaround until this is fixed properly? I would like to avoid real properties because it would be a breaking change and reset property values afterwards and I plan to maybe publish my addon at some point. |
You can't hook into the way existing properties are generated, but you can generate them in your class' script in a similar manner. You need to implement |
Hm looking at this code, wouldn't it be super easy to allow overriding the GetClassName function from scripts? |
That's a different problem entirely and is not the way to solve this particular issue. |
Note: This proposal text is kept as it originally was, but the follow-up comments explore and extend the actual implementation, as well as which parts of the proposal to keep and which to reject. As such, this description predates the most recent title of this proposal.
Describe the project you are working on
Godot engine
Describe the problem or limitation you are having in your project
While theming is a powerful tool for customizing the looks of the UI in your Godot projects, the underlying tech has shortcomings and limitations.
First of all, theme properties are still "stringy" as of the current state of Godot 4.0, and remain one of the last bits of Godot scripting which is so. This means worse code completion, more room for typos, less defined API. As we move towards first-class citizens for other "stringy" properties, theme items feel like a relic of a past. Additionally, the built-in theme properties have poor naming convention (none, really), which is partially obfuscated by the use of strings without proper property definitions.
Secondly, theme properties are weakly defined. While controls require them and use them, and have not only visual details but bits of logic based on the theme properties (e.g. margins of a stylebox), controls don't actually define their contract with the theming system. Instead, they kind of hope that the theme applied to them, or one of the higher-order themes, is going to have the necessary items. The actual definition happens in
scene/resources/default_theme.cpp
instead, where the default project theme is created, used as a fallback for everything.The default theme definitions is exactly what we use to create the list of control's theme override properties, for example. Same approach is used in the theme editor. And it's all, once again, string-based. This leads to the default theme missing definitions that some controls require, and, vice versa, having outdated or forever invalid definitions which the corresponding controls don't actually need. And as maintainers we have no tools to validate them, make sure we define all we need to define and remove all the bits we don't actually need.
All in all, it's a frustrating gap between a control and its default styling. And as a result, custom controls don't have a nice way to hook into the existing system and can't benefit from having defined theme overrides and default styling. You may be able to hack into an instance of the default theme, but that's not a good and stable solution, and definitely not an intuitive one.
Thirdly, theming is limited to controls, while it can be useful for other parts of your project. For example, you can use a theme to carry color information to your in-game units. You can of course create the necessary boilerplate code to imitate theme application and propagation to
Node2D
orNode3D
/Spatial
, but that becomes harder to sell with Godot 4.0, where we have a new kind of node that also implements theming —Window
. Implementing support for both controls and windows required hacking intoControl
's existing theming logic and making Windows inherently dependent onControl
's code to reduce code duplication.But I think it's a good sign that we might want to extend theming to just about any node, while keeping this system opt-in for the most of them (but enabled by default for controls and windows).
Describe the feature / enhancement and how it helps to overcome the problem or limitation
I propose several interconnected things to make the whole theming system more robust, extensible, and intuitive.
1. Make controls define their theme properties, and store them in ClassDB like normal properties (but separate).
Let's say, we introduce a new macro,
ADD_THEME_PROPERTY
that would create ClassDB definitions, and provide sensible default values for them if necessary. We'll use these definitions wherever and whenever we need a list of theme properties supported by each control (in the inspector, the theme editor, etc). The default theme specifically and the Theme resource in general remains the same, but using this now defined theming contract we can evaluate if the default theme has all the necessary items and if it has excessive items.To reduce stringy-ness of theme properties internally, we also introduce a
ThemeProperty
type, or something similar. We'll use this type to represent each Control's theme property. It will be able to look up definitions in the scene tree the same as control does now, but abstracted away from the rest of the control code. It will also handle local overrides for controls. I think that in the engine codeThemeProperty
members can be normal class properties, so accessing them would be natural and intuitive.2. We expose everything from the first point to scripting.
The
ThemeProperty
type would be a naturally exposed class. As for properties themselves, I propose we add an annotation@theme_property
, to separate them from regular properties (just like, say, signals are separated, despite being member-like). I think this separation is important because theme properties would be their own ClassDB entity. Plus, they have specific pre-defined behavior (like the theme overrides section), and this annotation would be the scripting way to achieve the same asADD_THEME_PROPERTY
internally.An example would be
With such tools, custom controls should become as natural as built-ins, benefiting from the native editor integration and stable, easily discoverable API.
3. Move theming logic from
Control
toNode
, make it opt-in.This removes the dependency of
Window
onControl
, but also opens up theming to be usable outside of UI. All nodes would have an innate ability to accept theme and theming notifications, but we won't enable it by default. Instead a node needs to explicitly turn this on.One of the features of theming is theme propagation and theme merging along a branch of nodes. So I think that opting in can be done by defining a property that would store node's own theme. In engine code it can be a
ADD_THEME
macro, acting similar toADD_THEME_PROPERTY
, but for the theme itself. And in scripting it can be a@theme
annotation, e.g.Opting in would make nodes a part of the propagation system, so they can affect underlying "themeable" nodes just like controls affect their child controls. Basically, what now happens between an uninterrupted chain of controls is going to happen between all the nodes, with nodes that opted into theming interacting and the rest of the nodes being ignored.
You can view this as a poor man's multiple inheritance/interface implementation. Nodes that opt into the theming system in a way implement an "IThemeable" interface or extend a "Themeable" class, without breaking their existing inheritance chain. I think that my approach fits Godot's and GDScript vision more than interfaces and multiple inheritance, at least as it currently stands.
What I wouldn't change...
... is the
Theme
resource and the editor UI for anything related. I think what I propose would improve things without any changes there.Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
See above.
If this enhancement will not be used often, can it be worked around with a few lines of script?
Points 1 and 2 are about core changes to how theme properties are defined.
Point 3 can be implemented with boilerplate code, but it's not just a few lines.
Is there a reason why this should be core and not an add-on in the asset library?
This is a core change.
The text was updated successfully, but these errors were encountered: