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