Skip to content
Quetzy edited this page Jun 19, 2022 · 4 revisions

A Theme file defines default text, element, and widget styles to be used for within your UI. The most common thing to do will be to override propeties like background and border sprites/colors, padding, spacing, and so on, to customize the general look of the UI. Themes can also be applied to custom widgets (such as the widgets included with YUI as well as any you make yourself). You can override most properties of elements and widgets this way, not just colors and layout!

The Example Project includes two themes that you can browse here:
https://github.com/shdwcat/YUI/tree/main/datafiles/YUI/Themes

The Default Theme

The YUI package comes with a default theme which will be used automatically, until you decide to edit it or use a different theme.

Using Custom Themes

You're not limited to using a single theme for your whole game! You can define multiple themes by creating additional theme files, and you can even mix and match themes within the same Screen.

In order to change the theme for an element, you simply set the theme property to the name of the theme you want to use:

type: panel
theme: inventory
...

Assuming you have defined an inventory.yui theme file, that element and all children will use the values defined in that theme.

Normally you'll set the theme on the root element of a Screen to set the theme for that screen, but you can override the theme property on any element if you want to mix and match themes within a screen.

Theme File Format

A Theme file is defined in YAML, and has the following top-level properties:

file_type

Type: theme
The file_type helps YUI understand what kind of file it is looking at, and can help catch certain errors where you might refer to the wrong kind of file accidentally. A Theme file must always have file_type: theme.

import

Type: Array of file path strings
The import property allows you to import other resources and interactions for use within the theme. File paths are relative to the location of the current file, so you may need to prefix the path with ../ etc. if you need to import a file in a different folder than that of the current file. See Importing Resources for more details.

constants

(documentation TODO, see default theme for example usage)

functions

(documentation TODO, see default theme for example usage)

resources

Type: resources map
The resources property lets you define resources directly in the theme file, without needing to import another file. This can be useful when using the same values for multiple elements or widgets; by referencing a resource value you in each element or widget, you can update your theme simply by editing the resource value, without needing to edit the values for each individual element or widget.

Note: the constants and functions sections will be resolved first, so that you can use those values within the resources section. See the see default theme for example usage.

theme

The theme property is where you'll define the actual theme for elements and text, using the following two properties:

elements

Type: map of element/widget names to theme values
Here you can override property values for any built-in element or custom widget. Almost every property on an element or widget can be customized by a theme file.

For example, the default theme customizes the button element like so:

    button:
      background: &control_bg
      border_color: &control_border
      border_focus_color: &focus_border
      border_thickness: 1
      highlight_color: &accent_color
      highlight_alpha: .5
      padding: [10, 5]

This means that any button used where this theme is active will use these values by default.

text_styles

Type: map of text_style names to theme values
The text and text_input elements have a text_style property, which allows you to set the font and color properties of that text to the value specified here for that name. For example, the default theme defines the title text style as:

    title:
      font: fnt_yui_title
      color: &text_color

Then you can use this on a text element:

type: text
text_style: title

And that text will use the font and color defined in the text style.

The default theme defines body title and subtitle text styles, by you can add your own or replace these if you want. Note that the default value for text_style on a text element is body, so if you want to change that you should use an element style (see above) to change the default value to the default text style name of your choice.

Understanding Theme Value Priority

When defining a theme for a [widget](Custom Widgets) (whether it's a Template or Fragment), it's important to understand the priority for values when the widget theme and the element theme for the root element of the widget specify the same property.

The general rule is: The most specific value is used.

For example:

    // attack_button definition
    type: fragment
    content:
      type: button
      border_color: grey
      content: Attack!
    // theme definition
    button:
      border_color: green

    attack_button:
      border_color: red
    // using an instance of attack_button in an actual UI
    type: attack_button

...what color is the border?

There are actually five different places the value for border_color could be set in this situation!

  • the border_color set on the instance of the attack_button widget
  • the border_color set in the theme for attack_button
  • the border_color set in the widget definition for attack_button
  • the border_color set in the theme for button
  • the default value of border_color defined in the YuiButtonElement source code (which is actually undefined)

The above list is in fact the order that they apply in: the value on a specific instance has the highest priority. Then YUI looks for the theme for that specific widget, then the definition of that widget, then the theme for the element type (button in this case) and lastly the default value that is set in the YUI source code.

Generally you shouldn't really have to think about this, as the intent is for it to do what you would intuitively expect to happen if you didn't understand how it actually worked ;)