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