/[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 - (show 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 /**
2 * 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 * 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
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 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
552 #ifdef PLUGSSS
553 static void gui_internal_destroy(struct gui_priv *this);
554 #endif
555
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 wm->speech=g_strdup("Back to map");
1682 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 wh->speech=g_strdup("Main Menu");
1691 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 wb=gui_internal_menu(this,"Add Bookmark");
2130 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 wb=gui_internal_menu(this,"Add Bookmark folder");
2157 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 wb=gui_internal_menu(this,"Rename");
2184 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 wb=gui_internal_menu(this, isel ? isel->name : "POIs");
2502 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 wb=gui_internal_button_new_with_callback(this, "View in Browser",
2695 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 wb=gui_internal_button_new_with_callback(this, "View in Browser",
2832 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 wb=gui_internal_button_new_with_callback(this, "View Attributes",
2838 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 wbc=gui_internal_button_new_with_callback(this, "Set as destination",
2847 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 wbc=gui_internal_button_new_with_callback(this, "Set as position",
2855 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 wbc=gui_internal_button_new_with_callback(this, "Add as bookmark",
2862 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 wbc=gui_internal_button_new_with_callback(this, "POIs",
2872 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 wbc=gui_internal_button_new_with_callback(this, "View on map",
2885 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 wbc=gui_internal_button_new_with_callback(this, "Cut Bookmark",
2952 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 wbc=gui_internal_button_new_with_callback(this, "Copy Bookmark",
2957 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 wbc=gui_internal_button_new_with_callback(this, "Rename Bookmark",
2962 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 wbc=gui_internal_button_new_with_callback(this, "Paste Bookmark",
2967 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 wbc=gui_internal_button_new_with_callback(this, "Delete Bookmark",
2971 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 wb=gui_internal_menu(this, "Bookmarks");
3082 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 wbm=gui_internal_button_new_with_callback(this, "Add Bookmark folder",
3117 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 wbm=gui_internal_button_new_with_callback(this, "Paste bookmark",
3123 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 wbm->name=g_strdup_printf("Bookmark %s",label_full);
3156 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
3267 #ifdef XXXXXX1
3268
3269 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
3286 #endif
3287
3288 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 KEY("Т"); KEY("У"); KEY("Ф"); KEY("Х"); KEY("Ц"); KEY("Ч"); KEY("Ш"); KEY("Щ"); KEY("Ъ");
3706 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 wb=gui_internal_menu(this, "Layout");
4008 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 #ifdef PLUGSSS
4031 gui_internal_destroy(this);
4032 #endif
4033 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 char *text=g_strdup_printf("Download %s",wm->name);
4052 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 wb=gui_internal_menu(this, wm->name?wm->name:"Map Download");
4113 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 wma=gui_internal_button_new_with_callback(this, "Download completely", NULL,
4150 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
4553 // -------- DISABLED ------
4554 /*
4555 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 */
4560 }
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 if (! win)
5558 {
5559 return 1;
5560 }
5561
5562 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
5568 this->resize_cb=callback_new_attr_1(callback_cast(gui_internal_resize), attr_resize, this);
5569 callback_add_names(this->resize_cb, "gui_internal_set_graphics", "gui_internal_resize");
5570 graphics_add_callback(gra, this->resize_cb);
5571
5572 this->button_cb=callback_new_attr_1(callback_cast(gui_internal_button), attr_button, this);
5573 callback_add_names(this->button_cb, "gui_internal_set_graphics", "gui_internal_button");
5574 graphics_add_callback(gra, this->button_cb);
5575
5576 this->motion_cb=callback_new_attr_1(callback_cast(gui_internal_motion), attr_motion, this);
5577 callback_add_names(this->motion_cb, "gui_internal_set_graphics", "gui_internal_motion");
5578 graphics_add_callback(gra, this->motion_cb);
5579
5580 this->keypress_cb=callback_new_attr_1(callback_cast(gui_internal_keypress), attr_keypress, this);
5581 callback_add_names(this->keypress_cb, "gui_internal_set_graphics", "gui_internal_keypress");
5582 graphics_add_callback(gra, this->keypress_cb);
5583
5584 this->window_closed_cb=callback_new_attr_1(callback_cast(gui_internal_window_closed), attr_window_closed, this);
5585 callback_add_names(this->window_closed_cb, "gui_internal_set_graphics", "gui_internal_window_closed");
5586 graphics_add_callback(gra, this->window_closed_cb);
5587
5588 // set fullscreen if needed
5589 if (this->fullscreen)
5590 {
5591 this->win->fullscreen(this->win, this->fullscreen != 0);
5592 }
5593 /* Was resize callback already issued? */
5594 if (navit_get_ready(this->nav) & 2)
5595 {
5596 gui_internal_setup_gc(this);
5597 }
5598 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 menu=gui_internal_menu(this, "Show Locale");
6483 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 text=g_strdup(" ");
6540 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 text=g_strdup(" ");
6550 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 text=g_strdup(" ");
6560 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 text=g_strdup("http://zanavi.cc/");
6564 // 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 text=g_strdup("Martin Schaller");
6597 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 struct gui_priv * gui_internal_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs, struct gui *gui)
6831 {
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 this->cbl=callback_list_new("gui_internal_new:this->cbl");
6952
6953 return this;
6954 }
6955
6956 //##############################################################################################################
6957 //# Description:
6958 //# Comment:
6959 //# Authors: Martin Schaller (04/2008)
6960 //##############################################################################################################
6961 #ifdef PLUGSSS
6962 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 #endif
6976

   
Visit the ZANavi Wiki