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.