// demo.c — DV/X GUI demonstration application #include "dvxApp.h" #include "dvxDialog.h" #include "dvxWidget.h" #include #include #include #include #include "thirdparty/stb_image.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_VIEW_ZOOM_IN 302 #define CMD_VIEW_ZOOM_OUT 303 #define CMD_VIEW_ZOOM_FIT 304 #define CMD_VIEW_TOOLBAR 305 #define CMD_VIEW_STATUSBAR 306 #define CMD_VIEW_SIZE_SMALL 307 #define CMD_VIEW_SIZE_MED 308 #define CMD_VIEW_SIZE_LARGE 309 #define CMD_HELP_ABOUT 400 // ============================================================ // Prototypes // ============================================================ static uint8_t *loadBmpPixels(AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch); 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; // ============================================================ // loadBmpPixels — load a BMP/PNG file into display-format pixels // ============================================================ static uint8_t *loadBmpPixels(AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch) { int imgW; int imgH; int channels; uint8_t *rgb = stbi_load(path, &imgW, &imgH, &channels, 3); if (!rgb) { return NULL; } const DisplayT *d = dvxGetDisplay(ctx); int32_t bpp = d->format.bytesPerPixel; int32_t pitch = imgW * bpp; uint8_t *data = (uint8_t *)malloc(pitch * imgH); if (!data) { stbi_image_free(rgb); return NULL; } for (int32_t y = 0; y < imgH; y++) { for (int32_t x = 0; x < imgW; x++) { uint8_t *src = rgb + (y * imgW + x) * 3; uint32_t color = packColor(d, src[0], src[1], src[2]); uint8_t *dst = data + y * pitch + x * bpp; if (bpp == 1) { *dst = (uint8_t)color; } else if (bpp == 2) { *(uint16_t *)dst = (uint16_t)color; } else { *(uint32_t *)dst = color; } } } stbi_image_free(rgb); *outW = imgW; *outH = imgH; *outPitch = pitch; return data; } // ============================================================ // 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) { int32_t result = dvxMessageBox(ctx, "Exit", "Are you sure you want to exit?", MB_YESNO | MB_ICONQUESTION); if (result == ID_YES) { dvxQuit(ctx); } } } // ============================================================ // onMenuCb // ============================================================ static void onMenuCb(WindowT *win, int32_t menuId) { AppContextT *ctx = (AppContextT *)win->userData; switch (menuId) { case CMD_FILE_EXIT: if (ctx) { int32_t result = dvxMessageBox(ctx, "Exit", "Are you sure you want to exit?", MB_YESNO | MB_ICONQUESTION); if (result == ID_YES) { dvxQuit(ctx); } } break; case CMD_VIEW_TERM: setupTerminalWindow(ctx); break; case CMD_VIEW_CTRL: setupControlsWindow(ctx); break; case CMD_HELP_ABOUT: dvxMessageBox(sCtx, "About DV/X Demo", "DV/X GUI Demonstration\n\n" "A DESQview/X-style windowing system for DOS.", MB_OK | MB_ICONINFO); 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, 360, 440, 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: ListView (multi-column list) --- WidgetT *page3 = wgtTabPage(tabs, "&List"); static const ListViewColT lvCols[] = { {"Name", (int32_t)(WGT_SIZE_CHARS | 16), ListViewAlignLeftE}, {"Size", (int32_t)(WGT_SIZE_CHARS | 8), ListViewAlignRightE}, {"Type", (int32_t)(WGT_SIZE_CHARS | 12), ListViewAlignLeftE}, {"Modified", (int32_t)(WGT_SIZE_CHARS | 12), ListViewAlignLeftE} }; static const char *lvData[] = { "AUTOEXEC.BAT", "412", "Batch File", "03/15/1994", "CONFIG.SYS", "256", "System File", "03/15/1994", "COMMAND.COM", "54,645", "Application", "09/30/1993", "HIMEM.SYS", "29,136", "System Driver", "09/30/1993", "EMM386.EXE", "120,926", "Application", "09/30/1993", "MOUSE.COM", "56,408", "Application", "06/01/1994", "DOSKEY.COM", "5,883", "Application", "09/30/1993", "EDIT.COM", "413", "Application", "09/30/1993", "README.TXT", "8,192", "Text File", "01/10/1994", "DVXDEMO.EXE", "98,304", "Application", "03/15/2026" }; WidgetT *lv = wgtListView(page3); wgtListViewSetColumns(lv, lvCols, 4); wgtListViewSetData(lv, lvData, 10); wgtListViewSetSelected(lv, 0); lv->weight = 100; // --- Tab 4: Toolbar (ImageButtons + VSeparator) --- WidgetT *page4 = wgtTabPage(tabs, "Tool&bar"); WidgetT *tb = wgtToolbar(page4); int32_t imgW; int32_t imgH; int32_t imgPitch; uint8_t *newData = loadBmpPixels(ctx, "new.bmp", &imgW, &imgH, &imgPitch); if (newData) { WidgetT *btnNew = wgtImageButton(tb, newData, imgW, imgH, imgPitch); strncpy(btnNew->name, "New", MAX_WIDGET_NAME); btnNew->onClick = onToolbarClick; } uint8_t *openData = loadBmpPixels(ctx, "open.bmp", &imgW, &imgH, &imgPitch); if (openData) { WidgetT *btnOpen = wgtImageButton(tb, openData, imgW, imgH, imgPitch); strncpy(btnOpen->name, "Open", MAX_WIDGET_NAME); btnOpen->onClick = onToolbarClick; } uint8_t *saveData = loadBmpPixels(ctx, "save.bmp", &imgW, &imgH, &imgPitch); if (saveData) { WidgetT *btnSave = wgtImageButton(tb, saveData, imgW, imgH, imgPitch); strncpy(btnSave->name, "Save", MAX_WIDGET_NAME); btnSave->onClick = onToolbarClick; } wgtVSeparator(tb); WidgetT *btnHelp = wgtButton(tb, "&Help"); btnHelp->onClick = onToolbarClick; wgtLabel(page4, "ImageButtons with VSeparator."); // --- Tab 5: Media (Image, ImageFromFile) --- WidgetT *page5 = wgtTabPage(tabs, "&Media"); wgtLabel(page5, "ImageFromFile (sample.bmp):"); wgtImageFromFile(page5, "sample.bmp"); wgtHSeparator(page5); wgtLabel(page5, "Image (logo.bmp):"); WidgetT *imgRow = wgtHBox(page5); uint8_t *logoData = loadBmpPixels(ctx, "logo.bmp", &imgW, &imgH, &imgPitch); if (logoData) { wgtImage(imgRow, logoData, imgW, imgH, imgPitch); } wgtVSeparator(imgRow); wgtLabel(imgRow, "32x32 DV/X logo"); // --- Tab 6: Editor (TextArea, Canvas) --- WidgetT *page6 = wgtTabPage(tabs, "&Editor"); wgtLabel(page6, "TextArea:"); WidgetT *ta = wgtTextArea(page6, 512); ta->weight = 100; wgtSetText(ta, "Multi-line text editor.\n\nFeatures:\n- Word wrap\n- Selection\n- Copy/Paste\n- Undo (Ctrl+Z)"); wgtHSeparator(page6); wgtLabel(page6, "Canvas (draw with mouse):"); const DisplayT *d = dvxGetDisplay(ctx); WidgetT *cv = wgtCanvas(page6, 280, 80); wgtCanvasSetPenColor(cv, packColor(d, 200, 0, 0)); wgtCanvasDrawRect(cv, 5, 5, 50, 35); wgtCanvasSetPenColor(cv, packColor(d, 0, 0, 200)); wgtCanvasFillCircle(cv, 150, 40, 25); wgtCanvasSetPenColor(cv, packColor(d, 0, 150, 0)); wgtCanvasDrawLine(cv, 70, 5, 130, 70); wgtCanvasSetPenColor(cv, packColor(d, 0, 0, 0)); // 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); wmAddMenuSeparator(viewMenu); wmAddMenuCheckItem(viewMenu, "Tool&bar", CMD_VIEW_TOOLBAR, true); wmAddMenuCheckItem(viewMenu, "&Status Bar", CMD_VIEW_STATUSBAR, true); wmAddMenuSeparator(viewMenu); wmAddMenuRadioItem(viewMenu, "S&mall", CMD_VIEW_SIZE_SMALL, false); wmAddMenuRadioItem(viewMenu, "Me&dium", CMD_VIEW_SIZE_MED, true); wmAddMenuRadioItem(viewMenu, "&Large", CMD_VIEW_SIZE_LARGE, false); wmAddMenuSeparator(viewMenu); MenuT *zoomMenu = wmAddSubMenu(viewMenu, "&Zoom"); if (zoomMenu) { wmAddMenuItem(zoomMenu, "Zoom &In", CMD_VIEW_ZOOM_IN); wmAddMenuItem(zoomMenu, "Zoom &Out", CMD_VIEW_ZOOM_OUT); wmAddMenuSeparator(zoomMenu); wmAddMenuItem(zoomMenu, "&Fit to Window", CMD_VIEW_ZOOM_FIT); } } 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[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); dvxMinimizeWindow(ctx, win); } // ============================================================ // 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, "&Password:"); wgtPasswordInput(row2, 32); WidgetT *row3 = wgtHBox(frame); wgtLabel(row3, "P&hone:"); wgtMaskedInput(row3, "(###) ###-####"); 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(int argc, char **argv) { (void)argc; // Change to executable's directory so relative BMP paths work char exeDir[260]; strncpy(exeDir, argv[0], sizeof(exeDir) - 1); exeDir[sizeof(exeDir) - 1] = '\0'; char *lastSep = strrchr(exeDir, '/'); char *lastBs = strrchr(exeDir, '\\'); if (lastBs > lastSep) { lastSep = lastBs; } if (lastSep) { *lastSep = '\0'; chdir(exeDir); } 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; }