# 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 vtable. ## 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) | | `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 | | `dvxImage.c` | `dvxLoadImage()` -- 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 | | `dvxWidget.h` | Widget system public API: WidgetT, WidgetClassT, size tags, layout, API registry | | `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) | | `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) | ## 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; // vtable pointer char name[32]; // 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 Vtable Each widget type defines a static WidgetClassT with flags and function pointers. The vtable has 26 function slots plus a flags field: | Slot | Signature | Purpose | |------|-----------|---------| | `flags` | `uint32_t` | Static properties (see Flags below) | | `paint` | `(w, d, ops, font, colors)` | Render the widget | | `paintOverlay` | `(w, d, ops, font, colors)` | Render overlay (dropdown popup) | | `calcMinSize` | `(w, font)` | Compute minimum size (bottom-up pass) | | `layout` | `(w, font)` | Position children (top-down pass) | | `getLayoutMetrics` | `(w, font, pad, gap, extraTop, borderW)` | Return padding/gap for box layout | | `onMouse` | `(w, root, vx, vy)` | Handle mouse click | | `onKey` | `(w, key, mod)` | Handle keyboard input | | `onAccelActivate` | `(w, root)` | Handle accelerator key match | | `destroy` | `(w)` | Free widget-private data | | `onChildChanged` | `(parent, child)` | Notification when a child changes | | `getText` | `(w)` | Return widget text | | `setText` | `(w, text)` | Set widget text | | `clearSelection` | `(w)` | Clear text/item selection | | `closePopup` | `(w)` | Close dropdown popup | | `getPopupRect` | `(w, font, contentH, popX, popY, popW, popH)` | Compute popup rectangle | | `onDragUpdate` | `(w, root, x, y)` | Mouse move during drag | | `onDragEnd` | `(w, root, x, y)` | Mouse release after drag | | `getCursorShape` | `(w, vx, vy)` | Return cursor ID for this position | | `poll` | `(w, win)` | Periodic polling (AnsiTerm comms) | | `quickRepaint` | `(w, outY, outH)` | Fast incremental repaint | ### 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`. A typical registration: ```c static int32_t sButtonType; static const WidgetClassT sButtonClass = { .flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE, .paint = buttonPaint, .calcMinSize = buttonCalcMinSize, .onMouse = buttonOnMouse, .onKey = buttonOnKey, .destroy = buttonDestroy, .getText = buttonGetText, .setText = buttonSetText, .setPressed = buttonSetPressed, .onAccelActivate = 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. ## Exported Symbols libdvx.lib exports symbols matching these prefixes: ``` dvx*, wgt*, wm*, prefs*, rect*, draw*, pack*, text*, setClip*, resetClip*, stbi*, dirtyList*, widget*, accelParse*, clipboard*, multiClick*, sCursor*, sDbl*, sDebug*, sClosed*, sFocused*, sKey*, sOpen*, sPressed*, sDrag*, sDrawing*, sResize*, sListView*, sSplitter*, sTreeView* ``` ## Build ``` make # builds bin/libs/libdvx.lib + bin/libs/libdvx.dep make clean # removes objects and library ``` Depends on: `libtasks.lib` (via libdvx.dep).