DVX_GUI/docs/dvx_widget_reference.html
2026-04-06 22:25:06 -05:00

1553 lines
69 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="ASCII">
<title>DVX Widget Reference</title>
<style>
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
max-width: 960px;
margin: 0 auto;
padding: 20px;
background: #fdfdfd;
color: #222;
line-height: 1.5;
}
h1 {
border-bottom: 3px solid #336;
padding-bottom: 8px;
color: #224;
}
h2 {
border-bottom: 2px solid #99b;
padding-bottom: 4px;
margin-top: 40px;
color: #336;
}
h3 {
color: #446;
margin-top: 24px;
margin-bottom: 4px;
}
code {
background: #eef;
padding: 1px 5px;
border-radius: 3px;
font-size: 0.95em;
}
pre {
background: #f4f4fa;
border: 1px solid #ccd;
border-radius: 4px;
padding: 10px 14px;
overflow-x: auto;
font-size: 0.9em;
}
table {
border-collapse: collapse;
width: 100%;
margin: 8px 0 16px 0;
}
th, td {
border: 1px solid #bbc;
padding: 5px 10px;
text-align: left;
vertical-align: top;
}
th {
background: #e8e8f4;
}
#toc {
background: #f0f0f8;
border: 1px solid #bbc;
border-radius: 4px;
padding: 12px 20px;
margin-bottom: 30px;
}
#toc ul {
list-style: none;
padding-left: 0;
margin: 0;
columns: 2;
}
#toc li {
margin: 3px 0;
}
#toc a {
text-decoration: none;
color: #336;
}
#toc a:hover {
text-decoration: underline;
}
.widget-section {
margin-bottom: 40px;
}
.sig {
font-weight: bold;
color: #224;
}
.note {
background: #ffe;
border-left: 3px solid #cc6;
padding: 6px 12px;
margin: 8px 0;
font-size: 0.93em;
}
a {
color: #336;
}
</style>
</head>
<body>
<h1>DVX Widget Reference</h1>
<p>
Complete reference for the DVX GUI widget toolkit. All widgets are implemented
as dynamically loaded DXE modules. They are created via convenience macros
that wrap the per-widget API function tables. The base <code>WidgetT</code>
structure is defined in <code>core/dvxWidget.h</code>; individual widget
headers live in <code>widgets/</code>.
</p>
<!-- ============================================================ -->
<!-- TABLE OF CONTENTS -->
<!-- ============================================================ -->
<div id="toc">
<h3>Table of Contents</h3>
<ul>
<li><a href="#base">Base WidgetT (Common)</a></li>
<li><a href="#ansiterm">AnsiTerm</a></li>
<li><a href="#box">Box (VBox / HBox / Frame)</a></li>
<li><a href="#button">Button</a></li>
<li><a href="#label">Label</a></li>
<li><a href="#textinput">TextInput / TextArea</a></li>
<li><a href="#checkbox">Checkbox</a></li>
<li><a href="#radio">Radio Button</a></li>
<li><a href="#dropdown">Dropdown</a></li>
<li><a href="#combobox">ComboBox</a></li>
<li><a href="#datactrl">DataCtrl</a></li>
<li><a href="#dbgrid">DbGrid</a></li>
<li><a href="#listbox">ListBox</a></li>
<li><a href="#listview">ListView</a></li>
<li><a href="#treeview">TreeView</a></li>
<li><a href="#image">Image</a></li>
<li><a href="#imagebutton">ImageButton</a></li>
<li><a href="#slider">Slider</a></li>
<li><a href="#spinner">Spinner</a></li>
<li><a href="#progressbar">ProgressBar</a></li>
<li><a href="#canvas">Canvas</a></li>
<li><a href="#timer">Timer</a></li>
<li><a href="#toolbar">Toolbar</a></li>
<li><a href="#statusbar">StatusBar</a></li>
<li><a href="#scrollpane">ScrollPane</a></li>
<li><a href="#splitter">Splitter</a></li>
<li><a href="#tabcontrol">TabControl</a></li>
<li><a href="#separator">Separator</a></li>
<li><a href="#spacer">Spacer</a></li>
<li><a href="#wrapbox">WrapBox</a></li>
</ul>
</div>
<!-- ============================================================ -->
<!-- BASE WIDGET -->
<!-- ============================================================ -->
<div class="widget-section" id="base">
<h2>Base WidgetT (Common Properties, Events, and Operations)</h2>
<p>
Every widget inherits from the <code>WidgetT</code> structure defined in
<code>core/dvxWidget.h</code>. The fields and callbacks listed here are
available on <em>all</em> widget types.
</p>
<h3>Common Properties</h3>
<table>
<tr><th>Field</th><th>Type</th><th>Description</th></tr>
<tr><td><code>name</code></td><td><code>char[32]</code></td>
<td>Widget name for lookup via <code>wgtFind()</code>.</td></tr>
<tr><td><code>x, y, w, h</code></td><td><code>int32_t</code></td>
<td>Computed geometry relative to the window content area (set by layout).</td></tr>
<tr><td><code>minW, minH</code></td><td><code>int32_t</code> (tagged)</td>
<td>Minimum size hints. Use <code>wgtPixels()</code>, <code>wgtChars()</code>, or <code>wgtPercent()</code>. 0 = auto.</td></tr>
<tr><td><code>maxW, maxH</code></td><td><code>int32_t</code> (tagged)</td>
<td>Maximum size constraints. 0 = no limit.</td></tr>
<tr><td><code>prefW, prefH</code></td><td><code>int32_t</code> (tagged)</td>
<td>Preferred size. 0 = auto.</td></tr>
<tr><td><code>weight</code></td><td><code>int32_t</code></td>
<td>Extra-space distribution weight. 0 = fixed, 100 = normal. A widget with weight=200 gets twice the extra space of one with weight=100.</td></tr>
<tr><td><code>align</code></td><td><code>WidgetAlignE</code></td>
<td>Main-axis alignment for children: <code>AlignStartE</code>, <code>AlignCenterE</code>, <code>AlignEndE</code>.</td></tr>
<tr><td><code>spacing</code></td><td><code>int32_t</code> (tagged)</td>
<td>Spacing between children (containers only). 0 = default.</td></tr>
<tr><td><code>padding</code></td><td><code>int32_t</code> (tagged)</td>
<td>Internal padding (containers only). 0 = default.</td></tr>
<tr><td><code>fgColor</code></td><td><code>uint32_t</code></td>
<td>Foreground color override. 0 = use color scheme default.</td></tr>
<tr><td><code>bgColor</code></td><td><code>uint32_t</code></td>
<td>Background color override. 0 = use color scheme default.</td></tr>
<tr><td><code>visible</code></td><td><code>bool</code></td>
<td>Visibility state.</td></tr>
<tr><td><code>enabled</code></td><td><code>bool</code></td>
<td>Enabled state. Disabled widgets are grayed out and ignore input.</td></tr>
<tr><td><code>readOnly</code></td><td><code>bool</code></td>
<td>Read-only mode: allows scrolling/selection but blocks editing.</td></tr>
<tr><td><code>swallowTab</code></td><td><code>bool</code></td>
<td>When true, Tab key goes to the widget instead of navigating focus.</td></tr>
<tr><td><code>accelKey</code></td><td><code>char</code></td>
<td>Lowercase accelerator character. 0 if none.</td></tr>
<tr><td><code>tooltip</code></td><td><code>const char *</code></td>
<td>Tooltip text. NULL = none. Caller owns the string.</td></tr>
<tr><td><code>contextMenu</code></td><td><code>MenuT *</code></td>
<td>Right-click context menu. NULL = none. Caller owns.</td></tr>
<tr><td><code>userData</code></td><td><code>void *</code></td>
<td>Application-defined user data pointer.</td></tr>
</table>
<h3>Size Specification Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtPixels(v)</code></td><td>Size in pixels.</td></tr>
<tr><td><code>wgtChars(v)</code></td><td>Size in character widths (multiplied by font charWidth).</td></tr>
<tr><td><code>wgtPercent(v)</code></td><td>Size as a percentage of parent dimension.</td></tr>
</table>
<h3>Common Events (Callbacks)</h3>
<p>These callback function pointers are available on every <code>WidgetT</code>.
Set them directly on the widget struct.</p>
<table>
<tr><th>Callback</th><th>Signature</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td><code>void (*)(WidgetT *w)</code></td>
<td>Fires on mouse click / activation.</td></tr>
<tr><td><code>onDblClick</code></td><td><code>void (*)(WidgetT *w)</code></td>
<td>Fires on double-click.</td></tr>
<tr><td><code>onChange</code></td><td><code>void (*)(WidgetT *w)</code></td>
<td>Fires when the widget's value changes (text, selection, check state, etc.).</td></tr>
<tr><td><code>onFocus</code></td><td><code>void (*)(WidgetT *w)</code></td>
<td>Fires when the widget receives keyboard focus.</td></tr>
<tr><td><code>onBlur</code></td><td><code>void (*)(WidgetT *w)</code></td>
<td>Fires when the widget loses keyboard focus.</td></tr>
<tr><td><code>onKeyPress</code></td><td><code>void (*)(WidgetT *w, int32_t keyAscii)</code></td>
<td>Fires on a printable key press (ASCII value).</td></tr>
<tr><td><code>onKeyDown</code></td><td><code>void (*)(WidgetT *w, int32_t keyCode, int32_t shift)</code></td>
<td>Fires on key down (scan code + shift state).</td></tr>
<tr><td><code>onKeyUp</code></td><td><code>void (*)(WidgetT *w, int32_t keyCode, int32_t shift)</code></td>
<td>Fires on key up.</td></tr>
<tr><td><code>onMouseDown</code></td><td><code>void (*)(WidgetT *w, int32_t button, int32_t x, int32_t y)</code></td>
<td>Fires on mouse button press.</td></tr>
<tr><td><code>onMouseUp</code></td><td><code>void (*)(WidgetT *w, int32_t button, int32_t x, int32_t y)</code></td>
<td>Fires on mouse button release.</td></tr>
<tr><td><code>onMouseMove</code></td><td><code>void (*)(WidgetT *w, int32_t button, int32_t x, int32_t y)</code></td>
<td>Fires on mouse movement over the widget.</td></tr>
<tr><td><code>onScroll</code></td><td><code>void (*)(WidgetT *w, int32_t delta)</code></td>
<td>Fires on mouse wheel scroll.</td></tr>
<tr><td><code>onValidate</code></td><td><code>bool (*)(WidgetT *w)</code></td>
<td>Validation callback. Return false to cancel a pending write.</td></tr>
</table>
<h3>Common Operations</h3>
<table>
<tr><th>Function</th><th>Description</th></tr>
<tr><td><code>WidgetT *wgtInitWindow(AppContextT *ctx, WindowT *win)</code></td>
<td>Initialize widgets for a window. Returns the root VBox container.</td></tr>
<tr><td><code>AppContextT *wgtGetContext(const WidgetT *w)</code></td>
<td>Walk up from any widget to retrieve the AppContextT.</td></tr>
<tr><td><code>void wgtInvalidate(WidgetT *w)</code></td>
<td>Mark widget for re-layout and repaint. Propagates to ancestors.</td></tr>
<tr><td><code>void wgtInvalidatePaint(WidgetT *w)</code></td>
<td>Mark widget for repaint only (no layout recalculation).</td></tr>
<tr><td><code>void wgtSetText(WidgetT *w, const char *text)</code></td>
<td>Set widget text (label, button, textinput, etc.).</td></tr>
<tr><td><code>const char *wgtGetText(const WidgetT *w)</code></td>
<td>Get widget text.</td></tr>
<tr><td><code>void wgtSetEnabled(WidgetT *w, bool enabled)</code></td>
<td>Enable or disable a widget.</td></tr>
<tr><td><code>void wgtSetReadOnly(WidgetT *w, bool readOnly)</code></td>
<td>Set read-only mode.</td></tr>
<tr><td><code>void wgtSetFocused(WidgetT *w)</code></td>
<td>Set keyboard focus to a widget.</td></tr>
<tr><td><code>WidgetT *wgtGetFocused(void)</code></td>
<td>Get the currently focused widget.</td></tr>
<tr><td><code>void wgtSetVisible(WidgetT *w, bool visible)</code></td>
<td>Show or hide a widget.</td></tr>
<tr><td><code>void wgtSetName(WidgetT *w, const char *name)</code></td>
<td>Set widget name for lookup.</td></tr>
<tr><td><code>WidgetT *wgtFind(WidgetT *root, const char *name)</code></td>
<td>Find a widget by name in the subtree.</td></tr>
<tr><td><code>void wgtDestroy(WidgetT *w)</code></td>
<td>Destroy a widget and all its children.</td></tr>
<tr><td><code>void wgtSetTooltip(WidgetT *w, const char *text)</code></td>
<td>Set tooltip text. Pass NULL to remove.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- ANSITERM -->
<!-- ============================================================ -->
<div class="widget-section" id="ansiterm">
<h2>AnsiTerm</h2>
<p>
A VT100/ANSI-compatible terminal emulator widget designed for connecting to
BBS systems over the serial link. Uses a traditional text-mode cell buffer
(character + attribute byte pairs) with the CP437 character set and 16-color
CGA palette. Supports cursor movement, screen/line erase, scrolling regions,
SGR colors, and scrollback history. Communication is abstracted through
read/write function pointers, allowing the terminal to work with raw serial
ports, the secLink encrypted channel, or any other byte-oriented transport.
</p>
<p>Header: <code>widgets/widgetAnsiTerm.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *term = wgtAnsiTerm(parent, 80, 25);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtAnsiTerm(parent, cols, rows)</code></td><td>Create an ANSI terminal widget with the given column and row dimensions.</td></tr>
<tr><td><code>wgtAnsiTermWrite(w, data, len)</code></td><td>Write raw bytes into the terminal's ANSI parser. <code>data</code> is a <code>const uint8_t *</code> buffer, <code>len</code> is the byte count.</td></tr>
<tr><td><code>wgtAnsiTermClear(w)</code></td><td>Clear the terminal screen and reset the cursor to the home position.</td></tr>
<tr><td><code>wgtAnsiTermSetComm(w, ctx, readFn, writeFn)</code></td><td>Attach a communication channel. <code>readFn</code> and <code>writeFn</code> are I/O callbacks; <code>ctx</code> is passed as their first argument.</td></tr>
<tr><td><code>wgtAnsiTermSetScrollback(w, maxLines)</code></td><td>Set the maximum number of scrollback lines. Lines scrolled off the top are saved in a circular buffer.</td></tr>
<tr><td><code>wgtAnsiTermPoll(w)</code></td><td>Poll the communication channel for incoming data and feed it into the ANSI parser.</td></tr>
<tr><td><code>wgtAnsiTermRepaint(w, outY, outH)</code></td><td>Fast repaint path that renders dirty rows directly into the window's content buffer, bypassing the widget pipeline. Returns the dirty region via <code>outY</code>/<code>outH</code>.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Cols</code></td><td>Integer</td><td>Read-only</td><td>Number of columns.</td></tr>
<tr><td><code>Rows</code></td><td>Integer</td><td>Read-only</td><td>Number of rows.</td></tr>
<tr><td><code>Scrollback</code></td><td>Integer</td><td>Write-only</td><td>Maximum scrollback lines.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>Clear</code></td><td>Clear the terminal screen.</td></tr>
<tr><td><code>Write</code></td><td>Write a string into the terminal.</td></tr>
</table>
<h3>Events</h3>
<p>AnsiTerm uses the common events only. No widget-specific events are defined.</p>
</div>
<!-- ============================================================ -->
<!-- BOX -->
<!-- ============================================================ -->
<div class="widget-section" id="box">
<h2>Box (VBox / HBox / Frame)</h2>
<p>
Container widgets that arrange their children in a vertical column (VBox),
horizontal row (HBox), or a titled group box (Frame). These are the primary
layout building blocks. Children are laid out using a flexbox-like algorithm
with weight-based extra-space distribution.
</p>
<p>Header: <code>widgets/widgetBox.h</code></p>
<h3>Creation</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtVBox(parent)</code></td><td>Create a vertical box container. Children are stacked top to bottom.</td></tr>
<tr><td><code>wgtHBox(parent)</code></td><td>Create a horizontal box container. Children are placed left to right.</td></tr>
<tr><td><code>wgtFrame(parent, title)</code></td><td>Create a titled group box (a VBox with a border and label).</td></tr>
</table>
<h3>Properties</h3>
<p>Box containers use the common <code>WidgetT</code> fields for layout control:</p>
<table>
<tr><th>Property</th><th>Description</th></tr>
<tr><td><code>align</code></td><td>Main-axis alignment of children. HBox: Start=left, Center=center, End=right. VBox: Start=top, Center=center, End=bottom.</td></tr>
<tr><td><code>spacing</code></td><td>Gap between children (tagged size).</td></tr>
<tr><td><code>padding</code></td><td>Internal padding around children (tagged size).</td></tr>
<tr><td><code>weight</code></td><td>Controls how the box itself stretches within its parent.</td></tr>
</table>
<h3>Events</h3>
<p>Containers use the common events only. No widget-specific events.</p>
</div>
<!-- ============================================================ -->
<!-- BUTTON -->
<!-- ============================================================ -->
<div class="widget-section" id="button">
<h2>Button</h2>
<p>
A push button with a text label. Fires <code>onClick</code> when pressed
and released. Supports keyboard activation via accelerator keys.
</p>
<p>Header: <code>widgets/widgetButton.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *btn = wgtButton(parent, "OK");</pre>
<h3>Macro</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtButton(parent, text)</code></td><td>Create a push button with the given label text.</td></tr>
</table>
<h3>Properties</h3>
<p>Uses common <code>WidgetT</code> properties. Set <code>accelKey</code> for keyboard shortcut. Use <code>wgtSetText()</code> / <code>wgtGetText()</code> to change the label.</p>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when the button is clicked (press + release).</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- LABEL -->
<!-- ============================================================ -->
<div class="widget-section" id="label">
<h2>Label</h2>
<p>
A static text label. Does not accept keyboard focus. Typically used to
describe other widgets. Supports text alignment and accelerator keys
(with <code>WCLASS_FOCUS_FORWARD</code>, the accelerator moves focus to the
next focusable sibling).
</p>
<p>Header: <code>widgets/widgetLabel.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *lbl = wgtLabel(parent, "Name:");</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtLabel(parent, text)</code></td><td>Create a text label.</td></tr>
<tr><td><code>wgtLabelSetAlign(w, align)</code></td><td>Set the text alignment (<code>AlignStartE</code>, <code>AlignCenterE</code>, <code>AlignEndE</code>).</td></tr>
</table>
<h3>Properties</h3>
<p>Use <code>wgtSetText()</code> / <code>wgtGetText()</code> to change the text. Set <code>accelKey</code> for accelerator support (focus forwards to next focusable widget).</p>
<h3>Events</h3>
<p>Labels use the common events only. Typically no callbacks are set on labels.</p>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Alignment</code></td><td>Enum (Left, Center, Right)</td><td>Read/Write</td><td>Text alignment within the label.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- TEXT INPUT -->
<!-- ============================================================ -->
<div class="widget-section" id="textinput">
<h2>TextInput / TextArea</h2>
<p>
Single-line text input, password input, masked input, and multi-line text area
with optional syntax colorization, line numbers, find/replace, and gutter
decorators.
</p>
<p>Header: <code>widgets/widgetTextInput.h</code></p>
<h3>Creation</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtTextInput(parent, maxLen)</code></td><td>Create a single-line text input. <code>maxLen</code> is the maximum number of characters.</td></tr>
<tr><td><code>wgtPasswordInput(parent, maxLen)</code></td><td>Create a password input (characters displayed as bullets).</td></tr>
<tr><td><code>wgtMaskedInput(parent, mask)</code></td><td>Create a masked input field. The <code>mask</code> string defines the input format.</td></tr>
<tr><td><code>wgtTextArea(parent, maxLen)</code></td><td>Create a multi-line text area.</td></tr>
</table>
<h3>Methods (TextArea-specific)</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtTextAreaSetColorize(w, fn, ctx)</code></td>
<td>Set a syntax colorization callback. The callback receives each line and fills a color index array. Color indices: 0=default, 1=keyword, 2=string, 3=comment, 4=number, 5=operator, 6=type/builtin, 7=reserved.</td></tr>
<tr><td><code>wgtTextAreaGoToLine(w, line)</code></td>
<td>Scroll to and place the cursor on the given line number.</td></tr>
<tr><td><code>wgtTextAreaSetAutoIndent(w, enable)</code></td>
<td>Enable or disable automatic indentation on newline.</td></tr>
<tr><td><code>wgtTextAreaSetShowLineNumbers(w, show)</code></td>
<td>Show or hide line numbers in the gutter.</td></tr>
<tr><td><code>wgtTextAreaSetCaptureTabs(w, capture)</code></td>
<td>When true, Tab key inserts a tab/spaces instead of moving focus.</td></tr>
<tr><td><code>wgtTextAreaSetTabWidth(w, width)</code></td>
<td>Set the tab stop width in characters.</td></tr>
<tr><td><code>wgtTextAreaSetUseTabChar(w, useChar)</code></td>
<td>When true, insert literal tab characters; when false, insert spaces.</td></tr>
<tr><td><code>wgtTextAreaFindNext(w, needle, caseSens, fwd)</code></td>
<td>Search for the next occurrence. Returns <code>true</code> if found.</td></tr>
<tr><td><code>wgtTextAreaReplaceAll(w, needle, repl, caseSens)</code></td>
<td>Replace all occurrences. Returns the number of replacements made.</td></tr>
<tr><td><code>wgtTextAreaSetLineDecorator(w, fn, ctx)</code></td>
<td>Set a gutter line decorator callback. The callback returns a color and receives the line number, a color output pointer, and the user context.</td></tr>
<tr><td><code>wgtTextAreaGetCursorLine(w)</code></td>
<td>Get the current cursor line number.</td></tr>
<tr><td><code>wgtTextAreaSetGutterClick(w, fn)</code></td>
<td>Set a callback for gutter clicks (e.g. for breakpoint toggling). Callback receives the widget and line number.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the text content changes.</td></tr>
<tr><td><code>onKeyPress</code></td><td>Fires on each key press (ASCII value).</td></tr>
<tr><td><code>onValidate</code></td><td>Called before committing a change. Return false to cancel.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- CHECKBOX -->
<!-- ============================================================ -->
<div class="widget-section" id="checkbox">
<h2>Checkbox</h2>
<p>
A toggle control with a text label. Clicking toggles between checked and
unchecked states.
</p>
<p>Header: <code>widgets/widgetCheckbox.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *cb = wgtCheckbox(parent, "Enable logging");</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtCheckbox(parent, text)</code></td><td>Create a checkbox with the given label text.</td></tr>
<tr><td><code>wgtCheckboxIsChecked(w)</code></td><td>Returns <code>true</code> if the checkbox is checked.</td></tr>
<tr><td><code>wgtCheckboxSetChecked(w, checked)</code></td><td>Set the checked state programmatically.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when clicked (after toggle).</td></tr>
<tr><td><code>onChange</code></td><td>Fires when the checked state changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Value</code></td><td>Boolean</td><td>Read/Write</td><td>Whether the checkbox is checked.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- RADIO -->
<!-- ============================================================ -->
<div class="widget-section" id="radio">
<h2>Radio Button</h2>
<p>
A mutually exclusive selection control. Radio buttons must be placed inside
a radio group container. Only one radio button within a group can be selected
at a time.
</p>
<p>Header: <code>widgets/widgetRadio.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *grp = wgtRadioGroup(parent);
WidgetT *r1 = wgtRadio(grp, "Option A");
WidgetT *r2 = wgtRadio(grp, "Option B");</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtRadioGroup(parent)</code></td><td>Create a radio group container.</td></tr>
<tr><td><code>wgtRadio(parent, text)</code></td><td>Create a radio button inside a group.</td></tr>
<tr><td><code>wgtRadioGroupSetSelected(w, idx)</code></td><td>Set the selected radio button by index within the group.</td></tr>
<tr><td><code>wgtRadioGetIndex(w)</code></td><td>Get the index of the currently selected radio button.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires on the radio button when clicked.</td></tr>
<tr><td><code>onChange</code></td><td>Fires when the selection changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Value</code></td><td>Integer</td><td>Read-only</td><td>Index of the currently selected radio button in the group.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>SetSelected</code></td><td>Set the selected radio button by index.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- DROPDOWN -->
<!-- ============================================================ -->
<div class="widget-section" id="dropdown">
<h2>Dropdown</h2>
<p>
A drop-down list that displays a single selected item and expands to show
all options when clicked. Read-only selection (the user cannot type into it).
</p>
<p>Header: <code>widgets/widgetDropdown.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *dd = wgtDropdown(parent);
const char *items[] = { "Red", "Green", "Blue" };
wgtDropdownSetItems(dd, items, 3);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtDropdown(parent)</code></td><td>Create a dropdown list.</td></tr>
<tr><td><code>wgtDropdownSetItems(w, items, count)</code></td><td>Set the list of items. <code>items</code> is a <code>const char **</code> array.</td></tr>
<tr><td><code>wgtDropdownGetSelected(w)</code></td><td>Get the index of the selected item (-1 if none).</td></tr>
<tr><td><code>wgtDropdownSetSelected(w, idx)</code></td><td>Set the selected item by index.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the selected item changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>ListIndex</code></td><td>Integer</td><td>Read/Write</td><td>Index of the currently selected item.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- COMBOBOX -->
<!-- ============================================================ -->
<div class="widget-section" id="combobox">
<h2>ComboBox</h2>
<p>
A combination of a text input and a dropdown list. The user can either type
a value or select from a list of predefined options. Unlike Dropdown, the
text field is editable.
</p>
<p>Header: <code>widgets/widgetComboBox.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *cb = wgtComboBox(parent, 128);
const char *items[] = { "Arial", "Courier", "Times" };
wgtComboBoxSetItems(cb, items, 3);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtComboBox(parent, maxLen)</code></td><td>Create a combo box. <code>maxLen</code> is the maximum text input length.</td></tr>
<tr><td><code>wgtComboBoxSetItems(w, items, count)</code></td><td>Set the dropdown items.</td></tr>
<tr><td><code>wgtComboBoxGetSelected(w)</code></td><td>Get the index of the selected item (-1 if the text does not match any item).</td></tr>
<tr><td><code>wgtComboBoxSetSelected(w, idx)</code></td><td>Set the selected item by index.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the text or selection changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>ListIndex</code></td><td>Integer</td><td>Read/Write</td><td>Index of the currently selected item.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- DATACTRL -->
<!-- ============================================================ -->
<div class="widget-section" id="datactrl">
<h2>DataCtrl</h2>
<p>
A VB3-style Data control for database binding. Displays a visible navigation
bar that connects to a SQLite database via <code>dvxSql*</code> functions.
Reads all rows from the RecordSource query into an in-memory cache for
bidirectional navigation. Fires Reposition events when the cursor moves so
bound controls can update. Supports master-detail linking between Data
controls.
</p>
<p>Header: <code>widgets/widgetDataCtrl.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *data = wgtDataCtrl(parent);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtDataCtrl(parent)</code></td><td>Create a Data control.</td></tr>
<tr><td><code>wgtDataCtrlRefresh(w)</code></td><td>Re-execute the RecordSource query and rebuild the row cache.</td></tr>
<tr><td><code>wgtDataCtrlMoveFirst(w)</code></td><td>Move the cursor to the first row.</td></tr>
<tr><td><code>wgtDataCtrlMovePrev(w)</code></td><td>Move the cursor to the previous row.</td></tr>
<tr><td><code>wgtDataCtrlMoveNext(w)</code></td><td>Move the cursor to the next row.</td></tr>
<tr><td><code>wgtDataCtrlMoveLast(w)</code></td><td>Move the cursor to the last row.</td></tr>
<tr><td><code>wgtDataCtrlGetField(w, colName)</code></td><td>Get the value of a column in the current row. Returns <code>const char *</code>.</td></tr>
<tr><td><code>wgtDataCtrlSetField(w, colName, value)</code></td><td>Set the value of a column in the current row (marks the row dirty).</td></tr>
<tr><td><code>wgtDataCtrlUpdateRow(w)</code></td><td>Write the current row's pending changes back to the database.</td></tr>
<tr><td><code>wgtDataCtrlUpdate(w)</code></td><td>Flush all pending changes to the database.</td></tr>
<tr><td><code>wgtDataCtrlAddNew(w)</code></td><td>Begin a new row. Sets dirty state; call Update to commit.</td></tr>
<tr><td><code>wgtDataCtrlDelete(w)</code></td><td>Delete the current row from the database.</td></tr>
<tr><td><code>wgtDataCtrlSetMasterValue(w, val)</code></td><td>Set the master-detail filter value for this control.</td></tr>
<tr><td><code>wgtDataCtrlGetRowCount(w)</code></td><td>Get the total number of cached rows.</td></tr>
<tr><td><code>wgtDataCtrlGetColCount(w)</code></td><td>Get the number of columns in the result set.</td></tr>
<tr><td><code>wgtDataCtrlGetColName(w, col)</code></td><td>Get the name of a column by index. Returns <code>const char *</code>.</td></tr>
<tr><td><code>wgtDataCtrlGetCellText(w, row, col)</code></td><td>Get the text of a specific cell by row and column index. Returns <code>const char *</code>.</td></tr>
<tr><td><code>wgtDataCtrlSetCurrentRow(w, row)</code></td><td>Set the current row by index (0-based).</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>DatabaseName</code></td><td>String</td><td>Read/Write</td><td>Path to the SQLite database file.</td></tr>
<tr><td><code>RecordSource</code></td><td>String</td><td>Read/Write</td><td>SQL query or table name for the result set.</td></tr>
<tr><td><code>KeyColumn</code></td><td>String</td><td>Read/Write</td><td>Primary key column name (used for UPDATE/DELETE).</td></tr>
<tr><td><code>MasterSource</code></td><td>String</td><td>Read/Write</td><td>Name of the master Data control for master-detail linking.</td></tr>
<tr><td><code>MasterField</code></td><td>String</td><td>Read/Write</td><td>Column in the master control to read for the filter value.</td></tr>
<tr><td><code>DetailField</code></td><td>String</td><td>Read/Write</td><td>Column in this table to filter by the master value.</td></tr>
<tr><td><code>Caption</code></td><td>String</td><td>Read/Write</td><td>Text displayed on the navigation bar.</td></tr>
<tr><td><code>BOF</code></td><td>Boolean</td><td>Read-only</td><td>True when the cursor is before the first row.</td></tr>
<tr><td><code>EOF</code></td><td>Boolean</td><td>Read-only</td><td>True when the cursor is past the last row.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>AddNew</code></td><td>Begin a new row.</td></tr>
<tr><td><code>Delete</code></td><td>Delete the current row.</td></tr>
<tr><td><code>MoveFirst</code></td><td>Move to the first row.</td></tr>
<tr><td><code>MoveLast</code></td><td>Move to the last row.</td></tr>
<tr><td><code>MoveNext</code></td><td>Move to the next row.</td></tr>
<tr><td><code>MovePrevious</code></td><td>Move to the previous row.</td></tr>
<tr><td><code>Refresh</code></td><td>Re-execute the query and rebuild the cache.</td></tr>
<tr><td><code>Update</code></td><td>Write pending changes to the database.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Event</th><th>Description</th></tr>
<tr><td><code>Reposition</code></td><td>Fires when the current row changes (navigation, refresh, etc.). Default event.</td></tr>
<tr><td><code>Validate</code></td><td>Fires before writing changes. Return false to cancel.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- DBGRID -->
<!-- ============================================================ -->
<div class="widget-section" id="dbgrid">
<h2>DbGrid</h2>
<p>
A database grid widget that displays all records from a Data control in a
scrollable, sortable table. Columns auto-populate from the Data control's
column names and can be hidden, resized, and renamed by the application.
Clicking a column header sorts the display. Selecting a row syncs the
Data control's cursor position. The grid reads directly from the Data
control's cached rows, so there is no separate copy of the data.
</p>
<p>Header: <code>widgets/widgetDbGrid.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *grid = wgtDbGrid(parent);
wgtDbGridSetDataWidget(grid, dataCtrl);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtDbGrid(parent)</code></td><td>Create a database grid widget.</td></tr>
<tr><td><code>wgtDbGridSetDataWidget(w, dataWidget)</code></td><td>Bind the grid to a Data control. The grid reads rows from this widget.</td></tr>
<tr><td><code>wgtDbGridRefresh(w)</code></td><td>Re-read the Data control's state and repaint the grid.</td></tr>
<tr><td><code>wgtDbGridSetColumnVisible(w, fieldName, visible)</code></td><td>Show or hide a column by field name.</td></tr>
<tr><td><code>wgtDbGridSetColumnHeader(w, fieldName, header)</code></td><td>Set a display header for a column (overrides the field name).</td></tr>
<tr><td><code>wgtDbGridSetColumnWidth(w, fieldName, width)</code></td><td>Set the width of a column by field name (tagged size, 0 = auto).</td></tr>
<tr><td><code>wgtDbGridGetSelectedRow(w)</code></td><td>Get the index of the currently selected data row (-1 if none).</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>GridLines</code></td><td>Boolean</td><td>Read/Write</td><td>Whether to draw grid lines between cells.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>Refresh</code></td><td>Re-read the Data control and repaint.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Event</th><th>Description</th></tr>
<tr><td><code>Click</code></td><td>Fires when a row is clicked.</td></tr>
<tr><td><code>DblClick</code></td><td>Fires when a row is double-clicked. Default event.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- LISTBOX -->
<!-- ============================================================ -->
<div class="widget-section" id="listbox">
<h2>ListBox</h2>
<p>
A scrollable list of text items. Supports single and multi-selection modes
and drag-to-reorder.
</p>
<p>Header: <code>widgets/widgetListBox.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *lb = wgtListBox(parent);
const char *items[] = { "Alpha", "Beta", "Gamma" };
wgtListBoxSetItems(lb, items, 3);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtListBox(parent)</code></td><td>Create a list box.</td></tr>
<tr><td><code>wgtListBoxSetItems(w, items, count)</code></td><td>Set the list items.</td></tr>
<tr><td><code>wgtListBoxGetSelected(w)</code></td><td>Get the index of the selected item (-1 if none).</td></tr>
<tr><td><code>wgtListBoxSetSelected(w, idx)</code></td><td>Set the selected item by index.</td></tr>
<tr><td><code>wgtListBoxSetMultiSelect(w, multi)</code></td><td>Enable or disable multi-selection mode.</td></tr>
<tr><td><code>wgtListBoxIsItemSelected(w, idx)</code></td><td>Check if a specific item is selected (multi-select mode).</td></tr>
<tr><td><code>wgtListBoxSetItemSelected(w, idx, selected)</code></td><td>Select or deselect a specific item.</td></tr>
<tr><td><code>wgtListBoxSelectAll(w)</code></td><td>Select all items (multi-select mode).</td></tr>
<tr><td><code>wgtListBoxClearSelection(w)</code></td><td>Deselect all items.</td></tr>
<tr><td><code>wgtListBoxSetReorderable(w, reorderable)</code></td><td>Enable drag-to-reorder.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when an item is clicked.</td></tr>
<tr><td><code>onDblClick</code></td><td>Fires when an item is double-clicked.</td></tr>
<tr><td><code>onChange</code></td><td>Fires when the selection changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>ListIndex</code></td><td>Integer</td><td>Read/Write</td><td>Index of the currently selected item.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>SelectAll</code></td><td>Select all items.</td></tr>
<tr><td><code>ClearSelection</code></td><td>Deselect all items.</td></tr>
<tr><td><code>SetMultiSelect</code></td><td>Enable or disable multi-selection.</td></tr>
<tr><td><code>SetReorderable</code></td><td>Enable or disable drag-to-reorder.</td></tr>
<tr><td><code>IsItemSelected</code></td><td>Check if a specific item is selected by index.</td></tr>
<tr><td><code>SetItemSelected</code></td><td>Select or deselect a specific item by index.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- LISTVIEW -->
<!-- ============================================================ -->
<div class="widget-section" id="listview">
<h2>ListView</h2>
<p>
A multi-column list with sortable headers. Supports single and multi-selection,
column alignment, header click sorting, and drag-to-reorder. Data is provided
as a flat array of strings (row-major order, one string per cell).
</p>
<p>Header: <code>widgets/widgetListView.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *lv = wgtListView(parent);
ListViewColT cols[] = {
{ "Name", wgtChars(20), ListViewAlignLeftE },
{ "Size", wgtChars(10), ListViewAlignRightE }
};
wgtListViewSetColumns(lv, cols, 2);
const char *cells[] = { "file.txt", "1234", "readme.md", "5678" };
wgtListViewSetData(lv, cells, 2);</pre>
<h3>Column Definition</h3>
<pre>typedef struct {
const char *title;
int32_t width; // tagged size (wgtPixels/wgtChars/wgtPercent, 0 = auto)
ListViewAlignE align; // ListViewAlignLeftE, ListViewAlignCenterE, ListViewAlignRightE
} ListViewColT;</pre>
<h3>Sort Direction</h3>
<pre>typedef enum {
ListViewSortNoneE,
ListViewSortAscE,
ListViewSortDescE
} ListViewSortE;</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtListView(parent)</code></td><td>Create a list view.</td></tr>
<tr><td><code>wgtListViewSetColumns(w, cols, count)</code></td><td>Define columns from an array of <code>ListViewColT</code>.</td></tr>
<tr><td><code>wgtListViewSetData(w, cellData, rowCount)</code></td><td>Set row data. <code>cellData</code> is a flat <code>const char **</code> array of size <code>rowCount * colCount</code>.</td></tr>
<tr><td><code>wgtListViewGetSelected(w)</code></td><td>Get the index of the selected row (-1 if none).</td></tr>
<tr><td><code>wgtListViewSetSelected(w, idx)</code></td><td>Set the selected row by index.</td></tr>
<tr><td><code>wgtListViewSetSort(w, col, dir)</code></td><td>Set the sort column and direction.</td></tr>
<tr><td><code>wgtListViewSetHeaderClickCallback(w, cb)</code></td><td>Set a callback for header clicks. Signature: <code>void (*cb)(WidgetT *w, int32_t col, ListViewSortE dir)</code>.</td></tr>
<tr><td><code>wgtListViewSetMultiSelect(w, multi)</code></td><td>Enable or disable multi-selection.</td></tr>
<tr><td><code>wgtListViewIsItemSelected(w, idx)</code></td><td>Check if a specific row is selected.</td></tr>
<tr><td><code>wgtListViewSetItemSelected(w, idx, selected)</code></td><td>Select or deselect a specific row.</td></tr>
<tr><td><code>wgtListViewSelectAll(w)</code></td><td>Select all rows.</td></tr>
<tr><td><code>wgtListViewClearSelection(w)</code></td><td>Deselect all rows.</td></tr>
<tr><td><code>wgtListViewSetReorderable(w, reorderable)</code></td><td>Enable drag-to-reorder of rows.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when a row is clicked.</td></tr>
<tr><td><code>onDblClick</code></td><td>Fires when a row is double-clicked.</td></tr>
<tr><td><code>onChange</code></td><td>Fires when the selection changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>ListIndex</code></td><td>Integer</td><td>Read/Write</td><td>Index of the currently selected row.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>SelectAll</code></td><td>Select all rows.</td></tr>
<tr><td><code>ClearSelection</code></td><td>Deselect all rows.</td></tr>
<tr><td><code>SetMultiSelect</code></td><td>Enable or disable multi-selection.</td></tr>
<tr><td><code>SetReorderable</code></td><td>Enable or disable drag-to-reorder.</td></tr>
<tr><td><code>IsItemSelected</code></td><td>Check if a specific row is selected by index.</td></tr>
<tr><td><code>SetItemSelected</code></td><td>Select or deselect a specific row by index.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- TREEVIEW -->
<!-- ============================================================ -->
<div class="widget-section" id="treeview">
<h2>TreeView</h2>
<p>
A hierarchical tree control with expandable/collapsible nodes. Supports
single and multi-selection and drag-to-reorder. Tree items are added as
children of the TreeView or of other tree items to create nested hierarchies.
</p>
<p>Header: <code>widgets/widgetTreeView.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *tv = wgtTreeView(parent);
WidgetT *root = wgtTreeItem(tv, "Root");
WidgetT *child = wgtTreeItem(root, "Child");</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtTreeView(parent)</code></td><td>Create a tree view control.</td></tr>
<tr><td><code>wgtTreeItem(parent, text)</code></td><td>Add a tree item as a child of the tree view or another tree item.</td></tr>
<tr><td><code>wgtTreeViewGetSelected(w)</code></td><td>Get the currently selected tree item (returns <code>WidgetT *</code>, NULL if none).</td></tr>
<tr><td><code>wgtTreeViewSetSelected(w, item)</code></td><td>Set the selected tree item.</td></tr>
<tr><td><code>wgtTreeViewSetMultiSelect(w, multi)</code></td><td>Enable or disable multi-selection.</td></tr>
<tr><td><code>wgtTreeViewSetReorderable(w, reorderable)</code></td><td>Enable drag-to-reorder of items.</td></tr>
<tr><td><code>wgtTreeItemSetExpanded(w, expanded)</code></td><td>Expand or collapse a tree item.</td></tr>
<tr><td><code>wgtTreeItemIsExpanded(w)</code></td><td>Check if a tree item is expanded.</td></tr>
<tr><td><code>wgtTreeItemIsSelected(w)</code></td><td>Check if a tree item is selected (multi-select mode).</td></tr>
<tr><td><code>wgtTreeItemSetSelected(w, selected)</code></td><td>Select or deselect a tree item.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when a tree item is clicked.</td></tr>
<tr><td><code>onDblClick</code></td><td>Fires when a tree item is double-clicked.</td></tr>
<tr><td><code>onChange</code></td><td>Fires when the selection changes.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>SetMultiSelect</code></td><td>Enable or disable multi-selection.</td></tr>
<tr><td><code>SetReorderable</code></td><td>Enable or disable drag-to-reorder.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- IMAGE -->
<!-- ============================================================ -->
<div class="widget-section" id="image">
<h2>Image</h2>
<p>
Displays a bitmap image. Can be created from raw pixel data or loaded from
a BMP file on disk. The image is rendered at its natural size within the
widget bounds.
</p>
<p>Header: <code>widgets/widgetImage.h</code></p>
<h3>Creation</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtImage(parent, data, w, h, pitch)</code></td><td>Create an image widget from raw pixel data. <code>data</code> is a <code>uint8_t *</code> pixel buffer, <code>w</code>/<code>h</code> are dimensions, <code>pitch</code> is bytes per row.</td></tr>
<tr><td><code>wgtImageFromFile(parent, path)</code></td><td>Create an image widget by loading a BMP file from disk.</td></tr>
</table>
<h3>Methods</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtImageSetData(w, data, imgW, imgH, pitch)</code></td><td>Replace the displayed image with new raw pixel data.</td></tr>
<tr><td><code>wgtImageLoadFile(w, path)</code></td><td>Replace the displayed image by loading a new file.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when the image is clicked.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Picture</code></td><td>String</td><td>Write-only</td><td>Load an image from a file path.</td></tr>
<tr><td><code>ImageWidth</code></td><td>Integer</td><td>Read-only</td><td>Width of the currently loaded image in pixels.</td></tr>
<tr><td><code>ImageHeight</code></td><td>Integer</td><td>Read-only</td><td>Height of the currently loaded image in pixels.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- IMAGEBUTTON -->
<!-- ============================================================ -->
<div class="widget-section" id="imagebutton">
<h2>ImageButton</h2>
<p>
A clickable button that displays an image instead of text. Has press/release
visual feedback like a regular button. Can be created from raw pixel data or
a BMP file.
</p>
<p>Header: <code>widgets/widgetImageButton.h</code></p>
<h3>Creation</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtImageButton(parent, data, w, h, pitch)</code></td><td>Create an image button from raw pixel data.</td></tr>
<tr><td><code>wgtImageButtonFromFile(parent, path)</code></td><td>Create an image button by loading a BMP file.</td></tr>
</table>
<h3>Methods</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtImageButtonSetData(w, data, imgW, imgH, pitch)</code></td><td>Replace the image with new raw pixel data.</td></tr>
<tr><td><code>wgtImageButtonLoadFile(w, path)</code></td><td>Replace the image by loading a new file.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when the image button is clicked (press + release).</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Picture</code></td><td>String</td><td>Write-only</td><td>Load an image from a file path.</td></tr>
<tr><td><code>ImageWidth</code></td><td>Integer</td><td>Read-only</td><td>Width of the currently loaded image in pixels.</td></tr>
<tr><td><code>ImageHeight</code></td><td>Integer</td><td>Read-only</td><td>Height of the currently loaded image in pixels.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- SLIDER -->
<!-- ============================================================ -->
<div class="widget-section" id="slider">
<h2>Slider</h2>
<p>
A horizontal slider (track bar) for selecting an integer value within a
range. The user drags the thumb or clicks the track to change the value.
</p>
<p>Header: <code>widgets/widgetSlider.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *sl = wgtSlider(parent, 0, 100);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtSlider(parent, minVal, maxVal)</code></td><td>Create a slider with the given integer range.</td></tr>
<tr><td><code>wgtSliderSetValue(w, value)</code></td><td>Set the slider value programmatically.</td></tr>
<tr><td><code>wgtSliderGetValue(w)</code></td><td>Get the current slider value.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the slider value changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Value</code></td><td>Integer</td><td>Read/Write</td><td>Current slider value.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- SPINNER -->
<!-- ============================================================ -->
<div class="widget-section" id="spinner">
<h2>Spinner</h2>
<p>
A numeric input with up/down buttons for incrementing and decrementing a
value within a range. Supports both integer and floating-point (real) modes.
</p>
<p>Header: <code>widgets/widgetSpinner.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *sp = wgtSpinner(parent, 0, 100, 1);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtSpinner(parent, minVal, maxVal, step)</code></td><td>Create a spinner with the given integer range and step size.</td></tr>
<tr><td><code>wgtSpinnerSetValue(w, value)</code></td><td>Set the integer value.</td></tr>
<tr><td><code>wgtSpinnerGetValue(w)</code></td><td>Get the current integer value.</td></tr>
<tr><td><code>wgtSpinnerSetRange(w, minVal, maxVal)</code></td><td>Set the integer range.</td></tr>
<tr><td><code>wgtSpinnerSetStep(w, step)</code></td><td>Set the integer step size.</td></tr>
<tr><td><code>wgtSpinnerSetRealMode(w, enable)</code></td><td>Switch to floating-point mode.</td></tr>
<tr><td><code>wgtSpinnerGetRealValue(w)</code></td><td>Get the current floating-point value.</td></tr>
<tr><td><code>wgtSpinnerSetRealValue(w, value)</code></td><td>Set the floating-point value.</td></tr>
<tr><td><code>wgtSpinnerSetRealRange(w, minVal, maxVal)</code></td><td>Set the floating-point range.</td></tr>
<tr><td><code>wgtSpinnerSetRealStep(w, step)</code></td><td>Set the floating-point step size.</td></tr>
<tr><td><code>wgtSpinnerSetDecimals(w, decimals)</code></td><td>Set the number of decimal places displayed in real mode.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the value changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Value</code></td><td>Integer</td><td>Read/Write</td><td>Current integer value.</td></tr>
<tr><td><code>RealMode</code></td><td>Boolean</td><td>Read/Write</td><td>Whether floating-point mode is active.</td></tr>
<tr><td><code>Decimals</code></td><td>Integer</td><td>Read/Write</td><td>Number of decimal places displayed in real mode.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>SetRange</code></td><td>Set the integer range (min, max).</td></tr>
<tr><td><code>SetStep</code></td><td>Set the integer step size.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- PROGRESSBAR -->
<!-- ============================================================ -->
<div class="widget-section" id="progressbar">
<h2>ProgressBar</h2>
<p>
A visual indicator of progress, displayed as a filled bar. Supports both
horizontal and vertical orientations. Value ranges from 0 to 100.
</p>
<p>Header: <code>widgets/widgetProgressBar.h</code></p>
<h3>Creation</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtProgressBar(parent)</code></td><td>Create a horizontal progress bar.</td></tr>
<tr><td><code>wgtProgressBarV(parent)</code></td><td>Create a vertical progress bar.</td></tr>
</table>
<h3>Methods</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtProgressBarSetValue(w, value)</code></td><td>Set the progress value (0-100).</td></tr>
<tr><td><code>wgtProgressBarGetValue(w)</code></td><td>Get the current progress value.</td></tr>
</table>
<h3>Events</h3>
<p>ProgressBar is a display-only widget. Typically no callbacks are set.</p>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Value</code></td><td>Integer</td><td>Read/Write</td><td>Current progress value (0-100).</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- CANVAS -->
<!-- ============================================================ -->
<div class="widget-section" id="canvas">
<h2>Canvas</h2>
<p>
A freeform drawing surface with a fixed-size pixel buffer. Provides drawing
primitives (lines, rectangles, circles, text, individual pixels) and supports
save/load to BMP files. Mouse interaction is available via a callback.
</p>
<p>Header: <code>widgets/widgetCanvas.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *cv = wgtCanvas(parent, 320, 200);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtCanvas(parent, w, h)</code></td><td>Create a canvas with the given pixel dimensions.</td></tr>
<tr><td><code>wgtCanvasClear(w, color)</code></td><td>Fill the entire canvas with a solid color.</td></tr>
<tr><td><code>wgtCanvasSetPenColor(w, color)</code></td><td>Set the drawing pen color.</td></tr>
<tr><td><code>wgtCanvasSetPenSize(w, size)</code></td><td>Set the drawing pen size in pixels.</td></tr>
<tr><td><code>wgtCanvasDrawLine(w, x0, y0, x1, y1)</code></td><td>Draw a line from (x0,y0) to (x1,y1).</td></tr>
<tr><td><code>wgtCanvasDrawRect(w, x, y, width, height)</code></td><td>Draw a rectangle outline.</td></tr>
<tr><td><code>wgtCanvasFillRect(w, x, y, width, height)</code></td><td>Draw a filled rectangle.</td></tr>
<tr><td><code>wgtCanvasFillCircle(w, cx, cy, radius)</code></td><td>Draw a filled circle.</td></tr>
<tr><td><code>wgtCanvasSetPixel(w, x, y, color)</code></td><td>Set a single pixel to the given color.</td></tr>
<tr><td><code>wgtCanvasGetPixel(w, x, y)</code></td><td>Get the color of a single pixel.</td></tr>
<tr><td><code>wgtCanvasDrawText(w, x, y, text)</code></td><td>Draw text at the given position using the current pen color.</td></tr>
<tr><td><code>wgtCanvasSetMouseCallback(w, cb)</code></td><td>Set a mouse interaction callback. Signature: <code>void (*cb)(WidgetT *w, int32_t cx, int32_t cy, bool drag)</code>. Receives canvas-relative coordinates and whether the mouse is being dragged.</td></tr>
<tr><td><code>wgtCanvasSave(w, path)</code></td><td>Save the canvas contents to a BMP file.</td></tr>
<tr><td><code>wgtCanvasLoad(w, path)</code></td><td>Load a BMP file into the canvas.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires when the canvas is clicked.</td></tr>
<tr><td>Mouse callback (set via <code>wgtCanvasSetMouseCallback</code>)</td><td>Fires on mouse down and drag with canvas-local coordinates.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>Clear</code></td><td>Clear the canvas to a given color.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- TIMER -->
<!-- ============================================================ -->
<div class="widget-section" id="timer">
<h2>Timer</h2>
<p>
A non-visual widget that fires its <code>onClick</code> callback at a
regular interval. Useful for animations, polling, and periodic updates.
Must be explicitly started after creation.
</p>
<p>Header: <code>widgets/widgetTimer.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *tmr = wgtTimer(parent, 1000, true); // 1 second, repeating
tmr-&gt;onClick = onTimerTick;
wgtTimerStart(tmr);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtTimer(parent, intervalMs, repeat)</code></td><td>Create a timer. <code>intervalMs</code> is the interval in milliseconds. <code>repeat</code>: true for repeating, false for one-shot.</td></tr>
<tr><td><code>wgtTimerStart(w)</code></td><td>Start the timer.</td></tr>
<tr><td><code>wgtTimerStop(w)</code></td><td>Stop the timer.</td></tr>
<tr><td><code>wgtTimerSetInterval(w, intervalMs)</code></td><td>Change the timer interval.</td></tr>
<tr><td><code>wgtTimerIsRunning(w)</code></td><td>Returns <code>true</code> if the timer is currently running.</td></tr>
<tr><td><code>wgtUpdateTimers()</code></td><td>Global tick function. Called by the event loop to advance all active timers.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onClick</code></td><td>Fires each time the timer elapses.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Enabled</code></td><td>Boolean</td><td>Read/Write</td><td>Whether the timer is running. Reading returns the running state; writing starts or stops it.</td></tr>
<tr><td><code>Interval</code></td><td>Integer</td><td>Write-only</td><td>Timer interval in milliseconds.</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>Start</code></td><td>Start the timer.</td></tr>
<tr><td><code>Stop</code></td><td>Stop the timer.</td></tr>
</table>
<h3>Extra Events (BASIC Interface)</h3>
<table>
<tr><th>Event</th><th>Description</th></tr>
<tr><td><code>Timer</code></td><td>Fires each time the timer elapses. Default event.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- TOOLBAR -->
<!-- ============================================================ -->
<div class="widget-section" id="toolbar">
<h2>Toolbar</h2>
<p>
A horizontal container for toolbar buttons and controls. Typically placed
at the top of a window. Children (usually ImageButtons or Buttons) are
laid out horizontally with toolbar-appropriate spacing.
</p>
<p>Header: <code>widgets/widgetToolbar.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *tb = wgtToolbar(parent);
wgtImageButtonFromFile(tb, "icons/save.bmp");
wgtImageButtonFromFile(tb, "icons/open.bmp");</pre>
<h3>Macro</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtToolbar(parent)</code></td><td>Create a toolbar container.</td></tr>
</table>
<h3>Properties</h3>
<p>Uses common container properties. Add children (buttons, separators, etc.) to populate the toolbar.</p>
<h3>Events</h3>
<p>Toolbar itself has no widget-specific events. Events fire on the child widgets.</p>
</div>
<!-- ============================================================ -->
<!-- STATUSBAR -->
<!-- ============================================================ -->
<div class="widget-section" id="statusbar">
<h2>StatusBar</h2>
<p>
A horizontal bar typically placed at the bottom of a window for displaying
status text and informational widgets. Children are laid out horizontally.
</p>
<p>Header: <code>widgets/widgetStatusBar.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *sb = wgtStatusBar(parent);
wgtLabel(sb, "Ready");</pre>
<h3>Macro</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtStatusBar(parent)</code></td><td>Create a status bar container.</td></tr>
</table>
<h3>Properties</h3>
<p>Uses common container properties. Add child widgets (labels, progress bars, etc.) to populate.</p>
<h3>Events</h3>
<p>StatusBar itself has no widget-specific events. Events fire on the child widgets.</p>
</div>
<!-- ============================================================ -->
<!-- SCROLLPANE -->
<!-- ============================================================ -->
<div class="widget-section" id="scrollpane">
<h2>ScrollPane</h2>
<p>
A scrollable container that provides vertical and/or horizontal scrollbars
when its content exceeds the visible area. Place a single child (typically
a VBox or HBox) inside the scroll pane.
</p>
<p>Header: <code>widgets/widgetScrollPane.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *sp = wgtScrollPane(parent);
WidgetT *content = wgtVBox(sp);
// add children to content...</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtScrollPane(parent)</code></td><td>Create a scroll pane container.</td></tr>
<tr><td><code>wgtScrollPaneScrollToChild(sp, child)</code></td><td>Scroll so that the given child widget is visible.</td></tr>
<tr><td><code>wgtScrollPaneSetNoBorder(w, noBorder)</code></td><td>When true, removes the border around the scroll pane.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onScroll</code></td><td>Fires when the scroll position changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>NoBorder</code></td><td>Boolean</td><td>Read/Write</td><td>Whether the border around the scroll pane is hidden.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- SPLITTER -->
<!-- ============================================================ -->
<div class="widget-section" id="splitter">
<h2>Splitter</h2>
<p>
A two-pane container with a draggable divider. The user drags the splitter
bar to resize the two panes. Can be oriented vertically (left/right panes)
or horizontally (top/bottom panes). Add exactly two children.
</p>
<p>Header: <code>widgets/widgetSplitter.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *sp = wgtSplitter(parent, true); // vertical = left|right
WidgetT *left = wgtVBox(sp);
WidgetT *right = wgtVBox(sp);</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtSplitter(parent, vertical)</code></td><td>Create a splitter. <code>vertical=true</code> for left/right panes, <code>false</code> for top/bottom.</td></tr>
<tr><td><code>wgtSplitterSetPos(w, pos)</code></td><td>Set the divider position in pixels.</td></tr>
<tr><td><code>wgtSplitterGetPos(w)</code></td><td>Get the current divider position in pixels.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the divider position changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Position</code></td><td>Integer</td><td>Read/Write</td><td>Divider position in pixels.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- TABCONTROL -->
<!-- ============================================================ -->
<div class="widget-section" id="tabcontrol">
<h2>TabControl</h2>
<p>
A tabbed container that displays one page at a time with clickable tabs
along the top. Each tab page is a container that holds its own child widgets.
</p>
<p>Header: <code>widgets/widgetTabControl.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *tabs = wgtTabControl(parent);
WidgetT *page1 = wgtTabPage(tabs, "General");
WidgetT *page2 = wgtTabPage(tabs, "Advanced");
// add children to page1, page2...</pre>
<h3>Macros</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtTabControl(parent)</code></td><td>Create a tab control.</td></tr>
<tr><td><code>wgtTabPage(parent, title)</code></td><td>Add a tab page with the given title. Returns the page container widget.</td></tr>
<tr><td><code>wgtTabControlSetActive(w, idx)</code></td><td>Set the active tab by index (0-based).</td></tr>
<tr><td><code>wgtTabControlGetActive(w)</code></td><td>Get the index of the active tab.</td></tr>
</table>
<h3>Events</h3>
<table>
<tr><th>Callback</th><th>Description</th></tr>
<tr><td><code>onChange</code></td><td>Fires when the active tab changes.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>TabIndex</code></td><td>Integer</td><td>Read/Write</td><td>Index of the currently active tab (0-based).</td></tr>
</table>
<h3>Methods (BASIC Interface)</h3>
<table>
<tr><th>Method</th><th>Description</th></tr>
<tr><td><code>SetActive</code></td><td>Set the active tab by index.</td></tr>
</table>
</div>
<!-- ============================================================ -->
<!-- SEPARATOR -->
<!-- ============================================================ -->
<div class="widget-section" id="separator">
<h2>Separator</h2>
<p>
A visual dividing line used to separate groups of widgets. Available in
horizontal and vertical orientations.
</p>
<p>Header: <code>widgets/widgetSeparator.h</code></p>
<h3>Creation</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtHSeparator(parent)</code></td><td>Create a horizontal separator line.</td></tr>
<tr><td><code>wgtVSeparator(parent)</code></td><td>Create a vertical separator line.</td></tr>
</table>
<h3>Events</h3>
<p>Separator is a visual-only widget. No events.</p>
</div>
<!-- ============================================================ -->
<!-- SPACER -->
<!-- ============================================================ -->
<div class="widget-section" id="spacer">
<h2>Spacer</h2>
<p>
An invisible widget used for layout purposes. By default it has
<code>weight=100</code>, so it absorbs available extra space. Useful for
pushing other widgets apart or aligning them to edges.
</p>
<p>Header: <code>widgets/widgetSpacer.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *row = wgtHBox(parent);
wgtButton(row, "OK");
wgtSpacer(row); // pushes Cancel to the right
wgtButton(row, "Cancel");</pre>
<h3>Macro</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtSpacer(parent)</code></td><td>Create an invisible spacer widget.</td></tr>
</table>
<h3>Events</h3>
<p>Spacer is an invisible layout widget. No events.</p>
</div>
<!-- ============================================================ -->
<!-- WRAPBOX -->
<!-- ============================================================ -->
<div class="widget-section" id="wrapbox">
<h2>WrapBox</h2>
<p>
A flow/wrap layout container that arranges children left-to-right, wrapping
to the next row when the available width is exceeded. Each row's height is
the maximum child height in that row. Supports configurable spacing between
items and rows, and per-row alignment for short rows.
</p>
<p>Header: <code>widgets/widgetWrapBox.h</code></p>
<h3>Creation</h3>
<pre>WidgetT *wrap = wgtWrapBox(parent);
wgtButton(wrap, "Tag 1");
wgtButton(wrap, "Tag 2");
wgtButton(wrap, "Tag 3");</pre>
<h3>Macro</h3>
<table>
<tr><th>Macro</th><th>Description</th></tr>
<tr><td><code>wgtWrapBox(parent)</code></td><td>Create a wrap box container.</td></tr>
</table>
<h3>Properties</h3>
<p>WrapBox uses the common <code>WidgetT</code> container fields for layout control:</p>
<table>
<tr><th>Property</th><th>Description</th></tr>
<tr><td><code>spacing</code></td><td>Gap between children in both the horizontal and vertical directions (tagged size). Default is 4 pixels.</td></tr>
<tr><td><code>padding</code></td><td>Internal padding around children (tagged size). Default is 2 pixels.</td></tr>
</table>
<h3>Properties (BASIC Interface)</h3>
<table>
<tr><th>Property</th><th>Type</th><th>Access</th><th>Description</th></tr>
<tr><td><code>Alignment</code></td><td>Enum (Left, Center, Right)</td><td>Read/Write</td><td>Row alignment for rows that do not fill the full width.</td></tr>
</table>
<h3>Events</h3>
<p>WrapBox is a container widget. It uses the common events only. No widget-specific events are defined.</p>
</div>
<!-- ============================================================ -->
<!-- FOOTER -->
<!-- ============================================================ -->
<hr>
<p style="font-size:0.85em; color:#666;">
DVX Widget Reference -- Generated from source headers in
<code>core/dvxWidget.h</code> and <code>widgets/*.h</code>.
</p>
</body>
</html>