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