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