449 lines
20 KiB
Markdown
449 lines
20 KiB
Markdown
# DVX Core Library (libdvx.lib)
|
|
|
|
The core GUI infrastructure for DVX, built as a DXE3 module. Provides
|
|
VESA video setup, 2D drawing primitives, dirty-rectangle compositing,
|
|
a window manager with Motif-style chrome, and the widget infrastructure
|
|
(layout engine, event dispatch, class registration). Individual widget
|
|
type implementations live in `../widgets/` as separate `.wgt` DXE
|
|
modules that register themselves at runtime via `wgtRegisterClass()`.
|
|
|
|
Core knows nothing about individual widget types. There is no
|
|
WidgetTypeE enum, no widget union, and no per-widget structs in
|
|
dvxWidget.h. All widget-specific behavior is dispatched through the
|
|
WidgetClassT dispatch table.
|
|
|
|
|
|
## 5-Layer Architecture
|
|
|
|
| Layer | Header | Source | Description |
|
|
|-------|--------|--------|-------------|
|
|
| 1. Video | `dvxVideo.h` | `dvxVideo.c` | VESA VBE init, LFB mapping, backbuffer, pixel format, `packColor()` |
|
|
| 2. Draw | `dvxDraw.h` | `dvxDraw.c` | Rect fills, bevels, text, bitmap cursors, focus rects, lines |
|
|
| 3. Compositor | `dvxComp.h` | `dvxComp.c` | Dirty rect tracking, merge, clip, LFB flush |
|
|
| 4. Window Manager | `dvxWm.h` | `dvxWm.c` | Window stack, chrome, drag/resize, menus, scrollbars, hit test |
|
|
| 5. Application | `dvxApp.h` | `dvxApp.c` | Event loop, input polling, color schemes, wallpaper, public API |
|
|
|
|
Additional modules built into libdvx.lib:
|
|
|
|
| Header | Source | Description |
|
|
|--------|--------|-------------|
|
|
| `dvxDialog.h` | `dvxDialog.c` | Modal message box and file open/save dialogs |
|
|
| `dvxPrefs.h` | `dvxPrefs.c` | INI-based preferences (read/write with typed accessors) |
|
|
| `dvxResource.h` | `dvxResource.c` | Resource system -- icons, text, and binary data appended to DXE files |
|
|
| `dvxMem.h` | (header only) | Per-app memory tracking API declarations |
|
|
| `dvxWidget.h` | `widgetClass.c`, `widgetCore.c`, `widgetEvent.c`, `widgetLayout.c`, `widgetOps.c`, `widgetScrollbar.c` | Widget infrastructure |
|
|
| `dvxWidgetPlugin.h` | (header only) | Plugin API for widget DXE modules |
|
|
| -- | `dvxImage.c` | Image loading via stb_image (BMP, PNG, JPEG, GIF) |
|
|
| -- | `dvxImageWrite.c` | PNG export via stb_image_write |
|
|
|
|
|
|
## Source Files
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `dvxVideo.c` | VESA mode negotiation, LFB mapping via DPMI, backbuffer alloc, `packColor()` |
|
|
| `dvxDraw.c` | `rectFill()`, `rectCopy()`, `drawBevel()`, `drawText()`, `drawTextN()`, `drawTermRow()`, cursor rendering |
|
|
| `dvxComp.c` | `dirtyListAdd()`, `dirtyListMerge()`, `flushRect()`, `rectIntersect()` |
|
|
| `dvxWm.c` | Window create/destroy, Z-order, chrome drawing, drag/resize, menu bar, scrollbars, minimize/maximize |
|
|
| `dvxApp.c` | `dvxInit()`, `dvxRun()`, `dvxUpdate()`, `dvxCreateWindow()`, color schemes, wallpaper, screenshots |
|
|
| `dvxDialog.c` | `dvxMessageBox()`, `dvxFileDialog()` -- modal dialogs with own event loops |
|
|
| `dvxPrefs.c` | `prefsLoad()`, `prefsSave()`, typed get/set for string/int/bool |
|
|
| `dvxResource.c` | `dvxResOpen()`, `dvxResRead()`, `dvxResFind()`, `dvxResClose()` -- resource system |
|
|
| `dvxImage.c` | `dvxLoadImage()`, `dvxLoadImageFromMemory()` -- stb_image loader, converts to native pixel format |
|
|
| `dvxImageWrite.c` | `dvxSaveImage()` -- PNG writer for screenshots |
|
|
| `widgetClass.c` | `wgtRegisterClass()`, `wgtRegisterApi()`, `wgtGetApi()`, class table |
|
|
| `widgetCore.c` | Widget allocation, tree ops, focus management, clipboard, hit testing, cursor blink |
|
|
| `widgetEvent.c` | `widgetOnMouse()`, `widgetOnKey()`, `widgetOnPaint()`, `widgetOnResize()`, scrollbar management |
|
|
| `widgetLayout.c` | Two-pass flexbox layout: bottom-up `calcMinSize`, top-down space allocation with weights |
|
|
| `widgetOps.c` | `wgtPaint()`, `wgtLayout()`, `wgtInitWindow()`, text get/set, invalidation |
|
|
| `widgetScrollbar.c` | Scrollbar drawing (H/V), thumb calculation, hit testing, drag update |
|
|
|
|
|
|
## Public Headers
|
|
|
|
| Header | Purpose |
|
|
|--------|---------|
|
|
| `dvxTypes.h` | All shared types: DisplayT, RectT, BlitOpsT, BevelStyleT, BitmapFontT, ColorSchemeT, WindowT, MenuT, ScrollbarT, CursorT, PopupStateT |
|
|
| `dvxVideo.h` | `videoInit()`, `videoShutdown()`, `packColor()`, `setClipRect()`, `resetClipRect()` |
|
|
| `dvxDraw.h` | All drawing functions: `rectFill()`, `drawBevel()`, `drawText()`, `drawTextN()`, `drawTermRow()`, etc. |
|
|
| `dvxComp.h` | Dirty list operations: `dirtyListAdd()`, `dirtyListMerge()`, `flushRect()`, `rectIntersect()` |
|
|
| `dvxWm.h` | Window management: `wmCreateWindow()`, `wmDestroyWindow()`, `wmRaiseWindow()`, menus, scrollbars, chrome |
|
|
| `dvxApp.h` | Application API: `dvxInit()`, `dvxRun()`, `dvxUpdate()`, `dvxCreateWindow()`, color schemes, wallpaper, image I/O |
|
|
| `dvxDialog.h` | Modal dialogs: `dvxMessageBox()`, `dvxFileDialog()` |
|
|
| `dvxPrefs.h` | INI preferences: `prefsLoad()`, `prefsSave()`, typed accessors |
|
|
| `dvxResource.h` | Resource system: `dvxResOpen()`, `dvxResRead()`, `dvxResFind()`, `dvxResClose()` |
|
|
| `dvxMem.h` | Per-app memory tracking: `dvxMalloc()`, `dvxFree()`, `dvxMemGetAppUsage()`, etc. |
|
|
| `dvxWidget.h` | Widget system public API: WidgetT, WidgetClassT, size tags, layout, API registry, `wclsFoo()` dispatch helpers |
|
|
| `dvxWidgetPlugin.h` | Plugin API for widget DXE authors: tree ops, focus, scrollbar helpers, shared state |
|
|
| `dvxFont.h` | Embedded 8x14 and 8x16 bitmap font data (CP437) |
|
|
| `dvxCursor.h` | Mouse cursor AND/XOR mask data (arrow, resize H/V/diag, busy) |
|
|
| `dvxPalette.h` | Default 256-color VGA palette for 8-bit mode |
|
|
|
|
|
|
## Platform Layer
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `platform/dvxPlatform.h` | Platform abstraction API (video, input, spans, DXE, crash recovery, memory tracking) |
|
|
| `platform/dvxPlatformDos.c` | DJGPP/DPMI implementation (VESA VBE, INT 33h mouse, INT 16h keyboard, asm spans) |
|
|
|
|
The platform layer is compiled into dvx.exe (the loader), not into
|
|
libdvx.lib. Platform functions are exported to all DXE modules via
|
|
`platformRegisterDxeExports()`.
|
|
|
|
|
|
## Third-Party Libraries
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `thirdparty/stb_image.h` | Image loading (implementation compiled into dvxImage.c) |
|
|
| `thirdparty/stb_image_write.h` | PNG writing (implementation compiled into dvxImageWrite.c) |
|
|
| `thirdparty/stb_ds.h` | Dynamic arrays/hash maps (implementation in loader, exported to all DXEs) |
|
|
|
|
|
|
## Dynamic Limits
|
|
|
|
All major data structures grow dynamically via realloc. There are no
|
|
fixed-size limits for:
|
|
|
|
- **Windows** -- `WindowStackT.windows` is a dynamic array
|
|
- **Menus** -- `MenuBarT.menus` and `MenuT.items` are dynamic arrays
|
|
- **Accelerator entries** -- `AccelTableT.entries` is a dynamic array
|
|
- **Dirty rectangles** -- `DirtyListT.rects` is a dynamic array
|
|
- **Submenu depth** -- `PopupStateT.parentStack` is a dynamic array
|
|
|
|
The only fixed-size buffers remaining are per-element string fields
|
|
(`MAX_TITLE_LEN = 128`, `MAX_MENU_LABEL = 32`, `MAX_WIDGET_NAME = 32`)
|
|
and the system menu (`SYS_MENU_MAX_ITEMS = 10`).
|
|
|
|
|
|
## Resource System
|
|
|
|
Resources are appended to DXE3 files (.app, .wgt, .lib) after the
|
|
normal DXE content. The DXE loader never reads past the DXE header,
|
|
so appended data is invisible to dlopen.
|
|
|
|
File layout:
|
|
|
|
[DXE3 content]
|
|
[resource data entries] -- sequential, variable length
|
|
[resource directory] -- fixed-size entries (48 bytes each)
|
|
[footer] -- magic + directory offset + count (16 bytes)
|
|
|
|
### Resource Types
|
|
|
|
| Define | Value | Description |
|
|
|--------|-------|-------------|
|
|
| `DVX_RES_ICON` | 1 | Image data (BMP icon: 16x16, 32x32, etc.) |
|
|
| `DVX_RES_TEXT` | 2 | Null-terminated string (author, copyright, etc.) |
|
|
| `DVX_RES_BINARY` | 3 | Arbitrary binary data (app-specific) |
|
|
|
|
### Resource API
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `dvxResOpen(path)` | Open a resource handle by reading the footer and directory. Returns NULL if no resources. |
|
|
| `dvxResRead(h, name, outSize)` | Find a resource by name and read its data into a malloc'd buffer. Caller frees. |
|
|
| `dvxResFind(h, name)` | Find a resource by name and return its directory entry pointer. |
|
|
| `dvxResClose(h)` | Close the handle and free associated memory. |
|
|
|
|
### Key Types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `DvxResDirEntryT` | Directory entry: name[32], type, offset, size, reserved (48 bytes) |
|
|
| `DvxResFooterT` | Footer: magic (`0x52585644` = "DVXR"), dirOffset, entryCount, reserved (16 bytes) |
|
|
| `DvxResHandleT` | Runtime handle: path, entries array, entry count |
|
|
|
|
|
|
## Memory Tracking (dvxMem.h)
|
|
|
|
Per-app memory tracking wraps malloc/free/calloc/realloc/strdup with a
|
|
small header per allocation that records the owning app ID and size.
|
|
DXE code does not need to include dvxMem.h -- the DXE export table maps
|
|
the standard allocator names to these wrappers transparently.
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `dvxMalloc(size)` | Tracked malloc |
|
|
| `dvxCalloc(nmemb, size)` | Tracked calloc |
|
|
| `dvxRealloc(ptr, size)` | Tracked realloc |
|
|
| `dvxFree(ptr)` | Tracked free (falls through to real free on non-tracked pointers) |
|
|
| `dvxStrdup(s)` | Tracked strdup |
|
|
| `dvxMemSnapshotLoad(appId)` | Record baseline memory for leak detection |
|
|
| `dvxMemGetAppUsage(appId)` | Query current memory usage for an app (bytes) |
|
|
| `dvxMemResetApp(appId)` | Free all allocations charged to an app |
|
|
|
|
The global `dvxMemAppIdPtr` pointer is set by the shell to
|
|
`&ctx->currentAppId` so the allocator knows which app to charge.
|
|
|
|
|
|
## WidgetT Structure
|
|
|
|
The WidgetT struct is generic -- no widget-specific fields or union:
|
|
|
|
```c
|
|
typedef struct WidgetT {
|
|
int32_t type; // assigned by wgtRegisterClass()
|
|
const struct WidgetClassT *wclass; // dispatch table pointer
|
|
char name[MAX_WIDGET_NAME];
|
|
|
|
// Tree linkage
|
|
struct WidgetT *parent, *firstChild, *lastChild, *nextSibling;
|
|
WindowT *window;
|
|
|
|
// Geometry (relative to window content area)
|
|
int32_t x, y, w, h;
|
|
int32_t calcMinW, calcMinH; // computed minimum size
|
|
|
|
// Size hints (tagged: wgtPixels/wgtChars/wgtPercent, 0 = auto)
|
|
int32_t minW, minH, maxW, maxH;
|
|
int32_t prefW, prefH;
|
|
int32_t weight; // extra-space distribution (0 = fixed)
|
|
|
|
// Container properties
|
|
WidgetAlignE align;
|
|
int32_t spacing, padding; // tagged sizes
|
|
|
|
// Colors (0 = use color scheme defaults)
|
|
uint32_t fgColor, bgColor;
|
|
|
|
// State
|
|
bool visible, enabled, readOnly, focused;
|
|
char accelKey;
|
|
|
|
// User data and callbacks
|
|
void *userData;
|
|
void *data; // widget-private data (allocated by widget DXE)
|
|
const char *tooltip;
|
|
MenuT *contextMenu;
|
|
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);
|
|
} WidgetT;
|
|
```
|
|
|
|
|
|
## WidgetClassT Dispatch Table
|
|
|
|
WidgetClassT is an ABI-stable dispatch table. Method IDs are fixed
|
|
constants that never change -- adding new methods appends new IDs
|
|
without shifting existing ones. Widget DXEs compiled against an older
|
|
DVX version continue to work unmodified.
|
|
|
|
```c
|
|
#define WGT_CLASS_VERSION 1 // bump on breaking ABI change
|
|
#define WGT_METHOD_MAX 32 // room for future methods
|
|
|
|
typedef struct WidgetClassT {
|
|
uint32_t version;
|
|
uint32_t flags;
|
|
void *handlers[WGT_METHOD_MAX];
|
|
} WidgetClassT;
|
|
```
|
|
|
|
### Method ID Table
|
|
|
|
21 methods are currently defined (IDs 0--20). WGT_METHOD_MAX is 32,
|
|
leaving room for 11 future methods without a version bump.
|
|
|
|
| ID | Method ID | Signature | Purpose |
|
|
|----|-----------|-----------|---------|
|
|
| 0 | `WGT_METHOD_PAINT` | `void (w, d, ops, font, colors)` | Render the widget |
|
|
| 1 | `WGT_METHOD_PAINT_OVERLAY` | `void (w, d, ops, font, colors)` | Render overlay (dropdown popup) |
|
|
| 2 | `WGT_METHOD_CALC_MIN_SIZE` | `void (w, font)` | Compute minimum size (bottom-up pass) |
|
|
| 3 | `WGT_METHOD_LAYOUT` | `void (w, font)` | Position children (top-down pass) |
|
|
| 4 | `WGT_METHOD_GET_LAYOUT_METRICS` | `void (w, font, pad, gap, extraTop, borderW)` | Return padding/gap for box layout |
|
|
| 5 | `WGT_METHOD_ON_MOUSE` | `void (w, root, vx, vy)` | Handle mouse click |
|
|
| 6 | `WGT_METHOD_ON_KEY` | `void (w, key, mod)` | Handle keyboard input |
|
|
| 7 | `WGT_METHOD_ON_ACCEL_ACTIVATE` | `void (w, root)` | Handle accelerator key match |
|
|
| 8 | `WGT_METHOD_DESTROY` | `void (w)` | Free widget-private data |
|
|
| 9 | `WGT_METHOD_ON_CHILD_CHANGED` | `void (parent, child)` | Notification when a child changes |
|
|
| 10 | `WGT_METHOD_GET_TEXT` | `const char *(w)` | Return widget text |
|
|
| 11 | `WGT_METHOD_SET_TEXT` | `void (w, text)` | Set widget text |
|
|
| 12 | `WGT_METHOD_CLEAR_SELECTION` | `bool (w)` | Clear text/item selection |
|
|
| 13 | `WGT_METHOD_CLOSE_POPUP` | `void (w)` | Close dropdown popup |
|
|
| 14 | `WGT_METHOD_GET_POPUP_RECT` | `void (w, font, contentH, popX, popY, popW, popH)` | Compute popup rectangle |
|
|
| 15 | `WGT_METHOD_ON_DRAG_UPDATE` | `void (w, root, x, y)` | Mouse move during drag |
|
|
| 16 | `WGT_METHOD_ON_DRAG_END` | `void (w, root, x, y)` | Mouse release after drag |
|
|
| 17 | `WGT_METHOD_GET_CURSOR_SHAPE` | `int32_t (w, vx, vy)` | Return cursor ID for this position |
|
|
| 18 | `WGT_METHOD_POLL` | `void (w, win)` | Periodic polling (AnsiTerm comms) |
|
|
| 19 | `WGT_METHOD_QUICK_REPAINT` | `int32_t (w, outY, outH)` | Fast incremental repaint |
|
|
| 20 | `WGT_METHOD_SCROLL_CHILD_INTO_VIEW` | `void (parent, child)` | Scroll to make a child visible |
|
|
|
|
### 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.
|
|
|
|
| Helper | Wraps Method ID |
|
|
|--------|-----------------|
|
|
| `wclsHas(w, methodId)` | Check if a method is implemented (non-NULL) |
|
|
| `wclsPaint(w, d, ops, font, colors)` | `WGT_METHOD_PAINT` |
|
|
| `wclsPaintOverlay(w, d, ops, font, colors)` | `WGT_METHOD_PAINT_OVERLAY` |
|
|
| `wclsCalcMinSize(w, font)` | `WGT_METHOD_CALC_MIN_SIZE` |
|
|
| `wclsLayout(w, font)` | `WGT_METHOD_LAYOUT` |
|
|
| `wclsGetLayoutMetrics(w, font, pad, gap, extraTop, borderW)` | `WGT_METHOD_GET_LAYOUT_METRICS` |
|
|
| `wclsOnMouse(w, root, vx, vy)` | `WGT_METHOD_ON_MOUSE` |
|
|
| `wclsOnKey(w, key, mod)` | `WGT_METHOD_ON_KEY` |
|
|
| `wclsOnAccelActivate(w, root)` | `WGT_METHOD_ON_ACCEL_ACTIVATE` |
|
|
| `wclsDestroy(w)` | `WGT_METHOD_DESTROY` |
|
|
| `wclsOnChildChanged(parent, child)` | `WGT_METHOD_ON_CHILD_CHANGED` |
|
|
| `wclsGetText(w)` | `WGT_METHOD_GET_TEXT` |
|
|
| `wclsSetText(w, text)` | `WGT_METHOD_SET_TEXT` |
|
|
| `wclsClearSelection(w)` | `WGT_METHOD_CLEAR_SELECTION` |
|
|
| `wclsClosePopup(w)` | `WGT_METHOD_CLOSE_POPUP` |
|
|
| `wclsGetPopupRect(w, font, contentH, popX, popY, popW, popH)` | `WGT_METHOD_GET_POPUP_RECT` |
|
|
| `wclsOnDragUpdate(w, root, x, y)` | `WGT_METHOD_ON_DRAG_UPDATE` |
|
|
| `wclsOnDragEnd(w, root, x, y)` | `WGT_METHOD_ON_DRAG_END` |
|
|
| `wclsGetCursorShape(w, vx, vy)` | `WGT_METHOD_GET_CURSOR_SHAPE` |
|
|
| `wclsPoll(w, win)` | `WGT_METHOD_POLL` |
|
|
| `wclsQuickRepaint(w, outY, outH)` | `WGT_METHOD_QUICK_REPAINT` |
|
|
| `wclsScrollChildIntoView(parent, child)` | `WGT_METHOD_SCROLL_CHILD_INTO_VIEW` |
|
|
|
|
### WidgetClassT Flags
|
|
|
|
| Flag | Value | Description |
|
|
|------|-------|-------------|
|
|
| `WCLASS_FOCUSABLE` | 0x0001 | Can receive keyboard focus |
|
|
| `WCLASS_BOX_CONTAINER` | 0x0002 | Uses VBox/HBox layout algorithm |
|
|
| `WCLASS_HORIZ_CONTAINER` | 0x0004 | Lays out children horizontally |
|
|
| `WCLASS_PAINTS_CHILDREN` | 0x0008 | Widget handles child rendering |
|
|
| `WCLASS_NO_HIT_RECURSE` | 0x0010 | Hit testing stops here |
|
|
| `WCLASS_FOCUS_FORWARD` | 0x0020 | Accel hit forwards focus to next focusable |
|
|
| `WCLASS_HAS_POPUP` | 0x0040 | Has dropdown popup overlay |
|
|
| `WCLASS_SCROLLABLE` | 0x0080 | Accepts mouse wheel events |
|
|
| `WCLASS_SCROLL_CONTAINER` | 0x0100 | Scroll container (ScrollPane) |
|
|
| `WCLASS_NEEDS_POLL` | 0x0200 | Needs periodic polling |
|
|
| `WCLASS_SWALLOWS_TAB` | 0x0400 | Tab key goes to widget, not focus nav |
|
|
| `WCLASS_RELAYOUT_ON_SCROLL` | 0x0800 | Full relayout on scrollbar drag |
|
|
| `WCLASS_PRESS_RELEASE` | 0x1000 | Click = press+release (buttons) |
|
|
| `WCLASS_ACCEL_WHEN_HIDDEN` | 0x2000 | Accel matching works when invisible |
|
|
|
|
|
|
## Widget Registration
|
|
|
|
Each widget DXE exports `wgtRegister()`, called by the loader after
|
|
`dlopen`. The WidgetClassT uses the `handlers[]` array indexed by
|
|
method IDs:
|
|
|
|
```c
|
|
static int32_t sButtonType;
|
|
|
|
static const WidgetClassT sButtonClass = {
|
|
.version = WGT_CLASS_VERSION,
|
|
.flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE,
|
|
.handlers = {
|
|
[WGT_METHOD_PAINT] = buttonPaint,
|
|
[WGT_METHOD_CALC_MIN_SIZE] = buttonCalcMinSize,
|
|
[WGT_METHOD_ON_MOUSE] = buttonOnMouse,
|
|
[WGT_METHOD_ON_KEY] = buttonOnKey,
|
|
[WGT_METHOD_DESTROY] = buttonDestroy,
|
|
[WGT_METHOD_GET_TEXT] = buttonGetText,
|
|
[WGT_METHOD_SET_TEXT] = buttonSetText,
|
|
[WGT_METHOD_ON_ACCEL_ACTIVATE] = buttonAccelActivate,
|
|
}
|
|
};
|
|
|
|
static const ButtonApiT sApi = { .create = buttonCreate };
|
|
|
|
void wgtRegister(void) {
|
|
sButtonType = wgtRegisterClass(&sButtonClass);
|
|
wgtRegisterApi("button", &sApi);
|
|
}
|
|
```
|
|
|
|
|
|
## Per-Widget API Registry
|
|
|
|
The monolithic WidgetApiT is gone. Each widget registers a small API
|
|
struct under a name via `wgtRegisterApi()`. Callers retrieve it via
|
|
`wgtGetApi()` and cast to the widget-specific type. Per-widget headers
|
|
(e.g. `widgetButton.h`) provide typed accessors and convenience macros:
|
|
|
|
```c
|
|
// widgetButton.h
|
|
typedef struct {
|
|
WidgetT *(*create)(WidgetT *parent, const char *text);
|
|
} ButtonApiT;
|
|
|
|
static inline const ButtonApiT *dvxButtonApi(void) {
|
|
static const ButtonApiT *sApi;
|
|
if (!sApi) { sApi = (const ButtonApiT *)wgtGetApi("button"); }
|
|
return sApi;
|
|
}
|
|
|
|
#define wgtButton(parent, text) dvxButtonApi()->create(parent, text)
|
|
```
|
|
|
|
|
|
## Tagged Size Values
|
|
|
|
Size hints encode both unit type and numeric value in a single int32_t:
|
|
|
|
| Macro | Encoding | Example |
|
|
|-------|----------|---------|
|
|
| `wgtPixels(v)` | Bits 31:30 = 00 | `w->minW = wgtPixels(200);` |
|
|
| `wgtChars(v)` | Bits 31:30 = 01 | `w->minW = wgtChars(40);` |
|
|
| `wgtPercent(v)` | Bits 31:30 = 10 | `w->minW = wgtPercent(50);` |
|
|
| `0` | -- | Auto (use computed minimum) |
|
|
|
|
|
|
## Layout Algorithm
|
|
|
|
Two-pass flexbox-like layout:
|
|
|
|
1. **Bottom-up** (`calcMinSize`): Each widget computes its minimum size.
|
|
Containers sum children along the main axis, max across the cross axis.
|
|
2. **Top-down** (`layout`): Available space is allocated to children.
|
|
Extra space beyond minimum is distributed proportionally to weights.
|
|
`weight=0` means fixed size, `weight=100` is the default flexible weight.
|
|
|
|
### Cross-Axis Centering
|
|
|
|
When a child widget has a `maxW` (in a VBox) or `maxH` (in an HBox)
|
|
that constrains it smaller than the available cross-axis space, the
|
|
layout engine automatically centers the child on the cross axis. This
|
|
means setting `maxW` or `maxH` on a child inside a container will both
|
|
cap its size and center it within the remaining space.
|
|
|
|
|
|
## Image Loading
|
|
|
|
Two image loading functions are available:
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `dvxLoadImage(ctx, path, outW, outH, outPitch)` | Load from a file path |
|
|
| `dvxLoadImageFromMemory(ctx, data, dataLen, outW, outH, outPitch)` | Load from a memory buffer (e.g. resource data) |
|
|
|
|
Both convert to the display's native pixel format. Caller frees the
|
|
returned buffer with `dvxFreeImage()`. Supported formats: BMP, PNG,
|
|
JPEG, GIF (via stb_image).
|
|
|
|
|
|
## Exported Symbols
|
|
|
|
libdvx.lib exports symbols matching these prefixes:
|
|
|
|
```
|
|
dvx*, wgt*, wm*, prefs*, rect*, draw*, pack*, text*, setClip*,
|
|
resetClip*, stbi*, stbi_write*, dirtyList*, widget*,
|
|
accelParse*, clipboard*, multiClick*,
|
|
sCursor*, sDbl*, sDebug*, sClosed*, sFocused*, sKey*,
|
|
sOpen*, sDrag*, sClosed*, sKey*
|
|
```
|
|
|
|
|
|
## Build
|
|
|
|
```
|
|
make # builds bin/libs/libdvx.lib + bin/libs/libdvx.dep
|
|
make clean # removes objects and library
|
|
```
|
|
|
|
Depends on: `libtasks.lib` (via libdvx.dep).
|