Theme Support
jacobsky opened this issue Β· comments
@setzer22 I am creating an issue that we can use to track the idea of adding some theme support to GodotEgui as well as capture our dicussion from Discord in a more formalized way.
based on capability of using EGUI directly as a tool script, PR #4 I was thinking about how we should proceed to get some kind of unified theming support.
After spending some more time reviewing the egui styles module, I'm in agreement that it's probably best to not bother with Godot Theme support. It's probably far too much work to work on an abstraction layer.
As PR #4 indicates that we have the capability to run EGUI directly in the Godot Editor, I think there's very little reason we shouldn't just work on a theme editor using EGUI. In addition to the benefits of not having to do any theme translation between Godot types and egui types, we can also get an active preview of the theme.
From here, I think it would be useful to just determine some kind of serializable type that can be used to store the theme information such as json, ron, or a .tres (possibly supporting multiple) that contains the relevant EGUI Theme information. Being able to run this inside the editor would be a nice plus for the IDE experience :)
Based on the above There are a couple of points that I'd like to consider as well.
I have a few points I'd like to work on settling below.
- Theme Serialization/Deserialization (go for a more Rusty or more Godoty method?
- How do we want to proceed with creating the theme resource files?
- How should this be integrated with the
GodotEgui
class? - Where should we develop the addon?
- Should the addon be included in this repository?
- Would it be worth splitting the theme editor off into it's own repository so that we can potentially support more targets than just Godot?
- If hosted in this repository should it be included in the main crate or a separate crate?
Thanks again for getting the EGUI ball rolling!
After some additional digging, I think that the settings UI may be a solid place to start from when creating a theme editor, the main issue with the settings page is that it isn't convenient for styling. As the settings tool appears to change the settings immediately, it results in some funky behavior as the modified text of the Settings UI immediately changes. I feel like it would be more convenient to have an unchanging theme editor UI and a preview panel that shows the various widgets (similar to how the godot theme editor works.
I'll work on mocking up an outline of the interface that I'm thinking of.
From the settings screen, it looks like the primary thing we'll need to work with is Style and conveniently, we can get serialization support with the "persistence" feature for egui.
Conviently, it looks like the egui authors already implemented most of the necessary menus by embedding the UI functions directly in the struct like the following example in the code.
impl Context {
pub fn style_ui(&self, ui: &mut Ui) {
let mut style: Style = (*self.style()).clone();
style.ui(ui);
self.set_style(style);
}
}
In addition, each of the settings types have their own predefined UI similar to how style has a ui
function, so it's relatively easy to duplicate the settings as they are mapped currently.
Now that we know this, I think the next things to check would be determining how we can turn all of these settings into a resource for GodotEgui to load on init.
Nice proposal! I think the best way to approach this would be to come up with something that is generally useful to other egui backends and not just tied to godot-egui. We can start the theme editor here, but over time I think it will make sense to split this project into a generic, backend-agnostic egui theme editor, and a Godot integration that makes it usable from within Godot.
Theme Serialization/Deserialization (go for a more Rusty or more Godoty method?
Following the idea of having the "core" theme editor be as backend-agnostic as possible, I think supporting something like json / ron would fit quite well. Another possibility is just to rely on egui's serialization feature you mention above, if it can be used to store all theme-relevant properties. I haven't had time to dig into this part of egui yet.
How do we want to proceed with creating the theme resource files?
I wouldn't introduce a separate serialization format as .tres
. But it's possible that Godot requires a resource class to be registered if we want to get certain editor functionalities, such as drag-and-drop themes into a GodotEgui node.
If that's the case, what I'd do is store the serialized data from whichever format we decide as a string inside a single property of the Resource file. It's a bit hacky, but at least we avoid having two separate representations for essentially the same data.
How should this be integrated with the GodotEgui class?
First of all, we should create some sort of struct representing the theme, let's call it EguiTheme
. There will be some fields in this struct where we can probably use egui's own data (like egui::Style) directly. But I also anticipate other things like font sizes to require specific structs, because we can't reuse the same FontDefinitions
structs, as that includes the font data, and we would only store font sizes in the theme.
Once we have that EguiTheme
struct, the GodotEgui class should get two new features:
- A new method,
set_theme
, whith would apply anEguiTheme
onto the inner egui context. - A new property, which holds a reference to a
EguiTheme
, or some sort ofEguiThemeResource
wrapper resource, so that the theme can also be set via drag and drop from the editor.
The code that actually goes over all the properties in an EguiTheme
and applies it to an existing egui context should not live inside GodotEgui, this way other backends can benefit from it as well. Perhaps it could be a method in EguiTheme
itself.
Where should we develop the addon?
- Should the addon be included in this repository?
I think we could start this here, out of convenience, and once we get something working that is generally useful to other egui backends we can split it into a different repo. But I'm also open to the idea of using a new repo from the start.
- Would it be worth splitting the theme editor off into it's own repository so that we can potentially support more targets than just Godot?
In the long term, definitely π As long as we manage to make it generic enough that it doesn't need to depend on any Godot-specific features, the more people that benefit from this, the better!
- If hosted in this repository should it be included in the main crate or a separate crate?
I think no matter where we host this, the theme editor should be developed as an independent crate from the start. This repo is already set up as a Cargo workspace, so adding another crate and making godot-egui depend on it (just how the example crate depends on godot-egui) should be fairly simple to achieve.
Overall I think this can be a very useful to egui :) nice work on the proposal! π
@setzer22 Thank you very much for the kind words!
I think that the rest of this work essentially boils down to three parts.
1, Godot Egui (aka this issue)
- Theme Resource container (
NativeClass
) that can be passed to the GodotEgui node via the editor so that themes can be usable in Egui. - GodotEgui node integration
- Default editor Egui theme that can be distributed with Egui directly. (We can just copy all the necessary colors/fonts from Godot directly and create an Egui compatible theme out of it
2. Godot Addon (probably can also be located in this repo as a separate project
The addon is a simple project that will just be wrapping the EguiThemer UI.
3. Egui Theme App
This would be the EguiTheme creator. I'm going to check to see if anything like this already exists. If it does, then this step can be unnecessary. As nothing similar appears to exist on crates.io, a custom solution will need to be created.
For Parts 1 and 2, I think these should belong in this repository. While I'm not sure how it works to grab addons from the Godot Asset Library, since there will be the inherent Rust toolchain requirement to use this, I think it's fine that it just remains a part of the repository or crate that can be copied into projects after building.
Part 3 (the theme editor) should probably be located in a separate repository. As you mentioned before, it may be a useful tool for other developers to make use of and there may be other integrations such as webapps, other game engines, etc that it could be pulled into. I'll go ahead and work on creating this separately and will work on building it as a library build with several additional crates that can be used to run the UI library. Similarly to how the demo app in the main Egui repository is configured. I suppose this will be some good practice for building GUIs in my games π
The next steps
For now, I'll continue to work on getting a minimum configuration built up for configuring the Widget colors and font definitions.
I'll start initially with the configuration options that you mentioned in discord from the screenshot below and try to wire something up as quickly as possible
From what I can see the persistence flag uses serde and appears to serialize the information to Ron out of the box, which greatly simplifies things. As a stretch goal, we can look at supporting JSON or other serialization formats in the future.
Please feel free to let me know if you have any other ideas or thoughts about this proposal/idea.
For Parts 1 and 2, I think these should belong in this repository. While I'm not sure how it works to grab addons from the Godot Asset Library, since there will be the inherent Rust toolchain requirement to use this, I think it's fine that it just remains a part of the repository or crate that can be copied into projects after building.
Typically gdnative addons are distributed as compiled binary dylibs, here's a famous plugin that does this, for instance: https://github.com/Zylann/godot_heightmap_plugin If we are going to distribute this on the Godot Asset store, I think that would be the best approach.
But as you said, I think it's safe to assume anyone interested in doing this sort of thing will already have a gdnative setup going. Even if an egui theme editor could be useful on its own, to actually use the themes you would need an additional gdnlib that depends on godot-egui, so most users will be comfortable with configuring Gdnative.
I'll start initially with the configuration options that you mentioned in discord from the screenshot below and try to wire something up
There may be some things specific to my game there, but it's probably a good starting point! π€
Overall it looks like a good plan. I'm already looking forward to use this π I'm assuming you want to take the lead on this, but please let me know if I can help in any way π
hub.com/Zylann/godot_heightmap_plugin If we are going to distribute this on the Godot Asset store, I think that would be the best approach.
But as you said, I think it's safe to assume anyone interested in doing this sort of thing will already have a gdnative setup going. Even if an egui theme editor could be useful on its own, to actually use the themes you would need an additional gdnlib that depends on godot-egui, so most users will be comfortable with configuring Gdnative.
That's good to know. I hadn't looked into any of the asset store stuff. I think we can put publishing addons to the asset library as a future task to consider.
For this instance, I'll definitely make the addon it's own crate/project in this repository. It'll probably be nice for any users that want to make use of egui to also get the theme maker addon easily.
There may be some things specific to my game there, but it's probably a good starting point! π€
Overall it looks like a good plan. I'm already looking forward to use this π I'm assuming you want to take the lead on this, but please let me know if I can help in any way π
Thank you very much! I'll probably ping about this in discord. I'll go ahead and take the lead on getting the theme editor created as well as getting the initial groundwork for the application going. Once I can configure the colors, spacing and fonts in the app and allow it to be exported to a ron
string, I'll make it public and start working on integrating it here.
I already created the application from the github template that egui provides and will let you know once I get a little bit farther (probably a bit later this week).
After I get the initial app built up, I'll work on integrating this and create a WIP pull request to track the additional changes and get some earlier feedback. I already feel like this will require a minor version bump since we'll probably need to completely change the input parameters of the GodotEgui
node. At least we don't have to worry about compatibility π