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