Editor UI theming for tools
Theme inheritance, icons, scale and local overrides.
Editor tool theming
An EditorPlugin panel should follow the editor theme and scale. This differs from styling game UI or the web portal: a game project's Theme does not replace the global editor theme.
Start with inheritance
Add ordinary Button, Label and Container controls to the plugin-owned EditorDock. Theme inheritance already supplies consistent fonts, colors and states. Avoid assigning every control its own Theme unnecessarily: focus, disabled and hover states can easily be lost.
Obtain the current theme through EditorInterface.Singleton.GetEditorTheme() and scale through GetEditorScale(). Editor icons use the EditorIcons theme type. Check optional icon names with HasIcon before reading so a missing name does not produce a log error.
This example creates a button for an existing Tool plugin. The caller adds it to owned controls and removes it with the panel:
using System;
using Reckfell;
public static class EditorButtons
{
// Call from a Tool EditorPlugin; add the result to its owned controls.
public static Button Create(string text, string iconName = "Add")
{
if (!Engine.IsEditorHint())
throw new InvalidOperationException("Editor context required.");
var button = new Button { Text = text };
void Refresh()
{
var editor = EditorInterface.Singleton;
var theme = editor.GetEditorTheme();
button.Icon = theme.HasIcon(iconName, "EditorIcons")
? theme.GetIcon(iconName, "EditorIcons") : null;
button.CustomMinimumSize = new Vector2(0, 32 * editor.GetEditorScale());
}
button.ThemeChanged += Refresh;
Refresh();
return button;
}
}The caller supplies text: localize it where the command is defined. Width is not fixed, allowing a long label to increase minimum size; the container and available width still need visual inspection. Height follows the current editor scale.
ThemeChanged refreshes the icon and size. This is notification-driven data updating, not a promise that every DPI/theme switch works on every OS. The example has no global EditorSettings subscription: the handler belongs to the button and is removed with its panel.
Make a local visual change
- Begin with a standard control and suitable container.
- If standard states are insufficient, use a local theme override or suitable theme variation.
- Duplicate a shared StyleBox before modifying it. Mutating a shared theme resource can affect other controls.
- Do not assume a variation name from an old article is required by the current theme. Check its existence and behavior in the selected style.
- Do not manually set text color only for normal state: focus, disabled, hover and contrast must remain readable too.
Check before shipping a tool
| Scenario | Check |
|---|---|
| Ordinary and long translation | Labels fit and adjacent buttons/fields remain accessible. |
| Small window | The container wraps or scrolls as intended; commands do not disappear beyond an edge. |
| Interface scale | Sizes, icons and spacing stay consistent; fixed widths do not break labels. |
| Keyboard | Focus and traversal order are visible; actions work without a mouse where required. |
| Theme change | Custom colors and copied styles are refreshed without mixing control states. |
| Plugin deactivation | Panels, buttons and handlers are removed; reactivation does not duplicate them. |
This article's installed headless-editor functional run checked theme access, the Add icon, unknown-icon fallback, scaled height, long RU-label minimum width, native signals and panel cleanup. Actual theme/DPI switches, keyboard traversal and rendered layout across operating systems were not tested. No new interface screenshots were added.
See EditorPlugin and EditorDock for full panel lifecycle and editor architecture for built-in interface structure.