Skip to content

controls

Jan Boon edited this page Jul 24, 2026 · 3 revisions

title: Interactive Widgets (Controls) description: Buttons, sliders and scrollbars, edit boxes, combo boxes, spinners and the color picker published: true editor: markdown

Controls take input. They inherit the common element attributes plus a shared tooltip set, and each family adds its own. Event wiring is by action handler name + params attribute pairs; note the params attribute name varies by widget (params_l on buttons, plain params on sliders and edit boxes).

Common control attributes: tooltips

Every <ctrl> accepts: tooltip (literal text, or a translation key when it starts with ui), tooltip_i18n (forced translation key, wins over tooltip), on_tooltip/on_tooltip_params (action handler producing a dynamic tooltip), tooltip_parent (ctrl default, mouse, win, special + tooltip_special_parent), tooltip_posref/tooltip_posref_alt (hotspot pairs or auto), and instant_help (default true — no hover delay).

Buttons

Push, toggle and radio buttons, text buttons and arrow buttons from the showcase

Two widget types share the button machinery:

  • button — a bitmap button: tx_normal, tx_pushed, tx_over textures (over is blended on top), scale, align.
  • text_button — a three-piece skinned button with a label: each of tx_normal/tx_pushed/tx_over is a base name expanded to <base>_l.tga, <base>_m.tga, <base>_r.tga (caps + stretched middle). Label via hardtext; sizing via wmargin, wmin, hmin; label placement text_posref (default centered), text_x/text_y; per-state text colors text_color_normal/pushed/over (+ shadow and global-color variants). All CViewText attributes also apply to the label (fontsize, shadow, case_mode, …).

Shared button attributes:

attribute default meaning
button_type toggle_button push_button (momentary), toggle_button (sticky), radio_button (exclusive per parent group)
pushed false initial state
onclick_l / params_l left-click action handler; also onclick_r, ondblclick_l, onlongclick_l, onover, onclock_tick with matching params_*
menu_l / menu_r / menu_b menu group opened on left/right/both clicks
color, col_pushed, col_over white per-state modulation colors; global_color_normal/pushed/over per-state overrides
over_when_pushed true show the over layer while pushed
frozen false ignore events but keep drawing (grayed unless frozen_half_tone="false"); distinct from active="false" which hides

Radio grouping is by parent group: all radio buttons directly inside the same group form one exclusive set; there is no group-name attribute. A pushed="true" on a radio button at parse time sets the visual only — select the initial state at runtime (action handler, database or Lua) if the group must start coherent.

Sliders and scrollbars: scroll

One widget type, two roles.

<!-- slider: value + range, no target -->
<ctrl type="scroll" id="sh" vertical="false" align="L" value="UI:TEMP:SLIDERH" min="0" max="255" w="200" h="8" tracksize="24"
      tx_bottomleft="w_scroll_l.tga" tx_middle="w_scroll_m.tga" tx_topright="w_scroll_r.tga" />

<!-- scrollbar: target group, engine computes the rest -->
<ctrl type="scroll" id="scroll_bar" target="text_list" ... />
attribute default meaning
vertical true orientation
tx_bottomleft / tx_middle / tx_topright w_scroll_l0_* track cap/middle/cap textures
value 0 literal, or a database leaf — the slider then both writes and follows the leaf
min / max 0 / 100 slider range
step_value 0 snap values to multiples
onscroll / params handler while moving; onscrollend/end_params on release; onscrollcancel/cancel_params with cancelable="true" (right-click aborts a drag)
target id of a group to scroll — switches the ctrl to scrollbar mode; target_stepx/target_stepy set the scroll quantum (e.g. line height)
keyboard false PageUp/PageDown support when focused
tracksize 8 thumb length (minimum, in scrollbar mode)

The showcase's sliders drive gauges purely through the database: slider writes UI:TEMP:SLIDERH, the bar/text_number views read it, and a <link> pops a warning icon above a threshold — no code anywhere. Mouse wheel over a vertical scrollbar scrolls its target 12 px per notch.

Edit boxes

The edit boxes window with typed text in the single-line box

edit_box is a group: it needs a child text view with id edit_text (auto-created with a warning if missing) which carries the visual attributes; multi-line editing = multi_line="true" on that child plus want_return="true" on the box.

attribute default meaning
onenter / params Enter handler
onchange / onchange_params text-change handler
on_focus / on_focus_lost (+_params) focus handlers
entry_type text input filter: text, integer, positive_integer, float, positive_float, alpha, alpha_num, alpha_num_space, password, filename, playername
max_num_chars / max_num_bytes unlimited length caps
prompt > prompt string
enter_loose_focus true Enter drops keyboard focus
enter_recover_focus true Enter anywhere refocuses the last edit box
max_historic 0 up-arrow history depth (entries pushed on Enter)
clear_on_escape false Escape wipes the content
want_return false Enter inserts a newline instead of validating
negative_filter characters banned from input
menu_r right-click context menu id
savable true content persisted with the interface config

enter_loose_focus defaults to true. A console/chat-style box that should accept the next line immediately must set enter_loose_focus="false" — otherwise every second command silently goes nowhere while the box regains focus. {.is-warning}

The current content is the reflected property input_string — readable and writable from Lua and <link> targets, not an XML attribute. edit_box_decor is the same widget with eight built-in border textures (tx_tltx_r).

Combo box

The menus window: a combo box and a select_number spinner The combo box unrolled over its menu

combo_box stores its selected index in a database leaf (value, required) and lists its entries as children:

<group type="combo_box" id="race" value="UI:TEMP:COMBO" w="120" h="18" ...>
	<combo_text name="Fyros" />
	<combo_text name="Matis" />
	...
</group>

It needs a child text view text and a child button select (usually supplied by an instance template), and the application must point the static combo menu ids at a menu group in your XML — see embedding. on_change/on_change_params fires on selection; entries can be added at runtime.

select_number is the spinner sibling: value (leaf, required), min/max/delta, loop; needs children slot_number, number, arrow_up, arrow_down. Mouse wheel steps it too.

Color picker

The color picker window at rest After a drag across the palette: swatch and RGB readouts updated, all through the database

colpick samples a palette texture under the mouse (click or drag) and writes the picked channels to up to four database leaves:

<ctrl type="colpick" id="cp" texture="color_picker.tga"
      dbcolr="UI:TEMP:COLOR:R" dbcolg="UI:TEMP:COLOR:G" dbcolb="UI:TEMP:COLOR:B"
      onchange="set" onchange_params="..." />

onchange fires continuously during a drag. Because it reads texture pixels, the palette must be a loose file, not an atlas entry — see Skinning.

Others worth knowing

  • tab_button — a text_button whose click is hijacked to tab selection; group= names the content group it shows. Covered with tab groups in Windows and containers.
  • group_wheel — an invisible group with on_wheel_up/on_wheel_down (+_params) handlers.
  • button_link — the hyperlink button used inside HTML/paragraph flows.
  • Drag and drop has no library widget: the draggable control in the library is a stub (the client implements its own item sheets on top). Gesture-driven UI is done in Lua with the embedder's mouse hooks — see the inventory demo pattern.

Clone this wiki locally