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