DVX_GUI/apps/dvxbasic/ide/ideToolbox.c

196 lines
5.5 KiB
C

// 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 "dvxRes.h"
#include "dvxWm.h"
#include "box/box.h"
#include "button/button.h"
#include "imageButton/imgBtn.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
// ============================================================
// Constants
// ============================================================
#define TBX_COLS 4
#define TBX_WIN_W 120
#define TBX_WIN_H 250
// ============================================================
// 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) {
dvxHideWindow(sDs->ctx, 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);
root->spacing = 0;
// 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: "icon24", "icon24-2", etc.
char iconResName[32];
char nameResName[32];
if (pathIdx <= 1) {
snprintf(iconResName, sizeof(iconResName), "icon24");
snprintf(nameResName, sizeof(nameResName), "name");
} else {
snprintf(iconResName, sizeof(iconResName), "icon24-%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);
row->spacing = 0;
}
// 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;
}