DVX_GUI/dvx/dvxWidget.h

796 lines
29 KiB
C

// dvxWidget.h — Widget system for DVX GUI
#ifndef DVX_WIDGET_H
#define DVX_WIDGET_H
#include "dvxTypes.h"
#include <time.h>
// Forward declarations
struct AppContextT;
struct WidgetClassT;
// ============================================================
// Size specifications
// ============================================================
//
// Tagged size values encode both a unit type and a numeric value.
// Use wgtPixels(), wgtChars(), or wgtPercent() to create them.
// A raw 0 means "auto" (use the widget's natural size).
#define WGT_SIZE_TYPE_MASK 0xC0000000
#define WGT_SIZE_VAL_MASK 0x3FFFFFFF
#define WGT_SIZE_PIXELS 0x00000000
#define WGT_SIZE_CHARS 0x40000000
#define WGT_SIZE_PERCENT 0x80000000
static inline int32_t wgtPixels(int32_t v) {
return (int32_t)(WGT_SIZE_PIXELS | ((uint32_t)v & WGT_SIZE_VAL_MASK));
}
static inline int32_t wgtChars(int32_t v) {
return (int32_t)(WGT_SIZE_CHARS | ((uint32_t)v & WGT_SIZE_VAL_MASK));
}
static inline int32_t wgtPercent(int32_t v) {
return (int32_t)(WGT_SIZE_PERCENT | ((uint32_t)v & WGT_SIZE_VAL_MASK));
}
// ============================================================
// Widget type enum
// ============================================================
typedef enum {
WidgetVBoxE,
WidgetHBoxE,
WidgetLabelE,
WidgetButtonE,
WidgetCheckboxE,
WidgetRadioGroupE,
WidgetRadioE,
WidgetTextInputE,
WidgetTextAreaE,
WidgetListBoxE,
WidgetSpacerE,
WidgetSeparatorE,
WidgetFrameE,
WidgetDropdownE,
WidgetComboBoxE,
WidgetProgressBarE,
WidgetSliderE,
WidgetTabControlE,
WidgetTabPageE,
WidgetStatusBarE,
WidgetToolbarE,
WidgetTreeViewE,
WidgetTreeItemE,
WidgetImageE,
WidgetImageButtonE,
WidgetCanvasE,
WidgetAnsiTermE,
WidgetListViewE,
WidgetSpinnerE,
WidgetScrollPaneE,
WidgetSplitterE
} WidgetTypeE;
// ============================================================
// ListView types
// ============================================================
#define LISTVIEW_MAX_COLS 16
typedef enum {
ListViewAlignLeftE,
ListViewAlignCenterE,
ListViewAlignRightE
} ListViewAlignE;
typedef enum {
ListViewSortNoneE,
ListViewSortAscE,
ListViewSortDescE
} ListViewSortE;
typedef struct {
const char *title;
int32_t width; // tagged size (wgtPixels/wgtChars/wgtPercent, 0 = auto)
ListViewAlignE align;
} ListViewColT;
// ============================================================
// Alignment enum
// ============================================================
//
// Controls main-axis alignment of children within a container.
// HBox: AlignStartE=left, AlignCenterE=center, AlignEndE=right
// VBox: AlignStartE=top, AlignCenterE=center, AlignEndE=bottom
typedef enum {
AlignStartE,
AlignCenterE,
AlignEndE
} WidgetAlignE;
// ============================================================
// Frame style enum
// ============================================================
typedef enum {
FrameInE, // beveled inward (sunken) — default
FrameOutE, // beveled outward (raised)
FrameFlatE // solid color line
} FrameStyleE;
// ============================================================
// Text input mode enum
// ============================================================
typedef enum {
InputNormalE, // default free-form text
InputPasswordE, // displays bullets, no copy
InputMaskedE // format mask (e.g. "(###) ###-####")
} InputModeE;
// ============================================================
// Large widget data (separately allocated to reduce WidgetT size)
// ============================================================
typedef struct {
uint8_t *cells; // character cells: (ch, attr) pairs, cols*rows*2 bytes
int32_t cols; // columns (default 80)
int32_t rows; // rows (default 25)
int32_t cursorRow; // 0-based cursor row
int32_t cursorCol; // 0-based cursor column
bool cursorVisible;
bool wrapMode; // auto-wrap at right margin
bool bold; // SGR bold flag (brightens foreground)
bool originMode; // cursor positioning relative to scroll region
bool csiPrivate; // '?' prefix in CSI sequence
uint8_t curAttr; // current text attribute (fg | bg<<4)
uint8_t parseState; // 0=normal, 1=ESC, 2=CSI
int32_t params[8]; // CSI parameter accumulator
int32_t paramCount; // number of CSI params collected
int32_t savedRow; // saved cursor position (SCP)
int32_t savedCol;
// Scrolling region (0-based, inclusive)
int32_t scrollTop; // top row of scroll region
int32_t scrollBot; // bottom row of scroll region
// Scrollback
uint8_t *scrollback; // circular buffer of scrollback lines
int32_t scrollbackMax; // max lines in scrollback buffer
int32_t scrollbackCount; // current number of lines stored
int32_t scrollbackHead; // write position (circular index)
int32_t scrollPos; // view position (scrollbackCount = live)
// Blink support
bool blinkVisible; // current blink phase (true = text visible)
clock_t blinkTime; // timestamp of last blink toggle
// Cursor blink
bool cursorOn; // current cursor blink phase
clock_t cursorTime; // timestamp of last cursor toggle
// Dirty tracking for fast repaint
uint32_t dirtyRows; // bitmask of rows needing repaint
int32_t lastCursorRow; // cursor row at last repaint
int32_t lastCursorCol; // cursor col at last repaint
// Cached packed palette (avoids packColor per repaint)
uint32_t packedPalette[16];
bool paletteValid;
// Selection (line indices in scrollback+screen space)
int32_t selStartLine;
int32_t selStartCol;
int32_t selEndLine;
int32_t selEndCol;
bool selecting;
// Communications interface (all NULL = disconnected)
void *commCtx;
int32_t (*commRead)(void *ctx, uint8_t *buf, int32_t maxLen);
int32_t (*commWrite)(void *ctx, const uint8_t *buf, int32_t len);
} AnsiTermDataT;
typedef struct {
const ListViewColT *cols;
int32_t colCount;
const char **cellData;
int32_t rowCount;
int32_t selectedIdx;
int32_t scrollPos;
int32_t scrollPosH;
int32_t sortCol;
ListViewSortE sortDir;
int32_t resolvedColW[LISTVIEW_MAX_COLS];
int32_t totalColW;
int32_t *sortIndex;
bool multiSelect;
int32_t anchorIdx;
uint8_t *selBits;
bool reorderable;
int32_t dragIdx;
int32_t dropIdx;
void (*onHeaderClick)(struct WidgetT *w, int32_t col, ListViewSortE dir);
} ListViewDataT;
// ============================================================
// Widget structure
// ============================================================
#define MAX_WIDGET_NAME 32
typedef struct WidgetT {
WidgetTypeE type;
const struct WidgetClassT *wclass;
char name[MAX_WIDGET_NAME];
uint32_t nameHash; // djb2 hash of name, 0 if unnamed
// Tree linkage
struct WidgetT *parent;
struct WidgetT *firstChild;
struct WidgetT *lastChild;
struct WidgetT *nextSibling;
WindowT *window;
// Computed geometry (relative to window content area)
int32_t x;
int32_t y;
int32_t w;
int32_t h;
// Computed minimum size (set by layout engine)
int32_t calcMinW;
int32_t calcMinH;
// Size hints (tagged: wgtPixels/wgtChars/wgtPercent, 0 = auto)
int32_t minW;
int32_t minH;
int32_t maxW; // 0 = no limit
int32_t maxH;
int32_t prefW; // preferred size, 0 = auto
int32_t prefH;
int32_t weight; // extra-space distribution (0 = fixed, 100 = normal)
// Container properties
WidgetAlignE align; // main-axis alignment for children
int32_t spacing; // tagged size for spacing between children (0 = default)
int32_t padding; // tagged size for internal padding (0 = default)
// Colors (0 = use color scheme defaults)
uint32_t fgColor;
uint32_t bgColor;
// State
bool visible;
bool enabled;
bool focused;
char accelKey; // lowercase accelerator character, 0 if none
// User data and callbacks
void *userData;
const char *tooltip; // tooltip text (NULL = none, caller owns string)
MenuT *contextMenu; // right-click context menu (NULL = none, caller owns)
void (*onClick)(struct WidgetT *w);
void (*onChange)(struct WidgetT *w);
void (*onDblClick)(struct WidgetT *w);
// Type-specific data
union {
struct {
const char *text;
} label;
struct {
const char *text;
bool pressed;
} button;
struct {
const char *text;
bool checked;
} checkbox;
struct {
int32_t selectedIdx;
} radioGroup;
struct {
const char *text;
int32_t index;
} radio;
struct {
char *buf;
int32_t bufSize;
int32_t len;
int32_t cursorPos;
int32_t scrollOff;
int32_t selStart; // selection anchor (-1 = none)
int32_t selEnd; // selection end (-1 = none)
char *undoBuf;
int32_t undoLen;
int32_t undoCursor;
InputModeE inputMode;
const char *mask; // format mask for InputMaskedE
} textInput;
struct {
char *buf;
int32_t bufSize;
int32_t len;
int32_t cursorRow;
int32_t cursorCol;
int32_t scrollRow;
int32_t scrollCol;
int32_t desiredCol; // sticky column for up/down movement
int32_t selAnchor; // selection anchor byte offset (-1 = none)
int32_t selCursor; // selection cursor byte offset (-1 = none)
char *undoBuf;
int32_t undoLen;
int32_t undoCursor; // byte offset at time of snapshot
int32_t cachedLines; // cached line count (-1 = dirty)
int32_t cachedMaxLL; // cached max line length (-1 = dirty)
} textArea;
struct {
const char **items;
int32_t itemCount;
int32_t selectedIdx; // cursor position (always valid); also sole selection in single-select
int32_t scrollPos;
int32_t maxItemLen; // cached max strlen of items
bool multiSelect;
int32_t anchorIdx; // anchor for shift+click range selection
uint8_t *selBits; // per-item selection flags (multi-select only)
bool reorderable; // allow drag-reorder of items
int32_t dragIdx; // item being dragged (-1 = none)
int32_t dropIdx; // insertion point (-1 = none)
} listBox;
struct {
bool vertical;
} separator;
struct {
const char *title;
FrameStyleE style; // FrameInE (default), FrameOutE, FrameFlatE
uint32_t color; // border color for FrameFlatE (0 = use windowShadow)
} frame;
struct {
const char **items;
int32_t itemCount;
int32_t selectedIdx;
bool open;
int32_t hoverIdx;
int32_t scrollPos;
int32_t maxItemLen; // cached max strlen of items
} dropdown;
struct {
char *buf;
int32_t bufSize;
int32_t len;
int32_t cursorPos;
int32_t scrollOff;
int32_t selStart; // selection anchor (-1 = none)
int32_t selEnd; // selection end (-1 = none)
char *undoBuf;
int32_t undoLen;
int32_t undoCursor;
const char **items;
int32_t itemCount;
int32_t selectedIdx;
bool open;
int32_t hoverIdx;
int32_t listScrollPos;
int32_t maxItemLen; // cached max strlen of items
} comboBox;
struct {
int32_t value;
int32_t maxValue;
bool vertical;
} progressBar;
struct {
int32_t value;
int32_t minValue;
int32_t maxValue;
bool vertical;
} slider;
struct {
int32_t activeTab;
int32_t scrollOffset; // horizontal scroll of tab headers
} tabControl;
struct {
const char *title;
} tabPage;
struct {
int32_t scrollPos;
int32_t scrollPosH;
struct WidgetT *selectedItem;
struct WidgetT *anchorItem; // anchor for shift+click range selection
bool multiSelect;
bool reorderable; // allow drag-reorder of items
struct WidgetT *dragItem; // item being dragged (NULL = none)
struct WidgetT *dropTarget; // insertion target (NULL = none)
bool dropAfter; // true = insert after target, false = before
} treeView;
struct {
const char *text;
bool expanded;
bool selected; // per-item flag for multi-select
} treeItem;
struct {
uint8_t *data; // pixel buffer in display format
int32_t imgW;
int32_t imgH;
int32_t imgPitch;
bool pressed;
} image;
struct {
uint8_t *data; // pixel buffer in display format
int32_t imgW;
int32_t imgH;
int32_t imgPitch;
bool pressed;
} imageButton;
struct {
uint8_t *data; // pixel buffer in display format
int32_t canvasW;
int32_t canvasH;
int32_t canvasPitch;
int32_t canvasBpp; // cached bytes per pixel (avoids pitch/w division)
uint32_t penColor;
int32_t penSize;
int32_t lastX;
int32_t lastY;
} canvas;
AnsiTermDataT *ansiTerm;
ListViewDataT *listView;
struct {
int32_t value;
int32_t minValue;
int32_t maxValue;
int32_t step;
char buf[16]; // formatted value text
int32_t len;
int32_t cursorPos;
int32_t scrollOff;
int32_t selStart; // selection anchor (-1 = none)
int32_t selEnd; // selection end (-1 = none)
char undoBuf[16]; // undo snapshot
int32_t undoLen;
int32_t undoCursor;
bool editing; // true when user is typing
} spinner;
struct {
int32_t scrollPosV;
int32_t scrollPosH;
} scrollPane;
struct {
int32_t dividerPos; // pixels from left/top edge
bool vertical; // true = vertical divider (left|right panes)
} splitter;
} as;
} WidgetT;
// ============================================================
// Window integration
// ============================================================
// Set up a window for widgets. Returns the root container (VBox).
// Automatically installs onPaint, onMouse, onKey, and onResize handlers.
WidgetT *wgtInitWindow(struct AppContextT *ctx, WindowT *win);
// ============================================================
// Container creation
// ============================================================
WidgetT *wgtVBox(WidgetT *parent);
WidgetT *wgtHBox(WidgetT *parent);
WidgetT *wgtFrame(WidgetT *parent, const char *title);
// ============================================================
// Basic widgets
// ============================================================
WidgetT *wgtLabel(WidgetT *parent, const char *text);
WidgetT *wgtButton(WidgetT *parent, const char *text);
WidgetT *wgtCheckbox(WidgetT *parent, const char *text);
WidgetT *wgtTextInput(WidgetT *parent, int32_t maxLen);
WidgetT *wgtPasswordInput(WidgetT *parent, int32_t maxLen);
WidgetT *wgtMaskedInput(WidgetT *parent, const char *mask);
// ============================================================
// Radio buttons
// ============================================================
WidgetT *wgtRadioGroup(WidgetT *parent);
WidgetT *wgtRadio(WidgetT *parent, const char *text);
// ============================================================
// Spacing and visual dividers
// ============================================================
WidgetT *wgtSpacer(WidgetT *parent);
WidgetT *wgtHSeparator(WidgetT *parent);
WidgetT *wgtVSeparator(WidgetT *parent);
// ============================================================
// Complex widgets
// ============================================================
WidgetT *wgtListBox(WidgetT *parent);
WidgetT *wgtTextArea(WidgetT *parent, int32_t maxLen);
// ============================================================
// Dropdown and ComboBox
// ============================================================
WidgetT *wgtDropdown(WidgetT *parent);
void wgtDropdownSetItems(WidgetT *w, const char **items, int32_t count);
int32_t wgtDropdownGetSelected(const WidgetT *w);
void wgtDropdownSetSelected(WidgetT *w, int32_t idx);
WidgetT *wgtComboBox(WidgetT *parent, int32_t maxLen);
void wgtComboBoxSetItems(WidgetT *w, const char **items, int32_t count);
int32_t wgtComboBoxGetSelected(const WidgetT *w);
void wgtComboBoxSetSelected(WidgetT *w, int32_t idx);
// ============================================================
// ProgressBar
// ============================================================
WidgetT *wgtProgressBar(WidgetT *parent);
WidgetT *wgtProgressBarV(WidgetT *parent);
void wgtProgressBarSetValue(WidgetT *w, int32_t value);
int32_t wgtProgressBarGetValue(const WidgetT *w);
// ============================================================
// Slider (TrackBar)
// ============================================================
WidgetT *wgtSlider(WidgetT *parent, int32_t minVal, int32_t maxVal);
void wgtSliderSetValue(WidgetT *w, int32_t value);
int32_t wgtSliderGetValue(const WidgetT *w);
// ============================================================
// Spinner (numeric input)
// ============================================================
WidgetT *wgtSpinner(WidgetT *parent, int32_t minVal, int32_t maxVal, int32_t step);
void wgtSpinnerSetValue(WidgetT *w, int32_t value);
int32_t wgtSpinnerGetValue(const WidgetT *w);
void wgtSpinnerSetRange(WidgetT *w, int32_t minVal, int32_t maxVal);
void wgtSpinnerSetStep(WidgetT *w, int32_t step);
// ============================================================
// TabControl
// ============================================================
WidgetT *wgtTabControl(WidgetT *parent);
WidgetT *wgtTabPage(WidgetT *parent, const char *title);
void wgtTabControlSetActive(WidgetT *w, int32_t idx);
int32_t wgtTabControlGetActive(const WidgetT *w);
// ============================================================
// StatusBar and Toolbar
// ============================================================
WidgetT *wgtStatusBar(WidgetT *parent);
WidgetT *wgtToolbar(WidgetT *parent);
// ============================================================
// TreeView
// ============================================================
WidgetT *wgtTreeView(WidgetT *parent);
WidgetT *wgtTreeViewGetSelected(const WidgetT *w);
void wgtTreeViewSetSelected(WidgetT *w, WidgetT *item);
void wgtTreeViewSetMultiSelect(WidgetT *w, bool multi);
void wgtTreeViewSetReorderable(WidgetT *w, bool reorderable);
WidgetT *wgtTreeItem(WidgetT *parent, const char *text);
void wgtTreeItemSetExpanded(WidgetT *w, bool expanded);
bool wgtTreeItemIsExpanded(const WidgetT *w);
bool wgtTreeItemIsSelected(const WidgetT *w);
void wgtTreeItemSetSelected(WidgetT *w, bool selected);
// ============================================================
// ListView (multi-column list)
// ============================================================
WidgetT *wgtListView(WidgetT *parent);
void wgtListViewSetColumns(WidgetT *w, const ListViewColT *cols, int32_t count);
void wgtListViewSetData(WidgetT *w, const char **cellData, int32_t rowCount);
int32_t wgtListViewGetSelected(const WidgetT *w);
void wgtListViewSetSelected(WidgetT *w, int32_t idx);
void wgtListViewSetSort(WidgetT *w, int32_t col, ListViewSortE dir);
void wgtListViewSetHeaderClickCallback(WidgetT *w, void (*cb)(WidgetT *w, int32_t col, ListViewSortE dir));
void wgtListViewSetMultiSelect(WidgetT *w, bool multi);
bool wgtListViewIsItemSelected(const WidgetT *w, int32_t idx);
void wgtListViewSetItemSelected(WidgetT *w, int32_t idx, bool selected);
void wgtListViewSelectAll(WidgetT *w);
void wgtListViewClearSelection(WidgetT *w);
void wgtListViewSetReorderable(WidgetT *w, bool reorderable);
// ============================================================
// ScrollPane
// ============================================================
WidgetT *wgtScrollPane(WidgetT *parent);
// ============================================================
// Splitter (draggable divider between two child regions)
// ============================================================
// Create a splitter. If vertical is true, children are arranged left|right;
// if false, top|bottom. Add exactly two children.
WidgetT *wgtSplitter(WidgetT *parent, bool vertical);
void wgtSplitterSetPos(WidgetT *w, int32_t pos);
int32_t wgtSplitterGetPos(const WidgetT *w);
// ============================================================
// ImageButton
// ============================================================
// Create an image button from raw pixel data (display format).
// Takes ownership of the data buffer (freed on destroy).
WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, int32_t pitch);
// Replace the image data. Takes ownership of the new buffer.
void wgtImageButtonSetData(WidgetT *w, uint8_t *data, int32_t imgW, int32_t imgH, int32_t pitch);
// ============================================================
// Image
// ============================================================
// Create an image widget from raw pixel data (display format).
// Takes ownership of the data buffer (freed on destroy).
WidgetT *wgtImage(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, int32_t pitch);
// Load an image widget from a file (BMP, PNG, JPEG, GIF).
// Returns NULL on load failure.
WidgetT *wgtImageFromFile(WidgetT *parent, const char *path);
// Replace the image data. Takes ownership of the new buffer.
void wgtImageSetData(WidgetT *w, uint8_t *data, int32_t imgW, int32_t imgH, int32_t pitch);
// ============================================================
// Canvas
// ============================================================
// Create a drawable canvas widget with the given dimensions.
WidgetT *wgtCanvas(WidgetT *parent, int32_t w, int32_t h);
// Clear the canvas to the specified color.
void wgtCanvasClear(WidgetT *w, uint32_t color);
// Set the pen color (in display pixel format).
void wgtCanvasSetPenColor(WidgetT *w, uint32_t color);
// Set the pen size in pixels (diameter).
void wgtCanvasSetPenSize(WidgetT *w, int32_t size);
// Save the canvas to a PNG file. Returns 0 on success, -1 on failure.
int32_t wgtCanvasSave(WidgetT *w, const char *path);
// Load a PNG file onto the canvas. Returns 0 on success, -1 on failure.
int32_t wgtCanvasLoad(WidgetT *w, const char *path);
// Programmatic drawing (coordinates are in canvas space)
void wgtCanvasDrawLine(WidgetT *w, int32_t x0, int32_t y0, int32_t x1, int32_t y1);
void wgtCanvasDrawRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t height);
void wgtCanvasFillRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t height);
void wgtCanvasFillCircle(WidgetT *w, int32_t cx, int32_t cy, int32_t radius);
void wgtCanvasSetPixel(WidgetT *w, int32_t x, int32_t y, uint32_t color);
uint32_t wgtCanvasGetPixel(const WidgetT *w, int32_t x, int32_t y);
// ============================================================
// ANSI Terminal
// ============================================================
// Create an ANSI terminal widget (0 for cols/rows = 80x25 default)
WidgetT *wgtAnsiTerm(WidgetT *parent, int32_t cols, int32_t rows);
// Write data through the ANSI parser (for loading .ANS files or feeding data without a connection)
void wgtAnsiTermWrite(WidgetT *w, const uint8_t *data, int32_t len);
// Clear the terminal screen and reset cursor to home
void wgtAnsiTermClear(WidgetT *w);
// Set the communications interface (NULL function pointers = disconnected)
void wgtAnsiTermSetComm(WidgetT *w, void *ctx, int32_t (*readFn)(void *, uint8_t *, int32_t), int32_t (*writeFn)(void *, const uint8_t *, int32_t));
// Set the scrollback buffer size in lines (default 500). Clears existing scrollback.
void wgtAnsiTermSetScrollback(WidgetT *w, int32_t maxLines);
// Poll the comm interface for incoming data and process it. Returns bytes processed.
int32_t wgtAnsiTermPoll(WidgetT *w);
// Fast repaint: renders only dirty rows directly into the window's content
// buffer, bypassing the full widget paint pipeline. Returns number of rows
// repainted (0 if nothing was dirty). If outY/outH are non-NULL, they receive
// the content-buffer-relative Y and height of the repainted region.
int32_t wgtAnsiTermRepaint(WidgetT *w, int32_t *outY, int32_t *outH);
// ============================================================
// Operations
// ============================================================
// Mark a widget (and ancestors) for relayout and repaint
void wgtInvalidate(WidgetT *w);
// Repaint only — skip measure/layout (use for visual-only changes)
void wgtInvalidatePaint(WidgetT *w);
// Set/get widget text (label, button, textInput, etc.)
void wgtSetText(WidgetT *w, const char *text);
const char *wgtGetText(const WidgetT *w);
// Enable/disable a widget
void wgtSetEnabled(WidgetT *w, bool enabled);
// Show/hide a widget
void wgtSetVisible(WidgetT *w, bool visible);
// Set a widget's name (for lookup via wgtFind)
void wgtSetName(WidgetT *w, const char *name);
// Find a widget by name (searches the subtree rooted at root)
WidgetT *wgtFind(WidgetT *root, const char *name);
// Destroy a widget and all its children (removes from parent)
void wgtDestroy(WidgetT *w);
// ============================================================
// List box operations
// ============================================================
void wgtListBoxSetItems(WidgetT *w, const char **items, int32_t count);
int32_t wgtListBoxGetSelected(const WidgetT *w);
void wgtListBoxSetSelected(WidgetT *w, int32_t idx);
void wgtListBoxSetMultiSelect(WidgetT *w, bool multi);
bool wgtListBoxIsItemSelected(const WidgetT *w, int32_t idx);
void wgtListBoxSetItemSelected(WidgetT *w, int32_t idx, bool selected);
void wgtListBoxSelectAll(WidgetT *w);
void wgtListBoxClearSelection(WidgetT *w);
void wgtListBoxSetReorderable(WidgetT *w, bool reorderable);
// ============================================================
// Tooltip
// ============================================================
// Set tooltip text for a widget (NULL to remove).
// Caller owns the string — it must outlive the widget.
static inline void wgtSetTooltip(WidgetT *w, const char *text) { w->tooltip = text; }
// ============================================================
// Debug
// ============================================================
// Draw borders around layout containers in ugly colors
void wgtSetDebugLayout(struct AppContextT *ctx, bool enabled);
// ============================================================
// Layout (called internally; available for manual trigger)
// ============================================================
// Resolve a tagged size to pixels
int32_t wgtResolveSize(int32_t taggedSize, int32_t parentSize, int32_t charWidth);
// Run layout on the entire widget tree
void wgtLayout(WidgetT *root, int32_t availW, int32_t availH, const BitmapFontT *font);
// Paint the entire widget tree
void wgtPaint(WidgetT *root, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
#endif // DVX_WIDGET_H