194 lines
5.4 KiB
C
194 lines
5.4 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 "dvxResource.h"
|
|
#include "dvxWm.h"
|
|
#include "widgetBox.h"
|
|
#include "widgetButton.h"
|
|
#include "widgetImageButton.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
|
|
// ============================================================
|
|
// 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;
|
|
}
|