| git.druid.rocks | index | militantprogrammer | astral_canvas | src/ | api/ | node.c |
src/api/node.c
#include "api/node.h"
#include "lib/id.h"
#include <stdlib.h>
#include <string.h>
static Node *g_root;
static Node **g_byId;
static unsigned g_cap;
static char *copyString(const char *s)
{
size_t n;
char *d;
if (!s)
return NULL;
n = strlen(s) + 1;
d = malloc(n);
if (!d)
return NULL;
memcpy(d, s, n);
return d;
}
static int ensureId(unsigned short id)
{
unsigned need = (unsigned)id + 1;
unsigned cap = g_cap;
Node **grown;
if (need <= g_cap)
return 0;
if (cap < 16)
cap = 16;
while (cap < need)
cap *= 2;
grown = realloc(g_byId, cap * sizeof(*grown));
if (!grown)
return -1;
memset(grown + g_cap, 0, (cap - g_cap) * sizeof(*grown));
g_byId = grown;
g_cap = cap;
return 0;
}
static void registerNode(Node *node)
{
if (!node)
return;
if (ensureId(node->widget.id) != 0)
return;
g_byId[node->widget.id] = node;
}
static void unregisterNode(Node *node)
{
if (!node || node->widget.id >= g_cap)
return;
if (g_byId[node->widget.id] == node)
g_byId[node->widget.id] = NULL;
}
int nodeGraphInit(void)
{
nodeGraphDestroy();
g_root = nodeCreate((Widget){ .id = 0, .widgetType = A_WIDGET_PAGE });
if (!g_root)
return -1;
return 0;
}
void nodeGraphDestroy(void)
{
if (g_root)
nodeDestroy(g_root);
g_root = NULL;
free(g_byId);
g_byId = NULL;
g_cap = 0;
}
Node *nodeRoot(void)
{
return g_root;
}
Node *nodeFind(unsigned short id)
{
if (!g_byId || id >= g_cap)
return NULL;
return g_byId[id];
}
Node *nodeCreate(Widget widget)
{
Node *node = calloc(1, sizeof(*node));
if (!node)
return NULL;
node->widget = widget;
registerNode(node);
if (!g_root && widget.id == 0)
g_root = node;
return node;
}
void nodeDetach(Node *node)
{
Node *parent;
if (!node || !node->parent)
return;
parent = node->parent;
if (node->prevSibling)
node->prevSibling->nextSibling = node->nextSibling;
else
parent->firstChild = node->nextSibling;
if (node->nextSibling)
node->nextSibling->prevSibling = node->prevSibling;
else
parent->lastChild = node->prevSibling;
node->parent = NULL;
node->nextSibling = NULL;
node->prevSibling = NULL;
}
int nodeAttach(Node *parent, Node *child)
{
if (!parent || !child || parent == child)
return -1;
nodeDetach(child);
child->parent = parent;
child->prevSibling = parent->lastChild;
child->nextSibling = NULL;
if (parent->lastChild)
parent->lastChild->nextSibling = child;
else
parent->firstChild = child;
parent->lastChild = child;
return 0;
}
void nodeDestroy(Node *node)
{
if (!node)
return;
while (node->firstChild)
nodeDestroy(node->firstChild);
nodeDetach(node);
unregisterNode(node);
if (node->widget.id != 0)
libFreeId(node->widget.id);
if (g_root == node)
g_root = NULL;
free(node->text);
free(node->shader);
free(node);
}
void nodeApplyShader(Node *node, const char *shader)
{
Node *child;
char *copy;
if (!node)
return;
copy = copyString(shader);
free(node->shader);
node->shader = copy;
for (child = node->firstChild; child; child = child->nextSibling)
nodeApplyShader(child, shader);
}
void nodeApplyStyle(Node *node, const Style *style)
{
Node *child;
if (!node || !style)
return;
node->style = *style;
for (child = node->firstChild; child; child = child->nextSibling)
nodeApplyStyle(child, style);
}