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