/[zanavi_public1]/navit/navit/gui/internal/gui_internal.c
ZANavi

Contents of /navit/navit/gui/internal/gui_internal.c

Parent Directory Parent Directory | Revision Log Revision Log


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

   
Visit the ZANavi Wiki