#include #include #include #include #include #include #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; }