DVX_GUI/core/widgetClass.c

156 lines
4.1 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 = interface descriptor
typedef struct {
char *key;
const WgtIfaceT *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 && sIfaceMap[i].value->basName) {
if (strcasecmp(sIfaceMap[i].value->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;
}
// ============================================================
// 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;
}
shput(sIfaceMap, name, iface);
}
// ============================================================
// 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;
}