Styled UI - coldrockgames/gml-raptor GitHub Wiki
At the starting page of the UI Subsystem, the style-array
is mentioned as one of four ways to create your UI.
This page takes a closer look at this feature.
A style-array looks like this:
[
[ Panel, { min_height: 144, dock: dock.top, padding: 12 } ,
[ Label, struct_join(label_struct, { text: "[scale,1.5][ci_accent]UTE - raptor Unit Test Engine", position: [48,32]}) ],
[ Label, struct_join(label_struct, { text: "[scale,1.5]Discovered Test Suites", position: [48,84]}) ],
[ Label, struct_join(label_struct, { text: "[scale,1.5]Detailled Test Results", position: [968, 84]}) ],
],
[ ScrollPanel, struct_join(scrpanel_struct, {
min_width: 1000,
dock: dock.right,
content_autofill: [true, 4],
content_object: [UnitTestResultsViewer, { detail_mode: true, }]
})
],
[ ScrollPanel, struct_join(scrpanel_struct, {
dock: dock.fill,
content_autofill: [true, 4],
content_object: [UnitTestResultsViewer, { detail_mode: false, }]
})
]
]
Let's go through this, step by step.
- It must be an array (and not a struct) because the order matters and structs can not guarantee to have a constant order of items.
- You always create one single array which contains several sub-arrays. Speaking of json or GML, you always create
[ ...content... ]
. - Each of the sub-arrays follows this structure:
-
[ type_to_create, <style_struct> ]
for any non-container item (like theLabel
objects above) or -
[ type_to_create, <style_struct>, [ next-level-subarray], ... ] ]
for containers (like thePanel
above, which contains the Labels)
-
- So you create any hierarchy in the form of array containing a type, init/style structs and another inner array for the elements of the container
- You do not have to deal with the ControlTree itself, no need to care about when and what to
.build()
, no need to call all those functions. - Just pure content, pure data.
- Highly dynamic, as you could even build such an array at runtime of your game and create dynamic UIs (like windows for inventories and similar things) specialized for the view you want to show.
- It can be "put together" like Lego pieces at runtime.
- It is compatible with the json format, so you can define your UI freely in your game configuration files, hence you could even "drop" parts of those array from your Race query to create custom details/properties views based on the dropped item from a loot table.
Behind the scenes, raptor executes a function which iterates recursively through this array and does all the .add_control(...)
and .build()
calls for you.
On every ]
end-of-array, if it contained sub-arrays (i.e. if it was a container), .build()
is invoked to make sure, the container has done all the calculations.
When reaching the end of the top-level array, .build()
is invoked on the master container, finishing the UI layout process.
With this feature, you can create UIs without any knowledge about the ControlTree itself, aside of knowing the functions, that are supported for the style_struct
.
Raptor offers two public functions, that will render this style-array for you:
/// @func styled_ui_create_room(_style_array)
/// @desc Submit a style_array to the UI_ROOT for the
/// main ui of the current room.
/// UI_ROOT.clear_children() is invoked, before the
/// array gets applied.
/// This function always returns the UI_ROOT for chainability.
function styled_ui_create_room(_style_array) {
/// @func styled_ui_create(_container_or_tree, _layer_or_depth, _init_struct, _style_array)
/// @desc Submit a style_array to any styleable control (i.e. any _baseContainerControl).
/// You can create panels or windows or any other container.
/// instance_create(...) is called for you and the created control will be returned.
function styled_ui_create(_container_or_tree, _layer_or_depth, _init_struct, _style_array) {
In short terms, every set_*
function in ControlTree can be used as a property in the style-struct. You do not have to write "set_". When you write dock: dock.fill
, raptor translates this into a call to set_dock(dock.fill)
.
Note
In addition to the calls in the table below, you may add any of the Variable Definitions, the control has. Examples are text
, font_to_use
, text_color
, etc. Just look in the inspector of the variables for any of the controls to find out, what you can style here.
To be exact, even if you write a variable here, that does not exist yet, it will be created in the instance! If you write my_cool_variable: true
in the style struct, your instance will have this as a member variable.
Available commands in a standard ControlTree
Command | Arguments | Description |
---|---|---|
margin |
left_or_all, top=undefined, right=undefined, bottom=undefined |
Define the margin (outer distance) between controls. If you supply only one argument, it is applied to all four directions. |
margin_left |
margin | Set the left margin. |
margin_top |
margin | Set the top margin. |
margin_right |
margin | Set the right margin. |
margin_bottom |
margin | Set the bottom margin. |
padding |
left_or_all, top=undefined, right=undefined, bottom=undefined |
Define the padding (inner distance) between a control and the border of its render area. If you supply only one argument, it is applied to all four directions. |
padding_left |
padding | Set the left padding. |
padding_top |
padding | Set the top padding. |
padding_right |
padding | Set the right padding. |
padding_bottom |
padding | Set the bottom padding. |
position |
xpos, ypos, relative=false |
Set a fixed position. NOTE: Padding and Margin are ignored when using static coordinates! |
position_from_align |
valign, halign, xoffset=0, yoffset=0 |
Sets the position, a control would have if aligned as specified as static coordinates. NOTE: Padding and Margin are ignored when using static coordinates! |
spread |
spreadx=-1, spready=-1 |
Both arguments range from 0..1 meaning percent of the total width/height. If you set spreadx to 0.5 this means "50% of the width of my container". |
dock |
dock | Apply docking to the control. Docking on a side means (let's take "left" as an example): "Take the full height of my container and set my x-position to zero." So it's positioned on the left edge of the container and takes the full height.dock.fill uses the entire remaining space of a container in all four directions. |
reorder_docks |
reorder | True by default. Reorder dock means a more "natural" feeling of adding right- and bottom docked elements. When you design a form, you think "left-to-right" and "top-to-bottom", so you likely want to have the second bottom added to appear BENEATH the first bottom! If you do not want that, just turn reorder off. |
align |
valign=fa_top, halign=fa_left, xoffset=0, yoffset=0 |
Align the control in its container in the same way you would align text in a Button or Label. fa_top/fa_middle/fa_bottom are used for vertical alignment and fa_left/fa_center/fa_right for horizontal alignment. |
anchor |
anchor | Perform anchoring on a control in its container. An anchor means, the distance from the edge of the container to the control will stay constant. So if the container changes its size, the control will change its size too, but will keep the distance to edge constant. NOTE: This is a bit-flag. You may use binary or operator to set multiple anchors, like anchor.top or anchor.bottom
|
name |
name | Set the name of the control. It can be accessed later on through the ControlTree by calling get_element(name) . |
visible |
visible | Set the visible flag.NOTE: This will set visible recursively on all child controls too! |
enabled |
enabled | Set the enabled flag.NOTE: This will set enabled recursively on all child controls too! |
Additional Commands available in a ScrollPanelControlTree
Command | Arguments | Description |
---|---|---|
content_object |
object_type, init_struct=undefined, custom_draw_method=undefined |
Define the content object of a ScrollPanel. The custom_draw_method may be a string (the name of the function), if the control shall use something else than draw_self to draw its contents. This function must exist in the control and is invoked when the gpu_scissor is active to draw parts of the content. |
content_autofill |
autofill, inner_padding |
By default, autofill is true for content objects. This flag means, that the ScrollPanel will resize the content object to take up all the available visible space of the panel, if its size is smaller than the panel size. |