The only King Arthur's Gold UI mod you'll ever need. Build responsive user interfaces with ease using modular components.
- Modular: Components can be combined in various ways to build any layout you desire.
- Familiar: The standard UI components provided out of the box match KAG's iconic style.
- Responsive: Components can be dynamically resized and everything will adjust accordingly.
- Extensible: Components can easily be inherited to alter the look or behaviour to fit your needs.
- Optimised: Components recalculate their bounds only when necessary so complex UIs run fast.
- Effortless: Seamlessly integrate a fully-featured UI experience into any mod with a single #include.
- Download and unzip
EasyUI.zip
from the latest release. - Put the contained
EasyUI
folder in yourMods
folder. - Add
EasyUI
to a new line inmods.cfg
above any mod that will use it. - Build, update, and render your UI in a new or existing client-only script.
#include "EasyUI.as"
#define CLIENT_ONLY
EasyUI@ ui;
void onInit(CRules@ this)
{
onRestart(this);
}
void onRestart(CRules@ this)
{
@ui = EasyUI();
Label@ label = StandardLabel();
label.SetText("This pane is centered on the screen and stretches horizontally!");
Pane@ pane = StandardPane();
pane.SetMargin(200, 0);
pane.SetPadding(20, 20);
pane.SetAlignment(0.5f, 0.5f);
pane.SetStretchRatio(1.0f, 0.0f);
pane.SetMaxSize(600, 0);
pane.AddComponent(label);
ui.AddComponent(pane);
}
void onTick(CRules@ this)
{
ui.Update();
}
void onRender(CRules@ this)
{
ui.Render();
// ui.Debug(getControls().isKeyPressed(KEY_LSHIFT));
}
- Components are positioned relative to their parent or the screen if they are a root component. Therefore, it is not possible to set the (x, y) position of a component.
- Components can never exceed or extend beyond their parent's bounds. The parent will always grow to fit its children.
- Components stretch to fill their parent. The stretched bounds will never cause the parent's bounds to grow.
- All input components require the
EasyUI
instance to be passed into the constructor. This is so the components can query the component tree to determine if they can be interacted with. - It is recommended that the model-view-controller design pattern be used for developing dynamic UIs. Use the game and player state (controller) to manipulate the data (model) that is displayed in the UI (view). The various
Set...()
methods should be used to update the UI with the data from the model rather than directly from game and player state.
Position and bounds
minimum bounds
┌──────────┴──────────┐
position ──────>┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
true position ──|─>┏━━━━━━━━━━━━━━━┓ |<────── bounds
inner position ─|──┃─>┌ ─ ─ ─ ─ ┐ ┃<─|── true bounds
| ┃ | epsilon |<─┃──|─ inner bounds
| ┃ └ ─ ─ ─ ─ ┘ ┃ |
| ┗━━━━━━━━━━━━━━━┛ |
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
└┬─┘ └─┬┘
margin padding
Composition and stretch
Note: This diagram depicts stretching for stack-based components; stretching in list-based components behaves slightly differently. Children don't stretch to the list's inner bounds; they instead stretch to fill the cell they occupy which is a division of the list's inner bounds.
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
parent minimum bounds ─>| ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ |
| ┃ ┏━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ |
parent true bounds ─────|─>┃ ┃ ┃ ┃ |
| ┃ ┃ ┃<─┃──|───────── child bounds
parent inner bounds ────|──┃─>┃ ┌ ─ ─ ─ ─ ┐ ┃ ┃ |
| ┃ ┃ | |<──────┃──┃──|─ child minimum bounds
| ┃ ┃ └ ─ ─ ─ ─ ┘ ┃ ┃ |
| ┃ ┃ ┃ ┃ |
| ┃ ┃ ┃ ┃ |
| ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ |
| ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ |
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
└┬─┘ └┬──────┘ └─┬┘
parent padding child 100% stretch parent margin
Category | Components |
---|---|
Input | StandardButton • StandardVerticalSlider • StandardHorizontalSlider • StandardToggle |
Informational | StandardAvatar • StandardIcon • StandardLabel • StandardHorizontalProgress |
Container | StandardList • StandardPane • StandardStack |
Planned: Dropdown, Minimap, Radio Button, Tile, Vertical Progress
Important
Only methods that should be used by modders are documented here. Other methods exposed on each interface are required for the UI system to work and should never be used.
The base interface implemented by all components.
Implemented by: Avatar, Button, Icon, Label, List, Pane, Progress, Slider, Stack, Toggle
Source code: Component.as
Add margin outside the visible bounds of the component.
Minimum: 0.0f, 0.0f
Default: 0.0f, 0.0f
void SetMargin(float x, float y);
Vec2f getMargin();
Add padding inside the visible bounds of the component.
Minimum: 0.0f, 0.0f
Default: 0.0f, 0.0f
void SetPadding(float x, float y);
Vec2f getMargin();
Align the component relative to its parent. The component is aligned relative to the screen if it is at the root.
Range: 0.0f, 0.0f
– 1.0f, 1.0f
Default: 0.0f, 0.0f
void SetAlignment(float x, float y);
Vec2f getAlignment();
Examples:
0.0f, 0.0f
means the component will align its top left corner to the top left corner of its parent.0.5f, 0.5f
means the component will be aligned to the middle of its parent.1.0f, 1.0f
means the component will align its bottom right corner to the bottom right corner of its parent.
Stretch the component to fill its parent. The component stretches to fill the screen if it is at the root.
Range: 0.0f, 0.0f
– 1.0f, 1.0f
Default: 0.0f, 0.0f
void SetStretchRatio(float x, float y);
Vec2f getStretchRatio();
Examples:
0.0f
on the x-axis means the component will stretch to 0% of its parent's width which the minimum size will always exceed.0.5f
on the x-axis means the component will stretch to 50% of its parent's width unless the minimum size exceeds this.1.0f
on the x-axis means the component will stretch to 100% of its parent's width.
Require the component to have a minimum size. The minimum size ignores margin.
Minimum: 0.0f, 0.0f
Default: 0.0f, 0.0f
void SetMinSize(float width, float height);
Vec2f getMinSize();
Restrict the component to a maximum size if it stretches, unless its children exceed this size. The maximum size ignores margin.
Minimum: 0.0f, 0.0f
Default: 0.0f, 0.0f
void SetMaxSize(float width, float height);
Vec2f getMaxSize();
The visibility of the component. If the component is hidden, all its children are hidden.
Default: true
void SetVisible(bool visible);
bool isVisible();
Add children to the component. Children can never exceed the bounds of the component.
void AddComponent(Component@ component);
void SetComponents(Component@[] components);
Component@[] getComponents();
Get the various positions of the component. Components are always positioned relative to its parent or screen and cannot be positioned manually.
// The position before margin or padding are applied
Vec2f getPosition();
// The true position after margin is applied
Vec2f getTruePosition();
// The inner position after margin and padding are applied
Vec2f getInnerPosition();
Get the various bounds of the component.
// The minimum bounds the component can be
// Takes into account margin, padding, and the minimum bounds of child components
Vec2f getMinBounds();
// The stretched bounds with margin and padding applied
Vec2f getBounds();
// The stretched bounds with only padding applied
Vec2f getTrueBounds();
// The stretched bounds before margin and padding are applied
Vec2f getInnerBounds();
Check various mouse-related attributes of the component.
// Is the mouse within the component's bounds
bool isHovering();
// Can the component be clicked if it is hovered and unobstructed
bool canClick();
// Can the component be scrolled down if it is hovered and unobstructed
bool canScrollDown();
// Can the component be scrolled up if it is hovered and unobstructed
bool canScrollUp();
A component that stacks its children on top of each other.
Implements: Component
Implemented by: Avatar, Icon, Label
Source code: Stack.as
No stack-specific methods.
A component that lists its children one after the other.
Implements: Component
Implemented by: Button, List, Pane, Progress, Slider, Stack, Toggle
Source code: List.as
The spacing between the component's children.
Minimum: 0.0f, 0.0f
Default: 0.0f, 0.0f
void SetSpacing(float x, float y);
Vec2f getSpacing();
The number of children that can be listed on the same row/column before they wrap.
Minimum: 1
Default: 1
void SetCellWrap(uint cells);
uint getCellWrap();
The direction children flow and wrap.
Default: FlowDirection::RightDown
void SetFlowDirection(FlowDirection direction);
FlowDirection getFlowDirection();
Valid values:
- Top left:
FlowDirection::RightDown
/FlowDirection::DownRight
- Top right:
FlowDirection::LeftDown
/FlowDirection::DownLeft
- Bottom right:
FlowDirection::RightUp
/FlowDirection::UpRight
- Bottom left:
FlowDirection::LeftUp
/FlowDirection::UpLeft
Examples:
FlowDirection::RightDown
means children are listed from left to right and wrap down onto new rows.FlowDirection::DownRight
means children are listed from top to bottom and wrap right onto new columns.
The maximum number of lines before the list requires scrolling to view all children.
Default: 0
(no maximum)
void SetMaxLines(uint lines);
uint getMaxLines();
The number of lines to scroll.
Default: 0
void SetScrollIndex(uint index);
uint getScrollIndex();
The relative size of each column for when children stretch.
Default: {}
(equally sized columns)
void SetColumnSizes(float[] sizes);
float[] getColumnSizes();
Implementation notes:
- If the array of sizes is too short compared to the number of columns, the remaining columns will assume a value of
0
(minimum stretch). For example,{ 2, 1 }
and{ 2, 1, 0 }
are identical when there are only two columns. - If the array of sizes is too long compared to the number of columns, the extra values are ignored. For example,
{ 1, 2, 3 }
and{ 1, 2 }
are identical when there are only two columns. - If the array of sizes is empty or contains only zeros, each column will be equally sized. For example,
{}
,{ 0, 0 }
, and{ 1, 1 }
are identical when there are two columns.
Examples:
{ 2, 3 }
means the first column will stretch two-fifths of the component's inner width and the second column will stretch three-fifths.{ 0, 1 }
means the first column will have minimum stretch and the second column will stretch to fill the component's remaining inner width.
The relative size of each row for when children stretch.
Default: {}
(equally sized rows)
void SetColumnSizes(float[] sizes);
float[] getColumnSizes();
The implementation notes and examples mentioned for column sizes applies to row sizes as well.
A component that displays a player's avatar from the Transhuman Design Forum.
Implements: Stack
Source code: Avatar.as
Implementation notes:
- If a player isn't configured, doesn't have a forum account, or doesn't have profile picture set, a black image will be displayed.
- The avatar can only be drawn with a 1:1 aspect ratio, so black bars will be present if the component has a non-square size.
The player whose avatar should be displayed.
Default: null
void SetPlayer(CPlayer@ player);
CPlayer@ getPlayer();
A button that can be hovered and pressed. A sound is played when it is clicked.
Implements: List
Source code: Button.as
Check whether the button is being pressed.
bool isPressed();
A component that displays an icon.
Implements: Stack
Source code: Icon.as
The texture that contains the icon.
Default: ""
void SetTexture(string texture);
string getTexture();
Set the index of the icon frame in the texture.
Minimum: 0
Default: 0
void SetFrameIndex(uint index);
uint getFrameIndex();
The dimensions of the icon frame in the texture.
Minimum: 0.0f
Default: 0.0f, 0.0f
void SetFrameDim(uint width, uint height);
Vec2f getFrameDim();
The icon can be cropped if it is too small compared to its frame dimensions.
Default: 0.0f, 0.0f, 0.0f, 0.0f
void SetCrop(float top, float right, float bottom, float left);
Whether the icon should maintain its aspect ratio regardless of the size of the component.
Default: true
void SetFixedAspectRatio(bool fixed);
bool isFixedAspectRatio();
Whether the icon is clickable to allow for icon buttons.
Default: false
void SetClickable(bool clickable);
A component that displays text.
Implements: Stack
Source code: Label.as
The text to display.
Default: ""
void SetText(string text);
string getText();
The font to display the text as.
Default: "menu"
(default KAG font)
void SetFont(string font);
string getFont();
The color of the text.
Default: white
void SetColor(SColor color);
SColor getColor();
Whether the text can wrap. Wrapped text must have a minimum width configured.
Default: false
void SetWrap(bool wrap);
bool getWrap();
The maximum number of lines before the text is truncated with ellipsis (...). This only comes into effect if the text can wrap.
Default: 1
(truncate on the first line)
void SetMaxLines(uint lines);
uint getMaxLines();
A component that displays a rectangular pane.
Implements: List
No pane-specific methods.
A component that displays a progress bar.
Implements: List
Source code: Progress.as
The progress percentage.
Range: 0.0f
– 1.0f
Default: 0.0f
void SetPercentage(float percentage);
float getPercentage();
A component that displays a slider whose handle can be dragged.
Implements: List
Source code: Slider.as
The percentage of the handle.
Range: 0.0f
– 1.0f
Default: 0.0f
void SetPercentage(float percentage);
float getPercentage();
A button that toggles when clicked.
Implements: Button
Source code: ToggleButton.as
Whether the button is toggled.
Default: false
void SetChecked(bool checked);
bool isChecked();