// ideToolbox.c -- DVX BASIC form designer toolbox window // // A small floating window with buttons for each registered widget // type that has a basName (VB-style name). Built dynamically from // the widget interface registry. #include "ideToolbox.h" #include "dvxApp.h" #include "dvxResource.h" #include "dvxWm.h" #include "widgetBox.h" #include "widgetButton.h" #include "widgetImageButton.h" #include #include #include #include // ============================================================ // Constants // ============================================================ #define TBX_COLS 4 #define TBX_WIN_W 90 #define TBX_WIN_H 200 // ============================================================ // Per-tool entry // ============================================================ typedef struct { char typeName[DSGN_MAX_NAME]; char tooltip[64]; } TbxToolEntryT; // ============================================================ // Module state // ============================================================ static DsgnStateT *sDs = NULL; static TbxToolEntryT *sTbxTools = NULL; // stb_ds dynamic array // ============================================================ // Callbacks // ============================================================ static void onToolClick(WidgetT *w) { if (!sDs) { return; } int32_t toolIdx = (int32_t)(intptr_t)w->userData; if (toolIdx >= 0 && toolIdx < (int32_t)arrlen(sTbxTools)) { const char *typeName = sTbxTools[toolIdx].typeName; // Toggle: clicking the same tool again deselects it if (strcasecmp(sDs->activeTool, typeName) == 0) { sDs->activeTool[0] = '\0'; } else { snprintf(sDs->activeTool, DSGN_MAX_NAME, "%s", typeName); } sDs->mode = DSGN_IDLE; } } static void onTbxClose(WindowT *win) { (void)win; } // ============================================================ // tbxCreate // ============================================================ WindowT *tbxCreate(AppContextT *ctx, DsgnStateT *ds) { sDs = ds; arrsetlen(sTbxTools, 0); WindowT *win = dvxCreateWindow(ctx, "Toolbox", 0, 30, TBX_WIN_W, TBX_WIN_H, false); if (!win) { return NULL; } win->onClose = onTbxClose; WidgetT *root = wgtInitWindow(ctx, win); // Enumerate all registered widget interfaces with a basName int32_t ifaceCount = wgtIfaceCount(); int32_t col = 0; WidgetT *row = NULL; WidgetT **buttons = NULL; // stb_ds array, parallel to sTbxTools for (int32_t i = 0; i < ifaceCount; i++) { const char *wgtName = NULL; const WgtIfaceT *iface = wgtIfaceAt(i, &wgtName); if (!iface || !iface->basName || !iface->basName[0]) { continue; } // Add tool entry TbxToolEntryT entry; memset(&entry, 0, sizeof(entry)); snprintf(entry.typeName, DSGN_MAX_NAME, "%s", iface->basName); // Load icon data and tooltip from the .wgt file resources uint8_t *iconData = NULL; int32_t iconW = 0; int32_t iconH = 0; int32_t iconPitch = 0; const char *wgtPath = wgtIfaceGetPath(wgtName); int32_t pathIdx = wgtIfaceGetPathIndex(wgtName); if (wgtPath) { // Build suffixed resource names: "icon16", "icon16-2", etc. char iconResName[32]; char nameResName[32]; if (pathIdx <= 1) { snprintf(iconResName, sizeof(iconResName), "icon16"); snprintf(nameResName, sizeof(nameResName), "name"); } else { snprintf(iconResName, sizeof(iconResName), "icon16-%d", (int)pathIdx); snprintf(nameResName, sizeof(nameResName), "name-%d", (int)pathIdx); } iconData = dvxResLoadIcon(ctx, wgtPath, iconResName, &iconW, &iconH, &iconPitch); dvxResLoadText(wgtPath, nameResName, entry.tooltip, sizeof(entry.tooltip)); } if (!entry.tooltip[0]) { snprintf(entry.tooltip, sizeof(entry.tooltip), "%s", iface->basName); } arrput(sTbxTools, entry); int32_t toolIdx = (int32_t)arrlen(sTbxTools) - 1; // Start a new row every TBX_COLS buttons if (col == 0 || !row) { row = wgtHBox(root); } // Create button in the current row WidgetT *btn = NULL; if (iconData) { btn = wgtImageButton(row, iconData, iconW, iconH, iconPitch); } else { btn = wgtButton(row, iface->basName); } btn->onClick = onToolClick; btn->userData = (void *)(intptr_t)toolIdx; arrput(buttons, btn); col = (col + 1) % TBX_COLS; // Yield to keep the UI responsive while loading icons dvxUpdate(ctx); } // Set tooltips after array is finalized (arrput can reallocate) int32_t btnCount = (int32_t)arrlen(buttons); for (int32_t i = 0; i < btnCount; i++) { wgtSetTooltip(buttons[i], sTbxTools[i].tooltip); } arrfree(buttons); dvxFitWindow(ctx, win); return win; } // ============================================================ // tbxDestroy // ============================================================ void tbxDestroy(AppContextT *ctx, WindowT *win) { if (win) { dvxDestroyWindow(ctx, win); } arrfree(sTbxTools); sTbxTools = NULL; sDs = NULL; }