Fix:core:Three memleaks fixed.
[profile/ivi/navit.git] / navit / navit / gui / internal / gui_internal.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2010 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: gui_internal.c
23 //# Description: New "internal" GUI for use with any graphics library
24 //# Comment: Trying to make a touchscreen friendly GUI
25 //# Authors: Martin Schaller (04/2008), Stefan Klumpp (04/2008)
26 //#
27 //##############################################################################################################
28
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <math.h>
34 #include <glib.h>
35 #include <time.h>
36 #include "config.h"
37 #ifdef HAVE_API_WIN32_BASE
38 #include <windows.h>
39 #endif
40 #ifndef _MSC_VER
41 #include <sys/time.h>
42 #endif /* _MSC_VER */
43 #include "item.h"
44 #include "file.h"
45 #include "navit.h"
46 #include "navit_nls.h"
47 #include "gui.h"
48 #include "coord.h"
49 #include "point.h"
50 #include "plugin.h"
51 #include "graphics.h"
52 #include "transform.h"
53 #include "color.h"
54 #include "map.h"
55 #include "layout.h"
56 #include "callback.h"
57 #include "vehicle.h"
58 #include "vehicleprofile.h"
59 #include "window.h"
60 #include "config_.h"
61 #include "keys.h"
62 #include "mapset.h"
63 #include "route.h"
64 #include "navit/search.h"
65 #include "track.h"
66 #include "country.h"
67 #include "config.h"
68 #include "event.h"
69 #include "navit_nls.h"
70 #include "navigation.h"
71 #include "gui_internal.h"
72 #include "command.h"
73 #include "xmlconfig.h"
74 #include "util.h"
75 #include "bookmarks.h"
76 #include "debug.h"
77 #include "fib.h"
78 #include "types.h"
79
80
81 extern char *version;
82
83 struct form {
84         char *onsubmit;
85 };
86
87
88 struct menu_data {
89         struct widget *search_list;
90         struct widget *keyboard;
91         struct widget *button_bar;
92         struct widget *menu;
93         int keyboard_mode;
94         void (*redisplay)(struct gui_priv *priv, struct widget *widget, void *data);
95         struct widget *redisplay_widget;
96         char *href;
97         struct attr refresh_callback_obj,refresh_callback;
98 };
99
100 //##############################################################################################################
101 //# Description:
102 //# Comment:
103 //# Authors: Martin Schaller (04/2008)
104 //##############################################################################################################
105 struct widget {
106         enum widget_type type;
107         struct graphics_gc *background,*text_background;
108         struct graphics_gc *foreground_frame;
109         struct graphics_gc *foreground;
110         char *text;
111         struct graphics_image *img;
112          /**
113           * A function to be invoked on actions.
114           * @li widget The widget that is receiving the button press.
115           *
116           */
117         void (*func)(struct gui_priv *priv, struct widget *widget, void *data);
118         int reason;
119         int datai;
120         void *data;
121         /**
122          * @brief A function to deallocate data
123          */
124         void (*data_free)(void *data);
125
126         /**
127          * @brief a function that will be called as the widget is being destroyed.
128          * This function can act as a destructor for the widget. It allows for
129          * on deallocation actions to be specified on a per widget basis.
130          * This function will call g_free on the widget (if required).
131          */
132         void (*free) (struct gui_priv *this_, struct widget * w);
133         char *prefix;
134         char *name;
135         char *speech;
136         char *command;
137         struct pcoord c;
138         struct item item;
139         int selection_id;
140         int state;
141         struct point p;
142         int wmin,hmin;
143         int w,h;
144         int textw,texth;
145         int font_idx;
146         int bl,br,bt,bb,spx,spy;
147         int border;
148         int packed;
149         /**
150          * The number of widgets to layout horizontally when doing
151          * a orientation_horizontal_vertical layout
152          */
153         int cols;
154         enum flags flags;
155         int flags2;
156         void *instance;
157         int (*set_attr)(void *, struct attr *);
158         int (*get_attr)(void *, enum attr_type, struct attr *, struct attr_iter *);
159         void (*remove_cb)(void *, struct callback *cb);
160         struct callback *cb;
161         struct attr on;
162         struct attr off;
163         int deflt;
164         int is_on;
165         int redraw;
166         struct menu_data *menu_data;
167         struct form *form;
168         GList *children;
169         struct widget *parent;
170 };
171
172 /**
173  * @brief A structure to store configuration values.
174  *
175  * This structure stores configuration values for how gui elements in the internal GUI
176  * should be drawn.
177  */
178 struct gui_config_settings {
179
180   /**
181    * The base size (in fractions of a point) to use for text.
182    */
183   int font_size;
184   /**
185    * The size (in pixels) that xs style icons should be scaled to.
186    * This icon size is typically used in various lists and should be set to value which allows a list row to be easily cliked or dragged.
187    */
188   int icon_xs;
189   /**
190    * The size (in pixels) that s style icons (small) should be scaled to, used for the menu top row icons
191    */
192   int icon_s;
193   /**
194    * The size (in pixels) that l style icons should be scaled to, used for icons defined in the menu html
195    */
196   int icon_l;
197   /**
198    * The default amount of spacing (in pixels) to place between GUI elements.
199    */
200   int spacing;
201
202 };
203
204 /**
205  * Indexes into the config_profiles array.
206  */
207 const int LARGE_PROFILE=0;
208 const int MEDIUM_PROFILE=1;
209 const int SMALL_PROFILE=2;
210
211 /**
212  * The default config profiles.
213  *
214  * [0] =>  LARGE_PROFILE (screens 640 in one dimension)
215  * [1] =>  MEDIUM PROFILE (screens larger than 320 in one dimension
216  * [2] => Small profile (default)
217  */
218 static struct gui_config_settings config_profiles[]={
219       {545,32,48,96,10}
220     , {300,32,48,64,3}
221       ,{200,16,32,48,2}
222 };
223
224 struct route_data {
225   struct widget * route_table;
226   int route_showing;
227
228 };
229
230 //##############################################################################################################
231 //# Description:
232 //# Comment:
233 //# Authors: Martin Schaller (04/2008)
234 //##############################################################################################################
235 struct gui_priv {
236         struct navit *nav;
237         struct attr self;
238         struct window *win;
239         struct graphics *gra;
240         struct graphics_gc *background;
241         struct graphics_gc *background2;
242         struct graphics_gc *highlight_background;
243         struct graphics_gc *foreground;
244         struct graphics_gc *text_foreground;
245         struct graphics_gc *text_background;
246         struct color background_color, background2_color, text_foreground_color, text_background_color;
247         int spacing;
248         int font_size;
249         int fullscreen;
250         struct graphics_font *fonts[3];
251         /**
252          * The size (in pixels) that xs style icons should be scaled to.
253          * This icon size can be too small to click it on some devices.
254          */
255         int icon_xs;
256         /**
257          * The size (in pixels) that s style icons (small) should be scaled to
258          */
259         int icon_s;
260         /**
261          * The size (in pixels) that l style icons should be scaled to
262          */
263         int icon_l;
264         int pressed;
265         struct widget *widgets;
266         int widgets_count;
267         int redraw;
268         struct widget root;
269         struct widget *highlighted,*editable;
270         struct widget *highlighted_menu;
271         struct pcoord clickp, vehiclep;
272         struct attr *click_coord_geo, *position_coord_geo;
273         struct search_list *sl;
274         int ignore_button;
275         int menu_on_map_click;
276         char *on_map_click;
277         int signal_on_map_click;
278         char *country_iso2;
279         int speech;
280         int keyboard;
281         int keyboard_required;
282         /**
283          * The setting information read from the configuration file.
284          * values of -1 indicate no value was specified in the config file.
285          */
286         struct gui_config_settings config;
287         struct event_idle *idle;
288         struct callback *motion_cb,*button_cb,*resize_cb,*keypress_cb,*window_closed_cb,*idle_cb, *motion_timeout_callback;
289         struct event_timeout *motion_timeout_event;
290         struct point current;
291
292         struct callback * vehicle_cb;
293           /**
294            * Stores information about the route.
295            */
296         struct route_data route_data;
297
298         struct gui_internal_data data;
299         struct callback_list *cbl;
300         int flags;
301         int cols;
302         struct attr osd_configuration;
303         int pitch;
304         int flags_town,flags_street,flags_house_number;
305         int radius;
306         int mouse_button_clicked_on_map;
307 /* html */
308         char *html_text;
309         int html_depth;
310         struct widget *html_container;
311         int html_skip;
312         char *html_anchor;
313         char *href;
314         int html_anchor_found;
315         struct form *form;
316         struct html {
317                 int skip;
318                 enum html_tag {
319                         html_tag_none,
320                         html_tag_a,
321                         html_tag_h1,
322                         html_tag_html,
323                         html_tag_img,
324                         html_tag_script,
325                         html_tag_form,
326                         html_tag_input,
327                         html_tag_div,
328                 } tag;
329                 char *command;
330                 char *name;
331                 char *href;
332                 char *refresh_cond;
333                 struct widget *w;
334                 struct widget *container;
335         } html[10];
336
337 /* gestures */  
338
339         struct gesture_elem {
340                 int msec;
341                 struct point p;
342         } gesture_ring[GESTURE_RINGSIZE];
343         int gesture_ring_last, gesture_ring_first;
344
345
346         int results_map_population;
347 };
348
349
350
351
352
353 struct html_tag_map {
354         char *tag_name;
355         enum html_tag tag;
356 } html_tag_map[] = {
357         {"a",html_tag_a},
358         {"h1",html_tag_h1},
359         {"html",html_tag_html},
360         {"img",html_tag_img},
361         {"script",html_tag_script},
362         {"form",html_tag_form},
363         {"input",html_tag_input},
364         {"div",html_tag_div},
365 };
366
367
368 /**
369  * @brief A structure to store information about a table.
370  *
371  * The table_data widget stores pointers to extra information needed by the
372  * table widget.
373  *
374  * The table_data structure needs to be freed with data_free along with the widget.
375  *
376  */
377 struct table_data
378 {
379   /**
380    * A GList pointer into a widget->children list that indicates the row
381    * currently being rendered at the top of the table.
382    */
383   GList * top_row;
384   /**
385    * A Glist pointer into a widget->children list that indicates the row
386    * currently being rendered at the bottom of the table.
387    */
388   GList * bottom_row;
389
390   /**
391    * A container box that is the child of the table widget that contains+groups
392    * the next and previous button.
393    */
394   struct widget * button_box;
395
396   /**
397    * Button box should not be displayed if button_box_hide is not zero.
398    */
399   int button_box_hide;
400   
401   /**
402    * A button widget to handle 'next page' requests
403    */
404   struct widget * next_button;
405   /**
406    * A button widget to handle 'previous page' requests.
407    */
408   struct widget * prev_button;
409
410
411   /**
412    * a pointer to the gui context.
413    * This is needed by the free function to destory the buttons.
414    */
415   struct  gui_priv *  this;
416 };
417
418 /**
419  * A data structure that holds information about a column that makes up a table.
420  *
421  *
422  */
423 struct table_column_desc
424 {
425
426   /**
427    * The computed height of a cell in the table.
428    */
429   int height;
430
431   /**
432    * The computed width of a cell in the table.
433    */
434   int width;
435 };
436
437
438 static void gui_internal_widget_render(struct gui_priv *this, struct widget *w);
439 static void gui_internal_widget_pack(struct gui_priv *this, struct widget *w);
440 static struct widget * gui_internal_box_new(struct gui_priv *this, enum flags flags);
441 static void gui_internal_widget_append(struct widget *parent, struct widget *child);
442 static void gui_internal_widget_prepend(struct widget *parent, struct widget *child);
443 static void gui_internal_widget_insert_before(struct widget *parent, struct widget *sibling, struct widget *child);
444 static void gui_internal_widget_insert_sorted(struct widget *parent, struct widget *child, GCompareFunc func);
445 static void gui_internal_widget_destroy(struct gui_priv *this, struct widget *w);
446 static void gui_internal_apply_config(struct gui_priv *this);
447
448 static struct widget* gui_internal_widget_table_new(struct gui_priv * this, enum flags flags, int buttons);
449 static struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags);
450 static void gui_internal_table_hide_rows(struct table_data * table_data);
451 static void gui_internal_table_render(struct gui_priv * this, struct widget * w);
452 static void gui_internal_table_pack(struct gui_priv * this, struct widget * w);
453 static void gui_internal_table_button_next(struct gui_priv * this, struct widget * wm, void *data);
454 static void gui_internal_table_button_prev(struct gui_priv * this, struct widget * wm, void *data);
455 static void gui_internal_widget_table_clear(struct gui_priv * this,struct widget * table);
456 static int gui_internal_widget_table_is_empty(struct gui_priv *this,struct widget * table);
457 static GList * gui_internal_widget_table_next_row(GList * row);
458 static GList * gui_internal_widget_table_prev_row(GList * row);
459 static struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags);
460 static void gui_internal_table_data_free(void * d);
461 static void gui_internal_route_update(struct gui_priv * this, struct navit * navit,
462                                       struct vehicle * v);
463 static void gui_internal_route_screen_free(struct gui_priv * this_,struct widget * w);
464 static void gui_internal_populate_route_table(struct gui_priv * this,
465                                        struct navit * navit);
466 static void gui_internal_search_idle_end(struct gui_priv *this);
467 static void gui_internal_search(struct gui_priv *this, char *what, char *type, int flags);
468 static void gui_internal_search_house_number(struct gui_priv *this, struct widget *widget, void *data);
469 static void gui_internal_search_house_number_in_street(struct gui_priv *this, struct widget *widget, void *data);
470 static void gui_internal_search_street(struct gui_priv *this, struct widget *widget, void *data);
471 static void gui_internal_search_street_in_town(struct gui_priv *this, struct widget *widget, void *data);
472 static void gui_internal_search_town(struct gui_priv *this, struct widget *wm, void *data);
473 static void gui_internal_search_town_in_country(struct gui_priv *this, struct widget *wm);
474 static void gui_internal_search_country(struct gui_priv *this, struct widget *widget, void *data);
475 static void gui_internal_check_exit(struct gui_priv *this);
476 static void gui_internal_cmd_view_in_browser(struct gui_priv *this, struct widget *wm, void *data);
477
478 static struct widget *gui_internal_keyboard_do(struct gui_priv *this, struct widget *wkbdb, int mode);
479 static struct menu_data * gui_internal_menu_data(struct gui_priv *this);
480
481 static int gui_internal_is_active_vehicle(struct gui_priv *this, struct vehicle *vehicle);
482 static void gui_internal_html_menu(struct gui_priv *this, const char *document, char *anchor);
483 static void gui_internal_html_load_href(struct gui_priv *this, char *href, int replace);
484 static void gui_internal_destroy(struct gui_priv *this);
485 static void gui_internal_enter(struct gui_priv *this, int ignore);
486 static void gui_internal_enter_setup(struct gui_priv *this);
487 static void gui_internal_html_main_menu(struct gui_priv *this);
488 static void gui_internal_menu_vehicle_settings(struct gui_priv *this, struct vehicle *v, char *name);
489
490
491 /*
492  * * Display image scaled to specific size
493  * * searches for scaleable and pre-scaled image
494  * * @param this Our gui context
495  * * @param name image name
496  * * @param w desired width of image
497  * * @param h desired height of image
498  * * @returns image_struct Ptr to scaled image struct or NULL if not scaled or found
499  * */
500 static struct graphics_image *
501 image_new_scaled(struct gui_priv *this, const char *name, int w, int h)
502 {
503         struct graphics_image *ret=NULL;
504         char *full_path=NULL;
505         full_path=graphics_icon_path(name);
506         ret=graphics_image_new_scaled(this->gra, full_path, w, h);
507         dbg(1,"Trying to load image '%s' (w=%d, h=%d): %s\n", name, w, h, ret ? "OK" : "NOT FOUND");
508         g_free(full_path);
509         if (!ret)
510                 dbg(0,"Failed to load image for '%s' (w=%d, h=%d)\n", name, w, h);
511         return ret;
512 }
513
514 #if 0
515 static struct graphics_image *
516 image_new_o(struct gui_priv *this, char *name)
517 {
518         return image_new_scaled(this, name, -1, -1);
519 }
520 #endif
521
522 /*
523  * * Display image scaled to xs (extra small) size
524  * * This image size can be too small to click it on some devices.
525  * * @param this Our gui context
526  * * @param name image name
527  * * @returns image_struct Ptr to scaled image struct or NULL if not scaled or found
528  * */
529 static struct graphics_image *
530 image_new_xs(struct gui_priv *this, const char *name)
531 {
532         return image_new_scaled(this, name, this->icon_xs, this->icon_xs);
533 }
534
535 /*
536  * * Display image scaled to s (small) size
537  * * @param this Our gui context
538  * * @param name image name
539  * * @returns image_struct Ptr to scaled image struct or NULL if not scaled or found
540  * */
541
542 static struct graphics_image *
543 image_new_s(struct gui_priv *this, const char *name)
544 {
545         return image_new_scaled(this, name, this->icon_s, this->icon_s);
546 }
547
548 /*
549  * * Display image scaled to l (large) size
550  * * @param this Our gui context
551  * * @param name image name
552  * * @returns image_struct Ptr to scaled image struct or NULL if not scaled or found
553  * */
554 static struct graphics_image *
555 image_new_l(struct gui_priv *this, const char *name)
556 {
557         return image_new_scaled(this, name, this->icon_l, this->icon_l);
558 }
559
560 static char *
561 coordinates_geo(const struct coord_geo *gc, char sep)
562 {
563         char latc='N',lngc='E';
564         int lat_deg,lat_min,lat_sec;
565         int lng_deg,lng_min,lng_sec;
566         struct coord_geo g=*gc;
567
568         if (g.lat < 0) {
569                 g.lat=-g.lat;
570                 latc='S';
571         }
572         if (g.lng < 0) {
573                 g.lng=-g.lng;
574                 lngc='W';
575         }
576         lat_deg=g.lat;
577         lat_min=fmod(g.lat*60,60);
578         lat_sec=fmod(g.lat*3600,60);
579         lng_deg=g.lng;
580         lng_min=fmod(g.lng*60,60);
581         lng_sec=fmod(g.lng*3600,60);
582         return g_strdup_printf("%d°%d'%d\" %c%c%d°%d'%d\" %c",lat_deg,lat_min,lat_sec,latc,sep,lng_deg,lng_min,lng_sec,lngc);
583 }
584
585 static char *
586 coordinates(struct pcoord *pc, char sep)
587 {
588         struct coord_geo g;
589         struct coord c;
590         c.x=pc->x;
591         c.y=pc->y;
592         transform_to_geo(pc->pro, &c, &g);
593         return coordinates_geo(&g, sep);
594
595 }
596
597 static void
598 gui_internal_background_render(struct gui_priv *this, struct widget *w)
599 {
600         struct point pnt=w->p;
601         if (w->state & STATE_HIGHLIGHTED)
602                 graphics_draw_rectangle(this->gra, this->highlight_background, &pnt, w->w, w->h);
603         else {
604                 if (w->background)
605                         graphics_draw_rectangle(this->gra, w->background, &pnt, w->w, w->h);
606         }
607 }
608
609 static struct widget *
610 gui_internal_label_font_new(struct gui_priv *this, char *text, int font)
611 {
612         struct point p[4];
613         int w=0;
614         int h=0;
615
616         struct widget *widget=g_new0(struct widget, 1);
617         widget->type=widget_label;
618         widget->font_idx=font;
619         if (text) {
620                 widget->text=g_strdup(text);
621                 graphics_get_text_bbox(this->gra, this->fonts[font], text, 0x10000, 0x0, p, 0);
622                 w=p[2].x-p[0].x;
623                 h=p[0].y-p[2].y;
624         }
625         widget->h=h+this->spacing;
626         widget->texth=h;
627         widget->w=w+this->spacing;
628         widget->textw=w;
629         widget->flags=gravity_center;
630         widget->foreground=this->text_foreground;
631         widget->text_background=this->text_background;
632
633         return widget;
634 }
635
636 static struct widget *
637 gui_internal_label_new(struct gui_priv *this, char *text)
638 {
639         return gui_internal_label_font_new(this, text, 0);
640 }
641
642 static struct widget *
643 gui_internal_label_new_abbrev(struct gui_priv *this, char *text, int maxwidth)
644 {
645         struct widget *ret=NULL;
646         char *tmp=g_malloc(strlen(text)+3), *p;
647         p=text+strlen(text);
648         while ((p=g_utf8_find_prev_char(text, p)) >= text) {
649                 int i=p-text;
650                 strcpy(tmp, text);
651                 strcpy(tmp+i,"..");
652                 ret=gui_internal_label_new(this, tmp);
653                 if (ret->w < maxwidth)
654                         break;
655                 gui_internal_widget_destroy(this, ret);
656                 ret=NULL;
657         }
658         if(!ret)
659                 ret=gui_internal_label_new(this, "");
660         g_free(tmp);
661         return ret;
662 }
663
664 static struct widget *
665 gui_internal_image_new(struct gui_priv *this, struct graphics_image *image)
666 {
667         struct widget *widget=g_new0(struct widget, 1);
668         widget->type=widget_image;
669         widget->img=image;
670         if (image) {
671                 widget->w=image->width;
672                 widget->h=image->height;
673         }
674         return widget;
675 }
676
677 static void
678 gui_internal_image_render(struct gui_priv *this, struct widget *w)
679 {
680         struct point pnt;
681
682         gui_internal_background_render(this, w);
683         if (w->img) {
684                 pnt=w->p;
685                 pnt.x+=w->w/2-w->img->hot.x;
686                 pnt.y+=w->h/2-w->img->hot.y;
687                 graphics_draw_image(this->gra, this->foreground, &pnt, w->img);
688         }
689 }
690
691 static void
692 gui_internal_label_render(struct gui_priv *this, struct widget *w)
693 {
694         struct point pnt=w->p;
695         gui_internal_background_render(this, w);
696         if (w->state & STATE_EDIT)
697                 graphics_draw_rectangle(this->gra, this->highlight_background, &pnt, w->w, w->h);
698         if (w->text) {
699                 char *text;
700                 char *startext=(char*)g_alloca(strlen(w->text)+1);
701                 text=w->text;
702                 if (w->flags2 & 1) {
703                         int i;
704                         for (i = 0 ; i < strlen(text); i++)
705                                 startext[i]='*';
706                         startext[i]='\0';
707                         text=startext;
708                 }
709                 if (w->flags & gravity_right) {
710                         pnt.y+=w->h-this->spacing;
711                         pnt.x+=w->w-w->textw-this->spacing;
712                         graphics_draw_text(this->gra, w->foreground, w->text_background, this->fonts[w->font_idx], text, &pnt, 0x10000, 0x0);
713                 } else {
714                         pnt.y+=w->h-this->spacing;
715                         graphics_draw_text(this->gra, w->foreground, w->text_background, this->fonts[w->font_idx], text, &pnt, 0x10000, 0x0);
716                 }
717         }
718 }
719
720 /**
721  * @brief A text box is a widget that renders a text string containing newlines.
722  * The string will be broken up into label widgets at each newline with a vertical layout.
723  *
724  */
725 static struct widget *
726 gui_internal_text_font_new(struct gui_priv *this, char *text, int font, enum flags flags)
727 {
728         char *s=g_strdup(text),*s2,*tok;
729         struct widget *ret=gui_internal_box_new(this, flags);
730         s2=s;
731         while ((tok=strtok(s2,"\n"))) {
732                 gui_internal_widget_append(ret, gui_internal_label_font_new(this, tok, font));
733                 s2=NULL;
734         }
735         gui_internal_widget_pack(this,ret);
736         g_free(s);
737         return ret;
738 }
739
740 static struct widget *
741 gui_internal_text_new(struct gui_priv *this, char *text, enum flags flags)
742 {
743         return gui_internal_text_font_new(this, text, 0, flags);
744 }
745
746
747 static struct widget *
748 gui_internal_button_font_new_with_callback(struct gui_priv *this, char *text, int font, struct graphics_image *image, enum flags flags, void(*func)(struct gui_priv *priv, struct widget *widget, void *data), void *data)
749 {
750         struct widget *ret=NULL;
751         ret=gui_internal_box_new(this, flags);
752         if (ret) {
753                 if (image)
754                         gui_internal_widget_append(ret, gui_internal_image_new(this, image));
755                 if (text)
756                         gui_internal_widget_append(ret, gui_internal_text_font_new(this, text, font, gravity_center|orientation_vertical));
757                 ret->func=func;
758                 ret->data=data;
759                 if (func) {
760                         ret->state |= STATE_SENSITIVE;
761                         ret->speech=g_strdup(text);
762                 }
763         }
764         return ret;
765
766 }
767
768 static struct widget *
769 gui_internal_button_new_with_callback(struct gui_priv *this, char *text, struct graphics_image *image, enum flags flags, void(*func)(struct gui_priv *priv, struct widget *widget, void *data), void *data)
770 {
771         return gui_internal_button_font_new_with_callback(this, text, 0, image, flags, func, data);
772 }
773
774 static int
775 gui_internal_button_attr_update(struct gui_priv *this, struct widget *w)
776 {
777         struct widget *wi;
778         int is_on=0;
779         struct attr curr;
780         GList *l;
781
782         if (w->get_attr(w->instance, w->on.type, &curr, NULL))
783                 is_on=curr.u.data == w->on.u.data;
784         else
785                 is_on=w->deflt;
786         if (is_on != w->is_on) {
787                 if (w->redraw)
788                         this->redraw=1;
789                 w->is_on=is_on;
790                 l=g_list_first(w->children);
791                 if (l) {
792                         wi=l->data;
793                         if (wi->img)
794                                 graphics_image_free(this->gra, wi->img);
795                         wi->img=image_new_xs(this, is_on ? "gui_active" : "gui_inactive");
796                 }
797                 if (w->is_on && w->off.type == attr_none)
798                         w->state &= ~STATE_SENSITIVE;
799                 else
800                         w->state |= STATE_SENSITIVE;
801                 return 1;
802         }
803         return 0;
804 }
805
806 static void
807 gui_internal_button_attr_callback(struct gui_priv *this, struct widget *w)
808 {
809         if (gui_internal_button_attr_update(this, w))
810                 gui_internal_widget_render(this, w);
811 }
812 static void
813 gui_internal_button_attr_pressed(struct gui_priv *this, struct widget *w, void *data)
814 {
815         if (w->is_on)
816                 w->set_attr(w->instance, &w->off);
817         else
818                 w->set_attr(w->instance, &w->on);
819         gui_internal_button_attr_update(this, w);
820
821 }
822
823 static struct widget *
824 gui_internal_button_navit_attr_new(struct gui_priv *this, char *text, enum flags flags, struct attr *on, struct attr *off)
825 {
826         struct graphics_image *image=NULL;
827         struct widget *ret;
828         if (!on && !off)
829                 return NULL;
830         image=image_new_xs(this, "gui_inactive");
831         ret=gui_internal_button_new_with_callback(this, text, image, flags, gui_internal_button_attr_pressed, NULL);
832         if (on)
833                 ret->on=*on;
834         if (off)
835                 ret->off=*off;
836         ret->get_attr=(int (*)(void *, enum attr_type, struct attr *, struct attr_iter *))navit_get_attr;
837         ret->set_attr=(int (*)(void *, struct attr *))navit_set_attr;
838         ret->remove_cb=(void (*)(void *, struct callback *))navit_remove_callback;
839         ret->instance=this->nav;
840         ret->cb=callback_new_attr_2(callback_cast(gui_internal_button_attr_callback), on?on->type:off->type, this, ret);
841         navit_add_callback(this->nav, ret->cb);
842         gui_internal_button_attr_update(this, ret);
843         return ret;
844 }
845
846 static struct widget *
847 gui_internal_button_map_attr_new(struct gui_priv *this, char *text, enum flags flags, struct map *map, struct attr *on, struct attr *off, int deflt)
848 {
849         struct graphics_image *image=NULL;
850         struct widget *ret;
851         image=image_new_xs(this, "gui_inactive");
852         if (!on && !off)
853                 return NULL;
854         ret=gui_internal_button_new_with_callback(this, text, image, flags, gui_internal_button_attr_pressed, NULL);
855         if (on)
856                 ret->on=*on;
857         if (off)
858                 ret->off=*off;
859         ret->deflt=deflt;
860         ret->get_attr=(int (*)(void *, enum attr_type, struct attr *, struct attr_iter *))map_get_attr;
861         ret->set_attr=(int (*)(void *, struct attr *))map_set_attr;
862         ret->remove_cb=(void (*)(void *, struct callback *))map_remove_callback;
863         ret->instance=map;
864         ret->redraw=1;
865         ret->cb=callback_new_attr_2(callback_cast(gui_internal_button_attr_callback), on?on->type:off->type, this, ret);
866         map_add_callback(map, ret->cb);
867         gui_internal_button_attr_update(this, ret);
868         return ret;
869 }
870
871 static struct widget *
872 gui_internal_button_new(struct gui_priv *this, char *text, struct graphics_image *image, enum flags flags)
873 {
874         return gui_internal_button_new_with_callback(this, text, image, flags, NULL, NULL);
875 }
876
877 #if 0
878 //##############################################################################################################
879 //# Description:
880 //# Comment:
881 //# Authors: Martin Schaller (04/2008)
882 //##############################################################################################################
883 static void gui_internal_clear(struct gui_priv *this)
884 {
885         struct graphics *gra=this->gra;
886         struct point pnt;
887         pnt.x=0;
888         pnt.y=0;
889         graphics_draw_rectangle(gra, this->background, &pnt, this->root.w, this->root.h);
890 }
891 #endif
892
893 static struct widget *
894 gui_internal_find_widget(struct widget *wi, struct point *p, int flags)
895 {
896         struct widget *ret,*child;
897         GList *l=wi->children;
898
899         if (p) {
900                 if (wi->p.x > p->x )
901                         return NULL;
902                 if (wi->p.y > p->y )
903                         return NULL;
904                 if ( wi->p.x + wi->w < p->x)
905                         return NULL;
906                 if ( wi->p.y + wi->h < p->y)
907                         return NULL;
908         }
909         if (wi->state & flags)
910                 return wi;
911         while (l) {
912                 child=l->data;
913                 ret=gui_internal_find_widget(child, p, flags);
914                 if (ret) {
915                         return ret;
916                 }
917                 l=g_list_next(l);
918         }
919         return NULL;
920
921 }
922
923 static void
924 gui_internal_highlight_do(struct gui_priv *this, struct widget *found)
925 {
926         if (found == this->highlighted)
927                 return;
928
929         graphics_draw_mode(this->gra, draw_mode_begin);
930         if (this->highlighted) {
931                 this->highlighted->state &= ~STATE_HIGHLIGHTED;
932                 if (this->root.children && this->highlighted_menu == g_list_last(this->root.children)->data)
933                         gui_internal_widget_render(this, this->highlighted);
934                 this->highlighted=NULL;
935                 this->highlighted_menu=NULL;
936         }
937         if (found) {
938                 this->highlighted=found;
939                 this->highlighted_menu=g_list_last(this->root.children)->data;
940                 this->highlighted->state |= STATE_HIGHLIGHTED;
941                 gui_internal_widget_render(this, this->highlighted);
942                 dbg(1,"%d,%d %dx%d\n", found->p.x, found->p.y, found->w, found->h);
943         }
944         graphics_draw_mode(this->gra, draw_mode_end);
945 }
946 //##############################################################################################################
947 //# Description:
948 //# Comment:
949 //# Authors: Martin Schaller (04/2008)
950 //##############################################################################################################
951 static void gui_internal_highlight(struct gui_priv *this)
952 {
953         struct widget *menu,*found=NULL;
954         if (this->current.x > -1 && this->current.y > -1) {
955                 menu=g_list_last(this->root.children)->data;
956                 found=gui_internal_find_widget(menu, &this->current, STATE_SENSITIVE);
957                 if (!found) {
958                         found=gui_internal_find_widget(menu, &this->current, STATE_EDITABLE);
959                         if (found) {
960                                 if (this->editable && this->editable != found) {
961                                         this->editable->state &= ~ STATE_EDIT;
962                                         gui_internal_widget_render(this, this->editable);
963                                 }
964                                 found->state |= STATE_EDIT;
965                                 gui_internal_widget_render(this, found);
966                                 this->editable=found;
967                                 found=NULL;
968                         }
969                 }
970         }
971         gui_internal_highlight_do(this, found);
972         this->motion_timeout_event=NULL;
973 }
974
975
976 static void gui_internal_gesture_ring_clear(struct gui_priv *this)
977 {
978         this->gesture_ring_last=this->gesture_ring_first=0;
979 };
980
981
982 static struct gesture_elem * gui_internal_gesture_ring_get(struct gui_priv *this, int i)
983 {
984         int n=(this->gesture_ring_last-i)%GESTURE_RINGSIZE;
985         if(n==this->gesture_ring_first)
986                 return NULL;
987         return this->gesture_ring+n;
988 };
989
990 static void gui_internal_gesture_ring_add(struct gui_priv *this, struct point *p)
991 {
992         int msec;
993 #ifndef HAVE_API_WIN32_CE
994         struct timeval tv;
995         gettimeofday(&tv,NULL);
996         msec=tv.tv_sec*1000+tv.tv_usec/1000;
997 #else
998         msec=GetTickCount();
999 #endif
1000         this->gesture_ring_last++;
1001         this->gesture_ring_last%=GESTURE_RINGSIZE;
1002         if(this->gesture_ring_last==this->gesture_ring_first) {
1003                 this->gesture_ring_first++;
1004                 this->gesture_ring_first%=GESTURE_RINGSIZE;
1005         }
1006         this->gesture_ring[this->gesture_ring_last].p=*p;
1007         this->gesture_ring[this->gesture_ring_last].msec=msec;
1008         dbg(2,"msec=%d x=%d y=%d\n",msec,p->x,p->y);
1009 };
1010
1011
1012 /*
1013  * @brief Calculate movement vector and timing of the gesture.
1014  * @param in this gui context
1015  * @param in msec time in milliseconds to find gesture within
1016  * @param out p0 pointer to the point object, where gesture starting point coordinates should be placed. Can be NULL.
1017  * @param out dx pointer to variable to store horizontal movement of the gesture.
1018  * @param out dy pointer to variable to store vertical movement of the gesture.
1019  * @returns amount of time the actual movement took.
1020  */
1021 static int gui_internal_gesture_get_vector(struct gui_priv *this, int msec, struct point *p0, int *dx, int *dy)
1022 {
1023         struct gesture_elem *g;
1024         int x,y,dt;
1025         int i;
1026
1027         dt=0;
1028
1029         if(dx) *dx=0;
1030         if(dy) *dy=0;
1031         if(p0) {
1032                 p0->x=-1;
1033                 p0->y=-1;
1034         }
1035
1036         g=gui_internal_gesture_ring_get(this,0);
1037         if(!g)
1038                 return 0;
1039         x=g->p.x;
1040         y=g->p.y;
1041         if(p0) {
1042                 *p0=g->p;
1043         }
1044         msec=g->msec;
1045         dbg(2,"%d %d %d\n",g->msec, g->p.x, g->p.y);
1046         for(i=1;(g=gui_internal_gesture_ring_get(this,i))!=NULL;i++) {
1047                 if( msec-g->msec > 1000 )
1048                         break;
1049                 dt=msec-g->msec;
1050                 if(dx) *dx=x-g->p.x;
1051                 if(dy) *dy=y-g->p.y;
1052                 if(p0) {
1053                         *p0=g->p;
1054                 }
1055                 dbg(2,"%d %d %d\n",g->msec, g->p.x, g->p.y);
1056         }
1057         return dt;
1058 }
1059
1060 static int gui_internal_gesture_do(struct gui_priv *this)
1061 {
1062         int dt;
1063         int dx,dy;
1064         
1065         dt=gui_internal_gesture_get_vector(this, 1000, NULL, &dx, &dy);
1066
1067         if( abs(dx) > this->icon_s*3 && abs(dy) < this->icon_s ) {
1068                 struct widget *wt;
1069                 dbg(1,"horizontal dx=%d dy=%d\n",dx,dy);
1070
1071                 /* Prevent swiping if widget was scrolled beforehand */
1072                 if(this->pressed==2)
1073                         return 0;
1074
1075                 for(wt=this->highlighted;wt && wt->type!=widget_table;wt=wt->parent);
1076                 if(!wt || wt->type!=widget_table || !wt->data)
1077                         return 0;
1078                 if(this->highlighted) {
1079                         this->highlighted->state &= ~STATE_HIGHLIGHTED;
1080                         this->highlighted=NULL;
1081                 }
1082                 if(dx<0)
1083                         gui_internal_table_button_next(this,NULL,wt);
1084                 else
1085                         gui_internal_table_button_prev(this,NULL,wt);
1086                 return 1;
1087         } else if( abs(dy) > this->icon_s*3 && abs(dx) < this->icon_s ) {
1088                 dbg(1,"vertical dx=%d dy=%d\n",dx,dy);
1089         } else if (dt>300 && abs(dx) <this->icon_s && abs(dy) <this->icon_s ) {
1090                 dbg(1,"longtap dx=%d dy=%d\n",dx,dy);
1091         } else {
1092                 dbg(1,"none dx=%d dy=%d\n",dx,dy);
1093         }
1094         
1095         return 0;
1096
1097 };
1098
1099 static void gui_internal_motion_cb(struct gui_priv *this)
1100 {
1101         this->motion_timeout_event=NULL;
1102         gui_internal_gesture_ring_add(this, &(this->current));
1103
1104         /* Check for scrollable table below the highligted item if there's a movement with the button pressed */
1105         if (this->pressed && this->highlighted) {
1106                 struct widget *wt=NULL;
1107                 struct widget *wr=NULL;
1108                 int dx,dy;
1109                 
1110                 /* Guard against accidental scrolling when user is likely going to swipe */
1111                 gui_internal_gesture_get_vector(this, 1000, NULL, &dx, &dy);
1112                 if(abs(dx)>abs(dy) || abs(dy)<this->icon_s)
1113                         return;
1114         
1115                 if(this->highlighted)
1116                         for(wr=this->highlighted;wr && wr->type!=widget_table_row;wr=wr->parent);
1117                 if(wr)
1118                         wt=wr->parent;
1119
1120                 if(wt && wt->type==widget_table && (wt->state & STATE_SCROLLABLE)) {
1121                         struct table_data *td=wt->data;
1122                         GList *top=NULL;
1123                         GList *btm=NULL;
1124                         GList *ttop, *tbtm;
1125                         
1126                         
1127
1128                         if(!wr || !wr->h)
1129                                 return;
1130                         
1131                         if(this->current.y < wr->p.y  && wr!=td->top_row->data ) {
1132                                 int n=(wr->p.y-this->current.y)/wr->h+1;
1133
1134                                 btm=td->bottom_row;
1135                                 top=td->top_row;
1136
1137                                 while(n-->0 && (tbtm=gui_internal_widget_table_next_row(btm))!=NULL && (ttop=gui_internal_widget_table_next_row(top))!=NULL) {
1138                                         top=ttop;
1139                                         btm=tbtm;
1140                                         if(top->data==wr)
1141                                                 break;
1142                                 }
1143                                 this->pressed=2;
1144                         } else if (this->current.y > wr->p.y + wr->h ) {
1145                                 int y=wt->p.y+wt->h-wr->h;
1146                                 int n;
1147
1148                                 if(td->button_box && td->button_box->p.y!=0)
1149                                         y=td->button_box->p.y - td->button_box->h;
1150
1151                                 if(y>this->current.y)
1152                                         y=this->current.y;
1153
1154                                 n=(y - wr->p.y )/wr->h;
1155
1156                                 btm=td->bottom_row;
1157                                 top=td->top_row;
1158                                 
1159                                 while(n-->0 && (ttop=gui_internal_widget_table_prev_row(top))!=NULL && (tbtm=gui_internal_widget_table_prev_row(btm))!=NULL) {
1160                                         btm=tbtm;
1161                                         top=ttop;
1162                                         if(btm->data==wr)
1163                                                 break;
1164                                 }
1165                                 this->pressed=2;
1166                         }
1167                         if( top && btm && (td->top_row!=top || td->bottom_row!=btm) ) {
1168                                 gui_internal_table_hide_rows(wt->data);
1169                                 td->top_row=top;
1170                                 td->bottom_row=btm;
1171                                 graphics_draw_mode(this->gra, draw_mode_begin);
1172                                 gui_internal_widget_render(this,wt);
1173                                 graphics_draw_mode(this->gra, draw_mode_end);
1174                         }
1175
1176                         return;
1177                 }
1178         }
1179
1180         /* Else, just move highlight after pointer if there's nothing to scroll */
1181         gui_internal_highlight(this);
1182 }
1183
1184 static struct widget *
1185 gui_internal_box_new_with_label(struct gui_priv *this, enum flags flags, const char *label)
1186 {
1187         struct widget *widget=g_new0(struct widget, 1);
1188
1189         if (label)
1190                 widget->text=g_strdup(label);
1191         widget->type=widget_box;
1192         widget->flags=flags;
1193         return widget;
1194 }
1195
1196 static struct widget *
1197 gui_internal_box_new(struct gui_priv *this, enum flags flags)
1198 {
1199         return gui_internal_box_new_with_label(this, flags, NULL);
1200 }
1201
1202
1203 static void gui_internal_box_render(struct gui_priv *this, struct widget *w)
1204 {
1205         struct widget *wc;
1206         GList *l;
1207
1208         gui_internal_background_render(this, w);
1209 #if 0
1210         w->border=1;
1211         w->foreground=this->foreground;
1212 #endif
1213 #if 1
1214         if (w->foreground && w->border) {
1215         struct point pnt[5];
1216         pnt[0]=w->p;
1217         pnt[1].x=pnt[0].x+w->w;
1218         pnt[1].y=pnt[0].y;
1219         pnt[2].x=pnt[0].x+w->w;
1220         pnt[2].y=pnt[0].y+w->h;
1221         pnt[3].x=pnt[0].x;
1222         pnt[3].y=pnt[0].y+w->h;
1223         pnt[4]=pnt[0];
1224         graphics_gc_set_linewidth(w->foreground, w->border ? w->border : 1);
1225         graphics_draw_lines(this->gra, w->foreground, pnt, 5);
1226         graphics_gc_set_linewidth(w->foreground, 1);
1227         }
1228 #endif
1229
1230         l=w->children;
1231         while (l) {
1232                 wc=l->data;
1233                 gui_internal_widget_render(this, wc);
1234                 l=g_list_next(l);
1235         }
1236 }
1237
1238
1239 /**
1240  * @brief Compute the size and location for the widget.
1241  *
1242  *
1243  */
1244 static void gui_internal_box_pack(struct gui_priv *this, struct widget *w)
1245 {
1246         struct widget *wc;
1247         int x0,x=0,y=0,width=0,height=0,owidth=0,oheight=0,expand=0,expandd=1,count=0,rows=0,cols=w->cols ? w->cols : 0;
1248         GList *l;
1249         int orientation=w->flags & 0xffff0000;
1250
1251         if (!cols)
1252                 cols=this->cols;
1253         if (!cols) {
1254                  if ( this->root.w > this->root.h )
1255                          cols=3;
1256                  else
1257                          cols=2;
1258                  width=0;
1259                  height=0;
1260         }
1261
1262
1263         /**
1264          * count the number of children
1265          */
1266         l=w->children;
1267         while (l) {
1268                 count++;
1269                 l=g_list_next(l);
1270         }
1271         if (orientation == orientation_horizontal_vertical && count <= cols)
1272                 orientation=orientation_horizontal;
1273         switch (orientation) {
1274         case orientation_horizontal:
1275                 /**
1276                  * For horizontal orientation:
1277                  * pack each child and find the largest height and
1278                  * compute the total width. x spacing (spx) is considered
1279                  *
1280                  * If any children want to be expanded
1281                  * we keep track of this
1282                  */
1283                 l=w->children;
1284                 while (l) {
1285                         wc=l->data;
1286                         gui_internal_widget_pack(this, wc);
1287                         if (height < wc->h)
1288                                 height=wc->h;
1289                         width+=wc->w;
1290                         if (wc->flags & flags_expand)
1291                                 expand+=wc->w ? wc->w : 1;
1292                         l=g_list_next(l);
1293                         if (l)
1294                                 width+=w->spx;
1295                 }
1296                 owidth=width;
1297                 if (expand && w->w) {
1298                         expandd=w->w-width+expand;
1299                         owidth=w->w;
1300                 } else
1301                         expandd=expand=1;
1302                 break;
1303         case orientation_vertical:
1304                 /**
1305                  * For vertical layouts:
1306                  * We pack each child and compute the largest width and
1307                  * the total height.  y spacing (spy) is considered
1308                  *
1309                  * If the expand flag is set then teh expansion amount
1310                  * is computed.
1311                  */
1312                 l=w->children;
1313                 while (l) {
1314                         wc=l->data;
1315                         gui_internal_widget_pack(this, wc);
1316                         if (width < wc->w)
1317                                 width=wc->w;
1318                         height+=wc->h;
1319                         if (wc->flags & flags_expand)
1320                                 expand+=wc->h ? wc->h : 1;
1321                         l=g_list_next(l);
1322                         if (l)
1323                                 height+=w->spy;
1324                 }
1325                 oheight=height;
1326                 if (expand && w->h) {
1327                         expandd=w->h-height+expand;
1328                         oheight=w->h;
1329                 } else
1330                         expandd=expand=1;
1331                 break;
1332         case orientation_horizontal_vertical:
1333                 /**
1334                  * For horizontal_vertical orientation
1335                  * pack the children.
1336                  * Compute the largest height and largest width.
1337                  * Layout the widgets based on having the
1338                  * number of columns specified by (cols)
1339                  */
1340                 count=0;
1341                 l=w->children;
1342                 while (l) {
1343                         wc=l->data;
1344                         gui_internal_widget_pack(this, wc);
1345                         if (height < wc->h)
1346                                 height=wc->h;
1347                         if (width < wc->w)
1348                                 width=wc->w;
1349                         l=g_list_next(l);
1350                         count++;
1351                 }
1352                 if (count < cols)
1353                         cols=count;
1354                 rows=(count+cols-1)/cols;
1355                 width*=cols;
1356                 height*=rows;
1357                 width+=w->spx*(cols-1);
1358                 height+=w->spy*(rows-1);
1359                 owidth=width;
1360                 oheight=height;
1361                 expandd=expand=1;
1362                 break;
1363         default:
1364                 /**
1365                  * No orientation was specified.
1366                  * width and height are both 0.
1367                  * The width & height of this widget
1368                  * will be used.
1369                  */
1370                 if(!w->w && !w->h)
1371                         dbg(0,"Warning width and height of a widget are 0");
1372                 break;
1373         }
1374         if (! w->w && ! w->h) {
1375                 w->w=w->bl+w->br+width;
1376                 w->h=w->bt+w->bb+height;
1377                 w->packed=1;
1378         }
1379 #if 0
1380         if (expand < 100)
1381                 expand=100;
1382 #endif
1383
1384         /**
1385          * At this stage the width and height of this
1386          * widget has been computed.
1387          * We now make a second pass assigning heights,
1388          * widths and coordinates to each child widget.
1389          */
1390
1391         if (w->flags & gravity_left)
1392                 x=w->p.x+w->bl;
1393         if (w->flags & gravity_xcenter)
1394                 x=w->p.x+w->w/2-owidth/2;
1395         if (w->flags & gravity_right)
1396                 x=w->p.x+w->w-w->br-owidth;
1397         if (w->flags & gravity_top)
1398                 y=w->p.y+w->bt;
1399         if (w->flags & gravity_ycenter)
1400                 y=w->p.y+w->h/2-oheight/2;
1401         if (w->flags & gravity_bottom)
1402                 y=w->p.y+w->h-w->bb-oheight;
1403         l=w->children;
1404         switch (orientation) {
1405         case orientation_horizontal:
1406                 l=w->children;
1407                 while (l) {
1408                         wc=l->data;
1409                         wc->p.x=x;
1410                         if (wc->flags & flags_fill)
1411                                 wc->h=w->h;
1412                         if (wc->flags & flags_expand) {
1413                                 if (! wc->w)
1414                                         wc->w=1;
1415                                 wc->w=wc->w*expandd/expand;
1416                         }
1417                         if (w->flags & gravity_top)
1418                                 wc->p.y=y;
1419                         if (w->flags & gravity_ycenter)
1420                                 wc->p.y=y-wc->h/2;
1421                         if (w->flags & gravity_bottom)
1422                                 wc->p.y=y-wc->h;
1423                         x+=wc->w+w->spx;
1424                         l=g_list_next(l);
1425                 }
1426                 break;
1427         case orientation_vertical:
1428                 l=w->children;
1429                 while (l) {
1430                         wc=l->data;
1431                         wc->p.y=y;
1432                         if (wc->flags & flags_fill)
1433                                 wc->w=w->w;
1434                         if (wc->flags & flags_expand) {
1435                                 if (! wc->h)
1436                                         wc->h=1;
1437                                 wc->h=wc->h*expandd/expand;
1438                         }
1439                         if (w->flags & gravity_left)
1440                                 wc->p.x=x;
1441                         if (w->flags & gravity_xcenter)
1442                                 wc->p.x=x-wc->w/2;
1443                         if (w->flags & gravity_right)
1444                                 wc->p.x=x-wc->w;
1445                         y+=wc->h+w->spy;
1446                         l=g_list_next(l);
1447                 }
1448                 break;
1449         case orientation_horizontal_vertical:
1450                 l=w->children;
1451                 x0=x;
1452                 count=0;
1453                 width/=cols;
1454                 height/=rows;
1455                 while (l) {
1456                         wc=l->data;
1457                         wc->p.x=x;
1458                         wc->p.y=y;
1459                         if (wc->flags & flags_fill) {
1460                                 wc->w=width;
1461                                 wc->h=height;
1462                         }
1463                         if (w->flags & gravity_left)
1464                                 wc->p.x=x;
1465                         if (w->flags & gravity_xcenter)
1466                                 wc->p.x=x+(width-wc->w)/2;
1467                         if (w->flags & gravity_right)
1468                                 wc->p.x=x+width-wc->w;
1469                         if (w->flags & gravity_top)
1470                                 wc->p.y=y;
1471                         if (w->flags & gravity_ycenter)
1472                                 wc->p.y=y+(height-wc->h)/2;
1473                         if (w->flags & gravity_bottom)
1474                                 wc->p.y=y-height-wc->h;
1475                         x+=width;
1476                         if (++count == cols) {
1477                                 count=0;
1478                                 x=x0;
1479                                 y+=height;
1480                         }
1481                         l=g_list_next(l);
1482                 }
1483                 break;
1484         default:
1485                 break;
1486         }
1487         /**
1488          * Call pack again on each child,
1489          * the child has now had its size and coordinates
1490          * set so they can repack their children.
1491          */
1492         l=w->children;
1493         while (l) {
1494                 wc=l->data;
1495                 gui_internal_widget_pack(this, wc);
1496                 l=g_list_next(l);
1497         }
1498 }
1499
1500 static void
1501 gui_internal_widget_reset_pack(struct gui_priv *this, struct widget *w)
1502 {
1503         struct widget *wc;
1504         GList *l;
1505
1506         l=w->children;
1507         while (l) {
1508                 wc=l->data;
1509                 gui_internal_widget_reset_pack(this, wc);
1510                 l=g_list_next(l);
1511         }
1512         if (w->packed) {
1513                 w->w=0;
1514                 w->h=0;
1515         }
1516 }
1517
1518 static void
1519 gui_internal_widget_append(struct widget *parent, struct widget *child)
1520 {
1521         if (! child)
1522                 return;
1523         if (! child->background)
1524                 child->background=parent->background;
1525         parent->children=g_list_append(parent->children, child);
1526         child->parent=parent;
1527 }
1528
1529 static void gui_internal_widget_prepend(struct widget *parent, struct widget *child)
1530 {
1531         if (! child->background)
1532                 child->background=parent->background;
1533         parent->children=g_list_prepend(parent->children, child);
1534         child->parent=parent;
1535 }
1536
1537 static void gui_internal_widget_insert_before(struct widget *parent, struct widget *sibling, struct widget *child)
1538 {
1539         GList *sib=NULL;
1540         if (! child->background)
1541                 child->background=parent->background;
1542
1543         if(sibling) 
1544                 sib=g_list_find(parent->children,sibling);
1545         parent->children=g_list_insert_before(parent->children, sib, child);
1546         child->parent=parent;
1547 }
1548
1549 static void gui_internal_widget_insert_sorted(struct widget *parent, struct widget *child, GCompareFunc func)
1550 {
1551         if (! child->background)
1552                 child->background=parent->background;
1553
1554         parent->children=g_list_insert_sorted(parent->children, child, func);
1555         child->parent=parent;
1556 }
1557
1558
1559 static void gui_internal_widget_children_destroy(struct gui_priv *this, struct widget *w)
1560 {
1561         GList *l;
1562         struct widget *wc;
1563
1564         l=w->children;
1565         while (l) {
1566                 wc=l->data;
1567                 gui_internal_widget_destroy(this, wc);
1568                 l=g_list_next(l);
1569         }
1570         g_list_free(w->children);
1571         w->children=NULL;
1572 }
1573
1574
1575 static void gui_internal_widget_destroy(struct gui_priv *this, struct widget *w)
1576 {
1577         gui_internal_widget_children_destroy(this, w);
1578         g_free(w->command);
1579         g_free(w->speech);
1580         g_free(w->text);
1581         if (w->img)
1582                 graphics_image_free(this->gra, w->img);
1583         if (w->prefix)
1584                 g_free(w->prefix);
1585         if (w->name)
1586                 g_free(w->name);
1587         if (w->data_free)
1588                 w->data_free(w->data);
1589         if (w->cb && w->remove_cb)
1590                 w->remove_cb(w->instance, w->cb);
1591         if (w==this->highlighted)
1592             this->highlighted=NULL;
1593         if(w->free)
1594                 w->free(this,w);
1595         else
1596                 g_free(w);
1597 }
1598
1599
1600 static void
1601 gui_internal_widget_render(struct gui_priv *this, struct widget *w)
1602 {
1603         if(w->p.x > this->root.w || w->p.y > this->root.h)
1604                 return;
1605
1606         switch (w->type) {
1607         case widget_box:
1608                 gui_internal_box_render(this, w);
1609                 break;
1610         case widget_label:
1611                 gui_internal_label_render(this, w);
1612                 break;
1613         case widget_image:
1614                 gui_internal_image_render(this, w);
1615                 break;
1616         case widget_table:
1617                 gui_internal_table_render(this,w);
1618                 break;
1619         default:
1620                 break;
1621         }
1622 }
1623
1624 static void
1625 gui_internal_widget_pack(struct gui_priv *this, struct widget *w)
1626 {
1627         switch (w->type) {
1628         case widget_box:
1629                 gui_internal_box_pack(this, w);
1630                 break;
1631         case widget_table:
1632           gui_internal_table_pack(this,w);
1633         default:
1634                 break;
1635         }
1636 }
1637
1638 //##############################################################################################################
1639 //# Description:
1640 //# Comment:
1641 //# Authors: Martin Schaller (04/2008)
1642 //##############################################################################################################
1643 static void gui_internal_call_highlighted(struct gui_priv *this)
1644 {
1645         if (! this->highlighted || ! this->highlighted->func)
1646                 return;
1647         this->highlighted->reason=1;
1648         this->highlighted->func(this, this->highlighted, this->highlighted->data);
1649 }
1650
1651 static void
1652 gui_internal_say(struct gui_priv *this, struct widget *w, int questionmark)
1653 {
1654         char *text=w->speech;
1655         if (! this->speech)
1656                 return;
1657         if (!text)
1658                 text=w->text;
1659         if (!text)
1660                 text=w->name;
1661         if (text) {
1662                 text=g_strdup_printf("%s%c", text, questionmark ? '?':'\0');
1663                 navit_say(this->nav, text);
1664                 g_free(text);
1665         }
1666 }
1667
1668 static void
1669 gui_internal_menu_destroy(struct gui_priv *this, struct widget *w)
1670 {
1671         struct menu_data *menu_data=w->menu_data;
1672         if (menu_data) {
1673                 if (menu_data->refresh_callback_obj.type) {
1674                         struct object_func *func;
1675                         func=object_func_lookup(menu_data->refresh_callback_obj.type);
1676                         if (func && func->remove_attr)
1677                                 func->remove_attr(menu_data->refresh_callback_obj.u.data, &menu_data->refresh_callback);
1678                 }
1679                 if (menu_data->refresh_callback.u.callback)
1680                         callback_destroy(menu_data->refresh_callback.u.callback);
1681
1682                 g_free(menu_data->href);
1683                 g_free(menu_data);
1684         }
1685         gui_internal_widget_destroy(this, w);
1686         this->root.children=g_list_remove(this->root.children, w);
1687 }
1688
1689 static void
1690 gui_internal_prune_menu_do(struct gui_priv *this, struct widget *w, int render)
1691 {
1692         GList *l;
1693         struct widget *wr,*wd;
1694         gui_internal_search_idle_end(this);
1695         while ((l = g_list_last(this->root.children))) {
1696                 wd=l->data;
1697                 if (wd == w) {
1698                         void (*redisplay)(struct gui_priv *priv, struct widget *widget, void *data);
1699                         if (!render)
1700                                 return;
1701                         gui_internal_say(this, w, 0);
1702                         redisplay=w->menu_data->redisplay;
1703                         wr=w->menu_data->redisplay_widget;
1704                         if (!w->menu_data->redisplay && !w->menu_data->href) {
1705                                 gui_internal_widget_render(this, w);
1706                                 return;
1707                         }
1708                         if (redisplay) {
1709                                 gui_internal_menu_destroy(this, w);
1710                                 redisplay(this, wr, wr->data);
1711                         } else {
1712                                 char *href=g_strdup(w->menu_data->href);
1713                                 gui_internal_menu_destroy(this, w);
1714                                 gui_internal_html_load_href(this, href, 0);
1715                                 g_free(href);
1716                         }
1717                         return;
1718                 }
1719                 gui_internal_menu_destroy(this, wd);
1720         }
1721 }
1722
1723 static void
1724 gui_internal_prune_menu(struct gui_priv *this, struct widget *w)
1725 {
1726         gui_internal_prune_menu_do(this, w, 1);
1727 }
1728
1729 static void
1730 gui_internal_prune_menu_count(struct gui_priv *this, int count, int render)
1731 {
1732         GList *l=g_list_last(this->root.children);
1733         struct widget *w=NULL;
1734         while (l && count-- > 0)
1735                 l=g_list_previous(l);
1736         if (l) {
1737                 w=l->data;
1738                 gui_internal_prune_menu_do(this, w, render);
1739         }
1740 }
1741
1742 static void
1743 gui_internal_back(struct gui_priv *this, struct widget *w, void *data)
1744 {
1745         gui_internal_prune_menu_count(this, 1, 1);
1746 }
1747
1748 static void
1749 gui_internal_cmd_return(struct gui_priv *this, struct widget *wm, void *data)
1750 {
1751         gui_internal_prune_menu(this, wm->data);
1752 }
1753
1754 static void
1755 gui_internal_cmd2_back(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
1756 {
1757         graphics_draw_mode(this->gra, draw_mode_begin);
1758         gui_internal_back(this, NULL, NULL);
1759         graphics_draw_mode(this->gra, draw_mode_end);
1760         gui_internal_check_exit(this);
1761 }
1762
1763 static void
1764 gui_internal_cmd2_back_to_map(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
1765 {
1766         gui_internal_prune_menu(this, NULL);
1767 }
1768
1769 static void
1770 gui_internal_cmd_main_menu(struct gui_priv *this, struct widget *wm, void *data)
1771 {
1772         struct widget *w=this->root.children->data;
1773         if (w && w->menu_data && w->menu_data->href && !strcmp(w->menu_data->href,"#Main Menu")) 
1774                 gui_internal_prune_menu(this, w);
1775         else
1776                 gui_internal_html_main_menu(this);
1777 }
1778
1779 static struct widget *
1780 gui_internal_top_bar(struct gui_priv *this)
1781 {
1782         struct widget *w,*wm,*wh,*wc,*wcn;
1783         int dots_len, sep_len;
1784         GList *res=NULL,*l;
1785         int width,width_used=0,use_sep=0,incomplete=0;
1786         struct graphics_gc *foreground=(this->flags & 256 ? this->background : this->text_foreground);
1787 /* flags
1788         1:Don't expand bar to screen width
1789         2:Don't show Map Icon
1790         4:Don't show Home Icon
1791         8:Show only current menu
1792         16:Don't use menu titles as button
1793         32:Show navit version
1794         64:Show time
1795         128:Show help
1796         256:Use background for menu headline
1797         512:Set osd_configuration and zoom to route when setting position
1798         1024:Don't show back button
1799         2048:No highlighting of keyboard
1800 */
1801
1802         w=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|(this->flags & 1 ? 0:flags_fill));
1803         w->bl=this->spacing;
1804         w->spx=this->spacing;
1805         w->background=this->background2;
1806         if ((this->flags & 6) == 6) {
1807                 w->bl=10;
1808                 w->br=10;
1809                 w->bt=6;
1810                 w->bb=6;
1811         }
1812         width=this->root.w-w->bl;
1813         if (! (this->flags & 2)) {
1814                 wm=gui_internal_button_new_with_callback(this, NULL,
1815                         image_new_s(this, "gui_map"), gravity_center|orientation_vertical,
1816                         gui_internal_cmd_return, NULL);
1817                 wm->speech=g_strdup(_("Back to map"));
1818                 gui_internal_widget_pack(this, wm);
1819                 gui_internal_widget_append(w, wm);
1820                 width-=wm->w;
1821         }
1822         if (! (this->flags & 4)) {
1823                 wh=gui_internal_button_new_with_callback(this, NULL,
1824                         image_new_s(this, "gui_home"), gravity_center|orientation_vertical,
1825                         gui_internal_cmd_main_menu, NULL);
1826                 wh->speech=g_strdup(_("Main Menu"));
1827                 gui_internal_widget_pack(this, wh);
1828                 gui_internal_widget_append(w, wh);
1829                 width-=wh->w;
1830         }
1831         if (!(this->flags & 6))
1832                 width-=w->spx;
1833         l=g_list_last(this->root.children);
1834         wcn=gui_internal_label_new(this,".. »");
1835         wcn->foreground=foreground;
1836         dots_len=wcn->w;
1837         gui_internal_widget_destroy(this, wcn);
1838         wcn=gui_internal_label_new(this,"»");
1839         wcn->foreground=foreground;
1840         sep_len=wcn->w;
1841         gui_internal_widget_destroy(this, wcn);
1842         while (l) {
1843                 if (g_list_previous(l) || !g_list_next(l)) {
1844                         wc=l->data;
1845                         wcn=gui_internal_label_new(this, wc->text);
1846                         wcn->foreground=foreground;
1847                         if (g_list_next(l))
1848                                 use_sep=1;
1849                         else
1850                                 use_sep=0;
1851                         dbg(1,"%d (%s) + %d + %d + %d > %d\n", wcn->w, wc->text, width_used, w->spx, use_sep ? sep_len : 0, width);
1852                         if (wcn->w + width_used + w->spx + (use_sep ? sep_len : 0) + (g_list_previous(l) ? dots_len : 0) > width) {
1853                                 incomplete=1;
1854                                 gui_internal_widget_destroy(this, wcn);
1855                                 break;
1856                         }
1857                         if (use_sep) {
1858                                 struct widget *wct=gui_internal_label_new(this, "»");
1859                                 wct->foreground=foreground;
1860                                 res=g_list_prepend(res, wct);
1861                                 width_used+=sep_len+w->spx;
1862                         }
1863                         width_used+=wcn->w;
1864                         if (!(this->flags & 16)) {
1865                                 wcn->func=gui_internal_cmd_return;
1866                                 wcn->data=wc;
1867                                 wcn->state |= STATE_SENSITIVE;
1868                         }
1869                         res=g_list_prepend(res, wcn);
1870                         if (this->flags & 8)
1871                                 break;
1872                 }
1873                 l=g_list_previous(l);
1874         }
1875         if (incomplete) {
1876                 if (! res) {
1877                         wcn=gui_internal_label_new_abbrev(this, wc->text, width-width_used-w->spx-dots_len);
1878                         wcn->foreground=foreground;
1879                         wcn->func=gui_internal_cmd_return;
1880                         wcn->data=wc;
1881                         wcn->state |= STATE_SENSITIVE;
1882                         res=g_list_prepend(res, wcn);
1883                         l=g_list_previous(l);
1884                         wc=l?l->data:NULL;
1885                 }
1886                 if(wc) {
1887                         wcn=gui_internal_label_new(this, ".. »");
1888                         wcn->foreground=foreground;
1889                         wcn->func=gui_internal_cmd_return;
1890                         wcn->data=wc;
1891                         wcn->state |= STATE_SENSITIVE;
1892                         res=g_list_prepend(res, wcn);
1893                 }
1894         }
1895         l=res;
1896         while (l) {
1897                 gui_internal_widget_append(w, l->data);
1898                 l=g_list_next(l);
1899         }
1900         if (this->flags & 32) {
1901                 char *version_text=g_strdup_printf("Navit %s",version);
1902                 wcn=gui_internal_label_new(this, version_text);
1903                 g_free(version_text);
1904                 wcn->flags=gravity_right_center|flags_expand;
1905                 gui_internal_widget_append(w, wcn);
1906         }
1907 #if 0
1908         if (dots)
1909                 gui_internal_widget_destroy(this, dots);
1910 #endif
1911         return w;
1912 }
1913
1914 static struct widget *
1915 gui_internal_time_help(struct gui_priv *this)
1916 {
1917         struct widget *w,*wc,*wcn;
1918         char timestr[64];
1919         struct tm *tm;
1920         time_t timep;
1921
1922         w=gui_internal_box_new(this, gravity_right_center|orientation_horizontal|flags_fill);
1923         w->bl=this->spacing;
1924         w->spx=this->spacing;
1925         w->spx=10;
1926         w->bl=10;
1927         w->br=10;
1928         w->bt=6;
1929         w->bb=6;
1930         if (this->flags & 64) {
1931                 wc=gui_internal_box_new(this, gravity_right_top|orientation_vertical|flags_fill);
1932                 wc->bl=10;
1933                 wc->br=20;
1934                 wc->bt=6;
1935                 wc->bb=6;
1936                 timep=time(NULL);
1937                 tm=localtime(&timep);
1938                 strftime(timestr, 64, "%H:%M %d.%m.%Y", tm);
1939                 wcn=gui_internal_label_new(this, timestr);
1940                 gui_internal_widget_append(wc, wcn);
1941                 gui_internal_widget_append(w, wc);
1942         }
1943         if (this->flags & 128) {
1944                 wcn=gui_internal_button_new_with_callback(this, _("Help"), image_new_l(this, "gui_help"), gravity_center|orientation_vertical|flags_fill, NULL, NULL);
1945                 gui_internal_widget_append(w, wcn);
1946         }
1947         return w;
1948 }
1949
1950
1951 /**
1952  * Applys the configuration values to this based on the settings
1953  * specified in the configuration file (this->config) and
1954  * the most approriate default profile based on screen resolution.
1955  *
1956  * This function should be run after this->root is setup and could
1957  * be rerun after the window is resized.
1958  *
1959  * @authors Steve Singer <ssinger_pg@sympatico.ca> (09/2008)
1960  */
1961 static void gui_internal_apply_config(struct gui_priv *this)
1962 {
1963   struct gui_config_settings *  current_config=0;
1964
1965   dbg(1,"w=%d h=%d\n", this->root.w, this->root.h);
1966   /**
1967    * Select default values from profile based on the screen.
1968    */
1969   if((this->root.w > 320 || this->root.h > 320) && this->root.w > 240 && this->root.h > 240)
1970   {
1971     if((this->root.w > 640 || this->root.h > 640) && this->root.w > 480 && this->root.h > 480 )
1972     {
1973       current_config = &config_profiles[LARGE_PROFILE];
1974     }
1975     else
1976     {
1977       current_config = &config_profiles[MEDIUM_PROFILE];
1978     }
1979   }
1980   else
1981   {
1982     current_config = &config_profiles[SMALL_PROFILE];
1983   }
1984
1985   /**
1986    * Apply override values from config file
1987    */
1988   if(this->config.font_size == -1 )
1989   {
1990     this->font_size = current_config->font_size;
1991   }
1992   else
1993   {
1994     this->font_size = this->config.font_size;
1995   }
1996
1997   if(this->config.icon_xs == -1 )
1998   {
1999       this->icon_xs = current_config->icon_xs;
2000   }
2001   else
2002   {
2003     this->icon_xs = this->config.icon_xs;
2004   }
2005
2006   if(this->config.icon_s == -1 )
2007   {
2008     this->icon_s = current_config->icon_s;
2009   }
2010   else
2011   {
2012     this->icon_s = this->config.icon_s;
2013   }
2014   if(this->config.icon_l == -1 )
2015   {
2016     this->icon_l = current_config->icon_l;
2017   }
2018   else
2019   {
2020     this->icon_l = this->config.icon_l;
2021   }
2022   if(this->config.spacing == -1 )
2023   {
2024     this->spacing = current_config->spacing;
2025   }
2026   else
2027   {
2028     this->spacing = current_config->spacing;
2029   }
2030
2031 }
2032
2033 static struct widget *
2034 gui_internal_button_label(struct gui_priv *this, char *label, int mode)
2035 {
2036         struct widget *wl,*wlb;
2037         struct widget *wb=gui_internal_menu_data(this)->button_bar;
2038         wlb=gui_internal_box_new(this, gravity_right_center|orientation_vertical);
2039         wl=gui_internal_label_new(this, label);
2040         wlb->border=1;
2041         wlb->foreground=this->text_foreground;
2042         wlb->bl=20;
2043         wlb->br=20;
2044         wlb->bb=6;
2045         wlb->bt=6;
2046         gui_internal_widget_append(wlb, wl);
2047         if (mode == 1)
2048                 gui_internal_widget_prepend(wb, wlb);
2049         if (mode == -1)
2050                 gui_internal_widget_append(wb, wlb);
2051
2052         return wlb;
2053 }
2054
2055
2056 static struct widget *
2057 gui_internal_menu(struct gui_priv *this, const char *label)
2058 {
2059         struct widget *menu,*w,*w1,*topbox;
2060
2061         gui_internal_search_idle_end(this);
2062         topbox=gui_internal_box_new_with_label(this, 0, label);
2063         topbox->w=this->root.w;
2064         topbox->h=this->root.h;
2065         gui_internal_widget_append(&this->root, topbox);
2066         menu=gui_internal_box_new(this, gravity_left_center|orientation_vertical);
2067         menu->w=this->root.w;
2068         menu->h=this->root.h;
2069         menu->background=this->background;
2070         gui_internal_apply_config(this);
2071         if (!this->fonts[0]) {
2072                 this->fonts[0]=graphics_font_new(this->gra,this->font_size,1);
2073                 this->fonts[1]=graphics_font_new(this->gra,this->font_size*66/100,1);
2074                 this->fonts[2]=graphics_font_new(this->gra,this->font_size*50/100,1);
2075         }
2076         topbox->menu_data=g_new0(struct menu_data, 1);
2077         gui_internal_widget_append(topbox, menu);
2078         w=gui_internal_top_bar(this);
2079         gui_internal_widget_append(menu, w);
2080         w=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
2081         w->spx=4*this->spacing;
2082         w->w=menu->w;
2083         gui_internal_widget_append(menu, w);
2084         if (this->flags & 16 && !(this->flags & 1024)) {
2085                 struct widget *wlb,*wb,*wm=w;
2086                 wm->flags=gravity_center|orientation_vertical|flags_expand|flags_fill;
2087                 w=gui_internal_box_new(this, gravity_center|orientation_horizontal|flags_expand|flags_fill);
2088                 dbg(0,"topbox->menu_data=%p\n", topbox->menu_data);
2089                 gui_internal_widget_append(wm, w);
2090                 wb=gui_internal_box_new(this, gravity_right_center|orientation_horizontal|flags_fill);
2091                 wb->bl=6;
2092                 wb->br=6;
2093                 wb->bb=6;
2094                 wb->bt=6;
2095                 wb->spx=6;
2096                 topbox->menu_data->button_bar=wb;
2097                 gui_internal_widget_append(wm, wb);
2098                 wlb=gui_internal_button_label(this,_("Back"),1);
2099                 wlb->func=gui_internal_back;
2100                 wlb->state |= STATE_SENSITIVE;
2101         }
2102         if (this->flags & 192) {
2103                 menu=gui_internal_box_new(this, gravity_left_center|orientation_vertical);
2104                 menu->w=this->root.w;
2105                 menu->h=this->root.h;
2106                 w1=gui_internal_time_help(this);
2107                 gui_internal_widget_append(menu, w1);
2108                 w1=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
2109                 gui_internal_widget_append(menu, w1);
2110                 gui_internal_widget_append(topbox, menu);
2111                 menu->background=NULL;
2112         }
2113         gui_internal_widget_pack(this, topbox);
2114         gui_internal_widget_reset_pack(this, topbox);
2115         topbox->w=this->root.w;
2116         topbox->h=this->root.h;
2117         menu->w=this->root.w;
2118         menu->h=this->root.h;
2119         return w;
2120 }
2121
2122 static struct menu_data *
2123 gui_internal_menu_data(struct gui_priv *this)
2124 {
2125         GList *l;
2126         struct widget *menu;
2127
2128         l=g_list_last(this->root.children);
2129         menu=l->data;
2130         return menu->menu_data;
2131 }
2132
2133 static void
2134 gui_internal_menu_reset_pack(struct gui_priv *this)
2135 {
2136         GList *l;
2137         struct widget *top_box;
2138
2139         l=g_list_last(this->root.children);
2140         top_box=l->data;
2141         gui_internal_widget_reset_pack(this, top_box);
2142 }
2143
2144 static void
2145 gui_internal_menu_render(struct gui_priv *this)
2146 {
2147         GList *l;
2148         struct widget *menu;
2149
2150         l=g_list_last(this->root.children);
2151         menu=l->data;
2152         gui_internal_say(this, menu, 0);
2153         gui_internal_widget_pack(this, menu);
2154         gui_internal_widget_render(this, menu);
2155 }
2156
2157 static void
2158 gui_internal_cmd_set_destination(struct gui_priv *this, struct widget *wm, void *data)
2159 {
2160         char *name=data;
2161         dbg(0,"c=%d:0x%x,0x%x\n", wm->c.pro, wm->c.x, wm->c.y);
2162         navit_set_destination(this->nav, &wm->c, name, 1);
2163         if (this->flags & 512) {
2164                 struct attr follow;
2165                 follow.type=attr_follow;
2166                 follow.u.num=180;
2167                 navit_set_attr(this->nav, &this->osd_configuration);
2168                 navit_set_attr(this->nav, &follow);
2169                 navit_zoom_to_route(this->nav, 0);
2170         }
2171         gui_internal_prune_menu(this, NULL);
2172 }
2173
2174 static void
2175 gui_internal_cmd_set_position(struct gui_priv *this, struct widget *wm, void *data)
2176 {
2177         struct attr v;
2178         if(data) {
2179                 v.type=attr_vehicle;
2180                 v.u.vehicle=NULL;
2181                 navit_set_attr(this->nav, &v);
2182         }
2183         navit_set_position(this->nav, &wm->c);
2184         gui_internal_prune_menu(this, NULL);
2185 }
2186
2187 static void
2188 gui_internal_cmd_add_bookmark_do(struct gui_priv *this, struct widget *widget)
2189 {
2190         GList *l;
2191         struct attr attr;
2192         dbg(0,"text='%s'\n", widget->text);
2193         if (widget->text && strlen(widget->text)){
2194                 navit_get_attr(this->nav, attr_bookmarks, &attr, NULL);
2195                 bookmarks_add_bookmark(attr.u.bookmarks, &widget->c, widget->text);
2196         }
2197         g_free(widget->text);
2198         widget->text=NULL;
2199         l=g_list_previous(g_list_last(this->root.children));
2200         gui_internal_prune_menu(this, l->data);
2201 }
2202
2203 static void
2204 gui_internal_cmd_add_bookmark_folder_do(struct gui_priv *this, struct widget *widget)
2205 {
2206         GList *l;
2207         struct attr attr;
2208         dbg(0,"text='%s'\n", widget->text);
2209         if (widget->text && strlen(widget->text)){
2210                 navit_get_attr(this->nav, attr_bookmarks, &attr, NULL);
2211                 bookmarks_add_bookmark(attr.u.bookmarks, NULL, widget->text);
2212         }
2213         g_free(widget->text);
2214         widget->text=NULL;
2215         l=g_list_previous(g_list_previous(g_list_last(this->root.children)));
2216         gui_internal_prune_menu(this, l->data);
2217 }
2218
2219 static void
2220 gui_internal_cmd_add_bookmark_clicked(struct gui_priv *this, struct widget *widget, void *data)
2221 {
2222         gui_internal_cmd_add_bookmark_do(this, widget->data);
2223 }
2224
2225 static void
2226 gui_internal_cmd_add_bookmark_folder_clicked(struct gui_priv *this, struct widget *widget, void *data)
2227 {
2228         gui_internal_cmd_add_bookmark_folder_do(this, widget->data);
2229 }
2230
2231 static void
2232 gui_internal_cmd_rename_bookmark_clicked(struct gui_priv *this, struct widget *widget,void *data)
2233 {
2234         struct widget *w=(struct widget*)widget->data;
2235         GList *l;
2236         struct attr attr;
2237         dbg(0,"text='%s'\n", w->text);
2238         if (w->text && strlen(w->text)){
2239                 navit_get_attr(this->nav, attr_bookmarks, &attr, NULL);
2240                 bookmarks_rename_bookmark(attr.u.bookmarks, w->name, w->text);
2241         }
2242         g_free(w->text);
2243         g_free(w->name);
2244         w->text=NULL;
2245         w->name=NULL;
2246         l=g_list_previous(g_list_previous(g_list_previous(g_list_last(this->root.children))));
2247         gui_internal_prune_menu(this, l->data);
2248 }
2249
2250 static void
2251 gui_internal_cmd_add_bookmark_changed(struct gui_priv *this, struct widget *wm, void *data)
2252 {
2253         int len;
2254         dbg(1,"enter\n");
2255         if (wm->text) {
2256                 len=strlen(wm->text);
2257                 dbg(1,"len=%d\n", len);
2258                 if (len && (wm->text[len-1] == '\n' || wm->text[len-1] == '\r')) {
2259                         wm->text[len-1]='\0';
2260                         gui_internal_cmd_add_bookmark_do(this, wm);
2261                 }
2262         }
2263 }
2264
2265
2266 static struct widget * gui_internal_keyboard(struct gui_priv *this, int mode);
2267
2268 static void
2269 gui_internal_cmd_add_bookmark2(struct gui_priv *this, struct widget *wm, void *data)
2270 {
2271         struct widget *w,*wb,*wk,*wl,*we,*wnext;
2272         char *name=data;
2273         wb=gui_internal_menu(this,_("Add Bookmark"));
2274         w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2275         gui_internal_widget_append(wb, w);
2276         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
2277         gui_internal_widget_append(w, we);
2278         gui_internal_widget_append(we, wk=gui_internal_label_new(this, name));
2279         wk->state |= STATE_EDIT|STATE_EDITABLE|STATE_CLEAR;
2280         wk->background=this->background;
2281         wk->flags |= flags_expand|flags_fill;
2282         wk->func = gui_internal_cmd_add_bookmark_changed;
2283         wk->c=wm->c;
2284         gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
2285         wnext->state |= STATE_SENSITIVE;
2286         wnext->func = gui_internal_cmd_add_bookmark_clicked;
2287         wnext->data=wk;
2288         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2289         gui_internal_widget_append(w, wl);
2290         if (this->keyboard)
2291                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
2292         gui_internal_menu_render(this);
2293 }
2294
2295 static void
2296 gui_internal_cmd_add_bookmark_folder2(struct gui_priv *this, struct widget *wm, void *data)
2297 {
2298         struct widget *w,*wb,*wk,*wl,*we,*wnext;
2299         char *name=data;
2300         wb=gui_internal_menu(this,_("Add Bookmark folder"));
2301         w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2302         gui_internal_widget_append(wb, w);
2303         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
2304         gui_internal_widget_append(w, we);
2305         gui_internal_widget_append(we, wk=gui_internal_label_new(this, name));
2306         wk->state |= STATE_EDIT|STATE_EDITABLE|STATE_CLEAR;
2307         wk->background=this->background;
2308         wk->flags |= flags_expand|flags_fill;
2309         wk->func = gui_internal_cmd_add_bookmark_changed;
2310         wk->c=wm->c;
2311         gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
2312         wnext->state |= STATE_SENSITIVE;
2313         wnext->func = gui_internal_cmd_add_bookmark_folder_clicked;
2314         wnext->data=wk;
2315         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2316         gui_internal_widget_append(w, wl);
2317         if (this->keyboard)
2318                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
2319         gui_internal_menu_render(this);
2320 }
2321
2322 static void
2323 gui_internal_cmd_rename_bookmark(struct gui_priv *this, struct widget *wm, void *data)
2324 {
2325         struct widget *w,*wb,*wk,*wl,*we,*wnext;
2326         char *name=wm->text;
2327         wb=gui_internal_menu(this,_("Rename"));
2328         w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2329         gui_internal_widget_append(wb, w);
2330         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
2331         gui_internal_widget_append(w, we);
2332         gui_internal_widget_append(we, wk=gui_internal_label_new(this, name));
2333         wk->state |= STATE_EDIT|STATE_EDITABLE|STATE_CLEAR;
2334         wk->background=this->background;
2335         wk->flags |= flags_expand|flags_fill;
2336         wk->func = gui_internal_cmd_add_bookmark_changed;
2337         wk->c=wm->c;
2338         wk->name=g_strdup(name);
2339         gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
2340         wnext->state |= STATE_SENSITIVE;
2341         wnext->func = gui_internal_cmd_rename_bookmark_clicked;
2342         wnext->data=wk;
2343         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2344         gui_internal_widget_append(w, wl);
2345         if (this->keyboard)
2346                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
2347         gui_internal_menu_render(this);
2348 }
2349
2350 static void
2351 gui_internal_cmd_cut_bookmark(struct gui_priv *this, struct widget *wm, void *data)
2352 {
2353         struct attr mattr;
2354         GList *l;
2355         navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL);
2356         bookmarks_cut_bookmark(mattr.u.bookmarks,wm->text);
2357         l=g_list_previous(g_list_previous(g_list_last(this->root.children)));
2358         gui_internal_prune_menu(this, l->data);
2359 }
2360
2361 static void
2362 gui_internal_cmd_copy_bookmark(struct gui_priv *this, struct widget *wm, void *data)
2363 {
2364         struct attr mattr;
2365         GList *l;
2366         navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL);
2367         bookmarks_copy_bookmark(mattr.u.bookmarks,wm->text);
2368         l=g_list_previous(g_list_previous(g_list_last(this->root.children)));
2369         gui_internal_prune_menu(this, l->data);
2370 }
2371
2372 static void
2373 gui_internal_cmd_paste_bookmark(struct gui_priv *this, struct widget *wm, void *data)
2374 {
2375         struct attr mattr;
2376         GList *l;
2377         navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL);
2378         bookmarks_paste_bookmark(mattr.u.bookmarks);
2379         l=g_list_previous(g_list_last(this->root.children));
2380         gui_internal_prune_menu(this, l->data);
2381 }
2382
2383 static void
2384 gui_internal_cmd_delete_bookmark(struct gui_priv *this, struct widget *wm, void *data)
2385 {
2386         struct attr mattr;
2387         GList *l;
2388         navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL);
2389         bookmarks_delete_bookmark(mattr.u.bookmarks,wm->text);
2390         l=g_list_previous(g_list_previous(g_list_last(this->root.children)));
2391         gui_internal_prune_menu(this, l->data);
2392 }
2393
2394 static void
2395 gui_internal_cmd_delete_bookmark_folder(struct gui_priv *this, struct widget *wm, void *data)
2396 {
2397         struct attr mattr;
2398         GList *l;
2399         navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL);
2400         bookmarks_move_up(mattr.u.bookmarks);
2401         bookmarks_delete_bookmark(mattr.u.bookmarks,wm->prefix);
2402         l=g_list_first(this->root.children);
2403         gui_internal_prune_menu(this, l->data);
2404 }
2405
2406 static void
2407 gui_internal_cmd_load_bookmarks_as_waypoints(struct gui_priv *this, struct widget *wm, void *data)
2408 {
2409         struct attr mattr;
2410
2411         if(navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL) ) {
2412                 struct attr attr;
2413                 struct item *item;
2414                 struct coord c;
2415                 struct pcoord *pc;
2416                 enum projection pro=bookmarks_get_projection(mattr.u.bookmarks);
2417                 int i, bm_count;
2418
2419                 navit_set_destination(this->nav, NULL, NULL, 0);
2420
2421                 bm_count=bookmarks_get_bookmark_count(mattr.u.bookmarks);
2422                 pc=g_alloca(bm_count*sizeof(struct pcoord));
2423                 bookmarks_item_rewind(mattr.u.bookmarks);
2424                 i=0;
2425                 while ((item=bookmarks_get_item(mattr.u.bookmarks))) {
2426                         if (!item_attr_get(item, attr_label, &attr)) 
2427                                 continue;
2428                         if (item->type == type_bookmark) {
2429                                 if (item_coord_get(item, &c, 1)) {
2430                                         pc[i].x=c.x;
2431                                         pc[i].y=c.y;
2432                                         pc[i].pro=pro;
2433                                         i++;
2434                                 }
2435                         }
2436                 }
2437                 bm_count=i;
2438
2439                 if (bm_count>0){
2440                         navit_set_destinations(this->nav, pc, bm_count, wm->prefix, 1);
2441                         if (this->flags & 512) {
2442                                 struct attr follow;
2443                                 follow.type=attr_follow;
2444                                 follow.u.num=180;
2445                                 navit_set_attr(this->nav, &this->osd_configuration);
2446                                 navit_set_attr(this->nav, &follow);
2447                                 navit_zoom_to_route(this->nav, 0);
2448                         }
2449                 }
2450         }
2451
2452         gui_internal_prune_menu(this, NULL);
2453 }
2454
2455 static void
2456 gui_internal_cmd_replace_bookmarks_from_waypoints(struct gui_priv *this, struct widget *wm, void *data)
2457 {
2458         struct attr mattr;
2459
2460         if(navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL) ) {
2461                 struct attr attr;
2462                 char *desc=NULL;
2463                 struct pcoord *pc;
2464                 int i, bm_count;
2465
2466                 if (bookmarks_get_bookmark_count(mattr.u.bookmarks)>0){
2467                         struct item *item;
2468                         bookmarks_item_rewind(mattr.u.bookmarks);
2469
2470                         while ((item=bookmarks_get_item(mattr.u.bookmarks))) {
2471
2472                                 if (!item_attr_get(item, attr_label, &attr)) 
2473                                         continue;
2474
2475                                 if (item->type == type_bookmark) 
2476                                         bookmarks_delete_bookmark(mattr.u.bookmarks,  attr.u.str);
2477
2478                                 bookmarks_move_down(mattr.u.bookmarks,wm->prefix);
2479                         }
2480                 }
2481                 bookmarks_item_rewind(mattr.u.bookmarks);
2482
2483                 bm_count=navit_get_destination_count(this->nav);
2484                 pc=g_alloca(bm_count*sizeof(struct pcoord));
2485                 navit_get_destinations(this->nav, pc, bm_count);
2486
2487                 for (i=0; i<bm_count; i++){
2488                         desc=g_strdup_printf("%s WP%d", navit_get_destination_description(this->nav, i), i+1);
2489                         navit_get_attr(this->nav, attr_bookmarks, &attr, NULL);
2490                         bookmarks_add_bookmark(attr.u.bookmarks, &pc[i], desc);
2491                         bookmarks_move_down(mattr.u.bookmarks,wm->prefix);
2492                         g_free(desc);
2493                 }
2494         }
2495
2496         gui_internal_prune_menu(this, NULL);
2497 }
2498
2499 static void
2500 get_direction(char *buffer, int angle, int mode)
2501 {
2502         angle=angle%360;
2503         switch (mode) {
2504         case 0:
2505                 sprintf(buffer,"%d",angle);
2506                 break;
2507         case 1:
2508                 if (angle < 69 || angle > 291)
2509                         *buffer++='N';
2510                 if (angle > 111 && angle < 249)
2511                         *buffer++='S';
2512                 if (angle > 22 && angle < 158)
2513                         *buffer++='E';
2514                 if (angle > 202 && angle < 338)
2515                         *buffer++='W';
2516                 *buffer++='\0';
2517                 break;
2518         case 2:
2519                 angle=(angle+15)/30;
2520                 if (! angle)
2521                         angle=12;
2522                 sprintf(buffer,"%d H", angle);
2523                 break;
2524         }
2525 }
2526
2527 static void gui_internal_cmd_position(struct gui_priv *this, struct widget *wm, void *data);
2528
2529 #ifndef _MSC_VER
2530 //MSVC doesn't supports this style of initialization and i'm not sure
2531 //how to fix it
2532 struct selector {
2533         char *icon;
2534         char *name;
2535         enum item_type *types;
2536 };
2537 struct selector selectors[]={
2538         {"bank","Bank",(enum item_type []){
2539                 type_poi_bank,type_poi_bank,
2540                 type_poi_atm,type_poi_atm,
2541                 type_none}},
2542         {"fuel","Fuel",(enum item_type []){type_poi_fuel,type_poi_fuel,type_none}},
2543         {"hotel","Hotel",(enum item_type []) {
2544                 type_poi_hotel,type_poi_camp_rv,
2545                 type_poi_camping,type_poi_camping,
2546                 type_poi_resort,type_poi_resort,
2547                 type_poi_motel,type_poi_hostel,
2548                 type_none}},
2549         {"restaurant","Restaurant",(enum item_type []) {
2550                 type_poi_bar,type_poi_picnic,
2551                 type_poi_burgerking,type_poi_fastfood,
2552                 type_poi_restaurant,type_poi_restaurant,
2553                 type_poi_cafe,type_poi_cafe,
2554                 type_poi_pub,type_poi_pub,
2555                 type_none}},
2556         {"shopping","Shopping",(enum item_type []) {
2557                 type_poi_mall,type_poi_mall,
2558                 type_poi_shop_grocery,type_poi_shop_grocery,
2559                 type_poi_shopping,type_poi_shopping,
2560                 type_poi_shop_butcher,type_poi_shop_baker,
2561                 type_poi_shop_fruit,type_poi_shop_fruit,
2562                 type_poi_shop_beverages,type_poi_shop_beverages,
2563                 type_none}},
2564         {"hospital","Service",(enum item_type []) {
2565                 type_poi_marina,type_poi_marina,
2566                 type_poi_hospital,type_poi_hospital,
2567                 type_poi_public_utilities,type_poi_public_utilities,
2568                 type_poi_police,type_poi_autoservice,
2569                 type_poi_information,type_poi_information,
2570                 type_poi_pharmacy,type_poi_pharmacy,
2571                 type_poi_personal_service,type_poi_repair_service,
2572                 type_poi_restroom,type_poi_restroom,
2573                 type_none}},
2574         {"parking","Parking",(enum item_type []){type_poi_car_parking,type_poi_car_parking,type_none}},
2575         {"peak","Land Features",(enum item_type []){
2576                 type_poi_land_feature,type_poi_rock,
2577                 type_poi_dam,type_poi_dam,
2578                 type_poi_peak,type_poi_peak,
2579                 type_none}},
2580         {"unknown","Other",(enum item_type []){
2581                 type_point_unspecified,type_poi_land_feature-1,
2582                 type_poi_rock+1,type_poi_fuel-1,
2583                 type_poi_marina+1,type_poi_shopping-1,
2584                 type_poi_shopping+1,type_poi_car_parking-1,
2585                 type_poi_car_parking+1,type_poi_bar-1,
2586                 type_poi_bank+1,type_poi_dam-1,
2587                 type_poi_dam+1,type_poi_information-1,
2588                 type_poi_information+1,type_poi_mall-1,
2589                 type_poi_mall+1,type_poi_personal_service-1,
2590                 type_poi_pharmacy+1,type_poi_repair_service-1,
2591                 type_poi_repair_service+1,type_poi_restaurant-1,
2592                 type_poi_restaurant+1,type_poi_restroom-1,
2593                 type_poi_restroom+1,type_poi_shop_grocery-1,
2594                 type_poi_shop_grocery+1,type_poi_peak-1,
2595                 type_poi_peak+1, type_poi_motel-1,
2596                 type_poi_hostel+1,type_poi_shop_butcher-1,
2597                 type_poi_shop_baker+1,type_poi_shop_fruit-1,
2598                 type_poi_shop_fruit+1,type_poi_shop_beverages-1,
2599                 type_poi_shop_beverages+1,type_poi_pub-1,
2600                 type_poi_atm+1,type_line-1,
2601                 type_none}},
2602 /*      {"unknown","Unknown",(enum item_type []){
2603                 type_point_unkn,type_point_unkn,
2604                 type_none}},*/
2605 };
2606
2607
2608 /*
2609  *  Get a utf-8 string, return the same prepared for case insensetive search. Result shoud be g_free()d after use.
2610  */
2611
2612 static char *
2613 removecase(char *s) 
2614 {
2615         char *r;
2616         r=g_utf8_casefold(s,-1);
2617         return r;
2618 }
2619
2620 /**
2621  * POI search/filtering parameters.
2622  *
2623  */
2624
2625 struct poi_param {
2626
2627                 /**
2628                  * =1 if selnb is defined, 0 otherwize.
2629                  */
2630                 unsigned char sel;
2631
2632                 /**
2633                  * Index to struct selector selectors[], shows what type of POIs is defined.
2634                  */             
2635                 unsigned char selnb;
2636                 /**
2637                  * Page number to display.
2638                  */             
2639                 unsigned char pagenb;
2640                 /**
2641                  * Radius (number of 10-kilometer intervals) to search for POIs.
2642                  */             
2643                 unsigned char dist;
2644                 /**
2645                  * Should filter phrase be compared to postal address of the POI.
2646                  * =1 - address filter, =0 - name filter
2647                  */             
2648                 unsigned char isAddressFilter;
2649                 /**
2650                  * Filter string, casefold()ed and divided into substrings at the spaces, which are replaced by ASCII 0*.
2651                  */             
2652                 char *filterstr; 
2653                 /**
2654                  * list of pointers to individual substrings of filterstr.
2655                  */             
2656                 GList *filter;
2657                 /**
2658                  * Number of POIs in this list
2659                  */
2660                 int count;
2661 };
2662
2663
2664 /**
2665  * @brief Free poi_param structure.
2666  *
2667  * @param p reference to the object to be freed.
2668  */
2669 static void
2670 gui_internal_poi_param_free(void *p) 
2671 {
2672         if(((struct poi_param *)p)->filterstr)
2673            g_free(((struct poi_param *)p)->filterstr);
2674         if(((struct poi_param *)p)->filter)
2675            g_list_free(((struct poi_param *)p)->filter);
2676         g_free(p);
2677 };
2678
2679 /**
2680  * @brief Clone poi_param structure.
2681  *
2682  * @param p reference to the object to be cloned.
2683  * @return  Cloned object reference.
2684  */
2685 static struct poi_param *
2686 gui_internal_poi_param_clone(struct poi_param *p) 
2687 {
2688         struct poi_param *r=g_new(struct poi_param,1);
2689         GList *l=p->filter;
2690         memcpy(r,p,sizeof(struct poi_param));
2691         r->filter=NULL;
2692         r->filterstr=NULL;
2693         if(p->filterstr) {
2694                 char *last=g_list_last(l)->data;
2695                 int len=(last - p->filterstr) + strlen(last)+1;
2696                 r->filterstr=g_memdup(p->filterstr,len);
2697         }
2698         while(l) {
2699                 r->filter=g_list_append(r->filter, r->filterstr + ((char*)(l->data) - p->filterstr) );
2700                 l=g_list_next(l);
2701         }
2702         return r;
2703 };
2704
2705 /**
2706  * @brief Set POIs filter data in poi_param structure.
2707  * @param param poi_param structure with unset filter data.
2708  * @param text filter text.
2709  */
2710 static void
2711 gui_internal_poi_param_set_filter(struct poi_param *param, char *text) 
2712 {
2713         char *s1, *s2;
2714         
2715         param->filterstr=removecase(text);
2716         s1=param->filterstr;
2717         do {
2718                 s2=g_utf8_strchr(s1,-1,' ');
2719                 if(s2)
2720                         *s2++=0;
2721                 param->filter=g_list_append(param->filter,s1);
2722                 if(s2) {
2723                         while(*s2==' ')
2724                                 s2++;
2725                 }
2726                 s1=s2;
2727         } while(s2 && *s2);
2728 }
2729
2730
2731 static void gui_internal_cmd_pois(struct gui_priv *this, struct widget *wm, void *data);
2732 static void gui_internal_cmd_pois_filter(struct gui_priv *this, struct widget *wm, void *data);
2733
2734
2735 static struct widget *
2736 gui_internal_cmd_pois_selector(struct gui_priv *this, struct pcoord *c, int pagenb)
2737 {
2738         struct widget *wl,*wb;
2739         int nitems,nrows;
2740         int i;
2741         //wl=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
2742         wl=gui_internal_box_new(this, gravity_left_center|orientation_horizontal_vertical|flags_fill);
2743         wl->background=this->background;
2744         wl->w=this->root.w;
2745         wl->cols=this->root.w/this->icon_s;
2746         nitems=sizeof(selectors)/sizeof(struct selector);
2747         nrows=nitems/wl->cols + (nitems%wl->cols>0);
2748         wl->h=this->icon_l*nrows;
2749         for (i = 0 ; i < nitems ; i++) {
2750                 struct poi_param *p=g_new0(struct poi_param,1);
2751                 p->sel = 1;
2752                 p->selnb = i;
2753                 p->pagenb = pagenb;
2754                 p->dist = 0;
2755                 p->filter=NULL;
2756                 p->filterstr=NULL;
2757                 gui_internal_widget_append(wl, wb=gui_internal_button_new_with_callback(this, NULL,
2758                         image_new_s(this, selectors[i].icon), gravity_left_center|orientation_vertical,
2759                         gui_internal_cmd_pois, p));
2760                 wb->c=*c;
2761                 wb->data_free=gui_internal_poi_param_free;
2762                 wb->bt=10;
2763         }
2764
2765         gui_internal_widget_append(wl, wb=gui_internal_button_new_with_callback(this, NULL,
2766                         image_new_s(this, "gui_search"), gravity_left_center|orientation_vertical,
2767                         gui_internal_cmd_pois_filter, NULL));
2768         wb->c=*c;
2769         wb->bt=10;
2770         
2771         gui_internal_widget_pack(this,wl);
2772         return wl;
2773 }
2774
2775 /**
2776  * @brief Get icon for given POI type.
2777  *
2778  * @param this pointer to gui context
2779  * @param type POI type
2780  * @return  Pointer to graphics_image object, or NULL if no picture available. 
2781  */
2782 static struct graphics_image * gui_internal_poi_icon(struct gui_priv *this, enum item_type type)
2783 {
2784         struct attr layout;
2785         GList *layer;
2786         navit_get_attr(this->nav, attr_layout, &layout, NULL);
2787         layer=layout.u.layout->layers;
2788         while(layer) {
2789                 GList *itemgra=((struct layer *)layer->data)->itemgras;
2790                 while(itemgra) {
2791                         GList *types=((struct itemgra *)itemgra->data)->type;
2792                         while(types) {
2793                                 if((long)types->data==type) {
2794                                         GList *element=((struct itemgra *)itemgra->data)->elements;
2795                                         while(element) {
2796                                                 struct element * el=element->data;
2797                                                 if(el->type==element_icon) {
2798                                                         struct graphics_image *img;
2799                                                         char *icon=g_strdup(el->u.icon.src);
2800                                                         char *dot=g_strrstr(icon,".");
2801                                                         dbg(0,"%s %s\n", item_to_name(type),icon);
2802                                                         if(dot)
2803                                                                 *dot=0;
2804                                                         img=image_new_xs(this,icon);
2805                                                         g_free(icon);
2806                                                         if(img) 
2807                                                                 return img;
2808                                                 }
2809                                                 element=g_list_next(element);
2810                                         }
2811                                 }
2812                                 types=g_list_next(types);       
2813                         }
2814                         itemgra=g_list_next(itemgra);
2815                 }
2816                 layer=g_list_next(layer);
2817         }
2818         return NULL;
2819 }
2820
2821 /**
2822  * @brief Widget to display POI item.
2823  *
2824  * @param this pointer to gui context
2825  * @param center reference to the standing point where angle to be counted from
2826  * @param item POI item reference
2827  * @param c POI coordinates
2828  * @param dist precomputed distance to POI (or -1 if it's not to be displayed)
2829  * @param name POI name
2830  * @return  Pointer to new widget.
2831  */
2832 static struct widget *
2833 gui_internal_cmd_pois_item(struct gui_priv *this, struct coord *center, struct item *item, struct coord *c, int dist, char* name)
2834 {
2835         char distbuf[32]="";
2836         char dirbuf[32]="";
2837         char *type;
2838         struct widget *wl;
2839         char *text;
2840         struct graphics_image *icon;
2841
2842         if (dist > 10000)
2843                 sprintf(distbuf,"%d ", dist/1000);
2844         else if (dist>0)
2845                 sprintf(distbuf,"%d.%d ", dist/1000, (dist%1000)/100);
2846         if(c) {
2847                 int len;                
2848                 get_direction(dirbuf, transform_get_angle_delta(center, c, 0), 1);
2849                 len=strlen(dirbuf);
2850                 dirbuf[len]=' ';
2851                 dirbuf[len+1]=0;
2852         }
2853         
2854         type=item_to_name(item->type);
2855
2856         icon=gui_internal_poi_icon(this,item->type);
2857         if(!icon) {
2858                 icon=image_new_xs(this,"gui_inactive");
2859                 text=g_strdup_printf("%s%s%s %s", distbuf, dirbuf, type, name);
2860         } else if(strlen(name)>0)
2861                 text=g_strdup_printf("%s%s%s", distbuf, dirbuf, name);
2862         else 
2863                 text=g_strdup_printf("%s%s%s", distbuf, dirbuf, type);
2864                 
2865         wl=gui_internal_button_new_with_callback(this, text, icon, gravity_left_center|orientation_horizontal|flags_fill, NULL, NULL);
2866         wl->datai=dist;
2867         g_free(text);
2868         if (name[0]) {
2869                 wl->name=g_strdup_printf("%s %s",type,name);
2870         } else {
2871                 wl->name=g_strdup(type);
2872         }
2873         wl->func=gui_internal_cmd_position;
2874         wl->data=(void *)9;
2875         wl->item=*item;
2876         wl->state|= STATE_SENSITIVE;
2877         return wl;
2878 }
2879
2880 /**
2881  * @brief Get string representation of item address suitable for doing search and for display in POI list.
2882  *
2883  * @param item reference to item.
2884  * @return  Pointer to string representation of address. To be g_free()d after use.
2885  */
2886 char *
2887 gui_internal_compose_item_address_string(struct item *item)
2888 {
2889         char *s=g_strdup("");
2890         struct attr attr;
2891         if(item_attr_get(item, attr_house_number, &attr)) 
2892                 s=g_strjoin(" ",s,attr.u.str,NULL);
2893         if(item_attr_get(item, attr_street_name, &attr)) 
2894                 s=g_strjoin(" ",s,attr.u.str,NULL);
2895         if(item_attr_get(item, attr_street_name_systematic, &attr)) 
2896                 s=g_strjoin(" ",s,attr.u.str,NULL);
2897         if(item_attr_get(item, attr_district_name, &attr)) 
2898                 s=g_strjoin(" ",s,attr.u.str,NULL);
2899         if(item_attr_get(item, attr_town_name, &attr)) 
2900                 s=g_strjoin(" ",s,attr.u.str,NULL);
2901         if(item_attr_get(item, attr_county_name, &attr)) 
2902                 s=g_strjoin(" ",s,attr.u.str,NULL);
2903         if(item_attr_get(item, attr_country_name, &attr)) 
2904                 s=g_strjoin(" ",s,attr.u.str,NULL);
2905         
2906         if(item_attr_get(item, attr_address, &attr)) 
2907                 s=g_strjoin(" ",s,"|",attr.u.str,NULL);
2908         return s;
2909 }
2910
2911 static int
2912 gui_internal_cmd_pois_item_selected(struct poi_param *param, struct item *item)
2913 {
2914         enum item_type *types;
2915         struct selector *sel = param->sel? &selectors[param->selnb]: NULL;
2916         enum item_type type=item->type;
2917         struct attr attr;
2918         int match=0;
2919         if (type >= type_line && param->filter==NULL)
2920                 return 0;
2921         if (! sel || !sel->types) {
2922                 match=1;
2923         } else {
2924                 types=sel->types;
2925                 while (*types != type_none) {
2926                         if (item->type >= types[0] && item->type <= types[1]) {
2927                                 return 1;
2928                         }
2929                         types+=2;
2930                 }
2931         }
2932         if (param->filter) {
2933                 char *long_name, *s;
2934                 GList *f;
2935                 if (param->isAddressFilter) {
2936                         s=gui_internal_compose_item_address_string(item);
2937                 } else if (item_attr_get(item, attr_label, &attr)) {
2938                         s=g_strdup_printf("%s %s", item_to_name(item->type), attr.u.str);
2939                 } else {
2940                         s=g_strdup(item_to_name(item->type));
2941                 }
2942                 long_name=removecase(s);
2943                 g_free(s);
2944                 item_attr_rewind(item);
2945                 
2946                 for(s=long_name,f=param->filter;f && s;f=g_list_next(f)) {
2947                         s=strstr(s,f->data);
2948                         if(!s) 
2949                                 break;
2950                         s=g_utf8_strchr(s,-1,' ');
2951                 }
2952                 if(f)
2953                         match=0;
2954                 g_free(long_name);
2955         }
2956         return match;
2957 }
2958
2959 struct item_data {
2960         int dist;
2961         char *label;
2962         struct item item;
2963         struct coord c;
2964 };
2965
2966 /**
2967  * @brief Event handler for POIs list "more" element.
2968  *
2969  * @param this The graphics context.
2970  * @param wm called widget.
2971  * @param data event data.
2972  */
2973 static void
2974 gui_internal_cmd_pois_more(struct gui_priv *this, struct widget *wm, void *data) 
2975 {
2976         struct widget *w=g_new0(struct widget,1);
2977         w->data=wm->data;
2978         w->c=wm->c;
2979         w->w=wm->w;
2980         wm->data_free=NULL;
2981         gui_internal_back(this, NULL, NULL);
2982         gui_internal_cmd_pois(this, w, w->data);
2983         free(w);
2984 }
2985
2986
2987 /**
2988  * @brief Event to apply POIs text filter.
2989  *
2990  * @param this The graphics context.
2991  * @param wm called widget.
2992  * @param data event data (pointer to editor widget containg filter text).
2993  */
2994 static void
2995 gui_internal_cmd_pois_filter_do(struct gui_priv *this, struct widget *wm, void *data) 
2996 {
2997         struct widget *w=data;
2998         struct poi_param *param;
2999         
3000         if(!w->text)
3001                 return;
3002         
3003         if(w->data) {
3004                 param=gui_internal_poi_param_clone(w->data);
3005                 param->pagenb=0;
3006         } else {
3007                 param=g_new0(struct poi_param,1);
3008         }
3009         param->isAddressFilter=strcmp(wm->name,"AddressFilter")==0;
3010
3011         gui_internal_poi_param_set_filter(param, w->text);
3012
3013         gui_internal_cmd_pois(this,w,param);
3014         gui_internal_poi_param_free(param);
3015 }
3016
3017 /**
3018  * @brief POIs filter dialog.
3019  * Event to handle '\r' '\n' keys pressed.
3020  * 
3021  */
3022
3023 static void
3024 gui_internal_cmd_pois_filter_changed(struct gui_priv *this, struct widget *wm, void *data)
3025 {
3026         int len;
3027         if (wm->text) {
3028                 len=strlen(wm->text);
3029                 dbg(1,"len=%d\n", len);
3030                 if (len && (wm->text[len-1] == '\n' || wm->text[len-1] == '\r')) {
3031                         wm->text[len-1]='\0';
3032                         //gui_internal_cmd_pois_filter_do(this, wm, wm); // Doesnt clean filter editor from the screen. How to disable its redrawal after POI list is drawn?
3033                 }
3034         }
3035 }
3036
3037
3038 /**
3039  * @brief POIs filter dialog.
3040  *
3041  * @param this The graphics context.
3042  * @param wm called widget.
3043  * @param data event data.
3044  */
3045 static void
3046 gui_internal_cmd_pois_filter(struct gui_priv *this, struct widget *wm, void *data) 
3047 {
3048         struct widget *wb, *w, *wr, *wk, *we;
3049         int keyboard_mode=2;
3050         wb=gui_internal_menu(this,"Filter");
3051         w=gui_internal_box_new(this, gravity_center|orientation_vertical|flags_expand|flags_fill);
3052         gui_internal_widget_append(wb, w);
3053         wr=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3054         gui_internal_widget_append(w, wr);
3055         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
3056         gui_internal_widget_append(wr, we);
3057
3058         gui_internal_widget_append(we, wk=gui_internal_label_new(this, NULL));
3059         wk->state |= STATE_EDIT|STATE_EDITABLE;
3060         wk->func=gui_internal_cmd_pois_filter_changed;
3061         wk->background=this->background;
3062         wk->flags |= flags_expand|flags_fill;
3063         wk->name=g_strdup("POIsFilter");
3064         wk->c=wm->c;
3065         gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
3066         wb->state |= STATE_SENSITIVE;
3067         wb->func = gui_internal_cmd_pois_filter_do;
3068         wb->name=g_strdup("NameFilter");
3069         wb->data=wk;
3070         gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "post")));
3071         wb->state |= STATE_SENSITIVE;
3072         wb->name=g_strdup("AddressFilter");
3073         wb->func = gui_internal_cmd_pois_filter_do;
3074         wb->data=wk;
3075         
3076         if (this->keyboard)
3077                 gui_internal_widget_append(w, gui_internal_keyboard(this,keyboard_mode));
3078         gui_internal_menu_render(this);
3079
3080
3081 }
3082
3083 /**
3084  * @brief Do POI search specified by poi_param and display POIs found
3085  *
3086  * @param this The graphics context.
3087  * @param wm called widget.
3088  * @param data event data, reference to poi_param or NULL.
3089  */
3090 static void
3091 gui_internal_cmd_pois(struct gui_priv *this, struct widget *wm, void *data)
3092 {
3093         struct map_selection *sel,*selm;
3094         struct coord c,center;
3095         struct mapset_handle *h;
3096         struct map *m;
3097         struct map_rect *mr;
3098         struct item *item;
3099         struct widget *wi,*w,*w2,*wb, *wtable, *row;
3100         enum projection pro=wm->c.pro;
3101         struct poi_param *param;
3102         int param_free=0;
3103         int idist,dist;
3104         struct selector *isel;
3105         int pagenb;
3106         int prevdist;
3107         // Starting value and increment of count of items to be extracted
3108         const int pagesize = 50; 
3109         int maxitem, it = 0, i;
3110         struct item_data *items;
3111         struct fibheap* fh = fh_makekeyheap();
3112         int cnt = 0;
3113         struct table_data *td;
3114
3115         if(data) {
3116           param = data;
3117         } else {
3118           param = g_new0(struct poi_param,1);
3119           param_free=1;
3120         }
3121         
3122         dist=10000*(param->dist+1);
3123         isel = param->sel? &selectors[param->selnb]: NULL;
3124         pagenb = param->pagenb;
3125         prevdist=param->dist*10000;
3126         maxitem = pagesize*(pagenb+1);
3127         items= g_new0( struct item_data, maxitem);
3128         
3129         
3130         dbg(0, "Params: sel = %i, selnb = %i, pagenb = %i, dist = %i, filterstr = %s, isAddressFilter= %d\n",
3131                 param->sel, param->selnb, param->pagenb, param->dist, param->filterstr, param->isAddressFilter);
3132
3133         wb=gui_internal_menu(this, isel ? isel->name : _("POIs"));
3134         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3135         gui_internal_widget_append(wb, w);
3136         if (!isel && !param->filter)
3137                 gui_internal_widget_append(w, gui_internal_cmd_pois_selector(this,&wm->c,pagenb));
3138         w2=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3139         gui_internal_widget_append(w, w2);
3140
3141         sel=map_selection_rect_new(&wm->c,dist*transform_scale(abs(wm->c.y)+dist*1.5),18);
3142         center.x=wm->c.x;
3143         center.y=wm->c.y;
3144         h=mapset_open(navit_get_mapset(this->nav));
3145         while ((m=mapset_next(h, 1))) {
3146                 selm=map_selection_dup_pro(sel, pro, map_projection(m));
3147                 mr=map_rect_new(m, selm);
3148                 dbg(2,"mr=%p\n", mr);
3149                 if (mr) {
3150                         while ((item=map_rect_get_item(mr))) {
3151                                 if (gui_internal_cmd_pois_item_selected(param, item) &&
3152                                     item_coord_get_pro(item, &c, 1, pro) &&
3153                                     coord_rect_contains(&sel->u.c_rect, &c)  &&
3154                                     (idist=transform_distance(pro, &center, &c)) < dist) {
3155                                         struct item_data *data;
3156                                         struct attr attr;
3157                                         char *label;
3158                                         
3159                                         if (item->type==type_house_number) {
3160                                                 label=gui_internal_compose_item_address_string(item);
3161                                         } else if (item_attr_get(item, attr_label, &attr)) {
3162                                                 label=g_strdup(attr.u.str);
3163                                                 // Buildings which label is equal to addr:housenumber value
3164                                                 // are duplicated by item_house_number. Don't include such 
3165                                                 // buildings into the list. This is true for OSM maps created with 
3166                                                 // maptool patched with #859 latest patch.
3167                                                 // FIXME: For non-OSM maps, we probably would better don't skip these items.
3168                                                 if(item->type==type_poly_building && item_attr_get(item, attr_house_number, &attr) ) {
3169                                                         if(strcmp(label,attr.u.str)==0) {
3170                                                                 g_free(label);
3171                                                                 continue;
3172                                                         }
3173                                                 }
3174
3175                                         } else {
3176                                                 label=g_strdup("");
3177                                         }
3178                                         
3179                                         if(it>=maxitem) {
3180                                                 data = fh_extractmin(fh);
3181                                                 g_free(data->label);
3182                                                 data->label=NULL;
3183                                         } else {
3184                                                 data = &items[it++];
3185                                         }
3186                                         data->label=label;
3187                                         data->item = *item;
3188                                         data->c = c;
3189                                         data->dist = idist;
3190                                         // Key expression is a workaround to fight
3191                                         // probable heap collisions when two objects
3192                                         // are at the same distance. But it destroys
3193                                         // right order of POIs 2048 km away from cener
3194                                         // and if table grows more than 1024 rows.
3195                                         fh_insertkey(fh, -((idist<<10) + cnt++), data);
3196                                         if (it == maxitem)
3197                                                 dist = (-fh_minkey(fh))>>10;
3198                                 }
3199                         }
3200                         map_rect_destroy(mr);
3201                 }
3202                 map_selection_destroy(selm);
3203         }
3204         map_selection_destroy(sel);
3205         mapset_close(h);
3206         
3207         wtable = gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
3208         td=wtable->data;
3209
3210         gui_internal_widget_append(w2,wtable);
3211
3212         // Move items from heap to the table
3213         for(i=0;;i++) 
3214         {
3215                 int key = fh_minkey(fh);
3216                 struct item_data *data = fh_extractmin(fh);
3217                 if (data == NULL)
3218                 {
3219                         dbg(2, "Empty heap: maxitem = %i, it = %i, dist = %i\n", maxitem, it, dist);
3220                         break;
3221                 }
3222                 dbg(2, "dist1: %i, dist2: %i\n", data->dist, (-key)>>10);
3223                 if(i==(it-pagesize*pagenb) && data->dist>prevdist)
3224                         prevdist=data->dist;
3225                 wi=gui_internal_cmd_pois_item(this, &center, &data->item, &data->c, data->dist, data->label);
3226                 wi->c.x=data->c.x;
3227                 wi->c.y=data->c.y;
3228                 wi->c.pro=pro;
3229                 wi->background=this->background;
3230                 row = gui_internal_widget_table_row_new(this,
3231                                                           gravity_left
3232                                                           | flags_fill
3233                                                           | orientation_horizontal);
3234                 gui_internal_widget_append(row,wi);
3235                 row->datai=data->dist;
3236                 gui_internal_widget_prepend(wtable,row);
3237                 free(data->label);
3238         }
3239
3240         fh_deleteheap(fh);
3241         free(items);
3242
3243         // Add an entry for more POI
3244         struct widget *wl,*wt;
3245         char buffer[32];
3246         struct poi_param *paramnew;
3247         row = gui_internal_widget_table_row_new(this,
3248                                                   gravity_left
3249                                                   | flags_fill
3250                                                   | orientation_horizontal);
3251         row->datai=100000000; // Really far away for Earth, but won't work for bigger planets.
3252         gui_internal_widget_append(wtable,row);
3253         wl=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
3254         gui_internal_widget_append(row,wl);
3255         if (it == maxitem) {
3256                 paramnew=gui_internal_poi_param_clone(param);
3257                 paramnew->pagenb++;
3258                 paramnew->count=it;
3259                 snprintf(buffer, sizeof(buffer), "Get more (up to %d items)...", (paramnew->pagenb+1)*pagesize);
3260                 wt=gui_internal_label_new(this, buffer);
3261                 gui_internal_widget_append(wl, wt);
3262                 wt->func=gui_internal_cmd_pois_more;
3263                 wt->data=paramnew;
3264                 wt->data_free=gui_internal_poi_param_free;
3265                 wt->state |= STATE_SENSITIVE;
3266                 wt->c = wm->c;
3267         } else {
3268                 static int dist[]={1,5,10,0};
3269                 wt=gui_internal_label_new(this, "Set distance to");
3270                 gui_internal_widget_append(wl, wt);
3271                 for(i=0;dist[i];i++) {
3272                         paramnew=gui_internal_poi_param_clone(param);
3273                         paramnew->dist+=dist[i];
3274                         paramnew->count=it;
3275                         snprintf(buffer, sizeof(buffer), " %i ", 10*(paramnew->dist+1));
3276                         wt=gui_internal_label_new(this, buffer);
3277                         gui_internal_widget_append(wl, wt);
3278                         wt->func=gui_internal_cmd_pois_more;
3279                         wt->data=paramnew;
3280                         wt->data_free=gui_internal_poi_param_free;
3281                         wt->state |= STATE_SENSITIVE;
3282                         wt->c = wm->c;
3283                 }
3284                 wt=gui_internal_label_new(this, "km.");
3285                 gui_internal_widget_append(wl, wt);
3286
3287         }
3288         // Rendering now is needed to have table_data->bottomrow filled in.
3289         gui_internal_menu_render(this);
3290         td=wtable->data;
3291         if(td->bottom_row!=NULL)
3292         {
3293 #if 0
3294                 while(((struct widget*)td->bottom_row->data)->datai<=prevdist
3295                                 && (td->next_button->state & STATE_SENSITIVE))
3296                 {
3297                         gui_internal_table_button_next(this, td->next_button, NULL);
3298                 }
3299 #else
3300                 int firstrow=g_list_index(wtable->children, td->top_row->data);
3301                 while(firstrow>=0) {
3302                         int currow=g_list_index(wtable->children, td->bottom_row->data) - firstrow;
3303                         if(currow<0) {
3304                                 dbg(0,"Can't find bottom row in children list. Stop paging.\n");
3305                                 break;
3306                         }
3307                         if(currow>=param->count)
3308                                 break;
3309                         if(!(td->next_button->state & STATE_SENSITIVE)) {
3310                                 dbg(0,"Reached last page but item %i not found. Stop paging.\n",param->count);
3311                                 break;
3312                         }
3313                         gui_internal_table_button_next(this, td->next_button, NULL);
3314                 }
3315 #endif
3316         }
3317         gui_internal_menu_render(this);
3318         if(param_free)
3319                 g_free(param);
3320 }
3321 #endif /* _MSC_VER */
3322
3323 static void
3324 gui_internal_cmd_view_on_map(struct gui_priv *this, struct widget *wm, void *data)
3325 {
3326         if (wm->item.type != type_none) {
3327                 enum item_type type;
3328                 if (wm->item.type < type_line)
3329                         type=type_selected_point;
3330                 else if (wm->item.type < type_area)
3331                         type=type_selected_point;
3332                 else
3333                         type=type_selected_area;
3334                 graphics_clear_selection(this->gra, NULL);
3335                 graphics_add_selection(this->gra, &wm->item, type, NULL);
3336         }
3337         navit_set_center(this->nav, &wm->c, 1);
3338         gui_internal_prune_menu(this, NULL);
3339 }
3340
3341
3342 static void
3343 gui_internal_cmd_view_attribute_details(struct gui_priv *this, struct widget *wm, void *data)
3344 {
3345         struct widget *w,*wb;
3346         struct map_rect *mr;
3347         struct item *item;
3348         struct attr attr;
3349         char *text,*url;
3350         int i;
3351
3352         text=g_strdup_printf("Attribute %s",wm->name);
3353         wb=gui_internal_menu(this, text);
3354         g_free(text);
3355         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3356         gui_internal_widget_append(wb, w);
3357         mr=map_rect_new(wm->item.map, NULL);
3358         item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
3359         for (i = 0 ; i < wm->datai ; i++) {
3360                 item_attr_get(item, attr_any, &attr);
3361         }
3362         if (item_attr_get(item, attr_any, &attr)) {
3363                 url=NULL;
3364                 switch (attr.type) {
3365                 case attr_osm_nodeid:
3366                         url=g_strdup_printf("http://www.openstreetmap.org/browse/node/"LONGLONG_FMT"\n",*attr.u.num64);
3367                         break;
3368                 case attr_osm_wayid:
3369                         url=g_strdup_printf("http://www.openstreetmap.org/browse/way/"LONGLONG_FMT"\n",*attr.u.num64);
3370                         break;
3371                 case attr_osm_relationid:
3372                         url=g_strdup_printf("http://www.openstreetmap.org/browse/relation/"LONGLONG_FMT"\n",*attr.u.num64);
3373                         break;
3374                 default:
3375                         break;
3376                 }
3377                 if (url) {
3378                         gui_internal_widget_append(w,
3379                                         wb=gui_internal_button_new_with_callback(this, _("View in Browser"),
3380                                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3381                                                 gui_internal_cmd_view_in_browser, NULL));
3382                         wb->name=url;
3383                 }
3384         }
3385         map_rect_destroy(mr);
3386         gui_internal_menu_render(this);
3387 }
3388
3389 static void
3390 gui_internal_cmd_view_attributes(struct gui_priv *this, struct widget *wm, void *data)
3391 {
3392         struct widget *w,*wb;
3393         struct map_rect *mr;
3394         struct item *item;
3395         struct attr attr;
3396         char *text;
3397         int count=0;
3398
3399         dbg(0,"item=%p 0x%x 0x%x\n", wm->item.map,wm->item.id_hi, wm->item.id_lo);
3400         wb=gui_internal_menu(this, "Attributes");
3401         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3402         gui_internal_widget_append(wb, w);
3403         mr=map_rect_new(wm->item.map, NULL);
3404         item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
3405         dbg(0,"item=%p\n", item);
3406         if (item) {
3407                 text=g_strdup_printf("%s:%s", _("Item type"), item_to_name(item->type));
3408                 gui_internal_widget_append(w,
3409                 wb=gui_internal_button_new(this, text,
3410                         NULL, gravity_left_center|orientation_horizontal|flags_fill));
3411                 wb->name=g_strdup(text);
3412                 wb->item=wm->item;
3413                 g_free(text);
3414                 while(item_attr_get(item, attr_any, &attr)) {
3415                         char *attrtxt;
3416                         text=g_strdup_printf("%s:%s", attr_to_name(attr.type), attrtxt=attr_to_text(&attr, wm->item.map, 1));
3417                         g_free(attrtxt);
3418                         gui_internal_widget_append(w,
3419                         wb=gui_internal_button_new_with_callback(this, text,
3420                                 NULL, gravity_left_center|orientation_horizontal|flags_fill,
3421                                 gui_internal_cmd_view_attribute_details, NULL));
3422                         wb->name=g_strdup(text);
3423                         wb->item=wm->item;
3424                         wb->datai=count++;
3425                         g_free(text);
3426                 }
3427         }
3428         map_rect_destroy(mr);
3429         gui_internal_menu_render(this);
3430 }
3431
3432 static void
3433 gui_internal_cmd_view_in_browser(struct gui_priv *this, struct widget *wm, void *data)
3434 {
3435         struct map_rect *mr;
3436         struct item *item;
3437         struct attr attr;
3438         char *cmd=NULL;
3439
3440         if (!wm->name) {
3441                 dbg(0,"item=%p 0x%x 0x%x\n", wm->item.map,wm->item.id_hi, wm->item.id_lo);
3442                 mr=map_rect_new(wm->item.map, NULL);
3443                 item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
3444                 dbg(0,"item=%p\n", item);
3445                 if (item) {
3446                         while(item_attr_get(item, attr_url_local, &attr)) {
3447                                 if (! cmd)
3448                                         cmd=g_strdup_printf("navit-browser.sh '%s' &",attr.u.str);
3449                         }
3450                 }
3451                 map_rect_destroy(mr);
3452         } else {
3453                 cmd=g_strdup_printf("navit-browser.sh '%s' &",wm->name);
3454         }
3455         if (cmd) {
3456 #ifdef HAVE_SYSTEM
3457                 system(cmd);
3458 #else
3459                 dbg(0,"calling external cmd '%s' is not supported\n",cmd);
3460 #endif
3461                 g_free(cmd);
3462         }
3463 }
3464
3465
3466 /*
3467  * @brief Event to transfer search results to a map.
3468  *
3469  * @param this The graphics context.
3470  * @param wm called widget.
3471  * @param data event data (pointer to the table widget containing results, or NULL if results map is only have to be cleaned).
3472  */
3473 static void
3474 gui_internal_cmd_results_to_map(struct gui_priv *this, struct widget *wm, void *data)
3475 {
3476         struct widget *w;
3477         struct mapset *ms;      
3478         struct map *map;
3479         struct map_selection sel;
3480         struct map_rect *mr;
3481         struct item *item;
3482         GList *l;
3483         struct coord_rect r;
3484         struct attr a;
3485         int count;
3486         
3487         ms=navit_get_mapset(this->nav);
3488
3489         if(!ms)
3490                 return;
3491
3492         map=mapset_get_map_by_name(ms, "search_results");
3493         if(!map) {
3494                 struct attr *attrs[10], attrmap;
3495                 enum attr_type types[]={attr_position_longitude,attr_position_latitude,attr_label,attr_none};
3496                 int i;
3497                 
3498                 attrs[0]=g_new0(struct attr,1);
3499                 attrs[0]->type=attr_type;
3500                 attrs[0]->u.str="csv";
3501
3502                 attrs[1]=g_new0(struct attr,1);
3503                 attrs[1]->type=attr_name;
3504                 attrs[1]->u.str="search_results";
3505
3506                 attrs[2]=g_new0(struct attr,1);
3507                 attrs[2]->type=attr_charset;
3508                 attrs[2]->u.str="utf-8";
3509                 
3510                 attrs[3]=g_new0(struct attr,1);
3511                 attrs[3]->type=attr_item_type;
3512                 attrs[3]->u.num=type_found_item;
3513
3514                 attrs[4]=g_new0(struct attr,1);
3515                 attrs[4]->type=attr_attr_types;
3516                 attrs[4]->u.attr_types=types;
3517                 attrs[5]=NULL;
3518                 
3519                 attrmap.type=attr_map;
3520                 map=attrmap.u.map=map_new(NULL,attrs);
3521                 if(map)
3522                         mapset_add_attr(ms,&attrmap);
3523
3524                 for(i=0;attrs[i];i++)
3525                         g_free(attrs[i]);
3526
3527         }
3528
3529         if(!map)
3530                 return;
3531
3532         sel.next=NULL;
3533         sel.order=18;
3534         sel.range.min=type_none;
3535         sel.range.max=type_tec_common;
3536         
3537
3538         mr = map_rect_new(map, NULL);
3539
3540         if(!mr)
3541                 return;
3542                 
3543         /* Clean the map */
3544         while((item = map_rect_get_item(mr))!=NULL) {
3545                 item_type_set(item,type_none);
3546         }
3547
3548         this->results_map_population=0;
3549          
3550         /* Find the table to pupulate the map */
3551         for(w=data; w && w->type!=widget_table;w=w->parent);
3552         
3553         if(!w) {
3554                 map_rect_destroy(mr);
3555                 dbg(1,"Can't find the results table - only map clean up is done.\n");
3556                 return;
3557         }
3558
3559         /* Populate the map with search results*/
3560         for(l=w->children, count=0;l;l=g_list_next(l)) {
3561                 struct widget *wr=l->data;
3562                 if(wr->type==widget_table_row) {
3563                         struct widget *wi=wr->children->data;
3564                         if(wi->name==NULL)
3565                                 continue;
3566                         dbg(0,"%s\n",wi->name);
3567                         struct item* it=map_rect_create_item(mr,type_found_item);
3568                         if(it) {
3569                                 struct coord c;
3570                                 struct attr a;
3571                                 c.x=wi->c.x;
3572                                 c.y=wi->c.y;
3573                                 item_coord_set(it, &c, 1, change_mode_modify);
3574                                 a.type=attr_label;
3575                                 a.u.str=wi->name;
3576                                 item_attr_set(it, &a, change_mode_modify);
3577                                 if(!count++)
3578                                         r.lu=r.rl=c;
3579                                 else
3580                                         coord_rect_extend(&r,&c);
3581                         }
3582                 }
3583         }
3584         map_rect_destroy(mr);
3585         if(!count)
3586                 return;
3587         a.type=attr_orientation;
3588         a.u.num=0;
3589         navit_set_attr(this->nav,&a);
3590         navit_zoom_to_rect(this->nav,&r);
3591         gui_internal_prune_menu(this, NULL);
3592         this->results_map_population=count;
3593 }
3594
3595 /*
3596  * @brief Event to remove search results from the a map.
3597  *
3598  * @param this The graphics context.
3599  * @param wm called widget.
3600  * @param data event data
3601  */
3602 static void
3603 gui_internal_cmd_results_map_clean(struct gui_priv *this, struct widget *wm, void *data)
3604 {
3605         gui_internal_cmd_results_to_map(this,wm,NULL);
3606         gui_internal_prune_menu(this, NULL);
3607         navit_draw(this->nav);
3608 }
3609
3610
3611 /* meaning of the bits in "flags":
3612  * 1: "Streets"
3613  * 2: "House numbers"
3614  * 4: "View in Browser", "View Attributes"
3615  * 8: "Set as dest."
3616  * 16: "Set as pos."
3617  * 32: "Add as bookm."
3618  * 64: "POIs"
3619  * 128: "View on Map"
3620  * 256: POIs around this point, "Drop search results from the map"
3621  * 512: "Cut/Copy... bookmark"
3622  * 1024: "Jump to attributes of top item within this->radius pixels of this point (implies flags|=256)"
3623  * 2048: "Show search results on the map"
3624  * TODO define constants for these values
3625  */
3626 static void
3627 gui_internal_cmd_position_do(struct gui_priv *this, struct pcoord *pc_in, struct coord_geo *g_in, struct widget *wm, char *name, int flags)
3628 {
3629         struct widget *wb,*w,*wtable,*row,*wc,*wbc,*wclosest=NULL;
3630         struct coord_geo g;
3631         struct pcoord pc;
3632         struct coord c;
3633         char *coord;
3634
3635         if (pc_in) {
3636                 pc=*pc_in;
3637                 c.x=pc.x;
3638                 c.y=pc.y;
3639                 dbg(0,"x=0x%x y=0x%x\n", c.x, c.y);
3640                 transform_to_geo(pc.pro, &c, &g);
3641         } else if (g_in) {
3642                 struct attr attr;
3643                 if (!navit_get_attr(this->nav, attr_projection, &attr, NULL))
3644                         return;
3645                 g=*g_in;
3646                 pc.pro=attr.u.projection;
3647                 transform_from_geo(pc.pro, &g, &c);
3648                 pc.x=c.x;
3649                 pc.y=c.y;
3650         } else
3651                 return;
3652
3653         wb=gui_internal_menu(this, name);
3654         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3655         gui_internal_widget_append(wb, w);
3656         coord=coordinates(&pc, ' ');
3657         gui_internal_widget_append(w, gui_internal_label_new(this, coord));
3658         g_free(coord);
3659         wtable = gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
3660         gui_internal_widget_append(w,wtable);
3661         
3662         if ((flags & 1) && wm) {
3663                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3664                 gui_internal_widget_append(row,
3665                         wc=gui_internal_button_new_with_callback(this, _("Streets"),
3666                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3667                                 gui_internal_search_street_in_town, wm));
3668                 wc->item=wm->item;
3669                 wc->selection_id=wm->selection_id;
3670         }
3671         if ((flags & 2) && wm) {
3672                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3673                 gui_internal_widget_append(row,
3674                         wc=gui_internal_button_new_with_callback(this, _("House numbers"),
3675                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3676                                 gui_internal_search_house_number_in_street, wm));
3677                 wc->item=wm->item;
3678                 wc->selection_id=wm->selection_id;
3679         }
3680         if ((flags & 4) && wm) {
3681                 struct map_rect *mr;
3682                 struct item *item;
3683                 struct attr attr;
3684                 mr=map_rect_new(wm->item.map, NULL);
3685                 item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
3686                 if (item) {
3687                         if (item_attr_get(item, attr_description, &attr))
3688                                 gui_internal_widget_append(w, gui_internal_label_new(this, attr.u.str));
3689                         if (item_attr_get(item, attr_url_local, &attr)) {
3690                                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3691                                 gui_internal_widget_append(row,
3692                                         wb=gui_internal_button_new_with_callback(this, _("View in Browser"),
3693                                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3694                                                 gui_internal_cmd_view_in_browser, NULL));
3695                                 wb->item=wm->item;
3696                         }
3697                         gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3698                         gui_internal_widget_append(row,
3699                                 wb=gui_internal_button_new_with_callback(this, _("View Attributes"),
3700                                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3701                                         gui_internal_cmd_view_attributes, NULL));
3702                         wb->item=wm->item;
3703                 }
3704                 map_rect_destroy(mr);
3705         }
3706         if (flags & 8) {
3707                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3708                 gui_internal_widget_append(row,
3709                         wbc=gui_internal_button_new_with_callback(this, _("Set as destination"),
3710                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3711                                 gui_internal_cmd_set_destination, g_strdup(name)));
3712                 wbc->data_free=g_free_func;
3713                 wbc->c=pc;
3714         }
3715         if (flags & 16) {
3716                 const char *text;
3717                 struct attr vehicle, source;
3718                 int deactivate=0;
3719                 if (navit_get_attr(this->nav, attr_vehicle, &vehicle, NULL) && vehicle.u.vehicle && 
3720                                 !(vehicle_get_attr(vehicle.u.vehicle, attr_source, &source, NULL) && source.u.str && !strcmp("demo://",source.u.str))) 
3721                         deactivate=1;
3722
3723                 text=deactivate? _("Set as position (and deactivate vehicle)") : _("Set as position");
3724
3725                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3726                 gui_internal_widget_append(row,
3727                         wbc=gui_internal_button_new_with_callback(this, text,
3728                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3729                         gui_internal_cmd_set_position, (void*)deactivate));
3730                 wbc->c=pc;
3731         }
3732         if (flags & 32) {
3733                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3734                 gui_internal_widget_append(row,
3735                         wbc=gui_internal_button_new_with_callback(this, _("Add as bookmark"),
3736                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3737                         gui_internal_cmd_add_bookmark2, g_strdup(name)));
3738                 wbc->data_free=g_free_func;
3739                 wbc->c=pc;
3740         }
3741 #ifndef _MSC_VER
3742 //POIs are not operational under MSVC yet
3743         if (flags & 64) {
3744                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3745                 gui_internal_widget_append(row,
3746                         wbc=gui_internal_button_new_with_callback(this, _("POIs"),
3747                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3748                                 gui_internal_cmd_pois, NULL));
3749                 wbc->c=pc;
3750         }
3751 #endif /* _MSC_VER */
3752 #if 0
3753         gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3754         gui_internal_widget_append(row,
3755                 gui_internal_button_new(this, "Add to tour",
3756                         image_new_o(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill));
3757 #endif
3758         if (flags & 128) {
3759                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3760                 gui_internal_widget_append(row,
3761                         wbc=gui_internal_button_new_with_callback(this, _("View on map"),
3762                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3763                                 gui_internal_cmd_view_on_map, NULL));
3764                 wbc->c=pc;
3765                 if ((flags & 4) && wm)
3766                         wbc->item=wm->item;
3767                 else
3768                         wbc->item.type=type_none;
3769         }
3770         if(flags & 256 && this->results_map_population) {
3771                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3772                 gui_internal_widget_append(row,
3773                         wbc=gui_internal_button_new_with_callback(this, _("Remove search results from the map"),
3774                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3775                                 gui_internal_cmd_results_map_clean, NULL));
3776                 wbc->data=wm;
3777         }
3778         if(flags & 2048) {
3779                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3780                 gui_internal_widget_append(row,
3781                         wbc=gui_internal_button_new_with_callback(this, _("Show results on the map"),
3782                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3783                                 gui_internal_cmd_results_to_map, NULL));
3784                 wbc->data=wm;
3785         }
3786         if ((flags & 256) || (flags & 1024)) {
3787                 struct displaylist_handle *dlh;
3788                 struct displaylist *display;
3789                 struct attr attr;
3790                 struct point p;
3791                 struct transformation *trans;
3792                 
3793                 char *text, *label;
3794                 struct map_selection *sel;
3795                 GList *l, *ll;
3796                 
3797                 c.x=pc.x;
3798                 c.y=pc.y;
3799
3800                 trans=navit_get_trans(this->nav);
3801                 transform(trans,pc.pro,&c,&p,1,0,0,0);
3802                 display=navit_get_displaylist(this->nav);
3803                 dlh=graphics_displaylist_open(display);
3804                 sel=displaylist_get_selection(display);
3805                 l=displaylist_get_clicked_list(display, &p, this->radius);
3806                 for(ll=l;ll;ll=g_list_next(ll)) {
3807                         struct displayitem *di;
3808                         struct item *item;
3809                         struct map_rect *mr;
3810                         struct item *itemo;
3811
3812                         di=(struct displayitem*)ll->data;
3813                         item=graphics_displayitem_get_item(di);
3814                         
3815                         mr=map_rect_new(item->map, sel);
3816                         itemo=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
3817                                 
3818                         if (item_attr_get(itemo, attr_label, &attr)) {
3819                                 label=map_convert_string(itemo->map, attr.u.str);
3820                                 text=g_strdup_printf("%s %s", item_to_name(item->type), label);
3821                                 map_convert_free(label);
3822                         } else
3823                                 text=g_strdup_printf("%s", item_to_name(item->type));
3824                         gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3825                         gui_internal_widget_append(row, wc=gui_internal_cmd_pois_item(this, NULL, itemo, NULL, -1, text));
3826                         wc->c=pc;
3827                         wc->name=g_strdup(text);
3828                         wc->item=*itemo;
3829                         g_free(text);
3830                         map_rect_destroy(mr);
3831                         if(!wclosest)
3832                                 wclosest=wc;
3833
3834                 }
3835                 g_list_free(l);
3836                 map_selection_destroy(sel);
3837                 graphics_displaylist_close(dlh);
3838         }
3839         if (flags & 512) {
3840                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3841                 gui_internal_widget_append(row,
3842                         wbc=gui_internal_button_new_with_callback(this, _("Cut Bookmark"),
3843                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3844                                 gui_internal_cmd_cut_bookmark, NULL));
3845                 wbc->text=g_strdup(wm->text);
3846                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3847                 gui_internal_widget_append(row,
3848                         wbc=gui_internal_button_new_with_callback(this, _("Copy Bookmark"),
3849                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3850                                 gui_internal_cmd_copy_bookmark, NULL));
3851                 wbc->text=g_strdup(wm->text);
3852                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3853                 gui_internal_widget_append(row,
3854                         wbc=gui_internal_button_new_with_callback(this, _("Rename Bookmark"),
3855                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3856                                 gui_internal_cmd_rename_bookmark, NULL));
3857                 wbc->text=g_strdup(wm->text);
3858                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3859                 gui_internal_widget_append(row,
3860                         wbc=gui_internal_button_new_with_callback(this, _("Paste Bookmark"),
3861                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3862                                 gui_internal_cmd_paste_bookmark, NULL));
3863                 gui_internal_widget_append(wtable,row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
3864                 gui_internal_widget_append(row,
3865                         wbc=gui_internal_button_new_with_callback(this, _("Delete Bookmark"),
3866                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3867                                 gui_internal_cmd_delete_bookmark, NULL));
3868                 wbc->text=g_strdup(wm->text);
3869         }
3870         
3871         gui_internal_menu_render(this);
3872
3873         if((flags & 1024) && wclosest) 
3874                         gui_internal_cmd_view_attributes(this,wclosest,wclosest->data);
3875 }
3876
3877
3878 /* wm->data:    0 Nothing special
3879                 1 Map Point
3880                 2 Item
3881                 3 Town
3882                 4 County
3883                 5 Street
3884                 6 House number
3885                 7 Bookmark
3886                 8 Former destination
3887                 9 Item from the POI list
3888 */
3889
3890 static void
3891 gui_internal_cmd_position(struct gui_priv *this, struct widget *wm, void *data)
3892 {
3893         int flags;
3894         switch ((long) wm->data) {
3895         case 0:
3896                 flags=8|16|32|64|128|256;
3897                 break;
3898         case 1:
3899                 flags=8|16|32|64|256;
3900                 break;
3901         case 2:
3902                 flags=4|8|16|32|64|128;
3903                 break;
3904         case 3:
3905                 flags=1|8|16|32|64|128|2048;
3906                 flags &= this->flags_town;
3907                 break;
3908         case 4:
3909                 gui_internal_search_town_in_country(this, wm);
3910                 return;
3911         case 5:
3912                 flags=2|8|16|32|64|128|2048;
3913                 flags &= this->flags_street;
3914                 break;
3915         case 6:
3916                 flags=8|16|32|64|128|2048;
3917                 flags &= this->flags_house_number;
3918                 break;
3919         case 7:
3920                 flags=8|16|64|128|512;
3921                 break;
3922         case 8:
3923                 flags=8|16|32|64|128;
3924                 break;
3925         case 9:
3926                 flags=4|8|16|32|64|128|2048;
3927                 break;
3928         default:
3929                 return;
3930         }
3931         switch (flags) {
3932         case 2:
3933                 gui_internal_search_house_number_in_street(this, wm, NULL);
3934                 return;
3935         case 8:
3936                 gui_internal_cmd_set_destination(this, wm, NULL);
3937                 return;
3938         }
3939         gui_internal_cmd_position_do(this, &wm->c, NULL, wm, wm->name ? wm->name : wm->text, flags);
3940 }
3941
3942 static void
3943 gui_internal_cmd2_position(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3944 {
3945         char *name=_("Position");
3946         int flags=-1;
3947
3948         dbg(1,"enter\n");
3949         if (!in || !in[0])
3950                 return;
3951         if (!ATTR_IS_COORD_GEO(in[0]->type))
3952                 return;
3953         if (in[1] && ATTR_IS_STRING(in[1]->type)) {
3954                 name=in[1]->u.str;
3955                 if (in[2] && ATTR_IS_INT(in[2]->type))
3956                         flags=in[2]->u.num;
3957         }
3958         dbg(1,"flags=0x%x\n",flags);
3959         gui_internal_cmd_position_do(this, NULL, in[0]->u.coord_geo, NULL, name, flags);
3960 }
3961
3962 static void
3963 gui_internal_cmd2_pois(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3964 {
3965         struct widget *w;
3966         struct poi_param *param;
3967         struct attr pro;
3968         struct coord c;
3969
3970         dbg(1,"enter\n");
3971         if (!in || !in[0])
3972                 return;
3973         if (!ATTR_IS_COORD_GEO(in[0]->type))
3974                 return;
3975         if (!navit_get_attr(this->nav, attr_projection, &pro, NULL))
3976                 return;
3977         w=g_new0(struct widget,1);
3978         param=g_new0(struct poi_param,1);
3979         if (in[1] && ATTR_IS_STRING(in[1]->type)) {
3980                 gui_internal_poi_param_set_filter(param, in[1]->u.str);
3981                 if (in[2] && ATTR_IS_INT(in[2]->type))
3982                         param->isAddressFilter=in[2]->u.num;
3983         }
3984         
3985         transform_from_geo(pro.u.projection,in[0]->u.coord_geo,&c);
3986         w->c.x=c.x;
3987         w->c.y=c.y;
3988         w->c.pro=pro.u.projection;
3989         gui_internal_cmd_pois(this, w, param);
3990         g_free(w);
3991         gui_internal_poi_param_free(param);
3992 }
3993
3994
3995 /**
3996   * The "Bookmarks" section of the OSD
3997   * 
3998   */
3999
4000 static void
4001 gui_internal_cmd_bookmarks(struct gui_priv *this, struct widget *wm, void *data)
4002 {
4003         struct attr attr,mattr;
4004         struct item *item;
4005         char *label_full,*prefix=0;
4006         int plen=0,hassub,found=0;
4007         struct widget *wb,*w,*wbm;
4008         struct coord c;
4009         struct widget *tbl, *row;
4010
4011         if (data)
4012                 prefix=g_strdup(data);
4013         else {
4014                 if (wm && wm->prefix)
4015                         prefix=g_strdup(wm->prefix);
4016         }
4017         if ( prefix )
4018                 plen=strlen(prefix);
4019
4020         gui_internal_prune_menu_count(this, 1, 0);
4021         wb=gui_internal_menu(this, _("Bookmarks"));
4022         wb->background=this->background;
4023         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
4024         //w->spy=this->spacing*3;
4025         gui_internal_widget_append(wb, w);
4026
4027         if(navit_get_attr(this->nav, attr_bookmarks, &mattr, NULL) ) {
4028                 if (!plen) {
4029                         bookmarks_move_root(mattr.u.bookmarks);
4030                 } else {
4031                         if (!strcmp(prefix,"..")) {
4032                                 bookmarks_move_up(mattr.u.bookmarks);
4033                                 g_free(prefix);
4034                                 prefix=g_strdup(bookmarks_item_cwd(mattr.u.bookmarks));
4035                                 if (prefix) {
4036                                         plen=strlen(prefix);
4037                                 } else {
4038                                         plen=0;
4039                                 }
4040                         } else {
4041                                 bookmarks_move_down(mattr.u.bookmarks,prefix);
4042                         }
4043                         
4044                           // "Back" button, when inside a bookmark folder
4045                           
4046                         if (plen) {
4047                                 wbm=gui_internal_button_new_with_callback(this, "..",
4048                                         image_new_xs(this, "gui_inactive"), gravity_left_center|orientation_horizontal|flags_fill,
4049                                                 gui_internal_cmd_bookmarks, NULL);
4050                                                 wbm->prefix=g_strdup("..");
4051                                 gui_internal_widget_append(w, wbm);
4052
4053                                 // load bookmark folder as Waypoints, if any
4054                                 if (bookmarks_get_bookmark_count(mattr.u.bookmarks) > 0){
4055                                         wbm=gui_internal_button_new_with_callback(this, _("Bookmarks as Waypoints"),
4056                                                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
4057                                                         gui_internal_cmd_load_bookmarks_as_waypoints, NULL);
4058                                         wbm->prefix=g_strdup(prefix);
4059                                         gui_internal_widget_append(w, wbm);
4060                                 }
4061
4062                                 // save Waypoints in bookmark folder, if route exists
4063                                 if (navit_get_destination_count(this->nav) > 0){
4064                                         if (bookmarks_get_bookmark_count(mattr.u.bookmarks)==0){
4065                                                 wbm=gui_internal_button_new_with_callback(this, _("Save Waypoints"),
4066                                                                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
4067                                                                         gui_internal_cmd_replace_bookmarks_from_waypoints, NULL);
4068                                         }else{
4069                                                 wbm=gui_internal_button_new_with_callback(this, _("Replace Waypoints"),
4070                                                                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
4071                                                                         gui_internal_cmd_replace_bookmarks_from_waypoints, NULL);
4072                                         }
4073                                         wbm->prefix=g_strdup(prefix);
4074                                         gui_internal_widget_append(w, wbm);
4075                                 }
4076
4077                                 // delete empty folder
4078                                 if (bookmarks_get_bookmark_count(mattr.u.bookmarks)==0){
4079                                         gui_internal_widget_append(w,
4080                                                         wbm=gui_internal_button_new_with_callback(this, _("Delete Folder"),
4081                                                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
4082                                                         gui_internal_cmd_delete_bookmark_folder, NULL));
4083                                         wbm->prefix=g_strdup(prefix);
4084                                 }
4085
4086                         }
4087                 }
4088                 
4089                 // Adds the Bookmark folders
4090                 wbm=gui_internal_button_new_with_callback(this, _("Add Bookmark folder"),
4091                             image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
4092                                 gui_internal_cmd_add_bookmark_folder2, NULL);
4093                 gui_internal_widget_append(w, wbm);
4094
4095                 // Pastes the Bookmark
4096                 wbm=gui_internal_button_new_with_callback(this, _("Paste bookmark"),
4097                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
4098                                 gui_internal_cmd_paste_bookmark, NULL);
4099                 gui_internal_widget_append(w, wbm);
4100
4101                 bookmarks_item_rewind(mattr.u.bookmarks);
4102                                 
4103                 tbl=gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
4104                 gui_internal_widget_append(w,tbl);
4105
4106                 while ((item=bookmarks_get_item(mattr.u.bookmarks))) {
4107                         if (!item_attr_get(item, attr_label, &attr)) continue;
4108                         label_full=attr.u.str;
4109                         dbg(0,"full_labled: %s\n",label_full);
4110                         
4111                         // hassub == 1 if the item type is a sub-folder
4112                         if (item->type == type_bookmark_folder) {
4113                                 hassub=1;
4114                         } else {
4115                                 hassub=0;
4116                         }
4117                         
4118                         row=gui_internal_widget_table_row_new(this,gravity_left| flags_fill| orientation_horizontal);
4119                         gui_internal_widget_append(tbl, row);
4120                         wbm=gui_internal_button_new_with_callback(this, label_full,
4121                                 image_new_xs(this, hassub ? "gui_inactive" : "gui_active" ), gravity_left_center|orientation_horizontal|flags_fill,
4122                                         hassub ? gui_internal_cmd_bookmarks : gui_internal_cmd_position, NULL);
4123
4124                         gui_internal_widget_append(row,wbm);
4125                         if (item_coord_get(item, &c, 1)) {
4126                                 wbm->c.x=c.x;
4127                                 wbm->c.y=c.y;
4128                                 wbm->c.pro=bookmarks_get_projection(mattr.u.bookmarks);
4129                                 wbm->name=g_strdup_printf(_("Bookmark %s"),label_full);
4130                                 wbm->text=g_strdup(label_full);
4131                                 if (!hassub) {
4132                                         wbm->data=(void*)7;//Mark us as a bookmark
4133                                 }
4134                                 wbm->prefix=g_strdup(label_full);
4135                         } else {
4136                                 gui_internal_widget_destroy(this, row);
4137                         }
4138                 }
4139         }
4140
4141         g_free(prefix);
4142
4143         if (found)
4144                 gui_internal_check_exit(this);
4145         else
4146                 gui_internal_menu_render(this);
4147 }
4148
4149 static void
4150 gui_internal_cmd2_bookmarks(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
4151 {
4152         char *str=NULL;
4153         if (in && in[0] && ATTR_IS_STRING(in[0]->type)) {
4154                 str=in[0]->u.str;
4155         }
4156         gui_internal_cmd_bookmarks(this, NULL, str);
4157 }
4158
4159
4160 static void
4161 gui_internal_cmd_formerdests(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
4162 {
4163         struct widget *wb,*w,*wbm,*tbl=NULL;
4164         struct map *formerdests;
4165         struct map_rect *mr_formerdests;
4166         struct item *item;
4167         struct attr attr;
4168         char *label_full;
4169         enum projection projection;
4170
4171         gui_internal_prune_menu_count(this, 1, 0);
4172         wb=gui_internal_menu(this, _("Former Destinations"));
4173         wb->background=this->background;
4174
4175         w=gui_internal_box_new(this,
4176                         gravity_top_center|orientation_vertical|flags_expand|flags_fill);
4177         w->spy=this->spacing*2;
4178         gui_internal_widget_append(wb, w);
4179
4180         formerdests=read_former_destinations_from_file();
4181         mr_formerdests=map_rect_new(formerdests, NULL);
4182         projection = map_projection(formerdests);
4183         while ((item=map_rect_get_item(mr_formerdests))) {
4184                 struct coord c;
4185                 struct widget *row;
4186                 if (!item_attr_get(item, attr_label, &attr)) continue;
4187                 if(!tbl) {
4188                         tbl=gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand | orientation_vertical,1);
4189                         gui_internal_widget_append(w,tbl);
4190                 }
4191                 row=gui_internal_widget_table_row_new(this,gravity_left| flags_fill| orientation_vertical);
4192                 gui_internal_widget_prepend(tbl, row);
4193                 label_full=attr.u.str;
4194                 wbm=gui_internal_button_new_with_callback(this, label_full,
4195                                 image_new_xs(this, "gui_active"),
4196                                 gravity_left_center|orientation_horizontal|flags_fill,
4197                                 gui_internal_cmd_position, NULL);
4198                 gui_internal_widget_append(row,wbm);
4199                 if (item_coord_get(item, &c, 1)) {
4200                         wbm->c.x=c.x;
4201                         wbm->c.y=c.y;
4202                         wbm->c.pro=projection;
4203                         wbm->name=g_strdup(label_full);
4204                         wbm->text=g_strdup(label_full);
4205                         wbm->data=(void*)8; //Mark us as a former destination 
4206                         wbm->prefix=g_strdup(label_full);
4207                 }
4208         }
4209         if (!tbl){
4210                 wbm=gui_internal_text_new(this, _("- No former destinations available -"), 
4211                     gravity_left_center|orientation_horizontal|flags_fill);
4212                 gui_internal_widget_append(w, wbm);
4213         }
4214         gui_internal_menu_render(this);
4215         map_rect_destroy(mr_formerdests);
4216 }
4217
4218 static void
4219 gui_internal_keynav_highlight_next(struct gui_priv *this, int dx, int dy);
4220
4221 static void gui_internal_keypress_do(struct gui_priv *this, char *key)
4222 {
4223         struct widget *wi,*menu,*search_list;
4224         int len=0;
4225         char *text=NULL;
4226
4227         menu=g_list_last(this->root.children)->data;
4228         wi=gui_internal_find_widget(menu, NULL, STATE_EDIT);
4229         if (wi) {
4230                 /* select first item of the searchlist */
4231                 if (*key == NAVIT_KEY_RETURN && (search_list=gui_internal_menu_data(this)->search_list)) {
4232                         GList *l=search_list->children;
4233                         if (l && l->data)
4234                                 gui_internal_highlight_do(this, l->data);
4235                         return; 
4236                 } else if (*key == NAVIT_KEY_BACKSPACE) {
4237                         dbg(0,"backspace\n");
4238                         if (wi->text && wi->text[0]) {
4239                                 len=g_utf8_prev_char(wi->text+strlen(wi->text))-wi->text;
4240                                 wi->text[len]=' ';
4241                                 text=g_strdup_printf("%s ", wi->text);
4242                         }
4243                 } else {
4244                         if (wi->state & STATE_CLEAR) {
4245                                 dbg(0,"wi->state=0x%x\n", wi->state);
4246                                 g_free(wi->text);
4247                                 wi->text=NULL;
4248                                 wi->state &= ~STATE_CLEAR;
4249                                 dbg(0,"wi->state=0x%x\n", wi->state);
4250                         }
4251                         text=g_strdup_printf("%s%s", wi->text ? wi->text : "", key);
4252                 }
4253                 g_free(wi->text);
4254                 wi->text=text;
4255                 if (*key == NAVIT_KEY_BACKSPACE && wi->text) {
4256                         gui_internal_widget_render(this, wi);
4257                         wi->text[len]='\0';
4258                 }
4259                 if (wi->func) {
4260                         wi->reason=2;
4261                         wi->func(this, wi, wi->data);
4262                 }
4263                 gui_internal_widget_render(this, wi);
4264         }
4265 }
4266
4267
4268 static void
4269 gui_internal_cmd_keypress(struct gui_priv *this, struct widget *wm, void *data)
4270 {
4271         struct menu_data *md=gui_internal_menu_data(this);
4272         gui_internal_keypress_do(this, (char *) wm->data);
4273         // Switch to lowercase after the first key is pressed
4274         if (md->keyboard_mode == 2) // Latin
4275                 gui_internal_keyboard_do(this, md->keyboard, 10);
4276         if (md->keyboard_mode == 26) // Umlaut
4277                 gui_internal_keyboard_do(this, md->keyboard, 34);
4278         if ((md->keyboard_mode & ~7) == 40) // Russian/Ukrainian/Belorussian
4279                 gui_internal_keyboard_do(this, md->keyboard, 48);
4280 }
4281
4282 static void
4283 gui_internal_search_idle_end(struct gui_priv *this)
4284 {
4285         if (this->idle) {
4286                 event_remove_idle(this->idle);
4287                 this->idle=NULL;
4288         }
4289         if (this->idle_cb) {
4290                 callback_destroy(this->idle_cb);
4291                 this->idle_cb=NULL;
4292         }
4293 }
4294
4295 static char *
4296 postal_str(struct search_list_result *res, int level)
4297 {
4298         char *ret=NULL;
4299         if (res->town->common.postal)
4300                 ret=res->town->common.postal;
4301         if (res->town->common.postal_mask)
4302                 ret=res->town->common.postal_mask;
4303         if (level == 1)
4304                 return ret;
4305         if (res->street->common.postal)
4306                 ret=res->street->common.postal;
4307         if (res->street->common.postal_mask)
4308                 ret=res->street->common.postal_mask;
4309         if (level == 2)
4310                 return ret;
4311         if (res->house_number->common.postal)
4312                 ret=res->house_number->common.postal;
4313         if (res->house_number->common.postal_mask)
4314                 ret=res->house_number->common.postal_mask;
4315         return ret;
4316 }
4317
4318 static char *
4319 district_str(struct search_list_result *res, int level)
4320 {
4321         char *ret=NULL;
4322         if (res->town->common.district_name)
4323                 ret=res->town->common.district_name;
4324         if (level == 1)
4325                 return ret;
4326         if (res->street->common.district_name)
4327                 ret=res->street->common.district_name;
4328         if (level == 2)
4329                 return ret;
4330         if (res->house_number->common.district_name)
4331                 ret=res->house_number->common.district_name;
4332         return ret;
4333 }
4334
4335 static char *
4336 town_str(struct search_list_result *res, int level, int flags)
4337 {
4338         char *town=res->town->common.town_name;
4339         char *district=district_str(res, level);
4340         char *postal=postal_str(res, level);
4341         char *postal_sep=" ";
4342         char *district_begin=" (";
4343         char *district_end=")";
4344         char *county_sep = ", Co. ";
4345         char *county = res->town->common.county_name;
4346         if (!postal)
4347                 postal_sep=postal="";
4348         if (!district || (flags & 1))
4349                 district_begin=district_end=district="";
4350         if (!county)
4351                 county_sep=county="";
4352
4353         return g_strdup_printf("%s%s%s%s%s%s%s%s", postal, postal_sep, town, district_begin, district, district_end, county_sep, county);
4354 }
4355
4356 static int gui_internal_search_cmp(gconstpointer _a, gconstpointer _b)
4357 {
4358   struct widget *a=(struct widget *)_a, *b=(struct widget *)_b;
4359   char *sa,*sb;
4360   int r;
4361   if(!b)
4362   if((!a || a->type!=widget_table_row || !a->text) && (!b || b->type!=widget_table_row || !b->text))
4363         return 0;
4364   if(!a || a->type!=widget_table_row || !a->text)
4365         return -1;
4366   if(!b || b->type!=widget_table_row || !b->text)
4367         return 1;
4368   r=a->datai-b->datai;
4369   if(r<0)
4370         return -1;
4371   if(r>0)
4372         return 1;
4373   sa=removecase(a->text);
4374   sb=removecase(b->text);
4375   r=strcmp(sa,sb);
4376   g_free(sa);
4377   g_free(sb);
4378   return r;
4379 }
4380
4381 static void
4382 gui_internal_search_idle(struct gui_priv *this, char *wm_name, struct widget *search_list, void *param)
4383 {
4384         char *text=NULL,*text2=NULL,*name=NULL;
4385         struct search_list_result *res;
4386         struct widget *wc;
4387         struct item *item=NULL;
4388         GList *l;
4389         static char possible_keys[256]="";
4390         struct widget *wi=NULL;
4391
4392         res=search_list_get_result(this->sl);
4393         if (res) {
4394                 gchar* trunk_name = NULL;
4395
4396                 struct widget *menu=g_list_last(this->root.children)->data;
4397                 wi=gui_internal_find_widget(menu, NULL, STATE_EDIT);
4398
4399                 if (wi) {
4400                         if (! strcmp(wm_name,"Town"))
4401                                 trunk_name = g_strrstr(res->town->common.town_name, wi->text);
4402                         if (! strcmp(wm_name,"Street"))
4403                         {
4404                                 name=res->street->name;
4405                                 if (name)
4406                                         trunk_name = g_strrstr(name, wi->text);
4407                                 else
4408                                         trunk_name = NULL;
4409                         }
4410
4411                         if (trunk_name) {
4412                                 char next_char = trunk_name[strlen(wi->text)];
4413                                 int i;
4414                                 int len = strlen(possible_keys);
4415                                 for(i = 0; (i<len) && (possible_keys[i] != next_char) ;i++) ;
4416                                 if (i==len || !len) {
4417                                         possible_keys[len]=trunk_name[strlen(wi->text)];
4418                                         possible_keys[len+1]='\0';
4419                                 }
4420                                 dbg(1,"%s %s possible_keys:%s \n", wi->text, res->town->common.town_name, possible_keys);
4421                         }
4422                 } else {
4423                         dbg(0, "Unable to find widget");
4424                 }
4425         }
4426
4427         if (! res) {
4428                 struct menu_data *md;
4429                 gui_internal_search_idle_end(this);
4430
4431                 md=gui_internal_menu_data(this);
4432                 if (md && md->keyboard && !(this->flags & 2048)) {
4433                         GList *lk=md->keyboard->children;
4434                         graphics_draw_mode(this->gra, draw_mode_begin);
4435                         while (lk) {
4436                                 struct widget *child=lk->data;
4437                                 GList *lk2=child->children;
4438                                 while (lk2) {
4439                                         struct widget *child_=lk2->data;
4440                                         lk2=g_list_next(lk2);
4441                                         if (child_->data && strcmp("\b", child_->data)) { // FIXME don't disable special keys
4442                                                 if (strlen(possible_keys) == 0)
4443                                                         child_->state|= STATE_HIGHLIGHTED|STATE_VISIBLE|STATE_SENSITIVE|STATE_CLEAR ;
4444                                                 else if (g_strrstr(possible_keys, child_->data)!=NULL ) {
4445                                                         child_->state|= STATE_HIGHLIGHTED|STATE_VISIBLE|STATE_SENSITIVE|STATE_CLEAR ;
4446                                                 } else {
4447                                                         child_->state&= ~(STATE_HIGHLIGHTED|STATE_VISIBLE|STATE_SELECTED) ;
4448                                                 }
4449                                                 gui_internal_widget_render(this,child_);
4450                                         }
4451                                 }
4452                                 lk=g_list_next(lk);
4453                         }
4454                         gui_internal_widget_render(this,md->keyboard);
4455                         graphics_draw_mode(this->gra, draw_mode_end);
4456                 }
4457
4458                 possible_keys[0]='\0';
4459                 return;
4460         }
4461
4462         if (! strcmp(wm_name,"Country")) {
4463                 name=res->country->name;
4464                 item=&res->country->common.item;
4465                 text=g_strdup_printf("%s", res->country->name);
4466         }
4467         if (! strcmp(wm_name,"Town")) {
4468                 item=&res->town->common.item;
4469                 name=res->town->common.town_name;
4470                 text=town_str(res, 1, 0);
4471         }
4472         if (! strcmp(wm_name,"Street")) {
4473                 name=res->street->name;
4474                 item=&res->street->common.item;
4475                 text=g_strdup(res->street->name);
4476                 text2=town_str(res, 2, 1);
4477         }
4478         if (! strcmp(wm_name,"House number")) {
4479                 name=res->house_number->house_number;
4480                 text=g_strdup_printf("%s %s", res->street->name, name);
4481                 text2=town_str(res, 3, 0);
4482         }
4483         dbg(1,"res->country->flag=%s\n", res->country->flag);
4484         struct widget *wr;
4485         wr=gui_internal_widget_table_row_new(this, gravity_left|orientation_horizontal|flags_fill);
4486
4487                 if (!text2) {
4488                         wr->text=g_strdup(text);
4489                         gui_internal_widget_insert_sorted(search_list, wr, gui_internal_search_cmp);
4490                         gui_internal_widget_append(wr,
4491                                 wc=gui_internal_button_new_with_callback(this, text,
4492                                         image_new_xs(this, res->country->flag),
4493                                         gravity_left_center|orientation_horizontal|flags_fill,
4494                                         gui_internal_cmd_position, param));
4495                 } else {
4496                         struct widget *wb;
4497                         wr->text=g_strdup_printf("%s %s",text,text2);
4498
4499                         if (! strcmp(wm_name,"House number") && !res->street->name) {
4500                                 wr->datai=1000;
4501                         } else if(name) {
4502                                 if(!wi)
4503                                         dbg(0,"search text widget is NULL\n");
4504                                 if(wi && strlen(name)==strlen(wi->text)) {
4505                                         dbg(1,"xact %s %s\n",name, wi->text);
4506                                         wr->datai=-1000;
4507                                 } else {
4508                                         dbg(1,"not xact %s %s\n",name, wi->text);
4509                                         wr->datai=0;
4510                                 }
4511                         }
4512                         gui_internal_widget_insert_sorted(search_list, wr, gui_internal_search_cmp);
4513                         
4514                         wc=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
4515                         gui_internal_widget_append(wr, wc);
4516                         gui_internal_widget_append(wc, gui_internal_image_new(this, image_new_xs(this, res->country->flag)));
4517                         wb=gui_internal_box_new(this, gravity_left_center|orientation_vertical|flags_fill);
4518                         gui_internal_widget_append(wc, wb);
4519                         gui_internal_widget_append(wb, gui_internal_label_new(this, text));
4520                         gui_internal_widget_append(wb, gui_internal_label_font_new(this, text2, 1));
4521                         wc->func=gui_internal_cmd_position;
4522                         wc->data=param;
4523                         wc->state |= STATE_SENSITIVE;
4524                         wc->speech=g_strdup(text);
4525                 }
4526                 wc->name=g_strdup(name);
4527                 if (res->c)
4528                         wc->c=*res->c;
4529                 wc->selection_id=res->id;
4530                 if (item)
4531                         wc->item=*item;
4532                 gui_internal_widget_pack(this, search_list);
4533                 l=g_list_last(this->root.children);
4534                 graphics_draw_mode(this->gra, draw_mode_begin);
4535                 gui_internal_widget_render(this, l->data);
4536                 graphics_draw_mode(this->gra, draw_mode_end);
4537         g_free(text);
4538         g_free(text2);
4539 }
4540
4541 static void
4542 gui_internal_search_idle_start(struct gui_priv *this, char *wm_name, struct widget *search_list, void *param)
4543 {
4544         this->idle_cb=callback_new_4(callback_cast(gui_internal_search_idle), this, wm_name, search_list, param);
4545         this->idle=event_add_idle(50,this->idle_cb);
4546         callback_call_0(this->idle_cb);
4547 }
4548
4549
4550 /**
4551  *
4552  * @param wm The widget that generated the event for the search changed,
4553  *        if this was generated by a key on the virtual keyboard then
4554  *        wm is the key button widget.
4555  */
4556 static void
4557 gui_internal_search_changed(struct gui_priv *this, struct widget *wm, void *data)
4558 {
4559         GList *l;
4560         struct widget *search_list=gui_internal_menu_data(this)->search_list;
4561         void *param=(void *)3;
4562         int minlen=1;
4563
4564         gui_internal_widget_table_clear(this, search_list);
4565
4566         if (! strcmp(wm->name,"Country"))
4567                 param=(void *)4;
4568         if (! strcmp(wm->name,"Street"))
4569                 param=(void *)5;
4570         if (! strcmp(wm->name,"House number"))
4571                 param=(void *)6;
4572         dbg(0,"%s now '%s'\n", wm->name, wm->text);
4573
4574         gui_internal_search_idle_end(this);
4575         if (wm->text && g_utf8_strlen(wm->text, -1) >= minlen) {
4576                 struct attr search_attr;
4577
4578                 dbg(0,"process\n");
4579                 if (! strcmp(wm->name,"Country"))
4580                         search_attr.type=attr_country_all;
4581                 if (! strcmp(wm->name,"Town"))
4582                         search_attr.type=attr_town_or_district_name;
4583                 if (! strcmp(wm->name,"Street"))
4584                         search_attr.type=attr_street_name;
4585                 if (! strcmp(wm->name,"House number"))
4586                         search_attr.type=attr_house_number;
4587                 search_attr.u.str=wm->text;
4588                 search_list_search(this->sl, &search_attr, 1);
4589                 gui_internal_search_idle_start(this, wm->name, search_list, param);
4590         }
4591         l=g_list_last(this->root.children);
4592         gui_internal_widget_render(this, l->data);
4593 }
4594
4595 static struct widget *
4596 gui_internal_keyboard_key_data(struct gui_priv *this, struct widget *wkbd, char *text, int font, void(*func)(struct gui_priv *priv, struct widget *widget, void *data), void *data, void (*data_free)(void *data), int w, int h)
4597 {
4598         struct widget *wk;
4599         gui_internal_widget_append(wkbd, wk=gui_internal_button_font_new_with_callback(this, text, font,
4600                 NULL, gravity_center|orientation_vertical, func, data));
4601         wk->data_free=data_free;
4602         wk->background=this->background;
4603         wk->bl=0;
4604         wk->br=0;
4605         wk->bt=0;
4606         wk->bb=0;
4607         wk->w=w;
4608         wk->h=h;
4609         return wk;
4610 }
4611
4612 static struct widget *
4613 gui_internal_keyboard_key(struct gui_priv *this, struct widget *wkbd, char *text, char *key, int w, int h)
4614 {
4615         return gui_internal_keyboard_key_data(this, wkbd, text, 0, gui_internal_cmd_keypress, g_strdup(key), g_free_func,w,h);
4616 }
4617
4618 static void gui_internal_keyboard_change(struct gui_priv *this, struct widget *key, void *data);
4619
4620
4621 // A list of availiable keyboard modes.
4622 struct gui_internal_keyb_mode {
4623     char title[16]; // Label to be displayed on keys that switch to it
4624     int font; // Font size of label
4625     int case_mode; // Mode to switch to when case CHANGE() key is pressed.
4626     int umlaut_mode;  // Mode to switch to when UMLAUT() key is pressed.
4627 } gui_internal_keyb_modes[]= {
4628         /* 0*/ {"ABC", 2,  8, 24},
4629         /* 8*/ {"abc", 2,  0, 32},
4630         /*16*/ {"123", 2,  0, 24},
4631         /*24*/ {"ÄÖÜ", 2, 40, 0},
4632         /*32*/ {"äöü", 2, 32, 8},
4633         /*40*/ {"АБВ", 2, 48,  0},
4634         /*48*/ {"абв", 2, 40,  8}
4635 };
4636
4637
4638 // Some macros that make the keyboard layout easier to visualise in
4639 // the source code. The macros are #undef'd after this function.
4640 #define KEY(x) gui_internal_keyboard_key(this, wkbd, (x), (x), max_w, max_h)
4641 #define SPACER() gui_internal_keyboard_key_data(this, wkbd, "", 0, NULL, NULL, NULL,max_w,max_h)
4642 #define MODE(x) gui_internal_keyboard_key_data(this, wkbd, \
4643                 gui_internal_keyb_modes[(x)/8].title, \
4644                 gui_internal_keyb_modes[(x)/8].font, \
4645                 gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h) \
4646                         -> datai=(mode&7)+((x)&~7)
4647 #define SWCASE() MODE(gui_internal_keyb_modes[mode/8].case_mode)
4648 #define UMLAUT() MODE(gui_internal_keyb_modes[mode/8].umlaut_mode)
4649 static struct widget *
4650 gui_internal_keyboard_do(struct gui_priv *this, struct widget *wkbdb, int mode)
4651 {
4652         struct widget *wkbd,*wk;
4653         struct menu_data *md=gui_internal_menu_data(this);
4654         int i, max_w=this->root.w, max_h=this->root.h;
4655         int render=0;
4656         char *space="_";
4657         char *backspace="←";
4658         char *hide="▼";
4659         char *unhide="▲";
4660
4661         if (wkbdb) {
4662                 this->current.x=-1;
4663                 this->current.y=-1;
4664                 gui_internal_highlight(this);
4665                 if (md->keyboard_mode >= 1024)
4666                         render=2;
4667                 else
4668                         render=1;
4669                 gui_internal_widget_children_destroy(this, wkbdb);
4670         } else
4671                 wkbdb=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_fill);
4672         md->keyboard=wkbdb;
4673         md->keyboard_mode=mode;
4674         wkbd=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_fill);
4675         wkbd->background=this->background;
4676         wkbd->cols=8;
4677         wkbd->spx=0;
4678         wkbd->spy=0;
4679         max_w=max_w/8;
4680         max_h=max_h/8; // Allows 3 results in the list when searching for Towns
4681         wkbd->p.y=max_h*2;
4682         if(mode>=40&&mode<56) { // Russian/Ukrainian/Belarussian layout needs more space...
4683                 max_h=max_h*4/5;
4684                 max_w=max_w*8/9;
4685                 wkbd->cols=9;
4686         }
4687
4688         if (mode >= 0 && mode < 8) {
4689                 for (i = 0 ; i < 26 ; i++) {
4690                         char text[]={'A'+i,'\0'};
4691                         KEY(text);
4692                 }
4693                 gui_internal_keyboard_key(this, wkbd, space," ",max_w,max_h);
4694                 if (mode == 0) {
4695                         KEY("-");
4696                         KEY("'");
4697                         wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4698                         wk->datai=mode+1024;
4699                 } else {
4700                         wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4701                         wk->datai=mode+1024;
4702                         SWCASE();
4703                         MODE(16);
4704                         
4705                 }
4706                 UMLAUT();
4707                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4708         }
4709         if (mode >= 8 && mode < 16) {
4710                 for (i = 0 ; i < 26 ; i++) {
4711                         char text[]={'a'+i,'\0'};
4712                         KEY(text);
4713                 }
4714                 gui_internal_keyboard_key(this, wkbd, space," ",max_w,max_h);
4715                 if (mode == 8) {
4716                         KEY("-");
4717                         KEY("'");
4718                         wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4719                         wk->datai=mode+1024;
4720                 } else {
4721                         wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4722                         wk->datai=mode+1024;
4723                         SWCASE();
4724                         
4725                         MODE(16);
4726                 }
4727                 UMLAUT();
4728                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4729         }
4730         if (mode >= 16 && mode < 24) {
4731                 for (i = 0 ; i < 10 ; i++) {
4732                         char text[]={'0'+i,'\0'};
4733                         KEY(text);
4734                 }
4735                 KEY("."); KEY("°"); KEY("'"); KEY("\""); KEY("-"); KEY("+");
4736                 KEY("*"); KEY("/"); KEY("("); KEY(")"); KEY("="); KEY("?");
4737
4738                 
4739
4740                 if (mode == 16) {
4741                         for (i = 0 ; i < 5 ; i++) SPACER();
4742                         KEY("-");
4743                         KEY("'");
4744                         wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4745                         wk->datai=mode+1024;
4746                 } else {
4747                         for (i = 0 ; i < 3 ; i++) SPACER();
4748                         MODE(40);
4749                         MODE(48);
4750                         wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4751                         wk->datai=mode+1024;
4752                         MODE(0);
4753                         MODE(8);
4754                 }
4755                 UMLAUT();
4756                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4757         }
4758         if (mode >= 24 && mode < 32) {
4759                 KEY("Ä"); KEY("Ë"); KEY("Ï"); KEY("Ö"); KEY("Ü"); KEY("Æ"); KEY("Ø"); KEY("Å");
4760                 KEY("Á"); KEY("É"); KEY("Í"); KEY("Ó"); KEY("Ú"); KEY("Š"); KEY("Č"); KEY("Ž");
4761                 KEY("À"); KEY("È"); KEY("Ì"); KEY("Ò"); KEY("Ù"); KEY("Ś"); KEY("Ć"); KEY("Ź");
4762                 KEY("Â"); KEY("Ê"); KEY("Î"); KEY("Ô"); KEY("Û"); SPACER();
4763
4764                 UMLAUT();
4765
4766                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4767         }
4768         if (mode >= 32 && mode < 40) {
4769                 KEY("ä"); KEY("ë"); KEY("ï"); KEY("ö"); KEY("ü"); KEY("æ"); KEY("ø"); KEY("å");
4770                 KEY("á"); KEY("é"); KEY("í"); KEY("ó"); KEY("ú"); KEY("š"); KEY("č"); KEY("ž");
4771                 KEY("à"); KEY("è"); KEY("ì"); KEY("ò"); KEY("ù"); KEY("ś"); KEY("ć"); KEY("ź");
4772                 KEY("â"); KEY("ê"); KEY("î"); KEY("ô"); KEY("û"); KEY("ß");
4773
4774                 UMLAUT();
4775
4776                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4777         }
4778         if (mode >= 40 && mode < 48) {
4779                 KEY("А"); KEY("Б"); KEY("В"); KEY("Г"); KEY("Д"); KEY("Е"); KEY("Ж"); KEY("З"); KEY("И");
4780                 KEY("Й"); KEY("К"); KEY("Л"); KEY("М"); KEY("Н"); KEY("О"); KEY("П"); KEY("Р"); KEY("С");
4781                 KEY("Т"); KEY("У"); KEY("Ф"); KEY("Х"); KEY("Ц"); KEY("Ч"); KEY("Ш"); KEY("Щ"); KEY("Ъ"); 
4782                 KEY("Ы"); KEY("Ь"); KEY("Э"); KEY("Ю"); KEY("Я"); KEY("Ё"); KEY("І"); KEY("Ї"); KEY("Ў");
4783                 SPACER(); SPACER(); SPACER();
4784                 gui_internal_keyboard_key(this, wkbd, space," ",max_w,max_h);
4785
4786                 wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4787                 wk->datai=mode+1024;
4788
4789                 SWCASE();
4790
4791                 MODE(16);
4792
4793                 SPACER();
4794
4795                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4796         }
4797         if (mode >= 48 && mode < 56) {
4798                 KEY("а"); KEY("б"); KEY("в"); KEY("г"); KEY("д"); KEY("е"); KEY("ж"); KEY("з"); KEY("и");
4799                 KEY("й"); KEY("к"); KEY("л"); KEY("м"); KEY("н"); KEY("о"); KEY("п"); KEY("р"); KEY("с");
4800                 KEY("т"); KEY("у"); KEY("ф"); KEY("х"); KEY("ц"); KEY("ч"); KEY("ш"); KEY("щ"); KEY("ъ");
4801                 KEY("ы"); KEY("ь"); KEY("э"); KEY("ю"); KEY("я"); KEY("ё"); KEY("і"); KEY("ї"); KEY("ў");
4802                 SPACER(); SPACER(); SPACER();
4803                 gui_internal_keyboard_key(this, wkbd, space," ",max_w,max_h);
4804                 
4805                 wk=gui_internal_keyboard_key_data(this, wkbd, hide, 0, gui_internal_keyboard_change, wkbdb, NULL,max_w,max_h);
4806                 wk->datai=mode+1024;
4807
4808                 SWCASE();
4809
4810                 MODE(16);
4811
4812                 SPACER();
4813
4814                 gui_internal_keyboard_key(this, wkbd, backspace,"\b",max_w,max_h);
4815         }
4816
4817
4818         if(md->search_list && md->search_list->type==widget_table) {
4819                 struct table_data *td=(struct table_data*)(md->search_list->data);
4820                 td->button_box_hide=mode<1024;
4821         }
4822         
4823         if (mode >= 1024) {
4824                 char *text=NULL;
4825                 int font=0;
4826                 struct widget *wkl;
4827                 mode -= 1024;
4828                 text=gui_internal_keyb_modes[mode/8].title;
4829                 font=gui_internal_keyb_modes[mode/8].font;
4830                 wk=gui_internal_box_new(this, gravity_center|orientation_horizontal|flags_fill);
4831                 wk->func=gui_internal_keyboard_change;
4832                 wk->data=wkbdb;
4833                 wk->background=this->background;
4834                 wk->bl=0;
4835                 wk->br=0;
4836                 wk->bt=0;
4837                 wk->bb=0;
4838                 wk->w=max_w;
4839                 wk->h=max_h;
4840                 wk->datai=mode;
4841                 wk->state |= STATE_SENSITIVE;
4842                 gui_internal_widget_append(wk, wkl=gui_internal_label_new(this, unhide));
4843                 wkl->background=NULL;
4844                 gui_internal_widget_append(wk, wkl=gui_internal_label_font_new(this, text, font));
4845                 wkl->background=NULL;
4846                 gui_internal_widget_append(wkbd, wk);
4847                 if (render)
4848                         render=2;
4849         }
4850         gui_internal_widget_append(wkbdb, wkbd);
4851         if (render == 1) {
4852                 gui_internal_widget_pack(this, wkbdb);
4853                 gui_internal_widget_render(this, wkbdb);
4854         } else if (render == 2) {
4855                 gui_internal_menu_reset_pack(this);
4856                 gui_internal_menu_render(this);
4857         }
4858         return wkbdb;
4859 }
4860 #undef KEY
4861 #undef SPACER
4862 #undef SWCASE
4863 #undef UMLAUT
4864 #undef MODE
4865
4866 static struct widget *
4867 gui_internal_keyboard(struct gui_priv *this, int mode)
4868 {
4869         if (! this->keyboard)
4870                 return NULL;
4871         return gui_internal_keyboard_do(this, NULL, mode);
4872 }
4873
4874 static void
4875 gui_internal_keyboard_change(struct gui_priv *this, struct widget *key, void *data)
4876 {
4877         gui_internal_keyboard_do(this, key->data, key->datai);
4878 }
4879
4880 static void
4881 gui_internal_search_list_set_default_country(struct gui_priv *this)
4882 {
4883         struct attr search_attr, country_name, country_iso2, *country_attr;
4884         struct item *item;
4885         struct country_search *cs;
4886         struct tracking *tracking;
4887         struct search_list_result *res;
4888
4889         country_attr=country_default();
4890         tracking=navit_get_tracking(this->nav);
4891         if (tracking && tracking_get_attr(tracking, attr_country_id, &search_attr, NULL))
4892                 country_attr=&search_attr;
4893         if (country_attr) {
4894                 cs=country_search_new(country_attr, 0);
4895                 item=country_search_get_item(cs);
4896                 if (item && item_attr_get(item, attr_country_name, &country_name)) {
4897                         search_attr.type=attr_country_all;
4898                         dbg(0,"country %s\n", country_name.u.str);
4899                         search_attr.u.str=country_name.u.str;
4900                         search_list_search(this->sl, &search_attr, 0);
4901                         while((res=search_list_get_result(this->sl)));
4902                         if(this->country_iso2) {
4903                                 g_free(this->country_iso2);
4904                                 this->country_iso2=NULL;
4905                         }
4906                         if (item_attr_get(item, attr_country_iso2, &country_iso2))
4907                                 this->country_iso2=g_strdup(country_iso2.u.str);
4908                 }
4909                 country_search_destroy(cs);
4910         } else {
4911                 dbg(0,"warning: no default country found\n");
4912                 if (this->country_iso2) {
4913                     dbg(0,"attempting to use country '%s'\n",this->country_iso2);
4914                     search_attr.type=attr_country_iso2;
4915                     search_attr.u.str=this->country_iso2;
4916             search_list_search(this->sl, &search_attr, 0);
4917             while((res=search_list_get_result(this->sl)));
4918                 }
4919         }
4920 }
4921
4922 static void
4923 gui_internal_search_list_new(struct gui_priv *this)
4924 {
4925         struct mapset *ms=navit_get_mapset(this->nav);
4926         if (! this->sl) {
4927                 this->sl=search_list_new(ms);
4928                 gui_internal_search_list_set_default_country(this);
4929         }
4930 }
4931
4932 static void
4933 gui_internal_search_list_destroy(struct gui_priv *this)
4934 {
4935         if (this->sl) {
4936                 search_list_destroy(this->sl);
4937                 this->sl=NULL;
4938         }
4939 }
4940
4941
4942 static void
4943 gui_internal_search(struct gui_priv *this, char *what, char *type, int flags)
4944 {
4945         struct widget *wb,*wk,*w,*wr,*we,*wl,*wnext=NULL;
4946         char *country;
4947         int keyboard_mode=2;
4948         gui_internal_search_list_new(this);
4949         wb=gui_internal_menu(this, what);
4950         w=gui_internal_box_new(this, gravity_center|orientation_vertical|flags_expand|flags_fill);
4951         gui_internal_widget_append(wb, w);
4952         wr=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
4953         gui_internal_widget_append(w, wr);
4954         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
4955         gui_internal_widget_append(wr, we);
4956         if (!strcmp(type,"Country")) {
4957                 wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_town"));
4958                 wnext->func=gui_internal_search_town;
4959         } else if (!strcmp(type,"Town")) {
4960                 if (this->country_iso2) {
4961 #if HAVE_API_ANDROID
4962                         char country_iso2[strlen(this->country_iso2)+1];
4963                         strtolower(country_iso2, this->country_iso2);
4964                         country=g_strdup_printf("country_%s", country_iso2);
4965 #else
4966                         country=g_strdup_printf("country_%s", this->country_iso2);
4967 #endif
4968                 } else
4969                         country=g_strdup("gui_select_country");
4970                 gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, country)));
4971                 wb->state |= STATE_SENSITIVE;
4972                 if (flags)
4973                         wb->func = gui_internal_search_country;
4974                 else
4975                         wb->func = gui_internal_back;
4976                 wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_street"));
4977                 wnext->func=gui_internal_search_street;
4978                 g_free(country);
4979         } else if (!strcmp(type,"Street")) {
4980                 gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_select_town")));
4981                 wb->state |= STATE_SENSITIVE;
4982                 wb->func = gui_internal_back;
4983                 wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_house_number"));
4984                 wnext->func=gui_internal_search_house_number;
4985         } else if (!strcmp(type,"House number")) {
4986                 gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_select_street")));
4987                 wb->state |= STATE_SENSITIVE;
4988                 wb->func = gui_internal_back;
4989                 keyboard_mode=18;
4990         }
4991         gui_internal_widget_append(we, wk=gui_internal_label_new(this, NULL));
4992         if (wnext) {
4993                 gui_internal_widget_append(we, wnext);
4994                 wnext->state |= STATE_SENSITIVE;
4995         }
4996         wl=gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);//gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
4997         gui_internal_widget_append(wr, wl);
4998         gui_internal_menu_data(this)->search_list=wl;
4999         wk->state |= STATE_EDIT|STATE_EDITABLE;
5000         wk->background=this->background;
5001         wk->flags |= flags_expand|flags_fill;
5002         wk->func = gui_internal_search_changed;
5003         wk->name=g_strdup(type);
5004         if (this->keyboard)
5005                 gui_internal_widget_append(w, gui_internal_keyboard(this,keyboard_mode));
5006         gui_internal_menu_render(this);
5007 }
5008
5009 static void
5010 gui_internal_search_house_number(struct gui_priv *this, struct widget *widget, void *data)
5011 {
5012         search_list_select(this->sl, attr_street_name, 0, 0);
5013         gui_internal_search(this,_("House number"),"House number",0);
5014 }
5015
5016 static void
5017 gui_internal_search_house_number_in_street(struct gui_priv *this, struct widget *widget, void *data)
5018 {
5019         dbg(0,"id %d\n", widget->selection_id);
5020         search_list_select(this->sl, attr_street_name, 0, 0);
5021         search_list_select(this->sl, attr_street_name, widget->selection_id, 1);
5022         gui_internal_search(this,_("House number"),"House number",0);
5023 }
5024
5025 static void
5026 gui_internal_search_street(struct gui_priv *this, struct widget *widget, void *data)
5027 {
5028         search_list_select(this->sl, attr_town_or_district_name, 0, 0);
5029         gui_internal_search(this,_("Street"),"Street",0);
5030 }
5031
5032 static void
5033 gui_internal_search_street_in_town(struct gui_priv *this, struct widget *widget, void *data)
5034 {
5035         dbg(0,"id %d\n", widget->selection_id);
5036         search_list_select(this->sl, attr_town_or_district_name, 0, 0);
5037         search_list_select(this->sl, attr_town_or_district_name, widget->selection_id, 1);
5038         gui_internal_search(this,_("Street"),"Street",0);
5039 }
5040
5041 static void
5042 gui_internal_search_town(struct gui_priv *this, struct widget *wm, void *data)
5043 {
5044         if (this->sl)
5045                 search_list_select(this->sl, attr_country_all, 0, 0);
5046         g_free(this->country_iso2);
5047         this->country_iso2=NULL;
5048         gui_internal_search(this,_("Town"),"Town",0);
5049 }
5050
5051 static void
5052 gui_internal_search_town_in_country(struct gui_priv *this, struct widget *widget)
5053 {
5054         struct search_list_common *slc;
5055         dbg(0,"id %d\n", widget->selection_id);
5056         search_list_select(this->sl, attr_country_all, 0, 0);
5057         slc=search_list_select(this->sl, attr_country_all, widget->selection_id, 1);
5058         if (slc) {
5059                 g_free(this->country_iso2);
5060                 this->country_iso2=g_strdup(((struct search_list_country *)slc)->iso2);
5061         }
5062         gui_internal_search(this,widget->name,"Town",0);
5063 }
5064
5065 static void
5066 gui_internal_search_country(struct gui_priv *this, struct widget *widget, void *data)
5067 {
5068         gui_internal_prune_menu_count(this, 1, 0);
5069         gui_internal_search(this,_("Country"),"Country",0);
5070 }
5071
5072 static void
5073 gui_internal_cmd2_town(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5074 {
5075         if (this->sl)
5076                 search_list_select(this->sl, attr_country_all, 0, 0);
5077         gui_internal_search(this,_("Town"),"Town",1);
5078 }
5079
5080 static void
5081 gui_internal_cmd2_setting_layout(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5082 {
5083         struct attr attr;
5084         struct widget *w,*wb,*wl,*row;
5085         struct attr_iter *iter;
5086
5087
5088         wb=gui_internal_menu(this, _("Layout"));
5089         w=gui_internal_widget_table_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill,1);
5090         gui_internal_widget_append(wb, w);
5091         iter=navit_attr_iter_new();
5092         while(navit_get_attr(this->nav, attr_layout, &attr, iter)) {
5093                 gui_internal_widget_append(w, row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
5094                 wl=gui_internal_button_navit_attr_new(this, attr.u.layout->name, gravity_left_center|orientation_horizontal|flags_fill,
5095                         &attr, NULL);
5096                 gui_internal_widget_append(row, wl);
5097         }
5098         navit_attr_iter_destroy(iter);
5099         gui_internal_menu_render(this);
5100 }
5101
5102 static char *
5103 gui_internal_cmd_match_expand(char *pattern, struct attr **in)
5104 {
5105         char p,*ret=g_strdup(pattern),*r=ret,*a;
5106         int len;
5107         while ((p=*pattern++)) {
5108                 switch (p) {
5109                 case '*':
5110                         *r='\0';
5111                         a=attr_to_text(*in++,NULL,0);
5112                         len=strlen(ret)+strlen(a)+strlen(pattern)+1;
5113                         r=g_malloc(len);
5114                         strcpy(r, ret);
5115                         strcat(r, a);
5116                         g_free(ret);
5117                         g_free(a);
5118                         ret=r;
5119                         r=ret+strlen(ret);
5120                         break;
5121                 case '\\':
5122                         p=*pattern++;
5123                 default:
5124                         *r++=p;
5125                 }       
5126         }
5127         *r++='\0';
5128         return ret;
5129 }
5130
5131 static int 
5132 gui_internal_match(const char *pattern, const char *string)
5133 {
5134         char p,s;
5135         while ((p=*pattern++)) {
5136                 switch (p) {
5137                 case '*':
5138                         while ((s=*string)) {
5139                                 if (gui_internal_match(pattern,string))
5140                                         return 1;
5141                                 string++;
5142                         }
5143                         break;
5144                 case '\\':
5145                         p=*pattern++;
5146                 default:
5147                         if (*string++ != p)
5148                                 return 0;
5149                 }
5150         }
5151         return 1;
5152 }
5153
5154 static int
5155 gui_internal_set(char *remove, char *add)
5156 {
5157         char *gui_file=g_strjoin(NULL, navit_get_user_data_directory(TRUE), "/gui_internal.txt", NULL);
5158         char *gui_file_new=g_strjoin(NULL, navit_get_user_data_directory(TRUE), "/gui_internal_new.txt", NULL);
5159         FILE *fo=fopen(gui_file_new,"w");
5160         FILE *fi=fopen(gui_file,"r");
5161         char *line=NULL;
5162         int ret;
5163         size_t size=0;
5164         if (fi != NULL){
5165                 while (getline(&line,&size,fi) > 0) {
5166                         int len=strlen(line);
5167                         if (len > 0 && line[len-1] == '\n')
5168                                 line[len-1]='\0';
5169                         dbg(1,"line=%s\n",line);
5170                         if (!gui_internal_match(remove, line))
5171                                 fprintf(fo,"%s\n",line);
5172                 }
5173                 if (line)
5174                         free(line);
5175                 fclose(fi);
5176         }
5177         fprintf(fo,"%s;\n",add);
5178         fclose(fo);
5179         ret=(rename(gui_file_new, gui_file)==0);
5180         g_free(gui_file_new);
5181         g_free(gui_file);
5182
5183         return ret;
5184 }
5185
5186 static void
5187 gui_internal_cmd2_set(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5188 {
5189         char *pattern,*command=NULL;
5190         if (!in || !in[0] || !ATTR_IS_STRING(in[0]->type)) {
5191                 dbg(0,"first parameter missing or wrong type\n");
5192                 return;
5193         }
5194         pattern=in[0]->u.str;
5195         dbg(0,"pattern %s\n",pattern);
5196         if (in[1]) {
5197                 command=gui_internal_cmd_match_expand(pattern, in+1);
5198                 dbg(0,"expand %s\n",command);
5199                 gui_internal_set(pattern, command);
5200                 command_evaluate(&this->self, command);
5201                 g_free(command);
5202         }
5203
5204 }
5205
5206 static void
5207 gui_internal_cmd2_quit(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5208 {
5209         struct attr navit;
5210         gui_internal_prune_menu(this, NULL);
5211         navit.type=attr_navit;
5212         navit.u.navit=this->nav;
5213         config_remove_attr(config, &navit);
5214         gui_internal_destroy(this);
5215         event_main_loop_quit();
5216 }
5217
5218 static void
5219 gui_internal_window_closed(struct gui_priv *this)
5220 {
5221         gui_internal_cmd2_quit(this, NULL, NULL, NULL, NULL);
5222 }
5223
5224 static void
5225 gui_internal_cmd2_abort_navigation(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5226 {
5227         navit_set_destination(this->nav, NULL, NULL, 0);
5228 }
5229
5230 static void
5231 gui_internal_cmd_map_download_do(struct gui_priv *this, struct widget *wm, void *data)
5232 {
5233         char *text=g_strdup_printf(_("Download %s"),wm->name);
5234         struct widget *w, *wb;
5235         struct map *map=data;
5236         double bllon,bllat,trlon,trlat;
5237
5238         wb=gui_internal_menu(this, text);
5239         g_free(text);
5240         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5241         w->spy=this->spacing*3;
5242         gui_internal_widget_append(wb, w);
5243         if (sscanf(wm->prefix,"%lf,%lf,%lf,%lf",&bllon,&bllat,&trlon,&trlat) == 4) {
5244                 struct coord_geo g;
5245                 struct map_selection sel;
5246                 struct map_rect *mr;
5247                 struct item *item;
5248
5249                 sel.next=NULL;
5250                 sel.order=255;
5251                 g.lng=bllon;
5252                 g.lat=trlat;
5253                 transform_from_geo(projection_mg, &g, &sel.u.c_rect.lu);
5254                 g.lng=trlon;
5255                 g.lat=bllat;
5256                 transform_from_geo(projection_mg, &g, &sel.u.c_rect.rl);
5257                 sel.range.min=type_none;
5258                 sel.range.max=type_last;
5259                 mr=map_rect_new(map, &sel);
5260                 while ((item=map_rect_get_item(mr))) {
5261                         dbg(0,"item\n");
5262                 }
5263                 map_rect_destroy(mr);
5264         }
5265         
5266         dbg(0,"bbox=%s\n",wm->prefix);
5267         gui_internal_menu_render(this);
5268 }
5269
5270 static void
5271 gui_internal_cmd_map_download(struct gui_priv *this, struct widget *wm, void *data)
5272 {
5273         struct attr on, off, download_enabled, download_disabled;
5274         struct widget *w,*wb,*wma;
5275         struct map *map=data;
5276         FILE *f;
5277         char *search,buffer[256];
5278         int found,sp_match=0;
5279
5280         dbg(1,"wm=%p prefix=%s\n",wm,wm->prefix);
5281
5282         search=wm->prefix;
5283         if (search) {
5284                 found=0;
5285                 while(search[sp_match] == ' ')
5286                         sp_match++;
5287                 sp_match++;
5288         } else {
5289                 found=1;
5290         }
5291         on.type=off.type=attr_active;
5292         on.u.num=1;
5293         off.u.num=0;
5294         wb=gui_internal_menu(this, wm->name?wm->name:_("Map Download"));
5295         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5296         w->spy=this->spacing*3;
5297         gui_internal_widget_append(wb, w);
5298         if (!search) {
5299                 wma=gui_internal_button_map_attr_new(this, _("Active"), gravity_left_center|orientation_horizontal|flags_fill, map, &on, &off, 1);
5300                 gui_internal_widget_append(w, wma);
5301         }
5302
5303         download_enabled.type=download_disabled.type=attr_update;
5304         download_enabled.u.num=1;
5305         download_disabled.u.num=0;
5306         wma=gui_internal_button_map_attr_new(this
5307                 , _("Download Enabled")
5308                 , gravity_left_center|orientation_horizontal|flags_fill
5309                 , map
5310                 , &download_enabled
5311                 , &download_disabled
5312                 , 0);
5313         gui_internal_widget_append(w, wma);
5314
5315
5316         f=fopen("maps/areas.tsv","r");
5317         while (f && fgets(buffer, sizeof(buffer), f)) {
5318                 char *nl,*description,*description_size,*bbox,*size=NULL;
5319                 int sp=0;
5320                 if ((nl=strchr(buffer,'\n')))
5321                         *nl='\0';
5322                 if ((nl=strchr(buffer,'\r')))
5323                         *nl='\0';
5324                 while(buffer[sp] == ' ')
5325                         sp++;
5326                 if ((bbox=strchr(buffer,'\t')))
5327                         *bbox++='\0';
5328                 if (bbox && (size=strchr(bbox,'\t'))) 
5329                         *size++='\0';
5330                 if (search && !strcmp(buffer, search)) {
5331                         wma=gui_internal_button_new_with_callback(this, _("Download completely"), NULL, 
5332                                 gravity_left_center|orientation_horizontal|flags_fill, gui_internal_cmd_map_download_do, map);
5333                         wma->name=g_strdup(buffer+sp);
5334                         wma->prefix=g_strdup(bbox);
5335                         gui_internal_widget_append(w, wma);
5336                         found=1;
5337                 } else if (sp < sp_match)
5338                         found=0;
5339                 if (sp == sp_match && found && buffer[sp]) {
5340                         description=g_strdup(buffer+sp);
5341                         if (size)
5342                                 description_size=g_strdup_printf("%s (%s)",description,size);
5343                         else
5344                                 description_size=g_strdup(description);
5345                         wma=gui_internal_button_new_with_callback(this, description_size, NULL, 
5346                                 gravity_left_center|orientation_horizontal|flags_fill, gui_internal_cmd_map_download, map);
5347                         g_free(description_size);
5348                         wma->prefix=g_strdup(buffer);
5349                         wma->name=description;
5350                         gui_internal_widget_append(w, wma);
5351                 }
5352         }
5353         
5354         gui_internal_menu_render(this);
5355 }
5356
5357 static void
5358 gui_internal_cmd2_setting_maps(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5359 {
5360         struct attr attr, on, off, description, type, data, url, active;
5361         struct widget *w,*wb,*row,*wma;
5362         char *label;
5363         struct attr_iter *iter;
5364
5365         wb=gui_internal_menu(this, _("Maps"));
5366         //w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5367         //w->spy=this->spacing*3;
5368         w = gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
5369         gui_internal_widget_append(wb, w);
5370         iter=navit_attr_iter_new();
5371         on.type=off.type=attr_active;
5372         on.u.num=1;
5373         off.u.num=0;
5374         while(navit_get_attr(this->nav, attr_map, &attr, iter)) {
5375                 if (map_get_attr(attr.u.map, attr_description, &description, NULL)) {
5376                         label=g_strdup(description.u.str);
5377                 } else {
5378                         if (!map_get_attr(attr.u.map, attr_type, &type, NULL))
5379                                 type.u.str="";
5380                         if (!map_get_attr(attr.u.map, attr_data, &data, NULL))
5381                                 data.u.str="";
5382                         label=g_strdup_printf("%s:%s", type.u.str, data.u.str);
5383                 }
5384                 if (map_get_attr(attr.u.map, attr_url, &url, NULL)) {
5385                         if (!map_get_attr(attr.u.map, attr_active, &active, NULL))
5386                                 active.u.num=1;
5387                         wma=gui_internal_button_new_with_callback(this, label, image_new_xs(this, active.u.num ? "gui_active" : "gui_inactive"),
5388                         gravity_left_center|orientation_horizontal|flags_fill,
5389                         gui_internal_cmd_map_download, attr.u.map);
5390                 } else {
5391                         wma=gui_internal_button_map_attr_new(this, label, gravity_left_center|orientation_horizontal|flags_fill,
5392                                 attr.u.map, &on, &off, 1);
5393                 }       
5394                 gui_internal_widget_append(w, row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
5395                 gui_internal_widget_append(row, wma);
5396                 g_free(label);
5397         }
5398         navit_attr_iter_destroy(iter);
5399         gui_internal_menu_render(this);
5400
5401 }
5402 static void
5403 gui_internal_cmd_set_active_vehicle(struct gui_priv *this, struct widget *wm, void *data)
5404 {
5405         struct attr vehicle = {attr_vehicle,{wm->data}};
5406         navit_set_attr(this->nav, &vehicle);
5407 }
5408
5409 static void
5410 gui_internal_cmd_show_satellite_status(struct gui_priv *this, struct widget *wm, void *data)
5411 {
5412         struct widget *w,*wb,*row;
5413         struct attr attr,sat_attr;
5414         struct vehicle *v=wm->data;
5415         char *str;
5416         int i;
5417         enum attr_type types[]={attr_sat_prn, attr_sat_elevation, attr_sat_azimuth, attr_sat_snr};
5418
5419         wb=gui_internal_menu(this, _("Show Satellite Status"));
5420         gui_internal_menu_data(this)->redisplay=gui_internal_cmd_show_satellite_status;
5421         gui_internal_menu_data(this)->redisplay_widget=wm;
5422         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5423         gui_internal_widget_append(wb, w);
5424         w = gui_internal_widget_table_new(this,gravity_center | orientation_vertical | flags_expand | flags_fill, 0);
5425         row = gui_internal_widget_table_row_new(this,gravity_left_top);
5426         gui_internal_widget_append(row, gui_internal_label_new(this, " PRN "));
5427         gui_internal_widget_append(row, gui_internal_label_new(this, _(" Elevation ")));
5428         gui_internal_widget_append(row, gui_internal_label_new(this, _(" Azimuth ")));
5429         gui_internal_widget_append(row, gui_internal_label_new(this, " SNR "));
5430         gui_internal_widget_append(w,row);
5431         while (vehicle_get_attr(v, attr_position_sat_item, &attr, NULL)) {
5432                 row = gui_internal_widget_table_row_new(this,gravity_left_top);
5433                 for (i = 0 ; i < sizeof(types)/sizeof(enum attr_type) ; i++) {
5434                         if (item_attr_get(attr.u.item, types[i], &sat_attr))
5435                                 str=g_strdup_printf("%ld", sat_attr.u.num);
5436                         else
5437                                 str=g_strdup("");
5438                         gui_internal_widget_append(row, gui_internal_label_new(this, str));
5439                         g_free(str);
5440                 }
5441                 gui_internal_widget_append(w,row);
5442         }
5443         gui_internal_widget_append(wb, w);
5444         gui_internal_menu_render(this);
5445 }
5446
5447 static void
5448 gui_internal_cmd_show_nmea_data(struct gui_priv *this, struct widget *wm, void *data)
5449 {
5450         struct widget *w,*wb;
5451         struct attr attr;
5452         struct vehicle *v=wm->data;
5453         wb=gui_internal_menu(this, _("Show NMEA Data"));
5454         gui_internal_menu_data(this)->redisplay=gui_internal_cmd_show_nmea_data;
5455         gui_internal_menu_data(this)->redisplay_widget=wm;
5456         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5457         gui_internal_widget_append(wb, w);
5458         if (vehicle_get_attr(v, attr_position_nmea, &attr, NULL))
5459                 gui_internal_widget_append(w, gui_internal_text_new(this, attr.u.str, gravity_left_center|orientation_vertical));
5460         gui_internal_menu_render(this);
5461 }
5462
5463 /**
5464  * A container to hold the selected vehicle and the desired profile in
5465  * one data item.
5466  */
5467 struct vehicle_and_profilename {
5468         struct vehicle *vehicle;
5469         char *profilename;
5470 };
5471
5472 /**
5473  * Figures out whether the given vehicle is the active vehicle.
5474  *
5475  * @return true if the vehicle is active, false otherwise.
5476  */
5477 static int
5478 gui_internal_is_active_vehicle(struct gui_priv *this, struct vehicle
5479         *vehicle)
5480 {
5481         struct attr active_vehicle;
5482
5483         if (!navit_get_attr(this->nav, attr_vehicle, &active_vehicle, NULL))
5484         active_vehicle.u.vehicle=NULL;
5485
5486         return active_vehicle.u.vehicle == vehicle;
5487 }
5488
5489 static void
5490 save_vehicle_xml(struct vehicle *v)
5491 {
5492         struct attr attr;
5493         struct attr_iter *iter=vehicle_attr_iter_new();
5494         int childs=0;
5495         dbg(0,"enter\n");
5496         printf("<vehicle");
5497         while (vehicle_get_attr(v, attr_any_xml, &attr, iter)) {
5498                 if (ATTR_IS_OBJECT(attr.type))
5499                         childs=1;
5500                 else    {
5501                         char *attrtxt;
5502                         printf(" %s=\"%s\"",attr_to_name(attr.type),attrtxt=attr_to_text(&attr, NULL, 1));
5503                         g_free(attrtxt);
5504                 }
5505         }
5506         if (childs) {
5507                 printf(">\n");
5508                 printf("</vehicle>\n");
5509         } else
5510                 printf(" />\n");
5511         vehicle_attr_iter_destroy(iter);
5512 }
5513
5514
5515 /**
5516  * Reacts to a button press that changes a vehicle's active profile.
5517  *
5518  * @see gui_internal_add_vehicle_profile
5519  */
5520 static void
5521 gui_internal_cmd_set_active_profile(struct gui_priv *this, struct
5522                 widget *wm, void *data)
5523 {
5524         struct vehicle_and_profilename *vapn = data;
5525         struct vehicle *v = vapn->vehicle;
5526         char *profilename = vapn->profilename;
5527         struct attr vehicle_name_attr;
5528         char *vehicle_name = NULL;
5529         struct attr profilename_attr;
5530
5531         // Get the vehicle name
5532         vehicle_get_attr(v, attr_name, &vehicle_name_attr, NULL);
5533         vehicle_name = vehicle_name_attr.u.str;
5534
5535         dbg(0, "Changing vehicle %s to profile %s\n", vehicle_name,
5536                         profilename);
5537
5538         // Change the profile name
5539         profilename_attr.type = attr_profilename;
5540         profilename_attr.u.str = profilename;
5541         if(!vehicle_set_attr(v, &profilename_attr)) {
5542                 dbg(0, "Unable to set the vehicle's profile name\n");
5543         }
5544
5545     // Notify Navit that the routing should be re-done if this is the
5546     // active vehicle.
5547         if (gui_internal_is_active_vehicle(this, v)) {
5548                 struct attr vehicle;
5549                 vehicle.type=attr_vehicle;
5550                 vehicle.u.vehicle=v;
5551                 navit_set_attr(this->nav, &vehicle);
5552         }
5553         save_vehicle_xml(v);
5554         
5555         gui_internal_prune_menu_count(this, 1, 0);
5556         gui_internal_menu_vehicle_settings(this, v, vehicle_name);
5557 }
5558
5559 /**
5560  * Adds the vehicle profile to the GUI, allowing the user to pick a
5561  * profile for the currently selected vehicle.
5562  */
5563 static void
5564 gui_internal_add_vehicle_profile(struct gui_priv *this, struct widget
5565                 *parent, struct vehicle *v, struct vehicleprofile *profile)
5566 {
5567         // Just here to show up in the translation file, nice and close to
5568         // where the translations are actually used.
5569         struct attr profile_attr;
5570         struct attr *attr = NULL;
5571         char *name = NULL;
5572         char *active_profile = NULL;
5573         char *label = NULL;
5574         int active;
5575         struct vehicle_and_profilename *context = NULL;
5576
5577 #ifdef ONLY_FOR_TRANSLATION
5578         char *translations[] = {_n("car"), _n("bike"), _n("pedestrian")};
5579 #endif
5580
5581         // Figure out the profile name
5582         attr = attr_search(profile->attrs, NULL, attr_name);
5583         if (!attr) {
5584                 dbg(0, "Adding vehicle profile failed. attr==NULL");
5585                 return;
5586         }
5587         name = attr->u.str;
5588
5589         // Determine whether the profile is the active one
5590         if (vehicle_get_attr(v, attr_profilename, &profile_attr, NULL))
5591                 active_profile = profile_attr.u.str;
5592         active = active_profile != NULL && !strcmp(name, active_profile);
5593
5594         dbg(0, "Adding vehicle profile %s, active=%s/%i\n", name,
5595                         active_profile, active);
5596
5597         // Build a translatable label.
5598         if(active) {
5599                 label = g_strdup_printf(_("Current profile: %s"), _(name));
5600         } else {
5601                 label = g_strdup_printf(_("Change profile to: %s"), _(name));
5602         }
5603
5604         // Create the context object (the vehicle and the desired profile)
5605         context = g_new0(struct vehicle_and_profilename, 1);
5606         context->vehicle = v;
5607         context->profilename = name;
5608
5609         // Add the button
5610         gui_internal_widget_append(parent,
5611                 gui_internal_button_new_with_callback(
5612                         this, label,
5613                         image_new_xs(this, active ? "gui_active" : "gui_inactive"),
5614                         gravity_left_center|orientation_horizontal|flags_fill,
5615                         gui_internal_cmd_set_active_profile, context));
5616
5617         free(label);
5618 }
5619
5620 static void
5621 gui_internal_menu_vehicle_settings(struct gui_priv *this, struct vehicle *v, char *name)
5622 {
5623         struct widget *w,*wb,*row;
5624         struct attr attr;
5625     struct vehicleprofile *profile = NULL;
5626         GList *profiles;
5627
5628         wb=gui_internal_menu(this, name);
5629         w=gui_internal_widget_table_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill,1);
5630         gui_internal_widget_append(wb, w);
5631
5632     // Add the "Set as active" button if this isn't the active
5633     // vehicle.
5634         if (!gui_internal_is_active_vehicle(this, v)) {
5635                 gui_internal_widget_append(w, row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
5636                 gui_internal_widget_append(row,
5637                         gui_internal_button_new_with_callback(this, _("Set as active"),
5638                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
5639                                 gui_internal_cmd_set_active_vehicle, v));
5640         }
5641
5642         if (vehicle_get_attr(v, attr_position_sat_item, &attr, NULL)) {
5643                 gui_internal_widget_append(w, row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
5644                 gui_internal_widget_append(row,
5645                         gui_internal_button_new_with_callback(this, _("Show Satellite status"),
5646                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
5647                                 gui_internal_cmd_show_satellite_status, v));
5648         }
5649         if (vehicle_get_attr(v, attr_position_nmea, &attr, NULL)) {
5650                 gui_internal_widget_append(w, row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
5651                 gui_internal_widget_append(row,
5652                         gui_internal_button_new_with_callback(this, _("Show NMEA data"),
5653                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
5654                                 gui_internal_cmd_show_nmea_data, v));
5655         }
5656
5657     // Add all the possible vehicle profiles to the menu
5658         profiles = navit_get_vehicleprofiles(this->nav);
5659     while(profiles) {
5660         profile = (struct vehicleprofile *)profiles->data;
5661         gui_internal_widget_append(w, row=gui_internal_widget_table_row_new(this,gravity_left|orientation_horizontal|flags_fill));
5662         gui_internal_add_vehicle_profile(this, row, v, profile);
5663                 profiles = g_list_next(profiles);
5664     }
5665
5666         callback_list_call_attr_2(this->cbl, attr_vehicle, w, v);
5667         gui_internal_menu_render(this);
5668 }
5669
5670 static void
5671 gui_internal_cmd_vehicle_settings(struct gui_priv *this, struct widget *wm, void *data)
5672 {
5673         gui_internal_menu_vehicle_settings(this, wm->data, wm->text);
5674 }
5675
5676 static void
5677 gui_internal_cmd2_setting_vehicle(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5678 {
5679         struct attr attr,attr2,vattr;
5680         struct widget *w,*wb,*wl;
5681         struct attr_iter *iter;
5682         struct attr active_vehicle;
5683
5684         iter=navit_attr_iter_new();
5685         if (navit_get_attr(this->nav, attr_vehicle, &attr, iter) && !navit_get_attr(this->nav, attr_vehicle, &attr2, iter)) {
5686                 vehicle_get_attr(attr.u.vehicle, attr_name, &vattr, NULL);
5687                 navit_attr_iter_destroy(iter);
5688                 gui_internal_menu_vehicle_settings(this, attr.u.vehicle, vattr.u.str);
5689                 return;
5690         }
5691         navit_attr_iter_destroy(iter);
5692
5693         wb=gui_internal_menu(this, _("Vehicle"));
5694         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5695         w->spy=this->spacing*3;
5696         gui_internal_widget_append(wb, w);
5697         if (!navit_get_attr(this->nav, attr_vehicle, &active_vehicle, NULL))
5698                 active_vehicle.u.vehicle=NULL;
5699         iter=navit_attr_iter_new();
5700         while(navit_get_attr(this->nav, attr_vehicle, &attr, iter)) {
5701                 vehicle_get_attr(attr.u.vehicle, attr_name, &vattr, NULL);
5702                 wl=gui_internal_button_new_with_callback(this, vattr.u.str,
5703                         image_new_xs(this, attr.u.vehicle == active_vehicle.u.vehicle ? "gui_active" : "gui_inactive"), gravity_left_center|orientation_horizontal|flags_fill,
5704                         gui_internal_cmd_vehicle_settings, attr.u.vehicle);
5705                 wl->text=g_strdup(vattr.u.str);
5706                 gui_internal_widget_append(w, wl);
5707         }
5708         navit_attr_iter_destroy(iter);
5709         gui_internal_menu_render(this);
5710 }
5711
5712
5713 static void
5714 gui_internal_cmd2_setting_rules(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5715 {
5716         struct widget *wb,*w;
5717         struct attr on,off;
5718         wb=gui_internal_menu(this, _("Rules"));
5719         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5720         w->spy=this->spacing*3;
5721         gui_internal_widget_append(wb, w);
5722         on.u.num=1;
5723         off.u.num=0;
5724         on.type=off.type=attr_tracking;
5725         gui_internal_widget_append(w,
5726                 gui_internal_button_navit_attr_new(this, _("Lock on road"), gravity_left_center|orientation_horizontal|flags_fill,
5727                         &on, &off));
5728         on.u.num=0;
5729         off.u.num=-1;
5730         on.type=off.type=attr_orientation;
5731         gui_internal_widget_append(w,
5732                 gui_internal_button_navit_attr_new(this, _("Northing"), gravity_left_center|orientation_horizontal|flags_fill,
5733                         &on, &off));
5734         on.u.num=1;
5735         off.u.num=0;
5736         on.type=off.type=attr_follow_cursor;
5737         gui_internal_widget_append(w,
5738                 gui_internal_button_navit_attr_new(this, _("Map follows Vehicle"), gravity_left_center|orientation_horizontal|flags_fill,
5739                         &on, &off));
5740         on.u.num=1;
5741         off.u.num=0;
5742         on.type=off.type=attr_waypoints_flag;
5743         gui_internal_widget_append(w,
5744                         gui_internal_button_navit_attr_new(this, _("Plan with Waypoints"), gravity_left_center|orientation_horizontal|flags_fill,
5745                                         &on, &off));
5746         gui_internal_menu_render(this);
5747 }
5748
5749 //##############################################################################################################
5750 //# Description:
5751 //# Comment:
5752 //# Authors: Martin Schaller (04/2008)
5753 //##############################################################################################################
5754 static void gui_internal_motion(void *data, struct point *p)
5755 {
5756
5757         struct gui_priv *this=data;
5758         if (!this->root.children) {
5759                 navit_handle_motion(this->nav, p);
5760                 return;
5761         }
5762         if (!this->pressed)
5763                 return;
5764         this->current=*p;
5765         if(!this->motion_timeout_callback)
5766                 this->motion_timeout_callback=callback_new_1(callback_cast(gui_internal_motion_cb), this);
5767         if(!this->motion_timeout_event)
5768                 this->motion_timeout_event=event_add_timeout(30,0, this->motion_timeout_callback);
5769 }
5770
5771 static const char *
5772 find_attr(const char **names, const char **values, const char *name)
5773 {
5774         while (*names) {
5775                 if (!g_strcasecmp(*names, name))
5776                         return *values;
5777                 names+=xml_attr_distance;
5778                 values+=xml_attr_distance;
5779         }
5780         return NULL;
5781 }
5782
5783 static char *
5784 find_attr_dup(const char **names, const char **values, const char *name)
5785 {
5786         return g_strdup(find_attr(names, values, name));
5787 }
5788
5789 static void
5790 gui_internal_evaluate(struct gui_priv *this, const char *command)
5791 {
5792         if (command)
5793                 command_evaluate(&this->self, command);
5794 }
5795
5796
5797 static void
5798 gui_internal_html_command(struct gui_priv *this, struct widget *w, void *data)
5799 {
5800         gui_internal_evaluate(this,w->command);
5801 }
5802
5803 static void
5804 gui_internal_html_submit_set(struct gui_priv *this, struct widget *w, struct form *form)
5805 {
5806         GList *l;
5807         if (w->form == form && w->name) {
5808                 struct attr *attr=attr_new_from_text(w->name, w->text?w->text:"");
5809                 if (attr)
5810                         gui_set_attr(this->self.u.gui, attr);
5811                 attr_free(attr);
5812         }
5813         l=w->children;
5814         while (l) {
5815                 w=l->data;
5816                 gui_internal_html_submit_set(this, w, form);
5817                 l=g_list_next(l);
5818         }
5819
5820 }
5821
5822 static void
5823 gui_internal_html_submit(struct gui_priv *this, struct widget *w, void *data)
5824 {
5825         struct widget *menu;
5826         GList *l;
5827
5828         dbg(1,"enter form %p %s\n",w->form,w->form->onsubmit);
5829         l=g_list_last(this->root.children);
5830         menu=l->data;
5831         graphics_draw_mode(this->gra, draw_mode_begin);
5832         gui_internal_highlight_do(this, NULL);
5833         gui_internal_menu_render(this);
5834         graphics_draw_mode(this->gra, draw_mode_end);
5835         gui_internal_html_submit_set(this, menu, w->form);
5836         gui_internal_evaluate(this,w->form->onsubmit);
5837 }
5838
5839 static void
5840 gui_internal_html_load_href(struct gui_priv *this, char *href, int replace)
5841 {
5842         if (replace)
5843                 gui_internal_prune_menu_count(this, 1, 0);
5844         if (href && href[0] == '#') {
5845                 dbg(1,"href=%s\n",href);
5846                 g_free(this->href);
5847                 this->href=g_strdup(href);
5848                 gui_internal_html_menu(this, this->html_text, href+1);
5849         }
5850 }
5851
5852 static void
5853 gui_internal_html_href(struct gui_priv *this, struct widget *w, void *data)
5854 {
5855         gui_internal_html_load_href(this, w->command, 0);
5856 }
5857
5858 struct div_flags_map {
5859         char *attr;
5860         char *val;
5861         enum flags flags;
5862 } div_flags_map[] = {
5863         {"gravity","none",gravity_none},
5864         {"gravity","left",gravity_left},
5865         {"gravity","xcenter",gravity_xcenter},
5866         {"gravity","right",gravity_right},
5867         {"gravity","top",gravity_top},
5868         {"gravity","ycenter",gravity_ycenter},
5869         {"gravity","bottom",gravity_bottom},
5870         {"gravity","left_top",gravity_left_top},
5871         {"gravity","top_center",gravity_top_center},
5872         {"gravity","right_top",gravity_right_top},
5873         {"gravity","left_center",gravity_left_center},
5874         {"gravity","center",gravity_center},
5875         {"gravity","right_center",gravity_right_center},
5876         {"gravity","left_bottom",gravity_left_bottom},
5877         {"gravity","bottom_center",gravity_bottom_center},
5878         {"gravity","right_bottom",gravity_right_bottom},
5879         {"expand","1",flags_expand},
5880         {"fill","1",flags_fill},
5881         {"orientation","horizontal",orientation_horizontal},
5882         {"orientation","vertical",orientation_vertical},
5883         {"orientation","horizontal_vertical",orientation_horizontal_vertical},
5884 };
5885
5886 static enum flags
5887 div_flag(const char **names, const char **values, char *name)
5888 {
5889         int i;
5890         enum flags ret=0;
5891         const char *value=find_attr(names, values, name);
5892         if (!value)
5893                 return ret;
5894         for (i = 0 ; i < sizeof(div_flags_map)/sizeof(struct div_flags_map); i++) {
5895                 if (!strcmp(div_flags_map[i].attr,name) && !strcmp(div_flags_map[i].val,value))
5896                         ret|=div_flags_map[i].flags;
5897         }
5898         return ret;
5899 }
5900
5901 static enum flags
5902 div_flags(const char **names, const char **values)
5903 {
5904         enum flags flags;
5905         flags = div_flag(names, values, "gravity");
5906         flags |= div_flag(names, values, "orientation");
5907         flags |= div_flag(names, values, "expand");
5908         flags |= div_flag(names, values, "fill");
5909         return flags;
5910 }
5911
5912 static struct widget *
5913 html_image(struct gui_priv *this, const char **names, const char **values)
5914 {
5915         const char *src, *size;
5916         struct graphics_image *img=NULL;
5917
5918         src=find_attr(names, values, "src");
5919         if (!src)
5920                 return NULL;
5921         size=find_attr(names, values, "size");
5922         if (!size)
5923                 size="l";
5924         if (!strcmp(size,"l"))
5925                 img=image_new_l(this, src);
5926         else if (!strcmp(size,"s"))
5927                 img=image_new_s(this, src);
5928         else if (!strcmp(size,"xs"))
5929                 img=image_new_xs(this, src);
5930         if (!img)
5931                 return NULL;
5932         return gui_internal_image_new(this, img);
5933 }
5934
5935 static void
5936 gui_internal_html_start(void *dummy, const char *tag_name, const char **names, const char **values, void *data, void *error)
5937 {
5938         struct gui_priv *this=data;
5939         int i;
5940         enum html_tag tag=html_tag_none;
5941         struct html *html=&this->html[this->html_depth];
5942         const char *cond, *type;
5943
5944         if (!g_strcasecmp(tag_name,"text"))
5945                 return;
5946         html->command=NULL;
5947         html->name=NULL;
5948         html->href=NULL;
5949         html->skip=0;
5950         cond=find_attr(names, values, "cond");
5951
5952         if (cond && !this->html_skip) {
5953                 if (!command_evaluate_to_boolean(&this->self, cond, NULL))
5954                         html->skip=1;
5955         }
5956
5957         for (i=0 ; i < sizeof(html_tag_map)/sizeof(struct html_tag_map); i++) {
5958                 if (!g_strcasecmp(html_tag_map[i].tag_name, tag_name)) {
5959                         tag=html_tag_map[i].tag;
5960                         break;
5961                 }
5962         }
5963         html->tag=tag;
5964         if (!this->html_skip && !html->skip) {
5965                 switch (tag) {
5966                 case html_tag_a:
5967                         html->name=find_attr_dup(names, values, "name");
5968                         if (html->name) {
5969                                 html->skip=this->html_anchor ? strcmp(html->name,this->html_anchor) : 0;
5970                                 if (!html->skip)
5971                                         this->html_anchor_found=1;
5972                         }
5973                         html->command=find_attr_dup(names, values, "onclick");
5974                         html->href=find_attr_dup(names, values, "href");
5975                         html->refresh_cond=find_attr_dup(names, values, "refresh_cond");
5976                         break;
5977                 case html_tag_img:
5978                         html->command=find_attr_dup(names, values, "onclick");
5979                         html->w=html_image(this, names, values);
5980                         break;
5981                 case html_tag_form:
5982                         this->form=g_new0(struct form, 1);
5983                         this->form->onsubmit=find_attr_dup(names, values, "onsubmit");
5984                         break;
5985                 case html_tag_input:
5986                         type=find_attr_dup(names, values, "type");
5987                         if (!type)
5988                                 break;
5989                         if (!strcmp(type,"image")) {
5990                                 html->w=html_image(this, names, values);
5991                                 if (html->w) {
5992                                         html->w->state|=STATE_SENSITIVE;
5993                                         html->w->func=gui_internal_html_submit;
5994                                 }
5995                         }
5996                         if (!strcmp(type,"text") || !strcmp(type,"password")) {
5997                                 html->w=gui_internal_label_new(this, NULL);
5998                                 html->w->background=this->background;
5999                                 html->w->flags |= div_flags(names, values);
6000                                 html->w->state|=STATE_EDITABLE;
6001                                 if (!this->editable) {
6002                                         this->editable=html->w;
6003                                         html->w->state|=STATE_EDIT;
6004                                 }
6005                                 this->keyboard_required=1;
6006                                 if (!strcmp(type,"password"))
6007                                         html->w->flags2 |= 1;
6008                         }
6009                         if (html->w) {
6010                                 html->w->form=this->form;
6011                                 html->w->name=find_attr_dup(names, values, "name");
6012                         }
6013                         break;
6014                 case html_tag_div:
6015                         html->w=gui_internal_box_new(this, div_flags(names, values));
6016                         html->container=this->html_container;
6017                         this->html_container=html->w;
6018                         break;
6019                 default:
6020                         break;
6021                 }
6022         }
6023         this->html_skip+=html->skip;
6024         this->html_depth++;
6025 }
6026
6027 static void
6028 gui_internal_html_end(void *dummy, const char *tag_name, void *data, void *error)
6029 {
6030         struct gui_priv *this=data;
6031         struct html *html;
6032         struct html *parent=NULL;
6033
6034         if (!g_strcasecmp(tag_name,"text"))
6035                 return;
6036         this->html_depth--;
6037         html=&this->html[this->html_depth];
6038         if (this->html_depth > 0)
6039                 parent=&this->html[this->html_depth-1];
6040
6041
6042         if (!this->html_skip) {
6043                 if (html->command && html->w) {
6044                         html->w->state |= STATE_SENSITIVE;
6045                         html->w->command=html->command;
6046                         html->w->func=gui_internal_html_command;
6047                         html->command=NULL;
6048                 }
6049                 if (parent && (parent->href || parent->command) && html->w) {
6050                         html->w->state |= STATE_SENSITIVE;
6051                         if (parent->command) {
6052                                 html->w->command=g_strdup(parent->command);
6053                                 html->w->func=gui_internal_html_command;
6054                         } else {
6055                                 html->w->command=g_strdup(parent->href);
6056                                 html->w->func=gui_internal_html_href;
6057                         }
6058                 }
6059                 switch (html->tag) {
6060                 case html_tag_div:
6061                         this->html_container=html->container;
6062                 case html_tag_img:
6063                 case html_tag_input:
6064                         gui_internal_widget_append(this->html_container, html->w);
6065                         break;
6066                 case html_tag_form:
6067                         this->form=NULL;
6068                         break;
6069                 default:
6070                         break;
6071                 }
6072         }
6073         this->html_skip-=html->skip;
6074         g_free(html->command);
6075         g_free(html->name);
6076         g_free(html->href);
6077         g_free(html->refresh_cond);
6078 }
6079
6080 static void
6081 gui_internal_refresh_callback_called(struct gui_priv *this, struct menu_data *menu_data)
6082 {
6083         if (gui_internal_menu_data(this) == menu_data) {
6084                 char *href=g_strdup(menu_data->href);
6085                 gui_internal_html_load_href(this, href, 1);
6086                 g_free(href);
6087         }
6088 }
6089
6090 static void
6091 gui_internal_set_refresh_callback(struct gui_priv *this, char *cond)
6092 {
6093         dbg(0,"cond=%s\n",cond);
6094         if (cond) {
6095                 enum attr_type type;
6096                 struct object_func *func;
6097                 struct menu_data *menu_data=gui_internal_menu_data(this);
6098                 dbg(0,"navit=%p\n",this->nav);
6099                 type=command_evaluate_to_attr(&this->self, cond, NULL, &menu_data->refresh_callback_obj);
6100                 if (type == attr_none)
6101                         return;
6102                 func=object_func_lookup(menu_data->refresh_callback_obj.type);
6103                 if (!func || !func->add_attr)
6104                         return;
6105                 menu_data->refresh_callback.type=attr_callback;
6106                 menu_data->refresh_callback.u.callback=callback_new_attr_2(callback_cast(gui_internal_refresh_callback_called),type,this,menu_data);
6107                 func->add_attr(menu_data->refresh_callback_obj.u.data, &menu_data->refresh_callback);
6108         }
6109 }
6110
6111 static void
6112 gui_internal_html_text(void *dummy, const char *text, int len, void *data, void *error)
6113 {
6114         struct gui_priv *this=data;
6115         struct widget *w;
6116         int depth=this->html_depth-1;
6117         struct html *html=&this->html[depth];
6118         gchar *text_stripped;
6119
6120         if (this->html_skip)
6121                 return;
6122         while (isspace(text[0])) {
6123                 text++;
6124                 len--;
6125         }
6126         while (len > 0 && isspace(text[len-1]))
6127                 len--;
6128
6129         text_stripped = g_strndup(text, len);
6130         if (html->tag == html_tag_html && depth > 2) {
6131                 if (this->html[depth-1].tag == html_tag_script) {
6132                         html=&this->html[depth-2];
6133                 }
6134         }
6135         switch (html->tag) {
6136         case html_tag_a:
6137                 if (html->name && len) {
6138                         this->html_container=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
6139                         gui_internal_widget_append(gui_internal_menu(this, _(text_stripped)), this->html_container);
6140                         gui_internal_menu_data(this)->href=g_strdup(this->href);
6141                         gui_internal_set_refresh_callback(this, html->refresh_cond);
6142                         this->html_container->spx=this->spacing*10;
6143                 }
6144                 break;
6145         case html_tag_h1:
6146                 if (!this->html_container) {
6147                         this->html_container=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
6148                         gui_internal_widget_append(gui_internal_menu(this, _(text_stripped)), this->html_container);
6149                         this->html_container->spx=this->spacing*10;
6150                 }
6151                 break;
6152         case html_tag_img:
6153                 if (len) {
6154                         w=gui_internal_box_new(this, gravity_center|orientation_vertical);
6155                         gui_internal_widget_append(w, html->w);
6156                         gui_internal_widget_append(w, gui_internal_text_new(this, _(text_stripped), gravity_center|orientation_vertical));
6157                         html->w=w;
6158                 }
6159                 break;
6160         case html_tag_div:
6161                 if (len) {
6162                         gui_internal_widget_append(html->w, gui_internal_text_new(this, _(text_stripped), gravity_center|orientation_vertical));
6163                 }
6164                 break;
6165         case html_tag_script:
6166                 dbg(1,"execute %s\n",text_stripped);
6167                 gui_internal_evaluate(this,text_stripped);
6168                 break;
6169         default:
6170                 break;
6171         }
6172         g_free(text_stripped);
6173 }
6174
6175 static void
6176 gui_internal_html_menu(struct gui_priv *this, const char *document, char *anchor)
6177 {
6178         char *doc=g_strdup(document);
6179         graphics_draw_mode(this->gra, draw_mode_begin);
6180         this->html_container=NULL;
6181         this->html_depth=0;
6182         this->html_anchor=anchor;
6183         this->html_anchor_found=0;
6184         this->form=NULL;
6185         this->keyboard_required=0;
6186         this->editable=NULL;
6187         callback_list_call_attr_2(this->cbl,attr_gui,anchor,&doc);
6188         xml_parse_text(doc, this, gui_internal_html_start, gui_internal_html_end, gui_internal_html_text);
6189         g_free(doc);
6190         if (this->keyboard_required && this->keyboard) {
6191                 this->html_container->flags=gravity_center|orientation_vertical|flags_expand|flags_fill;
6192                 gui_internal_widget_append(this->html_container, gui_internal_keyboard(this,2));
6193         }
6194         gui_internal_menu_render(this);
6195         graphics_draw_mode(this->gra, draw_mode_end);
6196 }
6197
6198
6199 static void
6200 gui_internal_enter(struct gui_priv *this, int ignore)
6201 {
6202         struct graphics *gra=this->gra;
6203         if (ignore != -1) 
6204                 this->ignore_button=ignore;
6205
6206         navit_block(this->nav, 1);
6207         graphics_overlay_disable(gra, 1);
6208         this->root.p.x=0;
6209         this->root.p.y=0;
6210         this->root.background=this->background;
6211 }
6212
6213 static void
6214 gui_internal_leave(struct gui_priv *this)
6215 {
6216         graphics_draw_mode(this->gra, draw_mode_end);
6217 }
6218
6219 static void
6220 gui_internal_set_click_coord(struct gui_priv *this, struct point *p)
6221 {
6222         struct coord c;
6223         struct coord_geo g;
6224         struct attr attr;
6225         struct transformation *trans;
6226         trans=navit_get_trans(this->nav);
6227         attr_free(this->click_coord_geo);
6228         this->click_coord_geo=NULL;
6229         if (p) {
6230                 transform_reverse(trans, p, &c);
6231                 dbg(1,"x=0x%x y=0x%x\n", c.x, c.y);
6232                 this->clickp.pro=transform_get_projection(trans);
6233                 this->clickp.x=c.x;
6234                 this->clickp.y=c.y;
6235                 transform_to_geo(this->clickp.pro, &c, &g);
6236                 attr.u.coord_geo=&g;
6237                 attr.type=attr_click_coord_geo;
6238                 this->click_coord_geo=attr_dup(&attr);
6239         }
6240 }
6241
6242 static void
6243 gui_internal_set_position_coord(struct gui_priv *this)
6244 {
6245         struct transformation *trans;
6246         struct attr attr,attrp;
6247         struct coord c;
6248
6249         trans=navit_get_trans(this->nav);
6250         attr_free(this->position_coord_geo);
6251         this->position_coord_geo=NULL;
6252         if (navit_get_attr(this->nav, attr_vehicle, &attr, NULL) && attr.u.vehicle
6253                 && vehicle_get_attr(attr.u.vehicle, attr_position_coord_geo, &attrp, NULL)) {
6254                 this->position_coord_geo=attr_dup(&attrp);
6255                 this->vehiclep.pro=transform_get_projection(trans);
6256                 transform_from_geo(this->vehiclep.pro, attrp.u.coord_geo, &c);
6257                 this->vehiclep.x=c.x;
6258                 this->vehiclep.y=c.y;
6259         }
6260 }
6261
6262 static void
6263 gui_internal_enter_setup(struct gui_priv *this)
6264 {
6265         if (!this->mouse_button_clicked_on_map)
6266                 gui_internal_set_position_coord(this);
6267 }
6268
6269 static void
6270 gui_internal_html_main_menu(struct gui_priv *this)
6271 {
6272         gui_internal_prune_menu(this, NULL);
6273         gui_internal_html_load_href(this, "#Main Menu", 0);
6274 }
6275
6276 static void
6277 gui_internal_cmd_menu(struct gui_priv *this, int ignore, char *href)
6278 {
6279         dbg(1,"enter\n");
6280         gui_internal_enter(this, ignore);
6281         gui_internal_enter_setup(this);
6282         // draw menu
6283         if (href)
6284                 gui_internal_html_load_href(this, href, 0);
6285         else
6286                 gui_internal_html_main_menu(this);
6287 }
6288
6289 static void
6290 gui_internal_cmd_menu2(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
6291 {
6292         char *href=NULL;
6293         int i=0, ignore=0, replace=0;
6294
6295         if (in && in[i] && ATTR_IS_INT(in[i]->type))
6296                 ignore=in[i++]->u.num;
6297
6298         if (in && in[i] && ATTR_IS_STRING(in[i]->type)) {
6299                 href=in[i++]->u.str;
6300                 if (in[i] && ATTR_IS_INT(in[i]->type))
6301                         replace=in[i++]->u.num;
6302         }
6303
6304         if (this->root.children) {
6305                 if (!href)
6306                         return;
6307                 gui_internal_html_load_href(this, href, replace);
6308                 return;
6309         }
6310         gui_internal_cmd_menu(this, ignore, href);
6311 }
6312
6313
6314 static void
6315 gui_internal_cmd_log_do(struct gui_priv *this, struct widget *widget)
6316 {
6317         if (widget->text && strlen(widget->text)) {
6318                 if (this->position_coord_geo)
6319                         navit_textfile_debug_log_at(this->nav, &this->vehiclep, "type=log_entry label=\"%s\"",widget->text);
6320                 else
6321                         navit_textfile_debug_log(this->nav, "type=log_entry label=\"%s\"",widget->text);
6322         }
6323         g_free(widget->text);
6324         widget->text=NULL;
6325         gui_internal_prune_menu(this, NULL);
6326         gui_internal_check_exit(this);
6327 }
6328
6329 static void
6330 gui_internal_cmd_log_clicked(struct gui_priv *this, struct widget *widget, void *data)
6331 {
6332         gui_internal_cmd_log_do(this, widget->data);
6333 }
6334
6335 static void
6336 gui_internal_cmd_log_changed(struct gui_priv *this, struct widget *wm, void *data)
6337 {
6338         int len;
6339         if (wm->text) {
6340                 len=strlen(wm->text);
6341                 if (len && (wm->text[len-1] == '\n' || wm->text[len-1] == '\r')) {
6342                         wm->text[len-1]='\0';
6343                         gui_internal_cmd_log_do(this, wm);
6344                 }
6345         }
6346 }
6347
6348
6349 static void
6350 gui_internal_cmd_log(struct gui_priv *this)
6351 {
6352         struct widget *w,*wb,*wk,*wl,*we,*wnext;
6353         gui_internal_enter(this, 1);
6354         gui_internal_set_click_coord(this, NULL);
6355         gui_internal_enter_setup(this);
6356         wb=gui_internal_menu(this, "Log Message");
6357         w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
6358         gui_internal_widget_append(wb, w);
6359         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
6360         gui_internal_widget_append(w, we);
6361         gui_internal_widget_append(we, wk=gui_internal_label_new(this, _("Message")));
6362         wk->state |= STATE_EDIT|STATE_EDITABLE|STATE_CLEAR;
6363         wk->background=this->background;
6364         wk->flags |= flags_expand|flags_fill;
6365         wk->func = gui_internal_cmd_log_changed;
6366         gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
6367         wnext->state |= STATE_SENSITIVE;
6368         wnext->func = gui_internal_cmd_log_clicked;
6369         wnext->data=wk;
6370         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
6371         gui_internal_widget_append(w, wl);
6372         if (this->keyboard)
6373                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
6374         gui_internal_menu_render(this);
6375         gui_internal_leave(this);
6376 }
6377
6378 static void
6379 gui_internal_check_exit(struct gui_priv *this)
6380 {
6381         struct graphics *gra=this->gra;
6382         if (! this->root.children) {
6383                 gui_internal_search_idle_end(this);
6384                 gui_internal_search_list_destroy(this);
6385                 graphics_overlay_disable(gra, 0);
6386                 if (!navit_block(this->nav, 0)) {
6387                         if (this->redraw)
6388                                 navit_draw(this->nav);
6389                         else
6390                                 navit_draw_displaylist(this->nav);
6391                 }
6392         }
6393 }
6394
6395 static int
6396 gui_internal_get_attr(struct gui_priv *this, enum attr_type type, struct attr *attr)
6397 {
6398         switch (type) {
6399         case attr_active:
6400                 attr->u.num=this->root.children != NULL;
6401                 break;
6402         case attr_click_coord_geo:
6403                 if (!this->click_coord_geo)
6404                         return 0;
6405                 *attr=*this->click_coord_geo;
6406                 break;
6407         case attr_position_coord_geo:
6408                 if (!this->position_coord_geo)
6409                         return 0;
6410                 *attr=*this->position_coord_geo;
6411                 break;
6412         case attr_pitch:
6413                 attr->u.num=this->pitch;
6414                 break;
6415         case attr_button:
6416                 attr->u.num=this->mouse_button_clicked_on_map;
6417                 break;
6418         default:
6419                 return 0;
6420         }
6421         attr->type=type;
6422         return 1;
6423 }
6424
6425 static int
6426 gui_internal_add_attr(struct gui_priv *this, struct attr *attr)
6427 {
6428         switch (attr->type) {
6429         case attr_xml_text:
6430                 g_free(this->html_text);
6431                 this->html_text=g_strdup(attr->u.str);
6432                 return 1;
6433         default:
6434                 return 0;
6435         }
6436 }
6437
6438 static int
6439 gui_internal_set_attr(struct gui_priv *this, struct attr *attr)
6440 {
6441         switch (attr->type) {
6442         case attr_fullscreen:
6443                 if ((this->fullscreen > 0) != (attr->u.num > 0)) {
6444                         graphics_draw_mode(this->gra, draw_mode_end);
6445                         this->win->fullscreen(this->win, attr->u.num > 0);
6446                         graphics_draw_mode(this->gra, draw_mode_begin);
6447                 }
6448                 this->fullscreen=attr->u.num;
6449                 return 1;
6450         case attr_menu_on_map_click:
6451                 this->menu_on_map_click=attr->u.num;
6452                 return 1;
6453         case attr_on_map_click:
6454                 g_free(this->on_map_click);
6455                 this->on_map_click=g_strdup(attr->u.str);
6456                 return 1;
6457         default:
6458                 dbg(0,"%s\n",attr_to_name(attr->type));
6459                 return 1;
6460         }
6461 }
6462
6463 static void gui_internal_dbus_signal(struct gui_priv *this, struct point *p)
6464 {
6465         struct displaylist_handle *dlh;
6466         struct displaylist *display;
6467         struct displayitem *di;
6468         struct attr cb,**attr_list=NULL;
6469         int valid=0;
6470
6471         display=navit_get_displaylist(this->nav);
6472         dlh=graphics_displaylist_open(display);
6473         while ((di=graphics_displaylist_next(dlh))) {
6474                 struct item *item=graphics_displayitem_get_item(di);
6475                 if (item_is_point(*item) && graphics_displayitem_get_displayed(di) &&
6476                         graphics_displayitem_within_dist(display, di, p, this->radius)) {
6477                         struct map_rect *mr=map_rect_new(item->map, NULL);
6478                         struct item *itemo=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
6479                         struct attr attr;
6480                         if (itemo && item_attr_get(itemo, attr_data, &attr))
6481                                 attr_list=attr_generic_add_attr(attr_list, &attr);
6482                         map_rect_destroy(mr);
6483                 }
6484         }
6485         graphics_displaylist_close(dlh);
6486         if (attr_list && navit_get_attr(this->nav, attr_callback_list, &cb, NULL))
6487                 callback_list_call_attr_4(cb.u.callback_list, attr_command, "dbus_send_signal", attr_list, NULL, &valid);
6488         attr_list_free(attr_list);
6489 }
6490
6491
6492
6493 //##############################################################################################################
6494 //# Description: Function to handle mouse clicks and scroll wheel movement
6495 //# Comment:
6496 //# Authors: Martin Schaller (04/2008), Stefan Klumpp (04/2008)
6497 //##############################################################################################################
6498 static void gui_internal_button(void *data, int pressed, int button, struct point *p)
6499 {
6500         struct gui_priv *this=data;
6501         struct graphics *gra=this->gra;
6502
6503         dbg(1,"enter %d %d\n", pressed, button);
6504         // if still on the map (not in the menu, yet):
6505         dbg(1,"children=%p ignore_button=%d\n",this->root.children,this->ignore_button);
6506         if (!this->root.children || this->ignore_button) {
6507
6508                 this->ignore_button=0;
6509                 // check whether the position of the mouse changed during press/release OR if it is the scrollwheel
6510                 if (!navit_handle_button(this->nav, pressed, button, p, NULL)) {
6511                         dbg(1,"navit has handled button\n");
6512                         return;
6513                 }
6514                 dbg(1,"menu_on_map_click=%d\n",this->menu_on_map_click);
6515                 if (button != 1)
6516                         return;
6517                 if (this->on_map_click || this->menu_on_map_click) {
6518                         this->mouse_button_clicked_on_map=1;
6519                         gui_internal_set_click_coord(this, p);
6520                         gui_internal_set_position_coord(this);
6521                         if (this->on_map_click)
6522                                 command_evaluate(&this->self, this->on_map_click);
6523                         else
6524                                 gui_internal_cmd_menu(this, 0, NULL);
6525                         this->mouse_button_clicked_on_map=0;
6526                 } else if (this->signal_on_map_click) {
6527                         gui_internal_dbus_signal(this, p);
6528                         return;
6529                 }
6530                 return;
6531         }
6532
6533
6534         /*
6535          * If already in the menu:
6536          */
6537
6538         if (pressed) {
6539                 this->pressed=1;
6540                 this->current=*p;
6541                 gui_internal_gesture_ring_clear(this);
6542                 gui_internal_gesture_ring_add(this, p);
6543                 gui_internal_highlight(this);
6544         } else {
6545                 int dx,dy;
6546                 gui_internal_gesture_ring_add(this, p);
6547                 gui_internal_gesture_get_vector(this, 300, NULL, &dx, &dy);
6548                 this->current.x=-1;
6549                 this->current.y=-1;
6550                 graphics_draw_mode(gra, draw_mode_begin);
6551                 if(!gui_internal_gesture_do(this) && this->pressed!=2 && abs(dx)<this->icon_s && abs(dy)<this->icon_s)
6552                         gui_internal_call_highlighted(this);
6553                 this->pressed=0;
6554                 if (!event_main_loop_has_quit()) {
6555                         gui_internal_highlight(this);
6556                         graphics_draw_mode(gra, draw_mode_end);
6557                         gui_internal_check_exit(this);
6558                 }
6559         }
6560 }
6561
6562 static void
6563 gui_internal_setup(struct gui_priv *this)
6564 {
6565         struct color cbh={0x9fff,0x9fff,0x9fff,0xffff};
6566         struct color cf={0xbfff,0xbfff,0xbfff,0xffff};
6567         struct graphics *gra=this->gra;
6568         unsigned char *buffer;
6569         char *gui_file;
6570         int size;
6571
6572         if (this->background)
6573                 return;
6574         this->background=graphics_gc_new(gra);
6575         this->background2=graphics_gc_new(gra);
6576         this->highlight_background=graphics_gc_new(gra);
6577         graphics_gc_set_foreground(this->highlight_background, &cbh);
6578         this->foreground=graphics_gc_new(gra);
6579         graphics_gc_set_foreground(this->foreground, &cf);
6580         this->text_background=graphics_gc_new(gra);
6581         this->text_foreground=graphics_gc_new(gra);
6582         graphics_gc_set_foreground(this->background, &this->background_color);
6583         graphics_gc_set_foreground(this->background2, &this->background2_color);
6584         graphics_gc_set_foreground(this->text_background, &this->text_background_color);
6585         graphics_gc_set_foreground(this->text_foreground, &this->text_foreground_color);
6586         gui_file=g_strjoin(NULL, navit_get_user_data_directory(TRUE), "/gui_internal.txt", NULL);
6587         if (file_get_contents(gui_file,&buffer,&size)) {
6588                 char *command=g_malloc(size+1);
6589                 strncpy(command,(const char *)buffer,size);
6590                 command[size]=0;
6591                 command_evaluate(&this->self, command);
6592                 g_free(command);
6593                 g_free(buffer);
6594         }
6595         g_free(gui_file);
6596 }
6597
6598 //##############################################################################################################
6599 //# Description:
6600 //# Comment:
6601 //# Authors: Martin Schaller (04/2008)
6602 //##############################################################################################################
6603 static void gui_internal_resize(void *data, int w, int h)
6604 {
6605         struct gui_priv *this=data;
6606         int changed=0;
6607
6608         gui_internal_setup(this);
6609
6610         if (this->root.w != w || this->root.h != h) {
6611                 this->root.w=w;
6612                 this->root.h=h;
6613                 changed=1;
6614         }
6615         dbg(1,"w=%d h=%d children=%p\n", w, h, this->root.children);
6616         navit_handle_resize(this->nav, w, h);
6617         if (this->root.children) {
6618                 if (changed) {
6619                         gui_internal_html_main_menu(this);
6620                 } else {
6621                         gui_internal_menu_render(this);
6622                 }
6623         }
6624 }
6625
6626 static void
6627 gui_internal_keynav_point(struct widget *w, int dx, int dy, struct point *p)
6628 {
6629         p->x=w->p.x+w->w/2;
6630         p->y=w->p.y+w->h/2;
6631         if (dx < 0)
6632                 p->x=w->p.x;
6633         if (dx > 0)
6634                 p->x=w->p.x+w->w;
6635         if (dy < 0)
6636                 p->y=w->p.y;
6637         if (dy > 0)
6638                 p->y=w->p.y+w->h;
6639 }
6640
6641 static void
6642 gui_internal_keynav_find_closest(struct widget *wi, struct point *p, int dx, int dy, int *distance, struct widget **result)
6643 {
6644         GList *l=wi->children;
6645         // Skip hidden elements
6646         if (wi->p.x==0 && wi->p.y==0 && wi->w==0 && wi->h==0)
6647                 return;
6648         if ((wi->state & STATE_SENSITIVE) ) {
6649                 int dist1,dist2;
6650                 struct point wp;
6651                 gui_internal_keynav_point(wi, -dx, -dy, &wp);
6652                 if (dx) {
6653                         dist1=(wp.x-p->x)*dx;
6654                         dist2=wp.y-p->y;
6655                 } else if (dy) {
6656                         dist1=(wp.y-p->y)*dy;
6657                         dist2=wp.x-p->x;
6658                 } else {
6659                         dist2=wp.x-p->x;
6660                         dist1=wp.y-p->y;
6661                         if (dist1 < 0)
6662                                 dist1=-dist1;
6663                 }
6664                 dbg(1,"checking %d,%d %d %d against %d,%d-%d,%d result %d,%d\n", p->x, p->y, dx, dy, wi->p.x, wi->p.y, wi->p.x+wi->w, wi->p.y+wi->h, dist1, dist2);
6665                 if (dist1 >= 0) {
6666                         if (dist2 < 0)
6667                                 dist1-=dist2;
6668                         else
6669                                 dist1+=dist2;
6670                         if (dist1 < *distance) {
6671                                 *result=wi;
6672                                 *distance=dist1;
6673                         }
6674                 }
6675         }
6676         while (l) {
6677                 struct widget *child=l->data;
6678                 gui_internal_keynav_find_closest(child, p, dx, dy, distance, result);
6679                 l=g_list_next(l);
6680         }
6681 }
6682
6683 static void
6684 gui_internal_keynav_highlight_next(struct gui_priv *this, int dx, int dy)
6685 {
6686         struct widget *result,*menu=g_list_last(this->root.children)->data;
6687         struct point p;
6688         int distance;
6689         if (this->highlighted && this->highlighted_menu == g_list_last(this->root.children)->data)
6690                 gui_internal_keynav_point(this->highlighted, dx, dy, &p);
6691         else {
6692                 p.x=0;
6693                 p.y=0;
6694                 distance=INT_MAX;
6695                 result=NULL;
6696                 gui_internal_keynav_find_closest(menu, &p, 0, 0, &distance, &result);
6697                 if (result) {
6698                         gui_internal_keynav_point(result, dx, dy, &p);
6699                         dbg(1,"result origin=%p p=%d,%d\n", result, p.x, p.y);
6700                 }
6701         }
6702         result=NULL;
6703         distance=INT_MAX;
6704         gui_internal_keynav_find_closest(menu, &p, dx, dy, &distance, &result);
6705         dbg(1,"result=%p\n", result);
6706         if (! result) {
6707                 if (dx < 0)
6708                         p.x=this->root.w;
6709                 if (dx > 0)
6710                         p.x=0;
6711                 if (dy < 0)
6712                         p.y=this->root.h;
6713                 if (dy > 0)
6714                         p.y=0;
6715                 result=NULL;
6716                 distance=INT_MAX;
6717                 gui_internal_keynav_find_closest(menu, &p, dx, dy, &distance, &result);
6718                 dbg(1,"wraparound result=%p\n", result);
6719         }
6720         gui_internal_highlight_do(this, result);
6721         if (result)
6722                 gui_internal_say(this, result, 1);
6723 }
6724
6725 //##############################################################################################################
6726 //# Description:
6727 //# Comment:
6728 //# Authors: Martin Schaller (04/2008)
6729 //##############################################################################################################
6730 static void gui_internal_keypress(void *data, char *key)
6731 {
6732         struct gui_priv *this=data;
6733         int w,h;
6734         struct point p;
6735         if (!this->root.children) {
6736                 transform_get_size(navit_get_trans(this->nav), &w, &h);
6737                 switch (*key) {
6738                 case NAVIT_KEY_UP:
6739                         p.x=w/2;
6740                         p.y=0;
6741                         navit_set_center_screen(this->nav, &p, 1);
6742                         break;
6743                 case NAVIT_KEY_DOWN:
6744                         p.x=w/2;
6745                         p.y=h;
6746                         navit_set_center_screen(this->nav, &p, 1);
6747                         break;
6748                 case NAVIT_KEY_LEFT:
6749                         p.x=0;
6750                         p.y=h/2;
6751                         navit_set_center_screen(this->nav, &p, 1);
6752                         break;
6753                 case NAVIT_KEY_RIGHT:
6754                         p.x=w;
6755                         p.y=h/2;
6756                         navit_set_center_screen(this->nav, &p, 1);
6757                         break;
6758                 case NAVIT_KEY_ZOOM_IN:
6759                         navit_zoom_in(this->nav, 2, NULL);
6760                         break;
6761                 case NAVIT_KEY_ZOOM_OUT:
6762                         navit_zoom_out(this->nav, 2, NULL);
6763                         break;
6764                 case NAVIT_KEY_RETURN:
6765                 case NAVIT_KEY_MENU:
6766                         gui_internal_set_click_coord(this, NULL);
6767                         gui_internal_cmd_menu(this, 0, NULL);
6768                         break;
6769                 }
6770                 return;
6771         }
6772         graphics_draw_mode(this->gra, draw_mode_begin);
6773         switch (*key) {
6774         case NAVIT_KEY_LEFT:
6775                 gui_internal_keynav_highlight_next(this,-1,0);
6776                 break;
6777         case NAVIT_KEY_RIGHT:
6778                 gui_internal_keynav_highlight_next(this,1,0);
6779                 break;
6780         case NAVIT_KEY_UP:
6781                 gui_internal_keynav_highlight_next(this,0,-1);
6782                 break;
6783         case NAVIT_KEY_DOWN:
6784                 gui_internal_keynav_highlight_next(this,0,1);
6785                 break;
6786         case NAVIT_KEY_BACK:
6787                 if (g_list_length(this->root.children) > 1)
6788                         gui_internal_back(this, NULL, NULL);
6789                 else
6790                         gui_internal_prune_menu(this, NULL);
6791                 break;
6792         case NAVIT_KEY_RETURN:
6793                 if (this->highlighted && this->highlighted_menu == g_list_last(this->root.children)->data)
6794                         gui_internal_call_highlighted(this);
6795                 else
6796                         gui_internal_keypress_do(this, key);
6797                 break;
6798         default:
6799                 gui_internal_keypress_do(this, key);
6800         }
6801         if (!event_main_loop_has_quit()) {
6802                 graphics_draw_mode(this->gra, draw_mode_end);
6803                 gui_internal_check_exit(this);
6804         }
6805 }
6806
6807
6808 //##############################################################################################################
6809 //# Description:
6810 //# Comment:
6811 //# Authors: Martin Schaller (04/2008)
6812 //##############################################################################################################
6813 static int gui_internal_set_graphics(struct gui_priv *this, struct graphics *gra)
6814 {
6815         struct window *win;
6816         struct transformation *trans=navit_get_trans(this->nav);
6817
6818         win=graphics_get_data(gra, "window");
6819         if (! win)
6820                 return 1;
6821         navit_ignore_graphics_events(this->nav, 1);
6822         this->gra=gra;
6823         this->win=win;
6824         navit_ignore_graphics_events(this->nav, 1);
6825         transform_get_size(trans, &this->root.w, &this->root.h);
6826         this->resize_cb=callback_new_attr_1(callback_cast(gui_internal_resize), attr_resize, this);
6827         graphics_add_callback(gra, this->resize_cb);
6828         this->button_cb=callback_new_attr_1(callback_cast(gui_internal_button), attr_button, this);
6829         graphics_add_callback(gra, this->button_cb);
6830         this->motion_cb=callback_new_attr_1(callback_cast(gui_internal_motion), attr_motion, this);
6831         graphics_add_callback(gra, this->motion_cb);
6832         this->keypress_cb=callback_new_attr_1(callback_cast(gui_internal_keypress), attr_keypress, this);
6833         graphics_add_callback(gra, this->keypress_cb);
6834         this->window_closed_cb=callback_new_attr_1(callback_cast(gui_internal_window_closed), attr_window_closed, this);
6835         graphics_add_callback(gra, this->window_closed_cb);
6836
6837         // set fullscreen if needed
6838         if (this->fullscreen)
6839                 this->win->fullscreen(this->win, this->fullscreen != 0);
6840         /* Was resize callback already issued? */
6841         if (navit_get_ready(this->nav) & 2)
6842                 gui_internal_setup(this);
6843         return 0;
6844 }
6845
6846 static void gui_internal_disable_suspend(struct gui_priv *this)
6847 {
6848         if (this->win->disable_suspend)
6849                 this->win->disable_suspend(this->win);
6850 }
6851
6852 //##############################################################################################################
6853 //# Description:
6854 //# Comment:
6855 //# Authors: Martin Schaller (04/2008)
6856 //##############################################################################################################
6857 struct gui_methods gui_internal_methods = {
6858         NULL,
6859         NULL,
6860         gui_internal_set_graphics,
6861         NULL,
6862         NULL,
6863         NULL,
6864         gui_internal_disable_suspend,
6865         gui_internal_get_attr,
6866         gui_internal_add_attr,
6867         gui_internal_set_attr,
6868 };
6869
6870         static void
6871 gui_internal_get_data(struct gui_priv *priv, char *command, struct attr **in, struct attr ***out)
6872 {
6873         struct attr private_data = { attr_private_data, {(void *)&priv->data}};
6874         if (out)
6875                 *out=attr_generic_add_attr(*out, &private_data);
6876 }
6877
6878 static void
6879 gui_internal_add_callback(struct gui_priv *priv, struct callback *cb)
6880 {
6881         callback_list_add(priv->cbl, cb);
6882 }
6883
6884 static void
6885 gui_internal_remove_callback(struct gui_priv *priv, struct callback *cb)
6886 {
6887         callback_list_remove(priv->cbl, cb);
6888 }
6889
6890
6891 static struct gui_internal_methods gui_internal_methods_ext = {
6892         gui_internal_add_callback,
6893         gui_internal_remove_callback,
6894         gui_internal_menu_render,
6895         image_new_xs,
6896         image_new_l,
6897 };
6898
6899
6900 static enum flags
6901 gui_internal_get_flags(struct widget *widget)
6902 {
6903         return widget->flags;
6904 }
6905
6906 static void
6907 gui_internal_set_flags(struct widget *widget, enum flags flags)
6908 {
6909         widget->flags=flags;
6910 }
6911
6912 static int
6913 gui_internal_get_state(struct widget *widget)
6914 {
6915         return widget->state;
6916 }
6917
6918 static void
6919 gui_internal_set_state(struct widget *widget, int state)
6920 {
6921         widget->state=state;
6922 }
6923
6924 static void
6925 gui_internal_set_func(struct widget *widget, void (*func)(struct gui_priv *priv, struct widget *widget, void *data))
6926 {
6927         widget->func=func;
6928 }
6929
6930 static void
6931 gui_internal_set_data(struct widget *widget, void *data)
6932 {
6933         widget->data=data;
6934 }
6935
6936 static void
6937 gui_internal_set_default_background(struct gui_priv *this, struct widget *widget)
6938 {
6939         widget->background=this->background;
6940 }
6941
6942 static struct gui_internal_widget_methods gui_internal_widget_methods = {
6943         gui_internal_widget_append,
6944         gui_internal_button_new,
6945         gui_internal_button_new_with_callback,
6946         gui_internal_box_new,
6947         gui_internal_label_new,
6948         gui_internal_image_new,
6949         gui_internal_keyboard,
6950         gui_internal_menu,
6951         gui_internal_get_flags,
6952         gui_internal_set_flags,
6953         gui_internal_get_state,
6954         gui_internal_set_state,
6955         gui_internal_set_func,
6956         gui_internal_set_data,
6957         gui_internal_set_default_background,
6958 };
6959
6960 static void
6961 gui_internal_cmd_write(struct gui_priv * this, char *function, struct attr **in, struct attr ***out, int *valid)
6962 {
6963         char *str=NULL,*str2=NULL;
6964         dbg(1,"enter %s %p %p %p\n",function,in,out,valid);
6965         if (!in || !in[0])
6966                 return;
6967         dbg(1,"%s\n",attr_to_name(in[0]->type));
6968         if (ATTR_IS_STRING(in[0]->type)) {
6969                 str=in[0]->u.str;
6970         }
6971         if (ATTR_IS_COORD_GEO(in[0]->type)) {
6972                 str=str2=coordinates_geo(in[0]->u.coord_geo, '\n');
6973         }
6974         if (str) {
6975                 str=g_strdup_printf("<html>%s</html>\n",str);
6976                 xml_parse_text(str, this, gui_internal_html_start, gui_internal_html_end, gui_internal_html_text);
6977         }
6978         g_free(str);
6979         g_free(str2);
6980 }
6981
6982
6983 /**
6984  * @brief Creates a new table widget.
6985  *
6986  * Creates and returns a new table widget.  This function will
6987  * setup next/previous buttons as children.
6988  *
6989  * @param this The graphics context.
6990  * @param flags widget sizing flags.
6991  * @returns The newly created widget
6992  */
6993 struct widget * gui_internal_widget_table_new(struct gui_priv * this, enum flags flags, int buttons)
6994 {
6995         struct widget * widget = g_new0(struct widget,1);
6996         struct table_data * data = NULL;
6997         widget->type=widget_table;
6998         widget->flags=flags;
6999         widget->state=STATE_SCROLLABLE;
7000         widget->data=g_new0(struct table_data,1);
7001         widget->data_free=gui_internal_table_data_free;
7002
7003         // We have to set background here explicitly
7004         // because it will be used by inner elements created later in this 
7005         // function (navigation buttons). Else that elements won't have
7006         // any background.
7007         widget->background=this->background;
7008         data = (struct table_data*)widget->data;
7009
7010         if (buttons) {
7011                 data->next_button=gui_internal_box_new(this, gravity_center|orientation_horizontal);
7012                 gui_internal_widget_append(data->next_button, gui_internal_text_new(this,_("Next"),gravity_center|orientation_horizontal));
7013                 gui_internal_widget_append(data->next_button, gui_internal_image_new(this, image_new_xs(this, "gui_arrow_right")));
7014                 data->next_button->func=gui_internal_table_button_next;
7015                 data->next_button->data=widget;
7016
7017
7018                 data->prev_button =  gui_internal_button_new_with_callback
7019                         (this, _("Prev"),
7020                         image_new_xs(this, "gui_arrow_left"),
7021                         gravity_center |orientation_horizontal,
7022                         gui_internal_table_button_prev,NULL);
7023
7024                 data->prev_button->data=widget;
7025
7026                 data->this=this;
7027
7028                 data->button_box=gui_internal_box_new(this,
7029                                               gravity_center|orientation_horizontal);
7030                 gui_internal_widget_append(widget, data->button_box);
7031                 gui_internal_widget_append(data->button_box, data->prev_button);
7032                 gui_internal_widget_append(data->button_box, data->next_button);
7033
7034                 data->button_box->bl=this->spacing;
7035                 gui_internal_widget_pack(this,data->button_box);
7036         }
7037
7038         return widget;
7039
7040 }
7041
7042 /**
7043  * @brief Clears all the rows from the table.
7044  * This function removes all rows from a table.
7045  * New rows can later be added to the table.
7046  */
7047 void gui_internal_widget_table_clear(struct gui_priv * this,struct widget * table)
7048 {
7049   GList * iter;
7050   struct table_data * table_data = (struct table_data* ) table->data;
7051
7052   iter = table->children;
7053   while(iter ) {
7054           if(iter->data != table_data->button_box) {
7055                   struct widget * child = (struct widget*)iter->data;
7056                   gui_internal_widget_destroy(this,child);
7057                   if(table->children == iter) {
7058                           table->children = g_list_remove(iter,iter->data);
7059                           iter=table->children;
7060                   }
7061                   else
7062                           iter = g_list_remove(iter,iter->data);
7063           }
7064           else {
7065                   iter = g_list_next(iter);
7066           }
7067
7068   }
7069   table_data->top_row=NULL;
7070   table_data->bottom_row=NULL;
7071 }
7072
7073 /**
7074  * @brief Check if table has any data rows filled.
7075  * @param this The graphics context
7076  * @param table table widget
7077  * @returns 1 if the table is empty, 0 if there any data rows present.
7078  */
7079 static int gui_internal_widget_table_is_empty(struct gui_priv *this, struct widget * table)
7080 {
7081    GList *l;
7082    struct table_data *td=(struct table_data*) table->data;
7083
7084    for(l=table->children;l;l=g_list_next(l)) {
7085         if(l->data != td->button_box)
7086                 return 0;
7087    }
7088
7089    return 1;
7090 }
7091
7092 /**
7093  * @brief Move GList pointer to the next table row, skipping other table children (button box, for example).
7094  * @param row GList pointer into the children list 
7095  * @returns GList pointer to the next row in the children list, or NULL if there are no any rows left.
7096  */
7097 static GList * gui_internal_widget_table_next_row(GList * row)
7098 {
7099   while((row=g_list_next(row))!=NULL) {
7100         if(row->data && ((struct widget *)(row->data))->type == widget_table_row)
7101                 break;
7102    }
7103   return row;
7104 }
7105
7106 /**
7107  * @brief Move GList pointer to the previous table row, skipping other table children (button box, for example).
7108  * @param row GList pointer into the children list 
7109  * @returns GList pointer to the previous row in the children list, or NULL if there are no any rows left.
7110  */
7111 static GList * gui_internal_widget_table_prev_row(GList * row)
7112 {
7113   while((row=g_list_previous(row))!=NULL) {
7114         if(row->data && ((struct widget *)(row->data))->type == widget_table_row)
7115                 break;
7116    }
7117   return row;
7118 }
7119
7120
7121 /**
7122  * Creates a new table_row widget.
7123  * @param this The graphics context
7124  * @param flags Sizing flags for the row
7125  * @returns The new table_row widget.
7126  */
7127 struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags)
7128 {
7129         struct widget * widget = g_new0(struct widget,1);
7130         widget->type=widget_table_row;
7131         widget->flags=flags;
7132         return widget;
7133 }
7134
7135
7136
7137 /**
7138  * @brief Computes the column dimensions for the table.
7139  *
7140  * @param w The table widget to compute dimensions for.
7141  *
7142  * This function examines all of the rows and columns for the table w
7143  * and returns a list (GList) of table_column_desc elements that
7144  * describe each column of the table.
7145  *
7146  * The caller is responsible for freeing the returned list.
7147  */
7148 static GList * gui_internal_compute_table_dimensions(struct gui_priv * this,struct widget * w)
7149 {
7150
7151         GList * column_desc = NULL;
7152         GList * current_desc=NULL;
7153         GList * cur_row = w->children;
7154         struct widget * cur_row_widget=NULL;
7155         GList * cur_column=NULL;
7156         struct widget * cell_w=NULL;
7157         struct table_column_desc * current_cell=NULL;
7158         struct table_data * table_data=NULL;
7159         int height=0;
7160         int width=0;
7161         int total_width=0;
7162         int column_count=0;
7163
7164         /**
7165          * Scroll through the the table and
7166          * 1. Compute the maximum width + height of each column across all rows.
7167          */
7168         table_data = (struct table_data*) w->data;
7169         for(cur_row=w->children;  cur_row ; cur_row = g_list_next(cur_row) )
7170         {
7171                 cur_row_widget = (struct widget*) cur_row->data;
7172                 current_desc = column_desc;
7173                 if(cur_row_widget == table_data->button_box)
7174                 {
7175                         continue;
7176                 }
7177                 column_count=0;
7178                 for(cur_column = cur_row_widget->children; cur_column;
7179                     cur_column=g_list_next(cur_column))
7180                 {
7181                         cell_w = (struct widget*) cur_column->data;
7182                         gui_internal_widget_pack(this,cell_w);
7183                         if(current_desc == 0)
7184                         {
7185                                 current_cell = g_new0(struct table_column_desc,1);
7186                                 column_desc = g_list_append(column_desc,current_cell);
7187                                 current_desc = g_list_last(column_desc);
7188                                 current_cell->height=cell_w->h;
7189                                 current_cell->width=cell_w->w;
7190                                 total_width+=cell_w->w;
7191
7192                         }
7193                         else
7194                         {
7195                                 current_cell = current_desc->data;
7196                                 height = cell_w->h;
7197                                 width = cell_w->w;
7198                                 if(current_cell->height < height )
7199                                 {
7200                                         current_cell->height = height;
7201                                 }
7202                                 if(current_cell->width < width)
7203                                 {
7204                                         total_width += (width-current_cell->width);
7205                                         current_cell->width = width;
7206
7207
7208
7209                                 }
7210                                 current_desc = g_list_next(current_desc);
7211                         }
7212                         column_count++;
7213
7214                 }/* column loop */
7215
7216         } /*row loop */
7217
7218
7219         /**
7220          * If the width of all columns is less than the width off
7221          * the table expand each cell proportionally.
7222          *
7223          */
7224         if(total_width+(this->spacing*column_count) < w->w ) {
7225                 for(current_desc=column_desc; current_desc; current_desc=g_list_next(current_desc)) {
7226                         current_cell = (struct table_column_desc*) current_desc->data;
7227                         current_cell->width= ( (current_cell->width+this->spacing)/(float)total_width) * w->w ;
7228                 }
7229         }
7230
7231         return column_desc;
7232 }
7233
7234
7235 /**
7236  * @brief Computes the height and width for the table.
7237  *
7238  * The height and widht are computed to display all cells in the table
7239  * at the requested height/width.
7240  *
7241  * @param this The graphics context
7242  * @param w The widget to pack.
7243  *
7244  */
7245 void gui_internal_table_pack(struct gui_priv * this, struct widget * w)
7246 {
7247
7248         int height=0;
7249         int width=0;
7250         int count=0;
7251         GList * column_data = gui_internal_compute_table_dimensions(this,w);
7252         GList * current=0;
7253         struct table_column_desc * cell_desc=0;
7254         struct table_data * table_data = (struct table_data*)w->data;
7255
7256         for(current = column_data; current; current=g_list_next(current))
7257         {
7258                 if(table_data->button_box == current->data )
7259                 {
7260                         continue;
7261                 }
7262                 cell_desc = (struct table_column_desc *) current->data;
7263                 width = width + cell_desc->width + this->spacing;
7264                 if(height < cell_desc->height)
7265                 {
7266                         height = cell_desc->height ;
7267                 }
7268         }
7269
7270
7271
7272         for(current=w->children; current; current=g_list_next(current))
7273         {
7274                 if(current->data!= table_data->button_box)
7275                 {
7276                         count++;
7277                 }
7278         }
7279
7280         w->w = width;
7281         if(w->w + w->c.x > this->root.w)
7282         {
7283                 w->w = this->root.w - w->c.x;
7284         }
7285
7286
7287         if(w->h + w->c.y   > this->root.h   )
7288         {
7289                 /**
7290                  * Do not allow the widget to exceed the screen.
7291                  *
7292                  */
7293                 w->h = this->root.h- w->c.y  - height;
7294         }
7295
7296         if (table_data->button_box) 
7297         {
7298                 gui_internal_widget_pack(this,table_data->button_box);
7299         }
7300
7301
7302         /**
7303          * Deallocate column descriptions.
7304          */
7305         g_list_foreach(column_data,(GFunc)g_free,NULL);
7306         g_list_free(column_data);
7307 }
7308
7309
7310
7311
7312 /**
7313  * @brief Invalidates coordinates for previosly rendered table widget rows.
7314  *
7315  * @param table_data Data from the table object.
7316  */
7317 static void gui_internal_table_hide_rows(struct table_data * table_data)
7318 {
7319         GList*cur_row;
7320         for(cur_row=table_data->top_row; cur_row ; cur_row = g_list_next(cur_row))
7321         {
7322                 struct widget * cur_row_widget = (struct widget*)cur_row->data;
7323                 if (cur_row_widget->type!=widget_table_row)
7324                         continue;
7325                 cur_row_widget->p.x=0;
7326                 cur_row_widget->p.y=0;
7327                 cur_row_widget->w=0;
7328                 cur_row_widget->h=0;
7329                 if(cur_row==table_data->bottom_row)
7330                         break;
7331         }
7332 }
7333
7334
7335 /**
7336  * @brief Renders a table widget.
7337  *
7338  * @param this The graphics context
7339  * @param w The table widget to render.
7340  */
7341 void gui_internal_table_render(struct gui_priv * this, struct widget * w)
7342 {
7343
7344         int x;
7345         int y;
7346         GList * column_desc=NULL;
7347         GList * cur_row = NULL;
7348         GList * current_desc=NULL;
7349         struct table_data * table_data = (struct table_data*)w->data;
7350         int is_skipped=0;
7351         int is_first_page=1;
7352         struct table_column_desc * dim=NULL;
7353
7354         dbg_assert(table_data);
7355         column_desc = gui_internal_compute_table_dimensions(this,w);
7356         if(!column_desc)
7357                 return;
7358         y=w->p.y;
7359         gui_internal_table_hide_rows(table_data);
7360         /**
7361          * Skip rows that are on previous pages.
7362          */
7363         cur_row = w->children;
7364         if(table_data->top_row && table_data->top_row != w->children && !table_data->button_box_hide)
7365         {
7366                 cur_row = table_data->top_row;
7367                 is_first_page=0;
7368         } else {
7369                 table_data->top_row=NULL;
7370         }
7371         /**
7372          * Loop through each row.  Drawing each cell with the proper sizes,
7373          * at the proper positions.
7374          */
7375         for(table_data->top_row=cur_row; cur_row; cur_row = g_list_next(cur_row))
7376         {
7377                 int max_height=0, bbox_height=0;
7378                 struct widget * cur_row_widget;
7379                 GList * cur_column=NULL;
7380                 current_desc = column_desc;
7381                 cur_row_widget = (struct widget*)cur_row->data;
7382                 x =w->p.x+this->spacing;
7383                 if(cur_row_widget == table_data->button_box )
7384                 {
7385                         continue;
7386                 }
7387                 dim = (struct table_column_desc*)current_desc->data;
7388
7389                 if (table_data->button_box && !table_data->button_box_hide)
7390                         bbox_height=table_data->button_box->h;
7391
7392                 if( y + dim->height + bbox_height + this->spacing >= w->p.y + w->h )
7393                 {
7394                         /*
7395                          * No more drawing space left.
7396                          */
7397                         is_skipped=1;
7398                         break;
7399                 }
7400                 for(cur_column = cur_row_widget->children; cur_column;
7401                     cur_column=g_list_next(cur_column))
7402                 {
7403                         struct  widget * cur_widget = (struct widget*) cur_column->data;
7404                         dim = (struct table_column_desc*)current_desc->data;
7405
7406                         cur_widget->p.x=x;
7407                         cur_widget->w=dim->width;
7408                         cur_widget->p.y=y;
7409                         cur_widget->h=dim->height;
7410                         x=x+cur_widget->w;
7411                         max_height = dim->height;
7412                         /* We pack the widget before rendering to ensure that the x and y
7413                          * coordinates get pushed down.
7414                          */
7415                         gui_internal_widget_pack(this,cur_widget);
7416                         gui_internal_widget_render(this,cur_widget);
7417
7418                         if(dim->height > max_height)
7419                         {
7420                                 max_height = dim->height;
7421                         }
7422                 }
7423                 
7424                 /* Row object should have its coordinates in actual
7425                  * state to be able to pass mouse clicks to Column objects
7426                  */
7427                 cur_row_widget->p.x=w->p.x;
7428                 cur_row_widget->w=w->w;
7429                 cur_row_widget->p.y=y;
7430                 cur_row_widget->h=max_height;
7431                 y = y + max_height;
7432                 table_data->bottom_row=cur_row;
7433                 current_desc = g_list_next(current_desc);
7434         }
7435         if(table_data->button_box && (is_skipped || !is_first_page) && !table_data->button_box_hide )
7436         {
7437                 table_data->button_box->p.y =w->p.y+w->h-table_data->button_box->h -
7438                         this->spacing;
7439                 if(table_data->button_box->p.y < y )
7440                 {
7441                         table_data->button_box->p.y=y;
7442                 }
7443                 table_data->button_box->p.x = w->p.x;
7444                 table_data->button_box->w = w->w;
7445                 //    table_data->button_box->h = w->h - y;
7446                 //    table_data->next_button->h=table_data->button_box->h;
7447                 //    table_data->prev_button->h=table_data->button_box->h;
7448                 //    table_data->next_button->c.y=table_data->button_box->c.y;
7449                 //    table_data->prev_button->c.y=table_data->button_box->c.y;
7450                 gui_internal_widget_pack(this,table_data->button_box);
7451                 if(table_data->next_button->p.y > w->p.y + w->h + table_data->next_button->h)
7452                 {
7453                         table_data->button_box->p.y = w->p.y + w->h -
7454                                 table_data->button_box->h;
7455                 }
7456                 if(is_skipped)
7457                 {
7458                         table_data->next_button->state|= STATE_SENSITIVE;
7459                 }
7460                 else
7461                 {
7462                         table_data->next_button->state&= ~STATE_SENSITIVE;
7463                 }
7464
7465                 if(table_data->top_row != w->children)
7466                 {
7467                         table_data->prev_button->state|= STATE_SENSITIVE;
7468                 }
7469                 else
7470                 {
7471                         table_data->prev_button->state&= ~STATE_SENSITIVE;
7472                 }
7473                 gui_internal_widget_render(this,table_data->button_box);
7474         }
7475
7476         /**
7477          * Deallocate column descriptions.
7478          */
7479         g_list_foreach(column_desc,(GFunc)g_free,NULL);
7480         g_list_free(column_desc);
7481 }
7482
7483
7484 /**
7485  * @brief Displays Route information
7486  *
7487  * @li The name of the active vehicle
7488  * @param wm The button that was pressed.
7489  * @param v Unused
7490  */
7491 static void
7492 gui_internal_cmd2_route_description(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
7493 {
7494
7495
7496         struct widget * menu;
7497         struct widget * row;
7498         struct widget * box;
7499
7500
7501         if(! this->vehicle_cb)
7502         {
7503           /**
7504            * Register the callback on vehicle updates.
7505            */
7506           this->vehicle_cb = callback_new_attr_1(callback_cast(gui_internal_route_update),
7507                                                        attr_position_coord_geo,this);
7508           navit_add_callback(this->nav,this->vehicle_cb);
7509         }
7510
7511         this->route_data.route_table = gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
7512
7513         row = gui_internal_widget_table_row_new(this,gravity_left | orientation_horizontal | flags_fill);
7514
7515
7516         menu=gui_internal_menu(this,_("Route Description"));
7517
7518         menu->free=gui_internal_route_screen_free;
7519         this->route_data.route_showing=1;
7520         this->route_data.route_table->spx = this->spacing;
7521
7522
7523         box = gui_internal_box_new(this, gravity_left_top| orientation_vertical | flags_fill | flags_expand);
7524
7525         //      gui_internal_widget_append(box,gui_internal_box_new_with_label(this,"Test"));
7526         gui_internal_widget_append(box,this->route_data.route_table);
7527         box->w=menu->w;
7528         box->spx = this->spacing;
7529         this->route_data.route_table->w=box->w;
7530         gui_internal_widget_append(menu,box);
7531         gui_internal_populate_route_table(this,this->nav);
7532         gui_internal_menu_render(this);
7533
7534 }
7535
7536 static int
7537 line_intersection(struct coord* a1, struct coord *a2, struct coord * b1, struct coord *b2, struct coord *res)
7538 {
7539         int n, a, b;
7540         int adx=a2->x-a1->x;
7541         int ady=a2->y-a1->y;
7542         int bdx=b2->x-b1->x;
7543         int bdy=b2->y-b1->y;
7544         n = bdy * adx - bdx * ady;
7545         a = bdx * (a1->y - b1->y) - bdy * (a1->x - b1->x);
7546         b = adx * (a1->y - b1->y) - ady * (a1->x - b1->x);
7547         if (n < 0) {
7548                 n = -n;
7549                 a = -a;
7550                 b = -b;
7551         }
7552         if (a < 0 || b < 0)
7553                 return 0;
7554         if (a > n || b > n)
7555                 return 0;
7556         if (n == 0) {
7557                 dbg(0,"a=%d b=%d n=%d\n", a, b, n);
7558                 dbg(0,"a1=0x%x,0x%x ad %d,%d\n", a1->x, a1->y, adx, ady);
7559                 dbg(0,"b1=0x%x,0x%x bd %d,%d\n", b1->x, b1->y, bdx, bdy);
7560                 dbg_assert(n != 0);
7561         }
7562         res->x = a1->x + a * adx / n;
7563         res->y = a1->y + a * ady / n;
7564         return 1;
7565 }
7566
7567 struct heightline {
7568         struct heightline *next;
7569         int height;
7570         struct coord_rect bbox;
7571         int count;
7572         struct coord c[0];
7573 };
7574
7575 struct diagram_point {
7576         struct diagram_point *next;
7577         struct coord c;
7578 };
7579
7580 static struct heightline *
7581 item_get_heightline(struct item *item)
7582 {
7583         struct heightline *ret=NULL;
7584         struct street_data *sd;
7585         struct attr attr;
7586         int i,height;
7587
7588         if (item_attr_get(item, attr_label, &attr)) {
7589                 height=atoi(attr.u.str);
7590                 sd=street_get_data(item);
7591                 if (sd && sd->count > 1) {
7592                         ret=g_malloc(sizeof(struct heightline)+sd->count*sizeof(struct coord));
7593                         ret->bbox.lu=sd->c[0];
7594                         ret->bbox.rl=sd->c[0];
7595                         ret->count=sd->count;
7596                         ret->height=height;
7597                         for (i = 0 ; i < sd->count ; i++) {
7598                                 ret->c[i]=sd->c[i];
7599                                 coord_rect_extend(&ret->bbox, sd->c+i);
7600                         }
7601                 }
7602                 street_data_free(sd);
7603         }
7604         return ret;
7605 }
7606
7607
7608 /**
7609  * @brief Displays Route Height Profile
7610  *
7611  * @li The name of the active vehicle
7612  * @param wm The button that was pressed.
7613  * @param v Unused
7614  */
7615 static void
7616 gui_internal_cmd2_route_height_profile(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
7617 {
7618
7619
7620         struct widget * menu, *box;
7621
7622         struct map * map=NULL;
7623         struct map_rect * mr=NULL;
7624         struct route * route;
7625         struct item * item =NULL;
7626         struct mapset *ms;
7627         struct mapset_handle *msh;
7628         int x,i,first=1,dist=0;
7629         struct coord c,last,res;
7630         struct coord_rect rbbox,dbbox;
7631         struct map_selection sel;
7632         struct heightline *heightline,*heightlines=NULL;
7633         struct diagram_point *min,*diagram_point,*diagram_points=NULL;
7634         sel.next=NULL;
7635         sel.order=18;
7636         sel.range.min=type_height_line_1;
7637         sel.range.max=type_height_line_3;
7638
7639
7640         menu=gui_internal_menu(this,_("Height Profile"));
7641         box = gui_internal_box_new(this, gravity_left_top| orientation_vertical | flags_fill | flags_expand);
7642         gui_internal_widget_append(menu, box);
7643         route = navit_get_route(this->nav);
7644         if (route)
7645                 map = route_get_map(route);
7646         if(map)
7647                 mr = map_rect_new(map,NULL);
7648         if(mr) {
7649                 while((item = map_rect_get_item(mr))) {
7650                         while (item_coord_get(item, &c, 1)) {
7651                                 if (first) {
7652                                         first=0;
7653                                         sel.u.c_rect.lu=c;
7654                                         sel.u.c_rect.rl=c;
7655                                 } else
7656                                         coord_rect_extend(&sel.u.c_rect, &c);
7657                         }
7658                 }
7659                 map_rect_destroy(mr);
7660                 ms=navit_get_mapset(this->nav);
7661                 if (!first && ms) {
7662                         msh=mapset_open(ms);
7663                         while ((map=mapset_next(msh, 1))) {
7664                                 mr=map_rect_new(map, &sel);
7665                                 if (mr) {
7666                                         while((item = map_rect_get_item(mr))) {
7667                                                 if (item->type >= sel.range.min && item->type <= sel.range.max) {
7668                                                         heightline=item_get_heightline(item);
7669                                                         if (heightline) {
7670                                                                 heightline->next=heightlines;
7671                                                                 heightlines=heightline;
7672                                                         }
7673                                                 }
7674                                         }
7675                                         map_rect_destroy(mr);
7676                                 }
7677                         }
7678                         mapset_close(msh);
7679                 }
7680         }
7681         map=NULL;
7682         mr=NULL;
7683         if (route)
7684                 map = route_get_map(route);
7685         if(map)
7686                 mr = map_rect_new(map,NULL);
7687         if(mr && heightlines) {
7688                 while((item = map_rect_get_item(mr))) {
7689                         first=1;
7690                         while (item_coord_get(item, &c, 1)) {
7691                                 if (first)
7692                                         first=0;
7693                                 else {
7694                                         heightline=heightlines;
7695                                         rbbox.lu=last;
7696                                         rbbox.rl=last;
7697                                         coord_rect_extend(&rbbox, &c);
7698                                         while (heightline) {
7699                                                 if (coord_rect_overlap(&rbbox, &heightline->bbox)) {
7700                                                         for (i = 0 ; i < heightline->count - 1; i++) {
7701                                                                 if (heightline->c[i].x != heightline->c[i+1].x || heightline->c[i].y != heightline->c[i+1].y) {
7702                                                                         if (line_intersection(heightline->c+i, heightline->c+i+1, &last, &c, &res)) {
7703                                                                                 diagram_point=g_new(struct diagram_point, 1);
7704                                                                                 diagram_point->c.x=dist+transform_distance(projection_mg, &last, &res);
7705                                                                                 diagram_point->c.y=heightline->height;
7706                                                                                 diagram_point->next=diagram_points;
7707                                                                                 diagram_points=diagram_point;
7708                                                                                 dbg(0,"%d %d\n", diagram_point->c.x, diagram_point->c.y);
7709                                                                         }
7710                                                                 }
7711                                                         }
7712                                                 }
7713                                                 heightline=heightline->next;
7714                                         }
7715                                         dist+=transform_distance(projection_mg, &last, &c);
7716                                 }
7717                                 last=c;
7718                         }
7719
7720                 }
7721                 map_rect_destroy(mr);
7722         }
7723
7724
7725         gui_internal_menu_render(this);
7726         first=1;
7727         diagram_point=diagram_points;
7728         while (diagram_point) {
7729                 if (first) {
7730                         dbbox.lu=diagram_point->c;
7731                         dbbox.rl=diagram_point->c;
7732                         first=0;
7733                 } else
7734                         coord_rect_extend(&dbbox, &diagram_point->c);
7735                 diagram_point=diagram_point->next;
7736         }
7737         dbg(0,"%d %d %d %d\n", dbbox.lu.x, dbbox.lu.y, dbbox.rl.x, dbbox.rl.y);
7738         if (dbbox.rl.x > dbbox.lu.x && dbbox.lu.x*100/(dbbox.rl.x-dbbox.lu.x) <= 25)
7739                 dbbox.lu.x=0;
7740         if (dbbox.lu.y > dbbox.rl.y && dbbox.rl.y*100/(dbbox.lu.y-dbbox.rl.y) <= 25)
7741                 dbbox.rl.y=0;
7742         dbg(0,"%d,%d %dx%d\n", box->p.x, box->p.y, box->w, box->h);
7743         x=dbbox.lu.x;
7744         first=1;
7745         for (;;) {
7746                 struct point p[2];
7747                 min=NULL;
7748                 diagram_point=diagram_points;
7749                 while (diagram_point) {
7750                         if (diagram_point->c.x >= x && (!min || min->c.x > diagram_point->c.x))
7751                                 min=diagram_point;
7752                         diagram_point=diagram_point->next;
7753                 }
7754                 if (! min)
7755                         break;
7756                 p[1].x=(min->c.x-dbbox.lu.x)*(box->w-10)/(dbbox.rl.x-dbbox.lu.x)+box->p.x+5;
7757                 p[1].y=(min->c.y-dbbox.rl.y)*(box->h-10)/(dbbox.lu.y-dbbox.rl.y)+box->p.y+5;
7758                 dbg(0,"%d,%d=%d,%d\n",min->c.x, min->c.y, p[1].x,p[1].y);
7759                 graphics_draw_circle(this->gra, this->foreground, &p[1], 2);
7760                 if (first)
7761                         first=0;
7762                 else
7763                         graphics_draw_lines(this->gra, this->foreground, p, 2);
7764                 p[0]=p[1];
7765                 x=min->c.x+1;
7766         }
7767
7768
7769 }
7770
7771
7772 static void
7773 gui_internal_cmd2_locale(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
7774 {
7775         struct widget *menu,*wb,*w;
7776         char *text;
7777
7778         graphics_draw_mode(this->gra, draw_mode_begin);
7779         menu=gui_internal_menu(this, _("Show Locale"));
7780         menu->spx=this->spacing*10;
7781         wb=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
7782         gui_internal_widget_append(menu, wb);
7783         text=g_strdup_printf("LANG=%1$s (1=%3$s 2=%2$s)",getenv("LANG"),"2","1");
7784         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7785         w->flags=gravity_left_center|orientation_horizontal|flags_fill;
7786         g_free(text);
7787 #ifdef HAVE_API_WIN32_BASE
7788         {
7789                 char country[32],lang[32];
7790 #ifdef HAVE_API_WIN32_CE
7791                 wchar_t wcountry[32],wlang[32];
7792
7793                 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, wlang, sizeof(wlang));
7794                 WideCharToMultiByte(CP_ACP,0,wlang,-1,lang,sizeof(lang),NULL,NULL);
7795 #else
7796                 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, lang, sizeof(lang));
7797 #endif
7798                 text=g_strdup_printf("LOCALE_SABBREVLANGNAME=%s",lang);
7799                 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7800                 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
7801                 g_free(text);
7802 #ifdef HAVE_API_WIN32_CE
7803                 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVCTRYNAME, wcountry, sizeof(wcountry));
7804                 WideCharToMultiByte(CP_ACP,0,wcountry,-1,country,sizeof(country),NULL,NULL);
7805 #else
7806                 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVCTRYNAME, country, sizeof(country));
7807 #endif
7808                 text=g_strdup_printf("LOCALE_SABBREVCTRYNAME=%s",country);
7809                 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7810                 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
7811                 g_free(text);
7812         }
7813 #endif
7814
7815         gui_internal_menu_render(this);
7816         graphics_draw_mode(this->gra, draw_mode_end);
7817 }
7818
7819 static void
7820 gui_internal_cmd2_about(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
7821 {
7822         struct widget *menu,*wb,*w;
7823         char *text;
7824
7825         graphics_draw_mode(this->gra, draw_mode_begin);
7826         menu=gui_internal_menu(this, _("About Navit"));
7827         menu->spx=this->spacing*10;
7828         wb=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand);
7829         gui_internal_widget_append(menu, wb);
7830
7831         //Icon
7832         gui_internal_widget_append(wb, w=gui_internal_image_new(this, image_new_xs(this, "navit")));
7833         w->flags=gravity_top_center|orientation_horizontal|flags_fill;
7834
7835         //app name
7836         text=g_strdup_printf("%s",PACKAGE_NAME);
7837         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7838         w->flags=gravity_top_center|orientation_horizontal|flags_expand;
7839         g_free(text);
7840
7841         //Version
7842         text=g_strdup_printf("%s",version);
7843         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7844         w->flags=gravity_top_center|orientation_horizontal|flags_expand;
7845         g_free(text);
7846
7847         //Site
7848         text=g_strdup_printf("http://www.navit-project.org/");
7849         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7850         w->flags=gravity_top_center|orientation_horizontal|flags_expand;
7851         g_free(text);
7852
7853         //Authors
7854         text=g_strdup_printf("%s:",_("By"));
7855         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7856         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7857         g_free(text);
7858         text=g_strdup_printf("Martin Schaller");
7859         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7860         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7861         g_free(text);
7862         text=g_strdup_printf("Michael Farmbauer");
7863         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7864         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7865         g_free(text);
7866         text=g_strdup_printf("Alexander Atanasov");
7867         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7868         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7869         g_free(text);
7870         text=g_strdup_printf("Pierre Grandin");
7871         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7872         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7873         g_free(text);
7874
7875         //Contributors
7876         text=g_strdup_printf("%s",_("And all the Navit Team"));
7877         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7878         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7879         g_free(text);
7880         text=g_strdup_printf("%s",_("members and contributors."));
7881         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
7882         w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
7883         g_free(text);
7884
7885         gui_internal_menu_render(this);
7886         graphics_draw_mode(this->gra, draw_mode_end);
7887 }
7888
7889 /**
7890  * @brief handles the 'next page' table event.
7891  * A callback function that is invoked when the 'next page' button is pressed
7892  * to advance the contents of a table widget.
7893  *
7894  * @param this The graphics context.
7895  * @param wm The button widget that was pressed.
7896  */
7897 static void gui_internal_table_button_next(struct gui_priv * this, struct widget * wm, void *data)
7898 {
7899         struct widget * table_widget=NULL;
7900         struct table_data * table_data = NULL;
7901
7902         if(wm)
7903                 table_widget = (struct widget * ) wm->data;
7904         else 
7905                 table_widget = data;
7906
7907         if(table_widget && table_widget->type==widget_table)
7908                 table_data = (struct table_data*) table_widget->data;
7909
7910         if(table_data)
7911         {
7912                 GList *l=g_list_next(table_data->bottom_row);
7913                 if(l)   {
7914                         gui_internal_table_hide_rows(table_data);
7915                         table_data->top_row=l;
7916                 }
7917         }
7918
7919         if(wm)
7920                 wm->state&= ~STATE_HIGHLIGHTED;
7921
7922         gui_internal_menu_render(this);
7923 }
7924
7925
7926
7927 /**
7928  * @brief handles the 'previous page' table event.
7929  * A callback function that is invoked when the 'previous page' button is pressed
7930  * to go back in the contents of a table widget.
7931  *
7932  * @param this The graphics context.
7933  * @param wm The button widget that was pressed.
7934  */
7935 static void gui_internal_table_button_prev(struct gui_priv * this, struct widget * wm, void *data)
7936 {
7937         struct widget * table_widget = NULL;
7938         struct table_data * table_data = NULL;
7939         
7940         if(wm)
7941                 table_widget=(struct widget * ) wm->data;
7942         else 
7943                 table_widget=(struct widget * ) data;
7944
7945         if(table_widget && table_widget->type==widget_table)
7946                 table_data = (struct table_data*) table_widget->data;
7947
7948         if(table_data)  {
7949                 int bottomy=table_widget->p.y+table_widget->h;
7950                 int n;
7951                 GList *top=table_data->top_row;
7952                 struct widget *w=(struct widget*)top->data;
7953                 if(table_data->button_box->p.y!=0) {
7954                     bottomy=table_data->button_box->p.y;
7955                 }
7956                 n=(bottomy-w->p.y)/w->h;
7957                 while(n-- > 0 && (top=g_list_previous(top))!=NULL);
7958                 gui_internal_table_hide_rows(table_data);
7959                 table_data->top_row=top;
7960         }
7961         if(wm)
7962                 wm->state&= ~STATE_HIGHLIGHTED;
7963         gui_internal_menu_render(this);
7964 }
7965
7966
7967 /**
7968  * @brief deallocates a table_data structure.
7969  *
7970  */
7971 void gui_internal_table_data_free(void * p)
7972 {
7973
7974
7975         /**
7976          * @note button_box and its children (next_button,prev_button)
7977          * have their memory managed by the table itself.
7978          */
7979         g_free(p);
7980
7981
7982 }
7983
7984
7985 /**
7986  * @brief Called when the route is updated.
7987  */
7988 void gui_internal_route_update(struct gui_priv * this, struct navit * navit, struct vehicle *v)
7989 {
7990
7991         if(this->route_data.route_showing) {
7992                 gui_internal_populate_route_table(this,navit);
7993                 graphics_draw_mode(this->gra, draw_mode_begin);
7994                 gui_internal_menu_render(this);
7995                 graphics_draw_mode(this->gra, draw_mode_end);
7996         }
7997
7998
7999 }
8000
8001
8002 /**
8003  * @brief Called when the route screen is closed (deallocated).
8004  *
8005  * The main purpose of this function is to remove the widgets from
8006  * references route_data because those widgets are about to be freed.
8007  */
8008 void gui_internal_route_screen_free(struct gui_priv * this_,struct widget * w)
8009 {
8010         if(this_) {
8011                 this_->route_data.route_showing=0;
8012                 this_->route_data.route_table=NULL;
8013                 g_free(w);
8014         }
8015
8016 }
8017
8018 /**
8019  * @brief Populates the route  table with route information
8020  *
8021  * @param this The gui context
8022  * @param navit The navit object
8023  */
8024 void gui_internal_populate_route_table(struct gui_priv * this,
8025                                        struct navit * navit)
8026 {
8027         struct map * map=NULL;
8028         struct map_rect * mr=NULL;
8029         struct navigation * nav = NULL;
8030         struct item * item =NULL;
8031         struct attr attr;
8032         struct widget * label = NULL;
8033         struct widget * row = NULL;
8034         struct coord c;
8035         nav = navit_get_navigation(navit);
8036         if(!nav) {
8037                 return;
8038         }
8039         map = navigation_get_map(nav);
8040         if(map)
8041           mr = map_rect_new(map,NULL);
8042         if(mr) {
8043                 gui_internal_widget_table_clear(this,this->route_data.route_table);
8044                 while((item = map_rect_get_item(mr))) {
8045                         if(item_attr_get(item,attr_navigation_long,&attr)) {
8046                           row = gui_internal_widget_table_row_new(this,
8047                                                                   gravity_left
8048                                                                   | flags_fill
8049                                                                   | orientation_horizontal);
8050                           gui_internal_widget_append(this->route_data.route_table,row);
8051
8052                           label = gui_internal_label_new(this,attr.u.str);
8053                           gui_internal_widget_append(row,label);
8054
8055                           label->item=*item;
8056                           item_coord_get(item, &c, 1);
8057                           label->c.x=c.x;
8058                           label->c.y=c.y;
8059                           label->c.pro=map_projection(map);
8060                           label->func=gui_internal_cmd_position;
8061                           label->state|=STATE_SENSITIVE;
8062                           label->data=(void*)2;   
8063                         }
8064
8065                 }
8066
8067         }
8068 }
8069
8070 static struct command_table commands[] = {
8071         {"abort_navigation",command_cast(gui_internal_cmd2_abort_navigation)},
8072         {"back",command_cast(gui_internal_cmd2_back)},
8073         {"back_to_map",command_cast(gui_internal_cmd2_back_to_map)},
8074         {"bookmarks",command_cast(gui_internal_cmd2_bookmarks)},
8075         {"formerdests",command_cast(gui_internal_cmd_formerdests)},
8076         {"get_data",command_cast(gui_internal_get_data)},
8077         {"locale",command_cast(gui_internal_cmd2_locale)},
8078         {"log",command_cast(gui_internal_cmd_log)},
8079         {"menu",command_cast(gui_internal_cmd_menu2)},
8080         {"position",command_cast(gui_internal_cmd2_position)},
8081         {"pois",command_cast(gui_internal_cmd2_pois)},
8082         {"route_description",command_cast(gui_internal_cmd2_route_description)},
8083         {"route_height_profile",command_cast(gui_internal_cmd2_route_height_profile)},
8084         {"set",command_cast(gui_internal_cmd2_set)},
8085         {"setting_layout",command_cast(gui_internal_cmd2_setting_layout)},
8086         {"setting_maps",command_cast(gui_internal_cmd2_setting_maps)},
8087         {"setting_rules",command_cast(gui_internal_cmd2_setting_rules)},
8088         {"setting_vehicle",command_cast(gui_internal_cmd2_setting_vehicle)},
8089         {"town",command_cast(gui_internal_cmd2_town)},
8090         {"quit",command_cast(gui_internal_cmd2_quit)},
8091         {"write",command_cast(gui_internal_cmd_write)},
8092         {"about",command_cast(gui_internal_cmd2_about)},
8093
8094 };
8095
8096
8097 //##############################################################################################################
8098 //# Description:
8099 //# Comment:
8100 //# Authors: Martin Schaller (04/2008)
8101 //##############################################################################################################
8102 static struct gui_priv * gui_internal_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs, struct gui *gui)
8103 {
8104         struct color color_white={0xffff,0xffff,0xffff,0xffff};
8105         struct color color_black={0x0,0x0,0x0,0xffff};
8106         struct color back2_color={0x4141,0x4141,0x4141,0xffff};
8107
8108         struct gui_priv *this;
8109         struct attr *attr;
8110         *meth=gui_internal_methods;
8111         this=g_new0(struct gui_priv, 1);
8112         this->nav=nav;
8113
8114         this->self.type=attr_gui;
8115         this->self.u.gui=gui;
8116
8117         if ((attr=attr_search(attrs, NULL, attr_menu_on_map_click)))
8118                 this->menu_on_map_click=attr->u.num;
8119         else
8120                 this->menu_on_map_click=1;
8121
8122         if ((attr=attr_search(attrs, NULL, attr_on_map_click)))
8123                 this->on_map_click=g_strdup(attr->u.str);
8124
8125         if ((attr=attr_search(attrs, NULL, attr_signal_on_map_click)))
8126                 this->signal_on_map_click=attr->u.num;
8127
8128         if ((attr=attr_search(attrs, NULL, attr_callback_list))) {
8129                 command_add_table(attr->u.callback_list, commands, sizeof(commands)/sizeof(struct command_table), this);
8130         }
8131
8132         if( (attr=attr_search(attrs,NULL,attr_font_size)))
8133         {
8134           this->config.font_size=attr->u.num;
8135         }
8136         else
8137         {
8138           this->config.font_size=-1;
8139         }
8140         if( (attr=attr_search(attrs,NULL,attr_icon_xs)))
8141         {
8142           this->config.icon_xs=attr->u.num;
8143         }
8144         else
8145         {
8146           this->config.icon_xs=-1;
8147         }
8148         if( (attr=attr_search(attrs,NULL,attr_icon_l)))
8149         {
8150           this->config.icon_l=attr->u.num;
8151         }
8152         else
8153         {
8154           this->config.icon_l=-1;
8155         }
8156         if( (attr=attr_search(attrs,NULL,attr_icon_s)))
8157         {
8158           this->config.icon_s=attr->u.num;
8159         }
8160         else
8161         {
8162           this->config.icon_s=-1;
8163         }
8164         if( (attr=attr_search(attrs,NULL,attr_spacing)))
8165         {
8166           this->config.spacing=attr->u.num;
8167         }
8168         else
8169         {
8170           this->config.spacing=-1;
8171         }
8172         if( (attr=attr_search(attrs,NULL,attr_gui_speech)))
8173         {
8174           this->speech=attr->u.num;
8175         }
8176         if( (attr=attr_search(attrs,NULL,attr_keyboard)))
8177           this->keyboard=attr->u.num;
8178         else
8179           this->keyboard=1;
8180
8181     if( (attr=attr_search(attrs,NULL,attr_fullscreen)))
8182       this->fullscreen=attr->u.num;
8183
8184         if( (attr=attr_search(attrs,NULL,attr_flags)))
8185               this->flags=attr->u.num;
8186         if( (attr=attr_search(attrs,NULL,attr_background_color)))
8187               this->background_color=*attr->u.color;
8188         else
8189               this->background_color=color_black;
8190         if( (attr=attr_search(attrs,NULL,attr_background_color2)))
8191                 this->background2_color=*attr->u.color;
8192         else
8193                 this->background2_color=back2_color;
8194         if( (attr=attr_search(attrs,NULL,attr_text_color)))
8195               this->text_foreground_color=*attr->u.color;
8196         else
8197               this->text_foreground_color=color_white;
8198         this->text_background_color=color_black;
8199         if( (attr=attr_search(attrs,NULL,attr_columns)))
8200               this->cols=attr->u.num;
8201         if( (attr=attr_search(attrs,NULL,attr_osd_configuration)))
8202               this->osd_configuration=*attr;
8203
8204         if( (attr=attr_search(attrs,NULL,attr_pitch)))
8205               this->pitch=attr->u.num;
8206         else
8207                 this->pitch=20;
8208         if( (attr=attr_search(attrs,NULL,attr_flags_town)))
8209                 this->flags_town=attr->u.num;
8210         else
8211                 this->flags_town=-1;
8212         if( (attr=attr_search(attrs,NULL,attr_flags_street)))
8213                 this->flags_street=attr->u.num;
8214         else
8215                 this->flags_street=-1;
8216         if( (attr=attr_search(attrs,NULL,attr_flags_house_number)))
8217                 this->flags_house_number=attr->u.num;
8218         else
8219                 this->flags_house_number=-1;
8220         if( (attr=attr_search(attrs,NULL,attr_radius)))
8221                 this->radius=attr->u.num;
8222         else
8223                 this->radius=10;
8224         this->data.priv=this;
8225         this->data.gui=&gui_internal_methods_ext;
8226         this->data.widget=&gui_internal_widget_methods;
8227         this->cbl=callback_list_new();
8228
8229         return this;
8230 }
8231
8232 //##############################################################################################################
8233 //# Description:
8234 //# Comment:
8235 //# Authors: Martin Schaller (04/2008)
8236 //##############################################################################################################
8237 void plugin_init(void)
8238 {
8239         plugin_register_gui_type("internal", gui_internal_new);
8240 }
8241
8242 static void
8243 gui_internal_destroy(struct gui_priv *this)
8244 {
8245         g_free(this->country_iso2);
8246         g_free(this->href);
8247         g_free(this->html_text);
8248         g_free(this->on_map_click);
8249         g_free(this);
8250 }