Theme editor: create, preview and save a resource
A complete .rdata generator, item/variation editing, previews and reusing a theme across levels.
Obtain an editable file
Add UiSampleStyle.cs and ThemeAssetBuilder.cs to a C# project. Attach ThemeAssetBuilder to a separate level's Control root, build and run with F6.
Press Create only if absent. Expect Error.Ok and asset://UI/DemoTheme.rdata. Repeating returns AlreadyExists and retains edits. Load this button's theme rereads the resource and applies ActionButton. AssetPath is a developer-configured project path, not arbitrary user-input handling.
ThemeAssetBuilder.cs
using Reckfell;
public partial class ThemeAssetBuilder : Control
{
[Export] public string AssetPath { get; set; } = "asset://UI/DemoTheme.rdata";
public Theme? LoadedTheme { get; private set; }
public Label Status { get; private set; } = null!;
public override void _Ready()
{
UiSampleStyle.Prepare(this);
var column = new VBoxContainer { Position = new Vector2(24, 24) }; AddChild(column);
Status = new Label { Text = AssetPath }; column.AddChild(Status);
var create = new Button { Text = UiSampleStyle.Text("Создать, если файла ещё нет", "Create only if absent") }; column.AddChild(create);
create.Pressed += () => Status.Text = CreateAsset().ToString();
var preview = new Button { Text = UiSampleStyle.Text("Загрузить тему для этой кнопки", "Load this button's theme") }; column.AddChild(preview);
preview.Pressed += () =>
{
if (!FileAccess.FileExists(AssetPath)) { Status.Text = Error.FileNotFound.ToString(); return; }
LoadedTheme = ResourceLoader.Load<Theme>(AssetPath, cacheMode: ResourceLoader.CacheMode.Ignore);
if (LoadedTheme is null) { Status.Text = Error.FileUnrecognized.ToString(); return; }
preview.Theme = LoadedTheme; preview.ThemeTypeVariation = "ActionButton"; Status.Text = AssetPath;
};
}
public Error CreateAsset()
{
if (!AssetPath.StartsWith("asset://") && !AssetPath.StartsWith("user://")) return Error.InvalidParameter;
if (!AssetPath.EndsWith(".rdata")) return Error.InvalidParameter;
if (FileAccess.FileExists(AssetPath)) return Error.AlreadyExists;
string directory = ProjectSettings.GlobalizePath(AssetPath.GetBaseDir());
Error error = DirAccess.MakeDirRecursiveAbsolute(directory);
if (error != Error.Ok) return error;
var theme = UiSampleStyle.Create();
theme.SetTypeVariation("ActionButton", "Button");
theme.SetColor("font_color", "ActionButton", new Color(.4f, .6f, 1));
return ResourceSaver.Save(theme, AssetPath);
}
}For asset://, stop the run, open Content (Ctrl + Space) and find the created file. Selecting Theme opens the Theme dock, at the bottom by default but also available as a floating window. A user:// file belongs to the user directory rather than project Content; obtain its actual path with ProjectSettings.GlobalizePath. Alternatively create and save a Theme resource in the editor; an embedded level theme does not automatically become a reusable external file.
This generator prepares a theme in a development project. In an exported game asset:// is normally not writable; save user themes in user:// and explicitly load them at startup. FileExists prevents ordinary repeated-button overwrites, not concurrent-writer races atomically.
Edit a setting
- Choose
Button. Find/addfont_colorunder colors,normalunder StyleBoxes andfont_sizeunder font sizes. - Create only necessary overrides. An empty Theme is supplemented by the default theme; it does not automatically contain a copy of every value.
- For StyleBoxFlat, set background, border, corner radius and content margins. Edit normal/hover/pressed/disabled/focus separately.
- Save the file. Assign it to the target UI root's Theme or select a project theme. Set ThemeTypeVariation on a target Control for a variation.
- Check your own level with real long labels and window dimensions, then run the game.
Preview and bulk operations
The editor previews standard controls; Add Preview adds your own hierarchy. Preview checks appearance; button actions and game logic require running the project. Check font/margin changes together with minimum sizes and containers.
Manage Items... manages types/items. Import Items offers Default Theme, Editor Theme and other resources. Select specific entries to import. Copying every value increases maintenance and can pin unwanted defaults. The editor theme is a styling source, not a required game design.
ResourceSaver persistence and in-memory Theme changes are separate operations. An already loaded resource can remain cached after a file edit; the generator explicitly uses CacheMode.Ignore to reread. Choose a consistent loading policy rather than rereading every frame. CacheMode.Ignore does not promise an independent copy of every external dependency: mutable StyleBox or Font resources can remain shared.
When an edit is invisible
Check the assigned resource path, type/variation, item name, current button state, local overrides and closer themes. Confirm the file was saved. Identify needed exceptions before removing overrides in bulk.