clay/src/context.c
Gwendolyn d89ef83551 Reworked property system completely.
Properties can now have values of different types, and they are registered with their name, either to a layout class or globally.
Layout classes are also registered with their name.
2023-02-08 01:09:21 +01:00

157 lines
5.1 KiB
C

#include <clay.h>
#include <stddef.h>
#include <malloc.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "layout.h"
#include "context.h"
#include "clay-map.h"
#include "clay-list.h"
// todo: thread safety? maybe as a macro option CLAY_ENABLE_THREADSAFE
CLAY_STRING_MAP_TYPE(property_def_map, clay_prop_definition)
typedef struct {
clay_layout_class class;
property_def_map property_definitions;
} layout_class_container;
CLAY_STRING_MAP_TYPE(layout_class_map, layout_class_container)
struct clay_ctx_t {
layout_class_map layout_classes;
property_def_map global_property_definitions;
clay_layout_list layouts;
};
clay_ctx clay_create_context(void) {
clay_ctx ctx = malloc(sizeof *ctx);
assert(ctx != NULL);
ctx->layouts = clay_list_create(clay_layout_list);
ctx->layout_classes = clay_map_create(layout_class_map);
ctx->global_property_definitions = clay_map_create(property_def_map);
// todo: need to figure out how to do that properly
// every module should register itself somehow, or be manually registered by the user
// the context implementation should not know about the different modules
clay_text_register(ctx);
clay_flex_register(ctx);
clay_document_register(ctx);
return ctx;
}
void clay_destroy_context(clay_ctx ctx) {
CLAY_LIST_FOREACH(ctx->layouts, layout, _) {
clay_layout_cleanup(*layout);
free(*layout);
}
clay_list_destroy(ctx->layouts);
clay_map_destroy(ctx->layout_classes);
clay_map_destroy(ctx->global_property_definitions);
free(ctx);
}
void clay_ctx_register_layout(clay_ctx ctx, clay layout) {
clay_list_append(ctx->layouts, layout);
}
void clay_ctx_unregister_layout(clay_ctx ctx, clay layout) {
CLAY_LIST_FOREACH(ctx->layouts, l, idx) {
if (*l == layout) {
clay_list_remove(ctx->layouts, idx);
break;
}
}
}
static clay_prop_definition transform_property_definition(clay_prop_definition_in *prop_def_in, bool global) {
clay_prop_definition prop_def = {
.allow_int = prop_def_in->allow_int,
.allow_float = prop_def_in->allow_float,
.allow_units = prop_def_in->allow_units,
.allow_color = prop_def_in->allow_color,
.allow_string = prop_def_in->allow_string,
.keywords = clay_map_create(clay_prop_keyword_map),
.inherits = prop_def_in->inherits,
.global = global,
.max_values = (prop_def_in->max_values == 0 ? 1 : prop_def_in->max_values),
};
for (size_t i = 0; i < prop_def_in->keywords.num_entries; ++i) {
clay_map_set(prop_def.keywords, prop_def_in->keywords.entries[i].keyword, prop_def_in->keywords.entries[i].value);
}
return prop_def;
}
void clay_ctx_register_global_property(clay_ctx ctx, const char *name, clay_prop_definition_in *prop_def) {
assert(!clay_map_has_key(ctx->global_property_definitions, name));
clay_map_set(ctx->global_property_definitions, name, transform_property_definition(prop_def, true));
}
void clay_ctx_register_class_property(clay_ctx ctx, const char *class_name, const char *name,
clay_prop_definition_in *prop_def) {
layout_class_container *class_container;
bool class_exists = clay_map_get_ptr(ctx->layout_classes, class_name, &class_container);
assert(class_exists);
if (class_exists) {
assert(!clay_map_has_key(class_container->property_definitions, name));
clay_map_set(class_container->property_definitions, name, transform_property_definition(prop_def, false));
}
}
const clay_prop_definition *clay_ctx_get_property_definition(clay_ctx ctx, clay_layout_class class, const char *name) {
clay_prop_definition *definition;
CLAY_MAP_FOREACH(ctx->layout_classes, _, container) {
(void)_;
if (container->class == class) {
if (clay_map_get_ptr(container->property_definitions, name, &definition)) {
return definition;
}
break;
}
}
if (clay_map_get_ptr(ctx->global_property_definitions, name, &definition)) {
return definition;
}
return NULL;
}
void clay_ctx_register_layout_class(clay_ctx ctx, const char *name, clay_layout_class class) {
assert(!clay_map_has_key(ctx->layout_classes, name));
layout_class_container container = {
.class = class,
.property_definitions = clay_map_create(property_def_map),
};
clay_map_set(ctx->layout_classes, name, container);
}
clay_layout_class clay_ctx_get_layout_class(clay_ctx ctx, const char *name) {
layout_class_container container;
if (clay_map_get(ctx->layout_classes, name, &container)) {
return container.class;
} else {
return NULL;
}
}
const char * clay_ctx_get_layout_class_name(clay_ctx ctx, clay_layout_class class) {
CLAY_MAP_FOREACH(ctx->layout_classes, name, container) {
if (container->class == class){
return name;
}
}
return NULL;
}