Modding:GUI

From Vintage Story Wiki
This page is a translated version of the page Modding:GUIs and the translation is 100% complete.

Эта страница проверялась в последний раз для версии Vintage Story 1.15.

Other languages:

Создание хороших графических пользовательских интерфейсов — непростая задача, иногда даже самые крупные компании допускают ошибки.

В Vintage Story в настоящее время вам нужно сформулировать свои графические интерфейсы в коде, что требует острого пространственного мышления. Надеюсь, когда-нибудь у нас появится конструктор графического интерфейса типа «укажи и щелкни», который снимет много работы. До тех пор, вот некоторые из предметов первой необходимости.

Protip:

 Используйте привязку клавиши отладки для «циклических режимов контура диалогового окна» при создании графического интерфейса. Он нарисует контуры вокруг границ вашего графического интерфейса, что значительно упростит понимание того, как ваш код переводится в визуальный графический интерфейс.

Начиная

Вы должны инкапсулировать каждый диалог GUI в свой собственный класс, хотя диалог может состоять из нескольких окон - например, диалоговое окно ванильного персонажа имеет два - одно для носимых игроков и одно для статистики игрока. Есть пара базовых классов, которые немного облегчат вам жизнь.

Графический интерфейс объекта блокировки

Чтобы создать графический интерфейс, привязанный к блочному объекту, наследуйте от GuiDialogBlockEntity. Затем в коде вашего блока вы можете создать и открыть этот графический интерфейс, например. при взаимодействии с игроком (пример: сущность блока жернова, master/Gui/GuiDialogBlockEntityQuern.cs Диалог блока жернова)

HUD

Чтобы создать элемент графического интерфейса, с которым нельзя взаимодействовать, наследуйте от HudElement.

Графический интерфейс общего назначения

Для любого другого использования наследуйте от класса общего назначения GuiDialog, от которого также наследуются HudElement и GuiDialogBlockEntity. Вы можете переопределить ToggleKeyCombinationCode на что-то вроде «yourAweseomeHotkeyCode» и использовать capi.Input.RegisterHotKey + capi.Input.SetHotKeyHandler, чтобы получить собственную клавишу клавиатуры. сопоставляется с открытием/закрытием вашего графического интерфейса (пример: World Map)

Основы графического интерфейса

В общем, вы можете создать свою собственную систему графического интерфейса, если хотите, просто переопределив OnRenderGUI и визуализируя все, что вам нравится. Также существует множество переопределяемых методов для обработки ввода с клавиатуры и мыши, см. также класс GuiDialog на Github.

Если вы хотите использовать ванильную систему графического интерфейса, ее концепция представляет собой просто плоский или иерархический список элементов графического интерфейса, размещенных в определенных позициях. Позиция определяется экземпляром ElementBounds. Рассмотрим подробнее его свойства:

Границы Элемента

  • FixedX/FixedY: абсолютное положение, в котором должен быть размещен элемент.
  • FixedWidth/FixedHeight: абсолютная ширина и высота элемента.
  • FixedPaddingX/FixedPaddingY: абсолютное внутреннее заполнение элемента.
  • FixedMarginX/FixedMarginY: абсолютное внешнее заполнение элемента
  • ParentBounds: родительские границы, в которых находится этот элемент.
  • ChildBounds: дочерние границы, которые содержит этот элемент.
  • Alignment: Выравнивание элемента. Если установлено значение None, используется фиксированная позиция X/Y. Для любого другого значения значения FixedX/Y игнорируются. Например, когда вы использовали RightTop, элемент всегда будет находиться в правом верхнем углу своих родительских границ. Если вы используете RightFixed, элемент будет выровнен по правому краю, но его Y-позиция определяется FixedY
  • HorizontalSizing/VerticalSizing: используемый метод изменения размера может быть либо Fixed (по умолчанию), Percentual, либо FitToChildren

GuiComposer

Это компонент, который создает и управляет вашими элементами графического интерфейса для вас. Вы можете создать композитор через клиентский API: capi.Gui.CreateCompo(dialogName, bounds). Вы должны предоставить ему уникальный идентификатор и общие границы диалога. Когда у вас есть экземпляр GUIComposer, вы можете последовательно добавлять элементы. Вот небольшой пример:

private void SetupDialog()
{
    // Auto-sized dialog at the center of the screen
    ElementBounds dialogBounds = ElementStdBounds.AutosizedMainDialog.WithAlignment(EnumDialogArea.CenterMiddle);

    // Just a simple 300x300 pixel box
    ElementBounds textBounds = ElementBounds.Fixed(0, 0, 300, 300);
        
    SingleComposer = capi.Gui.CreateCompo("myAwesomeDialog", dialogBounds)
        .AddStaticText("This is a piece of text at the center of your screen - Enjoy!", CairoFont.WhiteDetailText(), textBounds)
        .Compose()
    ;
}

Some explanations:

  • ElementStdBounds: Contains a bunch of often used element bounds configurations. See also ElementStdBounds on Github.
  • ElementBounds.Fixed(0, 0, 300, 300): Create a new bounds instance with fixedX/Y at 0/0 and a fixed widt/height of 300/300 pixels.
  • CairoFont.WhiteDetailText(): Create a new font configuration based on a often used size and color, in this case white with font size 14
  • SingleComposer: This property is defined in the GuiDialog class. Its a getter/setter to the Composers dictionary. It contains all the "windows" of this dialog which are then rendered / handled by this GuiDialog instance

Fancying it up

This is of course the absolute minimum example that will only show some text. Let's add a title bar and a dialog background:

private void SetupDialog()
{
    // Auto-sized dialog at the center of the screen
    ElementBounds dialogBounds = ElementStdBounds.AutosizedMainDialog.WithAlignment(EnumDialogArea.CenterMiddle);

    // Just a simple 300x100 pixel box with 40 pixels top spacing for the title bar
    ElementBounds textBounds = ElementBounds.Fixed(0, 40, 300, 100);

    // Background boundaries. Again, just make it fit it's child elements, then add the text as a child element
    ElementBounds bgBounds = ElementBounds.Fill.WithFixedPadding(GuiStyle.ElementToDialogPadding);
    bgBounds.BothSizing = ElementSizing.FitToChildren;
    bgBounds.WithChildren(textBounds);

    SingleComposer = capi.Gui.CreateCompo("myAwesomeDialog", dialogBounds)
        .AddShadedDialogBG(bgBounds)
        .AddDialogTitleBar("Heck yeah!", OnTitleBarCloseClicked)
        .AddStaticText("This is a piece of text at the center of your screen - Enjoy!", CairoFont.WhiteDetailText(), textBounds)
        .Compose()
    ;
}

private void OnTitleBarCloseClicked()
{
    TryClose();
}

This covers some of the most basic parts. There is a grand amount of various pre-built UI elements that each come with their own argument list that are in dire need of Documentation. Here's an overview of some of the more commonly used ones

Dialog / Graphics

  • .AddShadedDialogBG: Draws a pretty background and dialog border
  • .AddDialogTitleBar: Draws a title bar with a close button and a button to move around the dialog
  • .AddInset: Adds a darkened section with a inset border around it

Text

  • .AddStaticText: Add a static snippet of text
  • .AddDynamicText: Add a snippet of text that can be set to other texts without the need to redraw the whole dialog
  • .AddRichtext: Same as .AddDynamicText but allows use of VTML - a minimalist version of HTML code
  • .AddHoverText: When the mouse cursor moves over the element boundaries, will show supplied text as a tooltip

UI Control/Input

  • .AddButton: Adds a clickable button
  • .AddDropDown: Adds a drop down element
  • .AddHorizontalTabs: Adds horizontally aligned tabs, like the ingame chat window has
  • .AddVerticalScrollbar: Adds a vertical scrollbar
  • .AddTextInput: Adds an single line editable text field
  • .AddNumberInput: Adds an editable text field built for entering numbers
  • .AddTextArea: Adds multiple line editable text field

Tables/Grids/Inventory

Other

  • .AddIf/.EndIf: Can be used to conditionally add certain elements (but you can also just split up your creation code for more fine grained control)
  • .BeginClip/.EndClip: Used in combination with a scrollbar to cut away oversized content, such as in the creative inventory
  • .AddStaticCustomDraw: Lets you define your own drawing code to be added to the GUI

Examples

A simple standard dialog, triggered by the keyboard key 'U'

public class GuiDialogAnnoyingText : GuiDialog
{
    public override string ToggleKeyCombinationCode => "annoyingtextgui";

    public GuiDialogAnnoyingText(ICoreClientAPI capi) : base(capi)
    {
        SetupDialog();
    }

    private void SetupDialog()
    {
        // Auto-sized dialog at the center of the screen
        ElementBounds dialogBounds = ElementStdBounds.AutosizedMainDialog.WithAlignment(EnumDialogArea.CenterMiddle);

        // Just a simple 300x300 pixel box
        ElementBounds textBounds = ElementBounds.Fixed(0, 40, 300, 100);

        // Background boundaries. Again, just make it fit it's child elements, then add the text as a child element
        ElementBounds bgBounds = ElementBounds.Fill.WithFixedPadding(GuiStyle.ElementToDialogPadding);
        bgBounds.BothSizing = ElementSizing.FitToChildren;
        bgBounds.WithChildren(textBounds);

        // Lastly, create the dialog
        SingleComposer = capi.Gui.CreateCompo("myAwesomeDialog", dialogBounds)
            .AddShadedDialogBG(bgBounds)
            .AddDialogTitleBar("Heck yeah!", OnTitleBarCloseClicked)
            .AddStaticText("This is a piece of text at the center of your screen - Enjoy!", CairoFont.WhiteDetailText(), textBounds)
            .Compose()
        ;
    }

    private void OnTitleBarCloseClicked()
    {
        TryClose();
    }
}

public class AnnoyingTextSystem : ModSystem
{
    ICoreClientAPI capi;
    GuiDialog dialog;

    public override bool ShouldLoad(EnumAppSide forSide)
    {
        return forSide == EnumAppSide.Client;
    }
        
    public override void StartClientSide(ICoreClientAPI api)
    {
        base.StartClientSide(api);

        dialog = new GuiDialogAnnoyingText(api);

        capi = api;
        capi.Input.RegisterHotKey("annoyingtextgui", "Annoys you with annoyingly centered text", GlKeys.U, HotkeyType.GUIOrOtherControls);
        capi.Input.SetHotKeyHandler("annoyingtextgui", ToggleGui);
    }

    private bool ToggleGui(KeyCombination comb)
    {
        if (dialog.IsOpened()) dialog.TryClose();
        else dialog.TryOpen();

        return true;
    }
}


TBD

More to come here in the future.

Icon Sign.png

Wondering where some links have gone?
The modding navbox is going through some changes! Check out Navigation Box Updates for more info and help finding specific pages.

Modding
Modding Introduction Getting Started Пакет тем
Content Modding Content Mods Developing a Content Mod Basic Tutorials Intermediate Tutorials Advanced Tutorials Content Mod Concepts
Code Modding Code Mods Setting up your Development Environment
Property Overview ItemEntityEntity BehaviorsBlockBlock BehaviorsBlock ClassesBlock EntitiesBlock Entity BehaviorsCollectible BehaviorsWorld properties
Workflows & Infrastructure Modding Efficiency TipsMod-engine compatibilityMod ExtensibilityVS Engine
Additional Resources Community Resources Modding API Updates Programming Languages List of server commandsList of client commandsClient startup parametersServer startup parameters
Example ModsAPI DocsGitHub Repository