inital nodes and props

This commit is contained in:
chrisbell committed 2026-11-02 19:42:48 -06:00
1 parent 98f798ad45
commit 5dad34f2e3
12 files changed
+1107 -9

No files matched your search

+30
View File
@@ -1,4 +1,5 @@
#include "internal.h"
#include "regolith.h"
#include <stdarg.h>
#include <stdio.h>
@@ -102,6 +103,11 @@ rg_context *rg_create(const rg_config *config) {
ctx->viewport_h = cfg.viewport_h;
ctx->display_scale = cfg.display_scale;
if(rg__nodes_init(ctx) != RG_OK) {
rg_destroy(ctx);
return NULL;
}
rg__log(ctx, RG_LOG_DEBUG, "clay minimum memory: %zu bytes",
rg__clay_min_memory());
rg__log(ctx, RG_LOG_INFO, "context created (%dx%d @ %.2fx)",
@@ -116,7 +122,31 @@ void rg_destroy(rg_context *ctx) {
if (!ctx)
return;
rg__lua_close(ctx);
rg__nodes_free(ctx);
rg__log(ctx, RG_LOG_INFO, "context destroyed");
a = ctx->alloc;
a.free(ctx, sizeof *ctx, a.user);
}
void *rg__alloc(rg_context *ctx, size_t size) {
return ctx->alloc.alloc(size, ctx->alloc.user);
}
void *rg__zalloc(rg_context *ctx, size_t size) {
void *p = rg__alloc(ctx, size);
if (p)
memset(p, 0, size);
return p;
}
void *rg__realloc(rg_context *ctx, void *ptr, size_t old_size,
size_t new_size) {
if (!ptr)
return rg__alloc(ctx, new_size);
return ctx->alloc.realloc(ptr, old_size, new_size, ctx->alloc.user);
}
void rg__free(rg_context *ctx, void *ptr, size_t size) {
if (ptr)
ctx->alloc.free(ptr, size, ctx->alloc.user);
}
+74 -8
View File
@@ -1,33 +1,99 @@
#ifndef RG_INTERNAL_H
#define RG_INTERNAL_H
#include "regolith.h"
#if defined(__GNUC__)
#define RG_PRINTF(f, a) __attribute__((format(printf, f, a)))
#define RG_PRINTF(f, a) __attribute__((format(printf, f, a)))
#else
#define RG_PRINTF(f, a)
#define RG_PRINTF(f, a)
#endif
#define RG_NIL 0xFFFFFFFFu
enum { RG_PF_INHERIT = 1, RG_PF_LAYOUT = 2, RG_PF_ANIMATE = 4 };
enum { RG_TF_FOCUSABLE = 1, RG_TF_TEXT = 2 };
#define RG_V_BOOL(v) {RG_VAL_BOOL, (v), {0, 0, 0, 0}, NULL}
#define RG_V_ENUM(v) {RG_VAL_ENUM, (v), {0, 0, 0, 0}, NULL}
#define RG_V_FLOAT(v) {RG_VAL_FLOAT, 0, {(v), 0, 0, 0}, NULL}
#define RG_V_COLOR(r, g, b, a) {RG_VAL_COLOR, 0, {(r), (g), (b), (a)}, NULL}
#define RG_V_VEC4(a, b, c, d) {RG_VAL_VEC4, 0, {(a), (b), (c), (d)}, NULL}
#define RG_V_SIZE(mode, v) {RG_VAL_SIZE, (mode), {(v), 0, 0, 0}, NULL}
#define RG_V_STRING(s) {RG_VAL_STRING, 0, {0, 0, 0, 0}, (s)}
typedef struct rg_override {
int32_t prop;
rg_value value;
} rg_override;
typedef struct rg_prop_info {
const char *name;
int32_t type;
uint32_t flags;
rg_value def;
} rg_prop_info;
typedef struct rg_type_info {
const char *name;
uint32_t flags;
const rg_override *defaults;
int32_t default_count;
} rg_type_info;
typedef struct rg_node_data {
uint32_t index;
uint32_t generation;
uint32_t alive;
uint32_t parent, first_child, last_child, prev, next;
uint32_t next_free;
int32_t type;
rg_override *ov;
uint32_t ov_count, ov_cap;
} rg_node_data;
struct lua_State;
struct rg_context {
rg_allocator alloc;
rg_log_fn log;
void* log_user;
void *log_user;
int32_t log_level;
int32_t viewport_w;
int32_t viewport_h;
float display_scale;
char last_error[256];
struct lua_State* L;
struct lua_State *L;
rg_node_data **chunks;
uint32_t chunk_count;
uint32_t chunk_cap;
uint32_t slot_count;
uint32_t free_head;
uint32_t node_count;
rg_node root;
};
void rg__log(rg_context* ctx, int32_t level, const char* fmt, ...) RG_PRINTF(3, 4);
int rg__fail(rg_context* ctx, int code, const char* fmt, ...) RG_PRINTF(3, 4);
void rg__log(rg_context *ctx, int32_t level, const char *fmt, ...)
RG_PRINTF(3, 4);
int rg__fail(rg_context *ctx, int code, const char *fmt, ...) RG_PRINTF(3, 4);
void *rg__alloc(rg_context *ctx, size_t size);
void *rg__zalloc(rg_context *ctx, size_t size);
void *rg__realloc(rg_context *ctx, void *ptr, size_t old_size, size_t new_size);
void rg__free(rg_context *ctx, void *ptr, size_t size);
int rg__nodes_init(rg_context *ctx);
void rg__nodes_free(rg_context *ctx);
rg_node rg__node_create(rg_context *ctx, int32_t type);
rg_node_data *rg__node_resolve(const rg_context *ctx, rg_node node);
const rg_prop_info *rg__prop_info(int32_t prop);
const rg_type_info *rg__type_info(int32_t type);
const rg_value *rg__default_value(int32_t type, int32_t prop);
void rg__overrides_free(rg_context *ctx, rg_node_data *n);
size_t rg__clay_min_memory(void);
void rg__lua_close(rg_context* ctx);
void rg__lua_close(rg_context *ctx);
#endif
+276
View File
@@ -0,0 +1,276 @@
#include "internal.h"
#define CHUNK_SHIFT 8
#define CHUNK_SIZE (1u << CHUNK_SHIFT)
#define CHUNK_MASK (CHUNK_SIZE - 1u)
static rg_node_data *slot_at(const rg_context *ctx, uint32_t idx) {
return &ctx->chunks[idx >> CHUNK_SHIFT][idx & CHUNK_MASK];
}
static rg_node make_handle(const rg_node_data *n) {
return ((rg_node)n->generation << 32) | (rg_node)n->index;
}
static rg_node handle_of(const rg_context *ctx, uint32_t idx) {
return idx == RG_NIL ? RG_NODE_NONE : make_handle(slot_at(ctx, idx));
}
rg_node_data *rg__node_resolve(const rg_context *ctx, rg_node h) {
uint32_t idx = (uint32_t)(h & 0xFFFFFFFFu);
uint32_t gen = (uint32_t)(h >> 32);
rg_node_data *n;
if (h == RG_NODE_NONE || idx >= ctx->slot_count)
return NULL;
n = slot_at(ctx, idx);
if (!n->alive || n->generation != gen)
return NULL;
return n;
}
static int grow_chunks(rg_context *ctx) {
rg_node_data *chunk;
if (ctx->chunk_count == ctx->chunk_cap) {
uint32_t cap = ctx->chunk_cap ? ctx->chunk_cap * 2 : 4;
rg_node_data **arr = rg__realloc(
ctx, ctx->chunks, ctx->chunk_cap * sizeof *arr, cap * sizeof *arr);
if (!arr)
return RG_ERR_NO_MEMORY;
ctx->chunks = arr;
ctx->chunk_cap = cap;
}
chunk = rg__zalloc(ctx, CHUNK_SIZE * sizeof *chunk);
if (!chunk)
return RG_ERR_NO_MEMORY;
ctx->chunks[ctx->chunk_count++] = chunk;
return RG_OK;
}
static rg_node_data *slot_alloc(rg_context *ctx) {
rg_node_data *n;
uint32_t idx;
if (ctx->free_head != RG_NIL) {
idx = ctx->free_head;
n = slot_at(ctx, idx);
ctx->free_head = n->next_free;
} else {
idx = ctx->slot_count;
if ((idx >> CHUNK_SHIFT) == ctx->chunk_count && grow_chunks(ctx) != RG_OK)
return NULL;
n = slot_at(ctx, idx);
ctx->slot_count++;
}
n->index = idx;
if (n->generation == 0)
n->generation = 1;
n->alive = 1;
n->parent = n->first_child = n->last_child = RG_NIL;
n->prev = n->next = n->next_free = RG_NIL;
n->ov = NULL;
n->ov_count = n->ov_cap = 0;
ctx->node_count++;
return n;
}
static void release_slot(rg_context *ctx, rg_node_data *n) {
rg__log(ctx, RG_LOG_TRACE, "node destroyed: %s (slot %u)",
rg_type_name(n->type), (unsigned)n->index);
rg__overrides_free(ctx, n);
n->alive = 0;
if (++n->generation == 0)
n->generation = 1;
n->next_free = ctx->free_head;
ctx->free_head = n->index;
ctx->node_count--;
}
static void unlink_node(rg_context *ctx, rg_node_data *n) {
rg_node_data *p;
if (n->parent == RG_NIL)
return;
p = slot_at(ctx, n->parent);
if (n->prev != RG_NIL)
slot_at(ctx, n->prev)->next = n->next;
else
p->first_child = n->next;
if (n->next != RG_NIL)
slot_at(ctx, n->next)->prev = n->prev;
else
p->last_child = n->prev;
n->parent = n->prev = n->next = RG_NIL;
}
static void destroy_subtree(rg_context *ctx, rg_node_data *top) {
uint32_t top_idx = top->index;
uint32_t cur = top_idx;
for (;;) {
rg_node_data *n = slot_at(ctx, cur);
uint32_t parent;
if (n->first_child != RG_NIL) {
cur = n->first_child;
continue;
}
parent = n->parent;
unlink_node(ctx, n);
release_slot(ctx, n);
if (cur == top_idx)
break;
cur = parent;
}
}
static int is_self_or_ancestor(const rg_context *ctx, const rg_node_data *anc,
const rg_node_data *n) {
while (n) {
if (n == anc)
return 1;
n = n->parent == RG_NIL ? NULL : slot_at(ctx, n->parent);
}
return 0;
}
rg_node rg__node_create(rg_context *ctx, int32_t type) {
rg_node_data *n = slot_alloc(ctx);
if (!n) {
rg__fail(ctx, RG_ERR_NO_MEMORY, "node allocation failed");
return RG_NODE_NONE;
}
n->type = type;
rg__log(ctx, RG_LOG_TRACE, "node created: %s (slot %u)", rg_type_name(type),
(unsigned)n->index);
return make_handle(n);
}
int rg__nodes_init(rg_context *ctx) {
ctx->free_head = RG_NIL;
ctx->root = rg__node_create(ctx, RG_NODE_ROOT);
return ctx->root == RG_NODE_NONE ? RG_ERR_NO_MEMORY : RG_OK;
}
void rg__nodes_free(rg_context *ctx) {
uint32_t i;
for (i = 0; i < ctx->slot_count; i++) {
rg_node_data *n = slot_at(ctx, i);
if (n->alive)
rg__overrides_free(ctx, n);
}
for (i = 0; i < ctx->chunk_count; i++)
rg__free(ctx, ctx->chunks[i], CHUNK_SIZE * sizeof(rg_node_data));
rg__free(ctx, ctx->chunks, ctx->chunk_cap * sizeof *ctx->chunks);
ctx->chunks = NULL;
ctx->chunk_count = ctx->chunk_cap = ctx->slot_count = ctx->node_count = 0;
ctx->root = RG_NODE_NONE;
}
rg_node rg_root(const rg_context *ctx) { return ctx->root; }
rg_node rg_node_create(rg_context *ctx, int32_t type) {
if (type <= RG_NODE_ROOT || type >= RG_NODE_TYPE_COUNT) {
rg__fail(ctx, RG_ERR_TYPE, "cannot create node of type %d", (int)type);
return RG_NODE_NONE;
}
return rg__node_create(ctx, type);
}
void rg_node_destroy(rg_context *ctx, rg_node node) {
rg_node_data *n = rg__node_resolve(ctx, node);
if (!n) {
rg__log(ctx, RG_LOG_WARN, "destroy of a stale or invalid handle ignored");
return;
}
if (node == ctx->root) {
rg__log(ctx, RG_LOG_WARN, "the root node cannot be destroyed");
return;
}
unlink_node(ctx, n);
destroy_subtree(ctx, n);
}
int rg_node_valid(const rg_context *ctx, rg_node node) {
return rg__node_resolve(ctx, node) != NULL;
}
int32_t rg_node_type(const rg_context *ctx, rg_node node) {
rg_node_data *n = rg__node_resolve(ctx, node);
return n ? n->type : -1;
}
int rg_node_insert_before(rg_context *ctx, rg_node parent, rg_node child,
rg_node ref) {
rg_node_data *p = rg__node_resolve(ctx, parent);
rg_node_data *c = rg__node_resolve(ctx, child);
rg_node_data *r = NULL;
if (!p || !c)
return rg__fail(ctx, RG_ERR_HANDLE, "stale or invalid handle");
if (child == ctx->root)
return rg__fail(ctx, RG_ERR_STATE, "the root cannot be a child");
if (ref != RG_NODE_NONE) {
r = rg__node_resolve(ctx, ref);
if (!r)
return rg__fail(ctx, RG_ERR_HANDLE, "stale or invalid reference handle");
if (r == c || r->parent != p->index)
return rg__fail(ctx, RG_ERR_STATE,
"reference is not a child of the parent");
}
if (is_self_or_ancestor(ctx, c, p))
return rg__fail(ctx, RG_ERR_STATE, "insert would create a cycle");
unlink_node(ctx, c);
c->parent = p->index;
if (r) {
c->next = r->index;
c->prev = r->prev;
if (r->prev != RG_NIL)
slot_at(ctx, r->prev)->next = c->index;
else
p->first_child = c->index;
r->prev = c->index;
} else {
c->prev = p->last_child;
if (p->last_child != RG_NIL)
slot_at(ctx, p->last_child)->next = c->index;
else
p->first_child = c->index;
p->last_child = c->index;
}
return RG_OK;
}
int rg_node_append(rg_context *ctx, rg_node parent, rg_node child) {
return rg_node_insert_before(ctx, parent, child, RG_NODE_NONE);
}
int rg_node_detach(rg_context *ctx, rg_node node) {
rg_node_data *n = rg__node_resolve(ctx, node);
if (!n)
return rg__fail(ctx, RG_ERR_HANDLE, "stale or invalid handle");
unlink_node(ctx, n);
return RG_OK;
}
rg_node rg_node_parent(const rg_context *ctx, rg_node node) {
rg_node_data *n = rg__node_resolve(ctx, node);
return n ? handle_of(ctx, n->parent) : RG_NODE_NONE;
}
rg_node rg_node_first_child(const rg_context *ctx, rg_node node) {
rg_node_data *n = rg__node_resolve(ctx, node);
return n ? handle_of(ctx, n->first_child) : RG_NODE_NONE;
}
rg_node rg_node_next_sibling(const rg_context *ctx, rg_node node) {
rg_node_data *n = rg__node_resolve(ctx, node);
return n ? handle_of(ctx, n->next) : RG_NODE_NONE;
}
+251
View File
@@ -0,0 +1,251 @@
#include "internal.h"
#include <string.h>
static const rg_prop_info prop_table[RG_PROP_COUNT] = {
[RG_PROP_DIRECTION] = {"direction", RG_VAL_ENUM, RG_PF_LAYOUT,
RG_V_ENUM(RG_DIR_ROW)},
[RG_PROP_WIDTH] = {"width", RG_VAL_SIZE, RG_PF_LAYOUT | RG_PF_ANIMATE,
RG_V_SIZE(RG_SIZE_FIT, 0)},
[RG_PROP_HEIGHT] = {"height", RG_VAL_SIZE, RG_PF_LAYOUT | RG_PF_ANIMATE,
RG_V_SIZE(RG_SIZE_FIT, 0)},
[RG_PROP_PADDING] = {"padding", RG_VAL_VEC4, RG_PF_LAYOUT | RG_PF_ANIMATE,
RG_V_VEC4(0, 0, 0, 0)},
[RG_PROP_GAP] = {"gap", RG_VAL_FLOAT, RG_PF_LAYOUT | RG_PF_ANIMATE,
RG_V_FLOAT(0)},
[RG_PROP_ALIGN_X] = {"align_x", RG_VAL_ENUM, RG_PF_LAYOUT,
RG_V_ENUM(RG_ALIGN_START)},
[RG_PROP_ALIGN_Y] = {"align_y", RG_VAL_ENUM, RG_PF_LAYOUT,
RG_V_ENUM(RG_ALIGN_START)},
[RG_PROP_BACKGROUND] = {"background", RG_VAL_COLOR, RG_PF_ANIMATE,
RG_V_COLOR(0, 0, 0, 0)},
[RG_PROP_BORDER_COLOR] = {"border_color", RG_VAL_COLOR, RG_PF_ANIMATE,
RG_V_COLOR(0, 0, 0, 0)},
[RG_PROP_BORDER_WIDTH] = {"border_width", RG_VAL_VEC4,
RG_PF_LAYOUT | RG_PF_ANIMATE,
RG_V_VEC4(0, 0, 0, 0)},
[RG_PROP_CORNER_RADIUS] = {"corner_radius", RG_VAL_VEC4, RG_PF_ANIMATE,
RG_V_VEC4(0, 0, 0, 0)},
[RG_PROP_OPACITY] = {"opacity", RG_VAL_FLOAT, RG_PF_ANIMATE, RG_V_FLOAT(1)},
[RG_PROP_VISIBLE] = {"visible", RG_VAL_BOOL, RG_PF_LAYOUT, RG_V_BOOL(1)},
[RG_PROP_TEXT] = {"text", RG_VAL_STRING, RG_PF_LAYOUT, RG_V_STRING("")},
[RG_PROP_FONT] = {"font", RG_VAL_STRING, RG_PF_LAYOUT | RG_PF_INHERIT,
RG_V_STRING("")},
[RG_PROP_FONT_SIZE] = {"font_size", RG_VAL_FLOAT,
RG_PF_LAYOUT | RG_PF_INHERIT, RG_V_FLOAT(16)},
[RG_PROP_COLOR] = {"color", RG_VAL_COLOR, RG_PF_INHERIT | RG_PF_ANIMATE,
RG_V_COLOR(1, 1, 1, 1)},
};
static const char *val_type_name(int32_t t) {
static const char *names[] = {"none", "bool", "int", "float", "enum",
"color", "size", "vec4", "string"};
return t >= 0 && t <= RG_VAL_STRING ? names[t] : "invalid";
}
static void value_init(rg_value *v, int32_t type) {
memset(v, 0, sizeof *v);
v->type = type;
}
const rg_prop_info *rg__prop_info(int32_t prop) {
if (prop < 0 || prop >= RG_PROP_COUNT)
return NULL;
return &prop_table[prop];
}
int32_t rg_prop_find(const char *name) {
int32_t i;
if (!name)
return -1;
for (i = 0; i < RG_PROP_COUNT; i++)
if (strcmp(prop_table[i].name, name) == 0)
return i;
return -1;
}
const char *rg_prop_name(int32_t prop) {
const rg_prop_info *info = rg__prop_info(prop);
return info ? info->name : NULL;
}
int32_t rg_prop_type(int32_t prop) {
const rg_prop_info *info = rg__prop_info(prop);
return info ? info->type : RG_VAL_NONE;
}
const rg_value *rg__default_value(int32_t type, int32_t prop) {
const rg_type_info *t = rg__type_info(type);
int32_t i;
if (t)
for (i = 0; i < t->default_count; i++)
if (t->defaults[i].prop == prop)
return &t->defaults[i].value;
return &prop_table[prop].def;
}
static char *dup_string(rg_context *ctx, const char *s) {
size_t len = strlen(s) + 1;
char *p = rg__alloc(ctx, len);
if (p)
memcpy(p, s, len);
return p;
}
static void drop_value(rg_context *ctx, rg_value *v) {
if (v->type == RG_VAL_STRING && v->s) {
rg__free(ctx, (void *)v->s, strlen(v->s) + 1);
v->s = NULL;
}
}
void rg__overrides_free(rg_context *ctx, rg_node_data *n) {
uint32_t i;
for (i = 0; i < n->ov_count; i++)
drop_value(ctx, &n->ov[i].value);
rg__free(ctx, n->ov, n->ov_cap * sizeof *n->ov);
n->ov = NULL;
n->ov_count = n->ov_cap = 0;
}
static rg_override *find_override(const rg_node_data *n, int32_t prop) {
uint32_t i;
for (i = 0; i < n->ov_count; i++)
if (n->ov[i].prop == prop)
return &n->ov[i];
return NULL;
}
int rg_set(rg_context *ctx, rg_node node, int32_t prop, const rg_value *value) {
rg_node_data *n = rg__node_resolve(ctx, node);
const rg_prop_info *info = rg__prop_info(prop);
rg_override *o;
rg_value v;
if (!n)
return rg__fail(ctx, RG_ERR_HANDLE, "set: stale or invalid handle");
if (!info)
return rg__fail(ctx, RG_ERR_PROP, "set: unknown property %d", (int)prop);
if (!value || value->type != info->type)
return rg__fail(ctx, RG_ERR_TYPE, "set: property '%s' expects %s",
info->name, val_type_name(info->type));
if (value->type == RG_VAL_STRING && !value->s)
return rg__fail(ctx, RG_ERR_TYPE, "set: property '%s' got a null string",
info->name);
if (value->type == RG_VAL_SIZE &&
(value->i < RG_SIZE_FIT || value->i > RG_SIZE_PERCENT))
return rg__fail(ctx, RG_ERR_TYPE,
"set: property '%s' got an invalid size mode", info->name);
v = *value;
if (v.type == RG_VAL_STRING) {
v.s = dup_string(ctx, value->s);
if (!v.s)
return rg__fail(ctx, RG_ERR_NO_MEMORY, "set: string allocation failed");
}
o = find_override(n, prop);
if (o) {
drop_value(ctx, &o->value);
o->value = v;
} else {
if (n->ov_count == n->ov_cap) {
uint32_t cap = n->ov_cap ? n->ov_cap * 2 : 4;
rg_override *arr =
rg__realloc(ctx, n->ov, n->ov_cap * sizeof *arr, cap * sizeof *arr);
if (!arr) {
drop_value(ctx, &v);
return rg__fail(ctx, RG_ERR_NO_MEMORY,
"set: override allocation failed");
}
n->ov = arr;
n->ov_cap = cap;
}
n->ov[n->ov_count].prop = prop;
n->ov[n->ov_count].value = v;
n->ov_count++;
}
rg__log(ctx, RG_LOG_TRACE, "set %s on %s", info->name, rg_type_name(n->type));
return RG_OK;
}
int rg_get(rg_context *ctx, rg_node node, int32_t prop, rg_value *out) {
rg_node_data *n = rg__node_resolve(ctx, node);
const rg_override *o;
if (!n)
return rg__fail(ctx, RG_ERR_HANDLE, "get: stale or invalid handle");
if (!rg__prop_info(prop))
return rg__fail(ctx, RG_ERR_PROP, "get: unknown property %d", (int)prop);
if (!out)
return rg__fail(ctx, RG_ERR_STATE, "get: null output");
o = find_override(n, prop);
*out = o ? o->value : *rg__default_value(n->type, prop);
return RG_OK;
}
int rg_unset(rg_context *ctx, rg_node node, int32_t prop) {
rg_node_data *n = rg__node_resolve(ctx, node);
rg_override *o;
if (!n)
return rg__fail(ctx, RG_ERR_HANDLE, "unset: stale or invalid handle");
if (!rg__prop_info(prop))
return rg__fail(ctx, RG_ERR_PROP, "unset: unknown property %d", (int)prop);
o = find_override(n, prop);
if (o) {
drop_value(ctx, &o->value);
*o = n->ov[--n->ov_count];
}
return RG_OK;
}
int rg_set_int(rg_context *ctx, rg_node node, int32_t prop, int32_t v) {
const rg_prop_info *info = rg__prop_info(prop);
rg_value val;
if (!info)
return rg__fail(ctx, RG_ERR_PROP, "set: unknown property %d", (int)prop);
if (info->type != RG_VAL_BOOL && info->type != RG_VAL_INT &&
info->type != RG_VAL_ENUM)
return rg__fail(ctx, RG_ERR_TYPE,
"set: property '%s' is not an integer type", info->name);
value_init(&val, info->type);
val.i = v;
return rg_set(ctx, node, prop, &val);
}
int rg_set_float(rg_context *ctx, rg_node node, int32_t prop, float v) {
rg_value val;
value_init(&val, RG_VAL_FLOAT);
val.f[0] = v;
return rg_set(ctx, node, prop, &val);
}
int rg_set_string(rg_context *ctx, rg_node node, int32_t prop, const char *v) {
rg_value val;
value_init(&val, RG_VAL_STRING);
val.s = v;
return rg_set(ctx, node, prop, &val);
}
int rg_set_color(rg_context *ctx, rg_node node, int32_t prop, float r, float g,
float b, float a) {
rg_value val;
value_init(&val, RG_VAL_COLOR);
val.f[0] = r;
val.f[1] = g;
val.f[2] = b;
val.f[3] = a;
return rg_set(ctx, node, prop, &val);
}
+62
View File
@@ -0,0 +1,62 @@
#include "internal.h"
#include <string.h>
#define COUNT(a) ((int32_t)(sizeof(a) / sizeof((a)[0])))
static const rg_override root_defaults[] = {
{RG_PROP_WIDTH, RG_V_SIZE(RG_SIZE_GROW, 0)},
{RG_PROP_HEIGHT, RG_V_SIZE(RG_SIZE_GROW, 0)},
};
static const rg_override hbox_defaults[] = {
{RG_PROP_DIRECTION, RG_V_ENUM(RG_DIR_ROW)},
};
static const rg_override vbox_defaults[] = {
{RG_PROP_DIRECTION, RG_V_ENUM(RG_DIR_COLUMN)},
};
static const rg_override panel_defaults[] = {
{RG_PROP_PADDING, RG_V_VEC4(8, 8, 8, 8)},
{RG_PROP_BACKGROUND, RG_V_COLOR(0.15f, 0.15f, 0.18f, 1.0f)},
};
static const rg_override button_defaults[] = {
{RG_PROP_PADDING, RG_V_VEC4(8, 16, 8, 16)},
{RG_PROP_BACKGROUND, RG_V_COLOR(0.25f, 0.25f, 0.30f, 1.0f)},
{RG_PROP_CORNER_RADIUS, RG_V_VEC4(4, 4, 4, 4)},
};
static const rg_type_info type_table[RG_NODE_TYPE_COUNT] = {
[RG_NODE_ROOT] = {"Root", 0, root_defaults, COUNT(root_defaults)},
[RG_NODE_BOX] = {"Box", 0, NULL, 0},
[RG_NODE_HBOX] = {"HBox", 0, hbox_defaults, COUNT(hbox_defaults)},
[RG_NODE_VBOX] = {"VBox", 0, vbox_defaults, COUNT(vbox_defaults)},
[RG_NODE_PANEL] = {"Panel", 0, panel_defaults, COUNT(panel_defaults)},
[RG_NODE_LABEL] = {"Label", RG_TF_TEXT, NULL, 0},
[RG_NODE_BUTTON] = {"Button", RG_TF_TEXT | RG_TF_FOCUSABLE, button_defaults,
COUNT(button_defaults)},
};
const rg_type_info *rg__type_info(int32_t type) {
if (type < 0 || type >= RG_NODE_TYPE_COUNT)
return NULL;
return &type_table[type];
}
int32_t rg_type_find(const char *name) {
int32_t i;
if (!name)
return -1;
for (i = 0; i < RG_NODE_TYPE_COUNT; i++)
if (strcmp(type_table[i].name, name) == 0)
return i;
return -1;
}
const char *rg_type_name(int32_t type) {
const rg_type_info *t = rg__type_info(type);
return t ? t->name : "invalid";
}