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