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