d89ef83551
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.
157 lines
5.1 KiB
C
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;
|
|
} |