-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Welcome to the RHF wiki! If you'd like to jump straight into implementation/usage, see the link to the installation instructions in the sidebar and the example mod here, but to get a clear idea of this framework's features and capabilities, I recommend starting with the overview below:
UI elements are organized into a tree, and each node in the tree has a parent element and a list of children. Depth sorting and Z-Offsets aside, the elements in this tree are updated and drawn depth-first such that the parent node draws, then the first child draws, and that child, in turn, updates its first child, so on and so forth.
-
The Z-Offset property can be used to force an element and its children to draw earlier or later (affects input as well), as you might do for something like a dropdown menu in order to ensure that the dropdown's list draws in front of anything it's supposed to occlude.
-
Draw depth is the change in draw order due to depth sorting caused by differences in distance from the camera between different HUD Space Nodes. This is expanded on further on the HUD Spaces page.
Update Methods:
Each UI Node has four update methods:
-
Layout: As the name suggests,
Layout()
is used to update the Layout of the element and its child nodes, i.e. their size, position, and visibility. The order Layout is updated is depends solely on the node's position in the tree. -
Draw: Used to immediately draw billboards. You likely won't be using this very often, if ever, but if you do need to draw your own billboards directly, this is the place to do it. The update order for this method is dependent on Z-Offset and Draw depth, in addition to the node's position in the tree.
-
InputDepth: This is primarily used to determine whether the cursor is within the element's bounds and to do depth testing to see if there are any closer elements in front before running
HandleInput()
. The update order for this method is dependent on Z-Offset and Draw depth, in addition to the node's position in the tree. You probably won't ever need to override this, but if you do, now you know what it's for. -
HandleInput: This is where you'll be handling input. Shocking, right?
HandleInput()
executes afterDraw()
, and like it, is affected by Z-Offset and Draw depth, but unlike it, input is updated in the reverse order such that the elements that are drawn last (and on top) have their input updated first. This gives the top-most elements the opportunity to capture the cursor first, provided you're not sharing the cursor (the default behavior).
For the vast majority of use cases, Layout()
and HandleInput()
are the only methods you'll ever need to override, but it's helpful to know what the others are for if only to know when you shouldn't use them.
Node Base Types:
These are the base types that form the basis for every element in the library:
-
HudParentBase:
The base type for every other UI element. It has no definite size, position, or parent node, but it does have properties for Visibility and Z-Offset. Every child node is affected by these properties, but the behavior is a little different for each one:
-
Visibility: For a child node to be visible, both it and its parent must be visible.
-
Z-Offset: A sum of the Z-Offset of its parent node and its own.
-
HudNodeBase: The simplest parent-able UI element, but like parent base, it has no definite size or position.
-
HudSpaceNodeBase: Implements IReadOnlyHudSpaceNode and is the base type for nodes used to define a HUD Space. A HUD Space is a coordinate space defined by a Plane-To-World matrix transform that can be used to draw UI elements in world space with arbitrary matrix transforms. You can find more information about HUD Spaces here.
The closest parent space node in the parent tree is the one that will be used by child elements on draw.
-
HudElementBase: The simplest base type with definite size and position. This is the base class for most UI elements in the library, and that's probably true of anything you might make as well. The units used for sizing and positioning depend on the coordinate system used by the associated HUD Space. For the built-in HudMain.Root node, these units are in pixels with the origin in the center of the screen. Alternatively, HighDpiRoot, as the name suggests, is for high DPI displays and is automatically updated to normalize scaling for resolutions > 1080p.
- Size: The dimensions of the element + padding
- Padding: Extra spacing around the element.
- Origin: The position of its parent, if the parent exists and derives from HudElementBase. Defaults to zero.
- Offset: Displacement from the origin.
- ParentAlignment: Enum used to determine the starting position of the element relative to its parent (inner right, outer left, etc.).
- DimAlignment: Enum used to determine whether it should match its parent's size, on which axis, and whether to include padding.
-
UseCursor: Boolean property that determines whether or not an element will perform bounds checking on and attempt to capture the cursor. If the cursor is captured by an element, it will not be able to be recaptured until it is either released by the capturing element or until the next frame when it resets. If
ShareCursor
is set to true, then the element will not attempt to capture the cursor, but will still perform bounds checking. Both are false by default. -
IsMousedOver: Returns true if
UseCursor == true
and the element is currently moused over. -
IsMasking: If set to true, then the element will act as a clipping mask on its children, meaning anything drawn outside
the bounds of the parent will not be drawn. The
IsSelectivelyMasked
andCanIgnoreMasking
flags can be used to override this behavior. These are all false by default.
Parent and Dim alignment are particularly useful for creating a basic layout without having to resort to manually creating your own update methods and helps simplify them when you do.
- WindowBase: A basic window class that extends HudElementBase. Has a header bar, body, and border. Can be resized and dragged around using the mouse, or not, depending on the configuration.
-
-
The Bind Manager allows for the creation of groups of unique key binds that can be easily serialized/deserialized, making it fairly effortless to implement user-configurable key binds, particularly when used in conjunction with the rebind page in the settings menu. Each bind within a group must be unique in order to function, but binds between groups do not need to be unique.
-
BindManager: Manages and updates bind groups registered by the client. Provides utilities for creating/retrieving groups and allows retrieval of supported controls.
-
BlacklistMode: Enum property using SeBlacklistModes flags to determine which of Space Engineer's control groups should be disabled. Implemented using the utilities provided in
MyVisualScriptLogicProvider
and some camera matrix shenanigans to disable looking with the mouse. -
BindGroupInitializer: Intermediate container used to allow easier initialization of bind groups using collection-initializer syntax while also allowing you to mix and match
RichHudControls
andVRage.Input.MyKeys
control enums. - BindDefinition: Serializable keybind definition. BindGroups can be initialized with a list of BindDefinitions making loading from a config file as simple as passing in the deserialized list to the desired bind group.
-
BindGroup: A named collection of unique keybinds. Any binds registered that conflict with previously registered binds will be registered as empty and will not function.
-
Bind: A key bind whose combo is comprised of a list of controls. Input can either be polled with an update loop or you can register to the relevant press event.
Binds can only be created using a BindGroup. They're not sensitive to key press order and control order is not preserved when getting/setting.
- Control: A named wrapper for controls provided through the Space Engineers mod API (sans gamepad).
-
-
BlacklistMode: Enum property using SeBlacklistModes flags to determine which of Space Engineer's control groups should be disabled. Implemented using the utilities provided in
Important: BindGroup, Bind and Control objects returned by the Bind Manager are not tied to any specific instance of those objects, but to their corresponding indices. If those objects should cease to exist, or if their index changes, then the wrappers may not point to the correct group/bind/control if they point to a valid member at all.
A resizable and draggable windowed control panel used for configuring client mods, designed to roughly match the style of the rest of the Space Engineers UI. It's a bit like the Text HUD API's Mod Menu, but with a facelift and a bunch of new controls.
Every mod registered via the API is represented in the terminal by a ModControlRoot element, a drop-down list of terminal pages registered to the mod, using the name supplied when registering when the framework API. Every registered mod has a control root associated with it by default, but it must be enabled by the mod before it will be visible in the menu.
At the time of writing this there are currently three types of terminal page accessible via the API:
-
ControlPage: A scrolling list of control elements like sliders, text boxes, dropdown lists, etc. that can be used for mod configuration. Each terminal control is parented to a ControlTile, and that tile, in turn, is parented to a ControlCategory, which is parented to the page.
-
RebindPage: Specialized control page dedicated to rebinding controls. Simply register the bind group(s) you want to make configurable and you're good to go.
-
TextPage: A scrollable, wrapped text box, with a separate header, subheader, and body controllable via RichText properties. Useful for help pages.
The text renderer allows you to specify font style, alignment, color, and text size per-character. Well, technically for every string, but nothing is stopping you from making 1-character strings. Aside from common sense, of course.
-
RichText: This type is primarily used to set/retrieve text from UI elements. It's essentially a reusable collection of StringBuilders, each with a corresponding GlyphFormat.
-
Strings and StringBuilders are implicitly castable to this type. Any time unformatted text is assigned to a RichText field, a new RichText object will be instantiated. This is fine for initializing text fields in constructors, but if you're updating text in a loop, you're going to want to manage this a little more carefully.
-
Line alignment is determined by the first character in the line.
-
Supports collection initializer syntax:
GlyphFormat formattingA = new GlyphFormat(), formattingB = new GlyphFormat(); var text = new RichText() { {"Text using formattingA", formattingA}, {formattingB, "Text using formattingB\n"}, {"More text using formattingA", formattingA} };
But most of the time, you'll likely just be adding/updating a single line of text without changing the formatting. In that case, you can just set the default formatting for the element once and just pass in a regular, unformatted string.
textElement.Format = new GlyphFormat(size: 2f, color: Color.Red); textElement.Text = "Big Red Warning Text";
-
-
ITextBuilder: It's essentially a jagged, two-dimensional StringBuilder, but with fewer helper methods. Lines run along the X-axis, characters run along the Y-axis. Every text element in the framework is backed by one of these. Even when you're using an element's RichText property, you're using TextBuilder.
If you're planning on updating text in a loop, then you'll want to use this, either by directly appending to it or by setting its text with your own reusable StringBuilders and RichText objects.
-
BuilderModes:
- Unlined: No line breaks allowed, no text wrapping. If you add a line break, it'll just filter it out of the string.
- Lined: Lines separated by '\n'
- Wrapped: Lines separated by '\n' and wrap to the next line once the line width exceeds the width of the text element.
- By default, all text elements have their builder set to unlined. If you want to use multiple lines or if you want text wrapping, you'll need to change the builder mode.
-
ILine: Contains both the list of formatted characters as well as the size of the line.
-
IRichChar: Contains the size, position, format and associated character.
- Note: Characters on lines outside the visible range will not have their position updated.
-
IRichChar: Contains the size, position, format and associated character.
-
BuilderModes:
-
ITextBoard: Extends TextBuilder. Every text element uses this type. By default, TextBoards will resize to fit their contents, but they can be configured to be manually resizable; any text that doesn't fit just won't render.
This framework allows for the addition of custom fonts. You can find the font generator and instructions for it here. Custom fonts are shared by every mod using the framework. If you were so inclined, you could create a mod that was nothing more than a font pack for other mods to use.
Built-in fonts:
- Space Engineers
- Monospace
- AbhayaLibreMedium (a free Times New Roman alternative)
- BitstreamVeraSans (a free sans serif font)