# DVX Widget Modules

Individual widget type implementations, each built as a separate `.wgt`
DXE module. The loader recursively scans the `WIDGETS/` directory at startup and
loads every `.wgt` file it finds. Each module exports `wgtRegister()`,
which registers its widget class(es) and API struct with the core.

Core knows nothing about individual widgets. All per-widget state lives
in `w->data` (allocated by the widget DXE). All per-widget behavior is
dispatched through the `WidgetClassT` vtable. Each widget provides a
public header with its API struct, typed accessor, and convenience
macros.


## ABI-Stable Handler Dispatch

`WidgetClassT` contains a `handlers[WGT_METHOD_MAX]` array of function
pointers. Core dispatches via integer index:
`w->wclass->handlers[WGT_METHOD_PAINT]`, etc. Currently 21 methods are
defined (`WGT_METHOD_COUNT`), with room for 32 (`WGT_METHOD_MAX`).
Adding new methods does not break existing widget DXE binaries -- old
widgets simply have NULL in the new slots.

Key method constants:

| Constant | Index | Signature |
|----------|-------|-----------|
| `WGT_METHOD_PAINT` | 0 | `(w, d, ops, font, colors)` |
| `WGT_METHOD_PAINT_OVERLAY` | 1 | `(w, d, ops, font, colors)` |
| `WGT_METHOD_CALC_MIN_SIZE` | 2 | `(w, font)` |
| `WGT_METHOD_LAYOUT` | 3 | `(w, font)` |
| `WGT_METHOD_ON_MOUSE` | 5 | `(w, root, vx, vy)` |
| `WGT_METHOD_ON_KEY` | 6 | `(w, key, mod)` |
| `WGT_METHOD_DESTROY` | 8 | `(w)` |
| `WGT_METHOD_ON_DRAG_UPDATE` | 15 | `(w, root, x, y)` |
| `WGT_METHOD_ON_DRAG_END` | 16 | `(w, root, x, y)` |
| `WGT_METHOD_QUICK_REPAINT` | 19 | `(w, outY, outH)` |

## Generic Drag Support

Widgets that need drag behavior implement `WGT_METHOD_ON_DRAG_UPDATE`
and `WGT_METHOD_ON_DRAG_END`. Core tracks the drag widget and calls
these methods on mouse move/release during a drag. This replaces
per-widget drag hacks. Used by Slider, Splitter, ListBox (reorder),
ListView (reorder, column resize), and TreeView (reorder).

## Dynamic Limits

All widget child arrays, app slot tables, and callback lists use stb_ds
dynamic arrays. There are no fixed maximums for child count, app count,
or registered callbacks.


## Widget Summary

26 source files produce 26 `.wgt` modules containing 32 widget types:

| Source File | .wgt File | Types | Public Header | Dependencies |
|-------------|-----------|-------|---------------|--------------|
| `widgetBox.c` | `box.wgt` | VBox, HBox, Frame | `widgetBox.h` | -- |
| `widgetButton.c` | `button.wgt` | Button | `widgetButton.h` | -- |
| `widgetLabel.c` | `label.wgt` | Label | `widgetLabel.h` | -- |
| `widgetTextInput.c` | `textinpt.wgt` | TextInput, TextArea | `widgetTextInput.h` | texthelp |
| `widgetCheckbox.c` | `checkbox.wgt` | Checkbox | `widgetCheckbox.h` | -- |
| `widgetRadio.c` | `radio.wgt` | RadioGroup, Radio | `widgetRadio.h` | -- |
| `widgetDropdown.c` | `dropdown.wgt` | Dropdown | `widgetDropdown.h` | listhelp |
| `widgetComboBox.c` | `combobox.wgt` | ComboBox | `widgetComboBox.h` | texthelp, listhelp |
| `widgetListBox.c` | `listbox.wgt` | ListBox | `widgetListBox.h` | listhelp |
| `widgetListView.c` | `listview.wgt` | ListView | `widgetListView.h` | listhelp |
| `widgetTreeView.c` | `treeview.wgt` | TreeView, TreeItem | `widgetTreeView.h` | listhelp |
| `widgetSpinner.c` | `spinner.wgt` | Spinner | `widgetSpinner.h` | texthelp |
| `widgetSlider.c` | `slider.wgt` | Slider | `widgetSlider.h` | -- |
| `widgetProgressBar.c` | `progress.wgt` | ProgressBar | `widgetProgressBar.h` | -- |
| `widgetImage.c` | `image.wgt` | Image | `widgetImage.h` | -- |
| `widgetImageButton.c` | `imgbtn.wgt` | ImageButton | `widgetImageButton.h` | -- |
| `widgetCanvas.c` | `canvas.wgt` | Canvas | `widgetCanvas.h` | -- |
| `widgetSeparator.c` | `separatr.wgt` | Separator | `widgetSeparator.h` | -- |
| `widgetSpacer.c` | `spacer.wgt` | Spacer | `widgetSpacer.h` | -- |
| `widgetTabControl.c` | `tabctrl.wgt` | TabControl, TabPage | `widgetTabControl.h` | -- |
| `widgetScrollPane.c` | `scrlpane.wgt` | ScrollPane | `widgetScrollPane.h` | -- |
| `widgetSplitter.c` | `splitter.wgt` | Splitter | `widgetSplitter.h` | -- |
| `widgetToolbar.c` | `toolbar.wgt` | Toolbar | `widgetToolbar.h` | -- |
| `widgetStatusBar.c` | `statbar.wgt` | StatusBar | `widgetStatusBar.h` | -- |
| `widgetTimer.c` | `timer.wgt` | Timer | `widgetTimer.h` | -- |
| `widgetAnsiTerm.c` | `terminal.wgt` | AnsiTerm | `widgetAnsiTerm.h` | texthelp |


## Dependency Files (.dep)

Widgets that use shared helper libraries need a `.dep` file so the
loader loads the helper first. Dep files are in `config/` and copied
to `bin/widgets/` during build:

| Widget | Dep File | Dependencies |
|--------|----------|--------------|
| textinpt | `textinpt.dep` | texthelp |
| combobox | `combobox.dep` | texthelp, listhelp |
| spinner | `spinner.dep` | texthelp |
| terminal | `terminal.dep` | texthelp |
| dropdown | `dropdown.dep` | listhelp |
| listbox | `listbox.dep` | listhelp |
| listview | `listview.dep` | listhelp |
| treeview | `treeview.dep` | listhelp |


## Per-Widget API Details

### Box (VBox, HBox, Frame)

Container widgets that arrange children vertically or horizontally.
Frame adds a titled border around its children.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `vBox(parent)` | `wgtVBox(parent)` | Create vertical container |
| `hBox(parent)` | `wgtHBox(parent)` | Create horizontal container |
| `frame(parent, title)` | `wgtFrame(parent, title)` | Create titled frame container |

### Button

Push button with text label and accelerator key support.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, text)` | `wgtButton(parent, text)` | Create a button |

### Label

Static text label with optional alignment.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, text)` | `wgtLabel(parent, text)` | Create a label |
| `setAlign(w, align)` | `wgtLabelSetAlign(w, align)` | Set text alignment |

### TextInput / TextArea

Single-line text input, password input, masked input, and multiline
text area. Uses texthelp.lib for editing engine, cursor blink, word
boundaries, clipboard, and selection.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, maxLen)` | `wgtTextInput(parent, maxLen)` | Single-line text input |
| `password(parent, maxLen)` | `wgtPasswordInput(parent, maxLen)` | Password input (masked display) |
| `masked(parent, mask)` | `wgtMaskedInput(parent, mask)` | Masked input (e.g. phone number) |
| `textArea(parent, maxLen)` | `wgtTextArea(parent, maxLen)` | Multiline text editor |

### Checkbox

Toggle checkbox with text label.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, text)` | `wgtCheckbox(parent, text)` | Create a checkbox |
| `isChecked(w)` | `wgtCheckboxIsChecked(w)` | Get checked state |
| `setChecked(w, checked)` | `wgtCheckboxSetChecked(w, checked)` | Set checked state |

### Radio (RadioGroup, Radio)

Mutually exclusive radio buttons within a group container.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `group(parent)` | `wgtRadioGroup(parent)` | Create radio group container |
| `create(parent, text)` | `wgtRadio(parent, text)` | Create radio button in group |
| `groupSetSelected(w, idx)` | `wgtRadioGroupSetSelected(w, idx)` | Select radio by index |
| `getIndex(w)` | `wgtRadioGetIndex(w)` | Get selected index |

### Dropdown

Drop-down selection list with popup overlay.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtDropdown(parent)` | Create a dropdown |
| `setItems(w, items, count)` | `wgtDropdownSetItems(w, items, count)` | Set item list |
| `getSelected(w)` | `wgtDropdownGetSelected(w)` | Get selected index |
| `setSelected(w, idx)` | `wgtDropdownSetSelected(w, idx)` | Set selected index |

### ComboBox

Editable text input with dropdown suggestion list. Combines TextInput
and Dropdown behavior.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, maxLen)` | `wgtComboBox(parent, maxLen)` | Create a combo box |
| `setItems(w, items, count)` | `wgtComboBoxSetItems(w, items, count)` | Set suggestion list |
| `getSelected(w)` | `wgtComboBoxGetSelected(w)` | Get selected index (-1 if typed) |
| `setSelected(w, idx)` | `wgtComboBoxSetSelected(w, idx)` | Select item by index |

### ListBox

Scrollable list of text items with single or multi-select and optional
drag-reorder.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtListBox(parent)` | Create a list box |
| `setItems(w, items, count)` | `wgtListBoxSetItems(w, items, count)` | Set item list |
| `getSelected(w)` | `wgtListBoxGetSelected(w)` | Get selected index |
| `setSelected(w, idx)` | `wgtListBoxSetSelected(w, idx)` | Set selected index |
| `setMultiSelect(w, multi)` | `wgtListBoxSetMultiSelect(w, multi)` | Enable multi-select |
| `isItemSelected(w, idx)` | `wgtListBoxIsItemSelected(w, idx)` | Check if item is selected |
| `setItemSelected(w, idx, sel)` | `wgtListBoxSetItemSelected(w, idx, sel)` | Select/deselect item |
| `selectAll(w)` | `wgtListBoxSelectAll(w)` | Select all items |
| `clearSelection(w)` | `wgtListBoxClearSelection(w)` | Deselect all items |
| `setReorderable(w, r)` | `wgtListBoxSetReorderable(w, r)` | Enable drag reorder |

### ListView

Multi-column list with sortable headers, resizable columns, single or
multi-select, and optional drag-reorder.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtListView(parent)` | Create a list view |
| `setColumns(w, cols, count)` | `wgtListViewSetColumns(w, cols, count)` | Define columns |
| `setData(w, cellData, rowCount)` | `wgtListViewSetData(w, cellData, rowCount)` | Set row data |
| `getSelected(w)` | `wgtListViewGetSelected(w)` | Get selected row |
| `setSelected(w, idx)` | `wgtListViewSetSelected(w, idx)` | Set selected row |
| `setSort(w, col, dir)` | `wgtListViewSetSort(w, col, dir)` | Set sort column/direction |
| `setHeaderClickCallback(w, cb)` | `wgtListViewSetHeaderClickCallback(w, cb)` | Set header click handler |
| `setMultiSelect(w, multi)` | `wgtListViewSetMultiSelect(w, multi)` | Enable multi-select |
| `isItemSelected(w, idx)` | `wgtListViewIsItemSelected(w, idx)` | Check if row is selected |
| `setItemSelected(w, idx, sel)` | `wgtListViewSetItemSelected(w, idx, sel)` | Select/deselect row |
| `selectAll(w)` | `wgtListViewSelectAll(w)` | Select all rows |
| `clearSelection(w)` | `wgtListViewClearSelection(w)` | Deselect all rows |
| `setReorderable(w, r)` | `wgtListViewSetReorderable(w, r)` | Enable drag reorder |

Column definition uses `ListViewColT` with title, tagged width, and alignment
(`ListViewAlignLeftE`, `ListViewAlignCenterE`, `ListViewAlignRightE`).
Sort direction: `ListViewSortNoneE`, `ListViewSortAscE`, `ListViewSortDescE`.

### TreeView (TreeView, TreeItem)

Hierarchical tree with expand/collapse, single or multi-select, and
optional drag-reorder.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtTreeView(parent)` | Create a tree view |
| `getSelected(w)` | `wgtTreeViewGetSelected(w)` | Get selected item widget |
| `setSelected(w, item)` | `wgtTreeViewSetSelected(w, item)` | Set selected item |
| `setMultiSelect(w, multi)` | `wgtTreeViewSetMultiSelect(w, multi)` | Enable multi-select |
| `setReorderable(w, r)` | `wgtTreeViewSetReorderable(w, r)` | Enable drag reorder |
| `item(parent, text)` | `wgtTreeItem(parent, text)` | Create tree item |
| `itemSetExpanded(w, exp)` | `wgtTreeItemSetExpanded(w, exp)` | Expand/collapse item |
| `itemIsExpanded(w)` | `wgtTreeItemIsExpanded(w)` | Check if expanded |
| `itemIsSelected(w)` | `wgtTreeItemIsSelected(w)` | Check if selected |
| `itemSetSelected(w, sel)` | `wgtTreeItemSetSelected(w, sel)` | Select/deselect item |

### Spinner

Numeric input with up/down buttons.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, min, max, step)` | `wgtSpinner(parent, min, max, step)` | Create a spinner |
| `setValue(w, value)` | `wgtSpinnerSetValue(w, value)` | Set current value |
| `getValue(w)` | `wgtSpinnerGetValue(w)` | Get current value |
| `setRange(w, min, max)` | `wgtSpinnerSetRange(w, min, max)` | Set value range |
| `setStep(w, step)` | `wgtSpinnerSetStep(w, step)` | Set increment step |

### Slider

Horizontal track with draggable thumb for value selection.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, min, max)` | `wgtSlider(parent, min, max)` | Create a slider |
| `setValue(w, value)` | `wgtSliderSetValue(w, value)` | Set current value |
| `getValue(w)` | `wgtSliderGetValue(w)` | Get current value |

### ProgressBar

Horizontal or vertical progress indicator (0-100).

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtProgressBar(parent)` | Create horizontal progress bar |
| `createV(parent)` | `wgtProgressBarV(parent)` | Create vertical progress bar |
| `setValue(w, value)` | `wgtProgressBarSetValue(w, value)` | Set value (0-100) |
| `getValue(w)` | `wgtProgressBarGetValue(w)` | Get current value |

### Image

Displays a pixel buffer or image file in native display format.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, data, w, h, pitch)` | `wgtImage(parent, data, w, h, pitch)` | Create from pixel data |
| `fromFile(parent, path)` | `wgtImageFromFile(parent, path)` | Create from image file |
| `setData(w, data, imgW, imgH, pitch)` | `wgtImageSetData(w, data, imgW, imgH, pitch)` | Replace image data |

### ImageButton

Clickable button displaying an image instead of text.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, data, w, h, pitch)` | `wgtImageButton(parent, data, w, h, pitch)` | Create from pixel data |
| `fromFile(parent, path)` | `wgtImageButtonFromFile(parent, path)` | Create from image file |
| `setData(w, data, imgW, imgH, pitch)` | `wgtImageButtonSetData(w, data, imgW, imgH, pitch)` | Replace image data |

### Canvas

Drawable surface with pen tools, shapes, pixel access, and file I/O.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, w, h)` | `wgtCanvas(parent, w, h)` | Create a canvas |
| `clear(w, color)` | `wgtCanvasClear(w, color)` | Fill with solid color |
| `setPenColor(w, color)` | `wgtCanvasSetPenColor(w, color)` | Set drawing color |
| `setPenSize(w, size)` | `wgtCanvasSetPenSize(w, size)` | Set pen width |
| `setMouseCallback(w, cb)` | `wgtCanvasSetMouseCallback(w, cb)` | Set mouse event handler |
| `save(w, path)` | `wgtCanvasSave(w, path)` | Save canvas to file |
| `load(w, path)` | `wgtCanvasLoad(w, path)` | Load image into canvas |
| `drawLine(w, x0, y0, x1, y1)` | `wgtCanvasDrawLine(w, ...)` | Draw line |
| `drawRect(w, x, y, w, h)` | `wgtCanvasDrawRect(w, ...)` | Draw rectangle outline |
| `fillRect(w, x, y, w, h)` | `wgtCanvasFillRect(w, ...)` | Fill rectangle |
| `fillCircle(w, cx, cy, r)` | `wgtCanvasFillCircle(w, ...)` | Fill circle |
| `setPixel(w, x, y, color)` | `wgtCanvasSetPixel(w, x, y, color)` | Set individual pixel |
| `getPixel(w, x, y)` | `wgtCanvasGetPixel(w, x, y)` | Read pixel color |

### Separator (HSeparator, VSeparator)

Thin decorative line (horizontal or vertical).

| API Function | Macro | Description |
|--------------|-------|-------------|
| `hSeparator(parent)` | `wgtHSeparator(parent)` | Create horizontal separator |
| `vSeparator(parent)` | `wgtVSeparator(parent)` | Create vertical separator |

### Spacer

Invisible flexible space for layout padding.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtSpacer(parent)` | Create a spacer |

### TabControl (TabControl, TabPage)

Tabbed container with clickable tab headers.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtTabControl(parent)` | Create tab control |
| `page(parent, title)` | `wgtTabPage(parent, title)` | Add a tab page |
| `setActive(w, idx)` | `wgtTabControlSetActive(w, idx)` | Switch to tab by index |
| `getActive(w)` | `wgtTabControlGetActive(w)` | Get active tab index |

### ScrollPane

Scrollable container with internal scrollbars. Child content can
exceed the visible area; the ScrollPane handles clipping and scroll.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtScrollPane(parent)` | Create a scroll pane |

### Splitter

Resizable split between two child regions with a draggable divider.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, vertical)` | `wgtSplitter(parent, vertical)` | Create splitter |
| `setPos(w, pos)` | `wgtSplitterSetPos(w, pos)` | Set divider position (pixels) |
| `getPos(w)` | `wgtSplitterGetPos(w)` | Get divider position |

### Toolbar

Horizontal container for toolbar buttons (typically ImageButtons).

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtToolbar(parent)` | Create a toolbar |

### StatusBar

Single-line text display at the bottom of a window.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent)` | `wgtStatusBar(parent)` | Create a status bar |

Set text via `wgtSetText(statusBar, "text")`.

### Timer

Non-visual widget that fires callbacks at a specified interval.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, intervalMs, repeat)` | `wgtTimer(parent, intervalMs, repeat)` | Create a timer |
| `start(w)` | `wgtTimerStart(w)` | Start the timer |
| `stop(w)` | `wgtTimerStop(w)` | Stop the timer |
| `setInterval(w, intervalMs)` | `wgtTimerSetInterval(w, intervalMs)` | Change interval |
| `isRunning(w)` | `wgtTimerIsRunning(w)` | Check if running |
| `updateTimers()` | `wgtUpdateTimers()` | Process all pending timers |

### AnsiTerm

ANSI terminal emulator widget with scrollback buffer. Supports standard
escape sequences (cursor control, SGR colors, erase, scroll, DEC
private modes). Optionally connects to a comm channel for serial I/O.

| API Function | Macro | Description |
|--------------|-------|-------------|
| `create(parent, cols, rows)` | `wgtAnsiTerm(parent, cols, rows)` | Create terminal |
| `write(w, data, len)` | `wgtAnsiTermWrite(w, data, len)` | Write data to terminal |
| `clear(w)` | `wgtAnsiTermClear(w)` | Clear terminal screen |
| `setComm(w, ctx, readFn, writeFn)` | `wgtAnsiTermSetComm(w, ctx, readFn, writeFn)` | Set comm channel |
| `setScrollback(w, maxLines)` | `wgtAnsiTermSetScrollback(w, maxLines)` | Set scrollback depth |
| `poll(w)` | `wgtAnsiTermPoll(w)` | Poll comm channel |
| `repaint(w, outY, outH)` | `wgtAnsiTermRepaint(w, outY, outH)` | Fast incremental repaint |


## Build

```
make            # builds all 26 .wgt modules + dep files
make clean      # removes objects, .wgt files, and dep files
```

Each widget is compiled to a single `.o` file, then packaged via
`dxe3gen` into a `.wgt` DXE module exporting only `wgtRegister`.
