Fix:core:Try to fix n800 build again.
[profile/ivi/navit.git] / navit / 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 <stdlib.h>
30 #include <glib.h>
31 #include <stdio.h>
32 #include <math.h>
33 #include "config.h"
34 #include "debug.h"
35 #include "string.h"
36 #include "draw_info.h"
37 #include "point.h"
38 #include "graphics.h"
39 #include "projection.h"
40 #include "item.h"
41 #include "map.h"
42 #include "coord.h"
43 #include "transform.h"
44 #include "plugin.h"
45 #include "profile.h"
46 #include "mapset.h"
47 #include "layout.h"
48 #include "route.h"
49 #include "util.h"
50 #include "callback.h"
51 #include "file.h"
52 #include "event.h"
53
54
55 //##############################################################################################################
56 //# Description:
57 //# Comment:
58 //# Authors: Martin Schaller (04/2008)
59 //##############################################################################################################
60 struct graphics
61 {
62         struct graphics* parent;
63         struct graphics_priv *priv;
64         struct graphics_methods meth;
65         char *default_font;
66         int font_len;
67         struct graphics_font **font;
68         struct graphics_gc *gc[3];
69         struct attr **attrs;
70         struct callback_list *cbl;
71         struct point_rect r;
72         int gamma,brightness,contrast;
73         int colormgmt;
74         int font_size;
75         GList *selection;
76         int disabled;
77         /*
78          * Counter for z_order of displayitems;
79         */
80         int current_z_order;
81         GHashTable *image_cache_hash;
82 };
83
84 struct display_context
85 {
86         struct graphics *gra;
87         struct element *e;
88         struct graphics_gc *gc;
89         struct graphics_gc *gc_background;
90         struct graphics_image *img;
91         enum projection pro;
92         int mindist;
93         struct transformation *trans;
94         enum item_type type;
95         int maxlen;
96 };
97
98 #define HASH_SIZE 1024
99 struct hash_entry
100 {
101         enum item_type type;
102         struct displayitem *di;
103 };
104
105
106 struct displaylist {
107         int busy;
108         int workload;
109         struct callback *cb;
110         struct layout *layout, *layout_hashed;
111         struct display_context dc;
112         int order, order_hashed, max_offset;
113         struct mapset *ms;
114         struct mapset_handle *msh;
115         struct map *m;
116         int conv;
117         struct map_selection *sel;
118         struct map_rect *mr;
119         struct callback *idle_cb;
120         struct event_idle *idle_ev;
121         unsigned int seq;
122         struct hash_entry hash_entries[HASH_SIZE];
123 };
124
125
126 struct displaylist_icon_cache {
127         unsigned int seq;
128
129 };
130
131 static void draw_circle(struct point *pnt, int diameter, int scale, int start, int len, struct point *res, int *pos, int dir);
132 static void graphics_process_selection(struct graphics *gra, struct displaylist *dl);
133 static void graphics_gc_init(struct graphics *this_);
134
135 static void
136 clear_hash(struct displaylist *dl)
137 {
138         int i;
139         for (i = 0 ; i < HASH_SIZE ; i++)
140                 dl->hash_entries[i].type=type_none;
141 }
142
143 static struct hash_entry *
144 get_hash_entry(struct displaylist *dl, enum item_type type)
145 {
146         int hashidx=(type*2654435761UL) & (HASH_SIZE-1);
147         int offset=dl->max_offset;
148         do {
149                 if (!dl->hash_entries[hashidx].type)
150                         return NULL;
151                 if (dl->hash_entries[hashidx].type == type)
152                         return &dl->hash_entries[hashidx];
153                 hashidx=(hashidx+1)&(HASH_SIZE-1);
154         } while (offset-- > 0);
155         return NULL;
156 }
157
158 static struct hash_entry *
159 set_hash_entry(struct displaylist *dl, enum item_type type)
160 {
161         int hashidx=(type*2654435761UL) & (HASH_SIZE-1);
162         int offset=0;
163         for (;;) {
164                 if (!dl->hash_entries[hashidx].type) {
165                         dl->hash_entries[hashidx].type=type;
166                         if (dl->max_offset < offset)
167                                 dl->max_offset=offset;
168                         return &dl->hash_entries[hashidx];
169                 }
170                 if (dl->hash_entries[hashidx].type == type)
171                         return &dl->hash_entries[hashidx];
172                 hashidx=(hashidx+1)&(HASH_SIZE-1);
173                 offset++;
174         }
175         return NULL;
176 }
177
178 static int
179 graphics_set_attr_do(struct graphics *gra, struct attr *attr)
180 {
181         switch (attr->type) {
182         case attr_gamma:
183                 gra->gamma=attr->u.num;
184                 break;
185         case attr_brightness:
186                 gra->brightness=attr->u.num;
187                 break;
188         case attr_contrast:
189                 gra->contrast=attr->u.num;
190                 break;
191         case attr_font_size:
192                 gra->font_size=attr->u.num;
193                 return 1;
194         default:
195                 return 0;
196         }
197         gra->colormgmt=(gra->gamma != 65536 || gra->brightness != 0 || gra->contrast != 65536);
198         graphics_gc_init(gra);
199         return 1;
200 }
201
202 int
203 graphics_set_attr(struct graphics *gra, struct attr *attr)
204 {
205         int ret=1;
206         dbg(0,"enter\n");
207         if (gra->meth.set_attr)
208                 ret=gra->meth.set_attr(gra->priv, attr);
209         if (!ret)
210                 ret=graphics_set_attr_do(gra, attr);
211         return ret != 0;
212 }
213
214 void
215 graphics_set_rect(struct graphics *gra, struct point_rect *pr)
216 {
217         gra->r=*pr;
218 }
219
220 /**
221  * Creates a new graphics object
222  * attr type required
223  * @param <>
224  * @returns <>
225  * @author Martin Schaller (04/2008)
226 */
227 struct graphics * graphics_new(struct attr *parent, struct attr **attrs)
228 {
229         struct graphics *this_;
230         struct attr *type_attr;
231         struct graphics_priv * (*graphicstype_new)(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl);
232
233         if (! (type_attr=attr_search(attrs, NULL, attr_type))) {
234                 return NULL;
235         }
236
237         graphicstype_new=plugin_get_graphics_type(type_attr->u.str);
238         if (! graphicstype_new)
239                 return NULL;
240         this_=g_new0(struct graphics, 1);
241         this_->cbl=callback_list_new();
242         this_->priv=(*graphicstype_new)(parent->u.navit, &this_->meth, attrs, this_->cbl);
243         this_->attrs=attr_list_dup(attrs);
244         this_->brightness=0;
245         this_->contrast=65536;
246         this_->gamma=65536;
247         this_->font_size=20;
248         this_->image_cache_hash = g_hash_table_new_full(g_str_hash, g_str_equal,g_free,g_free);
249         while (*attrs) {
250                 graphics_set_attr_do(this_,*attrs);
251                 attrs++;
252         }
253         return this_;
254 }
255
256 /**
257  * FIXME
258  * @param <>
259  * @returns <>
260  * @author Martin Schaller (04/2008)
261 */
262 int graphics_get_attr(struct graphics *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
263 {
264         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
265 }
266
267 /**
268  * FIXME
269  * @param <>
270  * @returns <>
271  * @author Martin Schaller (04/2008)
272 */
273 struct graphics * graphics_overlay_new(struct graphics *parent, struct point *p, int w, int h, int alpha, int wraparound)
274 {
275         struct graphics *this_;
276         struct point_rect pr;
277         if (!parent->meth.overlay_new)
278                 return NULL;
279         this_=g_new0(struct graphics, 1);
280         this_->priv=parent->meth.overlay_new(parent->priv, &this_->meth, p, w, h, alpha, wraparound);
281         this_->image_cache_hash = parent->image_cache_hash;
282         this_->parent = parent;
283         pr.lu.x=0;
284         pr.lu.y=0;
285         pr.rl.x=w;
286         pr.rl.y=h;
287         this_->font_size=20;
288         graphics_set_rect(this_, &pr);
289         if (!this_->priv) {
290                 g_free(this_);
291                 this_=NULL;
292         }
293         return this_;
294 }
295
296 /**
297  * @brief Alters the size, position, alpha and wraparound for an overlay
298  *
299  * @param this_ The overlay's graphics struct
300  * @param p The new position of the overlay
301  * @param w The new width of the overlay
302  * @param h The new height of the overlay
303  * @param alpha The new alpha of the overlay
304  * @param wraparound The new wraparound of the overlay
305  */
306 void
307 graphics_overlay_resize(struct graphics *this_, struct point *p, int w, int h, int alpha, int wraparound)
308 {
309         if (! this_->meth.overlay_resize) {
310                 return;
311         }
312
313         this_->meth.overlay_resize(this_->priv, p, w, h, alpha, wraparound);
314 }
315
316 static void
317 graphics_gc_init(struct graphics *this_)
318 {
319         struct color background={ COLOR_BACKGROUND_ };
320         struct color black={ COLOR_BLACK_ };
321         struct color white={ COLOR_WHITE_ };
322         if (!this_->gc[0] || !this_->gc[1] || !this_->gc[2])
323                 return;
324         graphics_gc_set_background(this_->gc[0], &background );
325         graphics_gc_set_foreground(this_->gc[0], &background );
326         graphics_gc_set_background(this_->gc[1], &black );
327         graphics_gc_set_foreground(this_->gc[1], &white );
328         graphics_gc_set_background(this_->gc[2], &white );
329         graphics_gc_set_foreground(this_->gc[2], &black );
330 }
331
332
333
334 /**
335  * FIXME
336  * @param <>
337  * @returns <>
338  * @author Martin Schaller (04/2008)
339 */
340 void graphics_init(struct graphics *this_)
341 {
342         if (this_->gc[0])
343                 return;
344         this_->gc[0]=graphics_gc_new(this_);
345         this_->gc[1]=graphics_gc_new(this_);
346         this_->gc[2]=graphics_gc_new(this_);
347         graphics_gc_init(this_);
348         graphics_background_gc(this_, this_->gc[0]);
349 }
350
351 /**
352  * FIXME
353  * @param <>
354  * @returns <>
355  * @author Martin Schaller (04/2008)
356 */
357 void * graphics_get_data(struct graphics *this_, const char *type)
358 {
359         return (this_->meth.get_data(this_->priv, type));
360 }
361
362 void graphics_add_callback(struct graphics *this_, struct callback *cb)
363 {
364         callback_list_add(this_->cbl, cb);
365 }
366
367 void graphics_remove_callback(struct graphics *this_, struct callback *cb)
368 {
369         callback_list_remove(this_->cbl, cb);
370 }
371
372 /**
373  * FIXME
374  * @param <>
375  * @returns <>
376  * @author Martin Schaller (04/2008)
377 */
378 struct graphics_font * graphics_font_new(struct graphics *gra, int size, int flags)
379 {
380         struct graphics_font *this_;
381
382         this_=g_new0(struct graphics_font,1);
383         this_->priv=gra->meth.font_new(gra->priv, &this_->meth, gra->default_font, size, flags);
384         return this_;
385 }
386
387 struct graphics_font * graphics_named_font_new(struct graphics *gra, char *font, int size, int flags)
388 {
389         struct graphics_font *this_;
390
391         this_=g_new0(struct graphics_font,1);
392         this_->priv=gra->meth.font_new(gra->priv, &this_->meth, font, size, flags);
393         return this_;
394 }
395
396
397 /**
398  * Destroy graphics
399  * Called when navit exits
400  * @param gra The graphics instance
401  * @returns nothing
402  * @author David Tegze (02/2011)
403  */
404 void graphics_free(struct graphics *gra)
405 {
406         if (!gra)
407                 return;
408
409         /* If it's not an overlay, free the image cache. */
410         if(!gra->parent) {
411                 struct graphics_image *img;
412                 GList *ll, *l;
413
414                 /* We can't specify context (pointer to struct graphics) for g_hash_table_new to have it passed to free function
415                    so we have to free img->priv manually, the rest would be freed by g_hash_table_destroy. GHashTableIter isn't used because it
416                    broke n800 build at r5107.
417                 */
418                 for(ll=l=g_hash_to_list(gra->image_cache_hash);l;l=g_list_next(l)) {
419                         img=l->data;
420                         if (img && gra->meth.image_free)
421                                 gra->meth.image_free(gra->priv, img->priv);
422                 }
423                 g_list_free(ll);
424                 g_hash_table_destroy(gra->image_cache_hash);
425         }
426
427         graphics_gc_destroy(gra->gc[0]);
428         graphics_gc_destroy(gra->gc[1]);
429         graphics_gc_destroy(gra->gc[2]);
430         g_free(gra->default_font);
431         graphics_font_destroy_all(gra);
432         gra->meth.graphics_destroy(gra->priv);
433         g_free(gra);
434 }
435
436 /**
437  * Free all loaded fonts.
438  * Used when switching layouts.
439  * @param gra The graphics instance
440  * @returns nothing
441  * @author Sarah Nordstrom (05/2008)
442  */
443 void graphics_font_destroy_all(struct graphics *gra)
444 {
445         int i;
446         for(i = 0 ; i < gra->font_len; i++) {
447                 if(!gra->font[i]) continue;
448                 gra->font[i]->meth.font_destroy(gra->font[i]->priv);
449                 gra->font[i] = NULL;
450         }
451 }
452
453 /**
454  * FIXME
455  * @param <>
456  * @returns <>
457  * @author Martin Schaller (04/2008)
458 */
459 struct graphics_gc * graphics_gc_new(struct graphics *gra)
460 {
461         struct graphics_gc *this_;
462
463         this_=g_new0(struct graphics_gc,1);
464         this_->priv=gra->meth.gc_new(gra->priv, &this_->meth);
465         this_->gra=gra;
466         return this_;
467 }
468
469 /**
470  * FIXME
471  * @param <>
472  * @returns <>
473  * @author Martin Schaller (04/2008)
474 */
475 void graphics_gc_destroy(struct graphics_gc *gc)
476 {
477         if (!gc)
478             return;
479         gc->meth.gc_destroy(gc->priv);
480         g_free(gc);
481 }
482
483 static void
484 graphics_convert_color(struct graphics *gra, struct color *in, struct color *out)
485 {
486         *out=*in;
487         if (gra->brightness) {
488                 out->r+=gra->brightness;
489                 out->g+=gra->brightness;
490                 out->b+=gra->brightness;
491         }
492         if (gra->contrast != 65536) {
493                 out->r=out->r*gra->contrast/65536;
494                 out->g=out->g*gra->contrast/65536;
495                 out->b=out->b*gra->contrast/65536;
496         }
497         if (out->r < 0)
498                 out->r=0;
499         if (out->r > 65535)
500                 out->r=65535;
501         if (out->g < 0)
502                 out->g=0;
503         if (out->g > 65535)
504                 out->g=65535;
505         if (out->b < 0)
506                 out->b=0;
507         if (out->b > 65535)
508                 out->b=65535;
509         if (gra->gamma != 65536) {
510                 out->r=pow(out->r/65535.0,gra->gamma/65536.0)*65535.0;
511                 out->g=pow(out->g/65535.0,gra->gamma/65536.0)*65535.0;
512                 out->b=pow(out->b/65535.0,gra->gamma/65536.0)*65535.0;
513         }
514 }
515
516 /**
517  * FIXME
518  * @param <>
519  * @returns <>
520  * @author Martin Schaller (04/2008)
521 */
522 void graphics_gc_set_foreground(struct graphics_gc *gc, struct color *c)
523 {
524         struct color cn;
525         if (gc->gra->colormgmt) {
526                 graphics_convert_color(gc->gra, c, &cn);
527                 c=&cn;
528         }
529         gc->meth.gc_set_foreground(gc->priv, c);
530 }
531
532 /**
533  * FIXME
534  * @param <>
535  * @returns <>
536  * @author Martin Schaller (04/2008)
537 */
538 void graphics_gc_set_background(struct graphics_gc *gc, struct color *c)
539 {
540         struct color cn;
541         if (gc->gra->colormgmt) {
542                 graphics_convert_color(gc->gra, c, &cn);
543                 c=&cn;
544         }
545         gc->meth.gc_set_background(gc->priv, c);
546 }
547
548
549 /**
550  * FIXME
551  * @param <>
552  * @returns <>
553  * @author Martin Schaller (04/2008)
554 */
555 void graphics_gc_set_stipple(struct graphics_gc *gc, struct graphics_image *img)
556 {
557         gc->meth.gc_set_stipple(gc->priv, img ? img->priv : NULL);
558 }
559
560
561 /**
562  * FIXME
563  * @param <>
564  * @returns <>
565  * @author Martin Schaller (04/2008)
566 */
567 void graphics_gc_set_linewidth(struct graphics_gc *gc, int width)
568 {
569         gc->meth.gc_set_linewidth(gc->priv, width);
570 }
571
572 /**
573  * FIXME
574  * @param <>
575  * @returns <>
576  * @author Martin Schaller (04/2008)
577 */
578 void graphics_gc_set_dashes(struct graphics_gc *gc, int width, int offset, unsigned char dash_list[], int n)
579 {
580         if (gc->meth.gc_set_dashes)
581                 gc->meth.gc_set_dashes(gc->priv, width, offset, dash_list, n);
582 }
583
584 /**
585  * Create a new image from file path scaled to w and h pixels
586  * @param gra the graphics instance
587  * @param path path of the image to load
588  * @param w width to rescale to
589  * @param h height to rescale to
590  * @returns <>
591  * @author Martin Schaller (04/2008)
592 */
593 struct graphics_image * graphics_image_new_scaled(struct graphics *gra, char *path, int w, int h)
594 {
595         return graphics_image_new_scaled_rotated(gra, path, w, h, 0);
596 }
597
598 /**
599  * Create a new image from file path scaled to w and h pixels and possibly rotated
600  * @param gra the graphics instance
601  * @param path path of the image to load
602  * @param w width to rescale to
603  * @param h height to rescale to
604  * @param rotate angle to rotate the image. Warning, graphics might only support 90 degree steps here
605  * @returns <>
606  * @author Martin Schaller (04/2008)
607 */
608 struct graphics_image * graphics_image_new_scaled_rotated(struct graphics *gra, char *path, int w, int h, int rotate)
609 {
610         struct graphics_image *this_;
611         char* hash_key = g_strdup_printf("%s*%d*%d*%d",path,w,h,rotate);
612
613         if ( g_hash_table_lookup_extended( gra->image_cache_hash, hash_key, NULL, (gpointer)&this_) ) {
614                 g_free(hash_key);
615                 dbg(3,"Found cached image%sfor '%s'\n",this_?" ":" miss ",path);
616                 return this_;
617         }
618
619         this_=g_new0(struct graphics_image,1);
620         this_->height=h;
621         this_->width=w;
622
623         if(!this_->priv) {
624                 char *ext;
625                 char *s, *name, *new_name;
626                 int len=strlen(path);
627                 int i,k;
628                 int newwidth=-1, newheight=-1;
629
630                 ext=g_utf8_strrchr(path,-1,'.');
631                 i=path-ext+len;
632                 
633                 /* Dont allow too long or too short file name extensions*/
634                 if(ext && ((i>5) || (i<1)))
635                         ext=NULL;
636
637                 /* Search for _w_h name part, begin from char before extension if it exists */
638                 if(ext)
639                         s=ext-1;
640                 else
641                         s=path+len;
642                 
643                 k=1;
644                 while(s>path && g_ascii_isdigit(*s)) {
645                         if(newheight<0)
646                                 newheight=0;
647                         newheight+=(*s-'0')*k;
648                         k*=10;
649                         s--;
650                 }
651                 
652                 if(k>1 && s>path && *s=='_') {
653                         k=1;
654                         s--;
655                         while(s>path && g_ascii_isdigit(*s)) {
656                                 if(newwidth<0)
657                                         newwidth=0;
658                                 newwidth+=(*s-'0')*k;;
659                                 k*=10;
660                                 s--;
661                         }
662                 }
663                 
664                 if(k==1 || s<=path || *s!='_') {
665                         newwidth=-1;
666                         newheight=-1;
667                         if(ext)
668                                 s=ext;
669                         else
670                                 s=path+len;
671                                 
672                 }
673                 
674                 /* If exact h and w values were given as function parameters, they take precedence over values guessed from the image name */
675                 if(w!=-1)
676                         newwidth=w;
677                 if(h!=-1)
678                         newheight=h;
679                         
680                 name=g_strndup(path,s-path);
681                 for (i = 1 ; i < 6 ; i++) {
682                         new_name=NULL;
683                         switch (i) {
684                                 case 1:
685                                         /* The best variant both for cpu usage and quality would be prescaled png of a needed size */
686                                         if (newwidth != -1 && newheight != -1) {
687                                                 new_name=g_strdup_printf("%s_%d_%d.png", name, newwidth, newheight);
688                                         }
689                                         break;
690                                 case 2:
691                                         /* Try to load image by the exact name given by user. For example, if she wants to
692                                           scale some prescaled png variant to a new size given as function params, or have
693                                           default png image to be displayed unscaled. */
694                                         new_name=g_strdup(path);
695                                         break;
696                                 case 3:
697                                         /* Next, try uncompressed and compressed svgs as they should give best quality but 
698                                            rendering might take more cpu resources when the image is displayed for the first time */
699                                         new_name=g_strdup_printf("%s.svg", name);
700                                         break;
701                                 case 4:
702                                         new_name=g_strdup_printf("%s.svgz", name);
703                                         break;
704                                 case 5:
705                                         /* Scaling the default png to the needed size may give some quality loss */
706                                         new_name=g_strdup_printf("%s.png", name);
707                                         break;
708                                 case 6: 
709                                         /* xpm format is used as a last resort, because its not widely supported and we are moving to svg and png formats */
710                                         new_name=g_strdup_printf("%s.xpm", name);
711                                         break;
712                         }
713                         if (! new_name)
714                                 continue;
715
716                         this_->width=newwidth;
717                         this_->height=newheight;
718                         dbg(2,"Trying to load image '%s' for '%s' at %dx%d\n", new_name, path, newwidth, newheight);
719                         this_->priv=gra->meth.image_new(gra->priv, &this_->meth, new_name, &this_->width, &this_->height, &this_->hot, rotate);
720                         if (this_->priv) {
721                                 dbg(1,"Using image '%s' for '%s' at %dx%d\n", new_name, path, newwidth, newheight);
722                                 break;
723                         }
724                         g_free(new_name);
725                 }
726                 g_free(name);
727         }
728
729         if (! this_->priv) {
730                 dbg(0,"No image for '%s'\n", path);
731                 g_free(this_);
732                 this_=NULL;
733         }
734
735         g_hash_table_insert(gra->image_cache_hash, hash_key,  (gpointer)this_ );
736
737         return this_;
738 }
739
740 /**
741  * Create a new image from file path
742  * @param gra the graphics instance
743  * @param path path of the image to load
744  * @returns <>
745  * @author Martin Schaller (04/2008)
746 */
747 struct graphics_image * graphics_image_new(struct graphics *gra, char *path)
748 {
749         return graphics_image_new_scaled_rotated(gra, path, -1, -1, 0);
750 }
751
752 /**
753  * FIXME
754  * @param <>
755  * @returns <>
756  * @author Martin Schaller (04/2008)
757 */
758 void graphics_image_free(struct graphics *gra, struct graphics_image *img)
759 {
760         /* Image is cached inside gra->image_cache_hash. So it would be freed only when graphics is destroyed => Do nothing here. */
761 }
762
763 /**
764  * FIXME
765  * @param <>
766  * @returns <>
767  * @author Martin Schaller (04/2008)
768 */
769 void graphics_draw_restore(struct graphics *this_, struct point *p, int w, int h)
770 {
771         this_->meth.draw_restore(this_->priv, p, w, h);
772 }
773
774 /**
775  * FIXME
776  * @param <>
777  * @returns <>
778  * @author Martin Schaller (04/2008)
779 */
780 void graphics_draw_mode(struct graphics *this_, enum draw_mode_num mode)
781 {
782         this_->meth.draw_mode(this_->priv, mode);
783 }
784
785 /**
786  * FIXME
787  * @param <>
788  * @returns <>
789  * @author Martin Schaller (04/2008)
790 */
791 void graphics_draw_lines(struct graphics *this_, struct graphics_gc *gc, struct point *p, int count)
792 {
793         this_->meth.draw_lines(this_->priv, gc->priv, p, count);
794 }
795
796 /**
797  * FIXME
798  * @param <>
799  * @returns <>
800  * @author Martin Schaller (04/2008)
801 */
802 void graphics_draw_circle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int r)
803 {
804         struct point *pnt=g_alloca(sizeof(struct point)*(r*4+64));
805         int i=0;
806
807         if(this_->meth.draw_circle)
808                 this_->meth.draw_circle(this_->priv, gc->priv, p, r);
809         else
810         {
811                 draw_circle(p, r, 0, -1, 1026, pnt, &i, 1);
812                 pnt[i] = pnt[0];
813                 i++;
814                 this_->meth.draw_lines(this_->priv, gc->priv, pnt, i);
815         }
816 }
817
818 /**
819  * FIXME
820  * @param <>
821  * @returns <>
822  * @author Martin Schaller (04/2008)
823 */
824 void graphics_draw_rectangle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int w, int h)
825 {
826         this_->meth.draw_rectangle(this_->priv, gc->priv, p, w, h);
827 }
828
829 void graphics_draw_rectangle_rounded(struct graphics *this_, struct graphics_gc *gc, struct point *plu, int w, int h, int r, int fill)
830 {
831         struct point *p=g_alloca(sizeof(struct point)*(r*4+32));
832         struct point pi0={plu->x+r,plu->y+r};
833         struct point pi1={plu->x+w-r,plu->y+r};
834         struct point pi2={plu->x+w-r,plu->y+h-r};
835         struct point pi3={plu->x+r,plu->y+h-r};
836         int i=0;
837
838         draw_circle(&pi2, r*2, 0, -1, 258, p, &i, 1);
839         draw_circle(&pi1, r*2, 0, 255, 258, p, &i, 1);
840         draw_circle(&pi0, r*2, 0, 511, 258, p, &i, 1);
841         draw_circle(&pi3, r*2, 0, 767, 258, p, &i, 1);
842         p[i]=p[0];
843         i++;
844         if (fill)
845                 this_->meth.draw_polygon(this_->priv, gc->priv, p, i);
846         else
847                 this_->meth.draw_lines(this_->priv, gc->priv, p, i);
848 }
849
850
851 /**
852  * FIXME
853  * @param <>
854  * @returns <>
855  * @author Martin Schaller (04/2008)
856 */
857 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)
858 {
859         this_->meth.draw_text(this_->priv, gc1->priv, gc2 ? gc2->priv : NULL, font->priv, text, p, dx, dy);
860 }
861
862
863 /**
864  * FIXME
865  * @param <>
866  * @returns <>
867  * @author Martin Schaller (04/2008)
868 */
869 void graphics_get_text_bbox(struct graphics *this_, struct graphics_font *font, char *text, int dx, int dy, struct point *ret, int estimate)
870 {
871         this_->meth.get_text_bbox(this_->priv, font->priv, text, dx, dy, ret, estimate);
872 }
873
874 /**
875  * FIXME
876  * @param <>
877  * @returns <>
878  * @author Martin Schaller (04/2008)
879 */
880 void graphics_overlay_disable(struct graphics *this_, int disable)
881 {
882         this_->disabled = disable;
883         if (this_->meth.overlay_disable)
884                 this_->meth.overlay_disable(this_->priv, disable);
885 }
886
887 int  graphics_is_disabled(struct graphics *this_)
888 {
889         return this_->disabled || (this_->parent && this_->parent->disabled);
890 }
891
892 /**
893  * FIXME
894  * @param <>
895  * @returns <>
896  * @author Martin Schaller (04/2008)
897 */
898 void graphics_draw_image(struct graphics *this_, struct graphics_gc *gc, struct point *p, struct graphics_image *img)
899 {
900         this_->meth.draw_image(this_->priv, gc->priv, p, img->priv);
901 }
902
903
904 //##############################################################################################################
905 //# Description:
906 //# Comment:
907 //# Authors: Martin Schaller (04/2008)
908 //##############################################################################################################
909 int
910 graphics_draw_drag(struct graphics *this_, struct point *p)
911 {
912         if (!this_->meth.draw_drag)
913                 return 0;
914         this_->meth.draw_drag(this_->priv, p);
915         return 1;
916 }
917
918 void
919 graphics_background_gc(struct graphics *this_, struct graphics_gc *gc)
920 {
921         this_->meth.background_gc(this_->priv, gc ? gc->priv : NULL);
922 }
923
924 #include "attr.h"
925 #include "popup.h"
926 #include <stdio.h>
927
928
929 #if 0
930 //##############################################################################################################
931 //# Description:
932 //# Comment:
933 //# Authors: Martin Schaller (04/2008)
934 //##############################################################################################################
935 static void popup_view_html(struct popup_item *item, char *file)
936 {
937         char command[1024];
938         sprintf(command,"firefox %s", file);
939         system(command);
940 }
941
942 struct transformatin *tg;
943 enum projection pg;
944
945 //##############################################################################################################
946 //# Description:
947 //# Comment:
948 //# Authors: Martin Schaller (04/2008)
949 //##############################################################################################################
950 static void graphics_popup(struct display_list *list, struct popup_item **popup)
951 {
952         struct item *item;
953         struct attr attr;
954         struct map_rect *mr;
955         struct coord c;
956         struct popup_item *curr_item,*last=NULL;
957         item=list->data;
958         mr=map_rect_new(item->map, NULL, NULL, 0);
959         printf("id hi=0x%x lo=0x%x\n", item->id_hi, item->id_lo);
960         item=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
961         if (item) {
962                 if (item_attr_get(item, attr_name, &attr)) {
963                         curr_item=popup_item_new_text(popup,attr.u.str,1);
964                         if (item_attr_get(item, attr_info_html, &attr)) {
965                                 popup_item_new_func(&last,"HTML Info",1, popup_view_html, g_strdup(attr.u.str));
966                         }
967                         if (item_attr_get(item, attr_price_html, &attr)) {
968                                 popup_item_new_func(&last,"HTML Preis",2, popup_view_html, g_strdup(attr.u.str));
969                         }
970                         curr_item->submenu=last;
971                 }
972         }
973         map_rect_destroy(mr);
974 }
975 #endif
976
977
978 /**
979  * FIXME
980  * @param <>
981  * @returns <>
982  * @author Martin Schaller (04/2008)
983 */
984 struct displayitem {
985         struct displayitem *next;
986         struct item item;
987         char *label;
988         int z_order;
989         int count;
990         struct coord c[0];
991 };
992
993 /**
994  * FIXME
995  * @param <>
996  * @returns <>
997  * @author Martin Schaller (04/2008)
998 */
999 static void xdisplay_free(struct displaylist *dl)
1000 {
1001         int i;
1002         for (i = 0 ; i < HASH_SIZE ; i++) {
1003                 struct displayitem *di=dl->hash_entries[i].di;
1004                 while (di) {
1005                         struct displayitem *next=di->next;
1006                         g_free(di);
1007                         di=next;
1008                 }
1009                 dl->hash_entries[i].di=NULL;
1010         }
1011 }
1012
1013 /**
1014  * FIXME
1015  * @param <>
1016  * @returns <>
1017  * @author Martin Schaller (04/2008)
1018 */
1019 static void display_add(struct hash_entry *entry, struct item *item, int count, struct coord *c, char **label, int label_count)
1020 {
1021         struct displayitem *di;
1022         int len,i;
1023         char *p;
1024
1025         len=sizeof(*di)+count*sizeof(*c);
1026         if (label && label_count) {
1027                 for (i = 0 ; i < label_count ; i++) {
1028                         if (label[i])
1029                                 len+=strlen(label[i])+1;
1030                         else
1031                                 len++;
1032                 }
1033         }
1034         p=g_malloc(len);
1035
1036         di=(struct displayitem *)p;
1037         p+=sizeof(*di)+count*sizeof(*c);
1038         di->item=*item;
1039         di->z_order=0;
1040         if (label && label_count) {
1041                 di->label=p;
1042                 for (i = 0 ; i < label_count ; i++) {
1043                         if (label[i]) {
1044                                 strcpy(p, label[i]);
1045                                 p+=strlen(label[i])+1;
1046                         } else
1047                                 *p++='\0';
1048                 }
1049         } else
1050                 di->label=NULL;
1051         di->count=count;
1052         memcpy(di->c, c, count*sizeof(*c));
1053         di->next=entry->di;
1054         entry->di=di;
1055 }
1056
1057
1058 /**
1059  * FIXME
1060  * @param <>
1061  * @returns <>
1062  * @author Martin Schaller (04/2008)
1063 */
1064 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)
1065 {
1066         int i,x,y,tl,tlm,th,thm,tlsq,l;
1067         float lsq;
1068         double dx,dy;
1069         struct point p_t;
1070         struct point pb[5];
1071
1072         if (gra->meth.get_text_bbox) {
1073                 gra->meth.get_text_bbox(gra->priv, font->priv, label, 0x10000, 0x0, pb, 1);
1074                 tl=(pb[2].x-pb[0].x);
1075                 th=(pb[0].y-pb[1].y);
1076         } else {
1077                 tl=strlen(label)*4;
1078                 th=8;
1079         }
1080         tlm=tl*32;
1081         thm=th*36;
1082         tlsq = tlm*tlm;
1083         for (i = 0 ; i < count-1 ; i++) {
1084                 dx=p[i+1].x-p[i].x;
1085                 dx*=32;
1086                 dy=p[i+1].y-p[i].y;
1087                 dy*=32;
1088                 lsq = dx*dx+dy*dy;
1089                 if (lsq > tlsq) {
1090                         l=(int)sqrtf(lsq);
1091                         x=p[i].x;
1092                         y=p[i].y;
1093                         if (dx < 0) {
1094                                 dx=-dx;
1095                                 dy=-dy;
1096                                 x=p[i+1].x;
1097                                 y=p[i+1].y;
1098                         }
1099                         x+=(l-tlm)*dx/l/64;
1100                         y+=(l-tlm)*dy/l/64;
1101                         x-=dy*thm/l/64;
1102                         y+=dx*thm/l/64;
1103                         p_t.x=x;
1104                         p_t.y=y;
1105 #if 0
1106                         dbg(0,"display_text: '%s', %d, %d, %d, %d %d\n", label, x, y, dx*0x10000/l, dy*0x10000/l, l);
1107 #endif
1108                         if (x < gra->r.rl.x && x + tl > gra->r.lu.x && y + tl > gra->r.lu.y && y - tl < gra->r.rl.y)
1109                                 gra->meth.draw_text(gra->priv, fg->priv, bg?bg->priv:NULL, font->priv, label, &p_t, dx*0x10000/l, dy*0x10000/l);
1110                 }
1111         }
1112 }
1113
1114 static void display_draw_arrow(struct point *p, int dx, int dy, int l, struct graphics_gc *gc, struct graphics *gra)
1115 {
1116         struct point pnt[3];
1117         pnt[0]=pnt[1]=pnt[2]=*p;
1118         pnt[0].x+=-dx*l/65536+dy*l/65536;
1119         pnt[0].y+=-dy*l/65536-dx*l/65536;
1120         pnt[2].x+=-dx*l/65536-dy*l/65536;
1121         pnt[2].y+=-dy*l/65536+dx*l/65536;
1122         gra->meth.draw_lines(gra->priv, gc->priv, pnt, 3);
1123 }
1124
1125 static void display_draw_arrows(struct graphics *gra, struct graphics_gc *gc, struct point *pnt, int count)
1126 {
1127         int i,dx,dy,l;
1128         struct point p;
1129         for (i = 0 ; i < count-1 ; i++) {
1130                 dx=pnt[i+1].x-pnt[i].x;
1131                 dy=pnt[i+1].y-pnt[i].y;
1132                 l=sqrt(dx*dx+dy*dy);
1133                 if (l) {
1134                         dx=dx*65536/l;
1135                         dy=dy*65536/l;
1136                         p=pnt[i];
1137                         p.x+=dx*15/65536;
1138                         p.y+=dy*15/65536;
1139                         display_draw_arrow(&p, dx, dy, 10, gc, gra);
1140                         p=pnt[i+1];
1141                         p.x-=dx*15/65536;
1142                         p.y-=dy*15/65536;
1143                         display_draw_arrow(&p, dx, dy, 10, gc, gra);
1144                 }
1145         }
1146 }
1147
1148 static int
1149 intersection(struct point * a1, int adx, int ady, struct point * b1, int bdx, int bdy,
1150               struct point * res)
1151 {
1152         int n, a, b;
1153         n = bdy * adx - bdx * ady;
1154         a = bdx * (a1->y - b1->y) - bdy * (a1->x - b1->x);
1155         b = adx * (a1->y - b1->y) - ady * (a1->x - b1->x);
1156         if (n < 0) {
1157                 n = -n;
1158                 a = -a;
1159                 b = -b;
1160         }
1161 #if 0
1162         if (a < 0 || b < 0)
1163                 return 0;
1164         if (a > n || b > n)
1165                 return 0;
1166 #endif
1167         if (n == 0)
1168                 return 0;
1169         res->x = a1->x + a * adx / n;
1170         res->y = a1->y + a * ady / n;
1171         return 1;
1172 }
1173
1174 struct circle {
1175         short x,y,fowler;
1176 } circle64[]={
1177 {0,128,0},
1178 {13,127,13},
1179 {25,126,25},
1180 {37,122,38},
1181 {49,118,53},
1182 {60,113,67},
1183 {71,106,85},
1184 {81,99,104},
1185 {91,91,128},
1186 {99,81,152},
1187 {106,71,171},
1188 {113,60,189},
1189 {118,49,203},
1190 {122,37,218},
1191 {126,25,231},
1192 {127,13,243},
1193 {128,0,256},
1194 {127,-13,269},
1195 {126,-25,281},
1196 {122,-37,294},
1197 {118,-49,309},
1198 {113,-60,323},
1199 {106,-71,341},
1200 {99,-81,360},
1201 {91,-91,384},
1202 {81,-99,408},
1203 {71,-106,427},
1204 {60,-113,445},
1205 {49,-118,459},
1206 {37,-122,474},
1207 {25,-126,487},
1208 {13,-127,499},
1209 {0,-128,512},
1210 {-13,-127,525},
1211 {-25,-126,537},
1212 {-37,-122,550},
1213 {-49,-118,565},
1214 {-60,-113,579},
1215 {-71,-106,597},
1216 {-81,-99,616},
1217 {-91,-91,640},
1218 {-99,-81,664},
1219 {-106,-71,683},
1220 {-113,-60,701},
1221 {-118,-49,715},
1222 {-122,-37,730},
1223 {-126,-25,743},
1224 {-127,-13,755},
1225 {-128,0,768},
1226 {-127,13,781},
1227 {-126,25,793},
1228 {-122,37,806},
1229 {-118,49,821},
1230 {-113,60,835},
1231 {-106,71,853},
1232 {-99,81,872},
1233 {-91,91,896},
1234 {-81,99,920},
1235 {-71,106,939},
1236 {-60,113,957},
1237 {-49,118,971},
1238 {-37,122,986},
1239 {-25,126,999},
1240 {-13,127,1011},
1241 };
1242
1243 static void
1244 draw_circle(struct point *pnt, int diameter, int scale, int start, int len, struct point *res, int *pos, int dir)
1245 {
1246         struct circle *c;
1247
1248 #if 0
1249         dbg(0,"diameter=%d start=%d len=%d pos=%d dir=%d\n", diameter, start, len, *pos, dir);
1250 #endif
1251         int count=64;
1252         int end=start+len;
1253         int i,step;
1254         c=circle64;
1255         if (diameter > 128)
1256                 step=1;
1257         else if (diameter > 64)
1258                 step=2;
1259         else if (diameter > 24)
1260                 step=4;
1261         else if (diameter > 8)
1262                 step=8;
1263         else
1264                 step=16;
1265         if (len > 0) {
1266                 while (start < 0) {
1267                         start+=1024;
1268                         end+=1024;
1269                 }
1270                 while (end > 0) {
1271                         i=0;
1272                         while (i < count && c[i].fowler <= start)
1273                                 i+=step;
1274                         while (i < count && c[i].fowler < end) {
1275                                 if (1< *pos || 0<dir) {
1276                                         res[*pos].x=pnt->x+((c[i].x*diameter+128)>>8);
1277                                         res[*pos].y=pnt->y+((c[i].y*diameter+128)>>8);
1278                                         (*pos)+=dir;
1279                                 }
1280                                 i+=step;
1281                         }
1282                         end-=1024;
1283                         start-=1024;
1284                 }
1285         } else {
1286                 while (start > 1024) {
1287                         start-=1024;
1288                         end-=1024;
1289                 }
1290                 while (end < 1024) {
1291                         i=count-1;
1292                         while (i >= 0 && c[i].fowler >= start)
1293                                 i-=step;
1294                         while (i >= 0 && c[i].fowler > end) {
1295                                 if (1< *pos || 0<dir) {
1296                                         res[*pos].x=pnt->x+((c[i].x*diameter+128)>>8);
1297                                         res[*pos].y=pnt->y+((c[i].y*diameter+128)>>8);
1298                                         (*pos)+=dir;
1299                                 }
1300                                 i-=step;
1301                         }
1302                         start+=1024;
1303                         end+=1024;
1304                 }
1305         }
1306 }
1307
1308
1309 static int
1310 fowler(int dy, int dx)
1311 {
1312         int adx, ady;           /* Absolute Values of Dx and Dy */
1313         int code;               /* Angular Region Classification Code */
1314
1315         adx = (dx < 0) ? -dx : dx;      /* Compute the absolute values. */
1316         ady = (dy < 0) ? -dy : dy;
1317
1318         code = (adx < ady) ? 1 : 0;
1319         if (dx < 0)
1320                 code += 2;
1321         if (dy < 0)
1322                 code += 4;
1323
1324         switch (code) {
1325         case 0:
1326                 return (dx == 0) ? 0 : 128*ady / adx;   /* [  0, 45] */
1327         case 1:
1328                 return (256 - (128*adx / ady)); /* ( 45, 90] */
1329         case 3:
1330                 return (256 + (128*adx / ady)); /* ( 90,135) */
1331         case 2:
1332                 return (512 - (128*ady / adx)); /* [135,180] */
1333         case 6:
1334                 return (512 + (128*ady / adx)); /* (180,225] */
1335         case 7:
1336                 return (768 - (128*adx / ady)); /* (225,270) */
1337         case 5:
1338                 return (768 + (128*adx / ady)); /* [270,315) */
1339         case 4:
1340                 return (1024 - (128*ady / adx));/* [315,360) */
1341         }
1342         return 0;
1343 }
1344 static int
1345 int_sqrt(unsigned int n)
1346 {
1347         unsigned int h, p= 0, q= 1, r= n;
1348
1349         /* avoid q rollover */
1350         if(n >= (1<<(sizeof(n)*8-2))) {
1351                 q = 1<<(sizeof(n)*8-2);
1352         } else {
1353                 while ( q <= n ) {
1354                         q <<= 2;
1355                 }
1356                 q >>= 2;
1357         }
1358
1359         while ( q != 0 ) {
1360                 h = p + q;
1361                 p >>= 1;
1362                 if ( r >= h ) {
1363                         p += q;
1364                         r -= h;
1365                 }
1366                 q >>= 2;
1367         }
1368         return p;
1369 }
1370
1371 struct offset {
1372         int px,py,nx,ny;
1373 };
1374
1375 static void
1376 calc_offsets(int wi, int l, int dx, int dy, struct offset *res)
1377 {
1378         int x,y;
1379
1380         x = (dx * wi) / l;
1381         y = (dy * wi) / l;
1382         if (x < 0) {
1383                 res->nx = -x/2;
1384                 res->px = (x-1)/2;
1385         } else {
1386                 res->nx = -(x+1)/2;
1387                 res->px = x/2;
1388         }
1389         if (y < 0) {
1390                 res->ny = -y/2;
1391                 res->py = (y-1)/2;
1392         } else {
1393                 res->ny = -(y+1)/2;
1394                 res->py = y/2;
1395         }
1396 }
1397
1398 static void
1399 graphics_draw_polyline_as_polygon(struct graphics *gra, struct graphics_gc *gc, struct point *pnt, int count, int *width, int step)
1400 {
1401         int maxpoints=200;
1402         struct point *res=g_alloca(sizeof(struct point)*maxpoints);
1403         struct point pos, poso, neg, nego;
1404         int i, dx=0, dy=0, l=0, dxo=0, dyo=0;
1405         struct offset o,oo={0,0,0,0};
1406         int fow=0, fowo=0, delta;
1407         int wi, ppos = maxpoints/2, npos = maxpoints/2;
1408         int state,prec=5;
1409         int max_circle_points=20;
1410         int lscale=16;
1411         i=0;
1412         for (;;) {
1413                 wi=*width;
1414                 width+=step;
1415                 if (i < count - 1) {
1416                         int dxs,dys,lscales;
1417
1418                         dx = (pnt[i + 1].x - pnt[i].x);
1419                         dy = (pnt[i + 1].y - pnt[i].y);
1420 #if 0
1421                         l = int_sqrt(dx * dx * lscale * lscale + dy * dy * lscale * lscale);
1422 #else
1423                         dxs=dx*dx;
1424                        dys=dy*dy;
1425                        lscales=lscale*lscale;
1426                        if (dxs + dys > lscales)
1427                                l = int_sqrt(dxs+dys)*lscale;
1428                        else
1429                                l = int_sqrt((dxs+dys)*lscales);
1430 #endif
1431                         fow=fowler(-dy, dx);
1432                 }
1433                 if (! l)
1434                         l=1;
1435                 if (wi*lscale > 10000)
1436                         lscale=10000/wi;
1437                 dbg_assert(wi*lscale <= 10000);
1438                 calc_offsets(wi*lscale, l, dx, dy, &o);
1439                 pos.x = pnt[i].x + o.ny;
1440                 pos.y = pnt[i].y + o.px;
1441                 neg.x = pnt[i].x + o.py;
1442                 neg.y = pnt[i].y + o.nx;
1443                 if (! i)
1444                         state=0;
1445                 else if (i == count-1)
1446                         state=2;
1447                 else if (npos < max_circle_points || ppos >= maxpoints-max_circle_points)
1448                         state=3;
1449                 else
1450                         state=1;
1451                 switch (state) {
1452                 case 1:
1453                        if (fowo != fow) {
1454                                 poso.x = pnt[i].x + oo.ny;
1455                                 poso.y = pnt[i].y + oo.px;
1456                                 nego.x = pnt[i].x + oo.py;
1457                                 nego.y = pnt[i].y + oo.nx;
1458                                 delta=fowo-fow;
1459                                 if (delta < 0)
1460                                         delta+=1024;
1461                                 if (delta < 512) {
1462                                         if (intersection(&pos, dx, dy, &poso, dxo, dyo, &res[ppos]))
1463                                                 ppos++;
1464                                         res[--npos] = nego;
1465                                         --npos;
1466                                         draw_circle(&pnt[i], wi, prec, fowo-512, -delta, res, &npos, -1);
1467                                         res[npos] = neg;
1468                                 } else {
1469                                         res[ppos++] = poso;
1470                                         draw_circle(&pnt[i], wi, prec, fowo, 1024-delta, res, &ppos, 1);
1471                                         res[ppos++] = pos;
1472                                         if (intersection(&neg, dx, dy, &nego, dxo, dyo, &res[npos - 1]))
1473                                                 npos--;
1474                                 }
1475                         }
1476                         break;
1477                 case 2:
1478                 case 3:
1479                         res[--npos] = neg;
1480                         --npos;
1481                         draw_circle(&pnt[i], wi, prec, fow-512, -512, res, &npos, -1);
1482                         res[npos] = pos;
1483                         res[ppos++] = pos;
1484                         dbg_assert(npos > 0);
1485                         dbg_assert(ppos < maxpoints);
1486                         gra->meth.draw_polygon(gra->priv, gc->priv, res+npos, ppos-npos);
1487                         if (state == 2)
1488                                 break;
1489                         npos=maxpoints/2;
1490                         ppos=maxpoints/2;
1491                 case 0:
1492                         res[ppos++] = neg;
1493                         draw_circle(&pnt[i], wi, prec, fow+512, 512, res, &ppos, 1);
1494                         res[ppos++] = pos;
1495                         break;
1496                 }
1497                 i++;
1498                 if (i >= count)
1499                         break;
1500                 if (step) {
1501                         wi=*width;
1502                         calc_offsets(wi*lscale, l, dx, dy, &oo);
1503                 } else
1504                         oo=o;
1505                 dxo = -dx;
1506                 dyo = -dy;
1507                 fowo=fow;
1508         }
1509 }
1510
1511
1512 struct wpoint {
1513         int x,y,w;
1514 };
1515
1516 static int
1517 clipcode(struct wpoint *p, struct point_rect *r)
1518 {
1519         int code=0;
1520         if (p->x < r->lu.x)
1521                 code=1;
1522         if (p->x > r->rl.x)
1523                 code=2;
1524         if (p->y < r->lu.y)
1525                 code |=4;
1526         if (p->y > r->rl.y)
1527                 code |=8;
1528         return code;
1529 }
1530
1531
1532 static int
1533 clip_line(struct wpoint *p1, struct wpoint *p2, struct point_rect *r)
1534 {
1535         int code1,code2,ret=1;
1536         int dx,dy,dw;
1537         code1=clipcode(p1, r);
1538         if (code1)
1539                 ret |= 2;
1540         code2=clipcode(p2, r);
1541         if (code2)
1542                 ret |= 4;
1543         dx=p2->x-p1->x;
1544         dy=p2->y-p1->y;
1545         dw=p2->w-p1->w;
1546         while (code1 || code2) {
1547                 if (code1 & code2)
1548                         return 0;
1549                 if (code1 & 1) {
1550                         p1->y+=(r->lu.x-p1->x)*dy/dx;
1551                         p1->w+=(r->lu.x-p1->x)*dw/dx;
1552                         p1->x=r->lu.x;
1553                 } else if (code1 & 2) {
1554                         p1->y+=(r->rl.x-p1->x)*dy/dx;
1555                         p1->w+=(r->rl.x-p1->x)*dw/dx;
1556                         p1->x=r->rl.x;
1557                 } else if (code1 & 4) {
1558                         p1->x+=(r->lu.y-p1->y)*dx/dy;
1559                         p1->w+=(r->lu.y-p1->y)*dw/dy;
1560                         p1->y=r->lu.y;
1561                 } else if (code1 & 8) {
1562                         p1->x+=(r->rl.y-p1->y)*dx/dy;
1563                         p1->w+=(r->rl.y-p1->y)*dw/dy;
1564                         p1->y=r->rl.y;
1565                 }
1566                 code1=clipcode(p1, r);
1567                 if (code1 & code2)
1568                         return 0;
1569                 if (code2 & 1) {
1570                         p2->y+=(r->lu.x-p2->x)*dy/dx;
1571                         p2->w+=(r->lu.x-p2->x)*dw/dx;
1572                         p2->x=r->lu.x;
1573                 } else if (code2 & 2) {
1574                         p2->y+=(r->rl.x-p2->x)*dy/dx;
1575                         p2->w+=(r->rl.x-p2->x)*dw/dx;
1576                         p2->x=r->rl.x;
1577                 } else if (code2 & 4) {
1578                         p2->x+=(r->lu.y-p2->y)*dx/dy;
1579                         p2->w+=(r->lu.y-p2->y)*dw/dy;
1580                         p2->y=r->lu.y;
1581                 } else if (code2 & 8) {
1582                         p2->x+=(r->rl.y-p2->y)*dx/dy;
1583                         p2->w+=(r->rl.y-p2->y)*dw/dy;
1584                         p2->y=r->rl.y;
1585                 }
1586                 code2=clipcode(p2, r);
1587         }
1588         return ret;
1589 }
1590
1591 static void
1592 graphics_draw_polyline_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pa, int count, int *width, int step, int poly)
1593 {
1594         struct point *p=g_alloca(sizeof(struct point)*(count+1));
1595         int *w=g_alloca(sizeof(int)*(count*step+1));
1596         struct wpoint p1,p2;
1597         int i,code,out=0;
1598         int wmax;
1599         struct point_rect r=gra->r;
1600
1601         wmax=width[0];
1602         if (step) {
1603                 for (i = 1 ; i < count ; i++) {
1604                         if (width[i*step] > wmax)
1605                                 wmax=width[i*step];
1606                 }
1607         }
1608         if (wmax <= 0)
1609                 return;
1610         r.lu.x-=wmax;
1611         r.lu.y-=wmax;
1612         r.rl.x+=wmax;
1613         r.rl.y+=wmax;
1614         for (i = 0 ; i < count ; i++) {
1615                 if (i) {
1616                         p1.x=pa[i-1].x;
1617                         p1.y=pa[i-1].y;
1618                         p1.w=width[(i-1)*step];
1619                         p2.x=pa[i].x;
1620                         p2.y=pa[i].y;
1621                         p2.w=width[i*step];
1622                         /* 0 = invisible, 1 = completely visible, 3 = start point clipped, 5 = end point clipped, 7 both points clipped */
1623                         code=clip_line(&p1, &p2, &r);
1624                         if (((code == 1 || code == 5) && i == 1) || (code & 2)) {
1625                                 p[out].x=p1.x;
1626                                 p[out].y=p1.y;
1627                                 w[out*step]=p1.w;
1628                                 out++;
1629                         }
1630                         if (code) {
1631                                 p[out].x=p2.x;
1632                                 p[out].y=p2.y;
1633                                 w[out*step]=p2.w;
1634                                 out++;
1635                         }
1636                         if (i == count-1 || (code & 4)) {
1637                                 if (out > 1) {
1638                                         if (poly) {
1639                                                 graphics_draw_polyline_as_polygon(gra, gc, p, out, w, step);
1640                                         } else
1641                                                 gra->meth.draw_lines(gra->priv, gc->priv, p, out);
1642                                         out=0;
1643                                 }
1644                         }
1645                 }
1646         }
1647 }
1648
1649 static int
1650 is_inside(struct point *p, struct point_rect *r, int edge)
1651 {
1652         switch(edge) {
1653         case 0:
1654                 return p->x >= r->lu.x;
1655         case 1:
1656                 return p->x <= r->rl.x;
1657         case 2:
1658                 return p->y >= r->lu.y;
1659         case 3:
1660                 return p->y <= r->rl.y;
1661         default:
1662                 return 0;
1663         }
1664 }
1665
1666 static void
1667 poly_intersection(struct point *p1, struct point *p2, struct point_rect *r, int edge, struct point *ret)
1668 {
1669         int dx=p2->x-p1->x;
1670         int dy=p2->y-p1->y;
1671         switch(edge) {
1672         case 0:
1673                 ret->y=p1->y+(r->lu.x-p1->x)*dy/dx;
1674                 ret->x=r->lu.x;
1675                 break;
1676         case 1:
1677                 ret->y=p1->y+(r->rl.x-p1->x)*dy/dx;
1678                 ret->x=r->rl.x;
1679                 break;
1680         case 2:
1681                 ret->x=p1->x+(r->lu.y-p1->y)*dx/dy;
1682                 ret->y=r->lu.y;
1683                 break;
1684         case 3:
1685                 ret->x=p1->x+(r->rl.y-p1->y)*dx/dy;
1686                 ret->y=r->rl.y;
1687                 break;
1688         }
1689 }
1690
1691 static void
1692 graphics_draw_polygon_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pin, int count_in)
1693 {
1694         struct point_rect r=gra->r;
1695         struct point *pout,*p,*s,pi,*p1,*p2;
1696         int limit=10000;
1697         struct point *pa1=g_alloca(sizeof(struct point) * (count_in < limit ? count_in*8+1:0));
1698         struct point *pa2=g_alloca(sizeof(struct point) * (count_in < limit ? count_in*8+1:0));
1699         int count_out,edge=3;
1700         int i;
1701 #if 0
1702         r.lu.x+=20;
1703         r.lu.y+=20;
1704         r.rl.x-=20;
1705         r.rl.y-=20;
1706 #endif
1707         if (count_in < limit) {
1708                 p1=pa1;
1709                 p2=pa2;
1710         } else {
1711                 p1=g_new(struct point, count_in*8+1);
1712                 p2=g_new(struct point, count_in*8+1);
1713         }
1714
1715         pout=p1;
1716         for (edge = 0 ; edge < 4 ; edge++) {
1717                 p=pin;
1718                 s=pin+count_in-1;
1719                 count_out=0;
1720                 for (i = 0 ; i < count_in ; i++) {
1721                         if (is_inside(p, &r, edge)) {
1722                                 if (! is_inside(s, &r, edge)) {
1723                                         poly_intersection(s,p,&r,edge,&pi);
1724                                         pout[count_out++]=pi;
1725                                 }
1726                                 pout[count_out++]=*p;
1727                         } else {
1728                                 if (is_inside(s, &r, edge)) {
1729                                         poly_intersection(p,s,&r,edge,&pi);
1730                                         pout[count_out++]=pi;
1731                                 }
1732                         }
1733                         s=p;
1734                         p++;
1735                 }
1736                 count_in=count_out;
1737                 if (pin == p1) {
1738                         pin=p2;
1739                         pout=p1;
1740                 } else {
1741                         pin=p1;
1742                         pout=p2;
1743                 }
1744         }
1745         gra->meth.draw_polygon(gra->priv, gc->priv, pin, count_in);
1746         if (count_in >= limit) {
1747                 g_free(p1);
1748                 g_free(p2);
1749         }
1750 }
1751
1752
1753 static void
1754 display_context_free(struct display_context *dc)
1755 {
1756         if (dc->gc)
1757                 graphics_gc_destroy(dc->gc);
1758         if (dc->gc_background)
1759                 graphics_gc_destroy(dc->gc_background);
1760         if (dc->img)
1761                 graphics_image_free(dc->gra, dc->img);
1762         dc->gc=NULL;
1763         dc->gc_background=NULL;
1764         dc->img=NULL;
1765 }
1766
1767 static struct graphics_font *
1768 get_font(struct graphics *gra, int size)
1769 {
1770         if (size > 64)
1771                 size=64;
1772         if (size >= gra->font_len) {
1773                 gra->font=g_renew(struct graphics_font *, gra->font, size+1);
1774                 while (gra->font_len <= size)
1775                         gra->font[gra->font_len++]=NULL;
1776         }
1777         if (! gra->font[size])
1778                 gra->font[size]=graphics_font_new(gra, size*gra->font_size, 0);
1779         return gra->font[size];
1780 }
1781
1782 void graphics_draw_text_std(struct graphics *this_, int text_size, char *text, struct point *p)
1783 {
1784         struct graphics_font *font=get_font(this_, text_size);
1785         struct point bbox[4];
1786         int i;
1787
1788         graphics_get_text_bbox(this_, font, text, 0x10000, 0, bbox, 0);
1789         for (i = 0 ; i < 4 ; i++) {
1790                 bbox[i].x+=p->x;
1791                 bbox[i].y+=p->y;
1792         }
1793         graphics_draw_rectangle(this_, this_->gc[2], &bbox[1], bbox[2].x-bbox[0].x, bbox[0].y-bbox[1].y+5);
1794         graphics_draw_text(this_, this_->gc[1], this_->gc[2], font, text, p, 0x10000, 0);
1795 }
1796
1797 char *
1798 graphics_icon_path(char *icon)
1799 {
1800         static char *navit_sharedir;
1801         char *ret=NULL;
1802         struct file_wordexp *wordexp=NULL;
1803         dbg(1,"enter %s\n",icon);
1804         if (strchr(icon, '$')) {
1805                 wordexp=file_wordexp_new(icon);
1806                 if (file_wordexp_get_count(wordexp))
1807                         icon=file_wordexp_get_array(wordexp)[0];
1808         }
1809         if (strchr(icon,'/'))
1810                 ret=g_strdup(icon);
1811         else {
1812 #ifdef HAVE_API_ANDROID
1813                 // get resources for the correct screen density
1814                 //
1815                 // this part not needed, android unpacks only the correct version into res/drawable dir!
1816                 // dbg(1,"android icon_path %s\n",icon);
1817                 // static char *android_density;
1818                 // android_density = getenv("ANDROID_DENSITY");
1819                 // ret=g_strdup_printf("res/drawable-%s/%s",android_density ,icon);
1820                 ret=g_strdup_printf("res/drawable/%s" ,icon);
1821 #else
1822                 if (! navit_sharedir)
1823                         navit_sharedir = getenv("NAVIT_SHAREDIR");
1824                 ret=g_strdup_printf("%s/xpm/%s", navit_sharedir, icon);
1825 #endif
1826         }
1827         if (wordexp)
1828                 file_wordexp_destroy(wordexp);
1829         return ret;
1830 }
1831
1832 static int
1833 limit_count(struct coord *c, int count)
1834 {
1835         int i;
1836         for (i = 1 ; i < count ; i++) {
1837                 if (c[i].x == c[0].x && c[i].y == c[0].y)
1838                         return i+1;
1839         }
1840         return count;
1841 }
1842
1843
1844 static void
1845 displayitem_draw(struct displayitem *di, void *dummy, struct display_context *dc)
1846 {
1847         int *width=g_alloca(sizeof(int)*dc->maxlen);
1848         struct point *pa=g_alloca(sizeof(struct point)*dc->maxlen);
1849         struct graphics *gra=dc->gra;
1850         struct graphics_gc *gc=dc->gc;
1851         struct element *e=dc->e;
1852         struct graphics_image *img=dc->img;
1853         struct point p;
1854         char *path;
1855
1856         while (di) {
1857         int i,count=di->count,mindist=dc->mindist;
1858
1859         di->z_order=++(gra->current_z_order);
1860         
1861         if (! gc) {
1862                 gc=graphics_gc_new(gra);
1863                 graphics_gc_set_foreground(gc, &e->color);
1864                 dc->gc=gc;
1865         }
1866         if (item_type_is_area(dc->type) && (dc->e->type == element_polyline || dc->e->type == element_text))
1867                 count=limit_count(di->c, count);
1868         if (dc->type == type_poly_water_tiled)
1869                 mindist=0;
1870         if (dc->e->type == element_polyline)
1871                 count=transform(dc->trans, dc->pro, di->c, pa, count, mindist, e->u.polyline.width, width);
1872         else
1873                 count=transform(dc->trans, dc->pro, di->c, pa, count, mindist, 0, NULL);
1874         switch (e->type) {
1875         case element_polygon:
1876                 graphics_draw_polygon_clipped(gra, gc, pa, count);
1877                 break;
1878         case element_polyline:
1879                 {
1880                         gc->meth.gc_set_linewidth(gc->priv, 1);
1881                         if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0)
1882                                 graphics_gc_set_dashes(gc, e->u.polyline.width,
1883                                                        e->u.polyline.offset,
1884                                                        e->u.polyline.dash_table,
1885                                                        e->u.polyline.dash_num);
1886                         for (i = 0 ; i < count ; i++) {
1887                                 if (width[i] < 2)
1888                                         width[i]=2;
1889                         }
1890                         graphics_draw_polyline_clipped(gra, gc, pa, count, width, 1, e->u.polyline.width > 1);
1891                 }
1892                 break;
1893         case element_circle:
1894                 if (count) {
1895                         if (e->u.circle.width > 1)
1896                                 gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
1897                         graphics_draw_circle(gra, gc, pa, e->u.circle.radius);
1898                         if (di->label && e->text_size) {
1899                                 struct graphics_font *font=get_font(gra, e->text_size);
1900                                 struct graphics_gc *gc_background=dc->gc_background;
1901                                 if (! gc_background && e->u.circle.background_color.a) {
1902                                         gc_background=graphics_gc_new(gra);
1903                                         graphics_gc_set_foreground(gc_background, &e->u.circle.background_color);
1904                                         dc->gc_background=gc_background;
1905                                 }
1906                                 p.x=pa[0].x+3;
1907                                 p.y=pa[0].y+10;
1908                                 if (font)
1909                                         gra->meth.draw_text(gra->priv, gc->priv, gc_background?gc_background->priv:NULL, font->priv, di->label, &p, 0x10000, 0);
1910                                 else
1911                                         dbg(0,"Failed to get font with size %d\n",e->text_size);
1912                         }
1913                 }
1914                 break;
1915         case element_text:
1916                 if (count && di->label) {
1917                         struct graphics_font *font=get_font(gra, e->text_size);
1918                         struct graphics_gc *gc_background=dc->gc_background;
1919                         if (! gc_background && e->u.text.background_color.a) {
1920                                 gc_background=graphics_gc_new(gra);
1921                                 graphics_gc_set_foreground(gc_background, &e->u.text.background_color);
1922                                 dc->gc_background=gc_background;
1923                         }
1924                         if (font)
1925                                 label_line(gra, gc, gc_background, font, pa, count, di->label);
1926                         else
1927                                 dbg(0,"Failed to get font with size %d\n",e->text_size);
1928                 }
1929                 break;
1930         case element_icon:
1931                 if (count) {
1932                         if (!img || item_is_custom_poi(di->item)) {
1933                                 if (item_is_custom_poi(di->item)) {
1934                                         char *icon;
1935                                         char *src;
1936                                         if (img)
1937                                                 graphics_image_free(dc->gra, img);
1938                                         src=e->u.icon.src;
1939                                         if (!src || !src[0])
1940                                                 src="%s";
1941                                         icon=g_strdup_printf(src,di->label+strlen(di->label)+1);
1942                                         path=graphics_icon_path(icon);
1943                                         g_free(icon);
1944                                 } else
1945                                         path=graphics_icon_path(e->u.icon.src);
1946                                 img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation);
1947                                 if (img)
1948                                         dc->img=img;
1949                                 else
1950                                         dbg(0,"failed to load icon '%s'\n", path);
1951                                 g_free(path);
1952                         }
1953                         if (img) {
1954                                 p.x=pa[0].x - img->hot.x;
1955                                 p.y=pa[0].y - img->hot.y;
1956                                 gra->meth.draw_image(gra->priv, gra->gc[0]->priv, &p, img->priv);
1957                         }
1958                 }
1959                 break;
1960         case element_image:
1961                 dbg(1,"image: '%s'\n", di->label);
1962                 if (gra->meth.draw_image_warp)
1963                         gra->meth.draw_image_warp(gra->priv, gra->gc[0]->priv, pa, count, di->label);
1964                 else
1965                         dbg(0,"draw_image_warp not supported by graphics driver drawing '%s'\n", di->label);
1966                 break;
1967         case element_arrows:
1968                 display_draw_arrows(gra,gc,pa,count);
1969                 break;
1970         default:
1971                 dbg(0, "Unhandled element type %d\n", e->type);
1972
1973         }
1974         di=di->next;
1975         }
1976 }
1977 /**
1978  * FIXME
1979  * @param <>
1980  * @returns <>
1981  * @author Martin Schaller (04/2008)
1982 */
1983 static void xdisplay_draw_elements(struct graphics *gra, struct displaylist *display_list, struct itemgra *itm)
1984 {
1985         struct element *e;
1986         GList *es,*types;
1987         struct display_context *dc=&display_list->dc;
1988         struct hash_entry *entry;
1989
1990         es=itm->elements;
1991         while (es) {
1992                 e=es->data;
1993                 dc->e=e;
1994                 types=itm->type;
1995                 while (types) {
1996                         dc->type=GPOINTER_TO_INT(types->data);
1997                         entry=get_hash_entry(display_list, dc->type);
1998                         if (entry && entry->di) {
1999                                 displayitem_draw(entry->di, NULL, dc);
2000                                 display_context_free(dc);
2001                         }
2002                         types=g_list_next(types);
2003                 }
2004                 es=g_list_next(es);
2005         }
2006 }
2007
2008 void
2009 graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct transformation *t, char *label)
2010 {
2011         GList *es;
2012         struct display_context dc;
2013         int max_coord=32;
2014         char *buffer=g_alloca(sizeof(struct displayitem)+max_coord*sizeof(struct coord));
2015         struct displayitem *di=(struct displayitem *)buffer;
2016         es=itm->elements;
2017         di->item.type=type_none;
2018         di->item.id_hi=0;
2019         di->item.id_lo=0;
2020         di->item.map=NULL;
2021         di->z_order=0;
2022         di->label=label;
2023         dc.gra=gra;
2024         dc.gc=NULL;
2025         dc.gc_background=NULL;
2026         dc.img=NULL;
2027         dc.pro=projection_screen;
2028         dc.mindist=0;
2029         dc.trans=t;
2030         dc.type=type_none;
2031         dc.maxlen=max_coord;
2032         while (es) {
2033                 struct element *e=es->data;
2034                 if (e->coord_count) {
2035                         if (e->coord_count > max_coord) {
2036                                 dbg(0,"maximum number of coords reached: %d > %d\n",e->coord_count,max_coord);
2037                                 di->count=max_coord;
2038                         } else
2039                                 di->count=e->coord_count;
2040                         memcpy(di->c, e->coord, di->count*sizeof(struct coord));
2041                 } else {
2042                         di->c[0].x=0;
2043                         di->c[0].y=0;
2044                         di->count=1;
2045                 }
2046                 dc.e=e;
2047                 di->next=NULL;
2048                 displayitem_draw(di, NULL, &dc);
2049                 display_context_free(&dc);
2050                 es=g_list_next(es);
2051         }
2052 }
2053
2054 /**
2055  * FIXME
2056  * @param <>
2057  * @returns <>
2058  * @author Martin Schaller (04/2008)
2059 */
2060 static void xdisplay_draw_layer(struct displaylist *display_list, struct graphics *gra, struct layer *lay, int order)
2061 {
2062         GList *itms;
2063         struct itemgra *itm;
2064
2065         itms=lay->itemgras;
2066         while (itms) {
2067                itm=itms->data;
2068                if (order >= itm->order.min && order <= itm->order.max)
2069                        xdisplay_draw_elements(gra, display_list, itm);
2070                itms=g_list_next(itms);
2071         }
2072 }
2073
2074
2075 /**
2076  * FIXME
2077  * @param <>
2078  * @returns <>
2079  * @author Martin Schaller (04/2008)
2080 */
2081 static void xdisplay_draw(struct displaylist *display_list, struct graphics *gra, struct layout *l, int order)
2082 {
2083         GList *lays;
2084         struct layer *lay;
2085
2086         gra->current_z_order=0;
2087         lays=l->layers;
2088         while (lays) {
2089                 lay=lays->data;
2090                 if (lay->active)
2091                         xdisplay_draw_layer(display_list, gra, lay, order);
2092                 lays=g_list_next(lays);
2093         }
2094 }
2095
2096 /**
2097  * FIXME
2098  * @param <>
2099  * @returns <>
2100  * @author Martin Schaller (04/2008)
2101 */
2102 extern void *route_selection;
2103
2104 static void
2105 displaylist_update_layers(struct displaylist *displaylist, GList *layers, int order)
2106 {
2107         while (layers) {
2108                 struct layer *layer=layers->data;
2109                 GList *itemgras=layer->itemgras;
2110                 while (itemgras) {
2111                         struct itemgra *itemgra=itemgras->data;
2112                         GList *types=itemgra->type;
2113                         if (itemgra->order.min <= order && itemgra->order.max >= order) {
2114                                 while (types) {
2115                                         enum item_type type=(enum item_type) types->data;
2116                                         set_hash_entry(displaylist, type);
2117                                         types=g_list_next(types);
2118                                 }
2119                         }
2120                         itemgras=g_list_next(itemgras);
2121                 }
2122                 layers=g_list_next(layers);
2123         }
2124 }
2125
2126 static void
2127 displaylist_update_hash(struct displaylist *displaylist)
2128 {
2129         displaylist->max_offset=0;
2130         clear_hash(displaylist);
2131         displaylist_update_layers(displaylist, displaylist->layout->layers, displaylist->order);
2132         dbg(1,"max offset %d\n",displaylist->max_offset);
2133 }
2134
2135
2136 /**
2137  * @brief Returns selection structure based on displaylist transform, projection and order.
2138  * Use this function to get map selection if you are going to fetch complete item data from the map based on displayitem reference.
2139  * @param displaylist 
2140  * @returns Pointer to selection structure
2141  */
2142 struct map_selection *displaylist_get_selection(struct displaylist *displaylist)
2143 {
2144         return transform_get_selection(displaylist->dc.trans, displaylist->dc.pro, displaylist->order); 
2145 }
2146
2147 /**
2148  * @brief Compare displayitems based on their zorder values. 
2149  * Use with g_list_insert_sorted to sort less shaded items to be before more shaded ones in the result list.
2150  */
2151 static int displaylist_cmp_zorder(const struct displayitem *a, const struct displayitem *b)
2152 {
2153         if(a->z_order>b->z_order)
2154                 return -1;
2155         if(a->z_order<b->z_order)
2156                 return 1;
2157         return 0;
2158 }
2159
2160 /**
2161  * @brief Returns list of displayitems clicked at given coordinates. The deeper item is in current layout, the deeper it will be in the list.
2162  * @param displaylist 
2163  * @param p clicked point
2164  * @param radius radius of clicked area 
2165  * @returns GList of displayitems
2166  */
2167 GList *displaylist_get_clicked_list(struct displaylist *displaylist, struct point *p, int radius)
2168 {
2169         GList *l=NULL;
2170         struct displayitem *di;
2171         struct displaylist_handle *dlh=graphics_displaylist_open(displaylist);
2172
2173         while ((di=graphics_displaylist_next(dlh))) {
2174                 if (di->z_order>0 && graphics_displayitem_within_dist(displaylist, di, p,radius))
2175                         l=g_list_insert_sorted(l,(gpointer) di, (GCompareFunc) displaylist_cmp_zorder);
2176         }
2177
2178         return l;
2179 }
2180
2181
2182
2183 static void
2184 do_draw(struct displaylist *displaylist, int cancel, int flags)
2185 {
2186         struct item *item;
2187         int count,max=displaylist->dc.maxlen,workload=0;
2188         struct coord *ca=g_alloca(sizeof(struct coord)*max);
2189         struct attr attr,attr2;
2190         enum projection pro;
2191
2192         if (displaylist->order != displaylist->order_hashed || displaylist->layout != displaylist->layout_hashed) {
2193                 displaylist_update_hash(displaylist);
2194                 displaylist->order_hashed=displaylist->order;
2195                 displaylist->layout_hashed=displaylist->layout;
2196         }
2197         profile(0,NULL);
2198         pro=transform_get_projection(displaylist->dc.trans);
2199         while (!cancel) {
2200                 if (!displaylist->msh)
2201                         displaylist->msh=mapset_open(displaylist->ms);
2202                 if (!displaylist->m) {
2203                         displaylist->m=mapset_next(displaylist->msh, 1);
2204                         if (!displaylist->m) {
2205                                 mapset_close(displaylist->msh);
2206                                 displaylist->msh=NULL;
2207                                 break;
2208                         }
2209                         displaylist->dc.pro=map_projection(displaylist->m);
2210                         displaylist->conv=map_requires_conversion(displaylist->m);
2211                         if (route_selection)
2212                                 displaylist->sel=route_selection;
2213                         else
2214                                 displaylist->sel=displaylist_get_selection(displaylist);
2215                         displaylist->mr=map_rect_new(displaylist->m, displaylist->sel);
2216                 }
2217                 if (displaylist->mr) {
2218                         while ((item=map_rect_get_item(displaylist->mr))) {
2219                                 int label_count=0;
2220                                 char *labels[2];
2221                                 struct hash_entry *entry;
2222                                 if (item == &busy_item) {
2223                                         if (displaylist->workload)
2224                                                 return;
2225                                         else
2226                                                 continue;
2227                                 }
2228                                 entry=get_hash_entry(displaylist, item->type);
2229                                 if (!entry)
2230                                         continue;
2231                                 count=item_coord_get_within_selection(item, ca, item->type < type_line ? 1: max, displaylist->sel);
2232                                 if (! count)
2233                                         continue;
2234                                 if (displaylist->dc.pro != pro)
2235                                         transform_from_to_count(ca, displaylist->dc.pro, ca, pro, count);
2236                                 if (count == max) {
2237                                         dbg(0,"point count overflow %d for %s "ITEM_ID_FMT"\n", count,item_to_name(item->type),ITEM_ID_ARGS(*item));
2238                                         displaylist->dc.maxlen=max*2;
2239                                 }
2240                                 if (item_is_custom_poi(*item)) {
2241                                         if (item_attr_get(item, attr_icon_src, &attr2))
2242                                                 labels[1]=map_convert_string(displaylist->m, attr2.u.str);
2243                                         else
2244                                                 labels[1]=NULL;
2245                                         label_count=2;
2246                                 } else {
2247                                         labels[1]=NULL;
2248                                         label_count=0;
2249                                 }
2250                                 if (item_attr_get(item, attr_label, &attr)) {
2251                                         labels[0]=attr.u.str;
2252                                         if (!label_count)
2253                                                 label_count=2;
2254                                 } else
2255                                         labels[0]=NULL;
2256                                 if (displaylist->conv && label_count) {
2257                                         labels[0]=map_convert_string(displaylist->m, labels[0]);
2258                                         display_add(entry, item, count, ca, labels, label_count);
2259                                         map_convert_free(labels[0]);
2260                                 } else
2261                                         display_add(entry, item, count, ca, labels, label_count);
2262                                 if (labels[1])
2263                                         map_convert_free(labels[1]);
2264                                 workload++;
2265                                 if (workload == displaylist->workload)
2266                                         return;
2267                         }
2268                         map_rect_destroy(displaylist->mr);
2269                 }
2270                 if (!route_selection)
2271                         map_selection_destroy(displaylist->sel);
2272                 displaylist->mr=NULL;
2273                 displaylist->sel=NULL;
2274                 displaylist->m=NULL;
2275         }
2276         profile(1,"process_selection\n");
2277         if (displaylist->idle_ev)
2278                 event_remove_idle(displaylist->idle_ev);
2279         displaylist->idle_ev=NULL;
2280         callback_destroy(displaylist->idle_cb);
2281         displaylist->idle_cb=NULL;
2282         displaylist->busy=0;
2283         graphics_process_selection(displaylist->dc.gra, displaylist);
2284         profile(1,"draw\n");
2285         if (! cancel)
2286                 graphics_displaylist_draw(displaylist->dc.gra, displaylist, displaylist->dc.trans, displaylist->layout, flags);
2287         map_rect_destroy(displaylist->mr);
2288         if (!route_selection)
2289                 map_selection_destroy(displaylist->sel);
2290         mapset_close(displaylist->msh);
2291         displaylist->mr=NULL;
2292         displaylist->sel=NULL;
2293         displaylist->m=NULL;
2294         displaylist->msh=NULL;
2295         profile(1,"callback\n");
2296         callback_call_1(displaylist->cb, cancel);
2297         profile(0,"end\n");
2298 }
2299
2300 /**
2301  * FIXME
2302  * @param <>
2303  * @returns <>
2304  * @author Martin Schaller (04/2008)
2305 */
2306 void graphics_displaylist_draw(struct graphics *gra, struct displaylist *displaylist, struct transformation *trans, struct layout *l, int flags)
2307 {
2308         int order=transform_get_order(trans);
2309         if(displaylist->dc.trans && displaylist->dc.trans!=trans)
2310                 transform_destroy(displaylist->dc.trans);
2311         if(displaylist->dc.trans!=trans)
2312                 displaylist->dc.trans=transform_dup(trans);
2313         displaylist->dc.gra=gra;
2314         displaylist->dc.mindist=transform_get_scale(trans)/2;
2315         // FIXME find a better place to set the background color
2316         if (l) {
2317                 graphics_gc_set_background(gra->gc[0], &l->color);
2318                 graphics_gc_set_foreground(gra->gc[0], &l->color);
2319                 gra->default_font = g_strdup(l->font);
2320         }
2321         graphics_background_gc(gra, gra->gc[0]);
2322         if (flags & 1)
2323                 callback_list_call_attr_0(gra->cbl, attr_predraw);
2324         gra->meth.draw_mode(gra->priv, (flags & 8)?draw_mode_begin_clear:draw_mode_begin);
2325         if (!(flags & 2))
2326                 gra->meth.draw_rectangle(gra->priv, gra->gc[0]->priv, &gra->r.lu, gra->r.rl.x-gra->r.lu.x, gra->r.rl.y-gra->r.lu.y);
2327         if (l)  {
2328                 order+=l->order_delta;
2329                 xdisplay_draw(displaylist, gra, l, order>0?order:0);
2330         }
2331         if (flags & 1)
2332                 callback_list_call_attr_0(gra->cbl, attr_postdraw);
2333         if (!(flags & 4))
2334                 gra->meth.draw_mode(gra->priv, draw_mode_end);
2335 }
2336
2337 static void graphics_load_mapset(struct graphics *gra, struct displaylist *displaylist, struct mapset *mapset, struct transformation *trans, struct layout *l, int async, struct callback *cb, int flags)
2338 {
2339         int order=transform_get_order(trans);
2340
2341         dbg(1,"enter");
2342         if (displaylist->busy) {
2343                 if (async == 1)
2344                         return;
2345                 do_draw(displaylist, 1, flags);
2346         }
2347         xdisplay_free(displaylist);
2348         dbg(1,"order=%d\n", order);
2349
2350         displaylist->dc.gra=gra;
2351         displaylist->ms=mapset;
2352         if(displaylist->dc.trans && displaylist->dc.trans!=trans)
2353                 transform_destroy(displaylist->dc.trans);
2354         if(displaylist->dc.trans!=trans)
2355                 displaylist->dc.trans=transform_dup(trans);
2356         displaylist->workload=async ? 100 : 0;
2357         displaylist->cb=cb;
2358         displaylist->seq++;
2359         if (l)
2360                 order+=l->order_delta;
2361         displaylist->order=order>0?order:0;
2362         displaylist->busy=1;
2363         displaylist->layout=l;
2364         if (async) {
2365                 if (! displaylist->idle_cb)
2366                         displaylist->idle_cb=callback_new_3(callback_cast(do_draw), displaylist, 0, flags);
2367                 displaylist->idle_ev=event_add_idle(50, displaylist->idle_cb);
2368         } else
2369                 do_draw(displaylist, 0, flags);
2370 }
2371 /**
2372  * FIXME
2373  * @param <>
2374  * @returns <>
2375  * @author Martin Schaller (04/2008)
2376 */
2377 void graphics_draw(struct graphics *gra, struct displaylist *displaylist, struct mapset *mapset, struct transformation *trans, struct layout *l, int async, struct callback *cb, int flags)
2378 {
2379         graphics_load_mapset(gra, displaylist, mapset, trans, l, async, cb, flags);
2380 }
2381
2382 int
2383 graphics_draw_cancel(struct graphics *gra, struct displaylist *displaylist)
2384 {
2385         if (!displaylist->busy)
2386                 return 0;
2387         do_draw(displaylist, 1, 0);
2388         return 1;
2389 }
2390
2391 /**
2392  * FIXME
2393  * @param <>
2394  * @returns <>
2395  * @author Martin Schaller (04/2008)
2396 */
2397 struct displaylist_handle {
2398         struct displaylist *dl;
2399         struct displayitem *di;
2400         int hashidx;
2401 };
2402
2403 /**
2404  * FIXME
2405  * @param <>
2406  * @returns <>
2407  * @author Martin Schaller (04/2008)
2408 */
2409 struct displaylist_handle * graphics_displaylist_open(struct displaylist *displaylist)
2410 {
2411         struct displaylist_handle *ret;
2412
2413         ret=g_new0(struct displaylist_handle, 1);
2414         ret->dl=displaylist;
2415
2416         return ret;
2417 }
2418
2419 /**
2420  * FIXME
2421  * @param <>
2422  * @returns <>
2423  * @author Martin Schaller (04/2008)
2424 */
2425 struct displayitem * graphics_displaylist_next(struct displaylist_handle *dlh)
2426 {
2427         struct displayitem *ret;
2428         if (!dlh)
2429                 return NULL;
2430         for (;;) {
2431                 if (dlh->di) {
2432                         ret=dlh->di;
2433                         dlh->di=ret->next;
2434                         break;
2435                 }
2436                 if (dlh->hashidx == HASH_SIZE) {
2437                         ret=NULL;
2438                         break;
2439                 }
2440                 if (dlh->dl->hash_entries[dlh->hashidx].type)
2441                         dlh->di=dlh->dl->hash_entries[dlh->hashidx].di;
2442                 dlh->hashidx++;
2443         }
2444         return ret;
2445 }
2446
2447 /**
2448  * FIXME
2449  * @param <>
2450  * @returns <>
2451  * @author Martin Schaller (04/2008)
2452 */
2453 void graphics_displaylist_close(struct displaylist_handle *dlh)
2454 {
2455         g_free(dlh);
2456 }
2457
2458 /**
2459  * FIXME
2460  * @param <>
2461  * @returns <>
2462  * @author Martin Schaller (04/2008)
2463 */
2464 struct displaylist * graphics_displaylist_new(void)
2465 {
2466         struct displaylist *ret=g_new0(struct displaylist, 1);
2467
2468         ret->dc.maxlen=16384;
2469
2470         return ret;
2471 }
2472
2473 void graphics_displaylist_destroy(struct displaylist *displaylist)
2474 {
2475         if(displaylist->dc.trans)
2476                 transform_destroy(displaylist->dc.trans);
2477         g_free(displaylist);
2478         
2479 }
2480
2481
2482 /**
2483  * Get the map item which given displayitem is based on.
2484  * NOTE: returned structure doesn't contain any attributes or coordinates. type, map, idhi and idlow seem to be the only useable members.
2485  * @param di pointer to displayitem structure
2486  * @returns Pointer to struct item
2487  * @author Martin Schaller (04/2008)
2488 */
2489 struct item * graphics_displayitem_get_item(struct displayitem *di)
2490 {
2491         return &di->item;
2492 }
2493
2494 /**
2495  * Get the number of this item as it was last displayed on the screen, dependent of current layout. Items with lower numbers  
2496  * are shaded by items with higher ones when they overlap. Zero means item was not displayed at all. If the item is displayed twice, its topmost 
2497  * occurence is used.
2498  * @param di pointer to displayitem structure
2499  * @returns z-order of current item. 
2500 */
2501 int graphics_displayitem_get_z_order(struct displayitem *di)
2502 {
2503         return di->z_order;
2504 }
2505
2506
2507 int
2508 graphics_displayitem_get_coord_count(struct displayitem *di)
2509 {
2510         return di->count;
2511 }
2512
2513 /**
2514  * FIXME
2515  * @param <>
2516  * @returns <>
2517  * @author Martin Schaller (04/2008)
2518 */
2519 char * graphics_displayitem_get_label(struct displayitem *di)
2520 {
2521         return di->label;
2522 }
2523
2524 int
2525 graphics_displayitem_get_displayed(struct displayitem *di)
2526 {
2527         return 1;
2528 }
2529
2530 /**
2531  * FIXME
2532  * @param <>
2533  * @returns <>
2534  * @author Martin Schaller (04/2008)
2535 */
2536 static int within_dist_point(struct point *p0, struct point *p1, int dist)
2537 {
2538         if (p0->x == 32767 || p0->y == 32767 || p1->x == 32767 || p1->y == 32767)
2539                 return 0;
2540         if (p0->x == -32768 || p0->y == -32768 || p1->x == -32768 || p1->y == -32768)
2541                 return 0;
2542         if ((p0->x-p1->x)*(p0->x-p1->x) + (p0->y-p1->y)*(p0->y-p1->y) <= dist*dist) {
2543                 return 1;
2544         }
2545         return 0;
2546 }
2547
2548 /**
2549  * FIXME
2550  * @param <>
2551  * @returns <>
2552  * @author Martin Schaller (04/2008)
2553 */
2554 static int within_dist_line(struct point *p, struct point *line_p0, struct point *line_p1, int dist)
2555 {
2556         int vx,vy,wx,wy;
2557         int c1,c2;
2558         struct point line_p;
2559
2560         if (line_p0->x < line_p1->x) {
2561                 if (p->x < line_p0->x - dist)
2562                         return 0;
2563                 if (p->x > line_p1->x + dist)
2564                         return 0;
2565         } else {
2566                 if (p->x < line_p1->x - dist)
2567                         return 0;
2568                 if (p->x > line_p0->x + dist)
2569                         return 0;
2570         }
2571         if (line_p0->y < line_p1->y) {
2572                 if (p->y < line_p0->y - dist)
2573                         return 0;
2574                 if (p->y > line_p1->y + dist)
2575                         return 0;
2576         } else {
2577                 if (p->y < line_p1->y - dist)
2578                         return 0;
2579                 if (p->y > line_p0->y + dist)
2580                         return 0;
2581         }
2582
2583         vx=line_p1->x-line_p0->x;
2584         vy=line_p1->y-line_p0->y;
2585         wx=p->x-line_p0->x;
2586         wy=p->y-line_p0->y;
2587
2588         c1=vx*wx+vy*wy;
2589         if ( c1 <= 0 )
2590                 return within_dist_point(p, line_p0, dist);
2591         c2=vx*vx+vy*vy;
2592         if ( c2 <= c1 )
2593                 return within_dist_point(p, line_p1, dist);
2594
2595         line_p.x=line_p0->x+vx*c1/c2;
2596         line_p.y=line_p0->y+vy*c1/c2;
2597         return within_dist_point(p, &line_p, dist);
2598 }
2599
2600 /**
2601  * FIXME
2602  * @param <>
2603  * @returns <>
2604  * @author Martin Schaller (04/2008)
2605 */
2606 static int within_dist_polyline(struct point *p, struct point *line_pnt, int count, int dist, int close)
2607 {
2608         int i;
2609         for (i = 0 ; i < count-1 ; i++) {
2610                 if (within_dist_line(p,line_pnt+i,line_pnt+i+1,dist)) {
2611                         return 1;
2612                 }
2613         }
2614         if (close)
2615                 return (within_dist_line(p,line_pnt,line_pnt+count-1,dist));
2616         return 0;
2617 }
2618
2619 /**
2620  * FIXME
2621  * @param <>
2622  * @returns <>
2623  * @author Martin Schaller (04/2008)
2624 */
2625 static int within_dist_polygon(struct point *p, struct point *poly_pnt, int count, int dist)
2626 {
2627         int i, j, c = 0;
2628         for (i = 0, j = count-1; i < count; j = i++) {
2629                 if ((((poly_pnt[i].y <= p->y) && ( p->y < poly_pnt[j].y )) ||
2630                 ((poly_pnt[j].y <= p->y) && ( p->y < poly_pnt[i].y))) &&
2631                 (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))
2632                         c = !c;
2633         }
2634         if (! c)
2635                 return within_dist_polyline(p, poly_pnt, count, dist, 1);
2636         return c;
2637 }
2638
2639 /**
2640  * FIXME
2641  * @param <>
2642  * @returns <>
2643  * @author Martin Schaller (04/2008)
2644 */
2645 int graphics_displayitem_within_dist(struct displaylist *displaylist, struct displayitem *di, struct point *p, int dist)
2646 {
2647         struct point *pa=g_alloca(sizeof(struct point)*displaylist->dc.maxlen);
2648         int count;
2649
2650         count=transform(displaylist->dc.trans, displaylist->dc.pro, di->c, pa, di->count, 1, 0, NULL);
2651
2652         if (di->item.type < type_line) {
2653                 return within_dist_point(p, &pa[0], dist);
2654         }
2655         if (di->item.type < type_area) {
2656                 return within_dist_polyline(p, pa, count, dist, 0);
2657         }
2658         return within_dist_polygon(p, pa, count, dist);
2659 }
2660
2661
2662 static void
2663 graphics_process_selection_item(struct displaylist *dl, struct item *item)
2664 {
2665 #if 0 /* FIXME */
2666         struct displayitem di,*di_res;
2667         GHashTable *h;
2668         int count,max=dl->dc.maxlen;
2669         struct coord ca[max];
2670         struct attr attr;
2671         struct map_rect *mr;
2672
2673         di.item=*item;
2674         di.label=NULL;
2675         di.count=0;
2676         h=g_hash_table_lookup(dl->dl, GINT_TO_POINTER(di.item.type));
2677         if (h) {
2678                 di_res=g_hash_table_lookup(h, &di);
2679                 if (di_res) {
2680                         di.item.type=(enum item_type)item->priv_data;
2681                         display_add(dl, &di.item, di_res->count, di_res->c, NULL, 0);
2682                         return;
2683                 }
2684         }
2685         mr=map_rect_new(item->map, NULL);
2686         item=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
2687         count=item_coord_get(item, ca, item->type < type_line ? 1: max);
2688         if (!item_attr_get(item, attr_label, &attr))
2689                 attr.u.str=NULL;
2690         if (dl->conv && attr.u.str && attr.u.str[0]) {
2691                 char *str=map_convert_string(item->map, attr.u.str);
2692                 display_add(dl, item, count, ca, &str, 1);
2693                 map_convert_free(str);
2694         } else
2695                 display_add(dl, item, count, ca, &attr.u.str, 1);
2696         map_rect_destroy(mr);
2697 #endif
2698 }
2699
2700 void
2701 graphics_add_selection(struct graphics *gra, struct item *item, enum item_type type, struct displaylist *dl)
2702 {
2703         struct item *item_dup=g_new(struct item, 1);
2704         *item_dup=*item;
2705         item_dup->priv_data=(void *)type;
2706         gra->selection=g_list_append(gra->selection, item_dup);
2707         if (dl)
2708                 graphics_process_selection_item(dl, item_dup);
2709 }
2710
2711 void
2712 graphics_remove_selection(struct graphics *gra, struct item *item, enum item_type type, struct displaylist *dl)
2713 {
2714         GList *curr;
2715         int found;
2716
2717         for (;;) {
2718                 curr=gra->selection;
2719                 found=0;
2720                 while (curr) {
2721                         struct item *sitem=curr->data;
2722                         if (item_is_equal(*item,*sitem)) {
2723                                 if (dl) {
2724                                         struct displayitem di;
2725                                         /* Unused Variable
2726                                         GHashTable *h; */
2727                                         di.item=*sitem;
2728                                         di.label=NULL;
2729                                         di.count=0;
2730                                         di.item.type=type;
2731 #if 0 /* FIXME */
2732                                         h=g_hash_table_lookup(dl->dl, GINT_TO_POINTER(di.item.type));
2733                                         if (h)
2734                                                 g_hash_table_remove(h, &di);
2735 #endif
2736                                 }
2737                                 g_free(sitem);
2738                                 gra->selection=g_list_remove(gra->selection, curr->data);
2739                                 found=1;
2740                                 break;
2741                         }
2742                 }
2743                 if (!found)
2744                         return;
2745         }
2746 }
2747
2748 void
2749 graphics_clear_selection(struct graphics *gra, struct displaylist *dl)
2750 {
2751         while (gra->selection) {
2752                 struct item *item=(struct item *)gra->selection->data;
2753                 graphics_remove_selection(gra, item, (enum item_type)item->priv_data,dl);
2754         }
2755 }
2756
2757 static void
2758 graphics_process_selection(struct graphics *gra, struct displaylist *dl)
2759 {
2760         GList *curr;
2761
2762         curr=gra->selection;
2763         while (curr) {
2764                 struct item *item=curr->data;
2765                 graphics_process_selection_item(dl, item);
2766                 curr=g_list_next(curr);
2767         }
2768 }