Difference between revisions of "GUI Themes/Specs"

From ScummVM :: Wiki
Jump to navigation Jump to search
(→‎To Do: arrows are now implemented)
(→‎Resolution-dependent keys and layouts: >= and <= are now supported)
 
(62 intermediate revisions by 11 users not shown)
Line 1: Line 1:
== To Do ==
Since the merge of the new GUI into the ScummVM trunk, all documentation regarding the legacy GUI is now obsolete. Hence, this page has been updated with the details of the new Theme format.
* Add possibility to specify shadow types to widget classes and to individual widgets
* Theme hints too
* List widget
** get mock-up from Krest
** shadows under lists. We do not enable those because of missing scrollbar mock-up
** right padding
* PopUp widget (aka drop-down list)
** get mock-up from Krest
** less round corners
*** to do that we need to be able to define gfx for each widget class separately
** right text padding
** make it taller
* Tab widget
** tab widget is drawn completely wrong now
** though it would be nice to leave current drawing style and select them via widget property
* Editable text widget
** fix caret misaligning
** embossing (not shadow)
** less round corners
*** to do that we need to be able to define gfx for each widget class separately
* Text widget
** less round corners
*** to do that we need to be able to define gfx for each widget class separately
* Button widget
** probably tame colors for buttons to match mock-ups
** top line should be drawn with ''lighter'' color to make it look more natural
* Checkbox widget
** smaller version of widget for 320xY resolution
* Slider widget
** remove border
** less round corners
*** to do that we need to be able to define gfx for each widget class separately
** embossing
* Dialogs
** Scumm save/load dialog
*** put thumbnail and save properties inside one container. Container code is missing now
*** center dialog title agains list widget
** Scumm help dialog
*** correct buttons widths
** About dialog
*** looks bad. Probably add some shadows and text padding
*** fix glitch at the top of the dialog where part of the characters get stuck
*** [Classic theme] Text seems to be drawn over the dialog frame. At least at the top of the dialog.
** Chooser dialog (add game)
*** proper coloring and list shadow
** Options dialog
*** do something with buttons on the right when dialog is on
*** buttons are too wide on paths tab in global options
** Scumm options dialog.
*** add space after volume control


== GUI Themes config file format ==
=== Theme Packages ===


=== Overview ===
A theme file in the new version of the ScummVM GUI is a compressed ZIP file which contains all the required information


We always have a built-in theme. It is used when there is no external .ini file. For simplicity it uses exactly same format as external .ini but is defined in Theme::_defaultConfigINI string in gui/theme-config.cpp file.
* One or more STX (ScummVM Theme XML) files.
* Any external Bitmap fonts.
* Any external Bitmap images.
* A <tt>THEMERC</tt> file.
===== The STX Files =====


Config file consists of at least one section. These sections can override one another. This is used to make a slight alteration of base theme possible without duplicating all element whose position is not changed.
STX (ScummVM Theme XML) is the new format for theme descriptions on the Graphical User Interface of ScummVM.


'''NOTE: if you want to add new widgets, pay attention to correspondent section [[#What_to_do_if_I_need_to_add_new_widgets_to_GUI|below]]'''
The chosen syntax of this format is a basic subset of XML, the one which the embedded XML parser supports. Please refer to the parser documentation for its technical specifications.


=== Section names ===
Throughout the STX files, every single property of the theme's appearance and layout is defined: Although all this information can easily be stored in a single file, the theme engine conveniently allows to split the different sections of the Theme Description in one or more files.
They are defined with this regexp: (X|[0-9]+)x(Y|[0-9+]+). I.e. possible names are:
* [XxY] -- universal one which can be used for any resolution
* [640xY] -- could be used for 640x400 and 640x480
* [Xx400] -- could be used for 640x400 only (or any other resolution with height 400)
* [640x480] -- could be used for 640x480 only


=== Expressions ===
Any <tt>*.stx</tt> files contained inside the theme package will be automatically loaded and parsed. The content of such files must obviously adhere to the STX syntax which you can find in this document.
To add most flexibility arbitrary arithmetic expressions can be used for specifying any element. Allowed operations are '(', ')', '+', '-', '*', '/'. unary '+' and unary '-'. Atoms are either number or symbolic names.


=== Built-in Constants ===
===== The external resources =====
Currently there are these built-in constants defined:


* kButtonWidth
Together with the STX files, external resources for the theme may be optionally bundled. The most usual resources are bitmaps to use in the Graphical User Interface and Bitmap fonts.
* kButtonHeight
* kSliderWidth
* kSliderHeight
* kBigButtonWidth
* kBigButtonHeight
* kBigSliderWidth
* kBigSliderHeight
* kTextAlignLeft
* kTextAlignCenter
* kTextAlignRight


These correspond to constants defined in gui/widget.h file. There is no restriction on constants names.
Packaged resources will then be accessible from the STX syntax (check the <tt>font</tt> and <tt>bitmap</tt> keys in the STX documentation).


* kThumbnailWidth -- defined in graphics/scaler.h
===== The <tt>THEMERC</tt> file =====
* false = 0
* true = 1


=== Built-in Variables ===
ScummVM themes '''must''' also contain a simple <tt>THEMERC</tt> file stating the theme's version, name and author. The <tt>THEMERC</tt> file is a simple text file with the following syntax:
Built-in variables are symbolic names for ScummVM variables whose value is determined at run-time. These are:


* w -- current GUI width
<pre>[SCUMMVM_STX0.2:Name of the ScummVM Theme:Name of the Author]</pre>
* h -- current GUI height
The <tt>SCUMMVM_STX0.2</tt> is just a simple check to make sure that the theme was developed to be used on the proper version of the GUI; 0.2 is the latest version of the ScummVM STX format. Note that the <tt>THEMERC</tt> file is not optional, as it is used by the Theme engine to check that the Theme package is indeed valid and specifies the Name and Author fields that will be shown on the GUI.


=== Defining widget positions ===
===== Building theme packages =====
Widgets are specified by following construction:


  widget_name=X Y [W H]
Building a ScummVM Theme Package is as easy as dragging your STX files, bitmaps, resources and <tt>THEMERC</tt> files into your favorite archiver application and creating a zip file. However, to make the development process easier, a Python script called <tt>scummtheme.py</tt> has been included in the <tt>gui/themes/</tt> folder of the Git repository.


X, Y, W and H are whitespace-delimited expressions.
When ran with the <tt>makeall</tt> argument, the script will automatically parse all the theme folders in the Theme directory and build their ZIP files. It can be also used to build a single theme by passing it the <tt>make [themename]</tt> argument, where <tt>[themename]</tt> is the name of the folder containing the theme to be built.
W and H are optional.


This construct effectively defines
This Python script is totally standalone and doesn't require external ZIP utilities, only a standard Python distribution.


* widget_name.x
===== Building the built-in theme =====
* widget_name.y
* widget_name.w
* widget_name.h


If W and H are present, also these get defined:
The Graphical User Interface must contain a built-in theme to use a fall-back when no other custom themes can be loaded. The built-in theme must be built manually with the <tt>scummtheme.py</tt> script, by passing it the <tt>default [themename]</tt> argument.


* widget_name.x2 = widget_name.x + widget_name.w
The Python script will then parse the supplied theme's STX files into a single <tt>*.inc</tt> file; this file is automatically built together with the ScummVM executable file when building the ScummVM source code, and will be used as the default built-in theme.
* widget_name.y2 = widget_name.y + widget_name.h


Example:
Note that because only STX files are embedded in the source code, the theme which is converted into a built-in theme '''cannot''' contain Bitmaps or any other external resources.


  chooser_headline=10 6 (w - 2 * 16) (kLineHeight)
By default, the <tt>ScummVM Classic Theme</tt> is the built-in theme.


=== Widget properties ===
=== Drawing specifications ===
Above mentioned constructions with dots are called widget properties.


Example:
The process of rendering a widget on the screen is discretized into several phases called ''drawing steps''. A set of such steps, which generate a basic widget shape on screen is called a Draw Data set. The GUI Engine loads all the different data sets for a given widget and takes care of rendering it into the screen based on its current state.


  chooser_list.x
For example, the basic Button widget may be composed of several sets of data: Drawing data for the button's idle state, drawing data for when the button is hovered and drawing data for when the button is pressed.


Also there are following additional widget properties:
The functionality of each set of Drawing Data is hard-coded into the Graphical User Interface; the most up to date version of all the drawing sets may be found extensively commented in the <tt>&quot;gui/ThemeEngine.h&quot;</tt> file, in the <tt>DrawData</tt> enumeration.


* .visible -- if set to 0, then widget is not drawn
In order to successfully parse and load a custom theme definition, the whole list of Draw Data sets is not required to be defined in a theme description, but failing to declare all of them will make the parser complain and obviously several GUI elements will be missing.
* .align -- for text widgets defines text alignment (kTextAlignLeft, kTextAlignRight or kTextAlignCenter). Default is kTextAlignLeft


=== Widget class properties ===
=== Theme Layout specifications ===
Each widget class can be customized per-resolution. You need to specify their special properties.


==== ListWidget ====
The actual positioning and layout of widgets and dialogs on the graphical user interface is defined from the <tt>Layout</tt> section of the STX file. This new Graphical User Interface using a Flowing Layouts system which greatly differs from the old coordinate and arithmetic based implementation.
This is widget with list of selectable items
ListWidget.leftPadding=7                                                     
ListWidget.rightPadding=7                                                     
ListWidget.topPadding=5                                                       
ListWidget.bottomPadding=5                                                   
ListWidget.hlLeftPadding=0                                                   
ListWidget.hlRightPadding=0                                                   


''leftPadding'', ''rightPadding'', ''topPadding'' and ''bottomPadding'' specify list contents (text) padding from widget endges. Default values are 0.
The best way to learn about the new Layout system is to read the documentation on the <tt>layout</tt> key and its children, and to read the example Layout Design section, which provides a detailed overview into the steps required to design the layout of a dialog.


''hlLeftPadding'', ''hlRightPadding'' specify padding of selected text highlight, i.e. green bar in ''modern'' theme. Default values are 0.
=== Syntax overview ===


==== PopUpWidget ====
A full STX theme description is composed of:
This is drop-down list used to select one item out of several. In inactive state it displays only selected item.
PopUpWidget.leftPadding=7                                                     
PopUpWidget.rightPadding=7


''leftPadding'' and ''rightPadding'' specify list contents (text) padding from widget endges. Default values are 0.
* A root <tt>&lt;render_info&gt;</tt> key, containing all the information regarding the looks of the theme.
** An optional <tt>&lt;palette&gt;</tt> key, containing color definitions.
** An optional <tt>&lt;bitmaps&gt;</tt> key, containing all the loaded bitmaps which will be used on the GUI.
** A <tt>&lt;fonts&gt;</tt> key, specifying the fonts used to draw text on the GUI.
** A <tt>&lt;drawdata&gt;</tt> key for ''each'' DrawData identifier of the Theme Engine, specifying how is each individual widget drawn.
* A root &lt;layout_info&gt; key, containing all the information regarding the layout of the theme.
** A <tt>&lt;globals&gt;</tt> key, containing the global variables to use on the layout design.
** A <tt>&lt;dialog&gt;</tt> key for ''each'' dialog in the GUI, specifying the layout and position of the dialog and all its children widgets.
Here's a schematic overview of the layout of keys in a STX file:


=== Special variables ===
<syntaxhighlight lang="xml">
Special variables are:
<render_info>
    <palette>
        ...
    </palette>


* self
    <bitmaps>
* prev
        ...
    </bitmaps>


It is reference to current and last defined widget special variables respectively, i.e. .x, .y, .w and .h
    <fonts>
        ...
    </fonts>


Example:
    <drawdata>
        ...
    </drawdata>


  chooser_list=10 (6 + kLineHeight + 2) (w - 2 * 16) (h - self.y - buttonHeight - 12)
    ...
</render_info>


Denote self.y which equals to computed value of (6 + kLineHeight + 2).
<layout_info>
    <globals>
        ...
    </globals>


You cannot use these references forward, i.e. refer to .w in .x. They get defined from left to right.
    <dialog>
        ...
    </dialog>


=== Defining variables ===
    ...
</layout_info>
</syntaxhighlight>


Example:
The best place to start writing a full theme description is taking a look at the already written themes in the <tt>gui/themes/</tt> directory of the source code repository, while consulting the following documentation for each specific key:


  def_kLineHeight=16 * 2
=== Detailed STX documentation ===
  OneThirdWidth=(w / 3)


variable kLineHeight gets value 32. OneThirdWidth will be GUI width divided by 3. Note use of parens in last example. Definitions with 'def_' prefix have a special meaning and get skipped with USE keyword (see below).
The full documentation of the XML syntax used in the new Graphical User Interface can be found on its own [[GUI Themes/STX_Syntax|wiki page]].


=== Defining aliases ===
=== Resolution-dependent keys and layouts ===
You can define alias to any symbolic atom, i.e. constants, variables and widget properties.


Example:
Several keys in the STX syntax support the <tt>resolution</tt> property, which allows to load or skip the key and all its children when loading the theme on a given resolution dimension limit.


  set_headerBottomX=headline.x2
The resolution property must contain one or more resolution dimension limits, comma separated, for which the given key is supposed to be loaded. Resolutions without any modifiers will force the theme to be loaded in all resolutions. Here are a few examples:


Now you can use headerBottomX everywhere.
<syntaxhighlight lang="xml">
/* Key will be loaded in all resolutions */
<render_info>


=== Special alias ===
/* Key will ONLY be loaded in resolutions with 400 width or more */
<render_info resolution = 'y>=400'>


  set_parent=chooser_list
/* Key will ONLY be loaded in resolutions with less than 400 height */
<render_info resolution = 'y<400'>
</syntaxhighlight>


It sets 6 aliases for each widget property, i.e.
Note that the Theme Parser does not assert on repeated keys or values, it just replaces them accordingly. For instance, the following variable definition:


* parent.x = chooser_list.x
<syntaxhighlight lang="xml">
* parent.y = chooser_list.y
<def var = 'TestVar' value = '100'/>
<def var = 'TestVar' value = '200' resolution = 'y>=400'/>
</syntaxhighlight>


etc for .w, .h, .x2 and .y2
won't fail to parse. What will happen when loading the theme using a resolution with 400 height or mire is that <tt>TestVal</tt> first will be assigned the <tt>100</tt> value, and then it will be overwritten with the <tt>200</tt> value. On the other hand, when loading the theme using a resolution ''with less'' than 400 height, the <tt>ThemeVal</tt> will be assigned the <tt>100</tt> value and the second key will be plain ignored.


Example:
The &quot;proper&quot; way to do that multi-resolution assignment would obviously be:


  set_parent=tabMidi
<syntaxhighlight lang="xml">
  midi_checkbox=(parent.x + 10) (parent.y + 20)
<def var = 'TestVar' value = '100' resolution = 'y<400'/>
  roland_checkbox=midi_checkbox.x (parent.y + 50)
<def var = 'TestVar' value = '200' resolution = 'y>399'/>
</syntaxhighlight>


=== USE keyword ===
This way keys are only parsed on the resolution they are used in, but the result will be '''exactly the same''': Most of the time it's just cleaner to avoid using <tt>y<400</tt> resolution tags, and instead write a layout that works on all resolutions and overwrite parts of it with the <tt>y>399<tt> tag.
You can request loading of some particular section at any time within another section. But all variable definitions with def_ prefix get skipped. If you want to define a variable, use plain VAR=VAL construction.
 
Example:
 
  [640xY]
  def_buttonHeight=kBigButtonHeight
  def_kLineHeight=16
  listW=(w - 2 * 16)
  chooser_headline=10 6 listW (kLineHeight)
  chooser_list=10 (6 + kLineHeight + 2) listW (h - self.y - buttonHeight - 12)
 
  [320xY]
  def_buttonHeight=kButtonHeight
  def_kLineHeight=9
  use=640xY
 
In this example for 320xY resolution chooser_headline and chooser_list will be loaded from [640xY] section, though buttonHeight and kLineHeight will be different. listW will get the value.
 
=== USEWITHPREFIX keyword ===
This keyword is similiar to above described USE keyword. The difference is that all defined widgetset will get specified prefix. Example:
 
  [XxY]
  yoffset=10
  useWithPrefix=audioControls global_
  yoffset=50
  useWithPrefix=audioControls game_
 
  [audioControls]
  myx=10
  myw=(options_dialog.w - 20)
  midipopup=(myx -5) yoffset (myw + 5)
 
Here you will get global_midipopup and game_midipopup widgets defined.
 
=== Inactive dialog effects (new theme only) ===
For using an effect change the "inactive_dialog_shading" option in the "[extra]" section of default-theme.ini.
Possible values are: "luminance" and "dim".
 
* "luminance" will change all inactive screen areas to black and white.
** Example (enables it)
 
  [extra]
  inactive_dialog_shading=luminance
 
* "dim" will dim the screen with the given percentage value.
** "shading_dim_percent" in the "[extra]" section sets the dimming value 0 means no dim, 100 complete black
** Example (30% screen dim):
 
  [extra]
  inactive_dialog_shading=dim
  shading_dim_percent=30
 
== Evaluation precedence ==
Within one section everything is computed left to right down to top. No forward references are allowed. Only exception is aliases which can refer to not yet defined variables and widget properties, but at time of useage those variables should be defined, otherwise you will get an error.
 
Currently any error in evaluation will lead to error() and ScummVM will be closed. So be careful, especially with built-in theme.
 
On each resolution change all user-defined variables and aliases get cleared and all sections get recomputed. When sections get loaded for a single resolution, all of them are kept, so you can specify a generic [XxY] scheme and then overwrite only some widgets, thus simplifying whole thing.
 
Sections loading order is always the same. For resolution 640x480 it is:
 
# Built-in theme
## [XxY]
## [640xY]
## [Xx480]
## [640x480]
# Custom theme
## [XxY]
## [640xY]
## [Xx480]
## [640x480]
 
Only present sections are loaded. If section is not defined, no error message is generated
 
== Widget name conventions ==
 
Widget names are in form:
 
  dialog_widget
 
where dialog_ is dialog name, and widget is a distinguishable name within that dialog. Be discreet and give meaningful names.
 
Example:
 
  chooser_headline
  chooser_list
 
== What to do if I need to add new widgets to GUI ==
 
First thing to mention, is that all real GU behaviour is not described in theme config. You can only alter the look, not the feel. So all real coding should go in corresponding files in gui/ directory.
 
When you add a new widget, follow this checklist before committing:
 
* Does it look right in 320xY (./scummvm --force-1x-overlay)
** To do this you should either have no absolute positions in your config file or create [320xY] section
* Does it look right with classic theme (./scummvm --gui-theme=classic)
** that is the [XxY] section in gui/theme-config.cpp
* Does it look right <u>both</u> with classic theme and 320xY resolution (./scummvm --force-1x-overlay --gui-theme=classic)
** that is the [320xY] section in gui/theme-config.cpp
 
Currently the classic theme has the following most notable differences from the modern theme:
 
* Line spacing everywhere is narrower
* Indentation is lesser in most cases, besides in Game Options dialog

Latest revision as of 12:45, 16 March 2023

Since the merge of the new GUI into the ScummVM trunk, all documentation regarding the legacy GUI is now obsolete. Hence, this page has been updated with the details of the new Theme format.

Theme Packages

A theme file in the new version of the ScummVM GUI is a compressed ZIP file which contains all the required information

  • One or more STX (ScummVM Theme XML) files.
  • Any external Bitmap fonts.
  • Any external Bitmap images.
  • A THEMERC file.
The STX Files

STX (ScummVM Theme XML) is the new format for theme descriptions on the Graphical User Interface of ScummVM.

The chosen syntax of this format is a basic subset of XML, the one which the embedded XML parser supports. Please refer to the parser documentation for its technical specifications.

Throughout the STX files, every single property of the theme's appearance and layout is defined: Although all this information can easily be stored in a single file, the theme engine conveniently allows to split the different sections of the Theme Description in one or more files.

Any *.stx files contained inside the theme package will be automatically loaded and parsed. The content of such files must obviously adhere to the STX syntax which you can find in this document.

The external resources

Together with the STX files, external resources for the theme may be optionally bundled. The most usual resources are bitmaps to use in the Graphical User Interface and Bitmap fonts.

Packaged resources will then be accessible from the STX syntax (check the font and bitmap keys in the STX documentation).

The THEMERC file

ScummVM themes must also contain a simple THEMERC file stating the theme's version, name and author. The THEMERC file is a simple text file with the following syntax:

[SCUMMVM_STX0.2:Name of the ScummVM Theme:Name of the Author]

The SCUMMVM_STX0.2 is just a simple check to make sure that the theme was developed to be used on the proper version of the GUI; 0.2 is the latest version of the ScummVM STX format. Note that the THEMERC file is not optional, as it is used by the Theme engine to check that the Theme package is indeed valid and specifies the Name and Author fields that will be shown on the GUI.

Building theme packages

Building a ScummVM Theme Package is as easy as dragging your STX files, bitmaps, resources and THEMERC files into your favorite archiver application and creating a zip file. However, to make the development process easier, a Python script called scummtheme.py has been included in the gui/themes/ folder of the Git repository.

When ran with the makeall argument, the script will automatically parse all the theme folders in the Theme directory and build their ZIP files. It can be also used to build a single theme by passing it the make [themename] argument, where [themename] is the name of the folder containing the theme to be built.

This Python script is totally standalone and doesn't require external ZIP utilities, only a standard Python distribution.

Building the built-in theme

The Graphical User Interface must contain a built-in theme to use a fall-back when no other custom themes can be loaded. The built-in theme must be built manually with the scummtheme.py script, by passing it the default [themename] argument.

The Python script will then parse the supplied theme's STX files into a single *.inc file; this file is automatically built together with the ScummVM executable file when building the ScummVM source code, and will be used as the default built-in theme.

Note that because only STX files are embedded in the source code, the theme which is converted into a built-in theme cannot contain Bitmaps or any other external resources.

By default, the ScummVM Classic Theme is the built-in theme.

Drawing specifications

The process of rendering a widget on the screen is discretized into several phases called drawing steps. A set of such steps, which generate a basic widget shape on screen is called a Draw Data set. The GUI Engine loads all the different data sets for a given widget and takes care of rendering it into the screen based on its current state.

For example, the basic Button widget may be composed of several sets of data: Drawing data for the button's idle state, drawing data for when the button is hovered and drawing data for when the button is pressed.

The functionality of each set of Drawing Data is hard-coded into the Graphical User Interface; the most up to date version of all the drawing sets may be found extensively commented in the "gui/ThemeEngine.h" file, in the DrawData enumeration.

In order to successfully parse and load a custom theme definition, the whole list of Draw Data sets is not required to be defined in a theme description, but failing to declare all of them will make the parser complain and obviously several GUI elements will be missing.

Theme Layout specifications

The actual positioning and layout of widgets and dialogs on the graphical user interface is defined from the Layout section of the STX file. This new Graphical User Interface using a Flowing Layouts system which greatly differs from the old coordinate and arithmetic based implementation.

The best way to learn about the new Layout system is to read the documentation on the layout key and its children, and to read the example Layout Design section, which provides a detailed overview into the steps required to design the layout of a dialog.

Syntax overview

A full STX theme description is composed of:

  • A root <render_info> key, containing all the information regarding the looks of the theme.
    • An optional <palette> key, containing color definitions.
    • An optional <bitmaps> key, containing all the loaded bitmaps which will be used on the GUI.
    • A <fonts> key, specifying the fonts used to draw text on the GUI.
    • A <drawdata> key for each DrawData identifier of the Theme Engine, specifying how is each individual widget drawn.
  • A root <layout_info> key, containing all the information regarding the layout of the theme.
    • A <globals> key, containing the global variables to use on the layout design.
    • A <dialog> key for each dialog in the GUI, specifying the layout and position of the dialog and all its children widgets.

Here's a schematic overview of the layout of keys in a STX file:

<render_info>
    <palette>
        ...
    </palette>

    <bitmaps>
        ...
    </bitmaps>

    <fonts>
        ...
    </fonts>

    <drawdata>
        ...
    </drawdata>

    ...
</render_info>

<layout_info>
    <globals>
        ...
    </globals>

    <dialog>
        ...
    </dialog>

    ...
</layout_info>

The best place to start writing a full theme description is taking a look at the already written themes in the gui/themes/ directory of the source code repository, while consulting the following documentation for each specific key:

Detailed STX documentation

The full documentation of the XML syntax used in the new Graphical User Interface can be found on its own wiki page.

Resolution-dependent keys and layouts

Several keys in the STX syntax support the resolution property, which allows to load or skip the key and all its children when loading the theme on a given resolution dimension limit.

The resolution property must contain one or more resolution dimension limits, comma separated, for which the given key is supposed to be loaded. Resolutions without any modifiers will force the theme to be loaded in all resolutions. Here are a few examples:

/* Key will be loaded in all resolutions */
<render_info>

/* Key will ONLY be loaded in resolutions with 400 width or more */
<render_info resolution = 'y>=400'>

/* Key will ONLY be loaded in resolutions with less than 400 height */
<render_info resolution = 'y<400'>

Note that the Theme Parser does not assert on repeated keys or values, it just replaces them accordingly. For instance, the following variable definition:

<def var = 'TestVar' value = '100'/>
<def var = 'TestVar' value = '200' resolution = 'y>=400'/>

won't fail to parse. What will happen when loading the theme using a resolution with 400 height or mire is that TestVal first will be assigned the 100 value, and then it will be overwritten with the 200 value. On the other hand, when loading the theme using a resolution with less than 400 height, the ThemeVal will be assigned the 100 value and the second key will be plain ignored.

The "proper" way to do that multi-resolution assignment would obviously be:

<def var = 'TestVar' value = '100' resolution = 'y<400'/>
<def var = 'TestVar' value = '200' resolution = 'y>399'/>

This way keys are only parsed on the resolution they are used in, but the result will be exactly the same: Most of the time it's just cleaner to avoid using y<400 resolution tags, and instead write a layout that works on all resolutions and overwrite parts of it with the y>399 tag.