FIX:core:cache NAVIT_SHAREDIR from the enviroment for icon paths,
[navit-package] / navit / graphics.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 //##############################################################################################################
21 //#
22 //# File: graphics.c
23 //# Description: 
24 //# Comment: 
25 //# Authors: Martin Schaller (04/2008)
26 //#
27 //##############################################################################################################
28
29 #include <glib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include "debug.h"
34 #include "string.h"
35 #include "draw_info.h"
36 #include "point.h"
37 #include "graphics.h"
38 #include "projection.h"
39 #include "map.h"
40 #include "coord.h"
41 #include "transform.h"
42 #include "plugin.h"
43 #include "profile.h"
44 #include "mapset.h"
45 #include "layout.h"
46 #include "route.h"
47 #include "util.h"
48 #include "callback.h"
49
50 static char *navit_sharedir;
51
52 //##############################################################################################################
53 //# Description: 
54 //# Comment: 
55 //# Authors: Martin Schaller (04/2008)
56 //##############################################################################################################
57 struct graphics
58 {
59         struct graphics_priv *priv;
60         struct graphics_methods meth;
61         char *default_font;
62         struct graphics_font *font[16];
63         struct graphics_gc *gc[3];
64         struct attr **attrs;
65         struct callback_list *cbl;
66         int ready;
67 };
68
69
70 struct displaylist {
71         GHashTable *dl;
72 };
73
74 /**
75  * Creates a new graphics object
76  * attr type required
77  * @param <>
78  * @returns <>
79  * @author Martin Schaller (04/2008)
80 */
81 struct graphics * graphics_new(struct attr *parent, struct attr **attrs)
82 {
83         struct graphics *this_;
84         struct attr *type_attr;
85         struct graphics_priv * (*graphicstype_new)(struct navit *nav, struct graphics_methods *meth, struct attr **attrs);
86
87         if (! (type_attr=attr_search(attrs, NULL, attr_type))) {
88                 return NULL;
89         }
90
91         graphicstype_new=plugin_get_graphics_type(type_attr->u.str);
92         if (! graphicstype_new)
93                 return NULL;
94         this_=g_new0(struct graphics, 1);
95         this_->cbl=callback_list_new();
96         this_->priv=(*graphicstype_new)(parent->u.navit, &this_->meth, attrs);
97         this_->attrs=attr_list_dup(attrs);
98         return this_;
99 }
100
101 /**
102  * FIXME
103  * @param <>
104  * @returns <>
105  * @author Martin Schaller (04/2008)
106 */
107 int graphics_get_attr(struct graphics *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
108 {
109         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
110 }
111
112 /**
113  * FIXME
114  * @param <>
115  * @returns <>
116  * @author Martin Schaller (04/2008)
117 */
118 struct graphics * graphics_overlay_new(struct graphics *parent, struct point *p, int w, int h)
119 {
120         struct graphics *this_;
121         this_=g_new0(struct graphics, 1);
122         this_->priv=parent->meth.overlay_new(parent->priv, &this_->meth, p, w, h);
123         return this_;
124 }
125
126 /**
127  * FIXME
128  * @param <>
129  * @returns <>
130  * @author Martin Schaller (04/2008)
131 */
132 void graphics_init(struct graphics *this_)
133 {
134         this_->gc[0]=graphics_gc_new(this_);
135         graphics_gc_set_background(this_->gc[0], &(struct color) { 0xffff, 0xefef, 0xb7b7, 0xffff});
136         graphics_gc_set_foreground(this_->gc[0], &(struct color) { 0xffff, 0xefef, 0xb7b7, 0xffff });
137         this_->gc[1]=graphics_gc_new(this_);
138         graphics_gc_set_background(this_->gc[1], &(struct color) { 0x0000, 0x0000, 0x0000, 0xffff });
139         graphics_gc_set_foreground(this_->gc[1], &(struct color) { 0xffff, 0xffff, 0xffff, 0xffff });
140         this_->gc[2]=graphics_gc_new(this_);
141         graphics_gc_set_background(this_->gc[2], &(struct color) { 0xffff, 0xffff, 0xffff, 0xffff });
142         graphics_gc_set_foreground(this_->gc[2], &(struct color) { 0x0000, 0x0000, 0x0000, 0xffff });
143         this_->meth.background_gc(this_->priv, this_->gc[0]->priv);
144         navit_sharedir = getenv("NAVIT_SHAREDIR");
145 }
146
147 /**
148  * FIXME
149  * @param <>
150  * @returns <>
151  * @author Martin Schaller (04/2008)
152 */
153 void * graphics_get_data(struct graphics *this_, char *type)
154 {
155         return (this_->meth.get_data(this_->priv, type));
156 }
157
158 /**
159  * FIXME
160  * @param <>
161  * @returns <>
162  * @author Martin Schaller (04/2008)
163 */
164 void graphics_register_resize_callback(struct graphics *this_, void (*callback)(void *data, int w, int h), void *data)
165 {
166         this_->meth.register_resize_callback(this_->priv, callback, data);
167 }
168
169 /**
170  * Called in navit.c
171  * @param <>
172  * @returns <>
173  * @author Martin Schaller (04/2008)
174 */
175 void graphics_register_button_callback(struct graphics *this_, void (*callback)(void *data, int pressed, int button, struct point *p), void *data)
176 {
177         this_->meth.register_button_callback(this_->priv, callback, data);
178 }
179
180 /**
181  * FIXME
182  * @param <>
183  * @returns <>
184  * @author Martin Schaller (04/2008)
185 */
186 void graphics_register_motion_callback(struct graphics *this_, void (*callback)(void *data, struct point *p), void *data)
187 {
188         this_->meth.register_motion_callback(this_->priv, callback, data);
189 }
190
191 /**
192  * FIXME
193  * @param <>
194  * @returns <>
195  * @author Martin Schaller (04/2008)
196 */
197 void graphics_register_keypress_callback(struct graphics *this_, void (*callback)(void *data, char *key), void *data)
198 {
199         this_->meth.register_keypress_callback(this_->priv, callback, data);
200 }
201
202 void graphics_add_callback(struct graphics *this_, struct callback *cb)
203 {
204         callback_list_add(this_->cbl, cb);
205 }
206
207 /**
208  * FIXME
209  * @param <>
210  * @returns <>
211  * @author Martin Schaller (04/2008)
212 */
213 struct graphics_font * graphics_font_new(struct graphics *gra, int size, int flags)
214 {
215         struct graphics_font *this_;
216
217         this_=g_new0(struct graphics_font,1);
218         this_->priv=gra->meth.font_new(gra->priv, &this_->meth, gra->default_font, size, flags);
219         return this_;
220 }
221
222 /**
223  * Free all loaded fonts.
224  * Used when switching layouts.
225  * @param gra The graphics instance
226  * @returns nothing
227  * @author Sarah Nordstrom (05/2008)
228  */
229 void graphics_font_destroy_all(struct graphics *gra) 
230
231         int i; 
232         for(i = 0 ; i < sizeof(gra->font) / sizeof(gra->font[0]); i++) { 
233                 if(!gra->font[i]) continue; 
234                 gra->font[i]->meth.font_destroy(gra->font[i]->priv); 
235                 gra->font[i] = NULL; 
236         }
237 }
238
239 /**
240  * FIXME
241  * @param <>
242  * @returns <>
243  * @author Martin Schaller (04/2008)
244 */
245 struct graphics_gc * graphics_gc_new(struct graphics *gra)
246 {
247         struct graphics_gc *this_;
248
249         this_=g_new0(struct graphics_gc,1);
250         this_->priv=gra->meth.gc_new(gra->priv, &this_->meth);
251         return this_;
252 }
253
254 /**
255  * FIXME
256  * @param <>
257  * @returns <>
258  * @author Martin Schaller (04/2008)
259 */
260 void graphics_gc_destroy(struct graphics_gc *gc)
261 {
262         gc->meth.gc_destroy(gc->priv);
263         g_free(gc);
264 }
265
266 /**
267  * FIXME
268  * @param <>
269  * @returns <>
270  * @author Martin Schaller (04/2008)
271 */
272 void graphics_gc_set_foreground(struct graphics_gc *gc, struct color *c)
273 {
274         gc->meth.gc_set_foreground(gc->priv, c);
275 }
276
277 /**
278  * FIXME
279  * @param <>
280  * @returns <>
281  * @author Martin Schaller (04/2008)
282 */
283 void graphics_gc_set_background(struct graphics_gc *gc, struct color *c)
284 {
285         gc->meth.gc_set_background(gc->priv, c);
286 }
287
288 /**
289  * FIXME
290  * @param <>
291  * @returns <>
292  * @author Martin Schaller (04/2008)
293 */
294 void graphics_gc_set_linewidth(struct graphics_gc *gc, int width)
295 {
296         gc->meth.gc_set_linewidth(gc->priv, width);
297 }
298
299 /**
300  * FIXME
301  * @param <>
302  * @returns <>
303  * @author Martin Schaller (04/2008)
304 */
305 void graphics_gc_set_dashes(struct graphics_gc *gc, int width, int offset, unsigned char dash_list[], int n)
306 {
307         if (gc->meth.gc_set_dashes)
308                 gc->meth.gc_set_dashes(gc->priv, width, offset, dash_list, n);
309 }
310
311 /**
312  * Create a new image from file path scaled to w and h pixels
313  * @param gra the graphics instance
314  * @param path path of the image to load
315  * @param w width to rescale to
316  * @param h height to rescale to
317  * @returns <>
318  * @author Martin Schaller (04/2008)
319 */
320 struct graphics_image * graphics_image_new_scaled(struct graphics *gra, char *path, int w, int h)
321 {
322         struct graphics_image *this_;
323
324         this_=g_new0(struct graphics_image,1);
325         this_->height=h;
326         this_->width=w;
327         this_->priv=gra->meth.image_new(gra->priv, &this_->meth, path, &this_->width, &this_->height, &this_->hot);
328         if (! this_->priv) {
329                 g_free(this_);
330                 this_=NULL;
331         }
332         return this_;
333 }
334
335 /**
336  * Create a new image from file path
337  * @param gra the graphics instance
338  * @param path path of the image to load
339  * @returns <>
340  * @author Martin Schaller (04/2008)
341 */
342 struct graphics_image * graphics_image_new(struct graphics *gra, char *path)
343 {
344         return graphics_image_new_scaled(gra, path, -1, -1);
345 }
346
347 /**
348  * FIXME
349  * @param <>
350  * @returns <>
351  * @author Martin Schaller (04/2008)
352 */
353 void graphics_image_free(struct graphics *gra, struct graphics_image *img)
354 {
355         if (gra->meth.image_free)
356                 gra->meth.image_free(gra->priv, img->priv);
357         g_free(img);
358 }
359
360 /**
361  * FIXME
362  * @param <>
363  * @returns <>
364  * @author Martin Schaller (04/2008)
365 */
366 void graphics_draw_restore(struct graphics *this_, struct point *p, int w, int h)
367 {
368         this_->meth.draw_restore(this_->priv, p, w, h);
369 }
370
371 /**
372  * FIXME
373  * @param <>
374  * @returns <>
375  * @author Martin Schaller (04/2008)
376 */
377 void graphics_draw_mode(struct graphics *this_, enum draw_mode_num mode)
378 {
379         this_->meth.draw_mode(this_->priv, mode);
380 }
381
382 /**
383  * FIXME
384  * @param <>
385  * @returns <>
386  * @author Martin Schaller (04/2008)
387 */
388 void graphics_draw_lines(struct graphics *this_, struct graphics_gc *gc, struct point *p, int count)
389 {
390         this_->meth.draw_lines(this_->priv, gc->priv, p, count);
391 }
392
393 /**
394  * FIXME
395  * @param <>
396  * @returns <>
397  * @author Martin Schaller (04/2008)
398 */
399 void graphics_draw_circle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int r)
400 {
401         this_->meth.draw_circle(this_->priv, gc->priv, p, r);
402 }
403
404 /**
405  * FIXME
406  * @param <>
407  * @returns <>
408  * @author Martin Schaller (04/2008)
409 */
410 void graphics_draw_rectangle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int w, int h)
411 {
412         this_->meth.draw_rectangle(this_->priv, gc->priv, p, w, h);
413 }
414
415 /**
416  * FIXME
417  * @param <>
418  * @returns <>
419  * @author Martin Schaller (04/2008)
420 */
421 void graphics_draw_text(struct graphics *this_, struct graphics_gc *gc1, struct graphics_gc *gc2, struct graphics_font *font, char *text, struct point *p, int dx, int dy)
422 {
423         this_->meth.draw_text(this_->priv, gc1->priv, gc2 ? gc2->priv : NULL, font->priv, text, p, dx, dy);
424 }
425
426 /**
427  * FIXME
428  * @param <>
429  * @returns <>
430  * @author Martin Schaller (04/2008)
431 */
432 void graphics_get_text_bbox(struct graphics *this_, struct graphics_font *font, char *text, int dx, int dy, struct point *ret)
433 {
434         this_->meth.get_text_bbox(this_->priv, font->priv, text, dx, dy, ret);
435 }
436
437 /**
438  * FIXME
439  * @param <>
440  * @returns <>
441  * @author Martin Schaller (04/2008)
442 */
443 void graphics_overlay_disable(struct graphics *this_, int disable)
444 {
445         if (this_->meth.overlay_disable)
446                 this_->meth.overlay_disable(this_->priv, disable);
447 }
448
449 /**
450  * FIXME
451  * @param <>
452  * @returns <>
453  * @author Martin Schaller (04/2008)
454 */
455 void graphics_draw_image(struct graphics *this_, struct graphics_gc *gc, struct point *p, struct graphics_image *img)
456 {
457         this_->meth.draw_image(this_->priv, gc->priv, p, img->priv);
458 }
459
460 #include "attr.h"
461 #include "popup.h"
462 #include <stdio.h>
463
464
465 #if 0
466 //##############################################################################################################
467 //# Description: 
468 //# Comment: 
469 //# Authors: Martin Schaller (04/2008)
470 //##############################################################################################################
471 static void popup_view_html(struct popup_item *item, char *file)
472 {
473         char command[1024];
474         sprintf(command,"firefox %s", file);
475         system(command);
476 }
477
478 //##############################################################################################################
479 //# Description: 
480 //# Comment: 
481 //# Authors: Martin Schaller (04/2008)
482 //##############################################################################################################
483 static void graphics_popup(struct display_list *list, struct popup_item **popup)
484 {
485         struct item *item;
486         struct attr attr;
487         struct map_rect *mr;
488         struct coord c;
489         struct popup_item *curr_item,*last=NULL;
490         item=list->data;
491         mr=map_rect_new(item->map, NULL, NULL, 0);
492         printf("id hi=0x%x lo=0x%x\n", item->id_hi, item->id_lo);
493         item=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
494         if (item) {
495                 if (item_attr_get(item, attr_name, &attr)) {
496                         curr_item=popup_item_new_text(popup,attr.u.str,1);
497                         if (item_attr_get(item, attr_info_html, &attr)) {
498                                 popup_item_new_func(&last,"HTML Info",1, popup_view_html, g_strdup(attr.u.str));
499                         }
500                         if (item_attr_get(item, attr_price_html, &attr)) {
501                                 popup_item_new_func(&last,"HTML Preis",2, popup_view_html, g_strdup(attr.u.str));
502                         }
503                         curr_item->submenu=last;
504                 }
505         }
506         map_rect_destroy(mr);
507 }
508 #endif
509
510 /**
511  * FIXME
512  * @param <>
513  * @returns <>
514  * @author Martin Schaller (04/2008)
515 */
516 struct displayitem {
517         struct item item;
518         char *label;
519         int displayed;
520         int count;
521         struct point pnt[0];
522 };
523
524 /**
525  * FIXME
526  * @param <>
527  * @returns <>
528  * @author Martin Schaller (04/2008)
529 */
530 static int xdisplay_free_list(gpointer key, gpointer value, gpointer user_data)
531 {
532         GList *h, *l;
533         h=value;
534         l=h;
535         while (l) {
536                 struct displayitem *di=l->data;
537                 if (! di->displayed && di->item.type < type_line) 
538                         dbg(1,"warning: item '%s' not displayed\n", item_to_name(di->item.type));
539                 g_free(l->data);
540                 l=g_list_next(l);
541         }
542         g_list_free(h);
543         return TRUE;
544 }
545
546 /**
547  * FIXME
548  * @param <>
549  * @returns <>
550  * @author Martin Schaller (04/2008)
551 */
552 static void xdisplay_free(GHashTable *display_list)
553 {
554         g_hash_table_foreach_remove(display_list, xdisplay_free_list, NULL);
555 }
556
557 /**
558  * FIXME
559  * @param <>
560  * @returns <>
561  * @author Martin Schaller (04/2008)
562 */
563 void display_add(struct displaylist *displaylist, struct item *item, int count, struct point *pnt, char *label)
564 {
565         struct displayitem *di;
566         int len;
567         GList *l;
568         char *p;
569
570         len=sizeof(*di)+count*sizeof(*pnt);
571         if (label)
572                 len+=strlen(label)+1;
573
574         p=g_malloc(len);
575
576         di=(struct displayitem *)p;
577         di->displayed=0;
578         p+=sizeof(*di)+count*sizeof(*pnt);
579         di->item=*item;
580         if (label) {
581                 di->label=p;
582                 strcpy(di->label, label);
583         } else 
584                 di->label=NULL;
585         di->count=count;
586         memcpy(di->pnt, pnt, count*sizeof(*pnt));
587
588         l=g_hash_table_lookup(displaylist->dl, GINT_TO_POINTER(item->type));
589         l=g_list_prepend(l, di);
590         g_hash_table_insert(displaylist->dl, GINT_TO_POINTER(item->type), l);
591 }
592
593
594 /**
595  * FIXME
596  * @param <>
597  * @returns <>
598  * @author Martin Schaller (04/2008)
599 */
600 static void label_line(struct graphics *gra, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font, struct point *p, int count, char *label)
601 {
602         int i,x,y,tl;
603         double dx,dy,l;
604         struct point p_t;
605
606         tl=strlen(label)*400;
607         for (i = 0 ; i < count-1 ; i++) {
608                 dx=p[i+1].x-p[i].x;
609                 dx*=100;
610                 dy=p[i+1].y-p[i].y;
611                 dy*=100;
612                 l=(int)sqrt((float)(dx*dx+dy*dy));
613                 if (l > tl) {
614                         x=p[i].x;
615                         y=p[i].y;
616                         if (dx < 0) {
617                                 dx=-dx;
618                                 dy=-dy;
619                                 x=p[i+1].x;
620                                 y=p[i+1].y;
621                         }
622                         x+=(l-tl)*dx/l/200;
623                         y+=(l-tl)*dy/l/200;
624                         x-=dy*45/l/10;
625                         y+=dx*45/l/10;
626                         p_t.x=x;
627                         p_t.y=y;
628         #if 0
629                         printf("display_text: '%s', %d, %d, %d, %d %d\n", label, x, y, dx*0x10000/l, dy*0x10000/l, l);
630         #endif
631                         gra->meth.draw_text(gra->priv, fg->priv, bg->priv, font->priv, label, &p_t, dx*0x10000/l, dy*0x10000/l);
632                 }
633         }
634 }
635
636 static void display_draw_arrow(struct point *p, int dx, int dy, int l, struct graphics_gc *gc, struct graphics *gra)
637 {
638         struct point pnt[3];
639         pnt[0]=pnt[1]=pnt[2]=*p;
640         pnt[0].x+=-dx*l/65536+dy*l/65536;
641         pnt[0].y+=-dy*l/65536-dx*l/65536;
642         pnt[2].x+=-dx*l/65536-dy*l/65536;
643         pnt[2].y+=-dy*l/65536+dx*l/65536;
644         gra->meth.draw_lines(gra->priv, gc->priv, pnt, 3);
645 }
646
647 static void display_draw_arrows(struct displayitem *di, struct graphics_gc *gc, struct graphics *gra)
648 {
649         int i,dx,dy,l;
650         struct point p;
651         for (i = 0 ; i < di->count-1 ; i++) {
652                 dx=di->pnt[i+1].x-di->pnt[i].x; 
653                 dy=di->pnt[i+1].y-di->pnt[i].y;
654                 l=sqrt(dx*dx+dy*dy);
655                 if (l) {
656                         dx=dx*65536/l;
657                         dy=dy*65536/l;
658                         p=di->pnt[i];
659                         p.x+=dx*15/65536;
660                         p.y+=dy*15/65536;
661                         display_draw_arrow(&p, dx, dy, 10, gc, gra);
662                         p=di->pnt[i+1];
663                         p.x-=dx*15/65536;
664                         p.y-=dy*15/65536;
665                         display_draw_arrow(&p, dx, dy, 10, gc, gra);
666                 }
667         }
668 }
669
670 /**
671  * FIXME
672  * @param <>
673  * @returns <>
674  * @author Martin Schaller (04/2008)
675 */
676 static void xdisplay_draw_elements(struct graphics *gra, GHashTable *display_list, struct itemtype *itm)
677 {
678         struct element *e;
679         GList *l,*ls,*es,*types;
680         enum item_type type;
681         struct graphics_gc *gc = NULL;
682         struct graphics_image *img;
683         struct point p;
684         char path[PATH_MAX];
685
686         es=itm->elements;
687         while (es) {
688                 e=es->data;
689                 types=itm->type;
690                 while (types) {
691                         type=GPOINTER_TO_INT(types->data);
692                         ls=g_hash_table_lookup(display_list, GINT_TO_POINTER(type));
693                         l=ls;
694                         if (gc)
695                                 graphics_gc_destroy(gc);
696                         gc=NULL;
697                         img=NULL;
698                         while (l) {
699                                 struct displayitem *di;
700                                 di=l->data;
701                                 di->displayed=1;
702                                 if (! gc) {
703                                         gc=graphics_gc_new(gra);
704                                         gc->meth.gc_set_foreground(gc->priv, &e->color);
705                                 }
706                                 switch (e->type) {
707                                 case element_polygon:
708                                         gra->meth.draw_polygon(gra->priv, gc->priv, di->pnt, di->count);
709                                         break;
710                                 case element_polyline:
711                                         if (e->u.polyline.width > 1) 
712                                                 gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
713                                         if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0)
714                                                 graphics_gc_set_dashes(gc, e->u.polyline.width, 
715                                                                        e->u.polyline.dash_offset,
716                                                                        e->u.polyline.dash_table,
717                                                                        e->u.polyline.dash_num);
718                                         gra->meth.draw_lines(gra->priv, gc->priv, di->pnt, di->count);
719                                         break;
720                                 case element_circle:
721                                         if (e->u.circle.width > 1) 
722                                                 gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
723                                         gra->meth.draw_circle(gra->priv, gc->priv, &di->pnt[0], e->u.circle.radius);
724                                         if (di->label && e->label_size) {
725                                                 p.x=di->pnt[0].x+3;
726                                                 p.y=di->pnt[0].y+10;
727                                                 if (! gra->font[e->label_size])
728                                                         gra->font[e->label_size]=graphics_font_new(gra, e->label_size*20, 0);
729                                                 gra->meth.draw_text(gra->priv, gra->gc[2]->priv, gra->gc[1]->priv, gra->font[e->label_size]->priv, di->label, &p, 0x10000, 0);
730                                         }
731                                         break;
732                                 case element_label:
733                                         if (di->label) {
734                                                 if (! gra->font[e->label_size])
735                                                         gra->font[e->label_size]=graphics_font_new(gra, e->label_size*20, 0);
736                                                 label_line(gra, gra->gc[2], gra->gc[1], gra->font[e->label_size], di->pnt, di->count, di->label);
737                                         }
738                                         break;
739                                 case element_icon:
740                                         if (!img) {
741                                                 sprintf(path,"%s/xpm/%s", navit_sharedir, e->u.icon.src);
742                                                 img=graphics_image_new(gra, path);
743                                                 if (! img)
744                                                         dbg(0,"failed to load icon '%s'\n", e->u.icon.src);
745                                         }
746                                         if (img) {
747                                                 p.x=di->pnt[0].x - img->hot.x;
748                                                 p.y=di->pnt[0].y - img->hot.y;
749                                                 gra->meth.draw_image(gra->priv, gra->gc[0]->priv, &p, img->priv);
750                                                 graphics_image_free(gra, img);
751                                                 img = NULL;
752                                         }
753                                         break;
754                                 case element_image:
755                                         dbg(1,"image: '%s'\n", di->label);
756                                         if (gra->meth.draw_image_warp)
757                                                 gra->meth.draw_image_warp(gra->priv, gra->gc[0]->priv, di->pnt, di->count, di->label);
758                                         else
759                                                 dbg(0,"draw_image_warp not supported by graphics driver drawing '%s'\n", di->label);
760                                         break;
761                                 case element_arrows:
762                                         display_draw_arrows(di,gc,gra);
763                                         break;
764                                 default:
765                                         printf("Unhandled element type %d\n", e->type);
766                                 
767                                 }
768                                 l=g_list_next(l);
769                         }
770                         types=g_list_next(types);
771                 }
772                 es=g_list_next(es);
773         }
774         if (gc)
775                 graphics_gc_destroy(gc);
776 }
777
778 /**
779  * FIXME
780  * @param <>
781  * @returns <>
782  * @author Martin Schaller (04/2008)
783 */
784 static void xdisplay_draw_layer(GHashTable *display_list, struct graphics *gra, struct layer *lay, int order)
785 {
786         GList *itms;
787         struct itemtype *itm;
788
789         itms=lay->itemtypes;
790         while (itms) {
791                 itm=itms->data;
792                 if (order >= itm->order_min && order <= itm->order_max) 
793                         xdisplay_draw_elements(gra, display_list, itm);
794                 itms=g_list_next(itms);
795         }
796 }
797
798 /**
799  * FIXME
800  * @param <>
801  * @returns <>
802  * @author Martin Schaller (04/2008)
803 */
804 static void xdisplay_draw(GHashTable *display_list, struct graphics *gra, struct layout *l, int order)
805 {
806         GList *lays;
807         struct layer *lay;
808         
809         lays=l->layers;
810         while (lays) {
811                 lay=lays->data;
812                 xdisplay_draw_layer(display_list, gra, lay, order);
813                 lays=g_list_next(lays);
814         }
815 }
816
817 /**
818  * FIXME
819  * @param <>
820  * @returns <>
821  * @author Martin Schaller (04/2008)
822 */
823 extern void *route_selection;
824
825 /**
826  * FIXME
827  * @param <>
828  * @returns <>
829  * @author Martin Schaller (04/2008)
830 */
831 static void do_draw_map(struct displaylist *displaylist, struct transformation *t, struct map *m, int order)
832 {
833         enum projection pro;
834         struct map_rect *mr;
835         struct item *item;
836         int conv,count,max=16384;
837         struct point pnt[max];
838         struct coord ca[max];
839         struct attr attr;
840         struct map_selection *sel;
841
842         pro=map_projection(m);
843         conv=map_requires_conversion(m);
844         sel=transform_get_selection(t, pro, order);
845         if (route_selection)
846                 mr=map_rect_new(m, route_selection);
847         else
848                 mr=map_rect_new(m, sel);
849         if (! mr) {
850                 map_selection_destroy(sel);
851                 return;
852         }
853         while ((item=map_rect_get_item(mr))) {
854                 count=item_coord_get(item, ca, item->type < type_line ? 1: max);
855                 if (item->type >= type_line && count < 2) {
856                         dbg(1,"poly from map has only %d points\n", count);
857                         continue;
858                 }
859                 if (item->type < type_line) {
860                         if (! map_selection_contains_point(sel, &ca[0])) {
861                                 dbg(1,"point not visible\n");
862                                 continue;
863                         }
864                 } else if (item->type < type_area) {
865                         if (! map_selection_contains_polyline(sel, ca, count)) {
866                                 dbg(1,"polyline not visible\n");
867                                 continue;
868                         }
869                 } else {
870                         if (! map_selection_contains_polygon(sel, ca, count)) {
871                                 dbg(1,"polygon not visible\n");
872                                 continue;
873                         }
874                 }
875                 if (count == max) 
876                         dbg(0,"point count overflow\n", count);
877                 count=transform(t, pro, ca, pnt, count, 1);
878                 if (item->type >= type_line && count < 2) {
879                         dbg(1,"poly from transform has only %d points\n", count);
880                         continue;
881                 }
882                 if (!item_attr_get(item, attr_label, &attr))
883                         attr.u.str=NULL;
884                 if (conv && attr.u.str && attr.u.str[0]) {
885                         char *str=map_convert_string(m, attr.u.str);
886                         display_add(displaylist, item, count, pnt, str);
887                         map_convert_free(str);
888                 } else
889                         display_add(displaylist, item, count, pnt, attr.u.str);
890         }
891         map_rect_destroy(mr);
892         map_selection_destroy(sel);
893 }
894
895 /**
896  * FIXME
897  * @param <>
898  * @returns <>
899  * @author Martin Schaller (04/2008)
900 */
901 static void do_draw(struct displaylist *displaylist, struct transformation *t, GList *mapsets, int order)
902 {
903         struct mapset *ms;
904         struct map *m;
905         struct mapset_handle *h;
906
907         if (! mapsets)
908                 return;
909         ms=mapsets->data;
910         h=mapset_open(ms);
911         while ((m=mapset_next(h, 1))) {
912                 do_draw_map(displaylist, t, m, order);
913         }
914         mapset_close(h);
915 }
916
917 /**
918  * FIXME
919  * @param <>
920  * @returns <>
921  * @author Martin Schaller (04/2008)
922 */
923 int graphics_ready(struct graphics *this_)
924 {
925         return this_->ready;
926 }
927
928 /**
929  * FIXME
930  * @param <>
931  * @returns <>
932  * @author Martin Schaller (04/2008)
933 */
934 void graphics_displaylist_draw(struct graphics *gra, struct displaylist *displaylist, struct transformation *trans, struct layout *l, int callback)
935 {
936         int order=transform_get_order(trans);
937         struct point p;
938         p.x=0;
939         p.y=0;
940         // FIXME find a better place to set the background color
941         graphics_gc_set_background(gra->gc[0], &l->color);
942         graphics_gc_set_foreground(gra->gc[0], &l->color);
943         gra->default_font = g_strdup(l->font);
944         gra->meth.background_gc(gra->priv, gra->gc[0]->priv);
945         gra->meth.draw_mode(gra->priv, draw_mode_begin);
946         gra->meth.draw_rectangle(gra->priv, gra->gc[0]->priv, &p, 32767, 32767);
947         xdisplay_draw(displaylist->dl, gra, l, order+l->order_delta);
948         if (callback)
949                 callback_list_call_attr_0(gra->cbl, attr_postdraw);
950         gra->meth.draw_mode(gra->priv, draw_mode_end);
951 }
952
953 /**
954  * FIXME
955  * @param <>
956  * @returns <>
957  * @author Martin Schaller (04/2008)
958 */
959 void graphics_displaylist_move(struct displaylist *displaylist, int dx, int dy)
960 {
961         struct displaylist_handle *dlh;
962         struct displayitem *di;
963         int i;
964
965         dlh=graphics_displaylist_open(displaylist);
966         while ((di=graphics_displaylist_next(dlh))) {
967                 for (i = 0 ; i < di->count ; i++) {
968                         di->pnt[i].x+=dx;
969                         di->pnt[i].y+=dy;
970                 }
971         }
972         graphics_displaylist_close(dlh);
973 }
974
975 /**
976  * FIXME
977  * @param <>
978  * @returns <>
979  * @author Martin Schaller (04/2008)
980 */
981 void graphics_draw(struct graphics *gra, struct displaylist *displaylist, GList *mapsets, struct transformation *trans, struct layout *l)
982 {
983         int order=transform_get_order(trans);
984
985         dbg(1,"enter");
986
987 #if 0
988         printf("scale=%d center=0x%x,0x%x mercator scale=%f\n", scale, co->trans->center.x, co->trans->center.y, transform_scale(co->trans->center.y));
989 #endif
990         
991         xdisplay_free(displaylist->dl);
992         dbg(1,"order=%d\n", order);
993
994
995 #if 0
996         for (i = 0 ; i < data_window_type_end; i++) {
997                 data_window_begin(co->data_window[i]);  
998         }
999 #endif
1000         profile(0,NULL);
1001         order+=l->order_delta;
1002         do_draw(displaylist, trans, mapsets, order);
1003 //      profile(1,"do_draw");
1004         graphics_displaylist_draw(gra, displaylist, trans, l, 1);
1005         profile(1,"xdisplay_draw");
1006         profile(0,"end");
1007   
1008 #if 0
1009         for (i = 0 ; i < data_window_type_end; i++) {
1010                 data_window_end(co->data_window[i]);    
1011         }
1012 #endif
1013         gra->ready=1;
1014 }
1015
1016 /**
1017  * FIXME
1018  * @param <>
1019  * @returns <>
1020  * @author Martin Schaller (04/2008)
1021 */
1022 struct displaylist_handle {
1023         GList *hl_head,*hl,*l;
1024 };
1025
1026 /**
1027  * FIXME
1028  * @param <>
1029  * @returns <>
1030  * @author Martin Schaller (04/2008)
1031 */
1032 struct displaylist_handle * graphics_displaylist_open(struct displaylist *displaylist)
1033 {
1034         struct displaylist_handle *ret;
1035
1036         ret=g_new0(struct displaylist_handle, 1);
1037         ret->hl_head=ret->hl=g_hash_to_list(displaylist->dl);
1038
1039         return ret;
1040 }
1041
1042 /**
1043  * FIXME
1044  * @param <>
1045  * @returns <>
1046  * @author Martin Schaller (04/2008)
1047 */
1048 struct displayitem * graphics_displaylist_next(struct displaylist_handle *dlh)
1049 {
1050         struct displayitem *ret;
1051         if (! dlh->l) {
1052                 if (!dlh->hl)
1053                         return NULL;
1054                 dlh->l=dlh->hl->data;
1055                 dlh->hl=g_list_next(dlh->hl);
1056         }
1057         ret=dlh->l->data;
1058         dlh->l=g_list_next(dlh->l);
1059         return ret;
1060 }
1061
1062 /**
1063  * FIXME
1064  * @param <>
1065  * @returns <>
1066  * @author Martin Schaller (04/2008)
1067 */
1068 void graphics_displaylist_close(struct displaylist_handle *dlh)
1069 {
1070         g_list_free(dlh->hl_head);
1071         g_free(dlh);
1072 }
1073
1074 /**
1075  * FIXME
1076  * @param <>
1077  * @returns <>
1078  * @author Martin Schaller (04/2008)
1079 */
1080 struct displaylist * graphics_displaylist_new(void)
1081 {
1082         struct displaylist *ret=g_new(struct displaylist, 1);
1083
1084         ret->dl=g_hash_table_new(NULL,NULL);
1085
1086         return ret;
1087 }
1088
1089 /**
1090  * FIXME
1091  * @param <>
1092  * @returns <>
1093  * @author Martin Schaller (04/2008)
1094 */
1095 struct item * graphics_displayitem_get_item(struct displayitem *di)
1096 {
1097         return &di->item;       
1098 }
1099
1100 /**
1101  * FIXME
1102  * @param <>
1103  * @returns <>
1104  * @author Martin Schaller (04/2008)
1105 */
1106 char * graphics_displayitem_get_label(struct displayitem *di)
1107 {
1108         return di->label;
1109 }
1110
1111 /**
1112  * FIXME
1113  * @param <>
1114  * @returns <>
1115  * @author Martin Schaller (04/2008)
1116 */
1117 static int within_dist_point(struct point *p0, struct point *p1, int dist)
1118 {
1119         if (p0->x == 32767 || p0->y == 32767 || p1->x == 32767 || p1->y == 32767)
1120                 return 0;
1121         if (p0->x == -32768 || p0->y == -32768 || p1->x == -32768 || p1->y == -32768)
1122                 return 0;
1123         if ((p0->x-p1->x)*(p0->x-p1->x) + (p0->y-p1->y)*(p0->y-p1->y) <= dist*dist) {
1124                 return 1;
1125         }
1126         return 0;
1127 }
1128
1129 /**
1130  * FIXME
1131  * @param <>
1132  * @returns <>
1133  * @author Martin Schaller (04/2008)
1134 */
1135 static int within_dist_line(struct point *p, struct point *line_p0, struct point *line_p1, int dist)
1136 {
1137         int vx,vy,wx,wy;
1138         int c1,c2;
1139         struct point line_p;
1140
1141         vx=line_p1->x-line_p0->x;
1142         vy=line_p1->y-line_p0->y;
1143         wx=p->x-line_p0->x;
1144         wy=p->y-line_p0->y;
1145
1146         c1=vx*wx+vy*wy;
1147         if ( c1 <= 0 )
1148                 return within_dist_point(p, line_p0, dist);
1149         c2=vx*vx+vy*vy;
1150         if ( c2 <= c1 )
1151                 return within_dist_point(p, line_p1, dist);
1152
1153         line_p.x=line_p0->x+vx*c1/c2;
1154         line_p.y=line_p0->y+vy*c1/c2;
1155         return within_dist_point(p, &line_p, dist);
1156 }
1157
1158 /**
1159  * FIXME
1160  * @param <>
1161  * @returns <>
1162  * @author Martin Schaller (04/2008)
1163 */
1164 static int within_dist_polyline(struct point *p, struct point *line_pnt, int count, int dist, int close)
1165 {
1166         int i;
1167         for (i = 0 ; i < count-1 ; i++) {
1168                 if (within_dist_line(p,line_pnt+i,line_pnt+i+1,dist)) {
1169                         return 1;
1170                 }
1171         }
1172         if (close)
1173                 return (within_dist_line(p,line_pnt,line_pnt+count-1,dist));
1174         return 0;
1175 }
1176
1177 /**
1178  * FIXME
1179  * @param <>
1180  * @returns <>
1181  * @author Martin Schaller (04/2008)
1182 */
1183 static int within_dist_polygon(struct point *p, struct point *poly_pnt, int count, int dist)
1184 {
1185         int i, j, c = 0;
1186         for (i = 0, j = count-1; i < count; j = i++) {
1187                 if ((((poly_pnt[i].y <= p->y) && ( p->y < poly_pnt[j].y )) ||
1188                 ((poly_pnt[j].y <= p->y) && ( p->y < poly_pnt[i].y))) &&
1189                 (p->x < (poly_pnt[j].x - poly_pnt[i].x) * (p->y - poly_pnt[i].y) / (poly_pnt[j].y - poly_pnt[i].y) + poly_pnt[i].x)) 
1190                         c = !c;
1191         }
1192         if (! c)
1193                 return within_dist_polyline(p, poly_pnt, count, dist, 1);
1194         return c;
1195 }
1196
1197 /**
1198  * FIXME
1199  * @param <>
1200  * @returns <>
1201  * @author Martin Schaller (04/2008)
1202 */
1203 int graphics_displayitem_within_dist(struct displayitem *di, struct point *p, int dist)
1204 {
1205         if (di->item.type < type_line) {
1206                 return within_dist_point(p, &di->pnt[0], dist);
1207         }
1208         if (di->item.type < type_area) {
1209                 return within_dist_polyline(p, di->pnt, di->count, dist, 0);
1210         }
1211         return within_dist_polygon(p, di->pnt, di->count, dist);
1212 }