Modding:GUIs: Difference between revisions

From Vintage Story Wiki
m
Updated navbox to new code navbox.
(More accurately describe the ElementBounds fields)
m (Updated navbox to new code navbox.)
 
(16 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{GameVersion|1.19.0}}
{{GameVersion|1.19.3}}


{{#css:
{{#css:
Line 13: Line 13:
<!--T:2-->
<!--T:2-->
In Vintage Story you currently need to formulate your GUIs in code, which requires acute spacial thinking. Hopefully someday we'll have a point&click GUI designer that takes off a lot of work. Until then, here are some of the essentials.
In Vintage Story you currently need to formulate your GUIs in code, which requires acute spacial thinking. Hopefully someday we'll have a point&click GUI designer that takes off a lot of work. Until then, here are some of the essentials.
__TOC__


== Dialog Outline Modes ==
== Dialog Outline Modes ==
Line 23: Line 25:
In addition to the mode 2 rectangles around GuiElements (explained below), bold white rectangles are drawn around GuiComposers.
In addition to the mode 2 rectangles around GuiElements (explained below), bold white rectangles are drawn around GuiComposers.


[[File:Settings-controls tab-mode 1.png|class=pixelated|Controls dialog in outline mode 1<br>The outer, bold white rectangle is from a GuiComposer.]]
[[File:Settings-controls tab-mode 1.png|class=pixelated|frame|none|Controls dialog in outline mode 1<br>The outer, bold white rectangle is from a GuiComposer.]]


=== Mode 2: Element Outlines ===
=== Mode 2: Element Outlines ===
The bounding boxes of GuiElements are drawn as rectangles. The rectangle color is determined by the possibly overridden implementation of [https://apidocs.vintagestory.at/api/Vintagestory.API.Client.GuiElement.html#Vintagestory_API_Client_GuiElement_OutlineColor GuiElement.OutlineColor], which returns a color in [https://github.com/anegostudios/vsapi/blob/9bf26b71970ff2168d6f8534cf6ee4a914087511/Math/ColorUtil.cs#L505 0xAARRGGBB format].
The bounding boxes of GuiElements are drawn as rectangles. The rectangle color is determined by the possibly overridden implementation of [https://apidocs.vintagestory.at/api/Vintagestory.API.Client.GuiElement.html#Vintagestory_API_Client_GuiElement_OutlineColor GuiElement.OutlineColor], which returns a color in [https://github.com/anegostudios/vsapi/blob/9bf26b71970ff2168d6f8534cf6ee4a914087511/Math/ColorUtil.cs#L505 0xAARRGGBB format].


[[File:Settings-controls tab-mode 2.png|class=pixelated|Controls dialog in outline mode 2]]
[[File:Settings-controls tab-mode 2.png|class=pixelated|frame|none|Controls dialog in outline mode 2]]


{| class="wikitable"
{| class="wikitable"
Line 68: Line 70:
[[File:Gui box model.png|box model]]
[[File:Gui box model.png|box model]]


The fields in ElementBounds with the 'abs' prefix should be treated as internal fields. They are written by ElementBounds.CalcWorldBounds. However, these other fields should be set either directly or with helper methods.
The fields in ElementBounds with the 'abs' prefix should be treated as internal fields. They are written by ElementBounds.CalcWorldBounds. However, these other fields may be set either directly or with helper methods.


<!--T:15-->
<!--T:15-->
Line 126: Line 128:
| The sizing method to be used, can be either <code>Fixed</code> (default), <code>Percentual</code> or <code>FitToChildren</code>
| The sizing method to be used, can be either <code>Fixed</code> (default), <code>Percentual</code> or <code>FitToChildren</code>
|}
|}
== Layout ==
Compared to the CSS flow layout algorithm, the GuiComposer layout algorithm is very primitive.
=== Alignment ===
The alignment option can automatically place a child element in any of the 4 corners or 4 edges of the parent. However, the alignment algorithm does nothing to prevent two child elements from overlapping on the same edge/corner. For example, if two text boxes were added to the bottom edge of a dialog, then the two pieces of text would overlap. There are a few options to fix the conflict:
# Use different edges or corners for the two pieces of text.
# Use <code>.WithFixedAlignmentOffset(0, -10)</code> to move one of the children up 10 pixels (relative to the bottom alignment in this example).
# Give up on automatic alignment and used fixed alignment instead, where the child coordinates must be calculated exactly relative to the top-left corner of the parent content box.
Typically one uses fixed alignment to layout the dialog. The functions <code>BelowCopy</code> and <code>RightCopy</code> help calculate the bounds next to the previous bounds.
=== Sizing ===
<code>ElementSizing.FitToChildren</code> tells a parent to automatically size itself so that it contains the bottom-right corner of the padding box for all of its children. Note that unlike the HTML flow layout, the VS layout does not prevent the children from overlapping. So the sizing algorithm is more or less sizing the parent to fit its largest child.


== GUI Basics == <!--T:11-->
== GUI Basics == <!--T:11-->
Line 166: Line 185:
====Tables/Grids/Inventory====
====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>.AddItemSlotGrid</code>: Create a grid displaying the contents of supplied inventory (example: [https://github.com/anegostudios/vsessentialsmod/blob/master/Gui/GuiDialogCreatureContents.cs GuiDialogCreatureContents])
* <code>.AddSkillItemGrid</code>: Create a grid of custom elements (example: [https://github.com/anegostudios/vssurvivalmod/blob/master/Gui/GuiDialogBlockEntityRecipeSelector.cs GuiDialogBlockEntityRecipeSelector])
* <code>.AddSkillItemGrid</code>: Create a grid of custom elements (example: [https://github.com/anegostudios/vssurvivalmod/blob/master/Gui/GuiDialogBlockEntityRecipeSelector.cs GuiDialogBlockEntityRecipeSelector])


Line 173: Line 192:
* <code>.BeginClip</code>/<code>.EndClip</code>: Used in combination with a scrollbar to cut away oversized content, such as in the creative inventory
* <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
* <code>.AddStaticCustomDraw</code>: Lets you define your own drawing code to be added to the GUI
== GuiElements ==
To better show what is rendered by the GuiElements, the screenshots shown below were taken with dialog outlines enabled.
=== GuiElementDialogBackground ===
Draws a pretty background and dialog border. The background is drawn on both the padding and content boxes. Typically one uses <code>ElementBounds.Fill</code> (with padding optionally set) to set the background for the entire dialog. Although it is technically possible to use smaller bounds. The <code>withTitleBar</code> does not actually draw the title bar, but instead moves the top of the background box down <code>GuiStyle.TitleBarHeight</code> units to make room for the title bar.
GuiComposer factory functions:
* <code>.AddShadedDialogBG(ElementBounds bounds, bool withTitleBar = true, double strokeWidth = 5.0, float alpha = 0.75f)</code>
* <code>.AddDialogBG(ElementBounds bounds, bool withTitleBar = true, float alpha = 1f)</code>
<gallery>
File:AddDialogBG.png|class=pixelated|AddDialogBG with a bounding box set to the entire dialog. The blank space at the top is due to the withTitleBar=true parameter.
File:AddShadedDialogBG.png|class=pixelated|thumb|none|AddShadedDialogBG with a bounding box set to the entire dialog. The blank space at the top is due to the withTitleBar=true parameter.
File:AddShadedDialogBG_with_position_offset.png|class=pixelated|thumb|none|AddShadedDialogBG with a bounding box less than the entire dialog. In this case the blur from AddShadedDialogBG is offset incorrectly. AddDialogBG works correctly (not shown).
</gallery>
=== GuiElementDialogTitleBar ===
Draws a title bar with a close button and a button to move around the dialog. The drawBg option is ignored.
GuiComposer factory functions:
* <code>.AddDialogTitleBar(string text, Action onClose = null, CairoFont font = null, ElementBounds bounds = null)</code>: The default null for the bounds will put the title bar in the correct place. The default title bar height is <code>GuiStyle.TitleBarHeight</code>.
<gallery>
File:AddDialogTitleBar.png|class=pixelated|
</gallery>
=== GuiElementInset ===
Adds a darkened section with a inset border around it.
GuiComposer factory functions:
* <code>.AddInset(string text, ElementBounds bounds, int depth = 4, float brightness = 0.85f)</code>
<gallery>
File:AddInset.png|class=pixelated|Inset drawn on top of a background, with 10 units on all sides.
File:AddInset_with_padding.png|class=pixelated|Do not use padding in the inset bounds. Otherwise the rectangle for the darkened section is miscalculated and drawn outside of the embossed border.
</gallery>
=== GuiElementStaticText  ===
Add a static snippet of text.
GuiComposer factory functions:
* <code>.AddStaticText(string text, CairoFont font, ElementBounds bounds, string key = null)</code>
* <code>.AddStaticText(string text, CairoFont font, EnumTextOrientation orientation, ElementBounds bounds, string key = null)</code>
* <code>.AddStaticTextAutoBoxSize(string text, CairoFont font, EnumTextOrientation orientation, ElementBounds bounds, string key = null)</code>: adds text and resizes the bounding box such that the text fits on one line. Since the bounds are updated immediately, this may be useful for adding additional components to the right of the text. After calling <code>AddStaticTextAutoBoxSize</code>, one could use <code>newbounds.FixedRightOf(textbounds)</code>,  <code>newbounds.RightOf(textbounds)</code>, or  <code>textbounds.RightCopy()</code>.
* <code>.AddStaticTextAutoFontSize(string text, string text, CairoFont font, ElementBounds bounds, string key = null)</code>: attempts to shrink the font size such that the text fits in one line in <code>bounds</code>.
The standard fonts can be obtained through static factory methods inside of CairoFont. These are commonly used:
* <code>CairoFont.WhiteSmallText()</code>
* <code>CairoFont.WhiteDetailText()</code>
The text orientation would more accurately be called the text justification. It defaults to the font's justification, which is typically left. The options are:
* <code>Left</code>
* <code>Right</code>
* <code>Center</code>
* <code>Justify</code>: does the same thing as Left.
The key option is used to find the static text later with <code>GuiElementStaticText.GetStaticText(SingleComposer, key)</code>.
<gallery>
File:AddStaticText.png|class=pixelated|WhiteSmallText drawn on top of a dialog background, with 10 units of padding.
File:AddStaticTextAutoBoxSize.png|class=pixelated|<code>AddStaticTextAutoBoxSize</code> auto sized the text box such that the single line of text was clipped by the dialog bounds.
File:AddStaticTextAutoFontSize.png|class=pixelated|<code>AddStaticTextAutoFontSize</code> attempted to shrink down the font so that it could fit on a single line.
</gallery>


== Example ==
== Example ==
Line 302: Line 386:
</syntaxhighlight>
</syntaxhighlight>


{{Navbox/modding|Vintage Story}}
{{Navbox/codemodding}}
Confirmedusers
637

edits