659 lines
18 KiB
C
659 lines
18 KiB
C
// demo.c — DV/X GUI demonstration application
|
|
|
|
#include "dvxApp.h"
|
|
#include "dvxWidget.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// ============================================================
|
|
// Menu command IDs
|
|
// ============================================================
|
|
|
|
#define CMD_FILE_NEW 100
|
|
#define CMD_FILE_OPEN 101
|
|
#define CMD_FILE_SAVE 102
|
|
#define CMD_FILE_EXIT 103
|
|
#define CMD_EDIT_CUT 200
|
|
#define CMD_EDIT_COPY 201
|
|
#define CMD_EDIT_PASTE 202
|
|
#define CMD_VIEW_TERM 300
|
|
#define CMD_VIEW_CTRL 301
|
|
#define CMD_HELP_ABOUT 400
|
|
|
|
// ============================================================
|
|
// Prototypes
|
|
// ============================================================
|
|
|
|
static void onCloseCb(WindowT *win);
|
|
static void onCloseMainCb(WindowT *win);
|
|
static void onMenuCb(WindowT *win, int32_t menuId);
|
|
static void onOkClick(WidgetT *w);
|
|
static void onPaintColor(WindowT *win, RectT *dirtyArea);
|
|
static void onPaintPattern(WindowT *win, RectT *dirtyArea);
|
|
static void onPaintText(WindowT *win, RectT *dirtyArea);
|
|
static void onToolbarClick(WidgetT *w);
|
|
static void setupControlsWindow(AppContextT *ctx);
|
|
static void setupMainWindow(AppContextT *ctx);
|
|
static void setupTerminalWindow(AppContextT *ctx);
|
|
static void setupWidgetDemo(AppContextT *ctx);
|
|
|
|
// ============================================================
|
|
// Globals
|
|
// ============================================================
|
|
|
|
static AppContextT *sCtx = NULL;
|
|
|
|
|
|
// ============================================================
|
|
// onCloseCb
|
|
// ============================================================
|
|
|
|
static void onCloseCb(WindowT *win) {
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
|
|
if (ctx) {
|
|
dvxDestroyWindow(ctx, win);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onCloseMainCb
|
|
// ============================================================
|
|
|
|
static void onCloseMainCb(WindowT *win) {
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
|
|
if (ctx) {
|
|
dvxQuit(ctx);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onMenuCb
|
|
// ============================================================
|
|
|
|
static void onMenuCb(WindowT *win, int32_t menuId) {
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
|
|
switch (menuId) {
|
|
case CMD_FILE_EXIT:
|
|
if (ctx) {
|
|
dvxQuit(ctx);
|
|
}
|
|
break;
|
|
|
|
case CMD_VIEW_TERM:
|
|
setupTerminalWindow(ctx);
|
|
break;
|
|
|
|
case CMD_VIEW_CTRL:
|
|
setupControlsWindow(ctx);
|
|
break;
|
|
|
|
case CMD_HELP_ABOUT:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onOkClick
|
|
// ============================================================
|
|
|
|
static void onOkClick(WidgetT *w) {
|
|
WidgetT *root = w;
|
|
|
|
while (root->parent) {
|
|
root = root->parent;
|
|
}
|
|
|
|
WidgetT *status = wgtFind(root, "status");
|
|
|
|
if (status) {
|
|
wgtSetText(status, "Button clicked!");
|
|
wgtInvalidate(status);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onPaintColor
|
|
// ============================================================
|
|
|
|
static void onPaintColor(WindowT *win, RectT *dirtyArea) {
|
|
(void)dirtyArea;
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
|
|
if (!win->contentBuf || !ctx) {
|
|
return;
|
|
}
|
|
|
|
const DisplayT *d = dvxGetDisplay(ctx);
|
|
const BlitOpsT *ops = dvxGetBlitOps(ctx);
|
|
|
|
for (int32_t y = 0; y < win->contentH; y++) {
|
|
uint8_t r = (uint8_t)((y * 255) / (win->contentH > 1 ? win->contentH - 1 : 1));
|
|
uint8_t g = (uint8_t)(100);
|
|
uint8_t b = (uint8_t)(200 - (y * 150) / (win->contentH > 1 ? win->contentH - 1 : 1));
|
|
|
|
uint32_t color = packColor(d, r, g, b);
|
|
uint8_t *row = win->contentBuf + y * win->contentPitch;
|
|
|
|
ops->spanFill(row, color, win->contentW);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onPaintPattern
|
|
// ============================================================
|
|
|
|
static void onPaintPattern(WindowT *win, RectT *dirtyArea) {
|
|
(void)dirtyArea;
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
|
|
if (!win->contentBuf || !ctx) {
|
|
return;
|
|
}
|
|
|
|
const DisplayT *d = dvxGetDisplay(ctx);
|
|
int32_t bpp = d->format.bytesPerPixel;
|
|
int32_t sq = 16;
|
|
|
|
uint32_t c1 = packColor(d, 255, 255, 255);
|
|
uint32_t c2 = packColor(d, 0, 0, 180);
|
|
|
|
for (int32_t y = 0; y < win->contentH; y++) {
|
|
for (int32_t x = 0; x < win->contentW; x++) {
|
|
uint32_t color = ((x / sq) + (y / sq)) & 1 ? c2 : c1;
|
|
uint8_t *px = win->contentBuf + y * win->contentPitch + x * bpp;
|
|
|
|
if (bpp == 1) {
|
|
*px = (uint8_t)color;
|
|
} else if (bpp == 2) {
|
|
*(uint16_t *)px = (uint16_t)color;
|
|
} else {
|
|
*(uint32_t *)px = color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onPaintText
|
|
// ============================================================
|
|
|
|
static void onPaintText(WindowT *win, RectT *dirtyArea) {
|
|
(void)dirtyArea;
|
|
AppContextT *ctx = (AppContextT *)win->userData;
|
|
|
|
if (!win->contentBuf || !ctx) {
|
|
return;
|
|
}
|
|
|
|
const DisplayT *d = dvxGetDisplay(ctx);
|
|
const BlitOpsT *ops = dvxGetBlitOps(ctx);
|
|
const BitmapFontT *font = dvxGetFont(ctx);
|
|
int32_t bpp = d->format.bytesPerPixel;
|
|
|
|
uint32_t bg = packColor(d, 255, 255, 255);
|
|
uint32_t fg = packColor(d, 0, 0, 0);
|
|
|
|
for (int32_t y = 0; y < win->contentH; y++) {
|
|
ops->spanFill(win->contentBuf + y * win->contentPitch, bg, win->contentW);
|
|
}
|
|
|
|
static const char *lines[] = {
|
|
"DV/X GUI Compositor",
|
|
"",
|
|
"A DESQview/X-style windowed GUI",
|
|
"compositor for DOS, targeting",
|
|
"DJGPP/DPMI.",
|
|
"",
|
|
"Features:",
|
|
" - VESA VBE 2.0+ LFB",
|
|
" - Dirty-rect compositing",
|
|
" - Beveled Motif-style chrome",
|
|
" - Draggable/resizable windows",
|
|
" - Menu bars with accelerators",
|
|
" - Scrollbars",
|
|
" - Widget system",
|
|
" - ANSI terminal emulator",
|
|
NULL
|
|
};
|
|
|
|
int32_t textY = 4;
|
|
|
|
for (int32_t i = 0; lines[i] != NULL; i++) {
|
|
const char *line = lines[i];
|
|
int32_t textX = 4;
|
|
|
|
for (int32_t j = 0; line[j] != '\0'; j++) {
|
|
int32_t idx = (uint8_t)line[j] - font->firstChar;
|
|
|
|
if (idx < 0 || idx >= font->numChars) {
|
|
textX += font->charWidth;
|
|
continue;
|
|
}
|
|
|
|
const uint8_t *glyph = font->glyphData + idx * font->charHeight;
|
|
|
|
for (int32_t row = 0; row < font->charHeight; row++) {
|
|
int32_t py = textY + row;
|
|
|
|
if (py >= win->contentH) {
|
|
break;
|
|
}
|
|
|
|
uint8_t bits = glyph[row];
|
|
|
|
for (int32_t col = 0; col < font->charWidth; col++) {
|
|
int32_t px = textX + col;
|
|
|
|
if (px >= win->contentW) {
|
|
break;
|
|
}
|
|
|
|
if (bits & (0x80 >> col)) {
|
|
uint8_t *dst = win->contentBuf + py * win->contentPitch + px * bpp;
|
|
|
|
if (bpp == 1) {
|
|
*dst = (uint8_t)fg;
|
|
} else if (bpp == 2) {
|
|
*(uint16_t *)dst = (uint16_t)fg;
|
|
} else {
|
|
*(uint32_t *)dst = fg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
textX += font->charWidth;
|
|
}
|
|
|
|
textY += font->charHeight + 2;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// onToolbarClick
|
|
// ============================================================
|
|
|
|
static void onToolbarClick(WidgetT *w) {
|
|
WidgetT *root = w;
|
|
|
|
while (root->parent) {
|
|
root = root->parent;
|
|
}
|
|
|
|
WidgetT *status = wgtFind(root, "advStatus");
|
|
|
|
if (status) {
|
|
wgtSetText(status, wgtGetText(w));
|
|
wgtInvalidate(status);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// setupControlsWindow — advanced widgets with tabs
|
|
// ============================================================
|
|
|
|
static const char *colorItems[] = {"Red", "Green", "Blue", "Yellow", "Cyan", "Magenta"};
|
|
static const char *sizeItems[] = {"Small", "Medium", "Large", "Extra Large"};
|
|
|
|
static void setupControlsWindow(AppContextT *ctx) {
|
|
WindowT *win = dvxCreateWindow(ctx, "Advanced Widgets", 380, 50, 320, 400, true);
|
|
|
|
if (!win) {
|
|
return;
|
|
}
|
|
|
|
win->userData = ctx;
|
|
win->onClose = onCloseCb;
|
|
|
|
WidgetT *root = wgtInitWindow(ctx, win);
|
|
|
|
// TabControl at top
|
|
WidgetT *tabs = wgtTabControl(root);
|
|
|
|
// --- Tab 1: Controls ---
|
|
WidgetT *page1 = wgtTabPage(tabs, "&Controls");
|
|
|
|
WidgetT *ddRow = wgtHBox(page1);
|
|
wgtLabel(ddRow, "Co&lor:");
|
|
WidgetT *dd = wgtDropdown(ddRow);
|
|
wgtDropdownSetItems(dd, colorItems, 6);
|
|
wgtDropdownSetSelected(dd, 0);
|
|
|
|
WidgetT *cbRow = wgtHBox(page1);
|
|
wgtLabel(cbRow, "Si&ze:");
|
|
WidgetT *cb = wgtComboBox(cbRow, 32);
|
|
wgtComboBoxSetItems(cb, sizeItems, 4);
|
|
wgtComboBoxSetSelected(cb, 1);
|
|
|
|
wgtHSeparator(page1);
|
|
|
|
wgtLabel(page1, "&Progress:");
|
|
WidgetT *pb = wgtProgressBar(page1);
|
|
wgtProgressBarSetValue(pb, 65);
|
|
|
|
wgtLabel(page1, "&Volume:");
|
|
wgtSlider(page1, 0, 100);
|
|
|
|
// --- Tab 2: Tree ---
|
|
WidgetT *page2 = wgtTabPage(tabs, "&Tree");
|
|
|
|
WidgetT *tree = wgtTreeView(page2);
|
|
WidgetT *docs = wgtTreeItem(tree, "Documents");
|
|
wgtTreeItemSetExpanded(docs, true);
|
|
wgtTreeItem(docs, "README.md");
|
|
wgtTreeItem(docs, "DESIGN.md");
|
|
WidgetT *src = wgtTreeItem(docs, "src");
|
|
wgtTreeItemSetExpanded(src, true);
|
|
wgtTreeItem(src, "main.c");
|
|
wgtTreeItem(src, "utils.c");
|
|
wgtTreeItem(src, "render.c");
|
|
WidgetT *images = wgtTreeItem(tree, "Images");
|
|
wgtTreeItem(images, "logo.png");
|
|
wgtTreeItem(images, "icon.bmp");
|
|
WidgetT *config = wgtTreeItem(tree, "Config");
|
|
wgtTreeItem(config, "settings.ini");
|
|
wgtTreeItem(config, "palette.dat");
|
|
|
|
// --- Tab 3: Toolbar ---
|
|
WidgetT *page3 = wgtTabPage(tabs, "Tool&bar");
|
|
|
|
WidgetT *tb = wgtToolbar(page3);
|
|
WidgetT *btnNew = wgtButton(tb, "&New");
|
|
WidgetT *btnOpen = wgtButton(tb, "&Open");
|
|
WidgetT *btnSave = wgtButton(tb, "&Save");
|
|
btnNew->onClick = onToolbarClick;
|
|
btnOpen->onClick = onToolbarClick;
|
|
btnSave->onClick = onToolbarClick;
|
|
|
|
wgtLabel(page3, "Toolbar with buttons above.");
|
|
|
|
// Status bar at bottom (outside tabs)
|
|
WidgetT *sb = wgtStatusBar(root);
|
|
WidgetT *sbLabel = wgtLabel(sb, "Ready");
|
|
sbLabel->weight = 100;
|
|
strncpy(sbLabel->name, "advStatus", MAX_WIDGET_NAME);
|
|
wgtLabel(sb, "Line 1, Col 1");
|
|
|
|
wgtInvalidate(root);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// setupMainWindow — info window + paint demos
|
|
// ============================================================
|
|
|
|
static void setupMainWindow(AppContextT *ctx) {
|
|
// Window 1: Text information window with menu bar
|
|
WindowT *win1 = dvxCreateWindow(ctx, "DV/X Information", 50, 40, 340, 350, true);
|
|
|
|
if (win1) {
|
|
win1->userData = ctx;
|
|
win1->onPaint = onPaintText;
|
|
win1->onClose = onCloseMainCb;
|
|
win1->onMenu = onMenuCb;
|
|
|
|
MenuBarT *bar = wmAddMenuBar(win1);
|
|
|
|
if (bar) {
|
|
MenuT *fileMenu = wmAddMenu(bar, "&File");
|
|
|
|
if (fileMenu) {
|
|
wmAddMenuItem(fileMenu, "&New", CMD_FILE_NEW);
|
|
wmAddMenuItem(fileMenu, "&Open...", CMD_FILE_OPEN);
|
|
wmAddMenuItem(fileMenu, "&Save", CMD_FILE_SAVE);
|
|
wmAddMenuSeparator(fileMenu);
|
|
wmAddMenuItem(fileMenu, "E&xit", CMD_FILE_EXIT);
|
|
}
|
|
|
|
MenuT *editMenu = wmAddMenu(bar, "&Edit");
|
|
|
|
if (editMenu) {
|
|
wmAddMenuItem(editMenu, "Cu&t", CMD_EDIT_CUT);
|
|
wmAddMenuItem(editMenu, "&Copy", CMD_EDIT_COPY);
|
|
wmAddMenuItem(editMenu, "&Paste", CMD_EDIT_PASTE);
|
|
}
|
|
|
|
MenuT *viewMenu = wmAddMenu(bar, "&View");
|
|
|
|
if (viewMenu) {
|
|
wmAddMenuItem(viewMenu, "&Terminal", CMD_VIEW_TERM);
|
|
wmAddMenuItem(viewMenu, "&Controls", CMD_VIEW_CTRL);
|
|
}
|
|
|
|
MenuT *helpMenu = wmAddMenu(bar, "&Help");
|
|
|
|
if (helpMenu) {
|
|
wmAddMenuItem(helpMenu, "&About...", CMD_HELP_ABOUT);
|
|
}
|
|
}
|
|
|
|
wmUpdateContentRect(win1);
|
|
wmReallocContentBuf(win1, &ctx->display);
|
|
|
|
RectT fullRect = {0, 0, win1->contentW, win1->contentH};
|
|
win1->onPaint(win1, &fullRect);
|
|
}
|
|
|
|
// Window 2: Color gradient
|
|
WindowT *win2 = dvxCreateWindow(ctx, "Color Gradient", 200, 100, 280, 250, true);
|
|
|
|
if (win2) {
|
|
win2->userData = ctx;
|
|
win2->onPaint = onPaintColor;
|
|
win2->onClose = onCloseCb;
|
|
|
|
RectT fullRect = {0, 0, win2->contentW, win2->contentH};
|
|
win2->onPaint(win2, &fullRect);
|
|
}
|
|
|
|
// Window 3: Checkerboard pattern with scrollbars
|
|
WindowT *win3 = dvxCreateWindow(ctx, "Pattern", 400, 150, 250, 220, true);
|
|
|
|
if (win3) {
|
|
win3->userData = ctx;
|
|
win3->onPaint = onPaintPattern;
|
|
win3->onClose = onCloseCb;
|
|
|
|
wmAddVScrollbar(win3, 0, 100, 25);
|
|
wmAddHScrollbar(win3, 0, 100, 25);
|
|
wmUpdateContentRect(win3);
|
|
wmReallocContentBuf(win3, &ctx->display);
|
|
|
|
RectT fullRect = {0, 0, win3->contentW, win3->contentH};
|
|
win3->onPaint(win3, &fullRect);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// setupTerminalWindow — ANSI terminal widget demo
|
|
// ============================================================
|
|
|
|
static void setupTerminalWindow(AppContextT *ctx) {
|
|
WindowT *win = dvxCreateWindow(ctx, "ANSI Terminal", 60, 60, 660, 420, true);
|
|
|
|
if (!win) {
|
|
return;
|
|
}
|
|
|
|
win->userData = ctx;
|
|
win->onClose = onCloseCb;
|
|
|
|
WidgetT *root = wgtInitWindow(ctx, win);
|
|
WidgetT *term = wgtAnsiTerm(root, 80, 25);
|
|
|
|
term->weight = 100;
|
|
wgtAnsiTermSetScrollback(term, 500);
|
|
|
|
// Feed some ANSI content to demonstrate the terminal
|
|
static const uint8_t ansiDemo[] =
|
|
"\x1B[2J" // clear screen
|
|
"\x1B[1;34m========================================\r\n"
|
|
" DV/X ANSI Terminal Emulator\r\n"
|
|
"========================================\x1B[0m\r\n"
|
|
"\r\n"
|
|
"\x1B[1mBold text\x1B[0m, "
|
|
"\x1B[4mUnderlined\x1B[0m, "
|
|
"\x1B[7mReverse\x1B[0m, "
|
|
"\x1B[5mBlinking\x1B[0m\r\n"
|
|
"\r\n"
|
|
"Standard colors:\r\n"
|
|
" \x1B[30m\x1B[47m Black \x1B[0m"
|
|
" \x1B[31m Red \x1B[0m"
|
|
" \x1B[32m Green \x1B[0m"
|
|
" \x1B[33m Yellow \x1B[0m"
|
|
" \x1B[34m Blue \x1B[0m"
|
|
" \x1B[35m Magenta \x1B[0m"
|
|
" \x1B[36m Cyan \x1B[0m"
|
|
" \x1B[37m White \x1B[0m\r\n"
|
|
"\r\n"
|
|
"Bright colors:\r\n"
|
|
" \x1B[1;30m\x1B[47m DkGray \x1B[0m"
|
|
" \x1B[1;31m LtRed \x1B[0m"
|
|
" \x1B[1;32m LtGreen \x1B[0m"
|
|
" \x1B[1;33m LtYellow \x1B[0m"
|
|
" \x1B[1;34m LtBlue \x1B[0m"
|
|
" \x1B[1;35m LtMagenta \x1B[0m"
|
|
" \x1B[1;36m LtCyan \x1B[0m"
|
|
" \x1B[1;37m BrWhite \x1B[0m\r\n"
|
|
"\r\n"
|
|
"Background colors:\r\n"
|
|
" \x1B[40m\x1B[37m Black \x1B[0m"
|
|
" \x1B[41m\x1B[37m Red \x1B[0m"
|
|
" \x1B[42m\x1B[30m Green \x1B[0m"
|
|
" \x1B[43m\x1B[30m Yellow \x1B[0m"
|
|
" \x1B[44m\x1B[37m Blue \x1B[0m"
|
|
" \x1B[45m\x1B[37m Magenta \x1B[0m"
|
|
" \x1B[46m\x1B[30m Cyan \x1B[0m"
|
|
" \x1B[47m\x1B[30m White \x1B[0m\r\n"
|
|
"\r\n"
|
|
"CP437 graphics: "
|
|
"\x01\x02\x03\x04\x05\x06" // smileys, hearts, diamonds, clubs, spades
|
|
" \xB0\xB1\xB2\xDB" // shade blocks
|
|
" \xC4\xC5\xB3\xDA\xBF\xC0\xD9" // box drawing
|
|
"\r\n"
|
|
"\r\n"
|
|
"\x1B[1;32mTerminal ready.\x1B[0m "
|
|
"\x1B[36m(Not connected to any host)\x1B[0m\r\n";
|
|
|
|
wgtAnsiTermWrite(term, ansiDemo, (int32_t)(sizeof(ansiDemo) - 1));
|
|
|
|
WidgetT *sb = wgtStatusBar(root);
|
|
wgtLabel(sb, "80x25 [Local]");
|
|
|
|
dvxFitWindow(ctx, win);
|
|
wgtInvalidate(root);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// setupWidgetDemo — form with accelerators
|
|
// ============================================================
|
|
|
|
static void setupWidgetDemo(AppContextT *ctx) {
|
|
WindowT *win = dvxCreateWindow(ctx, "Widget Demo", 80, 200, 280, 360, true);
|
|
|
|
if (!win) {
|
|
return;
|
|
}
|
|
|
|
win->userData = ctx;
|
|
win->onClose = onCloseCb;
|
|
|
|
WidgetT *root = wgtInitWindow(ctx, win);
|
|
|
|
// Status label at top
|
|
WidgetT *status = wgtLabel(root, "Ready.");
|
|
strncpy(status->name, "status", MAX_WIDGET_NAME);
|
|
|
|
wgtHSeparator(root);
|
|
|
|
// Frame with text input
|
|
WidgetT *frame = wgtFrame(root, "&User Input");
|
|
WidgetT *row1 = wgtHBox(frame);
|
|
wgtLabel(row1, "&Name:");
|
|
wgtTextInput(row1, 64);
|
|
|
|
WidgetT *row2 = wgtHBox(frame);
|
|
wgtLabel(row2, "A&ddress:");
|
|
wgtTextInput(row2, 64);
|
|
|
|
wgtHSeparator(root);
|
|
|
|
// Checkboxes
|
|
wgtCheckbox(root, "Enable feature &A");
|
|
wgtCheckbox(root, "Enable feature &B");
|
|
|
|
wgtHSeparator(root);
|
|
|
|
// Radio buttons
|
|
WidgetT *rg = wgtRadioGroup(root);
|
|
wgtRadio(rg, "Option &1");
|
|
wgtRadio(rg, "Option &2");
|
|
wgtRadio(rg, "Option &3");
|
|
|
|
wgtHSeparator(root);
|
|
|
|
// List box
|
|
static const char *listItems[] = {"Alpha", "Beta", "Gamma", "Delta", "Epsilon"};
|
|
WidgetT *listRow = wgtHBox(root);
|
|
wgtLabel(listRow, "&Items:");
|
|
WidgetT *lb = wgtListBox(listRow);
|
|
wgtListBoxSetItems(lb, listItems, 5);
|
|
lb->weight = 100;
|
|
|
|
wgtHSeparator(root);
|
|
|
|
// Button row at bottom
|
|
WidgetT *btnRow = wgtHBox(root);
|
|
btnRow->align = AlignEndE;
|
|
WidgetT *okBtn = wgtButton(btnRow, "&OK");
|
|
okBtn->onClick = onOkClick;
|
|
wgtButton(btnRow, "&Cancel");
|
|
|
|
wgtInvalidate(root);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// main
|
|
// ============================================================
|
|
|
|
int main(void) {
|
|
AppContextT ctx;
|
|
|
|
printf("DV/X GUI Demo\n");
|
|
printf("Initializing VESA video...\n");
|
|
|
|
if (dvxInit(&ctx, 1024, 768, 16) != 0) {
|
|
fprintf(stderr, "Failed to initialize DV/X GUI\n");
|
|
return 1;
|
|
}
|
|
|
|
sCtx = &ctx;
|
|
|
|
setupMainWindow(&ctx);
|
|
setupWidgetDemo(&ctx);
|
|
setupControlsWindow(&ctx);
|
|
setupTerminalWindow(&ctx);
|
|
|
|
dvxRun(&ctx);
|
|
|
|
dvxShutdown(&ctx);
|
|
|
|
printf("DV/X GUI Demo ended.\n");
|
|
|
|
return 0;
|
|
}
|