Contents of /trunk/src/style.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 325 - (hide annotations)
Mon Dec 21 19:41:58 2009 UTC (14 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 13538 byte(s)
Pending patch
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of OSM2Go.
5     *
6     * OSM2Go is free software: you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * OSM2Go is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include "appdata.h"
21    
22     #include <libxml/parser.h>
23     #include <libxml/tree.h>
24    
25     #if !defined(LIBXML_TREE_ENABLED) || !defined(LIBXML_OUTPUT_ENABLED)
26     #error "libxml doesn't support required tree or output"
27     #endif
28    
29     static void xml_get_prop_float(xmlNode *node, char *prop, float *value) {
30     char *str = (char*)xmlGetProp(node, BAD_CAST prop);
31     if(str) {
32 harbaum 273 *value = g_ascii_strtod(str, NULL);
33 harbaum 1 xmlFree(str);
34     }
35     }
36    
37     static gboolean xml_prop_is(xmlNode *node, char *prop, char *str) {
38     char *prop_str = (char*)xmlGetProp(node, BAD_CAST prop);
39     if(!prop_str) return FALSE;
40    
41     gboolean match = (strcasecmp(prop_str, str) == 0);
42     xmlFree(prop_str);
43     return match;
44     }
45    
46     static style_t *parse_style(xmlDocPtr doc, xmlNode *a_node) {
47     xmlNode *cur_node = NULL, *sub_node = NULL;
48     style_t *style = g_new0(style_t, 1);
49    
50     style->name = (char*)xmlGetProp(a_node, BAD_CAST "name");
51    
52     /* -------------- setup defaults -------------------- */
53     /* (the defaults are pretty much the potlatch style) */
54 harbaum 22 style->background.color = 0xffffffff; // white
55 harbaum 1
56     style->area.border_width = 2.0;
57 harbaum 22 style->area.color = 0x00000060; // 37.5%
58 harbaum 1 style->area.zoom_max = 0.1111; // zoom factor above which an area is visible & selectable
59    
60     style->node.radius = 4.0;
61     style->node.border_radius = 2.0;
62 harbaum 22 style->node.color = 0x000000ff; // black with filling ...
63     style->node.fill_color = 0x008800ff; // ... in dark green
64 harbaum 1 style->node.show_untagged = FALSE;
65     style->node.zoom_max = 0.4444; // zoom factor above which a node is visible & selectable
66    
67     style->track.width = 6.0;
68     style->track.color = 0x0000ff40; // blue
69 harbaum 22 style->track.gps_color = 0x000080ff;
70 harbaum 1
71     style->way.width = 3.0;
72 harbaum 22 style->way.color = 0x606060ff; // grey
73     style->way.zoom_max = 0.2222; // zoom above which it's visible & selectable
74 harbaum 1
75     style->highlight.width = 3.0;
76 harbaum 152 style->highlight.color = 0xffff0080; // normal highlights are yellow
77     style->highlight.node_color = 0xff000080; // node highlights are red
78     style->highlight.touch_color = 0x0000ff80; // touchnode and
79     style->highlight.arrow_color = 0x0000ff80; // arrows are blue
80 harbaum 1 style->highlight.arrow_limit = 4.0;
81    
82     style->frisket.mult = 3.0;
83 harbaum 22 style->frisket.color = 0xffffffff;
84 harbaum 1 style->frisket.border.present = TRUE;
85     style->frisket.border.width = 6.0;
86     style->frisket.border.color = 0x00000099;
87    
88     style->icon.enable = FALSE;
89     style->icon.scale = 1.0; // icon size (multiplier)
90     style->icon.path_prefix = g_strdup("standard");
91    
92     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
93     if (cur_node->type == XML_ELEMENT_NODE) {
94     if(strcasecmp((char*)cur_node->name, "elemstyles") == 0) {
95     style->elemstyles_filename =
96     (char*)xmlGetProp(cur_node, BAD_CAST "filename");
97    
98     /* ---------- node ------------------------------------- */
99     } else if(strcasecmp((char*)cur_node->name, "node") == 0) {
100     parse_color(cur_node, "color", &style->node.color);
101 harbaum 22 parse_color(cur_node, "fill-color", &style->node.fill_color);
102 harbaum 1 xml_get_prop_float(cur_node, "radius", &style->node.radius);
103     xml_get_prop_float(cur_node, "border-radius",
104     &style->node.border_radius);
105     float scale_max = 0;
106     xml_get_prop_float(cur_node, "scale-max", &scale_max);
107     if (scale_max > 0)
108     style->node.zoom_max = scaledn_to_zoom(scale_max);
109     else
110     style->node.zoom_max = 0;
111    
112     style->node.show_untagged =
113     xml_prop_is(cur_node, "show-untagged", "true");
114    
115     /* ---------- icon ------------------------------------- */
116     } else if(strcasecmp((char*)cur_node->name, "icon") == 0) {
117     xml_get_prop_float(cur_node, "scale", &style->icon.scale);
118 harbaum 152 char *prefix = (char*)xmlGetProp(cur_node, BAD_CAST "path-prefix");
119     if(prefix) {
120     if(style->icon.path_prefix) g_free(style->icon.path_prefix);
121     style->icon.path_prefix = prefix;
122     }
123 harbaum 1 style->icon.enable = xml_prop_is(cur_node, "enable", "true");
124    
125     /* ---------- way ------------------------------------- */
126     } else if(strcasecmp((char*)cur_node->name, "way") == 0) {
127     parse_color(cur_node, "color", &style->way.color);
128     xml_get_prop_float(cur_node, "width", &style->way.width);
129     float scale_max = 0;
130     xml_get_prop_float(cur_node, "scale-max", &scale_max);
131     if (scale_max > 0)
132     style->way.zoom_max = scaledn_to_zoom(scale_max);
133     else
134     style->way.zoom_max = 0;
135    
136     /* ---------- frisket --------------------------------- */
137     } else if(strcasecmp((char*)cur_node->name, "frisket") == 0) {
138     xml_get_prop_float(cur_node, "mult", &style->frisket.mult);
139 harbaum 156 parse_color(cur_node, "color", &style->frisket.color);
140 harbaum 1 style->frisket.border.present = FALSE;
141    
142     for(sub_node = cur_node->children; sub_node; sub_node=sub_node->next) {
143     if(sub_node->type == XML_ELEMENT_NODE) {
144     if(strcasecmp((char*)sub_node->name, "border") == 0) {
145     style->frisket.border.present = TRUE;
146     xml_get_prop_float(sub_node, "width",
147     &style->frisket.border.width);
148    
149 harbaum 22 parse_color(sub_node, "color", &style->frisket.border.color);
150 harbaum 1 }
151     }
152     }
153    
154     /* ---------- highlight ------------------------------- */
155     } else if(strcasecmp((char*)cur_node->name, "highlight") == 0) {
156 harbaum 22 parse_color(cur_node, "color", &style->highlight.color);
157     parse_color(cur_node, "node-color", &style->highlight.node_color);
158     parse_color(cur_node, "touch-color", &style->highlight.touch_color);
159     parse_color(cur_node, "arrow-color", &style->highlight.arrow_color);
160 harbaum 1 xml_get_prop_float(cur_node, "width", &style->highlight.width);
161     xml_get_prop_float(cur_node, "arrow-limit",
162     &style->highlight.arrow_limit);
163    
164     /* ---------- track ------------------------------------ */
165     } else if(strcasecmp((char*)cur_node->name, "track") == 0) {
166 harbaum 22 parse_color(cur_node, "color", &style->track.color);
167 harbaum 1 parse_color(cur_node, "gps-color", &style->track.gps_color);
168     xml_get_prop_float(cur_node, "width", &style->track.width);
169    
170     /* ---------- area ------------------------------------- */
171     } else if(strcasecmp((char*)cur_node->name, "area") == 0) {
172     style->area.has_border_color =
173     parse_color(cur_node, "border-color", &style->area.border_color);
174     xml_get_prop_float(cur_node,"border-width", &style->area.border_width);
175 harbaum 22 float scale_max = 0;
176 harbaum 1 xml_get_prop_float(cur_node, "scale-max", &scale_max);
177 harbaum 22 if (scale_max > 0)
178 harbaum 1 style->area.zoom_max = scaledn_to_zoom(scale_max);
179     else
180 harbaum 22 style->area.zoom_max = 0;
181 harbaum 1
182 harbaum 22 parse_color(cur_node, "color", &style->area.color);
183 harbaum 1
184     /* ---------- background ------------------------------- */
185     } else if(strcasecmp((char*)cur_node->name, "background") == 0) {
186     parse_color(cur_node, "color", &style->background.color);
187    
188     } else
189     printf(" found unhandled style/%s\n", cur_node->name);
190     }
191     }
192     return style;
193     }
194    
195     static style_t *parse_doc(xmlDocPtr doc) {
196     /* Get the root element node */
197     xmlNode *cur_node = NULL;
198     style_t *style = NULL;
199    
200     for(cur_node = xmlDocGetRootElement(doc);
201     cur_node; cur_node = cur_node->next) {
202     if (cur_node->type == XML_ELEMENT_NODE) {
203     if(strcasecmp((char*)cur_node->name, "style") == 0) {
204     if(!style)
205     style = parse_style(doc, cur_node);
206     } else
207     printf(" found unhandled %s\n", cur_node->name);
208     }
209     }
210    
211     xmlFreeDoc(doc);
212     xmlCleanupParser();
213     return style;
214     }
215    
216     static style_t *style_parse(appdata_t *appdata, char *fullname) {
217     style_t *style = NULL;
218    
219     xmlDoc *doc = NULL;
220    
221     LIBXML_TEST_VERSION;
222    
223     /* parse the file and get the DOM */
224     if((doc = xmlReadFile(fullname, NULL, 0)) == NULL) {
225     xmlErrorPtr errP = xmlGetLastError();
226     errorf(GTK_WIDGET(appdata->window),
227     _("Style parsing failed:\n\n"
228     "XML error while parsing style file\n"
229     "%s"), errP->message);
230    
231     return NULL;
232     } else {
233     style = parse_doc(doc);
234     style->iconP = &appdata->icon;
235     }
236    
237     return style;
238     }
239    
240     style_t *style_load(appdata_t *appdata, char *name) {
241     printf("Trying to load style %s\n", name);
242    
243     char *filename = g_strdup_printf("%s.style", name);
244     char *fullname = find_file(filename);
245     g_free(filename);
246    
247     if (!fullname) {
248     printf("style %s not found, trying %s instead\n", name, DEFAULT_STYLE);
249     filename = g_strdup_printf("%s.style", DEFAULT_STYLE);
250     fullname = find_file(filename);
251     g_free(filename);
252     if (!fullname) {
253     printf(" style not found, failed to find fallback style too\n");
254     return NULL;
255     }
256     }
257    
258     printf(" style filename: %s\n", fullname);
259    
260     style_t *style = style_parse(appdata, fullname);
261     g_free(fullname);
262    
263     printf(" elemstyle filename: %s\n", style->elemstyles_filename);
264     elemstyle_t *elemstyles =
265     josm_elemstyles_load(style->elemstyles_filename);
266     xmlFree(style->elemstyles_filename);
267     style->elemstyles = elemstyles;
268    
269     return style;
270     }
271    
272     void style_free(style_t *style) {
273     if(!style) return;
274    
275     printf("freeing style\n");
276    
277     if(style->elemstyles)
278     josm_elemstyles_free(style->elemstyles);
279    
280     if(style->name) g_free(style->name);
281    
282     if (style->icon.path_prefix) g_free(style->icon.path_prefix);
283    
284     g_free(style);
285     }
286    
287     static char *style_basename(char *name) {
288     char *retval = name;
289    
290     if(strrchr(name, '/'))
291     retval = strrchr(name, '/') + 1;
292    
293     /* create a local copy */
294     retval = g_strdup(retval);
295    
296     /* and cut off extension */
297     if(strrchr(retval, '.'))
298     *strrchr(retval, '.') = 0;
299    
300     return retval;
301     }
302    
303 harbaum 317 GtkWidget *style_select_widget(appdata_t *appdata) {
304 harbaum 1 file_chain_t *chain = file_scan("*.style");
305    
306     /* there must be at least one style, otherwise */
307     /* the program wouldn't be running */
308     g_assert(chain);
309    
310 harbaum 317 GtkWidget *cbox = combo_box_new(_("Style"));
311 harbaum 1
312     /* fill combo box with presets */
313     int cnt = 0, match = -1;
314 harbaum 317 while(chain) {
315     file_chain_t *next = chain->next;
316    
317     printf(" file: %s\n", chain->name);
318 harbaum 1
319 harbaum 317 style_t *style = style_parse(appdata, chain->name);
320 harbaum 1 printf(" name: %s\n", style->name);
321 harbaum 317 combo_box_append_text(cbox, style->name);
322 harbaum 1
323 harbaum 317 char *basename = style_basename(chain->name);
324 harbaum 1 if(strcmp(basename, appdata->settings->style) == 0) match = cnt;
325     g_free(basename);
326    
327     xmlFree(style->elemstyles_filename);
328     style->elemstyles_filename = NULL;
329     style_free(style);
330    
331     cnt++;
332 harbaum 317
333     g_free(chain);
334     chain = next;
335 harbaum 1 }
336    
337     if(match >= 0)
338 harbaum 317 combo_box_set_active(cbox, match);
339 harbaum 1
340 harbaum 317 return cbox;
341     }
342 harbaum 1
343 harbaum 317 void style_change(appdata_t *appdata, const char *name) {
344     char *new_style = NULL;
345 harbaum 1
346 harbaum 317 file_chain_t *chain = file_scan("*.style");
347 harbaum 1
348     while(chain) {
349     file_chain_t *next = chain->next;
350     style_t *style = style_parse(appdata, chain->name);
351    
352 harbaum 317 if(strcmp(style->name, name) == 0) {
353     new_style = style_basename(chain->name);
354 harbaum 1 }
355    
356     xmlFree(style->elemstyles_filename);
357     style->elemstyles_filename = NULL;
358     style_free(style);
359    
360     g_free(chain);
361     chain = next;
362     }
363    
364 harbaum 317 /* check of style has really been changed */
365     if(appdata->settings->style &&
366     !strcmp(appdata->settings->style, new_style)) {
367     g_free(new_style);
368     return;
369     }
370 harbaum 1
371 harbaum 317 if(appdata->settings->style)
372     g_free(appdata->settings->style);
373    
374     appdata->settings->style = new_style;
375    
376 harbaum 1 map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
377     /* let gtk clean up first */
378     while(gtk_events_pending()) {
379     putchar('.');
380     gtk_main_iteration();
381     }
382    
383     style_free(appdata->map->style);
384     appdata->map->style = style_load(appdata, appdata->settings->style);
385    
386     /* canvas background may have changed */
387 harbaum 193 canvas_set_background(appdata->map->canvas,
388     appdata->map->style->background.color);
389 harbaum 1
390     map_paint(appdata);
391     }
392 achadwick 56
393 harbaum 317 #ifndef FREMANTLE
394     /* in fremantle this happens inside the submenu handling since this button */
395     /* is actually placed inside the submenu there */
396     void style_select(GtkWidget *parent, appdata_t *appdata) {
397    
398     printf("select style\n");
399    
400     /* ------------------ style dialog ---------------- */
401     GtkWidget *dialog =
402     misc_dialog_new(MISC_DIALOG_NOSIZE,_("Select style"),
403     GTK_WINDOW(parent),
404     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
405     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
406     NULL);
407    
408     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
409    
410     GtkWidget *cbox = style_select_widget(appdata);
411    
412     GtkWidget *hbox = gtk_hbox_new(FALSE, 8);
413     gtk_box_pack_start_defaults(GTK_BOX(hbox), gtk_label_new(_("Style:")));
414    
415     gtk_box_pack_start_defaults(GTK_BOX(hbox), cbox);
416     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
417    
418     gtk_widget_show_all(dialog);
419    
420     if(GTK_RESPONSE_ACCEPT != gtk_dialog_run(GTK_DIALOG(dialog))) {
421     printf("user clicked cancel\n");
422     gtk_widget_destroy(dialog);
423     return;
424     }
425    
426     const char *ptr = combo_box_get_active_text(cbox);
427     printf("user clicked ok on %s\n", ptr);
428    
429     gtk_widget_destroy(dialog);
430    
431     style_change(appdata, ptr);
432     }
433     #endif
434    
435 achadwick 56 //vim:et:ts=8:sw=2:sts=2:ai