-
Notifications
You must be signed in to change notification settings - Fork 113
xml_structure
title: Interface XML Structure description: Files, parse order, defines, templates, vectors, styles, options blocks and window registration published: true editor: markdown
An interface is a set of XML files, each rooted at <interface_config>, parsed as one merged document: the children of every file are appended in order and then processed together. Declaration order matters across files exactly as it does within one file — which is why skins and shared styles are parsed first (config_sample.xml, widgets_sample.xml before main_sample.xml in the sample; config.xml and widgets.xml first in the client).
Before each top-level element is handled, three text transforms run in order:
-
Feature flags —
<flag name=.../>and flat<if flags=...>/<elseif>/<else>/<endif>markers conditionally strip siblings (a preprocessor for product flavors). -
Define expansion — every
%namein every attribute is substituted (see below). -
Style merging —
style="name"attributes pull in style properties (element attributes win).
Then two passes over the top-level elements:
-
Pass 1:
<template>,<options>,<define>,<style>— declarations. -
Pass 2:
<root>,<group>,<instance>,<view>,<ctrl>,<vector>,<link>,<variable>,<tree>,<proc>,<anim>,<sheet_selection>,<lua>— content.
Unknown elements are offered to embedder-registered parser modules (this is where client-only elements like <macro> and <action_category> live — they are not part of the library).
A failed element normally warns and is skipped; the exception is <lua>, whose failure is fatal — scripts run at parse time and the interface is assumed to depend on them.
<define id="case_upper" value="2" />
<define id="menu_bg" value="w_modal.tga" />
<view type="text" case_mode="%case_upper" ... /><define> registers a textual macro; %name is replaced in every attribute of every later element. Names use [A-Za-z0-9_]; %% escapes a literal percent. An unknown %name fails the whole element that used it. value_from_code="expr" evaluates an interface expression at parse time and stores its string result.
The client's familiar
%case_upper,%case_normaletc. are defines from its config files, not built-ins. A standalone interface must declare them (0–5, see views) before use. {.is-info}
<template name="inv_slot" keep="true" id="" posparent="parent" posref="TL TL" x="0" y="0">
<group id="#id" posparent="#posparent" posref="#posref" x="#x" y="#y" w="44" h="44">
<view type="bitmap" id="back" posref="MM MM" texture="w_slot_item.tga" global_color="false" />
</group>
</template>
<instance template="inv_slot" id="b0" x="12" y="-70" />- Attributes on the
<template>element are parameter defaults;#paraminside any attribute of the template body is replaced by the instance's attribute of that name, falling back to the default. Longest name wins when parameters share prefixes; there is no escape for a literal#. - The template body is expanded inline where the
<instance>stands, then parsed as normal elements. -
keep="true"retains the template after parsing so it can be instantiated at runtime (createGroupInstancefrom code or client Lua).
<vector> is the repeated form of <instance> with $i index substitution and position chaining — syntax and semantics in Layout.
<style style="text_button_16" type="text_button" tx_normal="w_text_button" ...
fontsize="10" shadow="true" />
<ctrl style="text_button_16" id="bt_ok" hardtext="OK" ... />A <style> records a named bag of attributes; any element carrying style="name" receives each style attribute unless it already defines it — element attributes override the style. Styles are how the sample and client keep one skin definition per button family.
<options type="layer" name="layer0">
<param name="tx_tl" value="w_l0_tl.tga" />
<param name="header_h" value="24" />
...
</options><options> stores a named parameter map that widgets look up by name at setup: container windows read their entire skin from a layer options block (see Skinning), modal frames from a frame block (skin_modal in the shipped data), plus the fixed-name blocks container_move_opt and container_insertion_opt. herit="other" copies an existing block as the base.
Containers dereference
container_move_optunchecked. An interface with container windows but without that options block crashes on the first layout pass. Ship the global options blocks before any window XML. {.is-warning}
<root id="sample" x="0" y="0" w="800" h="600" active="true" />
...
<group type="container" id="hello" ... />
<tree node="hello"></tree>-
<root>creates (or switches to) a master group; its id gets an automaticui:prefix. Every subsequent top-level group/view/ctrl/link/tree is parented to the current master group. -
<tree node="shortname"/>registers a direct child group of the master group as a window. Only windows draw; a plain group at the root level parses fine and never renders. The name match is case-insensitive on the last id segment. - Nested
<tree><node node="child"/>...</tree>entries attach containers inside other containers — this is what builds docked rollout lists (see Windows and containers), not XML nesting of the container groups. -
Modal groups are auto-registered — no
<tree>needed. - Window stacking respects
win_priority(0–7, default 3) declared on the group.
The embedding application decides which master group is active (the sample activates ui:sample; the client runs ui:interface plus separate master groups for login and outgame).
<variable entry="UI:SAVE:CONTENT_ALPHA" type="sint32" value="255" />
<variable entry="UI:TEMP:MATRIX:$i:VAL" type="sint32" value="0" size="16" />Creates database leaves with initial values — the interface equivalent of declaring your state. Types: sint64, sint32, float/double, bool, rgba, hotspot. With size="N", $i in the path expands to N entries. If value is not a literal (doesn't start with a digit/-), it is treated as another database path to link to. Details and the fresh-database pitfalls in Database.
<proc> defines named action-handler sequences (see Action handlers and procedures); <lua file="script.lua"/> executes a script at parse time (see Lua scripting). Both are top-level elements.
<group type="...">, <view type="..."> and <ctrl type="..."> all draw from one class factory keyed by the type name; the tag only constrains what the result must be (a ctrl must be interactive, a group must be a group — a <group> with an unknown or missing type silently falls back to a plain interface_group, while views and ctrls fail). The full type-name table lives in NeL GUI; the per-widget attributes are documented in views, controls and windows.