255 lines
6.5 KiB
C
255 lines
6.5 KiB
C
#define DVX_WIDGET_IMPL
|
|
// widgetClass.c -- Widget class table, API registry, and dynamic registration
|
|
//
|
|
// widgetClassTable is a stb_ds dynamic array. Widget DXEs call
|
|
// wgtRegisterClass() during wgtRegister() to append their class
|
|
// definition and receive a runtime type ID. No widget types are
|
|
// known at compile time.
|
|
//
|
|
// The API registry uses an stb_ds string hashmap for O(1) lookup.
|
|
// Each widget DXE calls wgtRegisterApi("name", &sApi) during
|
|
// wgtRegister(). App/core code calls wgtGetApi("name") to get
|
|
// the API pointer, then casts and calls through it.
|
|
|
|
#include "dvxWidgetPlugin.h"
|
|
#include "stb_ds_wrap.h"
|
|
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
|
|
// stb_ds dynamic array of class pointers. Grows on each
|
|
// wgtRegisterClass() call. Index = type ID.
|
|
const WidgetClassT **widgetClassTable = NULL;
|
|
|
|
// stb_ds string hashmap: key = widget name, value = API pointer
|
|
typedef struct {
|
|
char *key; // stb_ds string key (heap-allocated by shput)
|
|
const void *value;
|
|
} ApiMapEntryT;
|
|
|
|
static ApiMapEntryT *sApiMap = NULL;
|
|
|
|
// stb_ds string hashmap: key = widget name, value = iface + path
|
|
typedef struct {
|
|
const WgtIfaceT *iface;
|
|
char path[DVX_MAX_PATH];
|
|
int32_t pathIndex; // 1-based: 1 = first widget from this file, 2 = second, etc.
|
|
} IfaceEntryT;
|
|
|
|
typedef struct {
|
|
char *key;
|
|
IfaceEntryT value;
|
|
} IfaceMapEntryT;
|
|
|
|
static IfaceMapEntryT *sIfaceMap = NULL;
|
|
|
|
|
|
// ============================================================
|
|
// wgtGetApi
|
|
// ============================================================
|
|
//
|
|
// Look up a widget API by name. O(1) via stb_ds string hashmap.
|
|
// Returns NULL if the widget is not loaded. Callers should still
|
|
// cache the result in a static local to skip even the hash.
|
|
|
|
const void *wgtGetApi(const char *name) {
|
|
if (!name) {
|
|
return NULL;
|
|
}
|
|
|
|
int32_t idx = shgeti(sApiMap, name);
|
|
|
|
if (idx < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
return sApiMap[idx].value;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtFindByBasName
|
|
// ============================================================
|
|
//
|
|
// Scan all registered interfaces for one whose basName matches
|
|
// (case-insensitive). Returns the widget type name, or NULL.
|
|
|
|
const char *wgtFindByBasName(const char *basName) {
|
|
if (!basName || !sIfaceMap) {
|
|
return NULL;
|
|
}
|
|
|
|
for (size_t i = 0; i < shlenu(sIfaceMap); i++) {
|
|
if (sIfaceMap[i].value.iface && sIfaceMap[i].value.iface->basName) {
|
|
if (strcasecmp(sIfaceMap[i].value.iface->basName, basName) == 0) {
|
|
return sIfaceMap[i].key;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtGetIface
|
|
// ============================================================
|
|
//
|
|
// Look up a widget interface descriptor by type name.
|
|
|
|
const WgtIfaceT *wgtGetIface(const char *name) {
|
|
if (!name) {
|
|
return NULL;
|
|
}
|
|
|
|
int32_t idx = shgeti(sIfaceMap, name);
|
|
|
|
if (idx < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
return sIfaceMap[idx].value.iface;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtIfaceCount / wgtIfaceAt
|
|
// ============================================================
|
|
//
|
|
// Enumerate all registered widget interfaces.
|
|
|
|
int32_t wgtIfaceCount(void) {
|
|
return sIfaceMap ? (int32_t)shlenu(sIfaceMap) : 0;
|
|
}
|
|
|
|
|
|
const WgtIfaceT *wgtIfaceAt(int32_t idx, const char **outName) {
|
|
if (!sIfaceMap || idx < 0 || idx >= (int32_t)shlenu(sIfaceMap)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (outName) {
|
|
*outName = sIfaceMap[idx].key;
|
|
}
|
|
|
|
return sIfaceMap[idx].value.iface;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtIfaceGetPath
|
|
// ============================================================
|
|
|
|
const char *wgtIfaceGetPath(const char *name) {
|
|
if (!name || !sIfaceMap) {
|
|
return NULL;
|
|
}
|
|
|
|
int32_t idx = shgeti(sIfaceMap, name);
|
|
|
|
if (idx < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
return sIfaceMap[idx].value.path[0] ? sIfaceMap[idx].value.path : NULL;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtIfaceGetPathIndex
|
|
// ============================================================
|
|
|
|
int32_t wgtIfaceGetPathIndex(const char *name) {
|
|
if (!name || !sIfaceMap) {
|
|
return 1;
|
|
}
|
|
|
|
int32_t idx = shgeti(sIfaceMap, name);
|
|
|
|
if (idx < 0) {
|
|
return 1;
|
|
}
|
|
|
|
return sIfaceMap[idx].value.pathIndex > 0 ? sIfaceMap[idx].value.pathIndex : 1;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtIfaceSetPath
|
|
// ============================================================
|
|
|
|
void wgtIfaceSetPath(const char *name, const char *path) {
|
|
if (!name || !path || !sIfaceMap) {
|
|
return;
|
|
}
|
|
|
|
int32_t idx = shgeti(sIfaceMap, name);
|
|
|
|
if (idx >= 0) {
|
|
snprintf(sIfaceMap[idx].value.path, sizeof(sIfaceMap[idx].value.path), "%s", path);
|
|
|
|
// Count how many ifaces already have this path to assign a 1-based index
|
|
int32_t count = 0;
|
|
|
|
for (size_t i = 0; i < shlenu(sIfaceMap); i++) {
|
|
if (sIfaceMap[i].value.path[0] && strcmp(sIfaceMap[i].value.path, path) == 0) {
|
|
count++;
|
|
}
|
|
}
|
|
|
|
sIfaceMap[idx].value.pathIndex = count;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtRegisterApi
|
|
// ============================================================
|
|
//
|
|
// Register a widget's public API struct under a name. Called by
|
|
// each widget DXE during wgtRegister().
|
|
|
|
void wgtRegisterApi(const char *name, const void *api) {
|
|
if (!name || !api) {
|
|
return;
|
|
}
|
|
|
|
shput(sApiMap, name, api);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtRegisterIface
|
|
// ============================================================
|
|
//
|
|
// Register a widget's interface descriptor under its type name.
|
|
// Called by widget DXEs during wgtRegister().
|
|
|
|
void wgtRegisterIface(const char *name, const WgtIfaceT *iface) {
|
|
if (!name || !iface) {
|
|
return;
|
|
}
|
|
|
|
IfaceEntryT entry;
|
|
memset(&entry, 0, sizeof(entry));
|
|
entry.iface = iface;
|
|
shput(sIfaceMap, name, entry);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// wgtRegisterClass
|
|
// ============================================================
|
|
//
|
|
// Appends a class to the table and returns the assigned type ID.
|
|
// The ID is simply the array index.
|
|
|
|
int32_t wgtRegisterClass(const WidgetClassT *wclass) {
|
|
if (!wclass) {
|
|
return -1;
|
|
}
|
|
|
|
int32_t id = arrlen(widgetClassTable);
|
|
arrput(widgetClassTable, wclass);
|
|
return id;
|
|
}
|