diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e1d639..6248adc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ add_executable(foobar particles/string.c particles/string.h particles/list.c particles/list.h + particles/map.c particles/map.h modules/label/label.c modules/label/label.h modules/clock/clock.c modules/clock/clock.h diff --git a/config.c b/config.c index 11a6879..2c5a5d0 100644 --- a/config.c +++ b/config.c @@ -10,6 +10,7 @@ #include "particle.h" #include "particles/string.h" #include "particles/list.h" +#include "particles/map.h" #include "module.h" #include "modules/label/label.h" @@ -155,7 +156,7 @@ particle_list_from_config(const struct yml_node *node, right_spacing = yml_value_as_int(right_spacing_node); size_t count = yml_list_length(items_node); - struct particle **parts = calloc(count, sizeof(*parts)); + struct particle *parts[count]; size_t idx = 0; for (struct yml_list_iter it = yml_list_iter(items_node); @@ -168,10 +169,37 @@ particle_list_from_config(const struct yml_node *node, struct particle *list = particle_list_new( parts, count, left_spacing, right_spacing, left_margin, right_margin); - free(parts); return list; } +static struct particle * +particle_map_from_config(const struct yml_node *node, const struct font *parent_font) +{ + const struct yml_node *tag = yml_get_value(node, "tag"); + const struct yml_node *values = yml_get_value(node, "values"); + + assert(yml_is_scalar(tag)); + assert(yml_is_dict(values)); + + printf("MAP tag: %s\n", yml_value_as_string(tag)); + + struct particle_map particle_map[yml_dict_length(values)]; + + size_t idx = 0; + for (struct yml_dict_iter it = yml_dict_iter(values); + it.key != NULL; + yml_dict_next(&it), idx++) + { + particle_map[idx].tag_value = yml_value_as_string(it.key); + particle_map[idx].particle = particle_from_config(it.value, parent_font); + assert(particle_map[idx].particle != NULL); + } + + return particle_map_new( + yml_value_as_string(tag), particle_map, yml_dict_length(values), + NULL, 0, 0); +} + static struct particle * particle_from_config(const struct yml_node *node, const struct font *parent_font) { @@ -185,6 +213,8 @@ particle_from_config(const struct yml_node *node, const struct font *parent_font return particle_string_from_config(pair.value, parent_font); else if (strcmp(type, "list") == 0) return particle_list_from_config(pair.value, parent_font); + else if (strcmp(type, "map") == 0) + return particle_map_from_config(pair.value, parent_font); else assert(false); } diff --git a/particles/map.c b/particles/map.c new file mode 100644 index 0000000..3dbaf90 --- /dev/null +++ b/particles/map.c @@ -0,0 +1,85 @@ +#include "map.h" + +#include +#include +#include + +struct map { + char *tag; + struct particle *default_particle; + struct particle_map *map; + size_t count; +}; + +static struct exposable * +instantiate(const struct particle *particle, const struct tag_set *tags) +{ + const struct map *map = particle->private; + const struct tag *tag = tag_for_name(tags, map->tag); + assert(tag != NULL || map->default_particle != NULL); + + if (tag == NULL) + return map->default_particle->instantiate(map->default_particle, tags); + + + const char *tag_value = tag->as_string(tag); + for (size_t i = 0; i < map->count; i++) { + const struct particle_map *e = &map->map[i]; + + if (strcmp(e->tag_value, tag_value) != 0) + continue; + + return e->particle->instantiate(e->particle, tags); + } + + assert(map->default_particle != NULL); + return map->default_particle->instantiate(map->default_particle, tags); +} + +static void +particle_destroy(struct particle *particle) +{ + struct map *map = particle->private; + + if (map->default_particle != NULL) + map->default_particle->destroy(map->default_particle); + + for (size_t i = 0; i < map->count; i++) { + struct particle *p = map->map[i].particle; + p->destroy(p); + free((char *)map->map[i].tag_value); + } + + free(map->map); + free(map->tag); + free(map); + free(particle); +} + +struct particle * +particle_map_new(const char *tag, const struct particle_map *particle_map, + size_t count, struct particle *default_particle, + int left_margin, int right_margin) +{ + struct particle *particle = particle_common_new(left_margin, right_margin); + particle->destroy = &particle_destroy; + particle->instantiate = &instantiate; + + struct map *map = malloc(sizeof(*map)); + map->tag = strdup(tag); + map->default_particle = default_particle; + map->count = count; + map->map = malloc(count * sizeof(map->map[0])); + + for (size_t i = 0; i < count; i++) { + map->map[i].tag_value = strdup(particle_map[i].tag_value); + map->map[i].particle = particle_map[i].particle; + map->map[i].particle->parent = particle; + } + + if (map->default_particle != NULL) + map->default_particle->parent = particle; + + particle->private = map; + return particle; +} diff --git a/particles/map.h b/particles/map.h new file mode 100644 index 0000000..55f72e9 --- /dev/null +++ b/particles/map.h @@ -0,0 +1,11 @@ +#pragma once +#include "../particle.h" + +struct particle_map { + const char *tag_value; + struct particle *particle; +}; + +struct particle *particle_map_new( + const char *tag, const struct particle_map *particle_map, size_t count, + struct particle *default_particle, int left_margin, int right_margin);