Example: Templates
In Example 2, we learned how styles can help us to avoid redundant data in our layouts. But since styles are limited, we will learn a more powerful way in this example called "Templates". A template defines a custom control-type for common used controls. There are already a lot of templates in "Templates" folder for the default in-game UI. Even the "ui.Button" item we used in the past examples is actually just a template called "Template_Button". Lets take a look at that template:
ui.UIManager.customTypes["ui.Button"] = {
"type": "ui.FreeLayout",
"controls":[
{
"type": "ui.SelectableWindow",
"frame": [0, 0, "100%", "100%"],
"margin": [0, 0, 0, 30],
"params": {
"action": -> p.action
},
"zIndex": 4999
},
{
"type": "ui.Text",
"sizeToFit": true,
"styles": ["regularUIText"],
"alignmentX": "center",
"alignmentY": "center",
"frame": [0, 0],
"margin": [0, 0, 0, 0]
"text": -> p.text
"zIndex": 5100
}
]
}
The first line, similar to layouts and styles, has always the same format like this:
ui.UIManager.customTypes["<module>.<unique_template_name>"] = {
or also just:
ui.UIManager.customTypes.<unique_template_name> = {
It is not necessary to understand that line completely, you only need to know that you have to use a unique name for your template.
We can see here how ui.Button is actually defined. We can see that a ui.Button is just a free-layout with a ui.SelectableWindow and a ui.Text control inside. The ui.SelectableWindow is also a template itself. So templates can use other templates which allows you to build more complex UIs.
The ui.SelectableWindow is a frame with shadow in default UI design. It uses "100%" for its size to scale it and fit the dimensions of the parent free-layout. So percentages values are very useful in templates to make a template usable with dynamic sizes.
The ui.Text just displays the text of the text property. In that example the text is set to "-> p.text" which is not actual text to display but a placeholder-function since we want that the button works with any kind of text. Placeholders can be used for any kind of property in a template. Whenever we want to make a certain value adjustable we can define a placeholder using the following format:
-> p.<placeholder_name>
The placeholder name should be unique inside the template and shouldn't contain spaces or special characters. The actual value for a placeholder can be set if the template is used with the help of the params-property. We already did that in our title-screen example.
{
"type": "ui.Button",
"params": { "text": "New Game" },
"resizable": true,
"margin": [0, 0, 0, 10]
}
So the params-property contains the values for all placeholders of the used template. The params-property is only valid for templates.
If the value of a placeholder is not passed to the template using params property, the value is null/empty by default. But you can define a default-value for a placeholder if necessary using the following format:
-> p.<placeholder_name> or <default_value>
Like:
-> p.text ? "A Button"
We are using the ?-operator, so if we don't specify a valid value for text-placeholder the text will be "A Button".
So with templates you can build complex controls and layouts very easily. If you take a look at the default templates you will see that templates very often using other templates. But there is a small set of basic controls which are not defined as a template like ui.Text or ui.Image. In regular, you are using this basic controls to build your own more powerful controls.