Fix:Core:Fix coverity bug #1, dead code
[navit-package] / navit / graphics.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 //##############################################################################################################
21 //#
22 //# File: graphics.c
23 //# Description: 
24 //# Comment: 
25 //# Authors: Martin Schaller (04/2008)
26 //#
27 //##############################################################################################################
28
29 #include <glib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include "debug.h"
34 #include "string.h"
35 #include "draw_info.h"
36 #include "point.h"
37 #include "graphics.h"
38 #include "projection.h"
39 #include "item.h"
40 #include "map.h"
41 #include "coord.h"
42 #include "transform.h"
43 #include "plugin.h"
44 #include "profile.h"
45 #include "mapset.h"
46 #include "layout.h"
47 #include "route.h"
48 #include "util.h"
49 #include "callback.h"
50 #include "file.h"
51 #include "event.h"
52
53 static char *navit_sharedir;
54
55 //##############################################################################################################
56 //# Description: 
57 //# Comment: 
58 //# Authors: Martin Schaller (04/2008)
59 //##############################################################################################################
60 struct graphics
61 {
62         struct graphics_priv *priv;
63         struct graphics_methods meth;
64         char *default_font;
65         int font_len;
66         struct graphics_font **font;
67         struct graphics_gc *gc[3];
68         struct attr **attrs;
69         struct callback_list *cbl;
70         struct point_rect r;
71         GList *selection;
72 };
73
74 struct display_context
75 {
76         struct graphics *gra;
77         struct element *e;
78         struct graphics_gc *gc;
79         struct graphics_image *img;
80         enum projection pro;
81         struct transformation *trans;
82 };
83
84 struct displaylist {
85         GHashTable *dl;
86         int busy;
87         int workload;
88         struct callback *cb;
89         struct layout *layout;
90         struct display_context dc;
91         int order;
92         struct mapset *ms;
93         struct mapset_handle *msh;
94         struct map *m;
95         int conv;
96         struct map_selection *sel;
97         struct map_rect *mr;
98         struct callback *idle_cb;
99         struct event_idle *idle_ev;
100 };
101
102
103 static void draw_circle(struct point *pnt, int diameter, int scale, int start, int len, struct point *res, int *pos, int dir);
104 static void graphics_process_selection(struct graphics *gra, struct displaylist *dl);
105
106 void
107 graphics_set_rect(struct graphics *gra, struct point_rect *pr)
108 {
109         gra->r=*pr;
110 }
111
112 /**
113  * Creates a new graphics object
114  * attr type required
115  * @param <>
116  * @returns <>
117  * @author Martin Schaller (04/2008)
118 */
119 struct graphics * graphics_new(struct attr *parent, struct attr **attrs)
120 {
121         struct graphics *this_;
122         struct attr *type_attr;
123         struct graphics_priv * (*graphicstype_new)(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl);
124
125         if (! (type_attr=attr_search(attrs, NULL, attr_type))) {
126                 return NULL;
127         }
128
129         graphicstype_new=plugin_get_graphics_type(type_attr->u.str);
130         if (! graphicstype_new)
131                 return NULL;
132         this_=g_new0(struct graphics, 1);
133         this_->cbl=callback_list_new();
134         this_->priv=(*graphicstype_new)(parent->u.navit, &this_->meth, attrs, this_->cbl);
135         this_->attrs=attr_list_dup(attrs);
136         return this_;
137 }
138
139 /**
140  * FIXME
141  * @param <>
142  * @returns <>
143  * @author Martin Schaller (04/2008)
144 */
145 int graphics_get_attr(struct graphics *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
146 {
147         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
148 }
149
150 /**
151  * FIXME
152  * @param <>
153  * @returns <>
154  * @author Martin Schaller (04/2008)
155 */
156 struct graphics * graphics_overlay_new(struct graphics *parent, struct point *p, int w, int h, int alpha, int wraparound)
157 {
158         struct graphics *this_;
159         if (!parent->meth.overlay_new)
160                 return NULL;
161         this_=g_new0(struct graphics, 1);
162         this_->priv=parent->meth.overlay_new(parent->priv, &this_->meth, p, w, h, alpha, wraparound);
163         if (!this_->priv) {
164                 g_free(this_);
165                 this_=NULL;
166         }
167         return this_;
168 }
169
170 /**
171  * @brief Alters the size, position, alpha and wraparound for an overlay
172  *
173  * @param this_ The overlay's graphics struct
174  * @param p The new position of the overlay
175  * @param w The new width of the overlay
176  * @param h The new height of the overlay
177  * @param alpha The new alpha of the overlay
178  * @param wraparound The new wraparound of the overlay
179  */
180 void 
181 graphics_overlay_resize(struct graphics *this_, struct point *p, int w, int h, int alpha, int wraparound)
182 {
183         if (! this_->meth.overlay_resize) {
184                 return;
185         }
186         
187         this_->meth.overlay_resize(this_->priv, p, w, h, alpha, wraparound);
188 }
189
190
191 /**
192  * FIXME
193  * @param <>
194  * @returns <>
195  * @author Martin Schaller (04/2008)
196 */
197 void graphics_init(struct graphics *this_)
198 {
199         this_->gc[0]=graphics_gc_new(this_);
200         graphics_gc_set_background(this_->gc[0], &(struct color) { 0xffff, 0xefef, 0xb7b7, 0xffff});
201         graphics_gc_set_foreground(this_->gc[0], &(struct color) { 0xffff, 0xefef, 0xb7b7, 0xffff });
202         this_->gc[1]=graphics_gc_new(this_);
203         graphics_gc_set_background(this_->gc[1], &(struct color) { 0x0000, 0x0000, 0x0000, 0xffff });
204         graphics_gc_set_foreground(this_->gc[1], &(struct color) { 0xffff, 0xffff, 0xffff, 0xffff });
205         this_->gc[2]=graphics_gc_new(this_);
206         graphics_gc_set_background(this_->gc[2], &(struct color) { 0xffff, 0xffff, 0xffff, 0xffff });
207         graphics_gc_set_foreground(this_->gc[2], &(struct color) { 0x0000, 0x0000, 0x0000, 0xffff });
208         graphics_background_gc(this_, this_->gc[0]);
209         navit_sharedir = getenv("NAVIT_SHAREDIR");
210 }
211
212 /**
213  * FIXME
214  * @param <>
215  * @returns <>
216  * @author Martin Schaller (04/2008)
217 */
218 void * graphics_get_data(struct graphics *this_, char *type)
219 {
220         return (this_->meth.get_data(this_->priv, type));
221 }
222
223 void graphics_add_callback(struct graphics *this_, struct callback *cb)
224 {
225         callback_list_add(this_->cbl, cb);
226 }
227
228 void graphics_remove_callback(struct graphics *this_, struct callback *cb)
229 {
230         callback_list_remove(this_->cbl, cb);
231 }
232
233 /**
234  * FIXME
235  * @param <>
236  * @returns <>
237  * @author Martin Schaller (04/2008)
238 */
239 struct graphics_font * graphics_font_new(struct graphics *gra, int size, int flags)
240 {
241         struct graphics_font *this_;
242
243         this_=g_new0(struct graphics_font,1);
244         this_->priv=gra->meth.font_new(gra->priv, &this_->meth, gra->default_font, size, flags);
245         return this_;
246 }
247
248 /**
249  * Free all loaded fonts.
250  * Used when switching layouts.
251  * @param gra The graphics instance
252  * @returns nothing
253  * @author Sarah Nordstrom (05/2008)
254  */
255 void graphics_font_destroy_all(struct graphics *gra) 
256
257         int i; 
258         for(i = 0 ; i < gra->font_len; i++) { 
259                 if(!gra->font[i]) continue; 
260                 gra->font[i]->meth.font_destroy(gra->font[i]->priv); 
261                 gra->font[i] = NULL; 
262         }
263 }
264
265 /**
266  * FIXME
267  * @param <>
268  * @returns <>
269  * @author Martin Schaller (04/2008)
270 */
271 struct graphics_gc * graphics_gc_new(struct graphics *gra)
272 {
273         struct graphics_gc *this_;
274
275         this_=g_new0(struct graphics_gc,1);
276         this_->priv=gra->meth.gc_new(gra->priv, &this_->meth);
277         return this_;
278 }
279
280 /**
281  * FIXME
282  * @param <>
283  * @returns <>
284  * @author Martin Schaller (04/2008)
285 */
286 void graphics_gc_destroy(struct graphics_gc *gc)
287 {
288         gc->meth.gc_destroy(gc->priv);
289         g_free(gc);
290 }
291
292 /**
293  * FIXME
294  * @param <>
295  * @returns <>
296  * @author Martin Schaller (04/2008)
297 */
298 void graphics_gc_set_foreground(struct graphics_gc *gc, struct color *c)
299 {
300         gc->meth.gc_set_foreground(gc->priv, c);
301 }
302
303 /**
304  * FIXME
305  * @param <>
306  * @returns <>
307  * @author Martin Schaller (04/2008)
308 */
309 void graphics_gc_set_background(struct graphics_gc *gc, struct color *c)
310 {
311         gc->meth.gc_set_background(gc->priv, c);
312 }
313
314
315 /**
316  * FIXME
317  * @param <>
318  * @returns <>
319  * @author Martin Schaller (04/2008)
320 */
321 void graphics_gc_set_stipple(struct graphics_gc *gc, struct graphics_image *img) 
322 {
323         gc->meth.gc_set_stipple(gc->priv, img ? img->priv : NULL);
324 }
325
326
327 /**
328  * FIXME
329  * @param <>
330  * @returns <>
331  * @author Martin Schaller (04/2008)
332 */
333 void graphics_gc_set_linewidth(struct graphics_gc *gc, int width)
334 {
335         gc->meth.gc_set_linewidth(gc->priv, width);
336 }
337
338 /**
339  * FIXME
340  * @param <>
341  * @returns <>
342  * @author Martin Schaller (04/2008)
343 */
344 void graphics_gc_set_dashes(struct graphics_gc *gc, int width, int offset, unsigned char dash_list[], int n)
345 {
346         if (gc->meth.gc_set_dashes)
347                 gc->meth.gc_set_dashes(gc->priv, width, offset, dash_list, n);
348 }
349
350 /**
351  * Create a new image from file path scaled to w and h pixels
352  * @param gra the graphics instance
353  * @param path path of the image to load
354  * @param w width to rescale to
355  * @param h height to rescale to
356  * @returns <>
357  * @author Martin Schaller (04/2008)
358 */
359 struct graphics_image * graphics_image_new_scaled(struct graphics *gra, char *path, int w, int h)
360 {
361         struct graphics_image *this_;
362
363         this_=g_new0(struct graphics_image,1);
364         this_->height=h;
365         this_->width=w;
366         this_->priv=gra->meth.image_new(gra->priv, &this_->meth, path, &this_->width, &this_->height, &this_->hot, 0);
367         if (! this_->priv) {
368                 g_free(this_);
369                 this_=NULL;
370         }
371         return this_;
372 }
373
374 /**
375  * Create a new image from file path scaled to w and h pixels and possibly rotated
376  * @param gra the graphics instance
377  * @param path path of the image to load
378  * @param w width to rescale to
379  * @param h height to rescale to
380  * @param rotate angle to rotate the image. Warning, graphics might only support 90 degree steps here
381  * @returns <>
382  * @author Martin Schaller (04/2008)
383 */
384 struct graphics_image * graphics_image_new_scaled_rotated(struct graphics *gra, char *path, int w, int h, int rotate)
385 {
386         struct graphics_image *this_;
387
388         this_=g_new0(struct graphics_image,1);
389         this_->height=h;
390         this_->width=w;
391         this_->priv=gra->meth.image_new(gra->priv, &this_->meth, path, &this_->width, &this_->height, &this_->hot, rotate);
392         if (! this_->priv) {
393                 g_free(this_);
394                 this_=NULL;
395         }
396         return this_;
397 }
398
399 /**
400  * Create a new image from file path
401  * @param gra the graphics instance
402  * @param path path of the image to load
403  * @returns <>
404  * @author Martin Schaller (04/2008)
405 */
406 struct graphics_image * graphics_image_new(struct graphics *gra, char *path)
407 {
408         return graphics_image_new_scaled(gra, path, -1, -1);
409 }
410
411 /**
412  * FIXME
413  * @param <>
414  * @returns <>
415  * @author Martin Schaller (04/2008)
416 */
417 void graphics_image_free(struct graphics *gra, struct graphics_image *img)
418 {
419         if (gra->meth.image_free)
420                 gra->meth.image_free(gra->priv, img->priv);
421         g_free(img);
422 }
423
424 /**
425  * FIXME
426  * @param <>
427  * @returns <>
428  * @author Martin Schaller (04/2008)
429 */
430 void graphics_draw_restore(struct graphics *this_, struct point *p, int w, int h)
431 {
432         this_->meth.draw_restore(this_->priv, p, w, h);
433 }
434
435 /**
436  * FIXME
437  * @param <>
438  * @returns <>
439  * @author Martin Schaller (04/2008)
440 */
441 void graphics_draw_mode(struct graphics *this_, enum draw_mode_num mode)
442 {
443         this_->meth.draw_mode(this_->priv, mode);
444 }
445
446 /**
447  * FIXME
448  * @param <>
449  * @returns <>
450  * @author Martin Schaller (04/2008)
451 */
452 void graphics_draw_lines(struct graphics *this_, struct graphics_gc *gc, struct point *p, int count)
453 {
454         this_->meth.draw_lines(this_->priv, gc->priv, p, count);
455 }
456
457 /**
458  * FIXME
459  * @param <>
460  * @returns <>
461  * @author Martin Schaller (04/2008)
462 */
463 void graphics_draw_circle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int r)
464 {
465         this_->meth.draw_circle(this_->priv, gc->priv, p, r);
466 }
467
468 /**
469  * FIXME
470  * @param <>
471  * @returns <>
472  * @author Martin Schaller (04/2008)
473 */
474 void graphics_draw_rectangle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int w, int h)
475 {
476         this_->meth.draw_rectangle(this_->priv, gc->priv, p, w, h);
477 }
478
479 void graphics_draw_rectangle_rounded(struct graphics *this_, struct graphics_gc *gc, struct point *plu, int w, int h, int r, int fill)
480 {
481         struct point p[r*4+32];
482         struct point pi0={plu->x+r,plu->y+r};
483         struct point pi1={plu->x+w-r,plu->y+r};
484         struct point pi2={plu->x+w-r,plu->y+h-r};
485         struct point pi3={plu->x+r,plu->y+h-r};
486         int i=0;
487
488         draw_circle(&pi2, r*2, 0, -1, 258, p, &i, 1);
489         draw_circle(&pi1, r*2, 0, 255, 258, p, &i, 1);
490         draw_circle(&pi0, r*2, 0, 511, 258, p, &i, 1);
491         draw_circle(&pi3, r*2, 0, 767, 258, p, &i, 1);
492         p[i]=p[0];
493         i++;
494         if (fill)
495                 this_->meth.draw_polygon(this_->priv, gc->priv, p, i);
496         else
497                 this_->meth.draw_lines(this_->priv, gc->priv, p, i);
498 }
499
500
501 /**
502  * FIXME
503  * @param <>
504  * @returns <>
505  * @author Martin Schaller (04/2008)
506 */
507 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)
508 {
509         this_->meth.draw_text(this_->priv, gc1->priv, gc2 ? gc2->priv : NULL, font->priv, text, p, dx, dy);
510 }
511
512 /**
513  * FIXME
514  * @param <>
515  * @returns <>
516  * @author Martin Schaller (04/2008)
517 */
518 void graphics_get_text_bbox(struct graphics *this_, struct graphics_font *font, char *text, int dx, int dy, struct point *ret, int estimate)
519 {
520         this_->meth.get_text_bbox(this_->priv, font->priv, text, dx, dy, ret, estimate);
521 }
522
523 /**
524  * FIXME
525  * @param <>
526  * @returns <>
527  * @author Martin Schaller (04/2008)
528 */
529 void graphics_overlay_disable(struct graphics *this_, int disable)
530 {
531         if (this_->meth.overlay_disable)
532                 this_->meth.overlay_disable(this_->priv, disable);
533 }
534
535 /**
536  * FIXME
537  * @param <>
538  * @returns <>
539  * @author Martin Schaller (04/2008)
540 */
541 void graphics_draw_image(struct graphics *this_, struct graphics_gc *gc, struct point *p, struct graphics_image *img)
542 {
543         this_->meth.draw_image(this_->priv, gc->priv, p, img->priv);
544 }
545
546
547 //##############################################################################################################
548 //# Description:
549 //# Comment:
550 //# Authors: Martin Schaller (04/2008)
551 //##############################################################################################################
552 int
553 graphics_draw_drag(struct graphics *this_, struct point *p)
554 {
555         if (!this_->meth.draw_drag)
556                 return 0;
557         this_->meth.draw_drag(this_->priv, p);
558         return 1;
559 }
560
561 void
562 graphics_background_gc(struct graphics *this_, struct graphics_gc *gc)
563 {
564         this_->meth.background_gc(this_->priv, gc ? gc->priv : NULL);
565 }
566
567 #include "attr.h"
568 #include "popup.h"
569 #include <stdio.h>
570
571
572 #if 0
573 //##############################################################################################################
574 //# Description: 
575 //# Comment: 
576 //# Authors: Martin Schaller (04/2008)
577 //##############################################################################################################
578 static void popup_view_html(struct popup_item *item, char *file)
579 {
580         char command[1024];
581         sprintf(command,"firefox %s", file);
582         system(command);
583 }
584
585 struct transformatin *tg;
586 enum projection pg;
587
588 //##############################################################################################################
589 //# Description: 
590 //# Comment: 
591 //# Authors: Martin Schaller (04/2008)
592 //##############################################################################################################
593 static void graphics_popup(struct display_list *list, struct popup_item **popup)
594 {
595         struct item *item;
596         struct attr attr;
597         struct map_rect *mr;
598         struct coord c;
599         struct popup_item *curr_item,*last=NULL;
600         item=list->data;
601         mr=map_rect_new(item->map, NULL, NULL, 0);
602         printf("id hi=0x%x lo=0x%x\n", item->id_hi, item->id_lo);
603         item=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
604         if (item) {
605                 if (item_attr_get(item, attr_name, &attr)) {
606                         curr_item=popup_item_new_text(popup,attr.u.str,1);
607                         if (item_attr_get(item, attr_info_html, &attr)) {
608                                 popup_item_new_func(&last,"HTML Info",1, popup_view_html, g_strdup(attr.u.str));
609                         }
610                         if (item_attr_get(item, attr_price_html, &attr)) {
611                                 popup_item_new_func(&last,"HTML Preis",2, popup_view_html, g_strdup(attr.u.str));
612                         }
613                         curr_item->submenu=last;
614                 }
615         }
616         map_rect_destroy(mr);
617 }
618 #endif
619
620 /**
621  * FIXME
622  * @param <>
623  * @returns <>
624  * @author Martin Schaller (04/2008)
625 */
626 struct displayitem {
627         struct item item;
628         char *label;
629         int displayed;
630         int count;
631         struct coord c[0];
632 };
633
634 /**
635  * FIXME
636  * @param <>
637  * @returns <>
638  * @author Martin Schaller (04/2008)
639 */
640 static int xdisplay_free_list(gpointer key, gpointer value, gpointer user_data)
641 {
642         GHashTable *hash=value;
643         if (hash) 
644                 g_hash_table_destroy(hash);
645         return TRUE;
646 }
647
648 /**
649  * FIXME
650  * @param <>
651  * @returns <>
652  * @author Martin Schaller (04/2008)
653 */
654 static void xdisplay_free(GHashTable *display_list)
655 {
656         g_hash_table_foreach_remove(display_list, xdisplay_free_list, NULL);
657 }
658
659 static guint
660 displayitem_hash(gconstpointer key)
661 {
662         const struct displayitem *di=key;
663         return (di->item.id_hi^di->item.id_lo^((int) di->item.map));
664 }
665
666 static gboolean
667 displayitem_equal(gconstpointer a, gconstpointer b)
668 {
669         const struct displayitem *dia=a;
670         const struct displayitem *dib=b;
671         if (item_is_equal(dia->item, dib->item))
672                 return TRUE;
673         return FALSE;
674 }
675
676
677 /**
678  * FIXME
679  * @param <>
680  * @returns <>
681  * @author Martin Schaller (04/2008)
682 */
683 static void display_add(struct displaylist *displaylist, struct item *item, int count, struct coord *c, char *label)
684 {
685         struct displayitem *di;
686         int len;
687         GHashTable *h;
688         char *p;
689
690         len=sizeof(*di)+count*sizeof(*c);
691         if (label)
692                 len+=strlen(label)+1;
693
694         p=g_malloc(len);
695
696         di=(struct displayitem *)p;
697         di->displayed=0;
698         p+=sizeof(*di)+count*sizeof(*c);
699         di->item=*item;
700         if (label) {
701                 di->label=p;
702                 strcpy(di->label, label);
703         } else 
704                 di->label=NULL;
705         di->count=count;
706         memcpy(di->c, c, count*sizeof(*c));
707
708         h=g_hash_table_lookup(displaylist->dl, GINT_TO_POINTER(item->type));
709         if (! h) {
710                 h=g_hash_table_new_full(displayitem_hash, displayitem_equal, g_free, NULL);
711                 g_hash_table_insert(displaylist->dl, GINT_TO_POINTER(item->type), h);
712         }
713         g_hash_table_replace(h, di, di);
714 }
715
716
717 /**
718  * FIXME
719  * @param <>
720  * @returns <>
721  * @author Martin Schaller (04/2008)
722 */
723 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)
724 {
725         int i,x,y,tl,tlm,th,thm,tlsq,l;
726         float lsq;
727         double dx,dy;
728         struct point p_t;
729         struct point pb[5];
730
731         if (gra->meth.get_text_bbox) {
732                 gra->meth.get_text_bbox(gra->priv, font->priv, label, 0x10000, 0x0, pb, 1);
733                 tl=(pb[2].x-pb[0].x);
734                 th=(pb[0].y-pb[1].y);
735         } else {
736                 tl=strlen(label)*4;
737                 th=8;
738         }
739         tlm=tl*128;
740         thm=th*144;
741         tlsq = tlm*tlm;
742         for (i = 0 ; i < count-1 ; i++) {
743                 dx=p[i+1].x-p[i].x;
744                 dx*=128;
745                 dy=p[i+1].y-p[i].y;
746                 dy*=128;
747                 lsq = dx*dx+dy*dy;
748                 if (lsq > tlsq) {
749                         l=(int)sqrtf(lsq);
750                         x=p[i].x;
751                         y=p[i].y;
752                         if (dx < 0) {
753                                 dx=-dx;
754                                 dy=-dy;
755                                 x=p[i+1].x;
756                                 y=p[i+1].y;
757                         }
758                         x+=(l-tlm)*dx/l/256;
759                         y+=(l-tlm)*dy/l/256;
760                         x-=dy*thm/l/256;
761                         y+=dx*thm/l/256;
762                         p_t.x=x;
763                         p_t.y=y;
764 #if 0
765                         dbg(0,"display_text: '%s', %d, %d, %d, %d %d\n", label, x, y, dx*0x10000/l, dy*0x10000/l, l);
766 #endif
767                         if (x < gra->r.rl.x && x + tl > gra->r.lu.x && y + tl > gra->r.lu.y && y - tl < gra->r.rl.y) 
768                                 gra->meth.draw_text(gra->priv, fg->priv, bg->priv, font->priv, label, &p_t, dx*0x10000/l, dy*0x10000/l);
769                 }
770         }
771 }
772
773 static void display_draw_arrow(struct point *p, int dx, int dy, int l, struct graphics_gc *gc, struct graphics *gra)
774 {
775         struct point pnt[3];
776         pnt[0]=pnt[1]=pnt[2]=*p;
777         pnt[0].x+=-dx*l/65536+dy*l/65536;
778         pnt[0].y+=-dy*l/65536-dx*l/65536;
779         pnt[2].x+=-dx*l/65536-dy*l/65536;
780         pnt[2].y+=-dy*l/65536+dx*l/65536;
781         gra->meth.draw_lines(gra->priv, gc->priv, pnt, 3);
782 }
783
784 static void display_draw_arrows(struct graphics *gra, struct graphics_gc *gc, struct point *pnt, int count)
785 {
786         int i,dx,dy,l;
787         struct point p;
788         for (i = 0 ; i < count-1 ; i++) {
789                 dx=pnt[i+1].x-pnt[i].x; 
790                 dy=pnt[i+1].y-pnt[i].y;
791                 l=sqrt(dx*dx+dy*dy);
792                 if (l) {
793                         dx=dx*65536/l;
794                         dy=dy*65536/l;
795                         p=pnt[i];
796                         p.x+=dx*15/65536;
797                         p.y+=dy*15/65536;
798                         display_draw_arrow(&p, dx, dy, 10, gc, gra);
799                         p=pnt[i+1];
800                         p.x-=dx*15/65536;
801                         p.y-=dy*15/65536;
802                         display_draw_arrow(&p, dx, dy, 10, gc, gra);
803                 }
804         }
805 }
806
807 static int
808 intersection(struct point * a1, int adx, int ady, struct point * b1, int bdx, int bdy,
809               struct point * res)
810 {
811         int n, a, b;
812         n = bdy * adx - bdx * ady;
813         a = bdx * (a1->y - b1->y) - bdy * (a1->x - b1->x);
814         b = adx * (a1->y - b1->y) - ady * (a1->x - b1->x);
815         if (n < 0) {
816                 n = -n;
817                 a = -a;
818                 b = -b;
819         }
820 #if 0
821         if (a < 0 || b < 0)
822                 return 0;
823         if (a > n || b > n)
824                 return 0;
825 #endif
826         if (n == 0)
827                 return 0;
828         res->x = a1->x + a * adx / n;
829         res->y = a1->y + a * ady / n;
830         return 1;
831 }
832
833 struct circle {
834         short x,y,fowler;
835 } circle64[]={
836 {0,128,0},
837 {13,127,13},
838 {25,126,25},
839 {37,122,38},
840 {49,118,53},
841 {60,113,67},
842 {71,106,85},
843 {81,99,104},
844 {91,91,128},
845 {99,81,152},
846 {106,71,171},
847 {113,60,189},
848 {118,49,203},
849 {122,37,218},
850 {126,25,231},
851 {127,13,243},
852 {128,0,256},
853 {127,-13,269},
854 {126,-25,281},
855 {122,-37,294},
856 {118,-49,309},
857 {113,-60,323},
858 {106,-71,341},
859 {99,-81,360},
860 {91,-91,384},
861 {81,-99,408},
862 {71,-106,427},
863 {60,-113,445},
864 {49,-118,459},
865 {37,-122,474},
866 {25,-126,487},
867 {13,-127,499},
868 {0,-128,512},
869 {-13,-127,525},
870 {-25,-126,537},
871 {-37,-122,550},
872 {-49,-118,565},
873 {-60,-113,579},
874 {-71,-106,597},
875 {-81,-99,616},
876 {-91,-91,640},
877 {-99,-81,664},
878 {-106,-71,683},
879 {-113,-60,701},
880 {-118,-49,715},
881 {-122,-37,730},
882 {-126,-25,743},
883 {-127,-13,755},
884 {-128,0,768},
885 {-127,13,781},
886 {-126,25,793},
887 {-122,37,806},
888 {-118,49,821},
889 {-113,60,835},
890 {-106,71,853},
891 {-99,81,872},
892 {-91,91,896},
893 {-81,99,920},
894 {-71,106,939},
895 {-60,113,957},
896 {-49,118,971},
897 {-37,122,986},
898 {-25,126,999},
899 {-13,127,1011},
900 };
901
902 static void
903 draw_circle(struct point *pnt, int diameter, int scale, int start, int len, struct point *res, int *pos, int dir)
904 {
905         struct circle *c;
906
907 #if 0
908         dbg(0,"diameter=%d start=%d len=%d pos=%d dir=%d\n", diameter, start, len, *pos, dir);
909 #endif
910         int count=64;
911         int end=start+len;
912         int i,step;
913         c=circle64;
914         if (diameter > 128)
915                 step=1;
916         else if (diameter > 64)
917                 step=2;
918         else if (diameter > 24)
919                 step=4;
920         else if (diameter > 8)
921                 step=8;
922         else
923                 step=16;
924         if (len > 0) {
925                 while (start < 0) {
926                         start+=1024;
927                         end+=1024;
928                 }
929                 while (end > 0) {
930                         i=0;
931                         while (i < count && c[i].fowler <= start)
932                                 i+=step;
933                         while (i < count && c[i].fowler < end) {
934                                 res[*pos].x=pnt->x+((c[i].x*diameter+128)>>8);
935                                 res[*pos].y=pnt->y+((c[i].y*diameter+128)>>8);
936                                 (*pos)+=dir;
937                                 i+=step;
938                         }
939                         end-=1024;
940                         start-=1024;
941                 }
942         } else {
943                 while (start > 1024) {
944                         start-=1024;
945                         end-=1024;
946                 }
947                 while (end < 1024) {
948                         i=count-1;
949                         while (i >= 0 && c[i].fowler >= start)
950                                 i-=step;
951                         while (i >= 0 && c[i].fowler > end) {
952                                 res[*pos].x=pnt->x+((c[i].x*diameter+128)>>8);
953                                 res[*pos].y=pnt->y+((c[i].y*diameter+128)>>8);
954                                 (*pos)+=dir;
955                                 i-=step;
956                         }
957                         start+=1024;
958                         end+=1024;
959                 }
960         }
961 }
962
963
964 static int
965 fowler(int dy, int dx)
966 {
967         int adx, ady;           /* Absolute Values of Dx and Dy */
968         int code;               /* Angular Region Classification Code */
969
970         adx = (dx < 0) ? -dx : dx;      /* Compute the absolute values. */
971         ady = (dy < 0) ? -dy : dy;
972
973         code = (adx < ady) ? 1 : 0;
974         if (dx < 0)
975                 code += 2;
976         if (dy < 0)
977                 code += 4;
978
979         switch (code) {
980         case 0:
981                 return (dx == 0) ? 0 : 128*ady / adx;   /* [  0, 45] */
982         case 1:
983                 return (256 - (128*adx / ady)); /* ( 45, 90] */
984         case 3:
985                 return (256 + (128*adx / ady)); /* ( 90,135) */
986         case 2:
987                 return (512 - (128*ady / adx)); /* [135,180] */
988         case 6:
989                 return (512 + (128*ady / adx)); /* (180,225] */
990         case 7:
991                 return (768 - (128*adx / ady)); /* (225,270) */
992         case 5:
993                 return (768 + (128*adx / ady)); /* [270,315) */
994         case 4:
995                 return (1024 - (128*ady / adx));/* [315,360) */
996         }
997         return 0;
998 }
999 static int
1000 int_sqrt(unsigned int n)
1001 {
1002         unsigned int h, p= 0, q= 1, r= n;
1003         while ( q <= n )
1004                 q <<= 2;
1005         while ( q != 1 ) {
1006                 q >>= 2;
1007                 h = p + q;
1008                 p >>= 1;
1009                 if ( r >= h ) {
1010                         p += q;
1011                         r -= h;
1012                 }
1013         }
1014         return p;
1015 }
1016
1017 struct offset {
1018         int px,py,nx,ny;
1019 };
1020
1021 static void
1022 calc_offsets(int wi, int l, int dx, int dy, struct offset *res)
1023 {
1024         int x,y;
1025         
1026         x = (dx * wi) / l;
1027         y = (dy * wi) / l;
1028         if (x < 0) {
1029                 res->nx = -x/2;
1030                 res->px = (x-1)/2;
1031         } else {
1032                 res->nx = -(x+1)/2;
1033                 res->px = x/2;
1034         }
1035         if (y < 0) {
1036                 res->ny = -y/2;
1037                 res->py = (y-1)/2;
1038         } else {
1039                 res->ny = -(y+1)/2;
1040                 res->py = y/2;
1041         }
1042 }
1043
1044 static void
1045 graphics_draw_polyline_as_polygon(struct graphics *gra, struct graphics_gc *gc, struct point *pnt, int count, int *width, int step)
1046 {
1047         int maxpoints=200;
1048         struct point res[maxpoints], pos, poso, neg, nego;
1049         int i, dx=0, dy=0, l=0, dxo=0, dyo=0;
1050         struct offset o,oo;
1051         int fow=0, fowo=0, delta;
1052         int wi, ppos = maxpoints/2, npos = maxpoints/2;
1053         int state,prec=5;
1054         int max_circle_points=20;
1055         int lscale=16;
1056         i=0;
1057         for (;;) {
1058                 wi=*width;
1059                 width+=step;
1060                 if (i < count - 1) {
1061                         dx = (pnt[i + 1].x - pnt[i].x);
1062                         dy = (pnt[i + 1].y - pnt[i].y);
1063                         l = int_sqrt(dx * dx * lscale * lscale + dy * dy * lscale * lscale);
1064                         fow=fowler(-dy, dx);
1065                 }
1066                 if (! l) 
1067                         l=1;
1068                 dbg_assert(wi*lscale < 10000);
1069                 calc_offsets(wi*lscale, l, dx, dy, &o);
1070                 pos.x = pnt[i].x + o.ny;
1071                 pos.y = pnt[i].y + o.px;
1072                 neg.x = pnt[i].x + o.py;
1073                 neg.y = pnt[i].y + o.nx;
1074                 if (! i)
1075                         state=0;
1076                 else if (i == count-1) 
1077                         state=2;
1078                 else if (npos < max_circle_points || ppos >= maxpoints-max_circle_points)
1079                         state=3;
1080                 else
1081                         state=1;
1082                 switch (state) {
1083                 case 1:
1084                        if (fowo != fow) {
1085                                 poso.x = pnt[i].x + oo.ny;
1086                                 poso.y = pnt[i].y + oo.px;
1087                                 nego.x = pnt[i].x + oo.py;
1088                                 nego.y = pnt[i].y + oo.nx;
1089                                 delta=fowo-fow;
1090                                 if (delta < 0)
1091                                         delta+=1024;
1092                                 if (delta < 512) {
1093                                         if (intersection(&pos, dx, dy, &poso, dxo, dyo, &res[ppos]))
1094                                                 ppos++;
1095                                         res[--npos] = nego;
1096                                         --npos;
1097                                         draw_circle(&pnt[i], wi, prec, fowo-512, -delta, res, &npos, -1);
1098                                         res[npos] = neg;
1099                                 } else {
1100                                         res[ppos++] = poso;
1101                                         draw_circle(&pnt[i], wi, prec, fowo, 1024-delta, res, &ppos, 1);
1102                                         res[ppos++] = pos;
1103                                         if (intersection(&neg, dx, dy, &nego, dxo, dyo, &res[npos - 1]))
1104                                                 npos--;
1105                                 }
1106                         }
1107                         break;
1108                 case 2:
1109                 case 3:
1110                         res[--npos] = neg;
1111                         --npos;
1112                         draw_circle(&pnt[i], wi, prec, fow-512, -512, res, &npos, -1);
1113                         res[npos] = pos;
1114                         res[ppos++] = pos;
1115                         dbg_assert(npos > 0);
1116                         dbg_assert(ppos < maxpoints);
1117                         gra->meth.draw_polygon(gra->priv, gc->priv, res+npos, ppos-npos);
1118                         if (state == 2)
1119                                 break;
1120                         npos=maxpoints/2;
1121                         ppos=maxpoints/2;
1122                 case 0:
1123                         res[ppos++] = neg;
1124                         draw_circle(&pnt[i], wi, prec, fow+512, 512, res, &ppos, 1);
1125                         res[ppos++] = pos;
1126                         break;
1127                 }
1128                 i++;
1129                 if (i >= count)
1130                         break;
1131                 if (step) {
1132                         wi=*width;
1133                         calc_offsets(wi*lscale, l, dx, dy, &oo);
1134                 } else 
1135                         oo=o;
1136                 dxo = -dx;
1137                 dyo = -dy;
1138                 fowo=fow;
1139         }
1140 }
1141
1142
1143 struct wpoint {
1144         int x,y,w;
1145 };
1146
1147 static int
1148 clipcode(struct wpoint *p, struct point_rect *r)
1149 {
1150         int code=0;
1151         if (p->x < r->lu.x)
1152                 code=1;
1153         if (p->x > r->rl.x)
1154                 code=2;
1155         if (p->y < r->lu.y)
1156                 code |=4;
1157         if (p->y > r->rl.y)
1158                 code |=8;
1159         return code;
1160 }
1161
1162
1163 static int
1164 clip_line(struct wpoint *p1, struct wpoint *p2, struct point_rect *r)
1165 {
1166         int code1,code2,ret=1;
1167         int dx,dy,dw;
1168         code1=clipcode(p1, r);
1169         if (code1)
1170                 ret |= 2;
1171         code2=clipcode(p2, r);
1172         if (code2)
1173                 ret |= 4;
1174         dx=p2->x-p1->x;
1175         dy=p2->y-p1->y;
1176         dw=p2->w-p1->w;
1177         while (code1 || code2) {
1178                 if (code1 & code2)
1179                         return 0;
1180                 if (code1 & 1) {
1181                         p1->y+=(r->lu.x-p1->x)*dy/dx;
1182                         p1->w+=(r->lu.x-p1->x)*dw/dx;
1183                         p1->x=r->lu.x;
1184                 } else if (code1 & 2) {
1185                         p1->y+=(r->rl.x-p1->x)*dy/dx;
1186                         p1->w+=(r->rl.x-p1->x)*dw/dx;
1187                         p1->x=r->rl.x;
1188                 } else if (code1 & 4) {
1189                         p1->x+=(r->lu.y-p1->y)*dx/dy;
1190                         p1->w+=(r->lu.y-p1->y)*dw/dy;
1191                         p1->y=r->lu.y;
1192                 } else if (code1 & 8) {
1193                         p1->x+=(r->rl.y-p1->y)*dx/dy;
1194                         p1->w+=(r->rl.y-p1->y)*dw/dy;
1195                         p1->y=r->rl.y;
1196                 }
1197                 code1=clipcode(p1, r);
1198                 if (code1 & code2)
1199                         return 0;
1200                 if (code2 & 1) {
1201                         p2->y+=(r->lu.x-p2->x)*dy/dx;
1202                         p2->w+=(r->lu.x-p2->x)*dw/dx;
1203                         p2->x=r->lu.x;
1204                 } else if (code2 & 2) {
1205                         p2->y+=(r->rl.x-p2->x)*dy/dx;
1206                         p2->w+=(r->rl.x-p2->x)*dw/dx;
1207                         p2->x=r->rl.x;
1208                 } else if (code2 & 4) {
1209                         p2->x+=(r->lu.y-p2->y)*dx/dy;
1210                         p2->w+=(r->lu.y-p2->y)*dw/dy;
1211                         p2->y=r->lu.y;
1212                 } else if (code2 & 8) {
1213                         p2->x+=(r->rl.y-p2->y)*dx/dy;
1214                         p2->w+=(r->rl.y-p2->y)*dw/dy;
1215                         p2->y=r->rl.y;
1216                 }
1217                 code2=clipcode(p2, r);
1218         }
1219         return ret;
1220 }
1221
1222 static void
1223 graphics_draw_polyline_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pa, int count, int *width, int step, int poly)
1224 {
1225         struct point p[count+1];
1226         int w[count*step+1];
1227         struct wpoint p1,p2;
1228         int i,code,out=0;
1229         int wmax;
1230         struct point_rect r=gra->r;
1231
1232         wmax=width[0];
1233         if (step) {
1234                 for (i = 1 ; i < count ; i++) {
1235                         if (width[i*step] > wmax)
1236                                 wmax=width[i*step];
1237                 }
1238         }
1239         if (wmax <= 0)
1240                 return;
1241         r.lu.x-=wmax;
1242         r.lu.y-=wmax;
1243         r.rl.x+=wmax;
1244         r.rl.y+=wmax;
1245         for (i = 0 ; i < count ; i++) {
1246                 if (i) {
1247                         p1.x=pa[i-1].x;
1248                         p1.y=pa[i-1].y;
1249                         p1.w=width[(i-1)*step];
1250                         p2.x=pa[i].x;
1251                         p2.y=pa[i].y;
1252                         p2.w=width[i*step];
1253                         /* 0 = invisible, 1 = completely visible, 3 = start point clipped, 5 = end point clipped, 7 both points clipped */
1254                         code=clip_line(&p1, &p2, &r);
1255                         if (((code == 1 || code == 5) && i == 1) || (code & 2)) {
1256                                 p[out].x=p1.x;
1257                                 p[out].y=p1.y;
1258                                 w[out*step]=p1.w;
1259                                 out++;
1260                         }
1261                         if (code) {
1262                                 p[out].x=p2.x;
1263                                 p[out].y=p2.y;
1264                                 w[out*step]=p2.w;
1265                                 out++;
1266                         }
1267                         if (i == count-1 || (code & 4)) {
1268                                 if (out > 1) {
1269                                         if (poly) {     
1270                                                 graphics_draw_polyline_as_polygon(gra, gc, p, out, w, step);
1271                                         } else
1272                                                 gra->meth.draw_lines(gra->priv, gc->priv, p, out);
1273                                         out=0;
1274                                 }
1275                         }
1276                 }
1277         }
1278 }
1279
1280 static int
1281 is_inside(struct point *p, struct point_rect *r, int edge)
1282 {
1283         switch(edge) {
1284         case 0:
1285                 return p->x >= r->lu.x;
1286         case 1:
1287                 return p->x <= r->rl.x;
1288         case 2:
1289                 return p->y >= r->lu.y;
1290         case 3:
1291                 return p->y <= r->rl.y;
1292         default:
1293                 return 0;
1294         }
1295 }
1296
1297 static void
1298 poly_intersection(struct point *p1, struct point *p2, struct point_rect *r, int edge, struct point *ret)
1299 {
1300         int dx=p2->x-p1->x;
1301         int dy=p2->y-p1->y;
1302         switch(edge) {
1303         case 0:
1304                 ret->y=p1->y+(r->lu.x-p1->x)*dy/dx;
1305                 ret->x=r->lu.x;
1306                 break;
1307         case 1:
1308                 ret->y=p1->y+(r->rl.x-p1->x)*dy/dx;
1309                 ret->x=r->rl.x;
1310                 break;
1311         case 2:
1312                 ret->x=p1->x+(r->lu.y-p1->y)*dx/dy;
1313                 ret->y=r->lu.y;
1314                 break;
1315         case 3:
1316                 ret->x=p1->x+(r->rl.y-p1->y)*dx/dy;
1317                 ret->y=r->rl.y;
1318                 break;
1319         }
1320 }
1321
1322 static void
1323 graphics_draw_polygon_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pin, int count_in)
1324 {
1325         struct point_rect r=gra->r;
1326         struct point *pout,*p,*s,pi;
1327         struct point p1[count_in*8+1];
1328         struct point p2[count_in*8+1];
1329         int count_out,edge=3;
1330         int i;
1331 #if 0
1332         r.lu.x+=20;
1333         r.lu.y+=20;
1334         r.rl.x-=20;
1335         r.rl.y-=20;
1336 #endif
1337
1338         pout=p1;
1339         for (edge = 0 ; edge < 4 ; edge++) {
1340                 p=pin;
1341                 s=pin+count_in-1;
1342                 count_out=0;
1343                 for (i = 0 ; i < count_in ; i++) {
1344                         if (is_inside(p, &r, edge)) {
1345                                 if (! is_inside(s, &r, edge)) {
1346                                         poly_intersection(s,p,&r,edge,&pi);
1347                                         pout[count_out++]=pi;
1348                                 }
1349                                 pout[count_out++]=*p;
1350                         } else {
1351                                 if (is_inside(s, &r, edge)) {
1352                                         poly_intersection(p,s,&r,edge,&pi);
1353                                         pout[count_out++]=pi;
1354                                 }
1355                         }
1356                         s=p;
1357                         p++;
1358                 }
1359                 count_in=count_out;
1360                 if (pin == p1) {
1361                         pin=p2;
1362                         pout=p1;
1363                 } else {
1364                         pin=p1;
1365                         pout=p2;
1366                 }
1367         }
1368         gra->meth.draw_polygon(gra->priv, gc->priv, pin, count_in);
1369 }
1370
1371
1372 static void
1373 display_context_free(struct display_context *dc)
1374 {
1375         if (dc->gc)
1376                 graphics_gc_destroy(dc->gc);
1377         if (dc->img)
1378                 graphics_image_free(dc->gra, dc->img);
1379         dc->gc=NULL;
1380         dc->img=NULL;
1381 }
1382
1383 static struct graphics_font *
1384 get_font(struct graphics *gra, int size)
1385 {
1386         if (size > 64)
1387                 size=64;
1388         if (size >= gra->font_len) {
1389                 gra->font=g_renew(struct graphics_font *, gra->font, size+1);
1390                 while (gra->font_len <= size) 
1391                         gra->font[gra->font_len++]=NULL;
1392         }
1393         if (! gra->font[size])
1394                 gra->font[size]=graphics_font_new(gra, size*20, 0);
1395         return gra->font[size];
1396 }
1397
1398
1399 static void
1400 displayitem_draw(struct displayitem *di, void *dummy, struct display_context *dc)
1401 {
1402         int width[16384];
1403         int i,count;
1404         struct point pa[16384];
1405         struct graphics *gra=dc->gra;
1406         struct graphics_gc *gc=dc->gc;
1407         struct element *e=dc->e;
1408         struct graphics_image *img=dc->img;
1409         struct point p;
1410         char path[PATH_MAX];
1411
1412         di->displayed=1;
1413         if (! gc) {
1414                 gc=graphics_gc_new(gra);
1415                 gc->meth.gc_set_foreground(gc->priv, &e->color);
1416                 dc->gc=gc;
1417         }
1418         if (dc->e->type == element_polyline) {
1419                 count=transform(dc->trans, dc->pro, di->c, pa, di->count, 1, e->u.polyline.width, width);
1420         }
1421         else
1422                 count=transform(dc->trans, dc->pro, di->c, pa, di->count, 1, 0, NULL);
1423         switch (e->type) {
1424         case element_polygon:
1425 #if 0
1426                 {
1427                         int i;
1428                         for (i = 0 ; i < count ; i++) {
1429                                 dbg(0,"pa[%d]=%d,%d\n", i, pa[i].x, pa[i].y);
1430                         }
1431                 }
1432                 dbg(0,"element_polygon count=%d\n",count);
1433 #endif
1434 #if 1
1435                 graphics_draw_polygon_clipped(gra, gc, pa, count);
1436 #endif
1437                 break;
1438         case element_polyline:
1439 #if 0
1440                 if (e->u.polyline.width > 1) {
1441                         graphics_draw_polyline_as_polygon(gra, gc, pa, count, width, 0);
1442                 } else {
1443 #else
1444                 {
1445 #if 0
1446                          if (e->u.polyline.width > 1)
1447                                      gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
1448 #else
1449                         gc->meth.gc_set_linewidth(gc->priv, 1);
1450 #endif
1451
1452                         
1453 #endif
1454                         if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0)
1455                                 graphics_gc_set_dashes(gc, e->u.polyline.width, 
1456                                                        e->u.polyline.offset,
1457                                                        e->u.polyline.dash_table,
1458                                                        e->u.polyline.dash_num);
1459 #if 0
1460                         if (di->label && !strcmp(di->label, "Bahnhofstr.") && di->item.type != type_street_1_city) {
1461                                 dbg(0,"0x%x,0x%x %s\n", di->item.id_hi, di->item.id_lo, item_to_name(di->item.type));
1462 #endif
1463                         for (i = 0 ; i < count ; i++) {
1464                                 if (width[i] < 2)
1465                                         width[i]=2;
1466                         }
1467                         graphics_draw_polyline_clipped(gra, gc, pa, count, width, 1, e->u.polyline.width > 1);
1468 #if 0
1469                         }
1470 #endif
1471                 }
1472                 break;
1473         case element_circle:
1474                 if (count) {
1475                         if (e->u.circle.width > 1) 
1476                                 gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
1477                         gra->meth.draw_circle(gra->priv, gc->priv, pa, e->u.circle.radius);
1478                         if (di->label && e->text_size) {
1479                                 struct graphics_font *font=get_font(gra, e->text_size);
1480                                 p.x=pa[0].x+3;
1481                                 p.y=pa[0].y+10;
1482                                 if (font)
1483                                         gra->meth.draw_text(gra->priv, gra->gc[2]->priv, gra->gc[1]->priv, font->priv, di->label, &p, 0x10000, 0);
1484                                 else
1485                                         dbg(0,"Failed to get font with size %d\n",e->text_size);
1486                         }
1487                 }
1488                 break;
1489         case element_text:
1490                 if (count && di->label) {
1491                         struct graphics_font *font=get_font(gra, e->text_size);
1492                         if (font)
1493                                 label_line(gra, gra->gc[2], gra->gc[1], font, pa, count, di->label);
1494                         else
1495                                 dbg(0,"Failed to get font with size %d\n",e->text_size);
1496                 }
1497                 break;
1498         case element_icon:
1499                 if (count) {
1500                         if (!img) {
1501                                 if (e->u.icon.src[0] == '/')
1502                                         strcpy(path,e->u.icon.src);
1503                                 else
1504                                         sprintf(path,"%s/xpm/%s", navit_sharedir, e->u.icon.src);
1505                                 img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation);
1506                                 if (img)
1507                                         dc->img=img;
1508                                 else
1509                                         dbg(0,"failed to load icon '%s'\n", e->u.icon.src);
1510                         }
1511                         if (img) {
1512                                 p.x=pa[0].x - img->hot.x;
1513                                 p.y=pa[0].y - img->hot.y;
1514                                 gra->meth.draw_image(gra->priv, gra->gc[0]->priv, &p, img->priv);
1515                         }
1516                 }
1517                 break;
1518         case element_image:
1519                 dbg(1,"image: '%s'\n", di->label);
1520                 if (gra->meth.draw_image_warp)
1521                         gra->meth.draw_image_warp(gra->priv, gra->gc[0]->priv, pa, count, di->label);
1522                 else
1523                         dbg(0,"draw_image_warp not supported by graphics driver drawing '%s'\n", di->label);
1524                 break;
1525         case element_arrows:
1526                 display_draw_arrows(gra,gc,pa,count);
1527                 break;
1528         default:
1529                 printf("Unhandled element type %d\n", e->type);
1530         
1531         }
1532 }
1533 /**
1534  * FIXME
1535  * @param <>
1536  * @returns <>
1537  * @author Martin Schaller (04/2008)
1538 */
1539 static void xdisplay_draw_elements(struct graphics *gra, struct displaylist *display_list, struct itemgra *itm)
1540 {
1541         struct element *e;
1542         GList *es,*types;
1543         GHashTable *h;
1544         enum item_type type;
1545
1546         es=itm->elements;
1547         while (es) {
1548                 e=es->data;
1549                 display_list->dc.e=e;
1550                 types=itm->type;
1551                 while (types) {
1552                         type=GPOINTER_TO_INT(types->data);
1553                         h=g_hash_table_lookup(display_list->dl, GINT_TO_POINTER(type));
1554                         if (h) {
1555                                 g_hash_table_foreach(h, (GHFunc)displayitem_draw, &display_list->dc);
1556                                 display_context_free(&display_list->dc);
1557                         }
1558                         types=g_list_next(types);
1559                 }
1560                 es=g_list_next(es);
1561         }
1562 }
1563
1564 void
1565 graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct transformation *t)
1566 {
1567         GList *es;
1568         struct point p;
1569         struct coord c;
1570         char *label=NULL;
1571         struct graphics_gc *gc = NULL;
1572         struct graphics_image *img;
1573         char path[PATH_MAX];
1574         es=itm->elements;
1575         c.x=0;
1576         c.y=0;
1577         while (es) {
1578                 struct element *e=es->data;
1579                 int count=e->coord_count;
1580                 struct point pnt[count+1];
1581                 if (count)
1582                         transform(t, projection_screen, e->coord, pnt, count, 0, 0, NULL);
1583                 else {
1584                         transform(t, projection_screen, &c, pnt, 1, 0, 0, NULL);
1585                         count=1;
1586                 }
1587                 gc=graphics_gc_new(gra);
1588                 gc->meth.gc_set_foreground(gc->priv, &e->color);
1589                 switch (e->type) {
1590                 case element_polyline:
1591                         if (e->u.polyline.width > 1) 
1592                                 gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
1593                         if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0)
1594                                 graphics_gc_set_dashes(gc, e->u.polyline.width, 
1595                                                        e->u.polyline.offset,
1596                                                        e->u.polyline.dash_table,
1597                                                        e->u.polyline.dash_num);
1598                         gra->meth.draw_lines(gra->priv, gc->priv, pnt, count);
1599                         break;
1600                 case element_polygon:
1601                         gra->meth.draw_polygon(gra->priv, gc->priv, pnt, count);
1602                         break;
1603                 case element_circle:
1604                         if (e->u.circle.width > 1) 
1605                                 gc->meth.gc_set_linewidth(gc->priv, e->u.polyline.width);
1606                         gra->meth.draw_circle(gra->priv, gc->priv, &pnt[0], e->u.circle.radius);
1607                         #if 0
1608                         // Leftover code,  displayitem_draw is intended to be merged with with graphics_draw_itemgra
1609                         if (label && e->text_size) {
1610                                 struct graphics_font *font=get_font(gra, e->text_size);
1611                                 p.x=pnt[0].x+3;
1612                                 p.y=pnt[0].y+10;
1613                                 if (font) 
1614                                         gra->meth.draw_text(gra->priv, gra->gc[2]->priv, gra->gc[1]->priv, font->priv, label, &p, 0x10000, 0);
1615                                 else
1616                                         dbg(0,"Failed to get font with size %d\n",e->text_size);
1617                         }
1618                         # endif
1619                         break;
1620                 case element_icon:
1621                         if (e->u.icon.src[0] == '/') 
1622                                 strcpy(path,e->u.icon.src);
1623                         else
1624                                 sprintf(path,"%s/xpm/%s", navit_sharedir, e->u.icon.src);
1625                         img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation);
1626                         if (! img)
1627                                 dbg(0,"failed to load icon '%s'\n", e->u.icon.src);
1628                         else {
1629                                 p.x=pnt[0].x - img->hot.x;
1630                                 p.y=pnt[0].y - img->hot.y;
1631                                 gra->meth.draw_image(gra->priv, gc->priv, &p, img->priv);
1632                                 graphics_image_free(gra, img);
1633                         }
1634                         break;
1635                 default:
1636                         dbg(0,"dont know how to draw %d\n", e->type);
1637                 }
1638                 graphics_gc_destroy(gc);
1639                 es=g_list_next(es);
1640         }
1641 }
1642
1643 /**
1644  * FIXME
1645  * @param <>
1646  * @returns <>
1647  * @author Martin Schaller (04/2008)
1648 */
1649 static void xdisplay_draw_layer(struct displaylist *display_list, struct graphics *gra, struct layer *lay, int order)
1650 {
1651         GList *itms;
1652         struct itemgra *itm;
1653
1654         itms=lay->itemgras;
1655         while (itms) {
1656                 itm=itms->data;
1657                 if (order >= itm->order.min && order <= itm->order.max) 
1658                         xdisplay_draw_elements(gra, display_list, itm);
1659                 itms=g_list_next(itms);
1660         }
1661 }
1662
1663 /**
1664  * FIXME
1665  * @param <>
1666  * @returns <>
1667  * @author Martin Schaller (04/2008)
1668 */
1669 static void xdisplay_draw(struct displaylist *display_list, struct graphics *gra, struct layout *l, int order)
1670 {
1671         GList *lays;
1672         struct layer *lay;
1673         
1674         lays=l->layers;
1675         while (lays) {
1676                 lay=lays->data;
1677                 xdisplay_draw_layer(display_list, gra, lay, order);
1678                 lays=g_list_next(lays);
1679         }
1680 }
1681
1682 /**
1683  * FIXME
1684  * @param <>
1685  * @returns <>
1686  * @author Martin Schaller (04/2008)
1687 */
1688 extern void *route_selection;
1689
1690 static void
1691 do_draw(struct displaylist *displaylist, int cancel)
1692 {
1693         struct item *item;
1694         int count,max=16384,workload=0;
1695         struct coord ca[max];
1696         struct attr attr;
1697
1698         while (!cancel) {
1699                 if (!displaylist->msh) 
1700                         displaylist->msh=mapset_open(displaylist->ms);
1701                 if (!displaylist->m) {
1702                         displaylist->m=mapset_next(displaylist->msh, 1);
1703                         if (!displaylist->m) {
1704                                 mapset_close(displaylist->msh);
1705                                 displaylist->msh=NULL;
1706                                 break;
1707                         }
1708                         displaylist->dc.pro=map_projection(displaylist->m);
1709                         displaylist->conv=map_requires_conversion(displaylist->m);
1710                         displaylist->sel=transform_get_selection(displaylist->dc.trans, displaylist->dc.pro, displaylist->order);
1711                         displaylist->mr=map_rect_new(displaylist->m, displaylist->sel);
1712                 }
1713                 if (displaylist->mr) {
1714                         while ((item=map_rect_get_item(displaylist->mr))) {
1715                                 count=item_coord_get_within_selection(item, ca, item->type < type_line ? 1: max, displaylist->sel);
1716                                 if (! count)
1717                                         continue;
1718                                 if (count == max) 
1719                                         dbg(0,"point count overflow %d\n", count);
1720                                 if (!item_attr_get(item, attr_label, &attr))
1721                                         attr.u.str=NULL;
1722                                 if (displaylist->conv && attr.u.str && attr.u.str[0]) {
1723                                         char *str=map_convert_string(displaylist->m, attr.u.str);
1724                                         display_add(displaylist, item, count, ca, str);
1725                                         map_convert_free(str);
1726                                 } else
1727                                         display_add(displaylist, item, count, ca, attr.u.str);
1728                                 workload++;
1729                                 if (workload == displaylist->workload)
1730                                         return;
1731                         }
1732                         map_rect_destroy(displaylist->mr);
1733                 }
1734                 map_selection_destroy(displaylist->sel);
1735                 displaylist->mr=NULL;
1736                 displaylist->sel=NULL;
1737                 displaylist->m=NULL;
1738         }
1739         event_remove_idle(displaylist->idle_ev);
1740         displaylist->idle_ev=NULL;
1741         displaylist->busy=0;
1742         graphics_process_selection(displaylist->dc.gra, displaylist);
1743         if (! cancel) 
1744                 graphics_displaylist_draw(displaylist->dc.gra, displaylist, displaylist->dc.trans, displaylist->layout, 1);
1745         map_rect_destroy(displaylist->mr);
1746         map_selection_destroy(displaylist->sel);
1747         mapset_close(displaylist->msh);
1748         displaylist->mr=NULL;
1749         displaylist->sel=NULL;
1750         displaylist->m=NULL;
1751         displaylist->msh=NULL;
1752         callback_call_1(displaylist->cb, cancel);
1753 }
1754
1755 /**
1756  * FIXME
1757  * @param <>
1758  * @returns <>
1759  * @author Martin Schaller (04/2008)
1760 */
1761 void graphics_displaylist_draw(struct graphics *gra, struct displaylist *displaylist, struct transformation *trans, struct layout *l, int callback)
1762 {
1763         int order=transform_get_order(trans);
1764         displaylist->dc.trans=trans;
1765         displaylist->dc.gra=gra;
1766         // FIXME find a better place to set the background color
1767         if (l) {
1768                 graphics_gc_set_background(gra->gc[0], &l->color);
1769                 graphics_gc_set_foreground(gra->gc[0], &l->color);
1770                 gra->default_font = g_strdup(l->font);
1771         }
1772         graphics_background_gc(gra, gra->gc[0]);
1773         gra->meth.draw_mode(gra->priv, draw_mode_begin);
1774         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);
1775         if (l) 
1776                 xdisplay_draw(displaylist, gra, l, order+l->order_delta);
1777         if (callback)
1778                 callback_list_call_attr_0(gra->cbl, attr_postdraw);
1779         gra->meth.draw_mode(gra->priv, draw_mode_end);
1780 }
1781
1782 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)
1783 {
1784         int order=transform_get_order(trans);
1785
1786         dbg(1,"enter");
1787         if (displaylist->busy) {
1788                 if (async == 1)
1789                         return;
1790                 do_draw(displaylist, 1);
1791         }
1792         xdisplay_free(displaylist->dl);
1793         dbg(1,"order=%d\n", order);
1794
1795         displaylist->dc.gra=gra;
1796         displaylist->ms=mapset;
1797         displaylist->dc.trans=trans;
1798         displaylist->workload=async ? 100 : 0;
1799         displaylist->cb=cb;
1800         if (l)
1801                 order+=l->order_delta;
1802         displaylist->order=order;
1803         displaylist->busy=1;
1804         displaylist->layout=l;
1805         if (async) {
1806                 if (! displaylist->idle_cb)
1807                         displaylist->idle_cb=callback_new_2(callback_cast(do_draw), displaylist, 0);
1808                 displaylist->idle_ev=event_add_idle(50, displaylist->idle_cb);
1809         }
1810 }
1811 /**
1812  * FIXME
1813  * @param <>
1814  * @returns <>
1815  * @author Martin Schaller (04/2008)
1816 */
1817 void graphics_draw(struct graphics *gra, struct displaylist *displaylist, struct mapset *mapset, struct transformation *trans, struct layout *l, int async, struct callback *cb)
1818 {
1819         graphics_load_mapset(gra, displaylist, mapset, trans, l, async, cb);
1820         if (! async)
1821                 do_draw(displaylist, 0);
1822 }
1823
1824 int
1825 graphics_draw_cancel(struct graphics *gra, struct displaylist *displaylist)
1826 {
1827         if (!displaylist->busy)
1828                 return 0;
1829         do_draw(displaylist, 1);
1830         return 1;
1831 }
1832
1833 /**
1834  * FIXME
1835  * @param <>
1836  * @returns <>
1837  * @author Martin Schaller (04/2008)
1838 */
1839 struct displaylist_handle {
1840         GList *hl_head,*hl,*l_head,*l;
1841 };
1842
1843 /**
1844  * FIXME
1845  * @param <>
1846  * @returns <>
1847  * @author Martin Schaller (04/2008)
1848 */
1849 struct displaylist_handle * graphics_displaylist_open(struct displaylist *displaylist)
1850 {
1851         struct displaylist_handle *ret;
1852
1853         ret=g_new0(struct displaylist_handle, 1);
1854         ret->hl_head=ret->hl=g_hash_to_list(displaylist->dl);
1855         ret->l_head=ret->l=g_hash_to_list_keys(ret->hl->data);
1856
1857         return ret;
1858 }
1859
1860 /**
1861  * FIXME
1862  * @param <>
1863  * @returns <>
1864  * @author Martin Schaller (04/2008)
1865 */
1866 struct displayitem * graphics_displaylist_next(struct displaylist_handle *dlh)
1867 {
1868         struct displayitem *ret;
1869         if (! dlh->l) {
1870                 dlh->hl=g_list_next(dlh->hl);
1871                 if (!dlh->hl)
1872                         return NULL;
1873                 g_list_free(dlh->l_head);
1874                 dlh->l_head=dlh->l=g_hash_to_list_keys(dlh->hl->data);
1875         }
1876         ret=dlh->l->data;
1877         dlh->l=g_list_next(dlh->l);
1878         return ret;
1879 }
1880
1881 /**
1882  * FIXME
1883  * @param <>
1884  * @returns <>
1885  * @author Martin Schaller (04/2008)
1886 */
1887 void graphics_displaylist_close(struct displaylist_handle *dlh)
1888 {
1889         g_list_free(dlh->hl_head);
1890         g_list_free(dlh->l_head);
1891         g_free(dlh);
1892 }
1893
1894 /**
1895  * FIXME
1896  * @param <>
1897  * @returns <>
1898  * @author Martin Schaller (04/2008)
1899 */
1900 struct displaylist * graphics_displaylist_new(void)
1901 {
1902         struct displaylist *ret=g_new0(struct displaylist, 1);
1903
1904         ret->dl=g_hash_table_new(NULL,NULL);
1905
1906         return ret;
1907 }
1908
1909 /**
1910  * FIXME
1911  * @param <>
1912  * @returns <>
1913  * @author Martin Schaller (04/2008)
1914 */
1915 struct item * graphics_displayitem_get_item(struct displayitem *di)
1916 {
1917         return &di->item;       
1918 }
1919
1920 /**
1921  * FIXME
1922  * @param <>
1923  * @returns <>
1924  * @author Martin Schaller (04/2008)
1925 */
1926 char * graphics_displayitem_get_label(struct displayitem *di)
1927 {
1928         return di->label;
1929 }
1930
1931 /**
1932  * FIXME
1933  * @param <>
1934  * @returns <>
1935  * @author Martin Schaller (04/2008)
1936 */
1937 static int within_dist_point(struct point *p0, struct point *p1, int dist)
1938 {
1939         if (p0->x == 32767 || p0->y == 32767 || p1->x == 32767 || p1->y == 32767)
1940                 return 0;
1941         if (p0->x == -32768 || p0->y == -32768 || p1->x == -32768 || p1->y == -32768)
1942                 return 0;
1943         if ((p0->x-p1->x)*(p0->x-p1->x) + (p0->y-p1->y)*(p0->y-p1->y) <= dist*dist) {
1944                 return 1;
1945         }
1946         return 0;
1947 }
1948
1949 /**
1950  * FIXME
1951  * @param <>
1952  * @returns <>
1953  * @author Martin Schaller (04/2008)
1954 */
1955 static int within_dist_line(struct point *p, struct point *line_p0, struct point *line_p1, int dist)
1956 {
1957         int vx,vy,wx,wy;
1958         int c1,c2;
1959         struct point line_p;
1960
1961         if (line_p0->x < line_p1->x) {
1962                 if (p->x < line_p0->x - dist)
1963                         return 0;
1964                 if (p->x > line_p1->x + dist)
1965                         return 0;
1966         } else {
1967                 if (p->x < line_p1->x - dist)
1968                         return 0;
1969                 if (p->x > line_p0->x + dist)
1970                         return 0;
1971         }
1972         if (line_p0->y < line_p1->y) {
1973                 if (p->y < line_p0->y - dist)
1974                         return 0;
1975                 if (p->y > line_p1->y + dist)
1976                         return 0;
1977         } else {
1978                 if (p->y < line_p1->y - dist)
1979                         return 0;
1980                 if (p->y > line_p0->y + dist)
1981                         return 0;
1982         }
1983                 
1984         vx=line_p1->x-line_p0->x;
1985         vy=line_p1->y-line_p0->y;
1986         wx=p->x-line_p0->x;
1987         wy=p->y-line_p0->y;
1988
1989         c1=vx*wx+vy*wy;
1990         if ( c1 <= 0 )
1991                 return within_dist_point(p, line_p0, dist);
1992         c2=vx*vx+vy*vy;
1993         if ( c2 <= c1 )
1994                 return within_dist_point(p, line_p1, dist);
1995
1996         line_p.x=line_p0->x+vx*c1/c2;
1997         line_p.y=line_p0->y+vy*c1/c2;
1998         return within_dist_point(p, &line_p, dist);
1999 }
2000
2001 /**
2002  * FIXME
2003  * @param <>
2004  * @returns <>
2005  * @author Martin Schaller (04/2008)
2006 */
2007 static int within_dist_polyline(struct point *p, struct point *line_pnt, int count, int dist, int close)
2008 {
2009         int i;
2010         for (i = 0 ; i < count-1 ; i++) {
2011                 if (within_dist_line(p,line_pnt+i,line_pnt+i+1,dist)) {
2012                         return 1;
2013                 }
2014         }
2015         if (close)
2016                 return (within_dist_line(p,line_pnt,line_pnt+count-1,dist));
2017         return 0;
2018 }
2019
2020 /**
2021  * FIXME
2022  * @param <>
2023  * @returns <>
2024  * @author Martin Schaller (04/2008)
2025 */
2026 static int within_dist_polygon(struct point *p, struct point *poly_pnt, int count, int dist)
2027 {
2028         int i, j, c = 0;
2029         for (i = 0, j = count-1; i < count; j = i++) {
2030                 if ((((poly_pnt[i].y <= p->y) && ( p->y < poly_pnt[j].y )) ||
2031                 ((poly_pnt[j].y <= p->y) && ( p->y < poly_pnt[i].y))) &&
2032                 (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)) 
2033                         c = !c;
2034         }
2035         if (! c)
2036                 return within_dist_polyline(p, poly_pnt, count, dist, 1);
2037         return c;
2038 }
2039
2040 /**
2041  * FIXME
2042  * @param <>
2043  * @returns <>
2044  * @author Martin Schaller (04/2008)
2045 */
2046 int graphics_displayitem_within_dist(struct displaylist *displaylist, struct displayitem *di, struct point *p, int dist)
2047 {
2048         struct point pa[16384];
2049         int count;
2050
2051         count=transform(displaylist->dc.trans, displaylist->dc.pro, di->c, pa, di->count, 1, 0, NULL);
2052         
2053         if (di->item.type < type_line) {
2054                 return within_dist_point(p, &pa[0], dist);
2055         }
2056         if (di->item.type < type_area) {
2057                 return within_dist_polyline(p, pa, count, dist, 0);
2058         }
2059         return within_dist_polygon(p, pa, count, dist);
2060 }
2061
2062
2063 static enum item_type
2064 graphics_selection_type(enum item_type type)
2065 {
2066         if (type < type_line) 
2067                 return type_selected_point;
2068         if (type < type_area) 
2069                 return type_selected_line;
2070         return type_selected_area;
2071         
2072 }
2073
2074
2075 static void
2076 graphics_process_selection_item(struct displaylist *dl, struct item *item)
2077 {
2078         struct displayitem di,*di_res;
2079         GHashTable *h;
2080
2081         di.item=*item;
2082         di.label=NULL;
2083         di.displayed=0;
2084         di.count=0;
2085         h=g_hash_table_lookup(dl->dl, GINT_TO_POINTER(di.item.type));
2086         if (h) {
2087                 di_res=g_hash_table_lookup(h, &di);
2088                 if (di_res) {
2089                         di.item.type=graphics_selection_type(di.item.type);
2090                         display_add(dl, &di.item, di_res->count, di_res->c, NULL);
2091                 }
2092         }
2093 }
2094
2095 void
2096 graphics_add_selection(struct graphics *gra, struct item *item, struct displaylist *dl)
2097 {
2098         struct item *item_dup=g_new(struct item, 1);
2099         *item_dup=*item;
2100         gra->selection=g_list_append(gra->selection, item_dup);
2101         if (dl)
2102                 graphics_process_selection_item(dl, item_dup);
2103 }
2104
2105 void
2106 graphics_remove_selection(struct graphics *gra, struct item *item, struct displaylist *dl)
2107 {
2108         GList *curr;
2109         int found;
2110
2111         for (;;) {
2112                 curr=gra->selection;
2113                 found=0;
2114                 while (curr) {
2115                         struct item *sitem=curr->data;
2116                         if (item_is_equal(*item,*sitem)) {
2117                                 if (dl) {
2118                                         struct displayitem di;
2119                                         GHashTable *h;
2120                                         di.item=*sitem;
2121                                         di.label=NULL;
2122                                         di.displayed=0;
2123                                         di.count=0;
2124                                         di.item.type=graphics_selection_type(di.item.type);
2125                                         h=g_hash_table_lookup(dl->dl, GINT_TO_POINTER(di.item.type));
2126                                         if (h)
2127                                                 g_hash_table_remove(h, &di);
2128                                 }
2129                                 g_free(sitem);
2130                                 gra->selection=g_list_remove(gra->selection, curr->data);
2131                                 found=1;
2132                                 break;
2133                         }
2134                 }
2135                 if (!found)
2136                         return;
2137         }
2138 }
2139
2140 void
2141 graphics_clear_selection(struct graphics *gra, struct displaylist *dl)
2142 {
2143         while (gra->selection) 
2144                 graphics_remove_selection(gra, (struct item *)gra->selection->data, dl);
2145 }
2146
2147 static void
2148 graphics_process_selection(struct graphics *gra, struct displaylist *dl)
2149 {
2150         GList *curr;
2151
2152         curr=gra->selection;
2153         while (curr) {
2154                 struct item *item=curr->data;
2155                 graphics_process_selection_item(dl, item);
2156                 curr=g_list_next(curr);
2157         }
2158 }