// dvxWidget.h -- Widget system for DVX GUI // // A retained-mode widget toolkit layered on top of the DVX window manager. // Widgets form a tree (parent-child via firstChild/lastChild/nextSibling // pointers) rooted at a per-window VBox container. Layout is automatic: // the engine measures minimum sizes bottom-up, then allocates space top-down // using a flexbox-like algorithm with weights for extra-space distribution. // // Design decisions and rationale: // // - Generic WidgetT with void *data: core knows nothing about individual // widget types. Each widget DXE allocates and manages its own private // data struct via w->data. The wclass vtable provides polymorphic // dispatch for paint, layout, events, and all type-specific operations. // No widget-specific enums, structs, or union members in this header. // // - Dynamic type IDs: wgtRegisterClass() returns a runtime ID at load // time. No compile-time enum. Adding a new widget requires zero core // changes -- just drop a .wgt DXE in the widgets directory. // // - Tagged size values (wgtPixels/wgtChars/wgtPercent): encoding the unit // in the high bits of a single int32_t avoids extra struct fields for // unit type and lets size hints be passed as plain integers. The 30-bit // value range (up to ~1 billion) is more than sufficient for pixel counts. // // - Tree linkage uses firstChild/lastChild/nextSibling (no prevSibling): // this halves the pointer overhead per widget and insertion/removal is // still O(n) in the worst case, which is acceptable given typical tree // depths of 5-10 nodes. #ifndef DVX_WIDGET_H #define DVX_WIDGET_H #include "dvxTypes.h" #include // Forward declarations struct AppContextT; struct WidgetClassT; // ============================================================ // Size specifications // ============================================================ // // Tagged size values encode both a unit type and a numeric value in a // single int32_t. The top 2 bits select the unit (pixels, character widths, // or percentage of parent), and the low 30 bits hold the numeric value. // A raw 0 means "auto" (use the widget's natural/minimum size). // // This encoding avoids a separate enum field for the unit type, keeping // size hints as simple scalar assignments: w->minW = wgtChars(40); // The wgtResolveSize() function in the layout engine decodes these tagged // values back into pixel counts using the font metrics and parent dimensions. #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 #define wgtPixels(v) ((int32_t)(WGT_SIZE_PIXELS | ((uint32_t)(v) & WGT_SIZE_VAL_MASK))) #define wgtChars(v) ((int32_t)(WGT_SIZE_CHARS | ((uint32_t)(v) & WGT_SIZE_VAL_MASK))) #define wgtPercent(v) ((int32_t)(WGT_SIZE_PERCENT | ((uint32_t)(v) & WGT_SIZE_VAL_MASK))) // Widget type IDs are assigned dynamically by wgtRegisterClass() at // runtime. There is no compile-time enum. Each widget DXE stores // its assigned ID(s) in file-scope globals. // ============================================================ // ListView column types (used by ListView API in widgetListView.h) // ============================================================ 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; // ============================================================ // Widget-specific enums and types used by the public API // ============================================================ // // These types are referenced by application code through the wgtApi // function table. Widget-private types (data structs) are defined // in their respective widget .c files. // ============================================================ // Widget class dispatch table // ============================================================ // // Each widget type has a WidgetClassT that defines its behavior. // Built-in classes are static const; dynamically registered classes // (from DXE plugins) are stored in the mutable region of // widgetClassTable[]. // // The handlers[] array provides ABI-stable dispatch: method IDs are // fixed constants that never change. Adding new methods appends new // IDs without shifting existing ones, so widget DXEs compiled against // an older DVX version continue to work unmodified. The version field // is checked at wgtRegisterClass() time to catch DXEs compiled against // an incompatible layout. // // Flags encode static properties checked by the framework: // FOCUSABLE -- can receive keyboard focus (Tab navigation) // BOX_CONTAINER -- uses the generic VBox/HBox layout algorithm // HORIZ_CONTAINER -- lays out children horizontally (vs. vertical) // PAINTS_CHILDREN -- widget handles child rendering itself // NO_HIT_RECURSE -- hit testing stops here, no child recursion // Flags encode static properties checked by the framework. // Widgets set these in their WidgetClassT definition. #define WCLASS_FOCUSABLE 0x00000001 #define WCLASS_BOX_CONTAINER 0x00000002 #define WCLASS_HORIZ_CONTAINER 0x00000004 #define WCLASS_PAINTS_CHILDREN 0x00000008 #define WCLASS_NO_HIT_RECURSE 0x00000010 #define WCLASS_FOCUS_FORWARD 0x00000020 // accel hit forwards focus to next focusable #define WCLASS_HAS_POPUP 0x00000040 // has dropdown popup overlay #define WCLASS_SCROLLABLE 0x00000080 // accepts mouse wheel events #define WCLASS_SCROLL_CONTAINER 0x00000100 // scroll container (ScrollPane) #define WCLASS_NEEDS_POLL 0x00000200 // needs periodic polling (AnsiTerm comms) #define WCLASS_SWALLOWS_TAB 0x00000400 // Tab key goes to widget, not focus nav #define WCLASS_RELAYOUT_ON_SCROLL 0x00000800 // full relayout on scrollbar drag #define WCLASS_PRESS_RELEASE 0x00001000 // click = press+release (Button, ImageButton) #define WCLASS_ACCEL_WHEN_HIDDEN 0x00002000 // accel matching works even when invisible // Method IDs -- stable ABI, never reorder, never reuse. // New methods are appended at the end with the next sequential ID. #define WGT_METHOD_PAINT 0 // void (w, d, ops, font, colors) #define WGT_METHOD_PAINT_OVERLAY 1 // void (w, d, ops, font, colors) #define WGT_METHOD_CALC_MIN_SIZE 2 // void (w, font) #define WGT_METHOD_LAYOUT 3 // void (w, font) #define WGT_METHOD_GET_LAYOUT_METRICS 4 // void (w, font, pad, gap, extraTop, borderW) #define WGT_METHOD_ON_MOUSE 5 // void (w, root, vx, vy) #define WGT_METHOD_ON_KEY 6 // void (w, key, mod) #define WGT_METHOD_ON_ACCEL_ACTIVATE 7 // void (w, root) #define WGT_METHOD_DESTROY 8 // void (w) #define WGT_METHOD_ON_CHILD_CHANGED 9 // void (parent, child) #define WGT_METHOD_GET_TEXT 10 // const char *(w) #define WGT_METHOD_SET_TEXT 11 // void (w, text) #define WGT_METHOD_CLEAR_SELECTION 12 // bool (w) #define WGT_METHOD_CLOSE_POPUP 13 // void (w) #define WGT_METHOD_GET_POPUP_RECT 14 // void (w, font, contentH, popX, popY, popW, popH) #define WGT_METHOD_ON_DRAG_UPDATE 15 // void (w, root, x, y) #define WGT_METHOD_ON_DRAG_END 16 // void (w, root, x, y) #define WGT_METHOD_GET_CURSOR_SHAPE 17 // int32_t (w, vx, vy) #define WGT_METHOD_POLL 18 // void (w, win) #define WGT_METHOD_QUICK_REPAINT 19 // int32_t (w, outY, outH) #define WGT_METHOD_SCROLL_CHILD_INTO_VIEW 20 // void (parent, child) #define WGT_METHOD_COUNT 21 #define WGT_METHOD_MAX 32 // room for future methods #define WGT_CLASS_VERSION 1 // bump on breaking ABI change typedef struct WidgetClassT { uint32_t version; uint32_t flags; void *handlers[WGT_METHOD_MAX]; } WidgetClassT; // ============================================================ // Widget structure // ============================================================ #define MAX_WIDGET_NAME 32 typedef struct WidgetT { int32_t type; // assigned by wgtRegisterClass() // wclass points to the vtable for this widget type. Looked up once at // creation from widgetClassTable[type]. This avoids a switch on type // in every paint/layout/event dispatch -- the cost is one pointer per // widget, which is negligible. const struct WidgetClassT *wclass; char name[MAX_WIDGET_NAME]; // 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 bottom-up by calcMinSize during layout. // These represent the smallest possible size for this widget (including // its children if it's a container). The layout engine uses these as // the starting point for space allocation. int32_t calcMinW; int32_t calcMinH; // Size hints (tagged: wgtPixels/wgtChars/wgtPercent, 0 = auto). // These are set by the application and influence the layout engine: // minW/minH override calcMinW/H if larger, maxW/maxH clamp the final // size, and prefW/prefH request a specific size (layout may override). 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; // weight controls how extra space beyond minimum is distributed among // siblings in a VBox/HBox. weight=0 means fixed size (no stretching), // weight=100 is the default for flexible widgets. A widget with // weight=200 gets twice as much extra space as one with weight=100. 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 readOnly; bool swallowTab; // Tab key goes to widget, not focus nav char accelKey; // lowercase accelerator character, 0 if none // User data and callbacks. These fire for ALL widget types from the // central event dispatcher, not from individual widget handlers. // Type-specific handlers (e.g. button press animation, listbox // selection) run first, then these universal callbacks fire. void *userData; void *data; // widget-private data (allocated by widget DXE) 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 (*onDblClick)(struct WidgetT *w); void (*onChange)(struct WidgetT *w); void (*onFocus)(struct WidgetT *w); void (*onBlur)(struct WidgetT *w); void (*onKeyPress)(struct WidgetT *w, int32_t keyAscii); void (*onKeyDown)(struct WidgetT *w, int32_t keyCode, int32_t shift); void (*onKeyUp)(struct WidgetT *w, int32_t keyCode, int32_t shift); void (*onMouseDown)(struct WidgetT *w, int32_t button, int32_t x, int32_t y); void (*onMouseUp)(struct WidgetT *w, int32_t button, int32_t x, int32_t y); void (*onMouseMove)(struct WidgetT *w, int32_t button, int32_t x, int32_t y); void (*onScroll)(struct WidgetT *w, int32_t delta); } WidgetT; // ============================================================ // Typed dispatch helpers // ============================================================ // // Each wclsFoo() inline function extracts a handler by stable method ID, // casts it to the correct function pointer type, and calls it with a // NULL check. This gives callers type-safe dispatch with the same // codegen as a direct struct field call. static inline bool wclsHas(const WidgetT *w, int32_t methodId) { return w->wclass && w->wclass->handlers[methodId] != NULL; } static inline void wclsPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) { typedef void (*FnT)(WidgetT *, DisplayT *, const BlitOpsT *, const BitmapFontT *, const ColorSchemeT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_PAINT] : NULL; if (fn) { fn(w, d, ops, font, colors); } } static inline void wclsPaintOverlay(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) { typedef void (*FnT)(WidgetT *, DisplayT *, const BlitOpsT *, const BitmapFontT *, const ColorSchemeT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_PAINT_OVERLAY] : NULL; if (fn) { fn(w, d, ops, font, colors); } } static inline void wclsCalcMinSize(WidgetT *w, const BitmapFontT *font) { typedef void (*FnT)(WidgetT *, const BitmapFontT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_CALC_MIN_SIZE] : NULL; if (fn) { fn(w, font); } } static inline void wclsLayout(WidgetT *w, const BitmapFontT *font) { typedef void (*FnT)(WidgetT *, const BitmapFontT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_LAYOUT] : NULL; if (fn) { fn(w, font); } } static inline void wclsGetLayoutMetrics(const WidgetT *w, const BitmapFontT *font, int32_t *pad, int32_t *gap, int32_t *extraTop, int32_t *borderW) { typedef void (*FnT)(const WidgetT *, const BitmapFontT *, int32_t *, int32_t *, int32_t *, int32_t *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_LAYOUT_METRICS] : NULL; if (fn) { fn(w, font, pad, gap, extraTop, borderW); } } static inline void wclsOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { typedef void (*FnT)(WidgetT *, WidgetT *, int32_t, int32_t); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_MOUSE] : NULL; if (fn) { fn(w, root, vx, vy); } } static inline void wclsOnKey(WidgetT *w, int32_t key, int32_t mod) { typedef void (*FnT)(WidgetT *, int32_t, int32_t); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_KEY] : NULL; if (fn) { fn(w, key, mod); } } static inline void wclsOnAccelActivate(WidgetT *w, WidgetT *root) { typedef void (*FnT)(WidgetT *, WidgetT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_ACCEL_ACTIVATE] : NULL; if (fn) { fn(w, root); } } static inline void wclsDestroy(WidgetT *w) { typedef void (*FnT)(WidgetT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_DESTROY] : NULL; if (fn) { fn(w); } } static inline void wclsOnChildChanged(WidgetT *parent, WidgetT *child) { typedef void (*FnT)(WidgetT *, WidgetT *); FnT fn = parent->wclass ? (FnT)parent->wclass->handlers[WGT_METHOD_ON_CHILD_CHANGED] : NULL; if (fn) { fn(parent, child); } } static inline const char *wclsGetText(const WidgetT *w) { typedef const char *(*FnT)(const WidgetT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_TEXT] : NULL; return fn ? fn(w) : ""; } static inline void wclsSetText(WidgetT *w, const char *text) { typedef void (*FnT)(WidgetT *, const char *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_SET_TEXT] : NULL; if (fn) { fn(w, text); } } static inline bool wclsClearSelection(WidgetT *w) { typedef bool (*FnT)(WidgetT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_CLEAR_SELECTION] : NULL; return fn ? fn(w) : false; } static inline void wclsClosePopup(WidgetT *w) { typedef void (*FnT)(WidgetT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_CLOSE_POPUP] : NULL; if (fn) { fn(w); } } static inline void wclsGetPopupRect(const WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH) { typedef void (*FnT)(const WidgetT *, const BitmapFontT *, int32_t, int32_t *, int32_t *, int32_t *, int32_t *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_POPUP_RECT] : NULL; if (fn) { fn(w, font, contentH, popX, popY, popW, popH); } } static inline void wclsOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { typedef void (*FnT)(WidgetT *, WidgetT *, int32_t, int32_t); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_DRAG_UPDATE] : NULL; if (fn) { fn(w, root, x, y); } } static inline void wclsOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { typedef void (*FnT)(WidgetT *, WidgetT *, int32_t, int32_t); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_DRAG_END] : NULL; if (fn) { fn(w, root, x, y); } } static inline int32_t wclsGetCursorShape(const WidgetT *w, int32_t vx, int32_t vy) { typedef int32_t (*FnT)(const WidgetT *, int32_t, int32_t); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_CURSOR_SHAPE] : NULL; return fn ? fn(w, vx, vy) : 0; } static inline void wclsPoll(WidgetT *w, WindowT *win) { typedef void (*FnT)(WidgetT *, WindowT *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_POLL] : NULL; if (fn) { fn(w, win); } } static inline int32_t wclsQuickRepaint(WidgetT *w, int32_t *outY, int32_t *outH) { typedef int32_t (*FnT)(WidgetT *, int32_t *, int32_t *); FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_QUICK_REPAINT] : NULL; return fn ? fn(w, outY, outH) : 0; } static inline void wclsScrollChildIntoView(WidgetT *parent, const WidgetT *child) { typedef void (*FnT)(WidgetT *, const WidgetT *); FnT fn = parent->wclass ? (FnT)parent->wclass->handlers[WGT_METHOD_SCROLL_CHILD_INTO_VIEW] : NULL; if (fn) { fn(parent, child); } } // ============================================================ // Window integration // ============================================================ // Initialize the widget system for a window. Creates a root VBox container // that fills the window's content area, and installs callback handlers // (onPaint, onMouse, onKey, onResize) that dispatch events to the widget // tree. After this call, the window is fully managed by the widget system // -- the application builds its UI by adding child widgets to the returned // root container. The window's userData is set to the AppContextT pointer. WidgetT *wgtInitWindow(struct AppContextT *ctx, WindowT *win); // ============================================================ // Operations // ============================================================ // Walk from any widget up the tree to the root, then retrieve the // AppContextT stored in the window's userData. This lets any widget // access the full application context without passing it through every // function call. struct AppContextT *wgtGetContext(const WidgetT *w); // Mark a widget as needing both re-layout (measure + position) and // repaint. Propagates upward to ancestors since a child's size change // can affect parent layout. Use this after structural changes (adding/ // removing children, changing text that affects size). void wgtInvalidate(WidgetT *w); // Mark a widget as needing repaint only, without re-layout. Use this // for visual-only changes that don't affect geometry (e.g. checkbox // toggle, selection highlight change, cursor blink). 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); // Set read-only mode (allows scrolling/selection but blocks editing) void wgtSetReadOnly(WidgetT *w, bool readOnly); // Set/get keyboard focus void wgtSetFocused(WidgetT *w); WidgetT *wgtGetFocused(void); // 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); // ============================================================ // Tooltip // ============================================================ // Set tooltip text for a widget (NULL to remove). // Caller owns the string -- it must outlive the widget. void wgtSetTooltip(WidgetT *w, const char *text); // ============================================================ // Debug // ============================================================ // Draw borders around layout containers in ugly colors void wgtSetDebugLayout(struct AppContextT *ctx, bool enabled); // ============================================================ // Dynamic widget registration // ============================================================ // Register a new widget class at runtime. Returns the assigned type ID // Appends wclass to widgetClassTable and returns the assigned type ID. // The WidgetClassT must remain valid for the lifetime of the process // (typically a static const in the registering DXE). int32_t wgtRegisterClass(const WidgetClassT *wclass); // ============================================================ // Layout (called internally; available for manual trigger) // ============================================================ // Decode a tagged size value (WGT_SIZE_PIXELS/CHARS/PERCENT) into a // concrete pixel count. For CHARS, multiplies by charWidth; for PERCENT, // computes the fraction of parentSize. Returns 0 for a raw 0 input // (meaning "auto"). int32_t wgtResolveSize(int32_t taggedSize, int32_t parentSize, int32_t charWidth); // Execute the full two-pass layout algorithm on the widget tree: // Pass 1 (bottom-up): calcMinSize on every widget to compute minimum sizes. // Pass 2 (top-down): allocate space within availW/availH, distributing // extra space according to weights and respecting min/max constraints. // Normally called automatically by the paint handler; exposed here for // cases where layout must be forced before the next paint (e.g. dvxFitWindow). void wgtLayout(WidgetT *root, int32_t availW, int32_t availH, const BitmapFontT *font); // Paint the entire widget tree by depth-first traversal. Each widget's // clip rect is set to its bounds before calling its paint function. // Overlays (dropdown popups, tooltips) are painted in a second pass // after the main tree so they render on top of everything. void wgtPaint(WidgetT *root, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors); // ============================================================ // Widget API registry // ============================================================ // // Each widget DXE registers a small API struct under a name // during wgtRegister(). Callers retrieve it via wgtGetApi() // and cast to the widget-specific API type. Per-widget headers // (e.g. widgetButton.h) provide typed accessors and convenience // macros so callers don't need manual casts. // // This replaces the monolithic WidgetApiT -- adding a new widget // requires zero changes to dvxWidget.h. void wgtRegisterApi(const char *name, const void *api); const void *wgtGetApi(const char *name); // ============================================================ // Widget interface descriptors // ============================================================ // // Each widget DXE can register an interface descriptor that // describes its BASIC-facing properties, methods, and events. // The form runtime and IDE use these for generic dispatch and // property panel enumeration. // Property data types #define WGT_IFACE_STRING 0 #define WGT_IFACE_INT 1 #define WGT_IFACE_BOOL 2 #define WGT_IFACE_FLOAT 3 #define WGT_IFACE_ENUM 4 // int32_t with named values // Method calling conventions (how the form runtime marshals args) #define WGT_SIG_VOID 0 // void fn(WidgetT *) #define WGT_SIG_INT 1 // void fn(WidgetT *, int32_t) #define WGT_SIG_BOOL 2 // void fn(WidgetT *, bool) #define WGT_SIG_STR 3 // void fn(WidgetT *, const char *) #define WGT_SIG_INT_INT 4 // void fn(WidgetT *, int32_t, int32_t) #define WGT_SIG_INT_BOOL 5 // void fn(WidgetT *, int32_t, bool) #define WGT_SIG_RET_INT 6 // int32_t fn(const WidgetT *) #define WGT_SIG_RET_BOOL 7 // bool fn(const WidgetT *) #define WGT_SIG_RET_BOOL_INT 8 // bool fn(const WidgetT *, int32_t) // Property descriptor typedef struct { const char *name; // BASIC property name (e.g. "Caption", "Value") uint8_t type; // WGT_IFACE_* void *getFn; // getter function pointer (NULL if write-only) void *setFn; // setter function pointer (NULL if read-only) const char **enumNames; // WGT_IFACE_ENUM only: NULL-terminated array of value names } WgtPropDescT; // Method descriptor typedef struct { const char *name; // BASIC method name (e.g. "Clear", "SetFocus") uint8_t sig; // WGT_SIG_* void *fn; // function pointer } WgtMethodDescT; // Event descriptor typedef struct { const char *name; // event name (e.g. "Click", "Change") } WgtEventDescT; // Common events implicitly available on all widgets. // The form runtime wires these callbacks on every control. // Widget descriptors only need to list EXTRA events beyond these. // Click, DblClick, Change, GotFocus, LostFocus // Create function signature types for design-time / runtime instantiation. // The create function is always the first slot in the widget API struct. typedef enum { WGT_CREATE_PARENT = 0, // fn(parent) WGT_CREATE_PARENT_TEXT, // fn(parent, const char *text) WGT_CREATE_PARENT_INT, // fn(parent, int32_t) WGT_CREATE_PARENT_INT_INT, // fn(parent, int32_t, int32_t) WGT_CREATE_PARENT_INT_INT_INT, // fn(parent, int32_t, int32_t, int32_t) WGT_CREATE_PARENT_INT_BOOL, // fn(parent, int32_t, bool) WGT_CREATE_PARENT_BOOL, // fn(parent, bool) WGT_CREATE_PARENT_DATA, // fn(parent, data, w, h, pitch) -- not auto-creatable } WgtCreateSigE; #define WGT_MAX_CREATE_ARGS 3 // Widget interface descriptor (registered by each .wgt) typedef struct { const char *basName; // VB-style name (e.g. "CommandButton"), or NULL const WgtPropDescT *props; // type-specific properties int32_t propCount; const WgtMethodDescT *methods; // type-specific methods int32_t methodCount; const WgtEventDescT *events; // extra events beyond common set int32_t eventCount; uint8_t createSig; // WgtCreateSigE: how to call create fn int32_t createArgs[WGT_MAX_CREATE_ARGS]; // default numeric args bool isContainer; // can hold child widgets const char *defaultEvent; // default event name (e.g. "Click") const char *namePrefix; // auto-name prefix (NULL = use basName) } WgtIfaceT; // Register/retrieve interface descriptors by widget type name. void wgtRegisterIface(const char *name, const WgtIfaceT *iface); const WgtIfaceT *wgtGetIface(const char *name); // Find a widget type name by its VB-style name (e.g. "CommandButton" -> "button"). // Returns NULL if no widget has that basName. Case-insensitive. const char *wgtFindByBasName(const char *basName); // Enumerate all registered widget interfaces. int32_t wgtIfaceCount(void); const WgtIfaceT *wgtIfaceAt(int32_t idx, const char **outName); // Get/set the .wgt file path for a registered widget (set by loader). const char *wgtIfaceGetPath(const char *name); void wgtIfaceSetPath(const char *name, const char *path); // Get the 1-based index of this widget within its .wgt file. // Used to construct suffixed resource names (e.g. "name-2", "icon16-2"). int32_t wgtIfaceGetPathIndex(const char *name); #endif // DVX_WIDGET_H