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