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