878 lines
29 KiB
Markdown
878 lines
29 KiB
Markdown
# DV/X GUI
|
|
|
|
A DESQview/X-style windowed GUI compositor for DOS, targeting DJGPP/DPMI with
|
|
VESA VBE 2.0+ linear framebuffer.
|
|
|
|
Motif-style beveled chrome, dirty-rectangle compositing, draggable and
|
|
resizable windows, dropdown menus, scrollbars, and a declarative widget/layout
|
|
system with buttons, checkboxes, radios, text inputs, dropdowns, combo boxes,
|
|
sliders, progress bars, tab controls, tree views, toolbars, status bars,
|
|
images, image buttons, drawable canvases, and an ANSI BBS terminal emulator.
|
|
|
|
## Building
|
|
|
|
Requires the DJGPP cross-compiler (`i586-pc-msdosdjgpp-gcc`).
|
|
|
|
The GUI is built as a static library (`lib/libdvx.a`). The demo links
|
|
against it.
|
|
|
|
```
|
|
cd dvxdemo
|
|
make # builds lib/libdvx.a then bin/demo.exe
|
|
make clean # removes obj/ and bin/
|
|
```
|
|
|
|
Set `DJGPP_PREFIX` in the Makefile if your toolchain is installed somewhere
|
|
other than `~/djgpp/djgpp`.
|
|
|
|
## Architecture
|
|
|
|
The library is organized in five layers. Each layer is a `.h`/`.c` pair.
|
|
Application code only needs to include `dvxApp.h` (which pulls in the rest)
|
|
and optionally `dvxWidget.h`.
|
|
|
|
```
|
|
Layer 1 dvxVideo VESA init, LFB mapping, backbuffer, pixel format
|
|
Layer 2 dvxDraw Spans, rects, bevels, text, bitmaps (asm inner loops)
|
|
Layer 3 dvxComp Dirty rectangle list, merge, LFB flush
|
|
Layer 4 dvxWm Window stack, chrome, drag, resize, focus, menus, scrollbars
|
|
Layer 5 dvxApp Event loop, mouse/keyboard input, public API
|
|
dvxWidget Widget/layout system (optional, standalone)
|
|
```
|
|
|
|
Supporting files:
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `dvxTypes.h` | Shared type definitions used by all layers |
|
|
| `dvxFont.h` | Built-in 8x14 bitmap font glyph data |
|
|
| `dvxCursor.h` | Mouse cursor bitmask data (5 shapes) |
|
|
| `dvxPalette.h` | Default VGA palette for 8-bit mode |
|
|
| `dvxIcon.c` | stb_image implementation unit (BMP/PNG/JPEG/GIF) |
|
|
| `dvxImageWrite.c` | stb_image_write implementation unit (PNG export) |
|
|
| `thirdparty/stb_image.h` | Third-party single-header image loader |
|
|
| `thirdparty/stb_image_write.h` | Third-party single-header image writer |
|
|
|
|
## Quick start
|
|
|
|
```c
|
|
#include "dvxApp.h"
|
|
|
|
static void onPaint(WindowT *win, RectT *dirty) {
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
const BlitOpsT *ops = dvxGetBlitOps(ctx);
|
|
const DisplayT *d = dvxGetDisplay(ctx);
|
|
uint32_t blue = packColor(d, 0, 0, 200);
|
|
|
|
for (int32_t y = 0; y < win->contentH; y++) {
|
|
ops->spanFill(win->contentBuf + y * win->contentPitch,
|
|
blue, win->contentW);
|
|
}
|
|
}
|
|
|
|
int main(void) {
|
|
AppContextT ctx;
|
|
|
|
if (dvxInit(&ctx, 1024, 768, 16) != 0) {
|
|
return 1;
|
|
}
|
|
|
|
WindowT *win = dvxCreateWindow(&ctx, "Hello", 100, 100, 300, 200, true);
|
|
win->userData = &ctx;
|
|
win->onPaint = onPaint;
|
|
|
|
RectT r = {0, 0, win->contentW, win->contentH};
|
|
win->onPaint(win, &r);
|
|
|
|
dvxRun(&ctx);
|
|
dvxShutdown(&ctx);
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
## Quick start (widgets)
|
|
|
|
```c
|
|
#include "dvxApp.h"
|
|
#include "dvxWidget.h"
|
|
|
|
static void onButtonClick(WidgetT *w) {
|
|
WidgetT *root = w;
|
|
while (root->parent) root = root->parent;
|
|
|
|
WidgetT *lbl = wgtFind(root, "status");
|
|
if (lbl) {
|
|
wgtSetText(lbl, "Clicked!");
|
|
wgtInvalidate(lbl);
|
|
}
|
|
}
|
|
|
|
int main(void) {
|
|
AppContextT ctx;
|
|
dvxInit(&ctx, 1024, 768, 16);
|
|
|
|
WindowT *win = dvxCreateWindow(&ctx, "Widgets", 100, 100, 260, 200, true);
|
|
win->userData = &ctx;
|
|
|
|
WidgetT *root = wgtInitWindow(&ctx, win);
|
|
|
|
WidgetT *lbl = wgtLabel(root, "Ready.");
|
|
strncpy(lbl->name, "status", MAX_WIDGET_NAME);
|
|
|
|
wgtHSeparator(root);
|
|
|
|
WidgetT *row = wgtHBox(root);
|
|
wgtLabel(row, "Name:");
|
|
wgtTextInput(row, 64);
|
|
|
|
WidgetT *btn = wgtButton(root, "Go");
|
|
btn->onClick = onButtonClick;
|
|
|
|
wgtInvalidate(root); // initial layout + paint
|
|
|
|
dvxRun(&ctx);
|
|
dvxShutdown(&ctx);
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Application API (`dvxApp.h`)
|
|
|
|
### Lifecycle
|
|
|
|
```c
|
|
int32_t dvxInit(AppContextT *ctx, int32_t requestedW, int32_t requestedH,
|
|
int32_t preferredBpp);
|
|
```
|
|
Initialize VESA video, input, fonts, color scheme, and cursors. Finds a mode
|
|
matching the requested resolution and bit depth (8, 15, 16, or 32). Returns
|
|
0 on success, -1 on failure.
|
|
|
|
```c
|
|
void dvxRun(AppContextT *ctx);
|
|
```
|
|
Enter the main event loop. Handles mouse movement, button clicks, keyboard
|
|
input, window management, dirty-rectangle compositing, and LFB flush.
|
|
Returns when `dvxQuit()` is called or ESC is pressed.
|
|
|
|
```c
|
|
bool dvxUpdate(AppContextT *ctx);
|
|
```
|
|
Process one iteration of the event loop: poll input, dispatch events,
|
|
composite dirty regions, and flush. Returns `true` if the GUI is still
|
|
running, `false` when exit has been requested. Use this instead of
|
|
`dvxRun()` when embedding the GUI inside an existing main loop.
|
|
|
|
```c
|
|
void dvxShutdown(AppContextT *ctx);
|
|
```
|
|
Restore text mode, release LFB mapping, and free the backbuffer.
|
|
|
|
```c
|
|
void dvxQuit(AppContextT *ctx);
|
|
```
|
|
Request exit from the main loop. `dvxRun()` returns on the next iteration.
|
|
|
|
### Windows
|
|
|
|
```c
|
|
WindowT *dvxCreateWindow(AppContextT *ctx, const char *title,
|
|
int32_t x, int32_t y, int32_t w, int32_t h,
|
|
bool resizable);
|
|
```
|
|
Create a window at screen position (`x`, `y`) with outer dimensions `w` x `h`.
|
|
If `resizable` is true, the window gets resize handles and a maximize button.
|
|
The window is raised to the top and given focus. Returns NULL on failure.
|
|
|
|
After creation, set `win->userData` and install callbacks:
|
|
|
|
| Callback | Signature | When called |
|
|
|----------|-----------|-------------|
|
|
| `onPaint` | `void (WindowT *win, RectT *dirtyArea)` | Content needs redrawing |
|
|
| `onKey` | `void (WindowT *win, int32_t key, int32_t mod)` | Key press (focused window) |
|
|
| `onMouse` | `void (WindowT *win, int32_t x, int32_t y, int32_t buttons)` | Mouse event in content area |
|
|
| `onResize` | `void (WindowT *win, int32_t newW, int32_t newH)` | Window resized |
|
|
| `onClose` | `void (WindowT *win)` | Close button double-clicked |
|
|
| `onMenu` | `void (WindowT *win, int32_t menuId)` | Menu item selected |
|
|
| `onScroll` | `void (WindowT *win, ScrollbarOrientE orient, int32_t value)` | Scrollbar moved |
|
|
|
|
Mouse/key coordinates are relative to the content area. `buttons` is a
|
|
bitmask (bit 0 = left, bit 1 = right, bit 2 = middle).
|
|
|
|
```c
|
|
void dvxDestroyWindow(AppContextT *ctx, WindowT *win);
|
|
```
|
|
Remove a window from the stack and free its resources.
|
|
|
|
```c
|
|
void dvxSetTitle(AppContextT *ctx, WindowT *win, const char *title);
|
|
```
|
|
Change the title bar text.
|
|
|
|
```c
|
|
int32_t dvxSetWindowIcon(AppContextT *ctx, WindowT *win, const char *path);
|
|
```
|
|
Load a BMP, TGA, or PNG image and assign it as the window's minimized icon.
|
|
The image is converted to the display pixel format and scaled to 64x64.
|
|
Returns 0 on success.
|
|
|
|
### Invalidation
|
|
|
|
```c
|
|
void dvxInvalidateRect(AppContextT *ctx, WindowT *win,
|
|
int32_t x, int32_t y, int32_t w, int32_t h);
|
|
void dvxInvalidateWindow(AppContextT *ctx, WindowT *win);
|
|
```
|
|
Mark a region (or the entire content area) as needing repaint. The
|
|
compositor flushes dirty rectangles to the LFB on the next frame.
|
|
|
|
### Accessors
|
|
|
|
```c
|
|
DisplayT *dvxGetDisplay(AppContextT *ctx);
|
|
const BlitOpsT *dvxGetBlitOps(const AppContextT *ctx);
|
|
const BitmapFontT *dvxGetFont(const AppContextT *ctx);
|
|
const ColorSchemeT *dvxGetColors(const AppContextT *ctx);
|
|
```
|
|
|
|
### Window properties
|
|
|
|
Set these directly on the `WindowT` struct after creation:
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `maxW` | `int32_t` | -1 | Maximum width when maximized (-1 = screen width) |
|
|
| `maxH` | `int32_t` | -1 | Maximum height when maximized (-1 = screen height) |
|
|
| `userData` | `void *` | NULL | Application data pointer, passed through to callbacks |
|
|
|
|
### Content buffer
|
|
|
|
Each window has a persistent content backbuffer:
|
|
|
|
| Field | Description |
|
|
|-------|-------------|
|
|
| `contentBuf` | Pixel data in display format |
|
|
| `contentPitch` | Bytes per scanline |
|
|
| `contentW` | Width in pixels |
|
|
| `contentH` | Height in pixels |
|
|
|
|
Paint callbacks write directly into `contentBuf`. The compositor copies
|
|
visible portions to the screen backbuffer, then flushes dirty rects to
|
|
the LFB.
|
|
|
|
---
|
|
|
|
## Menu bars
|
|
|
|
```c
|
|
MenuBarT *wmAddMenuBar(WindowT *win);
|
|
```
|
|
Add a menu bar to a window. Call `wmUpdateContentRect()` and
|
|
`wmReallocContentBuf()` after adding the menu bar (the menu bar reduces
|
|
the content area).
|
|
|
|
```c
|
|
MenuT *wmAddMenu(MenuBarT *bar, const char *label);
|
|
```
|
|
Add a top-level menu to the bar. Returns a `MenuT *` to populate with items.
|
|
|
|
```c
|
|
void wmAddMenuItem(MenuT *menu, const char *label, int32_t id);
|
|
void wmAddMenuSeparator(MenuT *menu);
|
|
```
|
|
Add items to a menu. `id` is an application-defined command passed to
|
|
`onMenu`. Up to 16 items per menu, 8 menus per bar.
|
|
|
|
---
|
|
|
|
## Scrollbars
|
|
|
|
```c
|
|
ScrollbarT *wmAddVScrollbar(WindowT *win, int32_t min, int32_t max,
|
|
int32_t pageSize);
|
|
ScrollbarT *wmAddHScrollbar(WindowT *win, int32_t min, int32_t max,
|
|
int32_t pageSize);
|
|
```
|
|
Add a scrollbar to a window. `pageSize` controls the thumb size relative to
|
|
the range. Call `wmUpdateContentRect()` and `wmReallocContentBuf()` afterward.
|
|
|
|
The `onScroll` callback fires when the user drags the thumb or clicks the
|
|
arrow buttons / trough.
|
|
|
|
Widget windows manage their own scrollbars automatically -- do not add them
|
|
manually.
|
|
|
|
---
|
|
|
|
## Video and drawing (`dvxVideo.h`, `dvxDraw.h`)
|
|
|
|
These are lower-level APIs. Application code typically only needs `packColor`.
|
|
|
|
```c
|
|
uint32_t packColor(const DisplayT *d, uint8_t r, uint8_t g, uint8_t b);
|
|
```
|
|
Pack an RGB triple into the display's pixel format.
|
|
|
|
```c
|
|
void rectFill(DisplayT *d, const BlitOpsT *ops,
|
|
int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
|
|
```
|
|
Fill a rectangle with a solid color (clipped to the display clip rect).
|
|
|
|
```c
|
|
void drawBevel(DisplayT *d, const BlitOpsT *ops,
|
|
int32_t x, int32_t y, int32_t w, int32_t h,
|
|
const BevelStyleT *style);
|
|
```
|
|
Draw a beveled frame. `BevelStyleT` specifies highlight, shadow, face colors
|
|
and border width.
|
|
|
|
```c
|
|
void drawText(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font,
|
|
int32_t x, int32_t y, const char *text,
|
|
uint32_t fg, uint32_t bg, bool opaque);
|
|
int32_t drawChar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font,
|
|
int32_t x, int32_t y, char ch,
|
|
uint32_t fg, uint32_t bg, bool opaque);
|
|
int32_t textWidth(const BitmapFontT *font, const char *text);
|
|
```
|
|
Draw text using the built-in 8-pixel-wide bitmap font. `opaque` controls
|
|
whether background pixels are drawn. `drawChar` returns the advance width.
|
|
|
|
```c
|
|
void drawHLine(DisplayT *d, const BlitOpsT *ops,
|
|
int32_t x, int32_t y, int32_t w, uint32_t color);
|
|
void drawVLine(DisplayT *d, const BlitOpsT *ops,
|
|
int32_t x, int32_t y, int32_t h, uint32_t color);
|
|
```
|
|
|
|
```c
|
|
void rectCopy(DisplayT *d, const BlitOpsT *ops,
|
|
int32_t dstX, int32_t dstY,
|
|
const uint8_t *srcBuf, int32_t srcPitch,
|
|
int32_t srcX, int32_t srcY, int32_t w, int32_t h);
|
|
```
|
|
Blit from a source buffer to the backbuffer with clipping.
|
|
|
|
```c
|
|
void setClipRect(DisplayT *d, int32_t x, int32_t y, int32_t w, int32_t h);
|
|
void resetClipRect(DisplayT *d);
|
|
```
|
|
|
|
---
|
|
|
|
## Widget system (`dvxWidget.h`)
|
|
|
|
An optional declarative layout system inspired by Amiga MUI and PC GEOS.
|
|
Widgets are arranged in a tree of VBox/HBox containers. A two-pass layout
|
|
engine (measure minimum sizes, then distribute space) handles geometry
|
|
automatically. Scrollbars appear when the window is too small for the
|
|
content.
|
|
|
|
### Initialization
|
|
|
|
```c
|
|
WidgetT *wgtInitWindow(AppContextT *ctx, WindowT *win);
|
|
```
|
|
Attach the widget system to a window. Returns the root container (a VBox
|
|
filling the content area). Installs `onPaint`, `onMouse`, `onKey`, and
|
|
`onResize` handlers on the window. Build the widget tree by passing the
|
|
returned root (or its children) as `parent` to the widget creation
|
|
functions below.
|
|
|
|
Call `wgtInvalidate(root)` after the tree is fully built to trigger the
|
|
initial layout and paint.
|
|
|
|
### Containers
|
|
|
|
```c
|
|
WidgetT *wgtVBox(WidgetT *parent); // vertical stack
|
|
WidgetT *wgtHBox(WidgetT *parent); // horizontal stack
|
|
WidgetT *wgtFrame(WidgetT *parent, const char *title); // titled border
|
|
```
|
|
Containers hold child widgets and control layout direction. `wgtFrame`
|
|
draws a styled border with a title label and lays out children vertically.
|
|
|
|
Frame styles (set `w->as.frame.style` after creation):
|
|
|
|
| Style | Description |
|
|
|-------|-------------|
|
|
| `FrameInE` | Beveled inward / sunken (default) |
|
|
| `FrameOutE` | Beveled outward / raised |
|
|
| `FrameFlatE` | Solid color line; set `w->as.frame.color` (0 = windowShadow) |
|
|
|
|
The title text is vertically centered on the top border line.
|
|
|
|
Container properties (set directly on the returned `WidgetT *`):
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `align` | `WidgetAlignE` | `AlignStartE` | Main-axis alignment when no children have weight |
|
|
| `spacing` | `int32_t` | 0 (4px) | Tagged size: gap between children |
|
|
| `padding` | `int32_t` | 0 (4px) | Tagged size: internal padding |
|
|
|
|
Alignment values:
|
|
|
|
| Value | HBox meaning | VBox meaning |
|
|
|-------|-------------|-------------|
|
|
| `AlignStartE` | left | top |
|
|
| `AlignCenterE` | center | center |
|
|
| `AlignEndE` | right | bottom |
|
|
|
|
### Widgets
|
|
|
|
```c
|
|
WidgetT *wgtLabel(WidgetT *parent, const char *text);
|
|
```
|
|
Static text label. Sized to fit its text.
|
|
|
|
```c
|
|
WidgetT *wgtButton(WidgetT *parent, const char *text);
|
|
```
|
|
Beveled push button with standard press/release behavior: the button
|
|
visually depresses on mouse-down, tracks the cursor while held, and
|
|
fires `onClick` on release if still over the button. Dragging off the
|
|
button cancels the click.
|
|
|
|
```c
|
|
WidgetT *wgtCheckbox(WidgetT *parent, const char *text);
|
|
```
|
|
Toggle checkbox. Read/write `w->as.checkbox.checked`. Set `onChange` to
|
|
be notified.
|
|
|
|
```c
|
|
WidgetT *wgtRadioGroup(WidgetT *parent);
|
|
WidgetT *wgtRadio(WidgetT *parent, const char *text);
|
|
```
|
|
Radio buttons. Create a group, then add options as children. The group
|
|
tracks the selected index in `w->as.radioGroup.selectedIdx`. Set
|
|
`onChange` on the group to be notified. Radio indices are auto-assigned.
|
|
|
|
```c
|
|
WidgetT *wgtTextInput(WidgetT *parent, int32_t maxLen);
|
|
```
|
|
Single-line text input field. Supports typing, cursor movement (arrows,
|
|
Home, End), backspace, and delete. `maxLen` is the buffer capacity.
|
|
Default weight is 100 (stretches to fill). Set `onChange` to be notified
|
|
on edits.
|
|
|
|
```c
|
|
WidgetT *wgtListBox(WidgetT *parent);
|
|
```
|
|
List box (basic -- set items with `wgtListBoxSetItems()`).
|
|
|
|
```c
|
|
WidgetT *wgtTextArea(WidgetT *parent, int32_t maxLen);
|
|
```
|
|
Multi-line text area (basic).
|
|
|
|
### Dropdown and ComboBox
|
|
|
|
```c
|
|
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);
|
|
```
|
|
Non-editable selection widget. Clicking the arrow button opens a popup
|
|
list below (or above if no room). Clicking the arrow again while the
|
|
popup is open closes it. Set `onChange` to be notified of selection
|
|
changes. The items array must remain valid for the widget's lifetime.
|
|
|
|
```c
|
|
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);
|
|
```
|
|
Editable text field with a dropdown list. The text area accepts keyboard
|
|
input (same editing keys as `wgtTextInput`). Clicking the arrow button
|
|
toggles the popup; clicking the text area focuses it for editing.
|
|
Selecting an item copies its text into the edit buffer. Default weight
|
|
is 100.
|
|
|
|
### ProgressBar and Slider
|
|
|
|
```c
|
|
WidgetT *wgtProgressBar(WidgetT *parent);
|
|
void wgtProgressBarSetValue(WidgetT *w, int32_t value);
|
|
int32_t wgtProgressBarGetValue(const WidgetT *w);
|
|
```
|
|
Horizontal progress indicator. Value is 0--100 (percentage). The filled
|
|
portion draws left-to-right with the system highlight color.
|
|
|
|
```c
|
|
WidgetT *wgtSlider(WidgetT *parent, int32_t minVal, int32_t maxVal);
|
|
void wgtSliderSetValue(WidgetT *w, int32_t value);
|
|
int32_t wgtSliderGetValue(const WidgetT *w);
|
|
```
|
|
Draggable slider/trackbar. Horizontal by default; set
|
|
`w->as.slider.vertical = true` after creation for vertical orientation.
|
|
The thumb tracks the mouse while held. Set `onChange` to be notified.
|
|
|
|
### TabControl
|
|
|
|
```c
|
|
WidgetT *wgtTabControl(WidgetT *parent);
|
|
WidgetT *wgtTabPage(WidgetT *parent, const char *title);
|
|
void wgtTabControlSetActive(WidgetT *w, int32_t idx);
|
|
int32_t wgtTabControlGetActive(const WidgetT *w);
|
|
```
|
|
Tabbed container. Create a tab control, then add pages as children.
|
|
Each page is a VBox that holds its own widget subtree. Only the active
|
|
page is visible and receives layout; inactive pages are hidden. Clicking
|
|
a tab header switches the active page.
|
|
|
|
### StatusBar and Toolbar
|
|
|
|
```c
|
|
WidgetT *wgtStatusBar(WidgetT *parent);
|
|
WidgetT *wgtToolbar(WidgetT *parent);
|
|
```
|
|
Horizontal containers with specialized chrome. StatusBar draws a sunken
|
|
panel background; Toolbar draws a raised background. Both use horizontal
|
|
layout with default spacing. Add child widgets (labels, buttons, etc.)
|
|
as with any HBox. StatusBar children with `weight > 0` stretch to fill.
|
|
|
|
### TreeView
|
|
|
|
```c
|
|
WidgetT *wgtTreeView(WidgetT *parent);
|
|
WidgetT *wgtTreeItem(WidgetT *parent, const char *text);
|
|
void wgtTreeItemSetExpanded(WidgetT *w, bool expanded);
|
|
bool wgtTreeItemIsExpanded(const WidgetT *w);
|
|
```
|
|
Hierarchical tree with expand/collapse support. Create a tree view, then
|
|
add items as children. Nest items by adding them as children of other
|
|
items. Items with children show a `[+]`/`[-]` expand box.
|
|
|
|
The tree view manages its own internal scrollbars: a vertical scrollbar
|
|
appears when expanded items exceed the visible height, and a horizontal
|
|
scrollbar appears when item text extends beyond the visible width. Both
|
|
scrollbars have arrow buttons, proportional thumbs, and page
|
|
scrolling on trough clicks.
|
|
|
|
Default weight is 100. Set `onClick` on individual tree items to handle
|
|
selection, or `onChange` to be notified of expand/collapse.
|
|
|
|
### Image
|
|
|
|
```c
|
|
WidgetT *wgtImage(WidgetT *parent, uint8_t *data,
|
|
int32_t w, int32_t h, int32_t pitch);
|
|
WidgetT *wgtImageFromFile(WidgetT *parent, const char *path);
|
|
void wgtImageSetData(WidgetT *w, uint8_t *data,
|
|
int32_t imgW, int32_t imgH, int32_t pitch);
|
|
```
|
|
Display a bitmap image. `wgtImage` takes ownership of the pixel buffer
|
|
(freed on destroy). `wgtImageFromFile` loads any format supported by
|
|
stb_image and converts to the display pixel format. Set `onClick` to
|
|
make the image clickable.
|
|
|
|
### ImageButton
|
|
|
|
```c
|
|
WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data,
|
|
int32_t w, int32_t h, int32_t pitch);
|
|
void wgtImageButtonSetData(WidgetT *w, uint8_t *data,
|
|
int32_t imgW, int32_t imgH, int32_t pitch);
|
|
```
|
|
Push button that displays an image instead of a text caption. Behaves
|
|
identically to `wgtButton` -- visually depresses on mouse-down, tracks the
|
|
cursor while held, and fires `onClick` on release if still over the button.
|
|
The image is centered on the button face with a 2px bevel border and no
|
|
extra padding. When pressed, the image shifts 1px down and right.
|
|
|
|
`wgtImageButton` takes ownership of the pixel buffer (freed on destroy).
|
|
`wgtImageButtonSetData` replaces the image data, freeing the previous buffer.
|
|
The pixel buffer must be in display pixel format (use `packColor()` and the
|
|
display's `bytesPerPixel` to prepare it).
|
|
|
|
### Canvas
|
|
|
|
```c
|
|
WidgetT *wgtCanvas(WidgetT *parent, int32_t w, int32_t h);
|
|
```
|
|
Drawable bitmap canvas with a sunken bevel border. Supports both
|
|
interactive freehand drawing (mouse strokes are Bresenham-interpolated)
|
|
and programmatic drawing from the API.
|
|
|
|
```c
|
|
void wgtCanvasClear(WidgetT *w, uint32_t color);
|
|
void wgtCanvasSetPenColor(WidgetT *w, uint32_t color);
|
|
void wgtCanvasSetPenSize(WidgetT *w, int32_t size);
|
|
int32_t wgtCanvasSave(WidgetT *w, const char *path);
|
|
int32_t wgtCanvasLoad(WidgetT *w, const char *path);
|
|
```
|
|
`wgtCanvasSave` writes the canvas to a PNG file (converting from display
|
|
pixel format to RGB). `wgtCanvasLoad` reads any image format supported by
|
|
stb_image and converts it to display pixel format.
|
|
|
|
Programmatic drawing primitives (all coordinates are in canvas space):
|
|
|
|
```c
|
|
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);
|
|
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);
|
|
```
|
|
`SetPixel`/`GetPixel` take explicit colors. `DrawLine` uses the current
|
|
pen color and pen size. `DrawRect` draws a 1px outline, `FillRect` fills
|
|
solid, and `FillCircle` fills a circle -- all using the current pen
|
|
color. All operations clip to the canvas bounds. Colors are in display
|
|
pixel format (use `packColor()` to create them).
|
|
|
|
### ANSI Terminal
|
|
|
|
```c
|
|
WidgetT *wgtAnsiTerm(WidgetT *parent, int32_t cols, int32_t rows);
|
|
```
|
|
ANSI BBS terminal emulator widget. Displays a character grid (default
|
|
80x25 if cols/rows are 0) with full ANSI escape sequence support and a
|
|
16-color CGA palette. The terminal has a 2px sunken bevel border and a
|
|
vertical scrollbar for scrollback history.
|
|
|
|
ANSI escape sequences supported:
|
|
|
|
| Sequence | Description |
|
|
|----------|-------------|
|
|
| `ESC[H` / `ESC[f` | Cursor position (CUP/HVP) |
|
|
| `ESC[A/B/C/D` | Cursor up/down/forward/back |
|
|
| `ESC[J` | Erase display (0=to end, 1=to start, 2=all) |
|
|
| `ESC[K` | Erase line (0=to end, 1=to start, 2=all) |
|
|
| `ESC[m` | SGR: colors 30-37/40-47, bright 90-97/100-107, bold(1), blink(5), reverse(7), reset(0) |
|
|
| `ESC[s` / `ESC[u` | Save / restore cursor position |
|
|
| `ESC[S` / `ESC[T` | Scroll up / down |
|
|
| `ESC[L` / `ESC[M` | Insert / delete lines |
|
|
| `ESC[?7h/l` | Enable / disable auto-wrap |
|
|
| `ESC[?25h/l` | Show / hide cursor |
|
|
|
|
Control characters: CR, LF, BS, TAB, BEL (ignored).
|
|
|
|
```c
|
|
void wgtAnsiTermWrite(WidgetT *w, const uint8_t *data, int32_t len);
|
|
```
|
|
Feed data through the ANSI parser. Use this to display `.ANS` files or
|
|
inject content without a communications link.
|
|
|
|
```c
|
|
void wgtAnsiTermClear(WidgetT *w);
|
|
```
|
|
Clear the screen, push all visible lines to scrollback, and reset the
|
|
cursor to the home position.
|
|
|
|
```c
|
|
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 communications interface. `readFn` should return bytes read
|
|
(0 if none available). `writeFn` sends bytes. Pass NULL function
|
|
pointers for a disconnected / display-only terminal.
|
|
|
|
When connected, keyboard input is translated to ANSI sequences and sent
|
|
via `writeFn` (arrows become `ESC[A`..`ESC[D`, etc.).
|
|
|
|
```c
|
|
int32_t wgtAnsiTermPoll(WidgetT *w);
|
|
```
|
|
Poll the comm interface for incoming data and process it through the
|
|
ANSI parser. Returns the number of bytes read. Call this from your
|
|
event loop or idle handler, then `wgtInvalidate()` if the return
|
|
value is nonzero.
|
|
|
|
```c
|
|
void wgtAnsiTermSetScrollback(WidgetT *w, int32_t maxLines);
|
|
```
|
|
Set the scrollback buffer size (default 500 lines). Clears any existing
|
|
scrollback. Lines scroll into the buffer when they leave the top of the
|
|
screen or when the screen is cleared (`ESC[2J` / `wgtAnsiTermClear`).
|
|
|
|
A vertical scrollbar appears automatically when there is scrollback
|
|
content. Click the arrow buttons for single-line scrolling, or the
|
|
trough for page scrolling. The view auto-follows live output unless the
|
|
user has scrolled back.
|
|
|
|
### Spacing and dividers
|
|
|
|
```c
|
|
WidgetT *wgtSpacer(WidgetT *parent);
|
|
```
|
|
Invisible spacer. Default weight is 100 -- pushes siblings apart.
|
|
|
|
```c
|
|
WidgetT *wgtHSeparator(WidgetT *parent); // horizontal line
|
|
WidgetT *wgtVSeparator(WidgetT *parent); // vertical line
|
|
```
|
|
Visual divider lines (shadow + highlight, 2px).
|
|
|
|
### Size specifications
|
|
|
|
Size fields (`minW`, `minH`, `maxW`, `maxH`, `prefW`, `prefH`, `spacing`,
|
|
`padding`) accept tagged values created with:
|
|
|
|
```c
|
|
wgtPixels(120) // 120 pixels
|
|
wgtChars(15) // 15 character widths
|
|
wgtPercent(50) // 50% of parent
|
|
```
|
|
|
|
A raw `0` means auto (use the widget's natural/computed size).
|
|
|
|
### Weight
|
|
|
|
The `weight` field controls how extra space is distributed among siblings.
|
|
When a container is larger than its children's combined minimum size, the
|
|
surplus is divided proportionally by weight.
|
|
|
|
- `weight = 0` -- fixed size, does not stretch (default for most widgets)
|
|
- `weight = 100` -- normal stretch (default for spacers and text inputs)
|
|
- Relative values work: weights of 100, 200, 100 give a 1:2:1 split
|
|
|
|
When all children have weight 0, the container's `align` property
|
|
determines where children are placed within the extra space.
|
|
|
|
### Operations
|
|
|
|
```c
|
|
void wgtSetText(WidgetT *w, const char *text);
|
|
const char *wgtGetText(const WidgetT *w);
|
|
```
|
|
Get/set text for labels, buttons, checkboxes, radios, and text inputs.
|
|
|
|
```c
|
|
void wgtSetEnabled(WidgetT *w, bool enabled);
|
|
void wgtSetVisible(WidgetT *w, bool visible);
|
|
```
|
|
Disabled widgets are drawn grayed out and ignore input. Hidden widgets
|
|
are excluded from layout.
|
|
|
|
```c
|
|
void wgtInvalidate(WidgetT *w);
|
|
```
|
|
Trigger a full relayout and repaint of the widget tree. Call after
|
|
modifying widget properties, adding/removing widgets, or changing text.
|
|
|
|
```c
|
|
WidgetT *wgtFind(WidgetT *root, const char *name);
|
|
```
|
|
Search the subtree for a widget by name. Set `w->name` (up to 31 chars)
|
|
to make a widget findable.
|
|
|
|
```c
|
|
void wgtDestroy(WidgetT *w);
|
|
```
|
|
Remove a widget and all its children from the tree and free memory.
|
|
|
|
```c
|
|
void wgtSetDebugLayout(bool enabled);
|
|
```
|
|
When enabled, draws 1px neon-colored borders around all layout containers
|
|
so their bounds are visible. Each container gets a distinct color derived
|
|
from its pointer.
|
|
|
|
### List box operations
|
|
|
|
```c
|
|
void wgtListBoxSetItems(WidgetT *w, const char **items, int32_t count);
|
|
int32_t wgtListBoxGetSelected(const WidgetT *w);
|
|
void wgtListBoxSetSelected(WidgetT *w, int32_t idx);
|
|
```
|
|
|
|
---
|
|
|
|
## Types reference (`dvxTypes.h`)
|
|
|
|
### WindowT
|
|
|
|
Core window structure. Key fields:
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `id` | `int32_t` | Unique window identifier |
|
|
| `x`, `y`, `w`, `h` | `int32_t` | Outer frame position and size |
|
|
| `contentX`, `contentY` | `int32_t` | Content area offset within frame |
|
|
| `contentW`, `contentH` | `int32_t` | Content area dimensions |
|
|
| `contentBuf` | `uint8_t *` | Pixel buffer (display format) |
|
|
| `contentPitch` | `int32_t` | Bytes per scanline in content buffer |
|
|
| `title` | `char[128]` | Title bar text |
|
|
| `visible` | `bool` | Window is shown |
|
|
| `focused` | `bool` | Window has input focus |
|
|
| `minimized` | `bool` | Window is minimized to icon |
|
|
| `maximized` | `bool` | Window is maximized |
|
|
| `resizable` | `bool` | Window has resize handles |
|
|
| `maxW`, `maxH` | `int32_t` | Max dimensions for maximize (-1 = screen) |
|
|
| `userData` | `void *` | Application data pointer |
|
|
|
|
### ColorSchemeT
|
|
|
|
All colors are pre-packed via `packColor()`:
|
|
|
|
| Field | Usage |
|
|
|-------|-------|
|
|
| `desktop` | Desktop background |
|
|
| `windowFace` | Window frame fill |
|
|
| `windowHighlight` | Bevel light edge |
|
|
| `windowShadow` | Bevel dark edge |
|
|
| `activeTitleBg/Fg` | Focused title bar |
|
|
| `inactiveTitleBg/Fg` | Unfocused title bar |
|
|
| `contentBg/Fg` | Window content area |
|
|
| `menuBg/Fg` | Menu bar and popups |
|
|
| `menuHighlightBg/Fg` | Highlighted menu item |
|
|
| `buttonFace` | Button interior |
|
|
| `scrollbarBg/Fg/Trough` | Scrollbar elements |
|
|
|
|
### BitmapFontT
|
|
|
|
Fixed-width bitmap font (8px wide, 14 or 16px tall). Glyphs are packed
|
|
1bpp, `charHeight` bytes per glyph, MSB-first.
|
|
|
|
### BevelStyleT
|
|
|
|
```c
|
|
typedef struct {
|
|
uint32_t highlight; // top/left edge color
|
|
uint32_t shadow; // bottom/right edge color
|
|
uint32_t face; // interior fill (0 = no fill)
|
|
int32_t width; // border thickness in pixels
|
|
} BevelStyleT;
|
|
```
|
|
|
|
---
|
|
|
|
## Window chrome
|
|
|
|
Windows use a Motif/GEOS-style frame:
|
|
|
|
- 4px beveled outer border with perpendicular groove breaks
|
|
- 20px title bar (dark charcoal background when focused)
|
|
- Close button on the left edge (requires double-click)
|
|
- Minimize button on the right edge (always present)
|
|
- Maximize button to the left of minimize (resizable windows only)
|
|
- Optional menu bar below the title bar (20px)
|
|
- Optional scrollbars along the right and bottom edges (16px)
|
|
|
|
Minimized windows appear as 64x64 beveled icons along the bottom of the
|
|
screen. If a window has an icon image set via `dvxSetWindowIcon()`, that
|
|
image is shown; otherwise a nearest-neighbor-scaled thumbnail of the
|
|
window's content buffer is used. Thumbnails are refreshed automatically
|
|
when the window's content changes, with updates staggered across frames
|
|
so only one icon redraws per interval. Double-click an icon to restore.
|
|
|
|
---
|
|
|
|
## Hardware requirements
|
|
|
|
- 486 or later CPU
|
|
- VESA VBE 2.0+ compatible video card with linear framebuffer support
|
|
- PS/2 mouse (or compatible mouse driver)
|
|
- DPMI host (CWSDPMI, Windows DOS box, DOSBox, 86Box)
|
|
|
|
Tested on 86Box with PCI video cards. DOSBox is a trusted reference
|
|
platform.
|