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