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