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