]> mj.ucw.cz Git - leo.git/blob - style.c
TODO
[leo.git] / style.c
1 /*
2  *      Hic Est Leo -- Styling
3  *
4  *      (c) 2014 Martin Mares <mj@ucw.cz>
5  */
6
7 #include "leo.h"
8 #include "osm.h"
9 #include "style.h"
10
11 #include <ucw/mempool.h>
12
13 #include <stdio.h>
14
15 struct dict style_prop_dict, style_layer_dict;
16
17 static const char * const style_wk_props[] = {
18   NULL,
19 #define P(x,y) [PROP_##x] = y,
20 #include "dict-props.h"
21 #undef P
22   NULL
23 };
24
25 static const char * const style_wk_layers[] = {
26   NULL,
27   "default",
28   NULL
29 };
30
31 void styles_init(void)
32 {
33   dict_init(&style_prop_dict, style_wk_props);
34   dict_init(&style_layer_dict, style_wk_layers);
35 }
36
37 #define HASH_NODE struct style_prop
38 #define HASH_PREFIX(x) style_prop_##x
39 #define HASH_KEY_ATOMIC key
40 #define HASH_WANT_FIND
41 #define HASH_WANT_LOOKUP
42 #define HASH_GIVE_ALLOC
43 // FIXME: Make <ucw/hashtable.h> accept our pool
44 #define HASH_ZERO_FILL
45 #define HASH_TABLE_DYNAMIC
46 #define HASH_TABLE_ALLOC
47 #define HASH_TABLE_VARS struct mempool *pool;
48 static void *style_prop_alloc(struct style_prop_table *table, uns size);
49 static inline void style_prop_free(struct style_prop_table *table UNUSED, void *x UNUSED) { }
50 #include <ucw/hashtable.h>
51
52 static void *style_prop_alloc(struct style_prop_table *table, uns size)
53 {
54   return mp_alloc_fast(table->pool, size);
55 }
56
57 void style_init(struct style_results *r)
58 {
59   r->pool = mp_new(4096);
60   r->num_layers = dict_size(&style_layer_dict);
61   r->layers = mp_alloc_zero(r->pool, r->num_layers * sizeof(struct style_info *));
62   r->num_active_layers = 0;
63   r->active_layers = mp_alloc_zero(r->pool, r->num_layers * sizeof(layer_t));
64 }
65
66 void style_cleanup(struct style_results *r)
67 {
68   mp_delete(r->pool);
69 }
70
71 void style_begin(struct style_results *r, struct osm_object *o)
72 {
73   ASSERT(!r->num_active_layers);
74   mp_push(r->pool);
75   r->obj = o;
76 }
77
78 void style_end(struct style_results *r)
79 {
80   for (uns i=0; i<r->num_active_layers; i++)
81     r->layers[r->active_layers[i]] = NULL;
82   r->layers[0] = NULL;
83   r->num_active_layers = 0;
84   mp_pop(r->pool);
85 }
86
87 static inline void style_assign(struct style_prop *dest, struct style_prop *src)
88 {
89   dest->type = src->type;
90   dest->val = src->val;
91 }
92
93 static struct style_info *style_get_info(struct style_results *r, layer_t layer)
94 {
95   ASSERT(layer < r->num_layers);
96   if (!r->layers[layer])
97     {
98       struct style_info *si = mp_alloc_zero(r->pool, sizeof(*si));
99       r->layers[layer] = si;
100       si->hash = mp_alloc_zero(r->pool, sizeof(struct style_prop_table));
101       si->hash->pool = r->pool;
102       style_prop_init(si->hash);
103
104       if (layer != STYLE_LAYER_ALL)
105         {
106           r->active_layers[r->num_active_layers++] = layer;
107
108           // Copy all properties which have been set for all layers
109           struct style_info *si_all = r->layers[STYLE_LAYER_ALL];
110           if (si_all)
111             {
112               /*
113                * CAVEAT: This is probably wrong. When no properties are set explicitly
114                * set for a layer, all-layer properties are not propagated. Hopefully harmless.
115                */
116               HASH_FOR_ALL_DYNAMIC(style_prop, si_all->hash, s)
117                 {
118                   style_assign(style_prop_lookup(si->hash, s->key), s);
119                 }
120               HASH_END_FOR;
121             }
122         }
123     }
124   return r->layers[layer];
125 }
126
127 void style_enable_default_layer(struct style_results *r)
128 {
129   style_get_info(r, STYLE_LAYER_DEFAULT);
130 }
131
132 void style_set_by_layer(struct style_results *r, layer_t layer, struct style_prop *p)
133 {
134   if (layer == STYLE_LAYER_ALL)
135     {
136       // Set in all existing layers
137       for (uns i=0; i < r->num_active_layers; i++)
138         style_assign(style_prop_lookup(r->layers[r->active_layers[i]]->hash, p->key), p);
139       // ... and let it propagate to STYLE_LAYER_ALL
140     }
141
142   struct style_info *si = style_get_info(r, layer);
143   style_assign(style_prop_lookup(si->hash, p->key), p);
144 }
145
146 struct style_prop *style_get_by_layer(struct style_results *r, layer_t layer, prop_t key)
147 {
148   struct style_info *si = style_get_info(r, layer);
149   return style_get(si, key);
150 }
151
152 void style_set(struct style_info *si, struct style_prop *p)
153 {
154   style_assign(style_prop_lookup(si->hash, p->key), p);
155 }
156
157 struct style_prop *style_get(struct style_info *si, prop_t key)
158 {
159   return style_prop_find(si->hash, key);
160 }
161
162 struct style_prop *style_get_and_check(struct style_info *si, prop_t key, uns allowed_types)
163 {
164   struct style_prop *p = style_prop_find(si->hash, key);
165   if (!p)
166     return NULL;
167   if (!(allowed_types & (1 << p->type)))
168     {
169       // XXX: Better diagnostics?
170       msg(L_WARN, "Style property %s set to invalid type #%u", style_prop_decode(p->key), p->type);
171       return NULL;
172     }
173   return p;
174 }
175
176 osm_val_t style_get_ident(struct style_info *si, prop_t key)
177 {
178   struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_IDENT);
179   return p ? p->val.id : 0;
180 }
181
182 osm_val_t style_get_string(struct style_info *si, prop_t key)
183 {
184   struct style_prop *p = style_get_and_check(si, key, (1 << PROP_TYPE_STRING) | (1 << PROP_TYPE_IDENT));
185   return p ? p->val.id : 0;
186 }
187
188 bool style_get_number(struct style_info *si, prop_t key, double *dp)
189 {
190   struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_NUMBER);
191   if (!p)
192     return 0;
193   *dp = p->val.number;
194   return 1;
195 }
196
197 bool style_get_color(struct style_info *si, prop_t key, color_t *colorp)
198 {
199   struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_COLOR);
200   if (!p)
201     return 0;
202   *colorp = p->val.color;
203   return 1;
204 }
205
206 void style_dump(struct style_results *r)
207 {
208   for (uns i=0; i < r->num_active_layers; i++)
209     {
210       layer_t layer = r->active_layers[i];
211       printf("Layer %s (%u)\n", style_layer_decode(layer), layer);
212       struct style_info *si = r->layers[layer];
213       HASH_FOR_ALL_DYNAMIC(style_prop, si->hash, s)
214         {
215           printf("\t");
216           style_dump_prop(s);
217         }
218       HASH_END_FOR;
219     }
220 }
221
222 static void style_dump_val(struct style_prop *s)
223 {
224   uns cnt = 0;
225
226   switch (s->type)
227     {
228     case PROP_TYPE_STRING:
229       printf("%s [string]", osm_val_decode(s->val.id));
230       break;
231     case PROP_TYPE_IDENT:
232       printf("%s [ident]", osm_val_decode(s->val.id));
233       break;
234     case PROP_TYPE_NUMBER:
235       printf("%.6g [number]", s->val.number);
236       break;
237     case PROP_TYPE_COLOR:
238       printf("%06x [color]", s->val.color);
239       break;
240     case PROP_TYPE_LIST:
241       putchar('(');
242       CLIST_FOR_EACH(struct style_val_list_entry *, e, *s->val.list)
243         {
244           if (cnt++)
245             printf(", ");
246           style_dump_val(&e->val);
247         }
248       printf(") [list]");
249       break;
250     default:
251       printf("[unknown type %u]", s->type);
252     }
253 }
254
255 void style_dump_prop(struct style_prop *s)
256 {
257   printf("%s = ", style_prop_decode(s->key));
258   style_dump_val(s);
259   putchar('\n');
260 }
261
262 void style_scale(struct style_info *si, double *wp, double *hp, prop_t width_prop, prop_t height_prop)
263 {
264   double w, h;
265   bool got_width = style_get_number(si, width_prop, &w);
266   bool got_height = style_get_number(si, height_prop, &h);
267
268   if (got_width + got_height == 2)
269     {
270       *wp = w;
271       *hp = h;
272     }
273   else if (got_width + got_height == 1)
274     {
275       if (got_width)
276         {
277           *hp *= w / *wp;
278           *wp = w;
279         }
280       else
281         {
282           *wp *= h / *hp;
283           *hp = h;
284         }
285     }
286 }