Add:gui_internal:Add via navit.xml configurable menus, expect some screwups the next...
[navit-package] / navit / gui / internal / gui_internal.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 //##############################################################################################################
21 //#
22 //# File: 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 #ifdef HAVE_API_WIN32_BASE
37 #include <windows.h>
38 #endif
39 #include "config.h"
40 #include "item.h"
41 #include "file.h"
42 #include "navit.h"
43 #include "navit_nls.h"
44 #include "debug.h"
45 #include "gui.h"
46 #include "coord.h"
47 #include "point.h"
48 #include "plugin.h"
49 #include "graphics.h"
50 #include "transform.h"
51 #include "color.h"
52 #include "map.h"
53 #include "layout.h"
54 #include "callback.h"
55 #include "vehicle.h"
56 #include "vehicleprofile.h"
57 #include "window.h"
58 #include "config_.h"
59 #include "keys.h"
60 #include "mapset.h"
61 #include "route.h"
62 #include "search.h"
63 #include "track.h"
64 #include "country.h"
65 #include "config.h"
66 #include "event.h"
67 #include "navit_nls.h"
68 #include "navigation.h"
69 #include "gui_internal.h"
70 #include "command.h"
71 #include "xmlconfig.h"
72 #include "util.h"
73
74 struct menu_data {
75         struct widget *search_list;
76         struct widget *keyboard;
77         struct widget *button_bar;
78         int keyboard_mode;
79         void (*redisplay)(struct gui_priv *priv, struct widget *widget, void *data);
80         struct widget *redisplay_widget;
81 };
82
83 //##############################################################################################################
84 //# Description:
85 //# Comment:
86 //# Authors: Martin Schaller (04/2008)
87 //##############################################################################################################
88 struct widget {
89         enum widget_type type;
90         struct graphics_gc *background,*text_background;
91         struct graphics_gc *foreground_frame;
92         struct graphics_gc *foreground;
93         char *text;
94         struct graphics_image *img;
95          /**
96           * A function to be invoked on actions.
97           * @li widget The widget that is receiving the button press.
98           *
99           */
100         void (*func)(struct gui_priv *priv, struct widget *widget, void *data);
101         int reason;
102         int datai;
103         void *data;
104         /**
105          * @brief A function to deallocate data
106          */
107         void (*data_free)(void *data);
108
109         /**
110          * @brief a function that will be called as the widget is being destroyed.
111          * This function can act as a destructor for the widget. It allows for
112          * on deallocation actions to be specified on a per widget basis.
113          * This function will call g_free on the widget (if required).
114          */
115         void (*free) (struct gui_priv *this_, struct widget * w);
116         char *prefix;
117         char *name;
118         char *speech;
119         char *command;
120         struct pcoord c;
121         struct item item;
122         int selection_id;
123         int state;
124         struct point p;
125         int wmin,hmin;
126         int w,h;
127         int textw,texth;
128         int bl,br,bt,bb,spx,spy;
129         int border;
130         /**
131          * The number of widgets to layout horizontally when doing
132          * a orientation_horizontal_vertical layout
133          */
134         int cols;
135         enum flags flags;
136         void *instance;
137         int (*set_attr)(void *, struct attr *);
138         int (*get_attr)(void *, enum attr_type, struct attr *, struct attr_iter *);
139         void (*remove_cb)(void *, struct callback *cb);
140         struct callback *cb;
141         struct attr on;
142         struct attr off;
143         int deflt;
144         int is_on;
145         int redraw;
146         struct menu_data *menu_data;
147         GList *children;
148 };
149
150 /**
151  * @brief A structure to store configuration values.
152  *
153  * This structure stores configuration values for how gui elements in the internal GUI
154  * should be drawn.
155  */
156 struct gui_config_settings {
157
158   /**
159    * The base size (in fractions of a point) to use for text.
160    */
161   int font_size;
162   /**
163    * The size (in pixels) that xs style icons should be scaled to.
164    */
165   int icon_xs;
166   /**
167    * The size (in pixels) that s style icons (small) should be scaled to
168    */
169   int icon_s;
170   /**
171    * The size (in pixels) that l style icons should be scaled to
172    */
173   int icon_l;
174   /**
175    * The default amount of spacing (in pixels) to place between GUI elements.
176    */
177   int spacing;
178
179 };
180
181 /**
182  * Indexes into the config_profiles array.
183  */
184 const int LARGE_PROFILE=0;
185 const int MEDIUM_PROFILE=1;
186 const int SMALL_PROFILE=2;
187
188 /**
189  * The default config profiles.
190  *
191  * [0] =>  LARGE_PROFILE (screens 640 in one dimension)
192  * [1] =>  MEDIUM PROFILE (screens larger than 320 in one dimension
193  * [2] => Small profile (default)
194  */
195 static struct gui_config_settings config_profiles[]={
196       {545,32,48,96,10}
197     , {300,32,48,64,3}
198       ,{200,16,32,48,2}
199 };
200
201 struct route_data {
202   struct widget * route_table;
203   int route_showing;
204
205 };
206
207 //##############################################################################################################
208 //# Description:
209 //# Comment:
210 //# Authors: Martin Schaller (04/2008)
211 //##############################################################################################################
212 struct gui_priv {
213         struct navit *nav;
214         struct attr self;
215         struct window *win;
216         struct graphics *gra;
217         struct graphics_gc *background;
218         struct graphics_gc *background2;
219         struct graphics_gc *highlight_background;
220         struct graphics_gc *foreground;
221         struct graphics_gc *text_foreground;
222         struct graphics_gc *text_background;
223         struct color background_color, background2_color, text_foreground_color, text_background_color;
224         int spacing;
225         int font_size;
226         int fullscreen;
227         struct graphics_font *font;
228         int icon_xs, icon_s, icon_l;
229         int pressed;
230         struct widget *widgets;
231         int widgets_count;
232         int redraw;
233         struct widget root;
234         struct widget *highlighted;
235         struct widget *highlighted_menu;
236         int clickp_valid, vehicle_valid;
237         struct pcoord clickp, vehiclep;
238         struct attr *click_coord_geo, *position_coord_geo;
239         struct search_list *sl;
240         int ignore_button;
241         int menu_on_map_click;
242         char *country_iso2;
243         int speech;
244         int keyboard;
245         /**
246          * The setting information read from the configuration file.
247          * values of -1 indicate no value was specified in the config file.
248          */
249         struct gui_config_settings config;
250         struct event_idle *idle;
251         struct callback *motion_cb,*button_cb,*resize_cb,*keypress_cb,*idle_cb, *motion_timeout_callback;
252         struct event_timeout *motion_timeout_event;
253         struct point current;
254
255         struct callback * vehicle_cb;
256           /**
257            * Stores information about the route.
258            */
259         struct route_data route_data;
260
261         struct gui_internal_data data;
262         struct callback_list *cbl;
263         int flags;
264         int cols;
265         struct attr osd_configuration;
266         int pitch;
267 /* html */
268         char *html_text;
269         int html_depth; 
270         struct widget *html_container;
271         int html_skip;
272         char *html_anchor;
273         int html_anchor_found;
274         struct html {
275                 int skip;
276                 enum html_tag {
277                         html_tag_none,
278                         html_tag_a,
279                         html_tag_h1,
280                         html_tag_html,
281                         html_tag_img,
282                         html_tag_script,
283                 } tag;
284                 char *command;
285                 char *name;
286                 char *href;
287                 struct widget *w;
288         } html[10];
289 };
290
291 struct html_tag_map {
292         char *tag_name;
293         enum html_tag tag;
294 } html_tag_map[] = {
295         {"a",html_tag_a},
296         {"h1",html_tag_h1},
297         {"html",html_tag_html},
298         {"img",html_tag_img},
299         {"script",html_tag_script},
300 };
301
302
303 /**
304  * @brief A structure to store information about a table.
305  *
306  * The table_data widget stores pointers to extra information needed by the
307  * table widget.
308  *
309  * The table_data structure needs to be freed with data_free along with the widget.
310  *
311  */
312 struct table_data
313 {
314   /**
315    * A GList pointer into a widget->children list that indicates the row
316    * currently being rendered at the top of the table.
317    */
318   GList * top_row;
319   /**
320    * A Glist pointer into a widget->children list that indicates the row
321    * currently being rendered at the bottom of the table.
322    */
323   GList * bottom_row;
324
325   /**
326    * A list of table_row widgets that mark the
327    * top rows for each page of the table.
328    * This is needed for the 'previous page' function of the table.
329    */
330   GList * page_headers;
331
332   /**
333    * A container box that is the child of the table widget that contains+groups
334    * the next and previous button.
335    */
336   struct widget * button_box;
337
338   /**
339    * A button widget to handle 'next page' requests
340    */
341   struct widget * next_button;
342   /**
343    * A button widget to handle 'previous page' requests.
344    */
345   struct widget * prev_button;
346
347
348   /**
349    * a pointer to the gui context.
350    * This is needed by the free function to destory the buttons.
351    */
352   struct  gui_priv *  this;
353 };
354
355 /**
356  * A data structure that holds information about a column that makes up a table.
357  *
358  *
359  */
360 struct table_column_desc
361 {
362
363   /**
364    * The computed height of a cell in the table.
365    */
366   int height;
367
368   /**
369    * The computed width of a cell in the table.
370    */
371   int width;
372 };
373
374
375 static void gui_internal_widget_render(struct gui_priv *this, struct widget *w);
376 static void gui_internal_widget_pack(struct gui_priv *this, struct widget *w);
377 static struct widget * gui_internal_box_new(struct gui_priv *this, enum flags flags);
378 static void gui_internal_widget_append(struct widget *parent, struct widget *child);
379 static void gui_internal_widget_destroy(struct gui_priv *this, struct widget *w);
380 static void gui_internal_apply_config(struct gui_priv *this);
381
382 static struct widget* gui_internal_widget_table_new(struct gui_priv * this, enum flags flags, int buttons);
383 static struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags);
384 static void gui_internal_table_render(struct gui_priv * this, struct widget * w);
385 static void gui_internal_table_pack(struct gui_priv * this, struct widget * w);
386 static void gui_internal_table_button_next(struct gui_priv * this, struct widget * wm, void *data);
387 static void gui_internal_table_button_prev(struct gui_priv * this, struct widget * wm, void *data);
388 static void gui_internal_widget_table_clear(struct gui_priv * this,struct widget * table);
389 static struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags);
390 static void gui_internal_table_data_free(void * d);
391 static void gui_internal_route_update(struct gui_priv * this, struct navit * navit,
392                                       struct vehicle * v);
393 static void gui_internal_route_screen_free(struct gui_priv * this_,struct widget * w);
394 static void gui_internal_populate_route_table(struct gui_priv * this,
395                                        struct navit * navit);
396 static void gui_internal_search_idle_end(struct gui_priv *this);
397 static void gui_internal_search(struct gui_priv *this, char *what, char *type, int flags);
398 static void gui_internal_search_house_number(struct gui_priv *this, struct widget *widget, void *data);
399 static void gui_internal_search_house_number_in_street(struct gui_priv *this, struct widget *widget, void *data);
400 static void gui_internal_search_street(struct gui_priv *this, struct widget *widget, void *data);
401 static void gui_internal_search_street_in_town(struct gui_priv *this, struct widget *widget, void *data);
402 static void gui_internal_search_town(struct gui_priv *this, struct widget *wm, void *data);
403 static void gui_internal_search_town_in_country(struct gui_priv *this, struct widget *wm);
404 static void gui_internal_search_country(struct gui_priv *this, struct widget *widget, void *data);
405 static void gui_internal_check_exit(struct gui_priv *this);
406 static void gui_internal_cmd_view_in_browser(struct gui_priv *this, struct widget *wm, void *data);
407
408 static struct widget *gui_internal_keyboard_do(struct gui_priv *this, struct widget *wkbdb, int mode);
409 static struct menu_data * gui_internal_menu_data(struct gui_priv *this);
410
411 static int gui_internal_is_active_vehicle(struct gui_priv *this, struct vehicle *vehicle);
412 static void gui_internal_html_menu(struct gui_priv *this, const char *document, char *anchor);
413
414 /*
415  * * Display image scaled to specific size
416  * * searches for scaleable and pre-scaled image
417  * * @param this Our gui context
418  * * @param name image name
419  * * @param w desired width of image
420  * * @param h desired height of image
421  * * @returns image_struct Ptr to scaled image struct or NULL if not scaled or found
422  * */
423 static struct graphics_image *
424 image_new_scaled(struct gui_priv *this, const char *name, int w, int h)
425 {
426         struct graphics_image *ret=NULL;
427         char *full_name=NULL;
428         char *full_path=NULL;
429         int i;
430
431         for (i = 1 ; i < 6 ; i++) {
432                 full_name=NULL;
433                 switch (i) {
434                 case 3:
435                         full_name=g_strdup_printf("%s.svg", name);
436                         break;
437                 case 2:
438                         full_name=g_strdup_printf("%s.svgz", name);
439                         break;
440                 case 1:
441                         if (w != -1 && h != -1) {
442                                 full_name=g_strdup_printf("%s_%d_%d.png", name, w, h);
443                         }
444                         break;
445                 case 4:
446                         full_name=g_strdup_printf("%s.png", name);
447                         break;
448                 case 5:
449                         full_name=g_strdup_printf("%s.xpm", name);
450                         break;
451                 }
452                 dbg(1,"trying '%s'\n", full_name);
453                 if (! full_name)
454                         continue;
455 #if 0
456                 /* needs to be checked in the driver */
457                 if (!file_exists(full_name)) {
458                         g_free(full_name);
459                         continue;
460                 }
461 #endif
462                 full_path=graphics_icon_path(full_name);
463                 ret=graphics_image_new_scaled(this->gra, full_path, w, h);
464                 dbg(1,"ret=%p\n", ret);
465                 g_free(full_path);
466                 g_free(full_name);
467                 if (ret)
468                         return ret;
469         }
470         dbg(0,"failed to load %s with %d,%d\n", name, w, h);
471         return NULL;
472 }
473
474 #if 0
475 static struct graphics_image *
476 image_new_o(struct gui_priv *this, char *name)
477 {
478         return image_new_scaled(this, name, -1, -1);
479 }
480 #endif
481
482 static struct graphics_image *
483 image_new_xs(struct gui_priv *this, const char *name)
484 {
485         return image_new_scaled(this, name, this->icon_xs, this->icon_xs);
486 }
487
488
489 static struct graphics_image *
490 image_new_s(struct gui_priv *this, const char *name)
491 {
492         return image_new_scaled(this, name, this->icon_s, this->icon_s);
493 }
494
495 static struct graphics_image *
496 image_new_l(struct gui_priv *this, const char *name)
497 {
498         return image_new_scaled(this, name, this->icon_l, this->icon_l);
499 }
500
501 static char *
502 coordinates_geo(const struct coord_geo *gc, char sep)
503 {
504         char latc='N',lngc='E';
505         int lat_deg,lat_min,lat_sec;
506         int lng_deg,lng_min,lng_sec;
507         struct coord_geo g=*gc;
508
509         if (g.lat < 0) {
510                 g.lat=-g.lat;
511                 latc='S';
512         }
513         if (g.lng < 0) {
514                 g.lng=-g.lng;
515                 lngc='W';
516         }
517         lat_deg=g.lat;
518         lat_min=fmod(g.lat*60,60);
519         lat_sec=fmod(g.lat*3600,60);
520         lng_deg=g.lng;
521         lng_min=fmod(g.lng*60,60);
522         lng_sec=fmod(g.lng*3600,60);
523         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);
524 }
525
526 static char *
527 coordinates(struct pcoord *pc, char sep)
528 {
529         struct coord_geo g;
530         struct coord c;
531         c.x=pc->x;
532         c.y=pc->y;
533         transform_to_geo(pc->pro, &c, &g);
534         return coordinates_geo(&g, sep);
535
536 }
537
538 static void
539 gui_internal_background_render(struct gui_priv *this, struct widget *w)
540 {
541         struct point pnt=w->p;
542         if (w->state & STATE_HIGHLIGHTED)
543                 graphics_draw_rectangle(this->gra, this->highlight_background, &pnt, w->w, w->h);
544         else {
545                 if (w->background)
546                         graphics_draw_rectangle(this->gra, w->background, &pnt, w->w, w->h);
547         }
548 }
549 static struct widget *
550 gui_internal_label_new(struct gui_priv *this, char *text)
551 {
552         struct point p[4];
553         int w=0;
554         int h=0;
555
556         struct widget *widget=g_new0(struct widget, 1);
557         widget->type=widget_label;
558         if (text) {
559                 widget->text=g_strdup(text);
560                 graphics_get_text_bbox(this->gra, this->font, text, 0x10000, 0x0, p, 0);
561                 w=p[2].x-p[0].x;
562                 h=p[0].y-p[2].y;
563         }
564         widget->h=h+this->spacing;
565         widget->texth=h;
566         widget->w=w+this->spacing;
567         widget->textw=w;
568         widget->flags=gravity_center;
569         widget->foreground=this->text_foreground;
570         widget->text_background=this->text_background;
571
572         return widget;
573 }
574
575 static struct widget *
576 gui_internal_label_new_abbrev(struct gui_priv *this, char *text, int maxwidth)
577 {
578         struct widget *ret=NULL;
579         char *tmp=g_malloc(strlen(text)+3);
580         int i;
581
582         i=strlen(text)-1;
583         while (i >= 0) {
584                 strcpy(tmp, text);
585                 strcpy(tmp+i,"..");
586                 ret=gui_internal_label_new(this, tmp);
587                 if (ret->w < maxwidth)
588                         break;
589                 gui_internal_widget_destroy(this, ret);
590                 ret=NULL;
591                 i--;
592         }
593         g_free(tmp);
594         return ret;
595 }
596
597 static struct widget *
598 gui_internal_image_new(struct gui_priv *this, struct graphics_image *image)
599 {
600         struct widget *widget=g_new0(struct widget, 1);
601         widget->type=widget_image;
602         widget->img=image;
603         if (image) {
604                 widget->w=image->width;
605                 widget->h=image->height;
606         }
607         return widget;
608 }
609
610 static void
611 gui_internal_image_render(struct gui_priv *this, struct widget *w)
612 {
613         struct point pnt;
614
615         gui_internal_background_render(this, w);
616         if (w->img) {
617                 pnt=w->p;
618                 pnt.x+=w->w/2-w->img->hot.x;
619                 pnt.y+=w->h/2-w->img->hot.y;
620                 graphics_draw_image(this->gra, this->foreground, &pnt, w->img);
621         }
622 }
623
624 static void
625 gui_internal_label_render(struct gui_priv *this, struct widget *w)
626 {
627         struct point pnt=w->p;
628         gui_internal_background_render(this, w);
629         if (w->text) {
630                 if (w->flags & gravity_right) {
631                         pnt.y+=w->h-this->spacing;
632                         pnt.x+=w->w-w->textw-this->spacing;
633                         graphics_draw_text(this->gra, w->foreground, w->text_background, this->font, w->text, &pnt, 0x10000, 0x0);
634                 } else {
635                         pnt.y+=w->h-this->spacing;
636                         graphics_draw_text(this->gra, w->foreground, w->text_background, this->font, w->text, &pnt, 0x10000, 0x0);
637                 }
638         }
639 }
640
641 /**
642  * @brief A text box is a widget that renders a text string containing newlines.
643  * The string will be broken up into label widgets at each newline with a vertical layout.
644  *
645  */
646 static struct widget *
647 gui_internal_text_new(struct gui_priv *this, char *text, enum flags flags)
648 {
649         char *s=g_strdup(text),*s2,*tok;
650         struct widget *ret=gui_internal_box_new(this, flags);
651         s2=s;
652         while ((tok=strtok(s2,"\n"))) {
653                 gui_internal_widget_append(ret, gui_internal_label_new(this, tok));
654                 s2=NULL;
655         }
656         gui_internal_widget_pack(this,ret);
657         return ret;
658 }
659
660
661 static struct widget *
662 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)
663 {
664         struct widget *ret=NULL;
665         ret=gui_internal_box_new(this, flags);
666         if (ret) {
667                 if (image)
668                         gui_internal_widget_append(ret, gui_internal_image_new(this, image));
669                 if (text)
670                         gui_internal_widget_append(ret, gui_internal_text_new(this, text, gravity_center|orientation_vertical));
671                 ret->func=func;
672                 ret->data=data;
673                 if (func) {
674                         ret->state |= STATE_SENSITIVE;
675                         ret->speech=g_strdup(text);
676                 }
677         }
678         return ret;
679
680 }
681
682 static int
683 gui_internal_button_attr_update(struct gui_priv *this, struct widget *w)
684 {
685         struct widget *wi;
686         int is_on=0;
687         struct attr curr;
688         GList *l;
689
690         if (w->get_attr(w->instance, w->on.type, &curr, NULL))
691                 is_on=curr.u.data == w->on.u.data;
692         else
693                 is_on=w->deflt;
694         if (is_on != w->is_on) {
695                 if (w->redraw)
696                         this->redraw=1;
697                 w->is_on=is_on;
698                 l=g_list_first(w->children);
699                 if (l) {
700                         wi=l->data;
701                         if (wi->img)
702                                 graphics_image_free(this->gra, wi->img);
703                         wi->img=image_new_xs(this, is_on ? "gui_active" : "gui_inactive");
704                 }
705                 if (w->is_on && w->off.type == attr_none)
706                         w->state &= ~STATE_SENSITIVE;
707                 else
708                         w->state |= STATE_SENSITIVE;
709                 return 1;
710         }
711         return 0;
712 }
713
714 static void
715 gui_internal_button_attr_callback(struct gui_priv *this, struct widget *w)
716 {
717         if (gui_internal_button_attr_update(this, w))
718                 gui_internal_widget_render(this, w);
719 }
720 static void
721 gui_internal_button_attr_pressed(struct gui_priv *this, struct widget *w, void *data)
722 {
723         if (w->is_on)
724                 w->set_attr(w->instance, &w->off);
725         else
726                 w->set_attr(w->instance, &w->on);
727         gui_internal_button_attr_update(this, w);
728
729 }
730
731 static struct widget *
732 gui_internal_button_navit_attr_new(struct gui_priv *this, char *text, enum flags flags, struct attr *on, struct attr *off)
733 {
734         struct graphics_image *image=NULL;
735         struct widget *ret;
736         if (!on && !off)
737                 return NULL;
738         image=image_new_xs(this, "gui_inactive");
739         ret=gui_internal_button_new_with_callback(this, text, image, flags, gui_internal_button_attr_pressed, NULL);
740         if (on)
741                 ret->on=*on;
742         if (off)
743                 ret->off=*off;
744         ret->get_attr=(int (*)(void *, enum attr_type, struct attr *, struct attr_iter *))navit_get_attr;
745         ret->set_attr=(int (*)(void *, struct attr *))navit_set_attr;
746         ret->remove_cb=(void (*)(void *, struct callback *))navit_remove_callback;
747         ret->instance=this->nav;
748         ret->cb=callback_new_attr_2(callback_cast(gui_internal_button_attr_callback), on?on->type:off->type, this, ret);
749         navit_add_callback(this->nav, ret->cb);
750         gui_internal_button_attr_update(this, ret);
751         return ret;
752 }
753
754 static struct widget *
755 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)
756 {
757         struct graphics_image *image=NULL;
758         struct widget *ret;
759         image=image_new_xs(this, "gui_inactive");
760         if (!on && !off)
761                 return NULL;
762         ret=gui_internal_button_new_with_callback(this, text, image, flags, gui_internal_button_attr_pressed, NULL);
763         if (on)
764                 ret->on=*on;
765         if (off)
766                 ret->off=*off;
767         ret->deflt=deflt;
768         ret->get_attr=(int (*)(void *, enum attr_type, struct attr *, struct attr_iter *))map_get_attr;
769         ret->set_attr=(int (*)(void *, struct attr *))map_set_attr;
770         ret->remove_cb=(void (*)(void *, struct callback *))map_remove_callback;
771         ret->instance=map;
772         ret->redraw=1;
773         ret->cb=callback_new_attr_2(callback_cast(gui_internal_button_attr_callback), on?on->type:off->type, this, ret);
774         map_add_callback(map, ret->cb);
775         gui_internal_button_attr_update(this, ret);
776         return ret;
777 }
778
779 static struct widget *
780 gui_internal_button_new(struct gui_priv *this, char *text, struct graphics_image *image, enum flags flags)
781 {
782         return gui_internal_button_new_with_callback(this, text, image, flags, NULL, NULL);
783 }
784
785 #if 0
786 //##############################################################################################################
787 //# Description:
788 //# Comment:
789 //# Authors: Martin Schaller (04/2008)
790 //##############################################################################################################
791 static void gui_internal_clear(struct gui_priv *this)
792 {
793         struct graphics *gra=this->gra;
794         struct point pnt;
795         pnt.x=0;
796         pnt.y=0;
797         graphics_draw_rectangle(gra, this->background, &pnt, this->root.w, this->root.h);
798 }
799 #endif
800
801 static struct widget *
802 gui_internal_find_widget(struct widget *wi, struct point *p, int flags)
803 {
804         struct widget *ret,*child;
805         GList *l=wi->children;
806
807         if (p) {
808                 if (wi->p.x > p->x )
809                         return NULL;
810                 if (wi->p.y > p->y )
811                         return NULL;
812                 if ( wi->p.x + wi->w < p->x)
813                         return NULL;
814                 if ( wi->p.y + wi->h < p->y)
815                         return NULL;
816         }
817         if (wi->state & flags)
818                 return wi;
819         while (l) {
820                 child=l->data;
821                 ret=gui_internal_find_widget(child, p, flags);
822                 if (ret) {
823                         return ret;
824                 }
825                 l=g_list_next(l);
826         }
827         return NULL;
828
829 }
830
831 static void
832 gui_internal_highlight_do(struct gui_priv *this, struct widget *found)
833 {
834         if (found == this->highlighted)
835                 return;
836
837         graphics_draw_mode(this->gra, draw_mode_begin);
838         if (this->highlighted) {
839                 this->highlighted->state &= ~STATE_HIGHLIGHTED;
840                 if (this->root.children && this->highlighted_menu == g_list_last(this->root.children)->data)
841                         gui_internal_widget_render(this, this->highlighted);
842                 this->highlighted=NULL;
843                 this->highlighted_menu=NULL;
844         }
845         if (found) {
846                 this->highlighted=found;
847                 this->highlighted_menu=g_list_last(this->root.children)->data;
848                 this->highlighted->state |= STATE_HIGHLIGHTED;
849                 gui_internal_widget_render(this, this->highlighted);
850                 dbg(1,"%d,%d %dx%d\n", found->p.x, found->p.y, found->w, found->h);
851         }
852         graphics_draw_mode(this->gra, draw_mode_end);
853 }
854 //##############################################################################################################
855 //# Description:
856 //# Comment:
857 //# Authors: Martin Schaller (04/2008)
858 //##############################################################################################################
859 static void gui_internal_highlight(struct gui_priv *this)
860 {
861         struct widget *menu,*found=NULL;
862         if (this->current.x > -1 && this->current.y > -1) {
863                 menu=g_list_last(this->root.children)->data;
864                 found=gui_internal_find_widget(menu, &this->current, STATE_SENSITIVE);
865         }
866         gui_internal_highlight_do(this, found);
867         this->motion_timeout_event=NULL;
868 }
869
870 static struct widget *
871 gui_internal_box_new_with_label(struct gui_priv *this, enum flags flags, const char *label)
872 {
873         struct widget *widget=g_new0(struct widget, 1);
874
875         if (label)
876                 widget->text=g_strdup(label);
877         widget->type=widget_box;
878         widget->flags=flags;
879         return widget;
880 }
881
882 static struct widget *
883 gui_internal_box_new(struct gui_priv *this, enum flags flags)
884 {
885         return gui_internal_box_new_with_label(this, flags, NULL);
886 }
887
888
889 static void gui_internal_box_render(struct gui_priv *this, struct widget *w)
890 {
891         struct widget *wc;
892         GList *l;
893
894         gui_internal_background_render(this, w);
895 #if 1
896         if (w->foreground && w->border) {
897         struct point pnt[5];
898         pnt[0]=w->p;
899         pnt[1].x=pnt[0].x+w->w;
900         pnt[1].y=pnt[0].y;
901         pnt[2].x=pnt[0].x+w->w;
902         pnt[2].y=pnt[0].y+w->h;
903         pnt[3].x=pnt[0].x;
904         pnt[3].y=pnt[0].y+w->h;
905         pnt[4]=pnt[0];
906         graphics_gc_set_linewidth(w->foreground, w->border ? w->border : 1);
907         graphics_draw_lines(this->gra, w->foreground, pnt, 5);
908         graphics_gc_set_linewidth(w->foreground, 1);
909         }
910 #endif
911
912         l=w->children;
913         while (l) {
914                 wc=l->data;
915                 gui_internal_widget_render(this, wc);
916                 l=g_list_next(l);
917         }
918 }
919
920
921 /**
922  * @brief Compute the size and location for the widget.
923  *
924  *
925  */
926 static void gui_internal_box_pack(struct gui_priv *this, struct widget *w)
927 {
928         struct widget *wc;
929         int x0,x=0,y=0,width=0,height=0,owidth=0,oheight=0,expand=0,count=0,rows=0,cols=w->cols ? w->cols : 0;
930         GList *l;
931         int orientation=w->flags & 0xffff0000;
932
933         if (!cols)
934                 cols=this->cols;
935         if (!cols) {
936                  if ( this->root.w > this->root.h )
937                          cols=3;
938                  else
939                          cols=2;
940                  width=0;
941                  height=0;
942         }
943
944
945         /**
946          * count the number of children
947          */
948         l=w->children;
949         while (l) {
950                 count++;
951                 l=g_list_next(l);
952         }
953         if (orientation == orientation_horizontal_vertical && count <= cols)
954                 orientation=orientation_horizontal;
955         switch (orientation) {
956         case orientation_horizontal:
957                 /**
958                  * For horizontal orientation:
959                  * pack each child and find the largest height and
960                  * compute the total width. x spacing (spx) is considered
961                  *
962                  * If any children want to be expanded
963                  * we keep track of this
964                  */
965                 l=w->children;
966                 while (l) {
967                         wc=l->data;
968                         gui_internal_widget_pack(this, wc);
969                         if (height < wc->h)
970                                 height=wc->h;
971                         width+=wc->w;
972                         if (wc->flags & flags_expand)
973                                 expand+=wc->w ? wc->w : 1;
974                         l=g_list_next(l);
975                         if (l)
976                                 width+=w->spx;
977                 }
978                 owidth=width;
979                 if (expand && w->w) {
980                         expand=100*(w->w-width+expand)/expand;
981                         owidth=w->w;
982                 } else
983                         expand=100;
984                 break;
985         case orientation_vertical:
986                 /**
987                  * For vertical layouts:
988                  * We pack each child and compute the largest width and
989                  * the total height.  y spacing (spy) is considered
990                  *
991                  * If the expand flag is set then teh expansion amount
992                  * is computed.
993                  */
994                 l=w->children;
995                 while (l) {
996                         wc=l->data;
997                         gui_internal_widget_pack(this, wc);
998                         if (width < wc->w)
999                                 width=wc->w;
1000                         height+=wc->h;
1001                         if (wc->flags & flags_expand)
1002                                 expand+=wc->h ? wc->h : 1;
1003                         l=g_list_next(l);
1004                         if (l)
1005                                 height+=w->spy;
1006                 }
1007                 oheight=height;
1008                 if (expand && w->h) {
1009                         expand=100*(w->h-height+expand)/expand;
1010                         oheight=w->h;
1011                 } else
1012                         expand=100;
1013                 break;
1014         case orientation_horizontal_vertical:
1015                 /**
1016                  * For horizontal_vertical orientation
1017                  * pack the children.
1018                  * Compute the largest height and largest width.
1019                  * Layout the widgets based on having the
1020                  * number of columns specified by (cols)
1021                  */
1022                 count=0;
1023                 l=w->children;
1024                 while (l) {
1025                         wc=l->data;
1026                         gui_internal_widget_pack(this, wc);
1027                         if (height < wc->h)
1028                                 height=wc->h;
1029                         if (width < wc->w)
1030                                 width=wc->w;
1031                         l=g_list_next(l);
1032                         count++;
1033                 }
1034                 if (count < cols)
1035                         cols=count;
1036                 rows=(count+cols-1)/cols;
1037                 width*=cols;
1038                 height*=rows;
1039                 width+=w->spx*(cols-1);
1040                 height+=w->spy*(rows-1);
1041                 owidth=width;
1042                 oheight=height;
1043                 expand=100;
1044                 break;
1045         default:
1046                 /**
1047                  * No orientation was specified.
1048                  * width and height are both 0.
1049                  * The width & height of this widget
1050                  * will be used.
1051                  */
1052                 if(!w->w && !w->h)
1053                         dbg(0,"Warning width and height of a widget are 0");
1054                 break;
1055         }
1056         if (! w->w && ! w->h) {
1057                 w->w=w->bl+w->br+width;
1058                 w->h=w->bt+w->bb+height;
1059         }
1060         if (expand < 100)
1061                 expand=100;
1062
1063         /**
1064          * At this stage the width and height of this
1065          * widget has been computed.
1066          * We now make a second pass assigning heights,
1067          * widths and coordinates to each child widget.
1068          */
1069
1070         if (w->flags & gravity_left)
1071                 x=w->p.x+w->bl;
1072         if (w->flags & gravity_xcenter)
1073                 x=w->p.x+w->w/2-owidth/2;
1074         if (w->flags & gravity_right)
1075                 x=w->p.x+w->w-w->br-owidth;
1076         if (w->flags & gravity_top)
1077                 y=w->p.y+w->bt;
1078         if (w->flags & gravity_ycenter)
1079                 y=w->p.y+w->h/2-oheight/2;
1080         if (w->flags & gravity_bottom)
1081                 y=w->p.y+w->h-w->bb-oheight;
1082         l=w->children;
1083         switch (orientation) {
1084         case orientation_horizontal:
1085                 l=w->children;
1086                 while (l) {
1087                         wc=l->data;
1088                         wc->p.x=x;
1089                         if (wc->flags & flags_fill)
1090                                 wc->h=w->h;
1091                         if (wc->flags & flags_expand) {
1092                                 if (! wc->w)
1093                                         wc->w=1;
1094                                 wc->w=wc->w*expand/100;
1095                         }
1096                         if (w->flags & gravity_top)
1097                                 wc->p.y=y;
1098                         if (w->flags & gravity_ycenter)
1099                                 wc->p.y=y-wc->h/2;
1100                         if (w->flags & gravity_bottom)
1101                                 wc->p.y=y-wc->h;
1102                         x+=wc->w+w->spx;
1103                         l=g_list_next(l);
1104                 }
1105                 break;
1106         case orientation_vertical:
1107                 l=w->children;
1108                 while (l) {
1109                         wc=l->data;
1110                         wc->p.y=y;
1111                         if (wc->flags & flags_fill)
1112                                 wc->w=w->w;
1113                         if (wc->flags & flags_expand) {
1114                                 if (! wc->h)
1115                                         wc->h=1;
1116                                 wc->h=wc->h*expand/100;
1117                         }
1118                         if (w->flags & gravity_left)
1119                                 wc->p.x=x;
1120                         if (w->flags & gravity_xcenter)
1121                                 wc->p.x=x-wc->w/2;
1122                         if (w->flags & gravity_right)
1123                                 wc->p.x=x-wc->w;
1124                         y+=wc->h+w->spy;
1125                         l=g_list_next(l);
1126                 }
1127                 break;
1128         case orientation_horizontal_vertical:
1129                 l=w->children;
1130                 x0=x;
1131                 count=0;
1132                 width/=cols;
1133                 height/=rows;
1134                 while (l) {
1135                         wc=l->data;
1136                         wc->p.x=x;
1137                         wc->p.y=y;
1138                         if (wc->flags & flags_fill) {
1139                                 wc->w=width;
1140                                 wc->h=height;
1141                         }
1142                         if (w->flags & gravity_left)
1143                                 wc->p.x=x;
1144                         if (w->flags & gravity_xcenter)
1145                                 wc->p.x=x+(width-wc->w)/2;
1146                         if (w->flags & gravity_right)
1147                                 wc->p.x=x+width-wc->w;
1148                         if (w->flags & gravity_top)
1149                                 wc->p.y=y;
1150                         if (w->flags & gravity_ycenter)
1151                                 wc->p.y=y+(height-wc->h)/2;
1152                         if (w->flags & gravity_bottom)
1153                                 wc->p.y=y-height-wc->h;
1154                         x+=width;
1155                         if (++count == cols) {
1156                                 count=0;
1157                                 x=x0;
1158                                 y+=height;
1159                         }
1160                         l=g_list_next(l);
1161                 }
1162                 break;
1163         default:
1164                 break;
1165         }
1166         /**
1167          * Call pack again on each child,
1168          * the child has now had its size and coordinates
1169          * set so they can repack their children.
1170          */
1171         l=w->children;
1172         while (l) {
1173                 wc=l->data;
1174                 gui_internal_widget_pack(this, wc);
1175                 l=g_list_next(l);
1176         }
1177 }
1178
1179 static void
1180 gui_internal_widget_append(struct widget *parent, struct widget *child)
1181 {
1182         if (! child)
1183                 return;
1184         if (! child->background)
1185                 child->background=parent->background;
1186         parent->children=g_list_append(parent->children, child);
1187 }
1188
1189 static void gui_internal_widget_prepend(struct widget *parent, struct widget *child)
1190 {
1191         if (! child->background)
1192                 child->background=parent->background;
1193         parent->children=g_list_prepend(parent->children, child);
1194 }
1195
1196 static void gui_internal_widget_children_destroy(struct gui_priv *this, struct widget *w)
1197 {
1198         GList *l;
1199         struct widget *wc;
1200
1201         l=w->children;
1202         while (l) {
1203                 wc=l->data;
1204                 gui_internal_widget_destroy(this, wc);
1205                 l=g_list_next(l);
1206         }
1207         g_list_free(w->children);
1208         w->children=NULL;
1209 }
1210
1211 static void gui_internal_widget_destroy(struct gui_priv *this, struct widget *w)
1212 {
1213         gui_internal_widget_children_destroy(this, w);
1214         g_free(w->command);
1215         g_free(w->speech);
1216         g_free(w->text);
1217         if (w->img)
1218                 graphics_image_free(this->gra, w->img);
1219         if (w->prefix)
1220                 g_free(w->prefix);
1221         if (w->name)
1222                 g_free(w->name);
1223         if (w->data_free)
1224                 w->data_free(w->data);
1225         if (w->cb && w->remove_cb)
1226                 w->remove_cb(w->instance, w->cb);
1227         if(w->free)
1228                 w->free(this,w);
1229         else
1230                 g_free(w);
1231 }
1232
1233
1234 static void
1235 gui_internal_widget_render(struct gui_priv *this, struct widget *w)
1236 {
1237         if(w->p.x > this->root.w || w->p.y > this->root.h)
1238                 return;
1239
1240         switch (w->type) {
1241         case widget_box:
1242                 gui_internal_box_render(this, w);
1243                 break;
1244         case widget_label:
1245                 gui_internal_label_render(this, w);
1246                 break;
1247         case widget_image:
1248                 gui_internal_image_render(this, w);
1249                 break;
1250         case widget_table:
1251                 gui_internal_table_render(this,w);
1252                 break;
1253         default:
1254                 break;
1255         }
1256 }
1257
1258 static void
1259 gui_internal_widget_pack(struct gui_priv *this, struct widget *w)
1260 {
1261         switch (w->type) {
1262         case widget_box:
1263                 gui_internal_box_pack(this, w);
1264                 break;
1265         case widget_table:
1266           gui_internal_table_pack(this,w);
1267         default:
1268                 break;
1269         }
1270 }
1271
1272 //##############################################################################################################
1273 //# Description:
1274 //# Comment:
1275 //# Authors: Martin Schaller (04/2008)
1276 //##############################################################################################################
1277 static void gui_internal_call_highlighted(struct gui_priv *this)
1278 {
1279         if (! this->highlighted || ! this->highlighted->func)
1280                 return;
1281         this->highlighted->reason=1;
1282         this->highlighted->func(this, this->highlighted, this->highlighted->data);
1283 }
1284
1285 static void
1286 gui_internal_say(struct gui_priv *this, struct widget *w, int questionmark)
1287 {
1288         char *text=w->speech;
1289         if (! this->speech)
1290                 return;
1291         if (!text)
1292                 text=w->text;
1293         if (!text)
1294                 text=w->name;
1295         if (text) {
1296                 text=g_strdup_printf("%s%c", text, questionmark ? '?':'\0');
1297                 navit_say(this->nav, text);
1298                 g_free(text);
1299         }
1300 }
1301
1302 static void
1303 gui_internal_prune_menu(struct gui_priv *this, struct widget *w)
1304 {
1305         GList *l;
1306         struct widget *wr;
1307         gui_internal_search_idle_end(this);
1308         while ((l = g_list_last(this->root.children))) {
1309                 if (l->data == w) {
1310                         void (*redisplay)(struct gui_priv *priv, struct widget *widget, void *data);
1311                         gui_internal_say(this, w, 0);
1312                         redisplay=w->menu_data->redisplay;
1313                         wr=w->menu_data->redisplay_widget;
1314                         if (!w->menu_data->redisplay) {
1315                                 gui_internal_widget_render(this, w);
1316                                 return;
1317                         }
1318                         gui_internal_widget_destroy(this, l->data);
1319                         this->root.children=g_list_remove(this->root.children, l->data);
1320                         redisplay(this, wr, wr->data);
1321                         return;
1322                 }
1323                 gui_internal_widget_destroy(this, l->data);
1324                 this->root.children=g_list_remove(this->root.children, l->data);
1325         }
1326 }
1327
1328 static void
1329 gui_internal_prune_menu_count(struct gui_priv *this, int count, int render)
1330 {
1331         GList *l;
1332         gui_internal_search_idle_end(this);
1333         while ((l = g_list_last(this->root.children)) && count-- > 0) {
1334                 gui_internal_widget_destroy(this, l->data);
1335                 this->root.children=g_list_remove(this->root.children, l->data);
1336         }
1337         if (l && render) {
1338                 gui_internal_say(this, l->data, 0);
1339                 gui_internal_widget_render(this, l->data);
1340         }
1341 }
1342
1343 static void
1344 gui_internal_back(struct gui_priv *this, struct widget *w, void *data)
1345 {
1346         gui_internal_prune_menu_count(this, 1, 1);
1347 }
1348
1349 static void
1350 gui_internal_cmd_return(struct gui_priv *this, struct widget *wm, void *data)
1351 {
1352         gui_internal_prune_menu(this, wm->data);
1353 }
1354
1355 static void
1356 gui_internal_cmd2_back_to_map(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
1357 {
1358         gui_internal_prune_menu(this, NULL);
1359 }
1360
1361
1362 static void
1363 gui_internal_cmd_main_menu(struct gui_priv *this, struct widget *wm, void *data)
1364 {
1365         gui_internal_prune_menu(this, this->root.children->data);
1366 }
1367
1368 static struct widget *
1369 gui_internal_top_bar(struct gui_priv *this)
1370 {
1371         struct widget *w,*wm,*wh,*wc,*wcn;
1372         int dots_len, sep_len;
1373         GList *res=NULL,*l;
1374         int width,width_used=0,use_sep=0,incomplete=0;
1375         struct graphics_gc *foreground=(this->flags & 256 ? this->background : this->text_foreground);
1376 /* flags
1377         1:Don't expand bar to screen width
1378         2:Don't show Map Icon
1379         4:Don't show Home Icon
1380         8:Show only current menu
1381         16:Don't use menu titles as button
1382         32:Show navit version
1383         64:Show time
1384         128:Show help
1385         256:Use background for menu headline
1386         512:Set osd_configuration and zoom to route when setting position
1387 */
1388
1389         w=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|(this->flags & 1 ? 0:flags_fill));
1390         w->bl=this->spacing;
1391         w->spx=this->spacing;
1392         w->background=this->background2;
1393         if ((this->flags & 6) == 6) {
1394                 w->bl=10;
1395                 w->br=10;
1396                 w->bt=6;
1397                 w->bb=6;
1398         }
1399         width=this->root.w-w->bl;
1400         if (! (this->flags & 2)) {
1401                 wm=gui_internal_button_new_with_callback(this, NULL,
1402                         image_new_s(this, "gui_map"), gravity_center|orientation_vertical,
1403                         gui_internal_cmd_return, NULL);
1404                 wm->speech=g_strdup(_("Back to map"));
1405                 gui_internal_widget_pack(this, wm);
1406                 gui_internal_widget_append(w, wm);
1407                 width-=wm->w;
1408         }
1409         if (! (this->flags & 4)) {
1410                 wh=gui_internal_button_new_with_callback(this, NULL,
1411                         image_new_s(this, "gui_home"), gravity_center|orientation_vertical,
1412                         gui_internal_cmd_main_menu, NULL);
1413                 wh->speech=g_strdup(_("Main Menu"));
1414                 gui_internal_widget_pack(this, wh);
1415                 gui_internal_widget_append(w, wh);
1416                 width-=wh->w;
1417         }
1418         if (!(this->flags & 6))
1419                 width-=w->spx;
1420         l=g_list_last(this->root.children);
1421         wcn=gui_internal_label_new(this,".. »");
1422         wcn->foreground=foreground;
1423         dots_len=wcn->w;
1424         gui_internal_widget_destroy(this, wcn);
1425         wcn=gui_internal_label_new(this,"»");
1426         wcn->foreground=foreground;
1427         sep_len=wcn->w;
1428         gui_internal_widget_destroy(this, wcn);
1429         while (l) {
1430                 if (g_list_previous(l) || !g_list_next(l)) {
1431                         wc=l->data;
1432                         wcn=gui_internal_label_new(this, wc->text);
1433                         wcn->foreground=foreground;
1434                         if (g_list_next(l))
1435                                 use_sep=1;
1436                         else
1437                                 use_sep=0;
1438                         dbg(1,"%d (%s) + %d + %d + %d > %d\n", wcn->w, wc->text, width_used, w->spx, use_sep ? sep_len : 0, width);
1439                         if (wcn->w + width_used + w->spx + (use_sep ? sep_len : 0) + (g_list_previous(l) ? dots_len : 0) > width) {
1440                                 incomplete=1;
1441                                 gui_internal_widget_destroy(this, wcn);
1442                                 break;
1443                         }
1444                         if (use_sep) {
1445                                 struct widget *wct=gui_internal_label_new(this, "»");
1446                                 wct->foreground=foreground;
1447                                 res=g_list_prepend(res, wct);
1448                                 width_used+=sep_len+w->spx;
1449                         }
1450                         width_used+=wcn->w;
1451                         if (!(this->flags & 16)) {
1452                                 wcn->func=gui_internal_cmd_return;
1453                                 wcn->data=wc;
1454                                 wcn->state |= STATE_SENSITIVE;
1455                         }
1456                         res=g_list_prepend(res, wcn);
1457                         if (this->flags & 8)
1458                                 break;
1459                 }
1460                 l=g_list_previous(l);
1461         }
1462         if (incomplete) {
1463                 if (! res) {
1464                         wcn=gui_internal_label_new_abbrev(this, wc->text, width-width_used-w->spx-dots_len);
1465                         wcn->foreground=foreground;
1466                         wcn->func=gui_internal_cmd_return;
1467                         wcn->data=wc;
1468                         wcn->state |= STATE_SENSITIVE;
1469                         res=g_list_prepend(res, wcn);
1470                         l=g_list_previous(l);
1471                         wc=l->data;
1472                 }
1473                 wcn=gui_internal_label_new(this, ".. »");
1474                 wcn->foreground=foreground;
1475                 wcn->func=gui_internal_cmd_return;
1476                 wcn->data=wc;
1477                 wcn->state |= STATE_SENSITIVE;
1478                 res=g_list_prepend(res, wcn);
1479         }
1480         l=res;
1481         while (l) {
1482                 gui_internal_widget_append(w, l->data);
1483                 l=g_list_next(l);
1484         }
1485         if (this->flags & 32) {
1486                 extern char *version;
1487                 char *version_text=g_strdup_printf("Navit %s",version);
1488                 wcn=gui_internal_label_new(this, version_text);
1489                 g_free(version_text);
1490                 wcn->flags=gravity_right_center|flags_expand;
1491                 gui_internal_widget_append(w, wcn);
1492         }
1493 #if 0
1494         if (dots)
1495                 gui_internal_widget_destroy(this, dots);
1496 #endif
1497         return w;
1498 }
1499
1500 static struct widget *
1501 gui_internal_time_help(struct gui_priv *this)
1502 {
1503         struct widget *w,*wc,*wcn;
1504         char timestr[64];
1505         struct tm *tm;
1506         time_t timep;
1507
1508         w=gui_internal_box_new(this, gravity_right_center|orientation_horizontal|flags_fill);
1509         w->bl=this->spacing;
1510         w->spx=this->spacing;
1511         w->spx=10;
1512         w->bl=10;
1513         w->br=10;
1514         w->bt=6;
1515         w->bb=6;
1516         if (this->flags & 64) {
1517                 wc=gui_internal_box_new(this, gravity_right_top|orientation_vertical|flags_fill);
1518                 wc->bl=10;
1519                 wc->br=20;
1520                 wc->bt=6;
1521                 wc->bb=6;
1522                 timep=time(NULL);
1523                 tm=localtime(&timep);
1524                 strftime(timestr, 64, "%H:%M %d.%m.%Y", tm);
1525                 wcn=gui_internal_label_new(this, timestr);
1526                 gui_internal_widget_append(wc, wcn);
1527                 gui_internal_widget_append(w, wc);
1528         }
1529         if (this->flags & 128) {
1530                 wcn=gui_internal_button_new_with_callback(this, _("Help"), image_new_l(this, "gui_help"), gravity_center|orientation_vertical|flags_fill, NULL, NULL);
1531                 gui_internal_widget_append(w, wcn);
1532         }
1533         return w;
1534 }
1535
1536
1537 /**
1538  * Applys the configuration values to this based on the settings
1539  * specified in the configuration file (this->config) and
1540  * the most approriate default profile based on screen resolution.
1541  *
1542  * This function should be run after this->root is setup and could
1543  * be rerun after the window is resized.
1544  *
1545  * @authors Steve Singer <ssinger_pg@sympatico.ca> (09/2008)
1546  */
1547 static void gui_internal_apply_config(struct gui_priv *this)
1548 {
1549   struct gui_config_settings *  current_config=0;
1550
1551   dbg(1,"w=%d h=%d\n", this->root.w, this->root.h);
1552   /**
1553    * Select default values from profile based on the screen.
1554    */
1555   if((this->root.w > 320 || this->root.h > 320) && this->root.w > 240 && this->root.h > 240)
1556   {
1557     if((this->root.w > 640 || this->root.h > 640) && this->root.w > 480 && this->root.h > 480 )
1558     {
1559       current_config = &config_profiles[LARGE_PROFILE];
1560     }
1561     else
1562     {
1563       current_config = &config_profiles[MEDIUM_PROFILE];
1564     }
1565   }
1566   else
1567   {
1568     current_config = &config_profiles[SMALL_PROFILE];
1569   }
1570
1571   /**
1572    * Apply override values from config file
1573    */
1574   if(this->config.font_size == -1 )
1575   {
1576     this->font_size = current_config->font_size;
1577   }
1578   else
1579   {
1580     this->font_size = this->config.font_size;
1581   }
1582
1583   if(this->config.icon_xs == -1 )
1584   {
1585       this->icon_xs = current_config->icon_xs;
1586   }
1587   else
1588   {
1589     this->icon_xs = this->config.icon_xs;
1590   }
1591
1592   if(this->config.icon_s == -1 )
1593   {
1594     this->icon_s = current_config->icon_s;
1595   }
1596   else
1597   {
1598     this->icon_s = this->config.icon_s;
1599   }
1600   if(this->config.icon_l == -1 )
1601   {
1602     this->icon_l = current_config->icon_l;
1603   }
1604   else
1605   {
1606     this->icon_l = this->config.icon_l;
1607   }
1608   if(this->config.spacing == -1 )
1609   {
1610     this->spacing = current_config->spacing;
1611   }
1612   else
1613   {
1614     this->spacing = current_config->spacing;
1615   }
1616
1617 }
1618
1619 static struct widget *
1620 gui_internal_button_label(struct gui_priv *this, char *label, int mode)
1621 {
1622         struct widget *wl,*wlb;
1623         struct widget *wb=gui_internal_menu_data(this)->button_bar;
1624         wlb=gui_internal_box_new(this, gravity_right_center|orientation_vertical);
1625         wl=gui_internal_label_new(this, label);
1626         wlb->border=1;
1627         wlb->foreground=this->text_foreground;
1628         wlb->bl=20;
1629         wlb->br=20;
1630         wlb->bb=6;
1631         wlb->bt=6;
1632         gui_internal_widget_append(wlb, wl);
1633         if (mode == 1)
1634                 gui_internal_widget_prepend(wb, wlb);
1635         if (mode == -1)
1636                 gui_internal_widget_append(wb, wlb);
1637
1638         return wlb;
1639 }
1640
1641
1642 static struct widget *
1643 gui_internal_menu(struct gui_priv *this, const char *label)
1644 {
1645         struct widget *menu,*w,*w1,*topbox;
1646
1647         gui_internal_search_idle_end(this);
1648         topbox=gui_internal_box_new_with_label(this, 0, label);
1649         topbox->w=this->root.w;
1650         topbox->h=this->root.h;
1651         gui_internal_widget_append(&this->root, topbox);
1652         menu=gui_internal_box_new(this, gravity_left_center|orientation_vertical);
1653         menu->w=this->root.w;
1654         menu->h=this->root.h;
1655         menu->background=this->background;
1656         gui_internal_apply_config(this);
1657         this->font=graphics_font_new(this->gra,this->font_size,1);
1658         topbox->menu_data=g_new0(struct menu_data, 1);
1659         gui_internal_widget_append(topbox, menu);
1660         w=gui_internal_top_bar(this);
1661         gui_internal_widget_append(menu, w);
1662         w=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
1663         w->spx=4*this->spacing;
1664         w->w=menu->w;
1665         gui_internal_widget_append(menu, w);
1666         if (this->flags & 16) {
1667                 struct widget *wlb,*wb,*wm=w;
1668                 wm->flags=gravity_center|orientation_vertical|flags_expand|flags_fill;
1669                 w=gui_internal_box_new(this, gravity_center|orientation_horizontal|flags_expand|flags_fill);
1670                 dbg(0,"topbox->menu_data=%p\n", topbox->menu_data);
1671                 gui_internal_widget_append(wm, w);
1672                 wb=gui_internal_box_new(this, gravity_right_center|orientation_horizontal|flags_fill);
1673                 wb->bl=6;
1674                 wb->br=6;
1675                 wb->bb=6;
1676                 wb->bt=6;
1677                 wb->spx=6;
1678                 topbox->menu_data->button_bar=wb;
1679                 gui_internal_widget_append(wm, wb);
1680                 wlb=gui_internal_button_label(this,_("Back"),1);
1681                 wlb->func=gui_internal_back;
1682                 wlb->state |= STATE_SENSITIVE;
1683         }
1684         if (this->flags & 192) {
1685                 menu=gui_internal_box_new(this, gravity_left_center|orientation_vertical);
1686                 menu->w=this->root.w;
1687                 menu->h=this->root.h;
1688                 w1=gui_internal_time_help(this);
1689                 gui_internal_widget_append(menu, w1);
1690                 w1=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
1691                 gui_internal_widget_append(menu, w1);
1692                 gui_internal_widget_append(topbox, menu);
1693                 menu->background=NULL;
1694         }
1695         return w;
1696 }
1697
1698 static struct menu_data *
1699 gui_internal_menu_data(struct gui_priv *this)
1700 {
1701         GList *l;
1702         struct widget *menu;
1703
1704         l=g_list_last(this->root.children);
1705         menu=l->data;
1706         return menu->menu_data;
1707 }
1708
1709 static void
1710 gui_internal_menu_render(struct gui_priv *this)
1711 {
1712         GList *l;
1713         struct widget *menu;
1714
1715         l=g_list_last(this->root.children);
1716         menu=l->data;
1717         gui_internal_say(this, menu, 0);
1718         gui_internal_widget_pack(this, menu);
1719         gui_internal_widget_render(this, menu);
1720 }
1721
1722 static void
1723 gui_internal_cmd_set_destination(struct gui_priv *this, struct widget *wm, void *data)
1724 {
1725         char *name=data;
1726         dbg(0,"c=%d:0x%x,0x%x\n", wm->c.pro, wm->c.x, wm->c.y);
1727         navit_set_destination(this->nav, &wm->c, name, 1);
1728         if (this->flags & 512) {
1729                 struct attr follow;
1730                 follow.type=attr_follow;
1731                 follow.u.num=180;
1732                 navit_set_attr(this->nav, &this->osd_configuration);
1733                 navit_set_attr(this->nav, &follow);
1734                 navit_zoom_to_route(this->nav, 0);
1735         }
1736         gui_internal_prune_menu(this, NULL);
1737 }
1738
1739 static void
1740 gui_internal_cmd_set_position(struct gui_priv *this, struct widget *wm, void *data)
1741 {
1742         navit_set_position(this->nav, &wm->c);
1743         gui_internal_prune_menu(this, NULL);
1744 }
1745
1746 static void
1747 gui_internal_cmd_add_bookmark_do(struct gui_priv *this, struct widget *widget)
1748 {
1749         GList *l;
1750         dbg(0,"text='%s'\n", widget->text);
1751         if (widget->text && strlen(widget->text))
1752                 navit_add_bookmark(this->nav, &widget->c, widget->text);
1753         g_free(widget->text);
1754         widget->text=NULL;
1755         l=g_list_previous(g_list_last(this->root.children));
1756         gui_internal_prune_menu(this, l->data);
1757 }
1758
1759 static void
1760 gui_internal_cmd_add_bookmark_clicked(struct gui_priv *this, struct widget *widget, void *data)
1761 {
1762         gui_internal_cmd_add_bookmark_do(this, widget->data);
1763 }
1764
1765 static void
1766 gui_internal_cmd_add_bookmark_changed(struct gui_priv *this, struct widget *wm, void *data)
1767 {
1768         int len;
1769         dbg(1,"enter\n");
1770         if (wm->text) {
1771                 len=strlen(wm->text);
1772                 dbg(1,"len=%d\n", len);
1773                 if (len && (wm->text[len-1] == '\n' || wm->text[len-1] == '\r')) {
1774                         wm->text[len-1]='\0';
1775                         gui_internal_cmd_add_bookmark_do(this, wm);
1776                 }
1777         }
1778 }
1779
1780
1781 static struct widget * gui_internal_keyboard(struct gui_priv *this, int mode);
1782
1783 static void
1784 gui_internal_cmd_add_bookmark2(struct gui_priv *this, struct widget *wm, void *data)
1785 {
1786         struct widget *w,*wb,*wk,*wl,*we,*wnext;
1787         char *name=data;
1788         wb=gui_internal_menu(this,_("Add Bookmark"));
1789         w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
1790         gui_internal_widget_append(wb, w);
1791         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
1792         gui_internal_widget_append(w, we);
1793         gui_internal_widget_append(we, wk=gui_internal_label_new(this, name));
1794         wk->state |= STATE_EDIT|STATE_CLEAR;
1795         wk->background=this->background;
1796         wk->flags |= flags_expand|flags_fill;
1797         wk->func = gui_internal_cmd_add_bookmark_changed;
1798         wk->c=wm->c;
1799         gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
1800         wnext->state |= STATE_SENSITIVE;
1801         wnext->func = gui_internal_cmd_add_bookmark_clicked;
1802         wnext->data=wk;
1803         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
1804         gui_internal_widget_append(w, wl);
1805         if (this->keyboard)
1806                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
1807         gui_internal_menu_render(this);
1808 }
1809
1810
1811 static void
1812 get_direction(char *buffer, int angle, int mode)
1813 {
1814         angle=angle%360;
1815         switch (mode) {
1816         case 0:
1817                 sprintf(buffer,"%d",angle);
1818                 break;
1819         case 1:
1820                 if (angle < 69 || angle > 291)
1821                         *buffer++='N';
1822                 if (angle > 111 && angle < 249)
1823                         *buffer++='S';
1824                 if (angle > 22 && angle < 158)
1825                         *buffer++='E';
1826                 if (angle > 202 && angle < 338)
1827                         *buffer++='W';
1828                 *buffer++='\0';
1829                 break;
1830         case 2:
1831                 angle=(angle+15)/30;
1832                 if (! angle)
1833                         angle=12;
1834                 sprintf(buffer,"%d H", angle);
1835                 break;
1836         }
1837 }
1838
1839 struct selector {
1840         char *icon;
1841         char *name;
1842         enum item_type *types;
1843 } selectors[]={
1844         {"bank","Bank",(enum item_type []){type_poi_bank,type_poi_bank,type_none}},
1845         {"fuel","Fuel",(enum item_type []){type_poi_fuel,type_poi_fuel,type_none}},
1846         {"hotel","Hotel",(enum item_type []) {
1847                 type_poi_hotel,type_poi_camp_rv,
1848                 type_poi_camping,type_poi_camping,
1849                 type_poi_resort,type_poi_resort,
1850                 type_poi_motel,type_poi_hostel,
1851                 type_none}},
1852         {"restaurant","Restaurant",(enum item_type []) {
1853                 type_poi_bar,type_poi_picnic,
1854                 type_poi_burgerking,type_poi_fastfood,
1855                 type_poi_restaurant,type_poi_restaurant,
1856                 type_none}},
1857         {"shopping","Shopping",(enum item_type []) {
1858                 type_poi_mall,type_poi_mall,
1859                 type_poi_shop_grocery,type_poi_shop_grocery,
1860                 type_none}},
1861         {"hospital","Service",(enum item_type []) {
1862                 type_poi_marina,type_poi_marina,
1863                 type_poi_hospital,type_poi_hospital,
1864                 type_poi_public_utilities,type_poi_public_utilities,
1865                 type_poi_police,type_poi_autoservice,
1866                 type_poi_information,type_poi_information,
1867                 type_poi_personal_service,type_poi_repair_service,
1868                 type_poi_restroom,type_poi_restroom,
1869                 type_none}},
1870         {"parking","Parking",(enum item_type []){type_poi_car_parking,type_poi_car_parking,type_none}},
1871         {"peak","Land Features",(enum item_type []){
1872                 type_poi_land_feature,type_poi_rock,
1873                 type_poi_dam,type_poi_dam,
1874                 type_none}},
1875         {"unknown","Other",(enum item_type []){
1876                 type_point_unspecified,type_point_unkn-1,
1877                 type_point_unkn+1,type_poi_land_feature-1,
1878                 type_poi_rock+1,type_poi_fuel-1,
1879                 type_poi_marina+1,type_poi_car_parking-1,
1880                 type_poi_car_parking+1,type_poi_bar-1,
1881                 type_poi_bank+1,type_poi_dam-1,
1882                 type_poi_dam+1,type_poi_information-1,
1883                 type_poi_information+1,type_poi_mall-1,
1884                 type_poi_mall+1,type_poi_personal_service-1,
1885                 type_poi_restaurant+1,type_poi_restroom-1,
1886                 type_poi_restroom+1,type_poi_shop_grocery-1,
1887                 type_poi_shop_grocery+1,type_poi_motel-1,
1888                 type_poi_hostel+1,type_selected_point,
1889                 type_none}},
1890         {"unknown","Unknown",(enum item_type []){
1891                 type_point_unkn,type_point_unkn,
1892                 type_none}},
1893 };
1894
1895 static void gui_internal_cmd_pois(struct gui_priv *this, struct widget *wm, void *data);
1896
1897 static struct widget *
1898 gui_internal_cmd_pois_selector(struct gui_priv *this, struct pcoord *c)
1899 {
1900         struct widget *wl,*wb;
1901         int i;
1902         wl=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
1903         for (i = 0 ; i < sizeof(selectors)/sizeof(struct selector) ; i++) {
1904         gui_internal_widget_append(wl, wb=gui_internal_button_new_with_callback(this, NULL,
1905                 image_new_xs(this, selectors[i].icon), gravity_left_center|orientation_vertical,
1906                 gui_internal_cmd_pois, &selectors[i]));
1907                 wb->c=*c;
1908                 wb->bt=10;
1909         }
1910         return wl;
1911 }
1912
1913 static struct widget *
1914 gui_internal_cmd_pois_item(struct gui_priv *this, struct coord *center, struct item *item, struct coord *c, int dist)
1915 {
1916         char distbuf[32];
1917         char dirbuf[32];
1918         char *type;
1919         struct attr attr;
1920         struct widget *wl,*wt;
1921         char *text;
1922
1923         wl=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
1924
1925         sprintf(distbuf,"%d", dist/1000);
1926         get_direction(dirbuf, transform_get_angle_delta(center, c, 0), 1);
1927         type=item_to_name(item->type);
1928         if (item_attr_get(item, attr_label, &attr)) {
1929                 wl->name=g_strdup_printf("%s %s",type,attr.u.str);
1930         } else {
1931                 attr.u.str="";
1932                 wl->name=g_strdup(type);
1933         }
1934         text=g_strdup_printf("%s %s %s %s", distbuf, dirbuf, type, attr.u.str);
1935         wt=gui_internal_label_new(this, text);
1936         wt->datai=dist;
1937         gui_internal_widget_append(wl, wt);
1938         g_free(text);
1939
1940         return wl;
1941 }
1942
1943 static gint
1944 gui_internal_cmd_pois_sort_num(gconstpointer a, gconstpointer b, gpointer user_data)
1945 {
1946         const struct widget *wa=a;
1947         const struct widget *wb=b;
1948         struct widget *wac=wa->children->data;
1949         struct widget *wbc=wb->children->data;
1950 #if 0
1951         int ia,ib;
1952         ia=atoi(wac->text);
1953         ib=atoi(wbc->text);
1954
1955         return ia-ib;
1956 #else
1957         return wac->datai-wbc->datai;
1958 #endif
1959 }
1960
1961 static int
1962 gui_internal_cmd_pois_item_selected(struct selector *sel, enum item_type type)
1963 {
1964         enum item_type *types;
1965         if (type >= type_line)
1966                 return 0;
1967         if (! sel || !sel->types)
1968                 return 1;
1969         types=sel->types;
1970         while (*types != type_none) {
1971                 if (type >= types[0] && type <= types[1]) {
1972                         return 1;
1973                 }
1974                 types+=2;
1975         }
1976         return 0;
1977 }
1978
1979 static void gui_internal_cmd_position(struct gui_priv *this, struct widget *wm, void *data);
1980
1981 static void
1982 gui_internal_cmd_pois(struct gui_priv *this, struct widget *wm, void *data)
1983 {
1984         struct map_selection *sel,*selm;
1985         struct coord c,center;
1986         struct mapset_handle *h;
1987         struct map *m;
1988         struct map_rect *mr;
1989         struct item *item;
1990         int idist,dist=20000;
1991         struct widget *wi,*w,*w2,*wb;
1992         enum projection pro=wm->c.pro;
1993         struct selector *isel=wm->data;
1994
1995         wb=gui_internal_menu(this, isel ? isel->name : _("POIs"));
1996         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
1997         gui_internal_widget_append(wb, w);
1998         if (! isel)
1999                 gui_internal_widget_append(w, gui_internal_cmd_pois_selector(this,&wm->c));
2000         w2=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
2001         gui_internal_widget_append(w, w2);
2002
2003         sel=map_selection_rect_new(&wm->c, dist, 18);
2004         center.x=wm->c.x;
2005         center.y=wm->c.y;
2006         h=mapset_open(navit_get_mapset(this->nav));
2007         while ((m=mapset_next(h, 1))) {
2008                 selm=map_selection_dup_pro(sel, pro, map_projection(m));
2009                 mr=map_rect_new(m, selm);
2010                 dbg(2,"mr=%p\n", mr);
2011                 if (mr) {
2012                         while ((item=map_rect_get_item(mr))) {
2013                                 if (gui_internal_cmd_pois_item_selected(isel, item->type) &&
2014                                     item_coord_get_pro(item, &c, 1, pro) &&
2015                                     coord_rect_contains(&sel->u.c_rect, &c) &&
2016                                     (idist=transform_distance(pro, &center, &c)) < dist) {
2017                                         gui_internal_widget_append(w2, wi=gui_internal_cmd_pois_item(this, &center, item, &c, idist));
2018                                         wi->func=gui_internal_cmd_position;
2019                                         wi->data=(void *)2;
2020                                         wi->item=*item;
2021                                         wi->state |= STATE_SENSITIVE;
2022                                         wi->c.x=c.x;
2023                                         wi->c.y=c.y;
2024                                         wi->c.pro=pro;
2025                                 }
2026                         }
2027                         map_rect_destroy(mr);
2028                 }
2029                 map_selection_destroy(selm);
2030         }
2031         map_selection_destroy(sel);
2032         mapset_close(h);
2033         w2->children=g_list_sort_with_data(w2->children,  gui_internal_cmd_pois_sort_num, (void *)1);
2034         gui_internal_menu_render(this);
2035 }
2036
2037 static void
2038 gui_internal_cmd_view_on_map(struct gui_priv *this, struct widget *wm, void *data)
2039 {
2040         struct widget *w=wm->data;
2041         int highlight=(w->data == (void *)2 || w->data == (void *)3 || w->data == (void *)4);
2042         if (highlight) {
2043                 graphics_clear_selection(this->gra, NULL);
2044                 graphics_add_selection(this->gra, &w->item, NULL);
2045         }
2046         navit_set_center(this->nav, &w->c, 1);
2047         gui_internal_prune_menu(this, NULL);
2048 }
2049
2050
2051 static void
2052 gui_internal_cmd_view_attribute_details(struct gui_priv *this, struct widget *wm, void *data)
2053 {
2054         struct widget *w,*wb;
2055         struct map_rect *mr;
2056         struct item *item;
2057         struct attr attr;
2058         char *text,*url;
2059         int i;
2060
2061         text=g_strdup_printf("Attribute %s",wm->name);
2062         wb=gui_internal_menu(this, text);
2063         g_free(text);
2064         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
2065         gui_internal_widget_append(wb, w);
2066         mr=map_rect_new(wm->item.map, NULL);
2067         item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
2068         for (i = 0 ; i < wm->datai ; i++) {
2069                 item_attr_get(item, attr_any, &attr);
2070         }
2071         if (item_attr_get(item, attr_any, &attr)) {
2072                 url=NULL;
2073                 switch (attr.type) {
2074                 case attr_osm_nodeid:
2075                         url=g_strdup_printf("http://www.openstreetmap.org/browse/node/%Ld\n",*attr.u.num64);
2076                         break;
2077                 case attr_osm_wayid:
2078                         url=g_strdup_printf("http://www.openstreetmap.org/browse/way/%Ld\n",*attr.u.num64);
2079                         break;
2080                 case attr_osm_relationid:
2081                         url=g_strdup_printf("http://www.openstreetmap.org/browse/relation/%Ld\n",*attr.u.num64);
2082                         break;
2083                 default:
2084                         break;
2085                 }
2086                 if (url) {      
2087                         gui_internal_widget_append(w,
2088                                         wb=gui_internal_button_new_with_callback(this, _("View in Browser"),
2089                                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2090                                                 gui_internal_cmd_view_in_browser, NULL));
2091                         wb->name=url;
2092                 }
2093         }
2094         map_rect_destroy(mr);
2095         gui_internal_menu_render(this);
2096 }
2097
2098 static void
2099 gui_internal_cmd_view_attributes(struct gui_priv *this, struct widget *wm, void *data)
2100 {
2101         struct widget *w,*wb;
2102         struct map_rect *mr;
2103         struct item *item;
2104         struct attr attr;
2105         char *text;
2106         int count=0;
2107
2108         dbg(0,"item=%p 0x%x 0x%x\n", wm->item.map,wm->item.id_hi, wm->item.id_lo);
2109         wb=gui_internal_menu(this, "Attributes");
2110         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
2111         gui_internal_widget_append(wb, w);
2112         mr=map_rect_new(wm->item.map, NULL);
2113         item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
2114         dbg(0,"item=%p\n", item);
2115         if (item) {
2116                 while(item_attr_get(item, attr_any, &attr)) {
2117                         text=g_strdup_printf("%s:%s", attr_to_name(attr.type), attr_to_text(&attr, wm->item.map, 1));
2118                         gui_internal_widget_append(w,
2119                         wb=gui_internal_button_new_with_callback(this, text,
2120                                 NULL, gravity_left_center|orientation_horizontal|flags_fill,
2121                                 gui_internal_cmd_view_attribute_details, NULL));
2122                         wb->name=g_strdup(text);
2123                         wb->item=wm->item;
2124                         wb->datai=count++;
2125                         g_free(text);
2126                 }
2127         }
2128         map_rect_destroy(mr);
2129         gui_internal_menu_render(this);
2130 }
2131
2132 static void
2133 gui_internal_cmd_view_in_browser(struct gui_priv *this, struct widget *wm, void *data)
2134 {
2135         struct map_rect *mr;
2136         struct item *item;
2137         struct attr attr;
2138         char *cmd=NULL;
2139
2140         if (!wm->name) {
2141                 dbg(0,"item=%p 0x%x 0x%x\n", wm->item.map,wm->item.id_hi, wm->item.id_lo);
2142                 mr=map_rect_new(wm->item.map, NULL);
2143                 item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
2144                 dbg(0,"item=%p\n", item);
2145                 if (item) {
2146                         while(item_attr_get(item, attr_url_local, &attr)) {
2147                                 if (! cmd)
2148                                         cmd=g_strdup_printf("navit-browser.sh '%s' &",attr.u.str);
2149                         }
2150                 }
2151                 map_rect_destroy(mr);
2152         } else {
2153                 cmd=g_strdup_printf("navit-browser.sh '%s' &",wm->name);
2154         }
2155         if (cmd) {
2156 #ifdef HAVE_SYSTEM
2157                 system(cmd);
2158 #else
2159                 dbg(0,"calling external cmd '%s' is not supported\n",cmd);
2160 #endif
2161                 g_free(cmd);
2162         }
2163 }
2164
2165 static void
2166 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)
2167 {
2168         struct widget *wb,*w,*wc,*wbc;
2169         struct coord_geo g;
2170         struct pcoord pc;
2171         struct coord c;
2172         char *coord;
2173
2174         if (pc_in) {
2175                 pc=*pc_in;
2176                 c.x=pc.x;
2177                 c.y=pc.y;
2178                 dbg(0,"x=0x%x y=0x%x\n", c.x, c.y);
2179                 transform_to_geo(pc.pro, &c, &g);
2180         } else if (g_in) {
2181                 struct attr attr;
2182                 if (!navit_get_attr(this->nav, attr_projection, &attr, NULL))
2183                         return;
2184                 g=*g_in;
2185                 pc.pro=attr.u.projection;
2186                 transform_from_geo(pc.pro, &g, &c);
2187                 pc.x=c.x;
2188                 pc.y=c.y;
2189         } else
2190                 return;
2191
2192         wb=gui_internal_menu(this, name);
2193         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
2194         gui_internal_widget_append(wb, w);
2195         coord=coordinates(&pc, ' ');
2196         gui_internal_widget_append(w, gui_internal_label_new(this, coord));
2197         g_free(coord);
2198         if ((flags & 1) && wm) {
2199                 gui_internal_widget_append(w,
2200                         wc=gui_internal_button_new_with_callback(this, _("Streets"),
2201                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2202                                 gui_internal_search_street_in_town, wm));
2203                 wc->item=wm->item;
2204                 wc->selection_id=wm->selection_id;
2205         }
2206         if ((flags & 2) && wm) {
2207                 gui_internal_widget_append(w,
2208                         wc=gui_internal_button_new_with_callback(this, _("House numbers"),
2209                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2210                                 gui_internal_search_house_number_in_street, wm));
2211                 wc->item=wm->item;
2212                 wc->selection_id=wm->selection_id;
2213         }
2214         if ((flags & 4) && wm) {
2215                 struct map_rect *mr;
2216                 struct item *item;
2217                 struct attr attr;
2218                 mr=map_rect_new(wm->item.map, NULL);
2219                 item = map_rect_get_item_byid(mr, wm->item.id_hi, wm->item.id_lo);
2220                 if (item) {
2221                         if (item_attr_get(item, attr_description, &attr))
2222                                 gui_internal_widget_append(w, gui_internal_label_new(this, attr.u.str));
2223                         if (item_attr_get(item, attr_url_local, &attr)) {
2224                                 gui_internal_widget_append(w,
2225                                         wb=gui_internal_button_new_with_callback(this, _("View in Browser"),
2226                                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2227                                                 gui_internal_cmd_view_in_browser, NULL));
2228                                 wb->item=wm->item;
2229                         }
2230                         gui_internal_widget_append(w,
2231                                 wb=gui_internal_button_new_with_callback(this, _("View Attributes"),
2232                                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2233                                         gui_internal_cmd_view_attributes, NULL));
2234                         wb->item=wm->item;
2235                 }
2236                 map_rect_destroy(mr);
2237         }
2238         if (flags & 8) {
2239                 gui_internal_widget_append(w,
2240                         wbc=gui_internal_button_new_with_callback(this, _("Set as destination"),
2241                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2242                                 gui_internal_cmd_set_destination, g_strdup(name)));
2243                 wbc->data_free=g_free;
2244                 wbc->c=pc;
2245         }
2246         if (flags & 16) {
2247                 gui_internal_widget_append(w,
2248                         wbc=gui_internal_button_new_with_callback(this, _("Set as position"),
2249                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2250                         gui_internal_cmd_set_position, wm));
2251                 wbc->c=pc;
2252         }
2253         if (flags & 32) {
2254                 gui_internal_widget_append(w,
2255                         wbc=gui_internal_button_new_with_callback(this, _("Add as bookmark"),
2256                         image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2257                         gui_internal_cmd_add_bookmark2, g_strdup(name)));
2258                 wbc->data_free=g_free;
2259                 wbc->c=pc;
2260         }
2261         if (flags & 64) {
2262                 gui_internal_widget_append(w,
2263                         wbc=gui_internal_button_new_with_callback(this, _("POIs"),
2264                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2265                                 gui_internal_cmd_pois, NULL));
2266                 wbc->c=pc;
2267         }
2268 #if 0
2269         gui_internal_widget_append(w,
2270                 gui_internal_button_new(this, "Add to tour",
2271                         image_new_o(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill));
2272 #endif
2273         if (flags & 128) {
2274                 gui_internal_widget_append(w,
2275                         gui_internal_button_new_with_callback(this, _("View on map"),
2276                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2277                                 gui_internal_cmd_view_on_map, wm));
2278         }
2279         if (flags & 256) {
2280                 int dist=10;
2281                 struct mapset *ms;
2282                 struct mapset_handle *h;
2283                 struct map_rect *mr;
2284                 struct map *m;
2285                 struct item *item;
2286                 struct street_data *data;
2287                 struct map_selection sel;
2288                 struct transformation *trans;
2289                 enum projection pro;
2290                 struct attr attr;
2291                 char *label,*text;
2292
2293                 trans=navit_get_trans(this->nav);
2294                 pro=transform_get_projection(trans);
2295                 transform_from_geo(pro, &g, &c);
2296                 ms=navit_get_mapset(this->nav);
2297                 sel.next=NULL;
2298                 sel.u.c_rect.lu.x=c.x-dist;
2299                 sel.u.c_rect.lu.y=c.y+dist;
2300                 sel.u.c_rect.rl.x=c.x+dist;
2301                 sel.u.c_rect.rl.y=c.y-dist;
2302                 sel.order=18;
2303                 sel.range=item_range_all;
2304                 h=mapset_open(ms);
2305                 while ((m=mapset_next(h,1))) {
2306                         mr=map_rect_new(m, &sel);
2307                         if (! mr)
2308                                 continue;
2309                         while ((item=map_rect_get_item(mr))) {
2310                                 data=street_get_data(item);
2311                                 if (transform_within_dist_item(&c, item->type, data->c, data->count, dist)) {
2312                                         if (item_attr_get(item, attr_label, &attr)) {
2313                                                 label=map_convert_string(m, attr.u.str);
2314                                                 text=g_strdup_printf("%s %s", item_to_name(item->type), label);
2315                                                 map_convert_free(label);
2316                                         } else
2317                                                 text=g_strdup_printf("%s", item_to_name(item->type));
2318                                         gui_internal_widget_append(w,
2319                                                 wc=gui_internal_button_new_with_callback(this, text,
2320                                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
2321                                                 gui_internal_cmd_position, (void *)2));
2322                                         wc->c.x=data->c[0].x;
2323                                         wc->c.y=data->c[0].y;
2324                                         wc->c.pro=pro;
2325                                         wc->name=g_strdup(text);
2326                                         wc->item=*item;
2327                                         g_free(text);
2328                                 }
2329                                 street_data_free(data);
2330                         }
2331                         map_rect_destroy(mr);
2332                 }
2333                 mapset_close(h);
2334         }
2335         gui_internal_menu_render(this);
2336 }
2337
2338
2339 /* wm->data: 0 Nothing special
2340              1 Map Point
2341              2 Item
2342              3 Town
2343              4 County
2344              5 Street
2345 */
2346
2347 static void
2348 gui_internal_cmd_position(struct gui_priv *this, struct widget *wm, void *data)
2349 {
2350         int flags;
2351         switch ((int) wm->data) {
2352         case 0:
2353                 flags=8|16|32|64|128|256;
2354                 break;
2355         case 1:
2356                 flags=8|16|32|64|256;
2357                 break;
2358         case 2:
2359                 flags=4|8|16|32|64|256;
2360                 break;
2361         case 3:
2362                 flags=1|8|16|32|64|256;
2363         case 4:
2364                 gui_internal_search_town_in_country(this, wm);
2365                 return;
2366         case 5:
2367                 flags=2|8|16|32|64|256;
2368                 break;
2369         default:
2370                 return;
2371         }
2372         gui_internal_cmd_position_do(this, &wm->c, NULL, wm, wm->name ? wm->name : wm->text, flags);
2373 }
2374
2375 static void
2376 gui_internal_cmd2_position(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
2377 {
2378         char *name=_("Position");
2379         int flags=-1;
2380
2381         dbg(1,"enter\n");
2382         if (!in || !in[0])
2383                 return;
2384         if (in[0]->type < attr_type_coord_geo_begin || in[0]->type > attr_type_coord_geo_end)
2385                 return;
2386         if (in[1] && in[1]->type >= attr_type_string_begin && in[1]->type <= attr_type_string_end) {
2387                 name=in[1]->u.str;
2388                 if (in[2] && in[2]->type >= attr_type_int_begin && in[2]->type <= attr_type_int_end) 
2389                         flags=in[2]->u.num;
2390         }
2391         dbg(1,"flags=0x%x\n",flags);
2392         gui_internal_cmd_position_do(this, NULL, in[0]->u.coord_geo, NULL, name, flags);
2393 }
2394
2395 static void
2396 gui_internal_cmd_bookmarks(struct gui_priv *this, struct widget *wm, void *data)
2397 {
2398         struct attr attr,mattr;
2399         struct map_rect *mr=NULL;
2400         struct item *item;
2401         char *label_full,*l,*prefix="",*pos;
2402         int len,plen,hassub;
2403         struct widget *wb,*w,*wbm;
2404         GHashTable *hash;
2405         struct coord c;
2406         char *text=_("Bookmarks");
2407         if (wm && wm->text)
2408                 text=wm->text;
2409
2410         wb=gui_internal_menu(this, text);
2411         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
2412         w->spy=this->spacing*3;
2413         gui_internal_widget_append(wb, w);
2414
2415         if (wm && wm->prefix)
2416                 prefix=wm->prefix;
2417         plen=strlen(prefix);
2418
2419         if(navit_get_attr(this->nav, attr_bookmark_map, &mattr, NULL) && mattr.u.map && (mr=map_rect_new(mattr.u.map, NULL))) {
2420                 hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
2421                 while ((item=map_rect_get_item(mr))) {
2422                         if (item->type != type_bookmark) continue;
2423                         if (!item_attr_get(item, attr_label, &attr)) continue;
2424                         label_full=attr.u.str;
2425                         if (!strncmp(label_full, prefix, plen)) {
2426                                 pos=strchr(label_full+plen, '/');
2427                                 if (pos) {
2428                                         hassub=1;
2429                                         len=pos-label_full;
2430                                 } else {
2431                                         hassub=0;
2432                                         len=strlen(label_full);
2433                                 }
2434                                 l=g_malloc(len-plen+1);
2435                                 strncpy(l, label_full+plen, len-plen);
2436                                 l[len-plen]='\0';
2437                                 if (!g_hash_table_lookup(hash, l)) {
2438                                         wbm=gui_internal_button_new_with_callback(this, l,
2439                                                 image_new_xs(this, hassub ? "gui_inactive" : "gui_active" ), gravity_left_center|orientation_horizontal|flags_fill,
2440                                                         hassub ? gui_internal_cmd_bookmarks : gui_internal_cmd_position, NULL);
2441                                         if (item_coord_get(item, &c, 1)) {
2442                                                 wbm->c.x=c.x;
2443                                                 wbm->c.y=c.y;
2444                                                 wbm->c.pro=map_projection(mattr.u.map);
2445                                                 wbm->name=g_strdup_printf(_("Bookmark %s"),label_full);
2446                                                 wbm->text=g_strdup(l);
2447                                                 gui_internal_widget_append(w, wbm);
2448                                                 g_hash_table_insert(hash, g_strdup(l), (void *)1);
2449                                                 wbm->prefix=g_malloc(len+2);
2450                                                 strncpy(wbm->prefix, label_full, len+1);
2451                                                 wbm->prefix[len+1]='\0';
2452                                         } else {
2453                                                 gui_internal_widget_destroy(this, wbm);
2454                                         }
2455                                 }
2456                                 g_free(l);
2457                         }
2458
2459                 }
2460                 g_hash_table_destroy(hash);
2461         }
2462         gui_internal_menu_render(this);
2463 }
2464
2465 static void
2466 gui_internal_cmd2_bookmarks(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
2467 {
2468         gui_internal_cmd_bookmarks(this, NULL, NULL);
2469 }
2470
2471 static void gui_internal_keypress_do(struct gui_priv *this, char *key)
2472 {
2473         struct widget *wi,*menu;
2474         int len=0;
2475         char *text=NULL;
2476
2477         menu=g_list_last(this->root.children)->data;
2478         wi=gui_internal_find_widget(menu, NULL, STATE_EDIT);
2479         if (wi) {
2480                 if (*key == NAVIT_KEY_BACKSPACE) {
2481                         dbg(0,"backspace\n");
2482                         if (wi->text && wi->text[0]) {
2483                                 len=g_utf8_prev_char(wi->text+strlen(wi->text))-wi->text;
2484                                 wi->text[len]=' ';
2485                                 text=g_strdup_printf("%s ", wi->text);
2486                         }
2487                 } else {
2488                         if (wi->state & STATE_CLEAR) {
2489                                 dbg(0,"wi->state=0x%x\n", wi->state);
2490                                 g_free(wi->text);
2491                                 wi->text=NULL;
2492                                 wi->state &= ~STATE_CLEAR;
2493                                 dbg(0,"wi->state=0x%x\n", wi->state);
2494                         }
2495                         text=g_strdup_printf("%s%s", wi->text ? wi->text : "", key);
2496                 }
2497                 g_free(wi->text);
2498                 wi->text=text;
2499                 if (*key == NAVIT_KEY_BACKSPACE && wi->text) {
2500                         gui_internal_widget_render(this, wi);
2501                         wi->text[len]='\0';
2502                 }
2503                 if (wi->func) {
2504                         wi->reason=2;
2505                         wi->func(this, wi, wi->data);
2506                 }
2507                 gui_internal_widget_render(this, wi);
2508         }
2509 }
2510
2511
2512 static void
2513 gui_internal_cmd_keypress(struct gui_priv *this, struct widget *wm, void *data)
2514 {
2515         struct menu_data *md=gui_internal_menu_data(this);
2516         gui_internal_keypress_do(this, (char *) wm->data);
2517         if (md->keyboard_mode == 2)
2518                 gui_internal_keyboard_do(this, md->keyboard, 10);
2519         if (md->keyboard_mode == 26)
2520                 gui_internal_keyboard_do(this, md->keyboard, 34);
2521 }
2522
2523 static void
2524 gui_internal_search_idle_end(struct gui_priv *this)
2525 {
2526         if (this->idle) {
2527                 event_remove_idle(this->idle);
2528                 this->idle=NULL;
2529         }
2530         if (this->idle_cb) {
2531                 callback_destroy(this->idle_cb);
2532                 this->idle_cb=NULL;
2533         }
2534 }
2535
2536 static void
2537 gui_internal_search_idle(struct gui_priv *this, char *wm_name, struct widget *search_list, void *param)
2538 {
2539         char *text=NULL,*name=NULL;
2540         struct search_list_result *res;
2541         struct widget *wc;
2542         struct item *item=NULL;
2543         GList *l;
2544         static char possible_keys[256]="";
2545
2546         res=search_list_get_result(this->sl);
2547         if (res) {
2548                 gchar* trunk_name = NULL;
2549
2550                 struct widget *menu=g_list_last(this->root.children)->data;
2551                 struct widget *wi=gui_internal_find_widget(menu, NULL, STATE_EDIT);
2552
2553                 if (! strcmp(wm_name,"Town"))
2554                         trunk_name = g_strrstr(res->town->name, wi->text);
2555                 if (! strcmp(wm_name,"Street"))
2556                         trunk_name = g_strrstr(name=res->street->name, wi->text);
2557
2558                 if (trunk_name) {
2559                         char next_char = trunk_name[strlen(wi->text)];
2560                         int i;
2561                         int len = strlen(possible_keys);
2562                         for(i = 0; (i<len) && (possible_keys[i] != next_char) ;i++) ;
2563                         if (i==len || !len) {
2564                                 possible_keys[len]=trunk_name[strlen(wi->text)];
2565                                 possible_keys[len+1]='\0';
2566
2567                         }
2568                         dbg(1,"%s %s possible_keys:%s \n", wi->text, res->town->name, possible_keys);
2569                 }
2570         }
2571
2572         if (! res) {
2573                 gui_internal_search_idle_end(this);
2574
2575                 struct menu_data *md=gui_internal_menu_data(this);
2576                 if (md && md->keyboard) {
2577                         GList *lk=md->keyboard->children;
2578                         graphics_draw_mode(this->gra, draw_mode_begin);
2579                         while (lk) {
2580                                 struct widget *child=lk->data;
2581                                 GList *lk2=child->children;
2582                                 while (lk2) {
2583                                         struct widget *child_=lk2->data;
2584                                         lk2=g_list_next(lk2);
2585                                         if (child_->data && strcmp("\b", child_->data)) { // FIXME don't disable special keys
2586                                                 if (strlen(possible_keys) == 0)
2587                                                         child_->state|= STATE_HIGHLIGHTED|STATE_VISIBLE|STATE_SENSITIVE|STATE_CLEAR ;
2588                                                 else if (g_strrstr(possible_keys, child_->data)!=NULL ) {
2589                                                         child_->state|= STATE_HIGHLIGHTED|STATE_VISIBLE|STATE_SENSITIVE|STATE_CLEAR ;
2590                                                 } else {
2591                                                         child_->state&= ~(STATE_HIGHLIGHTED|STATE_VISIBLE|STATE_SELECTED) ;
2592                                                 }
2593                                                 gui_internal_widget_render(this,child_);
2594                                         }
2595                                 }
2596                                 lk=g_list_next(lk);
2597                         }
2598                         gui_internal_widget_render(this,md->keyboard);
2599                         graphics_draw_mode(this->gra, draw_mode_end);
2600                 }
2601
2602                 possible_keys[0]='\0';
2603                 return;
2604         }
2605
2606         if (! strcmp(wm_name,"Country")) {
2607                 name=res->country->name;
2608                 item=&res->country->common.item;
2609                 text=g_strdup_printf("%s", res->country->name);
2610         }
2611         if (! strcmp(wm_name,"Town")) {
2612                 name=res->town->name;
2613                 item=&res->town->common.item;
2614                 if (res->town->name && res->town->district)
2615                         text=g_strdup_printf("%s%s%s (%s)", res->town->common.postal_mask ? res->town->common.postal_mask : "", res->town->common.postal_mask ? " ":"", res->town->name, res->town->district);
2616                 else
2617                         text=g_strdup_printf("%s%s%s", res->town->common.postal ? res->town->common.postal_mask : "", res->town->common.postal_mask ? " ":"", res->town->name);
2618         }
2619         if (! strcmp(wm_name,"Street")) {
2620                 name=res->street->name;
2621                 item=&res->street->common.item;
2622                 text=g_strdup_printf("%s %s", res->town->name, res->street->name);
2623         }
2624         dbg(1,"res->country->flag=%s\n", res->country->flag);
2625                 gui_internal_widget_append(search_list,
2626                                 wc=gui_internal_button_new_with_callback(this, text,
2627                                         image_new_xs(this, res->country->flag),
2628                                         gravity_left_center|orientation_horizontal|flags_fill,
2629                                         gui_internal_cmd_position, param));
2630                 wc->name=g_strdup(name);
2631                 if (res->c)
2632                         wc->c=*res->c;
2633                 wc->selection_id=res->id;
2634                 if (item)
2635                         wc->item=*item;
2636                 gui_internal_widget_pack(this, search_list);
2637                 l=g_list_last(this->root.children);
2638                 graphics_draw_mode(this->gra, draw_mode_begin);
2639                 gui_internal_widget_render(this, l->data);
2640                 graphics_draw_mode(this->gra, draw_mode_end);
2641         g_free(text);
2642 }
2643
2644 static void
2645 gui_internal_search_idle_start(struct gui_priv *this, char *wm_name, struct widget *search_list, void *param)
2646 {
2647         this->idle_cb=callback_new_4(callback_cast(gui_internal_search_idle), this, wm_name, search_list, param);
2648         this->idle=event_add_idle(50,this->idle_cb);
2649         callback_call_0(this->idle_cb);
2650 }
2651
2652
2653 /**
2654  *
2655  * @param wm The widget that generated the event for the search changed,
2656  *        if this was generated by a key on the virtual keyboard then
2657  *        wm is the key button widget.
2658  */
2659 static void
2660 gui_internal_search_changed(struct gui_priv *this, struct widget *wm, void *data)
2661 {
2662         GList *l;
2663         struct widget *search_list=gui_internal_menu_data(this)->search_list;
2664         gui_internal_widget_children_destroy(this, search_list);
2665
2666         void *param=(void *)3;
2667         int minlen=1;
2668         if (! strcmp(wm->name,"Country")) 
2669                 param=(void *)4;
2670         if (! strcmp(wm->name,"Street")) 
2671                 param=(void *)5;
2672         dbg(0,"%s now '%s'\n", wm->name, wm->text);
2673
2674         gui_internal_search_idle_end(this);
2675         if (wm->text && g_utf8_strlen(wm->text, -1) >= minlen) {
2676                 struct attr search_attr;
2677
2678                 dbg(0,"process\n");
2679                 if (! strcmp(wm->name,"Country"))
2680                         search_attr.type=attr_country_all;
2681                 if (! strcmp(wm->name,"Town"))
2682                         search_attr.type=attr_town_or_district_name;
2683                 if (! strcmp(wm->name,"Street"))
2684                         search_attr.type=attr_street_name;
2685                 if (! strcmp(wm->name,"House number"))
2686                         search_attr.type=attr_house_number;
2687                 search_attr.u.str=wm->text;
2688                 search_list_search(this->sl, &search_attr, 1);
2689                 gui_internal_search_idle_start(this, wm->name, search_list, param);
2690         }
2691         l=g_list_last(this->root.children);
2692         gui_internal_widget_render(this, l->data);
2693 }
2694
2695 static struct widget *
2696 gui_internal_keyboard_key_data(struct gui_priv *this, struct widget *wkbd, char *text, void(*func)(struct gui_priv *priv, struct widget *widget, void *data), void *data, void (*data_free)(void *data), int w, int h)
2697 {
2698         struct widget *wk;
2699         gui_internal_widget_append(wkbd, wk=gui_internal_button_new_with_callback(this, text,
2700                 NULL, gravity_center|orientation_vertical, func, data));
2701         wk->data_free=data_free;
2702         wk->background=this->background;
2703         wk->bl=w/2;
2704         wk->br=0;
2705         wk->bt=h/3;
2706         wk->bb=0;
2707         return wk;
2708 }
2709
2710 static struct widget *
2711 gui_internal_keyboard_key(struct gui_priv *this, struct widget *wkbd, char *text, char *key, int w, int h)
2712 {
2713         return gui_internal_keyboard_key_data(this, wkbd, text, gui_internal_cmd_keypress, g_strdup(key), g_free,w,h);
2714 }
2715
2716 static void gui_internal_keyboard_change(struct gui_priv *this, struct widget *key, void *data);
2717
2718 // Some macros that make the keyboard layout easier to visualise in
2719 // the source code. The macros are #undef'd after this function.
2720 #define KEY(x) gui_internal_keyboard_key(this, wkbd, (x), (x), max_w, max_h)
2721 #define SPACER() gui_internal_keyboard_key_data(this, wkbd, "", NULL, NULL, NULL,max_w,max_h)
2722 static struct widget *
2723 gui_internal_keyboard_do(struct gui_priv *this, struct widget *wkbdb, int mode)
2724 {
2725         struct widget *wkbd,*wk;
2726         struct menu_data *md=gui_internal_menu_data(this);
2727         int i, max_w=this->root.w, max_h=this->root.h;
2728         int render=0;
2729
2730         if (wkbdb) {
2731                 this->current.x=-1;
2732                 this->current.y=-1;
2733                 gui_internal_highlight(this);
2734                 render=1;
2735                 gui_internal_widget_children_destroy(this, wkbdb);
2736         } else
2737                 wkbdb=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_fill);
2738         md->keyboard=wkbdb;
2739         md->keyboard_mode=mode;
2740         wkbd=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_fill);
2741         wkbd->background=this->background;
2742         wkbd->cols=8;
2743         wkbd->spx=3;
2744         wkbd->spy=3;
2745         max_w=max_w/9;
2746         max_h=max_h/6;
2747
2748         if (mode >= 0 && mode < 8) {
2749                 for (i = 0 ; i < 26 ; i++) {
2750                         char text[]={'A'+i,'\0'};
2751                         KEY(text);
2752                 }
2753                 gui_internal_keyboard_key(this, wkbd, "_"," ",max_w,max_h);
2754                 if (mode == 0) {
2755                         KEY("-");
2756                         KEY("'");
2757                         SPACER();
2758                 } else {
2759                         SPACER();
2760                         wk=gui_internal_keyboard_key_data(this, wkbd, "a", gui_internal_keyboard_change, wkbd, NULL,max_w,max_h);
2761                         wk->datai=mode+8;
2762                         wk=gui_internal_keyboard_key_data(this, wkbd, "1", gui_internal_keyboard_change, wkbd, NULL,max_w,max_h);
2763                         wk->datai=mode+16;
2764                 }
2765                 wk=gui_internal_keyboard_key_data(this, wkbd, "Ä",gui_internal_keyboard_change, wkbdb,NULL,max_w,max_h);
2766                 wk->datai=mode+24;
2767                 gui_internal_keyboard_key(this, wkbd, "<-","\b",max_w,max_h);
2768         }
2769         if (mode >= 8 && mode < 16) {
2770                 for (i = 0 ; i < 26 ; i++) {
2771                         char text[]={'a'+i,'\0'};
2772                         KEY(text);
2773                 }
2774                 gui_internal_keyboard_key(this, wkbd, "_"," ",max_w,max_h);
2775                 if (mode == 8) {
2776                         KEY("-");
2777                         KEY("'");
2778                         SPACER();
2779                 } else {
2780                         SPACER();
2781                         wk=gui_internal_keyboard_key_data(this, wkbd, "A", gui_internal_keyboard_change, wkbd, NULL,max_w,max_h);
2782                         wk->datai=mode-8;
2783                         wk=gui_internal_keyboard_key_data(this, wkbd, "1", gui_internal_keyboard_change, wkbd, NULL,max_w,max_h);
2784                         wk->datai=mode+8;
2785                 }
2786                 wk=gui_internal_keyboard_key_data(this, wkbd, "ä",gui_internal_keyboard_change,wkbdb,NULL,max_w,max_h);
2787                 wk->datai=mode+24;
2788                 gui_internal_keyboard_key(this, wkbd, "<-","\b",max_w,max_h);
2789         }
2790         if (mode >= 16 && mode < 24) {
2791                 for (i = 0 ; i < 10 ; i++) {
2792                         char text[]={'0'+i,'\0'};
2793                         KEY(text);
2794                 }
2795                 KEY("."); KEY("°"); KEY("'"); KEY("\""); KEY("-"); KEY("+");
2796                 KEY("*"); KEY("/"); KEY("("); KEY(")"); KEY("="); KEY("?");
2797
2798                 for (i = 0 ; i < 5 ; i++) SPACER();
2799
2800                 if (mode == 16) {
2801                         KEY("-");
2802                         KEY("'");
2803                         SPACER();
2804                 } else {
2805                         SPACER();
2806                         wk=gui_internal_keyboard_key_data(this, wkbd, "A", gui_internal_keyboard_change, wkbd, NULL,max_w,max_h);
2807                         wk->datai=mode-16;
2808                         wk=gui_internal_keyboard_key_data(this, wkbd, "a", gui_internal_keyboard_change, wkbd, NULL,max_w,max_h);
2809                         wk->datai=mode-8;
2810                 }
2811                 wk=gui_internal_keyboard_key_data(this, wkbd, "Ä",gui_internal_keyboard_change,wkbdb,NULL,max_w,max_h);
2812                 wk->datai=mode+8;
2813                 gui_internal_keyboard_key(this, wkbd, "<-","\b",max_w,max_h);
2814         }
2815         if (mode >= 24 && mode < 32) {
2816                 KEY("Ä"); KEY("Ë"); KEY("Ï"); KEY("Ö"); KEY("Ü"); KEY("Æ"); KEY("Ø"); KEY("Å");
2817                 KEY("Á"); KEY("É"); KEY("Í"); KEY("Ó"); KEY("Ú"); KEY("Š"); KEY("Č"); KEY("Ž");
2818                 KEY("À"); KEY("È"); KEY("Ì"); KEY("Ò"); KEY("Ù"); KEY("Ś"); KEY("Ć"); KEY("Ź");
2819                 KEY("Â"); KEY("Ê"); KEY("Î"); KEY("Ô"); KEY("Û"); SPACER();
2820
2821                 wk=gui_internal_keyboard_key_data(this, wkbd, "A",gui_internal_keyboard_change,wkbdb,NULL,max_w,max_h);
2822                 wk->datai=mode-24;
2823
2824                 gui_internal_keyboard_key(this, wkbd, "<-","\b",max_w,max_h);
2825         }
2826         if (mode >= 32 && mode < 40) {
2827                 KEY("ä"); KEY("ë"); KEY("ï"); KEY("ö"); KEY("ü"); KEY("æ"); KEY("ø"); KEY("å");
2828                 KEY("á"); KEY("é"); KEY("í"); KEY("ó"); KEY("ú"); KEY("š"); KEY("č"); KEY("ž");
2829                 KEY("à"); KEY("è"); KEY("ì"); KEY("ò"); KEY("ù"); KEY("ś"); KEY("ć"); KEY("ź");
2830                 KEY("â"); KEY("ê"); KEY("î"); KEY("ô"); KEY("û"); KEY("ß");
2831
2832                 wk=gui_internal_keyboard_key_data(this, wkbd, "a",gui_internal_keyboard_change,wkbdb,NULL,max_w,max_h);
2833                 wk->datai=mode-24;
2834
2835                 gui_internal_keyboard_key(this, wkbd, "<-","\b",max_w,max_h);
2836         }
2837         gui_internal_widget_append(wkbdb, wkbd);
2838         if (render) {
2839                 gui_internal_widget_pack(this, wkbdb);
2840                 gui_internal_widget_render(this, wkbdb);
2841         }
2842         return wkbdb;
2843 }
2844 #undef KEY
2845 #undef SPACER
2846
2847 static struct widget *
2848 gui_internal_keyboard(struct gui_priv *this, int mode)
2849 {
2850         if (! this->keyboard)
2851                 return NULL;
2852         return gui_internal_keyboard_do(this, NULL, mode);
2853 }
2854
2855 static void
2856 gui_internal_keyboard_change(struct gui_priv *this, struct widget *key, void *data)
2857 {
2858         gui_internal_keyboard_do(this, key->data, key->datai);
2859 }
2860
2861 static void
2862 gui_internal_search_list_set_default_country(struct gui_priv *this)
2863 {
2864         struct attr search_attr, country_name, country_iso2, *country_attr;
2865         struct item *item;
2866         struct country_search *cs;
2867         struct tracking *tracking;
2868         struct search_list_result *res;
2869
2870         country_attr=country_default();
2871         tracking=navit_get_tracking(this->nav);
2872         if (tracking && tracking_get_attr(tracking, attr_country_id, &search_attr, NULL))
2873                 country_attr=&search_attr;
2874         if (country_attr) {
2875                 cs=country_search_new(country_attr, 0);
2876                 item=country_search_get_item(cs);
2877                 if (item && item_attr_get(item, attr_country_name, &country_name)) {
2878                         search_attr.type=attr_country_all;
2879                         dbg(0,"country %s\n", country_name.u.str);
2880                         search_attr.u.str=country_name.u.str;
2881                         search_list_search(this->sl, &search_attr, 0);
2882                         while((res=search_list_get_result(this->sl)));
2883                         g_free(this->country_iso2);
2884                         if (item_attr_get(item, attr_country_iso2, &country_iso2))
2885                                 this->country_iso2=g_strdup(country_iso2.u.str);
2886                 }
2887                 country_search_destroy(cs);
2888         } else {
2889                 dbg(0,"warning: no default country found\n");
2890                 if (this->country_iso2) {
2891                     dbg(0,"attempting to use country '%s'\n",this->country_iso2);
2892                     search_attr.type=attr_country_iso2;
2893                     search_attr.u.str=this->country_iso2;
2894             search_list_search(this->sl, &search_attr, 0);
2895             while((res=search_list_get_result(this->sl)));
2896                 }
2897         }
2898 }
2899
2900 static void
2901 gui_internal_search_list_new(struct gui_priv *this)
2902 {
2903         struct mapset *ms=navit_get_mapset(this->nav);
2904         if (! this->sl) {
2905                 this->sl=search_list_new(ms);
2906                 gui_internal_search_list_set_default_country(this);
2907         }
2908 }
2909
2910 static void
2911 gui_internal_search_list_destroy(struct gui_priv *this)
2912 {
2913         if (this->sl) {
2914                 search_list_destroy(this->sl);
2915                 this->sl=NULL;
2916         }
2917 }
2918
2919
2920 static void
2921 gui_internal_search(struct gui_priv *this, char *what, char *type, int flags)
2922 {
2923         struct widget *wb,*wk,*w,*wr,*we,*wl,*wnext=NULL;
2924         char *country;
2925         gui_internal_search_list_new(this);
2926         wb=gui_internal_menu(this, what);
2927         w=gui_internal_box_new(this, gravity_center|orientation_vertical|flags_expand|flags_fill);
2928         gui_internal_widget_append(wb, w);
2929         wr=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
2930         gui_internal_widget_append(w, wr);
2931         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
2932         gui_internal_widget_append(wr, we);
2933
2934         if (!strcmp(type,"Country")) {
2935                 wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_town"));
2936                 wnext->func=gui_internal_search_town;
2937         } else if (!strcmp(type,"Town")) {
2938                 if (this->country_iso2) {
2939 #if HAVE_API_ANDROID
2940                         char country_iso2[strlen(this->country_iso2)+1];
2941                         strtolower(country_iso2, this->country_iso2);
2942                         country=g_strdup_printf("country_%s", country_iso2);
2943 #else
2944                         country=g_strdup_printf("country_%s", this->country_iso2);
2945 #endif
2946                 } else
2947                         country=strdup("gui_select_country");
2948                 gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, country)));
2949                 wb->state |= STATE_SENSITIVE;
2950                 if (flags)
2951                         wb->func = gui_internal_search_country;
2952                 else
2953                         wb->func = gui_internal_back;
2954                 wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_street"));
2955                 wnext->func=gui_internal_search_street;
2956                 g_free(country);
2957         } else if (!strcmp(type,"Street")) {
2958                 gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_select_town")));
2959                 wb->state |= STATE_SENSITIVE;
2960                 wb->func = gui_internal_back;
2961                 wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_house_number"));
2962                 wnext->func=gui_internal_search_house_number;
2963         } else if (!strcmp(type,"House number")) {
2964                 gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_select_street")));
2965                 wb->state |= STATE_SENSITIVE;
2966                 wb->func = gui_internal_back;
2967         }
2968         gui_internal_widget_append(we, wk=gui_internal_label_new(this, NULL));
2969         if (wnext) {
2970                 gui_internal_widget_append(we, wnext);
2971                 wnext->state |= STATE_SENSITIVE;
2972         }
2973         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
2974         gui_internal_widget_append(wr, wl);
2975         gui_internal_menu_data(this)->search_list=wl;
2976         wk->state |= STATE_EDIT;
2977         wk->background=this->background;
2978         wk->flags |= flags_expand|flags_fill;
2979         wk->func = gui_internal_search_changed;
2980         wk->name=g_strdup(type);
2981         if (this->keyboard)
2982                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
2983         gui_internal_menu_render(this);
2984 }
2985
2986 static void
2987 gui_internal_search_house_number(struct gui_priv *this, struct widget *widget, void *data)
2988 {
2989         search_list_select(this->sl, attr_street_name, 0, 0);
2990         gui_internal_search(this,_("House number"),"House number",0);
2991 }
2992
2993 static void
2994 gui_internal_search_house_number_in_street(struct gui_priv *this, struct widget *widget, void *data)
2995 {
2996         dbg(0,"id %d\n", widget->selection_id);
2997         search_list_select(this->sl, attr_street_name, 0, 0);
2998         search_list_select(this->sl, attr_street_name, widget->selection_id, 1);
2999         gui_internal_search(this,_("House number"),"House number",0);
3000 }
3001
3002 static void
3003 gui_internal_search_street(struct gui_priv *this, struct widget *widget, void *data)
3004 {
3005         search_list_select(this->sl, attr_town_or_district_name, 0, 0);
3006         gui_internal_search(this,_("Street"),"Street",0);
3007 }
3008
3009 static void
3010 gui_internal_search_street_in_town(struct gui_priv *this, struct widget *widget, void *data)
3011 {
3012         dbg(0,"id %d\n", widget->selection_id);
3013         search_list_select(this->sl, attr_town_or_district_name, 0, 0);
3014         search_list_select(this->sl, attr_town_or_district_name, widget->selection_id, 1);
3015         gui_internal_search(this,_("Street"),"Street",0);
3016 }
3017
3018 static void
3019 gui_internal_search_town(struct gui_priv *this, struct widget *wm, void *data)
3020 {
3021         if (this->sl)
3022                 search_list_select(this->sl, attr_country_all, 0, 0);
3023         g_free(this->country_iso2);
3024         this->country_iso2=NULL;
3025         gui_internal_search(this,_("Town"),"Town",0);
3026 }
3027
3028 static void
3029 gui_internal_search_town_in_country(struct gui_priv *this, struct widget *widget)
3030 {
3031         struct search_list_common *slc;
3032         dbg(0,"id %d\n", widget->selection_id);
3033         search_list_select(this->sl, attr_country_all, 0, 0);
3034         slc=search_list_select(this->sl, attr_country_all, widget->selection_id, 1);
3035         if (slc) {
3036                 g_free(this->country_iso2);
3037                 this->country_iso2=((struct search_list_country *)slc)->iso2;
3038         }
3039         gui_internal_search(this,widget->name,"Town",0);
3040 }
3041
3042 static void
3043 gui_internal_search_country(struct gui_priv *this, struct widget *widget, void *data)
3044 {
3045         gui_internal_prune_menu_count(this, 1, 0);
3046         gui_internal_search(this,_("Country"),"Country",0);
3047 }
3048
3049 static void
3050 gui_internal_cmd2_town(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3051 {
3052         if (this->sl)
3053                 search_list_select(this->sl, attr_country_all, 0, 0);
3054         gui_internal_search(this,_("Town"),"Town",1);
3055 }
3056
3057 static void
3058 gui_internal_cmd_layout(struct gui_priv *this, struct widget *wm, void *data)
3059 {
3060         struct attr attr;
3061         struct widget *w,*wb,*wl;
3062         struct attr_iter *iter;
3063
3064
3065         wb=gui_internal_menu(this, _("Layout"));
3066         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3067         w->spy=this->spacing*3;
3068         gui_internal_widget_append(wb, w);
3069         iter=navit_attr_iter_new();
3070         while(navit_get_attr(this->nav, attr_layout, &attr, iter)) {
3071                 wl=gui_internal_button_navit_attr_new(this, attr.u.layout->name, gravity_left_center|orientation_horizontal|flags_fill,
3072                         &attr, NULL);
3073                 gui_internal_widget_append(w, wl);
3074         }
3075         navit_attr_iter_destroy(iter);
3076         gui_internal_menu_render(this);
3077 }
3078
3079 static void
3080 gui_internal_cmd_fullscreen(struct gui_priv *this, struct widget *wm, void *data)
3081 {
3082         graphics_draw_mode(this->gra, draw_mode_end);
3083         if (this->fullscreen != 2)
3084                 this->fullscreen=!this->fullscreen;
3085         this->win->fullscreen(this->win, this->fullscreen != 0);
3086         graphics_draw_mode(this->gra, draw_mode_begin);
3087 }
3088
3089 static void
3090 gui_internal_cmd_2d(struct gui_priv *this, struct widget *wm, void *data)
3091 {
3092         struct transformation *trans=navit_get_trans(this->nav);
3093         transform_set_pitch(trans, 0);
3094         this->redraw=1;
3095         gui_internal_prune_menu(this, NULL);
3096 }
3097
3098 static void
3099 gui_internal_cmd_3d(struct gui_priv *this, struct widget *wm, void *data)
3100 {
3101         struct transformation *trans=navit_get_trans(this->nav);
3102         transform_set_pitch(trans, this->pitch);
3103         this->redraw=1;
3104         gui_internal_prune_menu(this, NULL);
3105 }
3106
3107 static void
3108 gui_internal_cmd2_setting_display(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3109 {
3110         struct widget *w;
3111         struct transformation *trans;
3112
3113         w=gui_internal_menu(this, _("Display"));
3114         gui_internal_widget_append(w,
3115                 gui_internal_button_new_with_callback(this, _("Layout"),
3116                         image_new_l(this, "gui_display"), gravity_center|orientation_vertical,
3117                         gui_internal_cmd_layout, NULL));
3118
3119         if(this->fullscreen != 2) {
3120                 if (this->fullscreen) {
3121                         gui_internal_widget_append(w,
3122                                         gui_internal_button_new_with_callback(this, _("Window Mode"),
3123                                                 image_new_l(this, "gui_leave_fullscreen"), gravity_center|orientation_vertical,
3124                                                 gui_internal_cmd_fullscreen, NULL));
3125                 } else {
3126                         gui_internal_widget_append(w,
3127                                         gui_internal_button_new_with_callback(this, _("Fullscreen"),
3128                                                 image_new_l(this, "gui_fullscreen"), gravity_center|orientation_vertical,
3129                                                 gui_internal_cmd_fullscreen, NULL));
3130                 }
3131         }
3132         trans=navit_get_trans(this->nav);
3133         if (transform_get_pitch(trans)) {
3134                 gui_internal_widget_append(w,
3135                         gui_internal_button_new_with_callback(this, _("2D"),
3136                                 image_new_l(this, "gui_map"), gravity_center|orientation_vertical,
3137                                 gui_internal_cmd_2d, NULL));
3138
3139         } else {
3140                 gui_internal_widget_append(w,
3141                         gui_internal_button_new_with_callback(this, _("3D"),
3142                                 image_new_l(this, "gui_map"), gravity_center|orientation_vertical,
3143                                 gui_internal_cmd_3d, NULL));
3144         }
3145         gui_internal_menu_render(this);
3146 }
3147
3148 static void
3149 gui_internal_cmd2_quit(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3150 {
3151         struct attr navit;
3152         navit.type=attr_navit;
3153         navit.u.navit=this->nav;
3154         navit_destroy(navit.u.navit);
3155         config_remove_attr(config, &navit);
3156         event_main_loop_quit();
3157 }
3158
3159 static void
3160 gui_internal_cmd2_abort_navigation(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3161 {
3162         navit_set_destination(this->nav, NULL, NULL, 0);
3163 }
3164
3165
3166 static void
3167 gui_internal_cmd2_setting_maps(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3168 {
3169         struct attr attr, on, off, description, type, data;
3170         struct widget *w,*wb,*wma;
3171         char *label;
3172         struct attr_iter *iter;
3173
3174
3175         wb=gui_internal_menu(this, _("Maps"));
3176         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3177         w->spy=this->spacing*3;
3178         gui_internal_widget_append(wb, w);
3179         iter=navit_attr_iter_new();
3180         on.type=off.type=attr_active;
3181         on.u.num=1;
3182         off.u.num=0;
3183         while(navit_get_attr(this->nav, attr_map, &attr, iter)) {
3184                 if (map_get_attr(attr.u.map, attr_description, &description, NULL)) {
3185                         label=g_strdup(description.u.str);
3186                 } else {
3187                         if (!map_get_attr(attr.u.map, attr_type, &type, NULL))
3188                                 type.u.str="";
3189                         if (!map_get_attr(attr.u.map, attr_data, &data, NULL))
3190                                 data.u.str="";
3191                         label=g_strdup_printf("%s:%s", type.u.str, data.u.str);
3192                 }
3193                 wma=gui_internal_button_map_attr_new(this, label, gravity_left_center|orientation_horizontal|flags_fill,
3194                         attr.u.map, &on, &off, 1);
3195                 gui_internal_widget_append(w, wma);
3196                 g_free(label);
3197         }
3198         navit_attr_iter_destroy(iter);
3199         gui_internal_menu_render(this);
3200
3201 }
3202 static void
3203 gui_internal_cmd_set_active_vehicle(struct gui_priv *this, struct widget *wm, void *data)
3204 {
3205         struct attr vehicle = {attr_vehicle,{wm->data}};
3206         navit_set_attr(this->nav, &vehicle);
3207 }
3208
3209 static void
3210 gui_internal_cmd_show_satellite_status(struct gui_priv *this, struct widget *wm, void *data)
3211 {
3212         struct widget *w,*wb,*row;
3213         struct attr attr,sat_attr;
3214         struct vehicle *v=wm->data;
3215         char *str;
3216         int i;
3217         enum attr_type types[]={attr_sat_prn, attr_sat_elevation, attr_sat_azimuth, attr_sat_snr};
3218
3219         wb=gui_internal_menu(this, _("Show Satellite Status"));
3220         gui_internal_menu_data(this)->redisplay=gui_internal_cmd_show_satellite_status;
3221         gui_internal_menu_data(this)->redisplay_widget=wm;
3222         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3223         gui_internal_widget_append(wb, w);
3224         w = gui_internal_widget_table_new(this,gravity_center | orientation_vertical | flags_expand | flags_fill, 0);
3225         row = gui_internal_widget_table_row_new(this,gravity_left_top);
3226         gui_internal_widget_append(row, gui_internal_label_new(this, _(" PRN ")));
3227         gui_internal_widget_append(row, gui_internal_label_new(this, _(" Elevation ")));
3228         gui_internal_widget_append(row, gui_internal_label_new(this, _(" Azimuth ")));
3229         gui_internal_widget_append(row, gui_internal_label_new(this, _(" SNR ")));
3230         gui_internal_widget_append(w,row);
3231         while (vehicle_get_attr(v, attr_position_sat_item, &attr, NULL)) {
3232                 row = gui_internal_widget_table_row_new(this,gravity_left_top);
3233                 for (i = 0 ; i < sizeof(types)/sizeof(enum attr_type) ; i++) {
3234                         if (item_attr_get(attr.u.item, types[i], &sat_attr))
3235                                 str=g_strdup_printf("%d", sat_attr.u.num);
3236                         else
3237                                 str=g_strdup("");
3238                         gui_internal_widget_append(row, gui_internal_label_new(this, str));
3239                         g_free(str);
3240                 }
3241                 gui_internal_widget_append(w,row);
3242         }
3243         gui_internal_widget_append(wb, w);
3244         gui_internal_menu_render(this);
3245 }
3246
3247 static void
3248 gui_internal_cmd_show_nmea_data(struct gui_priv *this, struct widget *wm, void *data)
3249 {
3250         struct widget *w,*wb;
3251         struct attr attr;
3252         struct vehicle *v=wm->data;
3253         wb=gui_internal_menu(this, _("Show NMEA Data"));
3254         gui_internal_menu_data(this)->redisplay=gui_internal_cmd_show_nmea_data;
3255         gui_internal_menu_data(this)->redisplay_widget=wm;
3256         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3257         gui_internal_widget_append(wb, w);
3258         if (vehicle_get_attr(v, attr_position_nmea, &attr, NULL))
3259                 gui_internal_widget_append(w, gui_internal_text_new(this, attr.u.str, gravity_left_center|orientation_vertical));
3260         gui_internal_menu_render(this);
3261 }
3262
3263 /**
3264  * A container to hold the selected vehicle and the desired profile in
3265  * one data item.
3266  */
3267 struct vehicle_and_profilename {
3268         struct vehicle *vehicle;
3269         char *profilename;
3270 };
3271
3272 /**
3273  * Figures out whether the given vehicle is the active vehicle.
3274  *
3275  * @return true if the vehicle is active, false otherwise.
3276  */
3277 static int
3278 gui_internal_is_active_vehicle(struct gui_priv *this, struct vehicle
3279         *vehicle)
3280 {
3281         struct attr active_vehicle;
3282
3283         if (!navit_get_attr(this->nav, attr_vehicle, &active_vehicle, NULL))
3284         active_vehicle.u.vehicle=NULL;
3285
3286         return active_vehicle.u.vehicle == vehicle;
3287 }
3288
3289 static void
3290 save_vehicle_xml(struct vehicle *v)
3291 {
3292         struct attr attr;
3293         struct attr_iter *iter=vehicle_attr_iter_new();
3294         int childs=0;
3295         dbg(0,"enter\n");
3296         printf("<vehicle");
3297         while (vehicle_get_attr(v, attr_any_xml, &attr, iter)) {
3298                 if (attr_type_begin(attr.type) == attr_type_object_begin)
3299                         childs=1;
3300                 else
3301                         printf(" %s=\"%s\"",attr_to_name(attr.type),attr_to_text(&attr, NULL, 1));
3302         }
3303         if (childs) {
3304                 printf(">\n");
3305                 printf("</vehicle>\n");
3306         } else
3307                 printf(" />\n");
3308         vehicle_attr_iter_destroy(iter);
3309 }
3310
3311
3312 /**
3313  * Reacts to a button press that changes a vehicle's active profile.
3314  *
3315  * @see gui_internal_add_vehicle_profile
3316  */
3317 static void
3318 gui_internal_cmd_set_active_profile(struct gui_priv *this, struct
3319                 widget *wm, void *data)
3320 {
3321         struct vehicle_and_profilename *vapn = data;
3322         struct vehicle *v = vapn->vehicle;
3323         char *profilename = vapn->profilename;
3324         struct attr vehicle_name_attr;
3325         char *vehicle_name = NULL;
3326
3327         // Get the vehicle name
3328         vehicle_get_attr(v, attr_name, &vehicle_name_attr, NULL);
3329         vehicle_name = vehicle_name_attr.u.str;
3330
3331         dbg(0, "Changing vehicle %s to profile %s\n", vehicle_name,
3332                         profilename);
3333
3334         // Change the profile name
3335         struct attr profilename_attr = {attr_profilename, {profilename}};
3336         if(!vehicle_set_attr(v, &profilename_attr)) {
3337                 dbg(0, "Unable to set the vehicle's profile name\n");
3338         }
3339
3340     // Notify Navit that the routing should be re-done if this is the
3341     // active vehicle.
3342         if (gui_internal_is_active_vehicle(this, v)) {
3343                 struct attr vehicle;
3344                 vehicle.type=attr_vehicle;
3345                 vehicle.u.vehicle=v;
3346                 navit_set_attr(this->nav, &vehicle);
3347         }
3348         save_vehicle_xml(v);
3349 }
3350
3351 /**
3352  * Adds the vehicle profile to the GUI, allowing the user to pick a
3353  * profile for the currently selected vehicle.
3354  */
3355 static void
3356 gui_internal_add_vehicle_profile(struct gui_priv *this, struct widget
3357                 *parent, struct vehicle *v, struct vehicleprofile *profile)
3358 {
3359         // Just here to show up in the translation file, nice and close to
3360         // where the translations are actually used.
3361         struct attr profile_attr;
3362         struct attr *attr = NULL;
3363         char *name = NULL;
3364         char *active_profile = NULL;
3365         char *label = NULL;
3366         int active;
3367         struct vehicle_and_profilename *context = NULL;
3368
3369 #ifdef ONLY_FOR_TRANSLATION
3370         char *translations[] = {_n("car"), _n("bike"), _n("pedestrian")};
3371 #endif
3372
3373         // Figure out the profile name
3374         attr = attr_search(profile->attrs, NULL, attr_name);
3375         name = attr->u.str;
3376
3377         // Determine whether the profile is the active one
3378         vehicle_get_attr(v, attr_profilename, &profile_attr, NULL);
3379         active_profile = profile_attr.u.str;
3380         active = strcmp(name, active_profile) == 0;
3381
3382         dbg(0, "Adding vehicle profile %s, active=%s/%i\n", name,
3383                         active_profile, active);
3384
3385         // Build a translatable label.
3386         if(active) {
3387                 label = g_strdup_printf(_("Current profile: %s"), _(name));
3388         } else {
3389                 label = g_strdup_printf(_("Change profile to: %s"), _(name));
3390         }
3391
3392         // Create the context object (the vehicle and the desired profile)
3393         context = g_new0(struct vehicle_and_profilename, 1);
3394         context->vehicle = v;
3395         context->profilename = name;
3396
3397         // Add the button
3398         gui_internal_widget_append(parent,
3399                 gui_internal_button_new_with_callback(
3400                         this, label,
3401                         image_new_xs(this, active ? "gui_active" : "gui_inactive"),
3402                         gravity_left_center|orientation_horizontal|flags_fill,
3403                         gui_internal_cmd_set_active_profile, context));
3404
3405         free(label);
3406 }
3407
3408 static void
3409 gui_internal_cmd_vehicle_settings(struct gui_priv *this, struct widget *wm, void *data)
3410 {
3411         struct widget *w,*wb;
3412         struct attr attr;
3413         struct vehicle *v=wm->data;
3414     struct vehicleprofile *profile = NULL;
3415
3416         wb=gui_internal_menu(this, wm->text);
3417         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3418         gui_internal_widget_append(wb, w);
3419
3420     // Add the "Set as active" button if this isn't the active
3421     // vehicle.
3422         if (!gui_internal_is_active_vehicle(this, v)) {
3423                 gui_internal_widget_append(w,
3424                         gui_internal_button_new_with_callback(this, _("Set as active"),
3425                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3426                                 gui_internal_cmd_set_active_vehicle, wm->data));
3427         }
3428
3429         if (vehicle_get_attr(v, attr_position_sat_item, &attr, NULL)) {
3430                 gui_internal_widget_append(w,
3431                         gui_internal_button_new_with_callback(this, _("Show Satellite status"),
3432                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3433                                 gui_internal_cmd_show_satellite_status, wm->data));
3434         }
3435         if (vehicle_get_attr(v, attr_position_nmea, &attr, NULL)) {
3436                 gui_internal_widget_append(w,
3437                         gui_internal_button_new_with_callback(this, _("Show NMEA data"),
3438                                 image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill,
3439                                 gui_internal_cmd_show_nmea_data, wm->data));
3440         }
3441
3442     // Add all the possible vehicle profiles to the menu
3443         GList *profiles = navit_get_vehicleprofiles(this->nav);
3444     while(profiles) {
3445         profile = (struct vehicleprofile *)profiles->data;
3446         gui_internal_add_vehicle_profile(this, w, v, profile);
3447                 profiles = g_list_next(profiles);
3448     }
3449
3450         callback_list_call_attr_2(this->cbl, attr_vehicle, w, wm->data);
3451         gui_internal_menu_render(this);
3452 }
3453
3454 static void
3455 gui_internal_cmd2_setting_vehicle(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3456 {
3457         struct attr attr,vattr;
3458         struct widget *w,*wb,*wl;
3459         struct attr_iter *iter;
3460         struct attr active_vehicle;
3461
3462
3463         wb=gui_internal_menu(this, _("Vehicle"));
3464         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3465         w->spy=this->spacing*3;
3466         gui_internal_widget_append(wb, w);
3467         if (!navit_get_attr(this->nav, attr_vehicle, &active_vehicle, NULL))
3468                 active_vehicle.u.vehicle=NULL;
3469         iter=navit_attr_iter_new();
3470         while(navit_get_attr(this->nav, attr_vehicle, &attr, iter)) {
3471                 vehicle_get_attr(attr.u.vehicle, attr_name, &vattr, NULL);
3472                 wl=gui_internal_button_new_with_callback(this, vattr.u.str,
3473                         image_new_l(this, attr.u.vehicle == active_vehicle.u.vehicle ? "gui_active" : "gui_inactive"), gravity_left_center|orientation_horizontal|flags_fill,
3474                         gui_internal_cmd_vehicle_settings, attr.u.vehicle);
3475                 wl->text=g_strdup(vattr.u.str);
3476                 gui_internal_widget_append(w, wl);
3477         }
3478         navit_attr_iter_destroy(iter);
3479         gui_internal_menu_render(this);
3480 }
3481
3482
3483 static void
3484 gui_internal_cmd2_setting_rules(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
3485 {
3486         struct widget *wb,*w;
3487         struct attr on,off;
3488         wb=gui_internal_menu(this, _("Rules"));
3489         w=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
3490         w->spy=this->spacing*3;
3491         gui_internal_widget_append(wb, w);
3492         on.u.num=1;
3493         off.u.num=0;
3494         on.type=off.type=attr_tracking;
3495         gui_internal_widget_append(w,
3496                 gui_internal_button_navit_attr_new(this, _("Lock on road"), gravity_left_center|orientation_horizontal|flags_fill,
3497                         &on, &off));
3498         on.u.num=0;
3499         off.u.num=-1;
3500         on.type=off.type=attr_orientation;
3501         gui_internal_widget_append(w,
3502                 gui_internal_button_navit_attr_new(this, _("Northing"), gravity_left_center|orientation_horizontal|flags_fill,
3503                         &on, &off));
3504         on.u.num=1;
3505         off.u.num=0;
3506         on.type=off.type=attr_follow_cursor;
3507         gui_internal_widget_append(w,
3508                 gui_internal_button_navit_attr_new(this, _("Map follows Vehicle"), gravity_left_center|orientation_horizontal|flags_fill,
3509                         &on, &off));
3510         gui_internal_menu_render(this);
3511 }
3512
3513 //##############################################################################################################
3514 //# Description:
3515 //# Comment:
3516 //# Authors: Martin Schaller (04/2008)
3517 //##############################################################################################################
3518 static void gui_internal_motion(void *data, struct point *p)
3519 {
3520
3521         struct gui_priv *this=data;
3522         if (!this->root.children) {
3523                 navit_handle_motion(this->nav, p);
3524                 return;
3525         }
3526         if (!this->pressed)
3527                 return;
3528         this->current=*p;
3529         if(!this->motion_timeout_callback)
3530                 this->motion_timeout_callback=callback_new_1(callback_cast(gui_internal_highlight), this);
3531         if(!this->motion_timeout_event)
3532                 this->motion_timeout_event=event_add_timeout(100,0, this->motion_timeout_callback);
3533 }
3534
3535 static const char *
3536 find_attr(const char **names, const char **values, const char *name)
3537 {
3538         while (*names) {
3539                 if (!strcasecmp(*names, name))
3540                         return *values;
3541                 names+=xml_attr_distance;
3542                 values+=xml_attr_distance;
3543         }
3544         return NULL;
3545 }
3546
3547 static char *
3548 find_attr_dup(const char **names, const char **values, const char *name)
3549 {
3550         return g_strdup(find_attr(names, values, name));
3551 }
3552
3553 static void
3554 gui_internal_evaluate(struct gui_priv *this, const char *command)
3555 {
3556         if (command)
3557                 command_evaluate(&this->self, command);
3558 }
3559
3560
3561 static void
3562 gui_internal_html_command(struct gui_priv *this, struct widget *w, void *data)
3563 {
3564         gui_internal_evaluate(this,w->command);
3565 }
3566
3567 static void
3568 gui_internal_html_href(struct gui_priv *this, struct widget *w, void *data)
3569 {
3570         if (w->command && w->command[0] == '#') {
3571                 dbg(1,"href=%s\n",w->command);
3572                 gui_internal_html_menu(this, this->html_text, w->command+1);
3573         }
3574 }
3575
3576
3577 static void
3578 gui_internal_html_start(void *dummy, const char *tag_name, const char **names, const char **values, void *data, void *error)
3579 {
3580         struct gui_priv *this=data;
3581         int i;
3582         enum html_tag tag=html_tag_none;
3583         struct html *html=&this->html[this->html_depth];
3584         const char *src, *cond;
3585
3586         if (!strcasecmp(tag_name,"text"))
3587                 return;
3588         html->command=NULL;
3589         html->name=NULL;
3590         html->href=NULL;
3591         html->skip=0;
3592         cond=find_attr(names, values, "cond");
3593         
3594         if (cond && !this->html_skip) {
3595                 if (!command_evaluate_to_boolean(&this->self, cond, NULL)) 
3596                         html->skip=1;
3597         }
3598
3599         for (i=0 ; i < sizeof(html_tag_map)/sizeof(struct html_tag_map); i++) {
3600                 if (!strcasecmp(html_tag_map[i].tag_name, tag_name)) {
3601                         tag=html_tag_map[i].tag;
3602                         break;
3603                 }
3604         }
3605         html->tag=tag;
3606         if (!this->html_skip && !html->skip) {
3607                 switch (tag) {
3608                 case html_tag_a:
3609                         html->name=find_attr_dup(names, values, "name");
3610                         if (html->name) {
3611                                 if (this->html_anchor_found)
3612                                         html->skip=1;
3613                                 else
3614                                         html->skip=this->html_anchor ? strcmp(html->name,this->html_anchor) : 0;
3615                                 if (!html->skip)
3616                                         this->html_anchor_found=1;
3617                         }
3618                         html->href=find_attr_dup(names, values, "href");
3619                         break;
3620                 case html_tag_img:
3621                         html->command=find_attr_dup(names, values, "onclick");
3622                         src=find_attr(names, values, "src");
3623                         if (src)
3624                                 html->w=gui_internal_image_new(this, image_new_l(this, src));
3625                         break;
3626                 default:
3627                         break;
3628                 }
3629         }
3630         this->html_skip+=html->skip;
3631         this->html_depth++;
3632 }
3633
3634 static void
3635 gui_internal_html_end(void *dummy, const char *tag_name, void *data, void *error)
3636 {
3637         struct gui_priv *this=data;
3638         struct html *html;
3639         struct html *parent=NULL;
3640
3641         if (!strcasecmp(tag_name,"text"))
3642                 return;
3643         this->html_depth--;
3644         html=&this->html[this->html_depth];
3645         if (this->html_depth > 0)
3646                 parent=&this->html[this->html_depth-1];
3647         
3648
3649         if (!this->html_skip) { 
3650                 if (html->command && html->w) {
3651                         html->w->state |= STATE_SENSITIVE;
3652                         html->w->command=html->command;
3653                         html->w->func=gui_internal_html_command;
3654                         html->command=NULL;
3655                 }
3656                 if (parent && parent->href && html->w) {
3657                         html->w->state |= STATE_SENSITIVE;
3658                         html->w->command=g_strdup(parent->href);
3659                         html->w->func=gui_internal_html_href;
3660                 }
3661                 switch (html->tag) {
3662                 case html_tag_img:
3663                         gui_internal_widget_append(this->html_container, html->w);
3664                         break;
3665                 default:
3666                         break;
3667                 }
3668         }
3669         this->html_skip-=html->skip;
3670         g_free(html->command);
3671         g_free(html->name);
3672         g_free(html->href);
3673 }
3674
3675 static void
3676 gui_internal_html_text(void *dummy, const char *text, int len, void *data, void *error)
3677 {
3678         struct gui_priv *this=data;
3679         struct widget *w;
3680         int depth=this->html_depth-1;
3681         struct html *html=&this->html[depth];
3682         char *text_stripped;
3683
3684         if (this->html_skip)
3685                 return;
3686         while (isspace(text[0])) {
3687                 text++;
3688                 len--;
3689         }
3690         while (len > 0 && isspace(text[len-1]))
3691                 len--;
3692         text_stripped=g_malloc(len+1);
3693         strncpy(text_stripped, text, len);
3694         text_stripped[len]='\0';
3695         if (html->tag == html_tag_html && depth > 2) {
3696                 if (this->html[depth-1].tag == html_tag_script) {
3697                         html=&this->html[depth-2];
3698                 }
3699         }
3700         switch (html->tag) {
3701         case html_tag_a:
3702                 if (html->name && len) {
3703                         this->html_container=gui_internal_menu(this, gettext(text_stripped));
3704                         this->html_container->spx=this->spacing*10;
3705                 }
3706                 break;
3707         case html_tag_h1:
3708                 if (!this->html_container) {
3709                         this->html_container=gui_internal_menu(this, gettext(text_stripped));
3710                         this->html_container->spx=this->spacing*10;
3711                 }
3712                 break;
3713         case html_tag_img:
3714                 if (len) {
3715                         w=gui_internal_box_new(this, gravity_center|orientation_vertical);
3716                         gui_internal_widget_append(w, html->w);
3717                         gui_internal_widget_append(w, gui_internal_text_new(this, gettext(text_stripped), gravity_center|orientation_vertical));
3718                         html->w=w;
3719                 }
3720                 break;
3721         case html_tag_script:
3722                 dbg(1,"execute %s\n",text_stripped);
3723                 gui_internal_evaluate(this,text_stripped);
3724                 break;
3725         default:
3726                 break;
3727         }
3728 }
3729
3730 static void
3731 gui_internal_html_menu(struct gui_priv *this, const char *document, char *anchor)
3732 {
3733         graphics_draw_mode(this->gra, draw_mode_begin);
3734         this->html_container=NULL;
3735         this->html_depth=0;
3736         this->html_anchor=anchor;
3737         this->html_anchor_found=0;
3738         xml_parse_text(document, this, gui_internal_html_start, gui_internal_html_end, gui_internal_html_text);
3739         gui_internal_menu_render(this);
3740         graphics_draw_mode(this->gra, draw_mode_end);
3741 }
3742
3743
3744 static void gui_internal_menu_root(struct gui_priv *this)
3745 {
3746         gui_internal_html_menu(this, this->html_text, "Main Menu");
3747 }
3748
3749 static void
3750 gui_internal_enter(struct gui_priv *this, int ignore)
3751 {
3752         struct graphics *gra=this->gra;
3753         this->ignore_button=ignore;
3754         this->clickp_valid=this->vehicle_valid=0;
3755
3756         navit_block(this->nav, 1);
3757         graphics_overlay_disable(gra, 1);
3758         this->root.p.x=0;
3759         this->root.p.y=0;
3760         this->root.background=this->background;
3761 }
3762
3763 static void
3764 gui_internal_leave(struct gui_priv *this)
3765 {
3766         graphics_draw_mode(this->gra, draw_mode_end);
3767 }
3768
3769 static void
3770 gui_internal_cmd_menu(struct gui_priv *this, struct point *p, int ignore)
3771 {
3772         struct transformation *trans;
3773         struct coord c;
3774         struct coord_geo g;
3775         struct attr attr,attrp;
3776
3777         dbg(1,"enter\n");
3778         gui_internal_enter(this, ignore);
3779         trans=navit_get_trans(this->nav);
3780         attr_free(this->click_coord_geo);
3781         this->click_coord_geo=NULL;
3782         attr_free(this->position_coord_geo);
3783         this->position_coord_geo=NULL;
3784         if (p) {
3785                 transform_reverse(trans, p, &c);
3786                 dbg(1,"x=0x%x y=0x%x\n", c.x, c.y);
3787                 this->clickp.pro=transform_get_projection(trans);
3788                 this->clickp.x=c.x;
3789                 this->clickp.y=c.y;
3790                 transform_to_geo(this->clickp.pro, &c, &g);
3791                 attr.u.coord_geo=&g;
3792                 attr.type=attr_click_coord_geo;
3793                 this->click_coord_geo=attr_dup(&attr);
3794         }
3795         if (navit_get_attr(this->nav, attr_vehicle, &attr, NULL) && attr.u.vehicle
3796                 && vehicle_get_attr(attr.u.vehicle, attr_position_coord_geo, &attrp, NULL)) {
3797                 this->position_coord_geo=attr_dup(&attrp);
3798                 this->vehiclep.pro=transform_get_projection(trans);
3799                 transform_from_geo(this->vehiclep.pro, attrp.u.coord_geo, &c);
3800                 this->vehiclep.x=c.x;
3801                 this->vehiclep.y=c.y;
3802                 this->vehicle_valid=1;
3803         }
3804         // draw menu
3805         gui_internal_menu_root(this);
3806 }
3807
3808 static void
3809 gui_internal_cmd_menu2(struct gui_priv *this)
3810 {
3811         gui_internal_cmd_menu(this, NULL, 1);
3812 }
3813
3814
3815 static void
3816 gui_internal_cmd_log_do(struct gui_priv *this, struct widget *widget)
3817 {
3818         if (widget->text && strlen(widget->text))
3819                 navit_textfile_debug_log(this->nav, "type=log_entry label=\"%s\"",widget->text);
3820         g_free(widget->text);
3821         widget->text=NULL;
3822         gui_internal_prune_menu(this, NULL);
3823         gui_internal_check_exit(this);
3824 }
3825
3826 static void
3827 gui_internal_cmd_log_clicked(struct gui_priv *this, struct widget *widget, void *data)
3828 {
3829         gui_internal_cmd_log_do(this, widget->data);
3830 }
3831
3832 static void
3833 gui_internal_cmd_log_changed(struct gui_priv *this, struct widget *wm, void *data)
3834 {
3835         int len;
3836         if (wm->text) {
3837                 len=strlen(wm->text);
3838                 if (len && (wm->text[len-1] == '\n' || wm->text[len-1] == '\r')) {
3839                         wm->text[len-1]='\0';
3840                         gui_internal_cmd_log_do(this, wm);
3841                 }
3842         }
3843 }
3844
3845
3846 static void
3847 gui_internal_cmd_log(struct gui_priv *this)
3848 {
3849         struct widget *w,*wb,*wk,*wl,*we,*wnext;
3850         gui_internal_enter(this, 1);
3851         wb=gui_internal_menu(this, "Log Message");
3852         w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
3853         gui_internal_widget_append(wb, w);
3854         we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
3855         gui_internal_widget_append(w, we);
3856         gui_internal_widget_append(we, wk=gui_internal_label_new(this, _("Message")));
3857         wk->state |= STATE_EDIT|STATE_CLEAR;
3858         wk->background=this->background;
3859         wk->flags |= flags_expand|flags_fill;
3860         wk->func = gui_internal_cmd_log_changed;
3861         gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
3862         wnext->state |= STATE_SENSITIVE;
3863         wnext->func = gui_internal_cmd_log_clicked;
3864         wnext->data=wk;
3865         wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
3866         gui_internal_widget_append(w, wl);
3867         if (this->keyboard)
3868                 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
3869         gui_internal_menu_render(this);
3870         gui_internal_leave(this);
3871 }
3872
3873 static void
3874 gui_internal_check_exit(struct gui_priv *this)
3875 {
3876         struct graphics *gra=this->gra;
3877         if (! this->root.children) {
3878                 gui_internal_search_idle_end(this);
3879                 gui_internal_search_list_destroy(this);
3880                 graphics_overlay_disable(gra, 0);
3881                 if (!navit_block(this->nav, 0)) {
3882                         if (this->redraw)
3883                                 navit_draw(this->nav);
3884                         else
3885                                 navit_draw_displaylist(this->nav);
3886                 }
3887         }
3888 }
3889
3890 static int
3891 gui_internal_get_attr(struct gui_priv *this, enum attr_type type, struct attr *attr)
3892 {
3893         switch (type) {
3894         case attr_active:
3895                 attr->u.num=this->root.children != NULL;
3896                 break;
3897         case attr_click_coord_geo:
3898                 if (!this->click_coord_geo)
3899                         return 0;
3900                 *attr=*this->click_coord_geo;
3901                 break;
3902         case attr_position_coord_geo:
3903                 if (!this->position_coord_geo)
3904                         return 0;
3905                 *attr=*this->position_coord_geo;
3906                 break;
3907         default:
3908                 return 0;
3909         }
3910         attr->type=type;
3911         return 1;
3912 }
3913
3914 static int
3915 gui_internal_add_attr(struct gui_priv *this, struct attr *attr)
3916 {
3917         switch (attr->type) {
3918         case attr_xml_text:
3919                 g_free(this->html_text);
3920                 this->html_text=g_strdup(attr->u.str);
3921                 return 1;
3922         default:
3923                 return 0;
3924         }
3925 }
3926
3927
3928 //##############################################################################################################
3929 //# Description: Function to handle mouse clicks and scroll wheel movement
3930 //# Comment:
3931 //# Authors: Martin Schaller (04/2008), Stefan Klumpp (04/2008)
3932 //##############################################################################################################
3933 static void gui_internal_button(void *data, int pressed, int button, struct point *p)
3934 {
3935         struct gui_priv *this=data;
3936         struct graphics *gra=this->gra;
3937
3938         dbg(1,"enter %d %d\n", pressed, button);
3939         // if still on the map (not in the menu, yet):
3940         dbg(1,"children=%p ignore_button=%d\n",this->root.children,this->ignore_button);
3941         if (!this->root.children || this->ignore_button) {
3942                 this->ignore_button=0;
3943                 // check whether the position of the mouse changed during press/release OR if it is the scrollwheel
3944                 if (!navit_handle_button(this->nav, pressed, button, p, NULL)) {
3945                         dbg(1,"navit has handled button\n");
3946                         return;
3947                 }
3948                 dbg(1,"menu_on_map_click=%d\n",this->menu_on_map_click);
3949                 if (this->menu_on_map_click && button == 1) 
3950                         gui_internal_cmd_menu(this, p, 0);
3951                 return;
3952         }
3953
3954
3955         // if already in the menu:
3956         if (pressed) {
3957                 this->pressed=1;
3958                 this->current=*p;
3959                 gui_internal_highlight(this);
3960         } else {
3961                 this->pressed=0;
3962                 this->current.x=-1;
3963                 this->current.y=-1;
3964                 graphics_draw_mode(gra, draw_mode_begin);
3965                 gui_internal_call_highlighted(this);
3966                 gui_internal_highlight(this);
3967                 graphics_draw_mode(gra, draw_mode_end);
3968                 gui_internal_check_exit(this);
3969         }
3970 }
3971
3972 static void
3973 gui_internal_setup_gc(struct gui_priv *this)
3974 {
3975         struct color cbh={0x9fff,0x9fff,0x9fff,0xffff};
3976         struct color cf={0xbfff,0xbfff,0xbfff,0xffff};
3977         struct graphics *gra=this->gra;
3978
3979         if (this->background)
3980                 return;
3981         this->background=graphics_gc_new(gra);
3982         this->background2=graphics_gc_new(gra);
3983         this->highlight_background=graphics_gc_new(gra);
3984         graphics_gc_set_foreground(this->highlight_background, &cbh);
3985         this->foreground=graphics_gc_new(gra);
3986         graphics_gc_set_foreground(this->foreground, &cf);
3987         this->text_background=graphics_gc_new(gra);
3988         this->text_foreground=graphics_gc_new(gra);
3989         graphics_gc_set_foreground(this->background, &this->background_color);
3990         graphics_gc_set_foreground(this->background2, &this->background2_color);
3991         graphics_gc_set_foreground(this->text_background, &this->text_background_color);
3992         graphics_gc_set_foreground(this->text_foreground, &this->text_foreground_color);
3993 }
3994
3995 //##############################################################################################################
3996 //# Description:
3997 //# Comment:
3998 //# Authors: Martin Schaller (04/2008)
3999 //##############################################################################################################
4000 static void gui_internal_resize(void *data, int w, int h)
4001 {
4002         struct gui_priv *this=data;
4003         int changed=0;
4004
4005         gui_internal_setup_gc(this);
4006
4007         if (this->root.w != w || this->root.h != h) {
4008                 this->root.w=w;
4009                 this->root.h=h;
4010                 changed=1;
4011         }
4012         dbg(1,"w=%d h=%d children=%p\n", w, h, this->root.children);
4013         navit_handle_resize(this->nav, w, h);
4014         if (this->root.children && changed) {
4015                 gui_internal_prune_menu(this, NULL);
4016                 gui_internal_menu_root(this);
4017         }
4018 }
4019
4020 static void
4021 gui_internal_keynav_point(struct widget *w, int dx, int dy, struct point *p)
4022 {
4023         p->x=w->p.x+w->w/2;
4024         p->y=w->p.y+w->h/2;
4025         if (dx < 0)
4026                 p->x=w->p.x;
4027         if (dx > 0)
4028                 p->x=w->p.x+w->w;
4029         if (dy < 0)
4030                 p->y=w->p.y;
4031         if (dy > 0)
4032                 p->y=w->p.y+w->h;
4033 }
4034
4035 static void
4036 gui_internal_keynav_find_closest(struct widget *wi, struct point *p, int dx, int dy, int *distance, struct widget **result)
4037 {
4038         GList *l=wi->children;
4039         if (wi->state & STATE_SENSITIVE) {
4040                 int dist1,dist2;
4041                 struct point wp;
4042                 gui_internal_keynav_point(wi, -dx, -dy, &wp);
4043                 if (dx) {
4044                         dist1=(wp.x-p->x)*dx;
4045                         dist2=wp.y-p->y;
4046                 } else if (dy) {
4047                         dist1=(wp.y-p->y)*dy;
4048                         dist2=wp.x-p->x;
4049                 } else {
4050                         dist2=wp.x-p->x;
4051                         dist1=wp.y-p->y;
4052                         if (dist1 < 0)
4053                                 dist1=-dist1;
4054                 }
4055                 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);
4056                 if (dist1 >= 0) {
4057                         if (dist2 < 0)
4058                                 dist1-=dist2;
4059                         else
4060                                 dist1+=dist2;
4061                         if (dist1 < *distance) {
4062                                 *result=wi;
4063                                 *distance=dist1;
4064                         }
4065                 }
4066         }
4067         while (l) {
4068                 struct widget *child=l->data;
4069                 gui_internal_keynav_find_closest(child, p, dx, dy, distance, result);
4070                 l=g_list_next(l);
4071         }
4072 }
4073
4074 static void
4075 gui_internal_keynav_highlight_next(struct gui_priv *this, int dx, int dy)
4076 {
4077         struct widget *result,*menu=g_list_last(this->root.children)->data;
4078         struct point p;
4079         int distance;
4080         if (this->highlighted && this->highlighted_menu == g_list_last(this->root.children)->data)
4081                 gui_internal_keynav_point(this->highlighted, dx, dy, &p);
4082         else {
4083                 p.x=0;
4084                 p.y=0;
4085                 distance=INT_MAX;
4086                 result=NULL;
4087                 gui_internal_keynav_find_closest(menu, &p, 0, 0, &distance, &result);
4088                 if (result) {
4089                         gui_internal_keynav_point(result, dx, dy, &p);
4090                         dbg(1,"result origin=%p p=%d,%d\n", result, p.x, p.y);
4091                 }
4092         }
4093         result=NULL;
4094         distance=INT_MAX;
4095         gui_internal_keynav_find_closest(menu, &p, dx, dy, &distance, &result);
4096         dbg(1,"result=%p\n", result);
4097         if (! result) {
4098                 if (dx < 0)
4099                         p.x=this->root.w;
4100                 if (dx > 0)
4101                         p.x=0;
4102                 if (dy < 0)
4103                         p.y=this->root.h;
4104                 if (dy > 0)
4105                         p.y=0;
4106                 result=NULL;
4107                 distance=INT_MAX;
4108                 gui_internal_keynav_find_closest(menu, &p, dx, dy, &distance, &result);
4109                 dbg(1,"wraparound result=%p\n", result);
4110         }
4111         gui_internal_highlight_do(this, result);
4112         if (result)
4113                 gui_internal_say(this, result, 1);
4114 }
4115
4116 //##############################################################################################################
4117 //# Description:
4118 //# Comment:
4119 //# Authors: Martin Schaller (04/2008)
4120 //##############################################################################################################
4121 static void gui_internal_keypress(void *data, char *key)
4122 {
4123         struct gui_priv *this=data;
4124         int w,h;
4125         struct point p;
4126         if (!this->root.children) {
4127                 transform_get_size(navit_get_trans(this->nav), &w, &h);
4128                 switch (*key) {
4129                 case NAVIT_KEY_UP:
4130                         p.x=w/2;
4131                         p.y=0;
4132                         navit_set_center_screen(this->nav, &p, 1);
4133                         break;
4134                 case NAVIT_KEY_DOWN:
4135                         p.x=w/2;
4136                         p.y=h;
4137                         navit_set_center_screen(this->nav, &p, 1);
4138                         break;
4139                 case NAVIT_KEY_LEFT:
4140                         p.x=0;
4141                         p.y=h/2;
4142                         navit_set_center_screen(this->nav, &p, 1);
4143                         break;
4144                 case NAVIT_KEY_RIGHT:
4145                         p.x=w;
4146                         p.y=h/2;
4147                         navit_set_center_screen(this->nav, &p, 1);
4148                         break;
4149                 case NAVIT_KEY_ZOOM_IN:
4150                         navit_zoom_in(this->nav, 2, NULL);
4151                         break;
4152                 case NAVIT_KEY_ZOOM_OUT:
4153                         navit_zoom_out(this->nav, 2, NULL);
4154                         break;
4155                 case NAVIT_KEY_RETURN:
4156                 case NAVIT_KEY_MENU:
4157                         gui_internal_cmd_menu(this, NULL, 0);
4158                         break;
4159                 }
4160                 return;
4161         }
4162         graphics_draw_mode(this->gra, draw_mode_begin);
4163         switch (*key) {
4164         case NAVIT_KEY_LEFT:
4165                 gui_internal_keynav_highlight_next(this,-1,0);
4166                 break;
4167         case NAVIT_KEY_RIGHT:
4168                 gui_internal_keynav_highlight_next(this,1,0);
4169                 break;
4170         case NAVIT_KEY_UP:
4171                 gui_internal_keynav_highlight_next(this,0,-1);
4172                 break;
4173         case NAVIT_KEY_DOWN:
4174                 gui_internal_keynav_highlight_next(this,0,1);
4175                 break;
4176         case NAVIT_KEY_BACK:
4177                 break;
4178         case NAVIT_KEY_RETURN:
4179                 if (this->highlighted && this->highlighted_menu == g_list_last(this->root.children)->data)
4180                         gui_internal_call_highlighted(this);
4181                 else
4182                         gui_internal_keypress_do(this, key);
4183                 break;
4184         default:
4185                 gui_internal_keypress_do(this, key);
4186         }
4187         graphics_draw_mode(this->gra, draw_mode_end);
4188         gui_internal_check_exit(this);
4189 }
4190
4191
4192 //##############################################################################################################
4193 //# Description:
4194 //# Comment:
4195 //# Authors: Martin Schaller (04/2008)
4196 //##############################################################################################################
4197 static int gui_internal_set_graphics(struct gui_priv *this, struct graphics *gra)
4198 {
4199         struct window *win;
4200         struct transformation *trans=navit_get_trans(this->nav);
4201
4202         win=graphics_get_data(gra, "window");
4203         if (! win)
4204                 return 1;
4205         navit_ignore_graphics_events(this->nav, 1);
4206         this->gra=gra;
4207         this->win=win;
4208         navit_ignore_graphics_events(this->nav, 1);
4209         transform_get_size(trans, &this->root.w, &this->root.h);
4210         this->resize_cb=callback_new_attr_1(callback_cast(gui_internal_resize), attr_resize, this);
4211         graphics_add_callback(gra, this->resize_cb);
4212         this->button_cb=callback_new_attr_1(callback_cast(gui_internal_button), attr_button, this);
4213         graphics_add_callback(gra, this->button_cb);
4214         this->motion_cb=callback_new_attr_1(callback_cast(gui_internal_motion), attr_motion, this);
4215         graphics_add_callback(gra, this->motion_cb);
4216         this->keypress_cb=callback_new_attr_1(callback_cast(gui_internal_keypress), attr_keypress, this);
4217         graphics_add_callback(gra, this->keypress_cb);
4218
4219         // set fullscreen if needed
4220         if (this->fullscreen)
4221                 this->win->fullscreen(this->win, this->fullscreen != 0);
4222         /* Was resize callback already issued? */
4223         if (navit_get_ready(this->nav) & 2)
4224                 gui_internal_setup_gc(this);
4225         return 0;
4226 }
4227
4228 static void gui_internal_disable_suspend(struct gui_priv *this)
4229 {
4230         if (this->win->disable_suspend)
4231                 this->win->disable_suspend(this->win);
4232 }
4233
4234 //##############################################################################################################
4235 //# Description:
4236 //# Comment:
4237 //# Authors: Martin Schaller (04/2008)
4238 //##############################################################################################################
4239 struct gui_methods gui_internal_methods = {
4240         NULL,
4241         NULL,
4242         gui_internal_set_graphics,
4243         NULL,
4244         NULL,
4245         NULL,
4246         gui_internal_disable_suspend,
4247         gui_internal_get_attr,
4248         gui_internal_add_attr,
4249 };
4250
4251 static void
4252 gui_internal_get_data(struct gui_priv *priv, char *command, struct attr **in, struct attr ***out)
4253 {
4254         struct attr private_data = (struct attr) { attr_private_data, {(void *)&priv->data}};
4255         if (out)
4256                 *out=attr_generic_add_attr(*out, &private_data);
4257 }
4258
4259 static void
4260 gui_internal_add_callback(struct gui_priv *priv, struct callback *cb)
4261 {
4262         callback_list_add(priv->cbl, cb);
4263 }
4264
4265 static void
4266 gui_internal_remove_callback(struct gui_priv *priv, struct callback *cb)
4267 {
4268         callback_list_remove(priv->cbl, cb);
4269 }
4270
4271
4272 static struct gui_internal_methods gui_internal_methods_ext = {
4273         gui_internal_add_callback,
4274         gui_internal_remove_callback,
4275         gui_internal_menu_render,
4276         image_new_xs,
4277         image_new_l,
4278 };
4279
4280
4281 static enum flags
4282 gui_internal_get_flags(struct widget *widget)
4283 {
4284         return widget->flags;
4285 }
4286
4287 static void
4288 gui_internal_set_flags(struct widget *widget, enum flags flags)
4289 {
4290         widget->flags=flags;
4291 }
4292
4293 static int
4294 gui_internal_get_state(struct widget *widget)
4295 {
4296         return widget->state;
4297 }
4298
4299 static void
4300 gui_internal_set_state(struct widget *widget, int state)
4301 {
4302         widget->state=state;
4303 }
4304
4305 static void
4306 gui_internal_set_func(struct widget *widget, void (*func)(struct gui_priv *priv, struct widget *widget, void *data))
4307 {
4308         widget->func=func;
4309 }
4310
4311 static void
4312 gui_internal_set_data(struct widget *widget, void *data)
4313 {
4314         widget->data=data;
4315 }
4316
4317 static void
4318 gui_internal_set_default_background(struct gui_priv *this, struct widget *widget)
4319 {
4320         widget->background=this->background;
4321 }
4322
4323 static struct gui_internal_widget_methods gui_internal_widget_methods = {
4324         gui_internal_widget_append,
4325         gui_internal_button_new,
4326         gui_internal_button_new_with_callback,
4327         gui_internal_box_new,
4328         gui_internal_label_new,
4329         gui_internal_image_new,
4330         gui_internal_keyboard,
4331         gui_internal_menu,
4332         gui_internal_get_flags,
4333         gui_internal_set_flags,
4334         gui_internal_get_state,
4335         gui_internal_set_state,
4336         gui_internal_set_func,
4337         gui_internal_set_data,
4338         gui_internal_set_default_background,
4339 };
4340
4341 static void
4342 gui_internal_cmd_write(struct gui_priv * this, char *function, struct attr **in, struct attr ***out, int *valid)
4343 {
4344         char *str=NULL,*str2=NULL;
4345         dbg(1,"enter %s %p %p %p\n",function,in,out,valid);
4346         if (!in || !in[0])
4347                 return;
4348         dbg(1,"%s\n",attr_to_name(in[0]->type));        
4349         if (in[0]->type >= attr_type_string_begin && in[0]->type <= attr_type_string_end) {
4350                 str=in[0]->u.str;
4351         }
4352         if (in[0]->type >= attr_type_coord_geo_begin && in[0]->type <= attr_type_coord_geo_end) {
4353                 str=str2=coordinates_geo(in[0]->u.coord_geo, '\n');
4354         }
4355         if (str) {
4356                 str=g_strdup_printf("<html>%s</html>\n",str);
4357                 xml_parse_text(str, this, gui_internal_html_start, gui_internal_html_end, gui_internal_html_text);
4358         }
4359         g_free(str);
4360         g_free(str2);
4361 }
4362
4363
4364 /**
4365  * @brief Creates a new table widget.
4366  *
4367  * Creates and returns a new table widget.  This function will
4368  * setup next/previous buttons as children.
4369  *
4370  * @param this The graphics context.
4371  * @param flags widget sizing flags.
4372  * @returns The newly created widget
4373  */
4374 struct widget * gui_internal_widget_table_new(struct gui_priv * this, enum flags flags, int buttons)
4375 {
4376         struct widget * widget = g_new0(struct widget,1);
4377         struct table_data * data = NULL;
4378         widget->type=widget_table;
4379         widget->flags=flags;
4380         widget->data = g_new0(struct table_data,1);
4381         widget->data_free=gui_internal_table_data_free;
4382         data = (struct table_data*)widget->data;
4383
4384
4385         if (buttons) {
4386         data->next_button = gui_internal_button_new_with_callback
4387                 (this,"Next",image_new_xs(this, "gui_active") ,
4388                  gravity_left_center  |orientation_vertical,
4389                  gui_internal_table_button_next,NULL);
4390         data->next_button->data=widget;
4391
4392
4393         data->prev_button =  gui_internal_button_new_with_callback
4394                 (this,"Prev",
4395                  image_new_xs(this, "gui_active")
4396                  ,gravity_right_center |orientation_vertical,
4397                  gui_internal_table_button_prev,NULL);
4398
4399         data->prev_button->data=widget;
4400
4401         data->this=this;
4402
4403         data->button_box=gui_internal_box_new(this,
4404                                               gravity_center|orientation_horizontal);
4405         data->button_box->children=g_list_append(data->button_box->children,
4406                                                  data->next_button);
4407         data->button_box->children=g_list_append(data->button_box->children,
4408                                                  data->prev_button);
4409         //data->button_box->background=this->background2;
4410         data->button_box->bl=this->spacing;
4411         widget->children=g_list_append(widget->children,data->button_box);
4412         gui_internal_widget_pack(this,data->button_box);
4413         }
4414
4415         return widget;
4416
4417 }
4418
4419 /**
4420  * @brief Clears all the rows from the table.
4421  * This function removes all rows from a table.
4422  * New rows can later be added to the table.
4423  */
4424 void gui_internal_widget_table_clear(struct gui_priv * this,struct widget * table)
4425 {
4426   GList * iter;
4427   struct table_data * table_data = (struct table_data* ) table->data;
4428
4429   iter = table->children;
4430   while(iter ) {
4431           if(iter->data != table_data->button_box) {
4432                   struct widget * child = (struct widget*)iter->data;
4433                   gui_internal_widget_destroy(this,child);
4434                   if(table->children == iter) {
4435                           table->children = g_list_remove(iter,iter->data);
4436                           iter=table->children;
4437                   }
4438                   else
4439                           iter = g_list_remove(iter,iter->data);
4440           }
4441           else {
4442                   iter = g_list_next(iter);
4443           }
4444
4445   }
4446   table_data->top_row=NULL;
4447   table_data->bottom_row=NULL;
4448   if(table_data->page_headers)
4449           g_list_free(table_data->page_headers);
4450   table_data->page_headers=NULL;
4451 }
4452
4453
4454 /**
4455  * Creates a new table_row widget.
4456  * @param this The graphics context
4457  * @param flags Sizing flags for the row
4458  * @returns The new table_row widget.
4459  */
4460 struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags)
4461 {
4462         struct widget * widget = g_new0(struct widget,1);
4463         widget->type=widget_table_row;
4464         widget->flags=flags;
4465         return widget;
4466 }
4467
4468
4469
4470 /**
4471  * @brief Computes the column dimensions for the table.
4472  *
4473  * @param w The table widget to compute dimensions for.
4474  *
4475  * This function examines all of the rows and columns for the table w
4476  * and returns a list (GList) of table_column_desc elements that
4477  * describe each column of the table.
4478  *
4479  * The caller is responsible for freeing the returned list.
4480  */
4481 static GList * gui_internal_compute_table_dimensions(struct gui_priv * this,struct widget * w)
4482 {
4483
4484         GList * column_desc = NULL;
4485         GList * current_desc=NULL;
4486         GList * cur_row = w->children;
4487         struct widget * cur_row_widget=NULL;
4488         GList * cur_column=NULL;
4489         struct widget * cell_w=NULL;
4490         struct table_column_desc * current_cell=NULL;
4491         struct table_data * table_data=NULL;
4492         int height=0;
4493         int width=0;
4494         int total_width=0;
4495         int column_count=0;
4496
4497         /**
4498          * Scroll through the the table and
4499          * 1. Compute the maximum width + height of each column across all rows.
4500          */
4501         table_data = (struct table_data*) w->data;
4502         for(cur_row=w->children;  cur_row ; cur_row = g_list_next(cur_row) )
4503         {
4504                 cur_row_widget = (struct widget*) cur_row->data;
4505                 current_desc = column_desc;
4506                 if(cur_row_widget == table_data->button_box)
4507                 {
4508                         continue;
4509                 }
4510                 column_count=0;
4511                 for(cur_column = cur_row_widget->children; cur_column;
4512                     cur_column=g_list_next(cur_column))
4513                 {
4514                         cell_w = (struct widget*) cur_column->data;
4515                         gui_internal_widget_pack(this,cell_w);
4516                         if(current_desc == 0)
4517                         {
4518                                 current_cell = g_new0(struct table_column_desc,1);
4519                                 column_desc = g_list_append(column_desc,current_cell);
4520                                 current_desc = g_list_last(column_desc);
4521                                 current_cell->height=cell_w->h;
4522                                 current_cell->width=cell_w->w;
4523                                 total_width+=cell_w->w;
4524
4525                         }
4526                         else
4527                         {
4528                                 current_cell = current_desc->data;
4529                                 height = cell_w->h;
4530                                 width = cell_w->w;
4531                                 if(current_cell->height < height )
4532                                 {
4533                                         current_cell->height = height;
4534                                 }
4535                                 if(current_cell->width < width)
4536                                 {
4537                                         total_width += (width-current_cell->width);
4538                                         current_cell->width = width;
4539
4540
4541
4542                                 }
4543                                 current_desc = g_list_next(current_desc);
4544                         }
4545                         column_count++;
4546
4547                 }/* column loop */
4548
4549         } /*row loop */
4550
4551
4552         /**
4553          * If the width of all columns is less than the width off
4554          * the table expand each cell proportionally.
4555          *
4556          */
4557         if(total_width+(this->spacing*column_count) < w->w ) {
4558                 for(current_desc=column_desc; current_desc; current_desc=g_list_next(current_desc)) {
4559                         current_cell = (struct table_column_desc*) current_desc->data;
4560                         current_cell->width= ( (current_cell->width+this->spacing)/(float)total_width) * w->w ;
4561                 }
4562         }
4563
4564         return column_desc;
4565 }
4566
4567
4568 /**
4569  * @brief Computes the height and width for the table.
4570  *
4571  * The height and widht are computed to display all cells in the table
4572  * at the requested height/width.
4573  *
4574  * @param this The graphics context
4575  * @param w The widget to pack.
4576  *
4577  */
4578 void gui_internal_table_pack(struct gui_priv * this, struct widget * w)
4579 {
4580
4581         int height=0;
4582         int width=0;
4583         int count=0;
4584         GList * column_data = gui_internal_compute_table_dimensions(this,w);
4585         GList * current=0;
4586         struct table_column_desc * cell_desc=0;
4587         struct table_data * table_data = (struct table_data*)w->data;
4588
4589         for(current = column_data; current; current=g_list_next(current))
4590         {
4591                 if(table_data->button_box == current->data )
4592                 {
4593                         continue;
4594                 }
4595                 cell_desc = (struct table_column_desc *) current->data;
4596                 width = width + cell_desc->width + this->spacing;
4597                 if(height < cell_desc->height)
4598                 {
4599                         height = cell_desc->height ;
4600                 }
4601         }
4602
4603
4604
4605         for(current=w->children; current; current=g_list_next(current))
4606         {
4607                 if(current->data!= table_data->button_box)
4608                 {
4609                         count++;
4610                 }
4611         }
4612         if (table_data->button_box)
4613                 gui_internal_widget_pack(this,table_data->button_box);
4614
4615
4616
4617         if(w->h + w->c.y   > this->root.h   )
4618         {
4619                 /**
4620                  * Do not allow the widget to exceed the screen.
4621                  *
4622                  */
4623                 w->h = this->root.h- w->c.y  - height;
4624         }
4625         w->w = width;
4626
4627         /**
4628          * Deallocate column descriptions.
4629          */
4630         current = column_data;
4631         while( (current = g_list_last(current)) )
4632         {
4633                 current = g_list_remove(current,current->data);
4634         }
4635
4636 }
4637
4638
4639
4640 /**
4641  * @brief Renders a table widget.
4642  *
4643  * @param this The graphics context
4644  * @param w The table widget to render.
4645  */
4646 void gui_internal_table_render(struct gui_priv * this, struct widget * w)
4647 {
4648
4649         int x;
4650         int y;
4651         GList * column_desc=NULL;
4652         GList * cur_row = NULL;
4653         GList * current_desc=NULL;
4654         struct table_data * table_data = (struct table_data*)w->data;
4655         int is_skipped=0;
4656         int is_first_page=1;
4657         struct table_column_desc * dim=NULL;
4658
4659         dbg_assert(table_data);
4660         column_desc = gui_internal_compute_table_dimensions(this,w);
4661         y=w->p.y;
4662
4663         /**
4664          * Skip rows that are on previous pages.
4665          */
4666         cur_row = w->children;
4667         if(table_data->top_row && table_data->top_row != w->children )
4668         {
4669                 cur_row = table_data->top_row;
4670                 is_first_page=0;
4671         }
4672
4673
4674         /**
4675          * Loop through each row.  Drawing each cell with the proper sizes,
4676          * at the proper positions.
4677          */
4678         for(table_data->top_row=cur_row; cur_row; cur_row = g_list_next(cur_row))
4679         {
4680                 GList * cur_column=NULL;
4681                 current_desc = column_desc;
4682                 struct widget * cur_row_widget = (struct widget*)cur_row->data;
4683                 int max_height=0;
4684                 x =w->p.x+this->spacing;
4685                 if(cur_row_widget == table_data->button_box )
4686                 {
4687                         continue;
4688                 }
4689                 dim = (struct table_column_desc*)current_desc->data;
4690
4691                 if( y + dim->height + (table_data->button_box ? table_data->button_box->h : 0) + this->spacing >= w->p.y + w->h )
4692                 {
4693                         /*
4694                          * No more drawing space left.
4695                          */
4696                         is_skipped=1;
4697                         break;
4698
4699                 }
4700                 for(cur_column = cur_row_widget->children; cur_column;
4701                     cur_column=g_list_next(cur_column))
4702                 {
4703                         struct  widget * cur_widget = (struct widget*) cur_column->data;
4704                         dim = (struct table_column_desc*)current_desc->data;
4705
4706                         cur_widget->p.x=x;
4707                         cur_widget->w=dim->width;
4708                         cur_widget->p.y=y;
4709                         cur_widget->h=dim->height;
4710                         x=x+cur_widget->w;
4711                         max_height = dim->height;
4712                         /* We pack the widget before rendering to ensure that the x and y
4713                          * coordinates get pushed down.
4714                          */
4715                         gui_internal_widget_pack(this,cur_widget);
4716                         gui_internal_widget_render(this,cur_widget);
4717
4718                         if(dim->height > max_height)
4719                         {
4720                                 max_height = dim->height;
4721                         }
4722                 }
4723                 y = y + max_height;
4724                 table_data->bottom_row=cur_row;
4725                 current_desc = g_list_next(current_desc);
4726         }
4727         if(table_data->button_box && (is_skipped || !is_first_page)  )
4728         {
4729                 table_data->button_box->p.y =w->p.y+w->h-table_data->button_box->h -
4730                         this->spacing;
4731                 if(table_data->button_box->p.y < y )
4732                 {
4733                         table_data->button_box->p.y=y;
4734                 }
4735                 table_data->button_box->p.x = w->p.x;
4736                 table_data->button_box->w = w->w;
4737                 //    table_data->button_box->h = w->h - y;
4738                 //    table_data->next_button->h=table_data->button_box->h;
4739                 //    table_data->prev_button->h=table_data->button_box->h;
4740                 //    table_data->next_button->c.y=table_data->button_box->c.y;
4741                 //    table_data->prev_button->c.y=table_data->button_box->c.y;
4742
4743                 gui_internal_widget_pack(this,table_data->button_box);
4744                 if(table_data->next_button->p.y > w->p.y + w->h + table_data->next_button->h)
4745                 {
4746
4747                         table_data->button_box->p.y = w->p.y + w->h -
4748                                 table_data->button_box->h;
4749                 }
4750                 if(is_skipped)
4751                 {
4752                         table_data->next_button->state|= STATE_SENSITIVE;
4753                 }
4754                 else
4755                 {
4756                         table_data->next_button->state&= ~STATE_SENSITIVE;
4757                 }
4758
4759                 if(table_data->top_row != w->children)
4760                 {
4761                         table_data->prev_button->state|= STATE_SENSITIVE;
4762                 }
4763                 else
4764                 {
4765                         table_data->prev_button->state&= ~STATE_SENSITIVE;
4766                 }
4767                 gui_internal_widget_render(this,table_data->button_box);
4768
4769
4770         }
4771
4772         /**
4773          * Deallocate column descriptions.
4774          */
4775         current_desc = column_desc;
4776         while( (current_desc = g_list_last(current_desc)) )
4777         {
4778                 current_desc = g_list_remove(current_desc,current_desc->data);
4779         }
4780 }
4781
4782
4783 /**
4784  * @brief Displays Route information
4785  *
4786  * @li The name of the active vehicle
4787  * @param wm The button that was pressed.
4788  * @param v Unused
4789  */
4790 static void
4791 gui_internal_cmd2_route_description(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
4792 {
4793
4794
4795         struct widget * menu;
4796         struct widget * row;
4797
4798
4799         if(! this->vehicle_cb)
4800         {
4801           /**
4802            * Register the callback on vehicle updates.
4803            */
4804           this->vehicle_cb = callback_new_attr_1(callback_cast(gui_internal_route_update),
4805                                                        attr_position_coord_geo,this);
4806           navit_add_callback(this->nav,this->vehicle_cb);
4807         }
4808
4809         this->route_data.route_table = gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
4810         row = gui_internal_widget_table_row_new(this,gravity_left | orientation_horizontal | flags_fill);
4811
4812         row = gui_internal_widget_table_row_new(this,gravity_left | orientation_horizontal | flags_fill);
4813
4814
4815         menu=gui_internal_menu(this,_("Route Description"));
4816
4817         menu->free=gui_internal_route_screen_free;
4818         this->route_data.route_showing=1;
4819         this->route_data.route_table->spx = this->spacing;
4820
4821
4822         struct widget * box = gui_internal_box_new(this, gravity_left_top| orientation_vertical | flags_fill | flags_expand);
4823
4824         //      gui_internal_widget_append(box,gui_internal_box_new_with_label(this,"Test"));
4825         gui_internal_widget_append(box,this->route_data.route_table);
4826         box->w=menu->w;
4827         box->spx = this->spacing;
4828         this->route_data.route_table->w=box->w;
4829         gui_internal_widget_append(menu,box);
4830         gui_internal_populate_route_table(this,this->nav);
4831         gui_internal_menu_render(this);
4832
4833 }
4834
4835 static int
4836 line_intersection(struct coord* a1, struct coord *a2, struct coord * b1, struct coord *b2, struct coord *res)
4837 {
4838         int n, a, b;
4839         int adx=a2->x-a1->x;
4840         int ady=a2->y-a1->y;
4841         int bdx=b2->x-b1->x;
4842         int bdy=b2->y-b1->y;
4843         n = bdy * adx - bdx * ady;
4844         a = bdx * (a1->y - b1->y) - bdy * (a1->x - b1->x);
4845         b = adx * (a1->y - b1->y) - ady * (a1->x - b1->x);
4846         if (n < 0) {
4847                 n = -n;
4848                 a = -a;
4849                 b = -b;
4850         }
4851         if (a < 0 || b < 0)
4852                 return 0;
4853         if (a > n || b > n)
4854                 return 0;
4855         if (n == 0) {
4856                 dbg(0,"a=%d b=%d n=%d\n", a, b, n);
4857                 dbg(0,"a1=0x%x,0x%x ad %d,%d\n", a1->x, a1->y, adx, ady);
4858                 dbg(0,"b1=0x%x,0x%x bd %d,%d\n", b1->x, b1->y, bdx, bdy);
4859                 dbg_assert(n != 0);
4860         }
4861         res->x = a1->x + a * adx / n;
4862         res->y = a1->y + a * ady / n;
4863         return 1;
4864 }
4865
4866 struct heightline {
4867         struct heightline *next;
4868         int height;
4869         struct coord_rect bbox;
4870         int count;
4871         struct coord c[0];
4872 };
4873
4874 struct diagram_point {
4875         struct diagram_point *next;
4876         struct coord c;
4877 };
4878
4879 static struct heightline *
4880 item_get_heightline(struct item *item)
4881 {
4882         struct heightline *ret=NULL;
4883         struct street_data *sd;
4884         struct attr attr;
4885         int i,height;
4886
4887         if (item_attr_get(item, attr_label, &attr)) {
4888                 height=atoi(attr.u.str);
4889                 sd=street_get_data(item);
4890                 if (sd && sd->count > 1) {
4891                         ret=g_malloc(sizeof(struct heightline)+sd->count*sizeof(struct coord));
4892                         ret->bbox.lu=sd->c[0];
4893                         ret->bbox.rl=sd->c[0];
4894                         ret->count=sd->count;
4895                         ret->height=height;
4896                         for (i = 0 ; i < sd->count ; i++) {
4897                                 ret->c[i]=sd->c[i];
4898                                 coord_rect_extend(&ret->bbox, sd->c+i);
4899                         }
4900                 }
4901                 street_data_free(sd);
4902         }
4903         return ret;
4904 }
4905
4906
4907 /**
4908  * @brief Displays Route Height Profile
4909  *
4910  * @li The name of the active vehicle
4911  * @param wm The button that was pressed.
4912  * @param v Unused
4913  */
4914 static void
4915 gui_internal_cmd2_route_height_profile(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
4916 {
4917
4918
4919         struct widget * menu, *box;
4920
4921         struct map * map=NULL;
4922         struct map_rect * mr=NULL;
4923         struct route * route;
4924         struct item * item =NULL;
4925         struct mapset *ms;
4926         struct mapset_handle *msh;
4927         int x,i,first=1,dist=0;
4928         struct coord c,last,res;
4929         struct coord_rect rbbox,dbbox;
4930         struct map_selection sel;
4931         struct heightline *heightline,*heightlines=NULL;
4932         struct diagram_point *min,*diagram_point,*diagram_points=NULL;
4933         sel.next=NULL;
4934         sel.order=18;
4935         sel.range.min=type_height_line_1;
4936         sel.range.max=type_height_line_3;
4937
4938
4939         menu=gui_internal_menu(this,_("Height Profile"));
4940         box = gui_internal_box_new(this, gravity_left_top| orientation_vertical | flags_fill | flags_expand);
4941         gui_internal_widget_append(menu, box);
4942         route = navit_get_route(this->nav);
4943         if (route)
4944                 map = route_get_map(route);
4945         if(map)
4946                 mr = map_rect_new(map,NULL);
4947         if(mr) {
4948                 while((item = map_rect_get_item(mr))) {
4949                         while (item_coord_get(item, &c, 1)) {
4950                                 if (first) {
4951                                         first=0;
4952                                         sel.u.c_rect.lu=c;
4953                                         sel.u.c_rect.rl=c;
4954                                 } else
4955                                         coord_rect_extend(&sel.u.c_rect, &c);
4956                         }
4957                 }
4958                 map_rect_destroy(mr);
4959                 ms=navit_get_mapset(this->nav);
4960                 if (!first && ms) {
4961                         msh=mapset_open(ms);
4962                         while ((map=mapset_next(msh, 1))) {
4963                                 mr=map_rect_new(map, &sel);
4964                                 if (mr) {
4965                                         while((item = map_rect_get_item(mr))) {
4966                                                 if (item->type >= sel.range.min && item->type <= sel.range.max) {
4967                                                         heightline=item_get_heightline(item);
4968                                                         if (heightline) {
4969                                                                 heightline->next=heightlines;
4970                                                                 heightlines=heightline;
4971                                                         }
4972                                                 }
4973                                         }
4974                                         map_rect_destroy(mr);
4975                                 }
4976                         }
4977                         mapset_close(msh);
4978                 }
4979         }
4980         map=NULL;
4981         mr=NULL;
4982         if (route)
4983                 map = route_get_map(route);
4984         if(map)
4985                 mr = map_rect_new(map,NULL);
4986         if(mr && heightlines) {
4987                 while((item = map_rect_get_item(mr))) {
4988                         first=1;
4989                         while (item_coord_get(item, &c, 1)) {
4990                                 if (first)
4991                                         first=0;
4992                                 else {
4993                                         heightline=heightlines;
4994                                         rbbox.lu=last;
4995                                         rbbox.rl=last;
4996                                         coord_rect_extend(&rbbox, &c);
4997                                         while (heightline) {
4998                                                 if (coord_rect_overlap(&rbbox, &heightline->bbox)) {
4999                                                         for (i = 0 ; i < heightline->count - 1; i++) {
5000                                                                 if (heightline->c[i].x != heightline->c[i+1].x || heightline->c[i].y != heightline->c[i+1].y) {
5001                                                                         if (line_intersection(heightline->c+i, heightline->c+i+1, &last, &c, &res)) {
5002                                                                                 diagram_point=g_new(struct diagram_point, 1);
5003                                                                                 diagram_point->c.x=dist+transform_distance(projection_mg, &last, &res);
5004                                                                                 diagram_point->c.y=heightline->height;
5005                                                                                 diagram_point->next=diagram_points;
5006                                                                                 diagram_points=diagram_point;
5007                                                                                 dbg(0,"%d %d\n", diagram_point->c.x, diagram_point->c.y);
5008                                                                         }
5009                                                                 }
5010                                                         }
5011                                                 }
5012                                                 heightline=heightline->next;
5013                                         }
5014                                         dist+=transform_distance(projection_mg, &last, &c);
5015                                 }
5016                                 last=c;
5017                         }
5018
5019                 }
5020                 map_rect_destroy(mr);
5021         }
5022
5023
5024         gui_internal_menu_render(this);
5025         first=1;
5026         diagram_point=diagram_points;
5027         while (diagram_point) {
5028                 if (first) {
5029                         dbbox.lu=diagram_point->c;
5030                         dbbox.rl=diagram_point->c;
5031                         first=0;
5032                 } else
5033                         coord_rect_extend(&dbbox, &diagram_point->c);
5034                 diagram_point=diagram_point->next;
5035         }
5036         dbg(0,"%d %d %d %d\n", dbbox.lu.x, dbbox.lu.y, dbbox.rl.x, dbbox.rl.y);
5037         if (dbbox.rl.x > dbbox.lu.x && dbbox.lu.x*100/(dbbox.rl.x-dbbox.lu.x) <= 25)
5038                 dbbox.lu.x=0;
5039         if (dbbox.lu.y > dbbox.rl.y && dbbox.rl.y*100/(dbbox.lu.y-dbbox.rl.y) <= 25)
5040                 dbbox.rl.y=0;
5041         dbg(0,"%d,%d %dx%d\n", box->p.x, box->p.y, box->w, box->h);
5042         x=dbbox.lu.x;
5043         first=1;
5044         for (;;) {
5045                 struct point p[2];
5046                 min=NULL;
5047                 diagram_point=diagram_points;
5048                 while (diagram_point) {
5049                         if (diagram_point->c.x >= x && (!min || min->c.x > diagram_point->c.x))
5050                                 min=diagram_point;
5051                         diagram_point=diagram_point->next;
5052                 }
5053                 if (! min)
5054                         break;
5055                 p[1].x=(min->c.x-dbbox.lu.x)*(box->w-10)/(dbbox.rl.x-dbbox.lu.x)+box->p.x+5;
5056                 p[1].y=(min->c.y-dbbox.rl.y)*(box->h-10)/(dbbox.lu.y-dbbox.rl.y)+box->p.y+5;
5057                 dbg(0,"%d,%d=%d,%d\n",min->c.x, min->c.y, p[1].x,p[1].y);
5058                 graphics_draw_circle(this->gra, this->foreground, &p[1], 2);
5059                 if (first)
5060                         first=0;
5061                 else
5062                         graphics_draw_lines(this->gra, this->foreground, p, 2);
5063                 p[0]=p[1];
5064                 x=min->c.x+1;
5065         }
5066
5067
5068 }
5069
5070 static void
5071 gui_internal_cmd2_locale(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
5072 {
5073         struct widget *menu,*wb,*w;
5074         char *text;
5075
5076         graphics_draw_mode(this->gra, draw_mode_begin);
5077         menu=gui_internal_menu(this, _("Show Locale"));
5078         menu->spx=this->spacing*10;
5079         wb=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
5080         gui_internal_widget_append(menu, wb);
5081         text=g_strdup_printf("LANG=%s",getenv("LANG"));
5082         gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
5083         w->flags=gravity_left_center|orientation_horizontal|flags_fill;
5084         g_free(text);
5085 #ifdef HAVE_API_WIN32_BASE
5086         {
5087                 wchar_t wcountry[32],wlang[32];
5088                 char country[32],lang[32];
5089
5090                 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, wlang, sizeof(wlang));
5091                 WideCharToMultiByte(CP_ACP,0,wlang,-1,lang,sizeof(lang),NULL,NULL);
5092                 text=g_strdup_printf("LOCALE_SABBREVLANGNAME=%s",lang);
5093                 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
5094                 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
5095                 g_free(text);
5096                 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVCTRYNAME, wcountry, sizeof(wcountry));
5097                 WideCharToMultiByte(CP_ACP,0,wcountry,-1,country,sizeof(country),NULL,NULL);
5098                 text=g_strdup_printf("LOCALE_SABBREVCTRYNAME=%s",country);
5099                 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
5100                 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
5101                 g_free(text);
5102         }
5103 #endif
5104
5105         gui_internal_menu_render(this);
5106         graphics_draw_mode(this->gra, draw_mode_end);
5107 }
5108
5109
5110 /**
5111  * @brief handles the 'next page' table event.
5112  * A callback function that is invoked when the 'next page' button is pressed
5113  * to advance the contents of a table widget.
5114  *
5115  * @param this The graphics context.
5116  * @param wm The button widget that was pressed.
5117  */
5118 static void gui_internal_table_button_next(struct gui_priv * this, struct widget * wm, void *data)
5119 {
5120         struct widget * table_widget = (struct widget * ) wm->data;
5121         struct table_data * table_data = NULL;
5122         int found=0;
5123         GList * iterator;
5124
5125         if(table_widget)
5126         {
5127                 table_data = (struct table_data*) table_widget->data;
5128
5129         }
5130         if(table_data)
5131         {
5132                 /**
5133                  * Before advancing to the next page we need to ensure
5134                  * that the current top_row is in the list of previous top_rows
5135                  * so previous page can work.
5136                  *
5137                  */
5138                 for(iterator=table_data->page_headers; iterator != NULL;
5139                     iterator = g_list_next(iterator) )
5140                 {
5141                         if(iterator->data == table_data->top_row)
5142                         {
5143                                 found=1;
5144                                 break;
5145                         }
5146
5147                 }
5148                 if( ! found)
5149                 {
5150                         table_data->page_headers=g_list_append(table_data->page_headers,
5151                                                                table_data->top_row);
5152                 }
5153
5154                 table_data->top_row = g_list_next(table_data->bottom_row);
5155         }
5156         wm->state&= ~STATE_HIGHLIGHTED;
5157         gui_internal_menu_render(this);
5158 }
5159
5160
5161
5162 /**
5163  * @brief handles the 'previous page' table event.
5164  * A callback function that is invoked when the 'previous page' button is pressed
5165  * to go back in the contents of a table widget.
5166  *
5167  * @param this The graphics context.
5168  * @param wm The button widget that was pressed.
5169  */
5170 static void gui_internal_table_button_prev(struct gui_priv * this, struct widget * wm, void *data)
5171 {
5172         struct widget * table_widget = (struct widget * ) wm->data;
5173         struct table_data * table_data = NULL;
5174         GList * current_page_top=NULL;
5175
5176         GList * iterator;
5177         if(table_widget)
5178         {
5179                 table_data = (struct table_data*) table_widget->data;
5180                 if(table_data)
5181                 {
5182                         current_page_top = table_data->top_row;
5183                         for(iterator = table_data->page_headers; iterator != NULL;
5184                             iterator = g_list_next(iterator))
5185                         {
5186                                 if(current_page_top == iterator->data)
5187                                 {
5188                                         break;
5189                                 }
5190                                 table_data->top_row = (GList*) iterator->data;
5191                         }
5192                 }
5193         }
5194         wm->state&= ~STATE_HIGHLIGHTED;
5195         gui_internal_menu_render(this);
5196 }
5197
5198
5199 /**
5200  * @brief deallocates a table_data structure.
5201  *
5202  */
5203 void gui_internal_table_data_free(void * p)
5204 {
5205
5206
5207         /**
5208          * @note button_box and its children (next_button,prev_button)
5209          * have their memory managed by the table itself.
5210          */
5211         struct table_data * table_data =  (struct table_data*) p;
5212         g_list_free(table_data->page_headers);
5213         g_free(p);
5214
5215
5216 }
5217
5218
5219 /**
5220  * @brief Called when the route is updated.
5221  */
5222 void gui_internal_route_update(struct gui_priv * this, struct navit * navit, struct vehicle *v)
5223 {
5224
5225         if(this->route_data.route_showing) {
5226                 gui_internal_populate_route_table(this,navit);
5227                 graphics_draw_mode(this->gra, draw_mode_begin);
5228                 gui_internal_menu_render(this);
5229                 graphics_draw_mode(this->gra, draw_mode_end);
5230         }
5231
5232
5233 }
5234
5235
5236 /**
5237  * @brief Called when the route screen is closed (deallocated).
5238  *
5239  * The main purpose of this function is to remove the widgets from
5240  * references route_data because those widgets are about to be freed.
5241  */
5242 void gui_internal_route_screen_free(struct gui_priv * this_,struct widget * w)
5243 {
5244         if(this_) {
5245                 this_->route_data.route_showing=0;
5246                 this_->route_data.route_table=NULL;
5247                 g_free(w);
5248         }
5249
5250 }
5251
5252 /**
5253  * @brief Populates the route  table with route information
5254  *
5255  * @param this The gui context
5256  * @param navit The navit object
5257  */
5258 void gui_internal_populate_route_table(struct gui_priv * this,
5259                                        struct navit * navit)
5260 {
5261         struct map * map=NULL;
5262         struct map_rect * mr=NULL;
5263         struct navigation * nav = NULL;
5264         struct item * item =NULL;
5265         struct attr attr;
5266         struct widget * label = NULL;
5267         struct widget * row = NULL;
5268         nav = navit_get_navigation(navit);
5269         if(!nav) {
5270                 return;
5271         }
5272         map = navigation_get_map(nav);
5273         if(map)
5274           mr = map_rect_new(map,NULL);
5275         if(mr) {
5276                 gui_internal_widget_table_clear(this,this->route_data.route_table);
5277                 while((item = map_rect_get_item(mr))) {
5278                         if(item_attr_get(item,attr_navigation_long,&attr)) {
5279                           label = gui_internal_label_new(this,attr.u.str);
5280                           row = gui_internal_widget_table_row_new(this,
5281                                                                   gravity_left
5282                                                                   | flags_fill
5283                                                                   | orientation_horizontal);
5284                           row->children=g_list_append(row->children,label);
5285                           gui_internal_widget_append(this->route_data.route_table,row);
5286                         }
5287
5288                 }
5289
5290         }
5291 }
5292
5293 static struct command_table commands[] = {
5294         {"abort_navigation()",command_cast(gui_internal_cmd2_abort_navigation)},
5295         {"back_to_map",command_cast(gui_internal_cmd2_back_to_map)},
5296         {"bookmarks",command_cast(gui_internal_cmd2_bookmarks)},
5297         {"fullscreen",command_cast(gui_internal_cmd_fullscreen)},
5298         {"get_data",command_cast(gui_internal_get_data)},
5299         {"locale",command_cast(gui_internal_cmd2_locale)},
5300         {"log",command_cast(gui_internal_cmd_log)},
5301         {"menu",command_cast(gui_internal_cmd_menu2)},
5302         {"position",command_cast(gui_internal_cmd2_position)},
5303         {"route_description",command_cast(gui_internal_cmd2_route_description)},
5304         {"route_height_profile",command_cast(gui_internal_cmd2_route_height_profile)},
5305         {"setting_display",command_cast(gui_internal_cmd2_setting_display)},
5306         {"setting_maps",command_cast(gui_internal_cmd2_setting_maps)},
5307         {"setting_rules",command_cast(gui_internal_cmd2_setting_rules)},
5308         {"setting_vehicle",command_cast(gui_internal_cmd2_setting_vehicle)},
5309         {"town",command_cast(gui_internal_cmd2_town)},
5310         {"quit",command_cast(gui_internal_cmd2_quit)},
5311         {"write",command_cast(gui_internal_cmd_write)},
5312 };
5313
5314
5315 //##############################################################################################################
5316 //# Description:
5317 //# Comment:
5318 //# Authors: Martin Schaller (04/2008)
5319 //##############################################################################################################
5320 static struct gui_priv * gui_internal_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs, struct gui *gui)
5321 {
5322         struct gui_priv *this;
5323         struct attr *attr;
5324         *meth=gui_internal_methods;
5325         this=g_new0(struct gui_priv, 1);
5326         this->nav=nav;
5327
5328         this->self.type=attr_gui;
5329         this->self.u.gui=gui;   
5330
5331         if ((attr=attr_search(attrs, NULL, attr_menu_on_map_click)))
5332                 this->menu_on_map_click=attr->u.num;
5333         else
5334                 this->menu_on_map_click=1;
5335         if ((attr=attr_search(attrs, NULL, attr_callback_list))) {
5336                 command_add_table(attr->u.callback_list, commands, sizeof(commands)/sizeof(struct command_table), this);
5337         }
5338
5339         if( (attr=attr_search(attrs,NULL,attr_font_size)))
5340         {
5341           this->config.font_size=attr->u.num;
5342         }
5343         else
5344         {
5345           this->config.font_size=-1;
5346         }
5347         if( (attr=attr_search(attrs,NULL,attr_icon_xs)))
5348         {
5349           this->config.icon_xs=attr->u.num;
5350         }
5351         else
5352         {
5353           this->config.icon_xs=-1;
5354         }
5355         if( (attr=attr_search(attrs,NULL,attr_icon_l)))
5356         {
5357           this->config.icon_l=attr->u.num;
5358         }
5359         else
5360         {
5361           this->config.icon_l=-1;
5362         }
5363         if( (attr=attr_search(attrs,NULL,attr_icon_s)))
5364         {
5365           this->config.icon_s=attr->u.num;
5366         }
5367         else
5368         {
5369           this->config.icon_s=-1;
5370         }
5371         if( (attr=attr_search(attrs,NULL,attr_spacing)))
5372         {
5373           this->config.spacing=attr->u.num;
5374         }
5375         else
5376         {
5377           this->config.spacing=-1;
5378         }
5379         if( (attr=attr_search(attrs,NULL,attr_gui_speech)))
5380         {
5381           this->speech=attr->u.num;
5382         }
5383         if( (attr=attr_search(attrs,NULL,attr_keyboard)))
5384           this->keyboard=attr->u.num;
5385         else
5386           this->keyboard=1;
5387
5388     if( (attr=attr_search(attrs,NULL,attr_fullscreen)))
5389       this->fullscreen=attr->u.num;
5390
5391         if( (attr=attr_search(attrs,NULL,attr_flags)))
5392               this->flags=attr->u.num;
5393         if( (attr=attr_search(attrs,NULL,attr_background_color)))
5394               this->background_color=*attr->u.color;
5395         else
5396               this->background_color=(struct color){0x0,0x0,0x0,0xffff};
5397         if( (attr=attr_search(attrs,NULL,attr_background_color2)))
5398                 this->background2_color=*attr->u.color;
5399         else
5400                 this->background2_color=(struct color){0x4141,0x4141,0x4141,0xffff};
5401         if( (attr=attr_search(attrs,NULL,attr_text_color)))
5402               this->text_foreground_color=*attr->u.color;
5403         else
5404               this->text_foreground_color=(struct color){0xffff,0xffff,0xffff,0xffff};
5405         if( (attr=attr_search(attrs,NULL,attr_columns)))
5406               this->cols=attr->u.num;
5407         if( (attr=attr_search(attrs,NULL,attr_osd_configuration)))
5408               this->osd_configuration=*attr;
5409
5410         if( (attr=attr_search(attrs,NULL,attr_pitch)))
5411               this->pitch=attr->u.num;
5412         else
5413                 this->pitch=20;
5414         this->data.priv=this;
5415         this->data.gui=&gui_internal_methods_ext;
5416         this->data.widget=&gui_internal_widget_methods;
5417         this->cbl=callback_list_new();
5418
5419         return this;
5420 }
5421
5422 //##############################################################################################################
5423 //# Description:
5424 //# Comment:
5425 //# Authors: Martin Schaller (04/2008)
5426 //##############################################################################################################
5427 void plugin_init(void)
5428 {
5429         plugin_register_gui_type("internal", gui_internal_new);
5430 }
5431