Confirmedusers, Bureaucrats, editor, Administrators
1,522
edits
No edit summary |
VeryGoodDog (talk | contribs) m (VeryGoodDog moved page GUIs to Modding:GUIs) |
||
(19 intermediate revisions by one other user not shown) | |||
Line 4: | Line 4: | ||
== Starting out == | == Starting out == | ||
You should encapsulate every GUI Dialog into its own class, albeit a dialog may consist of multiple windows - the vanilla character dialog for example has two - one for the players wearables and one for the player stats. There's a couple of | You should encapsulate every GUI Dialog into its own class, albeit a dialog may consist of multiple windows - the vanilla character dialog for example has two - one for the players wearables and one for the player stats. There's a couple of base classes to make your live a bit easier. | ||
===Block Entity GUI=== | |||
To create a GUI that's bound to a block entity, inherit from <code>GuiDialogBlockEntity</code>. In your block entity code you can then create and open that gui e.g. upon player interaction (example: [https://github.com/anegostudios/vssurvivalmod/blob/master/BlockEntity/BEQuern.cs#L544 Quern Block Entity], [https://github.com/anegostudios/vssurvivalmod/blob/master/Gui/GuiDialogBlockEntityQuern.cs Quern Block Dialog]) | |||
===HUD=== | |||
To create a GUI element which is not interactable, inherit from <code>HudElement</code>. | |||
===General Purpose GUI=== | |||
For any other uses, inerhit from the general purpose class <code>GuiDialog</code>, from which HudElement and GuiDialogBlockEntity also inherit from. You can override <code>ToggleKeyCombinationCode</code> to something like "yourAweseomeHotkeyCode" and use <code>capi.Input.RegisterHotKey</code> + <code>capi.Input.SetHotKeyHandler</code> to have your own keyboard key mapped to opening/closing your GUI (example: [https://github.com/anegostudios/vsessentialsmod/blob/master/Systems/WorldMap/WorldMapManager.cs#L105 World Map]) | |||
== GUI Basics == | == GUI Basics == | ||
Line 25: | Line 33: | ||
* <code>ChildBounds</code>: The child boundaries this element contains | * <code>ChildBounds</code>: The child boundaries this element contains | ||
* <code>Alignment</code>: The alignment of the element. If set to <code>None</code> the FixedX/Y Position is used. For any other value the FixedX/Y values are ignored. For example when you used <code>RightTop</code> the element will always be at the right top most corner of its parent bounds. If you use <code>RightFixed</code> the element will be right aligned, but its Y-Position is determined by <code>FixedY</code> | * <code>Alignment</code>: The alignment of the element. If set to <code>None</code> the FixedX/Y Position is used. For any other value the FixedX/Y values are ignored. For example when you used <code>RightTop</code> the element will always be at the right top most corner of its parent bounds. If you use <code>RightFixed</code> the element will be right aligned, but its Y-Position is determined by <code>FixedY</code> | ||
* <code>HorizontalSizing</code>/<code>VerticalSizing</code>: The sizing method to be used, can be either <code>Fixed</code> (default), <code>Percentual</code> or <code>FitToChildren</code> | |||
===GuiComposer=== | ===GuiComposer=== | ||
Line 31: | Line 40: | ||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#"> | ||
// Auto-sized dialog at the center of the screen | private void SetupDialog() | ||
ElementBounds dialogBounds = ElementStdBounds.AutosizedMainDialog.WithAlignment(EnumDialogArea.CenterMiddle); | { | ||
// Auto-sized dialog at the center of the screen | |||
ElementBounds dialogBounds = ElementStdBounds.AutosizedMainDialog.WithAlignment(EnumDialogArea.CenterMiddle); | |||
SingleComposer = capi.Gui.CreateCompo("myAwesomeDialog", dialogBounds) | // 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() | |||
; | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Some explanations: | Some explanations: | ||
* <code>ElementStdBounds</code>: Contains a bunch of often used element bounds configurations. See also | * <code>ElementStdBounds</code>: Contains a bunch of often used element bounds configurations. See also [https://github.com/anegostudios/vsapi/blob/master/Client/UI/ElementStdBounds.cs ElementStdBounds] on Github. | ||
* <code>ElementBounds.Fixed(0, 0, 300, 300)</code>: Create a new bounds instance with fixedX/Y at 0/0 and a fixed widt/height of 300/300 pixels. | * <code>ElementBounds.Fixed(0, 0, 300, 300)</code>: Create a new bounds instance with fixedX/Y at 0/0 and a fixed widt/height of 300/300 pixels. | ||
* <code>CairoFont.WhiteDetailText()</code>: Create a new font configuration based on a often used size and color, in this case white with font size 14 | * <code>CairoFont.WhiteDetailText()</code>: Create a new font configuration based on a often used size and color, in this case white with font size 14 | ||
* <code>SingleComposer</code>: This property is defined in the <code>GuiDialog</code> class. Its a getter/setter to the <code>Composers</code> dictionary. It contains all the "windows" of this dialog which are then rendered / handled by this GuiDialog instance | * <code>SingleComposer</code>: This property is defined in the <code>GuiDialog</code> class. Its a getter/setter to the <code>Composers</code> 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: | |||
<syntaxhighlight lang="c#"> | |||
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(); | |||
} | |||
</syntaxhighlight> | |||
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==== | |||
* <code>.AddShadedDialogBG</code>: Draws a pretty background and dialog border | |||
* <code>.AddDialogTitleBar</code>: Draws a title bar with a close button and a button to move around the dialog | |||
* <code>.AddInset</code>: Adds a darkened section with a inset border around it | |||
====Text==== | |||
* <code>.AddStaticText</code>: Add a static snippet of text | |||
* <code>.AddDynamicText</code>: Add a static snippet of text that can be set to other texts without the need to redraw the whole dialog | |||
* <code>.AddRichtext</code>: Same as <code>.AddDynamicText</code> but allows use of [[VTML]] - a minimalist version of HTML code | |||
* <code>.AddHoverText</code>: When the mouse cursor moves over the element boundaries, will show supplied text as a tooltip | |||
====UI Control/Input==== | |||
* <code>.AddButton</code>: Adds a clickable button | |||
* <code>.AddDropDown</code>: Adds a drop down element | |||
* <code>.AddHorizontalTabs</code>: Adds horizontally aligned tabs, like the ingame chat window has | |||
* <code>.AddVerticalScrollbar</code>: Adds a vertical scrollbar | |||
* <code>.AddTextInput</code>: Adds an single line editable text field | |||
* <code>.AddNumberInput</code>: Adds an editable text field built for entering numbers | |||
* <code>.AddTextArea</code>: Adds multiple line editable text field | |||
====Tables/Grids/Inventory==== | |||
* <code>.AddItemSlotGrid</code>: Create a grid displaying the contents of supplied inventory (example: [https://github.com/anegostudios/vsessentialsmod/blob/master/Gui/GuiDialogCarcassContents.cs GuiDialogCarcassContents]) | |||
* <code>.AddSkillItemGrid</code>: Create a grid of custom elements (example: [https://github.com/anegostudios/vssurvivalmod/blob/master/Gui/GuiDialogBlockEntityRecipeSelector.cs GuiDialogBlockEntityRecipeSelector]) | |||
====Other==== | |||
* <code>.AddIf</code>/<code>.EndIf</code>: Can be used to conditionally add certain elements (but you can also just split up your creation code for more fine grained control) | |||
* <code>.BeginClip</code>/<code>.EndClip</code>: Used in combination with a scrollbar to cut away oversized content, such as in the creative inventory | |||
* <code>.AddStaticCustomDraw</code>: Lets you define your own drawing code to be added to the GUI | |||
== Examples == | |||
A simple standard dialog, triggered by the keyboard key 'U' | |||
<syntaxhighlight lang="c#"> | |||
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; | |||
} | |||
} | |||
</syntaxhighlight> | |||
=== TBD === | === TBD === | ||
More to come here in the future. | More to come here in the future. |