reckfellENGINE

Тема интерфейса: наследование и локальные изменения

Рабочий пример общей темы, порядка поиска и отдельного StyleBox для одной кнопки.

На этой странице

Где хранить оформление

Theme объединяет цвета, константы, шрифты, размеры шрифтов, текстуры, StyleBox и звуки по имени элемента и типу Control. Например, font_color типа Button и font_color типа Label — разные записи. Имена и регистр должны совпадать с API конкретного элемента. Список доступных имён есть в свойствах темы страницы типа API.

Назначьте общую тему корню UI. Дочерние Control и Window могут использовать её и дополнять своими темами. Для одного исключения удобно локальное Theme Override, для повторяемого варианта кнопки — именованная вариация типа. Не копируйте всю тему ради одного цвета.

Запустить пример

Добавьте UiSampleStyle.cs и ThemeBasicsDemo.cs в C#-проект. Прикрепите ThemeBasicsDemo к корню Control отдельного уровня, соберите и запустите F6.

Кнопка изменения общего фона меняет StyleBox у двух первых кнопок. Отдельный фон первой копирует ресурс и меняет только первую. Удаление override возвращает её к общей теме. Цвет фона состояния normal лучше виден, когда указатель находится вне этой кнопки: hover и pressed имеют отдельные записи.

ThemeBasicsDemo.cs
C#
using Reckfell;

public partial class ThemeBasicsDemo : Control
{
    public Button Left { get; private set; } = null!;
    public Button Right { get; private set; } = null!;
    public StyleBoxFlat SharedNormal { get; private set; } = null!;
    public override void _Ready()
    {
        UiSampleStyle.Prepare(this);
        Theme.SetColor("font_color", "Button", Colors.White);
        SharedNormal = (StyleBoxFlat)Theme.GetStylebox("normal", "Button");
        var margin = new MarginContainer(); AddChild(margin); margin.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect, margin: 24);
        var column = new VBoxContainer(); margin.AddChild(column);
        column.AddChild(new Label { Text = UiSampleStyle.Text("Общая тема и локальное изменение", "Shared theme and local override") });
        Left = new Button { Text = UiSampleStyle.Text("Первая кнопка", "First button") };
        Right = new Button { Text = UiSampleStyle.Text("Вторая кнопка", "Second button") };
        column.AddChild(Left); column.AddChild(Right);
        var shared = new Button { Text = UiSampleStyle.Text("Изменить общий фон", "Change shared background") }; column.AddChild(shared);
        shared.Pressed += () => SharedNormal.BgColor = new Color(.08f, .16f, .35f);
        var local = new Button { Text = UiSampleStyle.Text("Отдельный фон первой", "Separate first background") }; column.AddChild(local);
        local.Pressed += SeparateLeft;
        var reset = new Button { Text = UiSampleStyle.Text("Убрать локальное изменение", "Remove local override") }; column.AddChild(reset);
        reset.Pressed += () => Left.RemoveThemeStyleboxOverride("normal");
    }

    public void SeparateLeft()
    {
        var own = (StyleBoxFlat)Left.GetThemeStylebox("normal").Duplicate();
        own.BgColor = new Color(.12f, .28f, .7f);
        Left.AddThemeStyleboxOverride("normal", own);
    }
}

Как выбирается значение

Для обычного запроса Control сначала проверяет своё локальное переопределение. Затем ищет в темах ветви от ближайшего владельца к родителям; внутри каждой темы учитывает вариацию и цепочку типов. После ветви используются проектная/стандартная темы и резервные значения.

Владелец темы здесь — Control или Window с ресурсом Theme в цепочке UI, а не свойство Entity.Owner, используемое при сохранении иерархии. Обычная Entity между элементами разрывает наследование: Control(Theme) → Entity → Button не передаёт тему кнопке. Для UI-группировки используйте Control/Container либо явно назначьте Theme дочернему UI-корню. Изменение Entity.Owner не восстанавливает наследование.

Это порядок «ближайшая тема, затем её типы», а не глобальное правило «вариация всегда сильнее Button везде». Частичная локальная тема может заменить только один параметр, а остальные получить выше. Control.GetThemeColor/GetThemeStylebox возвращают разрешённое для элемента значение. Theme.GetColor/GetStylebox читают сам ресурс и не обходят иерархию Control.

ИзменениеГде действует
AddThemeColorOverride у одной кнопкиТолько этот Control; RemoveThemeColorOverride отменяет исключение
SetColor в общей ThemeНа пользователей этой записи, если более близкое значение её не перекрыло
Изменение общего StyleBoxFlatНа все элементы, разделяющие ресурс
Duplicate StyleBox и локальный overrideНа отдельную копию

Duplicate без глубокого копирования достаточно для показанного StyleBoxFlat. Для ресурса с вложенными изменяемыми ресурсами проверьте, какие из них всё ещё разделяются; глубокое копирование имеет собственные правила ресурсов. Получение GetThemeStylebox не создаёт независимую копию.

Для диагностики различайте три вопроса:

ПроверкаЧто показывает
Theme.HasColor("font_color", "Button")Есть ли такая запись в конкретном ресурсе
button.HasThemeColorOverride("font_color")Есть ли локальное исключение именно у кнопки
button.GetThemeColor("font_color")Какое значение получено после поиска по темам

Практический порядок настройки

Сначала задайте типографику, внутренние отступы и обычные состояния. Затем hover, pressed, disabled и заметный focus. Ширина рамки/отступы StyleBox могут менять требуемый размер; проверьте раскладку с длинными переводами. Modulate меняет итоговый рисунок целиком и не заменяет настройку конкретного цвета темы.

Для нескольких локальных изменений можно использовать BeginBulkThemeOverride/EndBulkThemeOverride, чтобы объединить уведомления. Завершайте блок через finally при возможном исключении: незавершённый bulk оставляет уведомления отложенными. Это флаг, а не счётчик вложенности; не вкладывайте такие блоки друг в друга. Удаляйте устаревшие overrides при переходе на общую тему: иначе они продолжат перекрывать новый дизайн. Для проекта целиком есть gui/theme/custom, для шрифта — gui/theme/custom_font; эти настройки требуют соответствующего перезапуска.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.