/[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 28 - (show annotations) (download)
Sun Jun 17 08:12:47 2012 UTC (11 years, 9 months ago) by zoff99
File MIME type: text/plain
File size: 199006 byte(s)
lots of new stuff and 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
4471 // -------- DISABLED ------
4472 /*
4473 if(!this->motion_timeout_callback)
4474 this->motion_timeout_callback=callback_new_1(callback_cast(gui_internal_highlight), this);
4475 if(!this->motion_timeout_event)
4476 this->motion_timeout_event=event_add_timeout(100,0, this->motion_timeout_callback);
4477 */
4478 }
4479
4480 static const char *
4481 find_attr(const char **names, const char **values, const char *name)
4482 {
4483 while (*names) {
4484 if (!g_strcasecmp(*names, name))
4485 return *values;
4486 names+=xml_attr_distance;
4487 values+=xml_attr_distance;
4488 }
4489 return NULL;
4490 }
4491
4492 static char *
4493 find_attr_dup(const char **names, const char **values, const char *name)
4494 {
4495 return g_strdup(find_attr(names, values, name));
4496 }
4497
4498 static void
4499 gui_internal_evaluate(struct gui_priv *this, const char *command)
4500 {
4501 if (command)
4502 command_evaluate(&this->self, command);
4503 }
4504
4505
4506 static void
4507 gui_internal_html_command(struct gui_priv *this, struct widget *w, void *data)
4508 {
4509 gui_internal_evaluate(this,w->command);
4510 }
4511
4512 static void
4513 gui_internal_html_submit_set(struct gui_priv *this, struct widget *w, struct form *form)
4514 {
4515 GList *l;
4516 if (w->form == form && w->name) {
4517 struct attr *attr=attr_new_from_text(w->name, w->text?w->text:"");
4518 if (attr)
4519 gui_set_attr(this->self.u.gui, attr);
4520 attr_free(attr);
4521 }
4522 l=w->children;
4523 while (l) {
4524 w=l->data;
4525 gui_internal_html_submit_set(this, w, form);
4526 l=g_list_next(l);
4527 }
4528
4529 }
4530
4531 static void
4532 gui_internal_html_submit(struct gui_priv *this, struct widget *w, void *data)
4533 {
4534 struct widget *menu;
4535 GList *l;
4536
4537 dbg(1,"enter form %p %s\n",w->form,w->form->onsubmit);
4538 l=g_list_last(this->root.children);
4539 menu=l->data;
4540 graphics_draw_mode(this->gra, draw_mode_begin);
4541 gui_internal_highlight_do(this, NULL);
4542 gui_internal_menu_render(this);
4543 graphics_draw_mode(this->gra, draw_mode_end);
4544 gui_internal_html_submit_set(this, menu, w->form);
4545 gui_internal_evaluate(this,w->form->onsubmit);
4546 }
4547
4548 static void
4549 gui_internal_html_load_href(struct gui_priv *this, char *href, int replace)
4550 {
4551 if (replace)
4552 gui_internal_prune_menu_count(this, 1, 0);
4553 if (href && href[0] == '#') {
4554 dbg(1,"href=%s\n",href);
4555 g_free(this->href);
4556 this->href=g_strdup(href);
4557 gui_internal_html_menu(this, this->html_text, href+1);
4558 }
4559 }
4560
4561 static void
4562 gui_internal_html_href(struct gui_priv *this, struct widget *w, void *data)
4563 {
4564 gui_internal_html_load_href(this, w->command, 0);
4565 }
4566
4567 struct div_flags_map {
4568 char *attr;
4569 char *val;
4570 enum flags flags;
4571 } div_flags_map[] = {
4572 {"gravity","none",gravity_none},
4573 {"gravity","left",gravity_left},
4574 {"gravity","xcenter",gravity_xcenter},
4575 {"gravity","right",gravity_right},
4576 {"gravity","top",gravity_top},
4577 {"gravity","ycenter",gravity_ycenter},
4578 {"gravity","bottom",gravity_bottom},
4579 {"gravity","left_top",gravity_left_top},
4580 {"gravity","top_center",gravity_top_center},
4581 {"gravity","right_top",gravity_right_top},
4582 {"gravity","left_center",gravity_left_center},
4583 {"gravity","center",gravity_center},
4584 {"gravity","right_center",gravity_right_center},
4585 {"gravity","left_bottom",gravity_left_bottom},
4586 {"gravity","bottom_center",gravity_bottom_center},
4587 {"gravity","right_bottom",gravity_right_bottom},
4588 {"expand","1",flags_expand},
4589 {"fill","1",flags_fill},
4590 {"orientation","horizontal",orientation_horizontal},
4591 {"orientation","vertical",orientation_vertical},
4592 {"orientation","horizontal_vertical",orientation_horizontal_vertical},
4593 };
4594
4595 static enum flags
4596 div_flag(const char **names, const char **values, char *name)
4597 {
4598 int i;
4599 enum flags ret=0;
4600 const char *value=find_attr(names, values, name);
4601 if (!value)
4602 return ret;
4603 for (i = 0 ; i < sizeof(div_flags_map)/sizeof(struct div_flags_map); i++) {
4604 if (!strcmp(div_flags_map[i].attr,name) && !strcmp(div_flags_map[i].val,value))
4605 ret|=div_flags_map[i].flags;
4606 }
4607 return ret;
4608 }
4609
4610 static enum flags
4611 div_flags(const char **names, const char **values)
4612 {
4613 enum flags flags;
4614 flags = div_flag(names, values, "gravity");
4615 flags |= div_flag(names, values, "orientation");
4616 flags |= div_flag(names, values, "expand");
4617 flags |= div_flag(names, values, "fill");
4618 return flags;
4619 }
4620
4621 static struct widget *
4622 html_image(struct gui_priv *this, const char **names, const char **values)
4623 {
4624 const char *src, *size;
4625 struct graphics_image *img=NULL;
4626
4627 src=find_attr(names, values, "src");
4628 if (!src)
4629 return NULL;
4630 size=find_attr(names, values, "size");
4631 if (!size)
4632 size="l";
4633 if (!strcmp(size,"l"))
4634 img=image_new_l(this, src);
4635 else if (!strcmp(size,"s"))
4636 img=image_new_s(this, src);
4637 else if (!strcmp(size,"xs"))
4638 img=image_new_xs(this, src);
4639 if (!img)
4640 return NULL;
4641 return gui_internal_image_new(this, img);
4642 }
4643
4644 static void
4645 gui_internal_html_start(void *dummy, const char *tag_name, const char **names, const char **values, void *data, void *error)
4646 {
4647 struct gui_priv *this=data;
4648 int i;
4649 enum html_tag tag=html_tag_none;
4650 struct html *html=&this->html[this->html_depth];
4651 const char *cond, *type;
4652
4653 if (!g_strcasecmp(tag_name,"text"))
4654 return;
4655 html->command=NULL;
4656 html->name=NULL;
4657 html->href=NULL;
4658 html->skip=0;
4659 cond=find_attr(names, values, "cond");
4660
4661 if (cond && !this->html_skip) {
4662 if (!command_evaluate_to_boolean(&this->self, cond, NULL))
4663 html->skip=1;
4664 }
4665
4666 for (i=0 ; i < sizeof(html_tag_map)/sizeof(struct html_tag_map); i++) {
4667 if (!g_strcasecmp(html_tag_map[i].tag_name, tag_name)) {
4668 tag=html_tag_map[i].tag;
4669 break;
4670 }
4671 }
4672 html->tag=tag;
4673 if (!this->html_skip && !html->skip) {
4674 switch (tag) {
4675 case html_tag_a:
4676 html->name=find_attr_dup(names, values, "name");
4677 if (html->name) {
4678 html->skip=this->html_anchor ? strcmp(html->name,this->html_anchor) : 0;
4679 if (!html->skip)
4680 this->html_anchor_found=1;
4681 }
4682 html->command=find_attr_dup(names, values, "onclick");
4683 html->href=find_attr_dup(names, values, "href");
4684 html->refresh_cond=find_attr_dup(names, values, "refresh_cond");
4685 break;
4686 case html_tag_img:
4687 html->command=find_attr_dup(names, values, "onclick");
4688 html->w=html_image(this, names, values);
4689 break;
4690 case html_tag_form:
4691 this->form=g_new0(struct form, 1);
4692 this->form->onsubmit=find_attr_dup(names, values, "onsubmit");
4693 break;
4694 case html_tag_input:
4695 type=find_attr_dup(names, values, "type");
4696 if (!type)
4697 break;
4698 if (!strcmp(type,"image")) {
4699 html->w=html_image(this, names, values);
4700 if (html->w) {
4701 html->w->state|=STATE_SENSITIVE;
4702 html->w->func=gui_internal_html_submit;
4703 }
4704 }
4705 if (!strcmp(type,"text") || !strcmp(type,"password")) {
4706 html->w=gui_internal_label_new(this, NULL);
4707 html->w->background=this->background;
4708 html->w->flags |= div_flags(names, values);
4709 html->w->state|=STATE_EDITABLE;
4710 if (!this->editable) {
4711 this->editable=html->w;
4712 html->w->state|=STATE_EDIT;
4713 }
4714 this->keyboard_required=1;
4715 if (!strcmp(type,"password"))
4716 html->w->flags2 |= 1;
4717 }
4718 if (html->w) {
4719 html->w->form=this->form;
4720 html->w->name=find_attr_dup(names, values, "name");
4721 }
4722 break;
4723 case html_tag_div:
4724 html->w=gui_internal_box_new(this, div_flags(names, values));
4725 html->container=this->html_container;
4726 this->html_container=html->w;
4727 break;
4728 default:
4729 break;
4730 }
4731 }
4732 this->html_skip+=html->skip;
4733 this->html_depth++;
4734 }
4735
4736 static void
4737 gui_internal_html_end(void *dummy, const char *tag_name, void *data, void *error)
4738 {
4739 struct gui_priv *this=data;
4740 struct html *html;
4741 struct html *parent=NULL;
4742
4743 if (!g_strcasecmp(tag_name,"text"))
4744 return;
4745 this->html_depth--;
4746 html=&this->html[this->html_depth];
4747 if (this->html_depth > 0)
4748 parent=&this->html[this->html_depth-1];
4749
4750
4751 if (!this->html_skip) {
4752 if (html->command && html->w) {
4753 html->w->state |= STATE_SENSITIVE;
4754 html->w->command=html->command;
4755 html->w->func=gui_internal_html_command;
4756 html->command=NULL;
4757 }
4758 if (parent && (parent->href || parent->command) && html->w) {
4759 html->w->state |= STATE_SENSITIVE;
4760 if (parent->command) {
4761 html->w->command=g_strdup(parent->command);
4762 html->w->func=gui_internal_html_command;
4763 } else {
4764 html->w->command=g_strdup(parent->href);
4765 html->w->func=gui_internal_html_href;
4766 }
4767 }
4768 switch (html->tag) {
4769 case html_tag_div:
4770 this->html_container=html->container;
4771 case html_tag_img:
4772 case html_tag_input:
4773 gui_internal_widget_append(this->html_container, html->w);
4774 break;
4775 case html_tag_form:
4776 this->form=NULL;
4777 break;
4778 default:
4779 break;
4780 }
4781 }
4782 this->html_skip-=html->skip;
4783 g_free(html->command);
4784 g_free(html->name);
4785 g_free(html->href);
4786 g_free(html->refresh_cond);
4787 }
4788
4789 static void
4790 gui_internal_refresh_callback_called(struct gui_priv *this, struct menu_data *menu_data)
4791 {
4792 if (gui_internal_menu_data(this) == menu_data) {
4793 char *href=g_strdup(menu_data->href);
4794 gui_internal_html_load_href(this, href, 1);
4795 g_free(href);
4796 }
4797 }
4798
4799 static void
4800 gui_internal_set_refresh_callback(struct gui_priv *this, char *cond)
4801 {
4802 dbg(0,"cond=%s\n",cond);
4803 if (cond) {
4804 enum attr_type type;
4805 struct object_func *func;
4806 struct menu_data *menu_data=gui_internal_menu_data(this);
4807 dbg(0,"navit=%p\n",this->nav);
4808 type=command_evaluate_to_attr(&this->self, cond, NULL, &menu_data->refresh_callback_obj);
4809 if (type == attr_none)
4810 return;
4811 func=object_func_lookup(menu_data->refresh_callback_obj.type);
4812 if (!func || !func->add_attr)
4813 return;
4814 menu_data->refresh_callback.type=attr_callback;
4815 menu_data->refresh_callback.u.callback=callback_new_attr_2(callback_cast(gui_internal_refresh_callback_called),type,this,menu_data);
4816 func->add_attr(menu_data->refresh_callback_obj.u.data, &menu_data->refresh_callback);
4817 }
4818 }
4819
4820 static void
4821 gui_internal_html_text(void *dummy, const char *text, int len, void *data, void *error)
4822 {
4823 struct gui_priv *this=data;
4824 struct widget *w;
4825 int depth=this->html_depth-1;
4826 struct html *html=&this->html[depth];
4827 gchar *text_stripped;
4828
4829 if (this->html_skip)
4830 return;
4831 while (isspace(text[0])) {
4832 text++;
4833 len--;
4834 }
4835 while (len > 0 && isspace(text[len-1]))
4836 len--;
4837
4838 text_stripped = g_strndup(text, len);
4839 if (html->tag == html_tag_html && depth > 2) {
4840 if (this->html[depth-1].tag == html_tag_script) {
4841 html=&this->html[depth-2];
4842 }
4843 }
4844 switch (html->tag) {
4845 case html_tag_a:
4846 if (html->name && len) {
4847 this->html_container=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
4848 gui_internal_widget_append(gui_internal_menu(this, gettext(text_stripped)), this->html_container);
4849 gui_internal_menu_data(this)->href=g_strdup(this->href);
4850 gui_internal_set_refresh_callback(this, html->refresh_cond);
4851 this->html_container->spx=this->spacing*10;
4852 }
4853 break;
4854 case html_tag_h1:
4855 if (!this->html_container) {
4856 this->html_container=gui_internal_box_new(this, gravity_center|orientation_horizontal_vertical|flags_expand|flags_fill);
4857 gui_internal_widget_append(gui_internal_menu(this, gettext(text_stripped)), this->html_container);
4858 this->html_container->spx=this->spacing*10;
4859 }
4860 break;
4861 case html_tag_img:
4862 if (len) {
4863 w=gui_internal_box_new(this, gravity_center|orientation_vertical);
4864 gui_internal_widget_append(w, html->w);
4865 gui_internal_widget_append(w, gui_internal_text_new(this, gettext(text_stripped), gravity_center|orientation_vertical));
4866 html->w=w;
4867 }
4868 break;
4869 case html_tag_div:
4870 if (len) {
4871 gui_internal_widget_append(html->w, gui_internal_text_new(this, gettext(text_stripped), gravity_center|orientation_vertical));
4872 }
4873 break;
4874 case html_tag_script:
4875 dbg(1,"execute %s\n",text_stripped);
4876 gui_internal_evaluate(this,text_stripped);
4877 break;
4878 default:
4879 break;
4880 }
4881 g_free(text_stripped);
4882 }
4883
4884 static void
4885 gui_internal_html_menu(struct gui_priv *this, const char *document, char *anchor)
4886 {
4887 char *doc=g_strdup(document);
4888 graphics_draw_mode(this->gra, draw_mode_begin);
4889 this->html_container=NULL;
4890 this->html_depth=0;
4891 this->html_anchor=anchor;
4892 this->html_anchor_found=0;
4893 this->form=NULL;
4894 this->keyboard_required=0;
4895 this->editable=NULL;
4896 callback_list_call_attr_2(this->cbl,attr_gui,anchor,&doc);
4897 xml_parse_text(doc, this, gui_internal_html_start, gui_internal_html_end, gui_internal_html_text);
4898 g_free(doc);
4899 if (this->keyboard_required && this->keyboard) {
4900 this->html_container->flags=gravity_center|orientation_vertical|flags_expand|flags_fill;
4901 gui_internal_widget_append(this->html_container, gui_internal_keyboard(this,2));
4902 }
4903 gui_internal_menu_render(this);
4904 graphics_draw_mode(this->gra, draw_mode_end);
4905 }
4906
4907
4908 static void
4909 gui_internal_enter(struct gui_priv *this, int ignore)
4910 {
4911 struct graphics *gra=this->gra;
4912 this->ignore_button=ignore;
4913 this->clickp_valid=this->vehicle_valid=0;
4914
4915 navit_block(this->nav, 1);
4916 graphics_overlay_disable(gra, 1);
4917 this->root.p.x=0;
4918 this->root.p.y=0;
4919 this->root.background=this->background;
4920 }
4921
4922 static void
4923 gui_internal_leave(struct gui_priv *this)
4924 {
4925 graphics_draw_mode(this->gra, draw_mode_end);
4926 }
4927
4928 static void
4929 gui_internal_enter_setup(struct gui_priv *this, struct point *p)
4930 {
4931 struct transformation *trans;
4932 struct coord c;
4933 struct coord_geo g;
4934 struct attr attr,attrp;
4935
4936 trans=navit_get_trans(this->nav);
4937 attr_free(this->click_coord_geo);
4938 this->click_coord_geo=NULL;
4939 attr_free(this->position_coord_geo);
4940 this->position_coord_geo=NULL;
4941 if (p) {
4942 transform_reverse(trans, p, &c);
4943 dbg(1,"x=0x%x y=0x%x\n", c.x, c.y);
4944 this->clickp.pro=transform_get_projection(trans);
4945 this->clickp.x=c.x;
4946 this->clickp.y=c.y;
4947 transform_to_geo(this->clickp.pro, &c, &g);
4948 attr.u.coord_geo=&g;
4949 attr.type=attr_click_coord_geo;
4950 this->click_coord_geo=attr_dup(&attr);
4951 }
4952 if (navit_get_attr(this->nav, attr_vehicle, &attr, NULL) && attr.u.vehicle
4953 && vehicle_get_attr(attr.u.vehicle, attr_position_coord_geo, &attrp, NULL)) {
4954 this->position_coord_geo=attr_dup(&attrp);
4955 this->vehiclep.pro=transform_get_projection(trans);
4956 transform_from_geo(this->vehiclep.pro, attrp.u.coord_geo, &c);
4957 this->vehiclep.x=c.x;
4958 this->vehiclep.y=c.y;
4959 this->vehicle_valid=1;
4960 }
4961 }
4962
4963 static void
4964 gui_internal_cmd_menu(struct gui_priv *this, struct point *p, int ignore, char *href)
4965 {
4966 dbg(1,"enter\n");
4967 gui_internal_enter(this, ignore);
4968 gui_internal_enter_setup(this, p);
4969 // draw menu
4970 gui_internal_html_load_href(this, href?href:"#Main Menu", 0);
4971 }
4972
4973 static void
4974 gui_internal_cmd_menu2(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
4975 {
4976 char *href=NULL;
4977 int replace=0;
4978 if (in && in[0] && ATTR_IS_STRING(in[0]->type)) {
4979 href=in[0]->u.str;
4980 if (in[1] && ATTR_IS_INT(in[1]->type))
4981 replace=in[1]->u.num;
4982 }
4983 if (this->root.children) {
4984 if (!href)
4985 return;
4986 gui_internal_html_load_href(this, href, replace);
4987 return;
4988 }
4989 gui_internal_cmd_menu(this, NULL, 0, href);
4990 }
4991
4992
4993 static void
4994 gui_internal_cmd_log_do(struct gui_priv *this, struct widget *widget)
4995 {
4996 if (widget->text && strlen(widget->text)) {
4997 if (this->vehicle_valid)
4998 navit_textfile_debug_log_at(this->nav, &this->vehiclep, "type=log_entry label=\"%s\"",widget->text);
4999 else
5000 navit_textfile_debug_log(this->nav, "type=log_entry label=\"%s\"",widget->text);
5001 }
5002 g_free(widget->text);
5003 widget->text=NULL;
5004 gui_internal_prune_menu(this, NULL);
5005 gui_internal_check_exit(this);
5006 }
5007
5008 static void
5009 gui_internal_cmd_log_clicked(struct gui_priv *this, struct widget *widget, void *data)
5010 {
5011 gui_internal_cmd_log_do(this, widget->data);
5012 }
5013
5014 static void
5015 gui_internal_cmd_log_changed(struct gui_priv *this, struct widget *wm, void *data)
5016 {
5017 int len;
5018 if (wm->text) {
5019 len=strlen(wm->text);
5020 if (len && (wm->text[len-1] == '\n' || wm->text[len-1] == '\r')) {
5021 wm->text[len-1]='\0';
5022 gui_internal_cmd_log_do(this, wm);
5023 }
5024 }
5025 }
5026
5027
5028 static void
5029 gui_internal_cmd_log(struct gui_priv *this)
5030 {
5031 struct widget *w,*wb,*wk,*wl,*we,*wnext;
5032 gui_internal_enter(this, 1);
5033 gui_internal_enter_setup(this, NULL);
5034 wb=gui_internal_menu(this, "Log Message");
5035 w=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
5036 gui_internal_widget_append(wb, w);
5037 we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
5038 gui_internal_widget_append(w, we);
5039 gui_internal_widget_append(we, wk=gui_internal_label_new(this, _("Message")));
5040 wk->state |= STATE_EDIT|STATE_EDITABLE|STATE_CLEAR;
5041 wk->background=this->background;
5042 wk->flags |= flags_expand|flags_fill;
5043 wk->func = gui_internal_cmd_log_changed;
5044 gui_internal_widget_append(we, wnext=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
5045 wnext->state |= STATE_SENSITIVE;
5046 wnext->func = gui_internal_cmd_log_clicked;
5047 wnext->data=wk;
5048 wl=gui_internal_box_new(this, gravity_left_top|orientation_vertical|flags_expand|flags_fill);
5049 gui_internal_widget_append(w, wl);
5050 if (this->keyboard)
5051 gui_internal_widget_append(w, gui_internal_keyboard(this,2));
5052 gui_internal_menu_render(this);
5053 gui_internal_leave(this);
5054 }
5055
5056 static void
5057 gui_internal_check_exit(struct gui_priv *this)
5058 {
5059 struct graphics *gra=this->gra;
5060 if (! this->root.children) {
5061 gui_internal_search_idle_end(this);
5062 gui_internal_search_list_destroy(this);
5063 graphics_overlay_disable(gra, 0);
5064 if (!navit_block(this->nav, 0)) {
5065 if (this->redraw)
5066 navit_draw(this->nav);
5067 else
5068 navit_draw_displaylist(this->nav);
5069 }
5070 }
5071 }
5072
5073 static int
5074 gui_internal_get_attr(struct gui_priv *this, enum attr_type type, struct attr *attr)
5075 {
5076 switch (type) {
5077 case attr_active:
5078 attr->u.num=this->root.children != NULL;
5079 break;
5080 case attr_click_coord_geo:
5081 if (!this->click_coord_geo)
5082 return 0;
5083 *attr=*this->click_coord_geo;
5084 break;
5085 case attr_position_coord_geo:
5086 if (!this->position_coord_geo)
5087 return 0;
5088 *attr=*this->position_coord_geo;
5089 break;
5090 case attr_pitch:
5091 attr->u.num=this->pitch;
5092 break;
5093 default:
5094 return 0;
5095 }
5096 attr->type=type;
5097 return 1;
5098 }
5099
5100 static int
5101 gui_internal_add_attr(struct gui_priv *this, struct attr *attr)
5102 {
5103 switch (attr->type) {
5104 case attr_xml_text:
5105 g_free(this->html_text);
5106 this->html_text=g_strdup(attr->u.str);
5107 return 1;
5108 default:
5109 return 0;
5110 }
5111 }
5112
5113 static int
5114 gui_internal_set_attr(struct gui_priv *this, struct attr *attr)
5115 {
5116 switch (attr->type) {
5117 case attr_fullscreen:
5118 if ((this->fullscreen > 0) != (attr->u.num > 0)) {
5119 graphics_draw_mode(this->gra, draw_mode_end);
5120 this->win->fullscreen(this->win, attr->u.num > 0);
5121 graphics_draw_mode(this->gra, draw_mode_begin);
5122 }
5123 this->fullscreen=attr->u.num;
5124 return 1;
5125 case attr_menu_on_map_click:
5126 this->menu_on_map_click=attr->u.num;
5127 return 1;
5128 default:
5129 dbg(0,"%s\n",attr_to_name(attr->type));
5130 return 1;
5131 }
5132 }
5133
5134 static void gui_internal_dbus_signal(struct gui_priv *this, struct point *p)
5135 {
5136 struct displaylist_handle *dlh;
5137 struct displaylist *display;
5138 struct displayitem *di;
5139 struct attr cb,**attr_list=NULL;
5140 int valid=0;
5141
5142 display=navit_get_displaylist(this->nav);
5143 dlh=graphics_displaylist_open(display);
5144 while ((di=graphics_displaylist_next(dlh))) {
5145 struct item *item=graphics_displayitem_get_item(di);
5146 if (item_is_point(*item) && graphics_displayitem_get_displayed(di) &&
5147 graphics_displayitem_within_dist(display, di, p, this->radius)) {
5148 struct map_rect *mr=map_rect_new(item->map, NULL);
5149 struct item *itemo=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
5150 struct attr attr;
5151 if (itemo && item_attr_get(itemo, attr_data, &attr))
5152 attr_list=attr_generic_add_attr(attr_list, &attr);
5153 map_rect_destroy(mr);
5154 }
5155 }
5156 graphics_displaylist_close(dlh);
5157 if (attr_list && navit_get_attr(this->nav, attr_callback_list, &cb, NULL))
5158 callback_list_call_attr_4(cb.u.callback_list, attr_command, "dbus_send_signal", attr_list, NULL, &valid);
5159 attr_list_free(attr_list);
5160 }
5161
5162 // static int allow_gui_internal;
5163
5164 //##############################################################################################################
5165 //# Description: Function to handle mouse clicks and scroll wheel movement
5166 //# Comment:
5167 //# Authors: Martin Schaller (04/2008), Stefan Klumpp (04/2008)
5168 //##############################################################################################################
5169 static void gui_internal_button(void *data, int pressed, int button, struct point *p)
5170 {
5171 struct gui_priv *this=data;
5172 struct graphics *gra=this->gra;
5173
5174 //dbg(0,"enter @@@@@@@@@@@@@@@@@@@@ %d %d\n", pressed, button);
5175 // if still on the map (not in the menu, yet):
5176 //dbg(0,"children=%p ignore_button=%d\n",this->root.children,this->ignore_button);
5177 if (!this->root.children || this->ignore_button)
5178 {
5179
5180 this->ignore_button=0;
5181 // check whether the position of the mouse changed during press/release OR if it is the scrollwheel
5182 if (!navit_handle_button(this->nav, pressed, button, p, NULL))
5183 {
5184 //dbg(0,"navit has handled button\n");
5185 return;
5186 }
5187 //dbg(0,"menu_on_map_click=%d\n",this->menu_on_map_click);
5188 if (button != 1)
5189 return;
5190 if (this->menu_on_map_click)
5191 {
5192 if (allow_gui_internal == 1)
5193 {
5194 //dbg(0,"@@@@@@@ enter GUI internal!!\n");
5195 gui_internal_cmd_menu(this, p, 0, NULL);
5196 }
5197 else
5198 {
5199 //dbg(0,"+++++++ GUI internal DISABLED!!\n");
5200 }
5201 return;
5202 }
5203 if (this->signal_on_map_click)
5204 {
5205 gui_internal_dbus_signal(this, p);
5206 return;
5207 }
5208 return;
5209 }
5210
5211
5212 // if already in the menu:
5213 if (pressed) {
5214 this->pressed=1;
5215 this->current=*p;
5216 gui_internal_highlight(this);
5217 } else {
5218 this->pressed=0;
5219 this->current.x=-1;
5220 this->current.y=-1;
5221 graphics_draw_mode(gra, draw_mode_begin);
5222 gui_internal_call_highlighted(this);
5223 if (!event_main_loop_has_quit()) {
5224 gui_internal_highlight(this);
5225 graphics_draw_mode(gra, draw_mode_end);
5226 gui_internal_check_exit(this);
5227 }
5228 }
5229 }
5230
5231 static void
5232 gui_internal_setup_gc(struct gui_priv *this)
5233 {
5234 struct color cbh={0x9fff,0x9fff,0x9fff,0xffff};
5235 struct color cf={0xbfff,0xbfff,0xbfff,0xffff};
5236 struct graphics *gra=this->gra;
5237
5238 if (this->background)
5239 return;
5240 this->background=graphics_gc_new(gra);
5241 this->background2=graphics_gc_new(gra);
5242 this->highlight_background=graphics_gc_new(gra);
5243 graphics_gc_set_foreground(this->highlight_background, &cbh);
5244 this->foreground=graphics_gc_new(gra);
5245 graphics_gc_set_foreground(this->foreground, &cf);
5246 this->text_background=graphics_gc_new(gra);
5247 this->text_foreground=graphics_gc_new(gra);
5248 graphics_gc_set_foreground(this->background, &this->background_color);
5249 graphics_gc_set_foreground(this->background2, &this->background2_color);
5250 graphics_gc_set_foreground(this->text_background, &this->text_background_color);
5251 graphics_gc_set_foreground(this->text_foreground, &this->text_foreground_color);
5252 }
5253
5254 //##############################################################################################################
5255 //# Description:
5256 //# Comment:
5257 //# Authors: Martin Schaller (04/2008)
5258 //##############################################################################################################
5259 static void gui_internal_resize(void *data, int w, int h)
5260 {
5261 struct gui_priv *this=data;
5262 int changed=0;
5263
5264 gui_internal_setup_gc(this);
5265
5266 if (this->root.w != w || this->root.h != h) {
5267 this->root.w=w;
5268 this->root.h=h;
5269 changed=1;
5270 }
5271 dbg(1,"w=%d h=%d children=%p\n", w, h, this->root.children);
5272 navit_handle_resize(this->nav, w, h);
5273 if (this->root.children) {
5274 if (changed) {
5275 gui_internal_prune_menu(this, NULL);
5276 gui_internal_html_load_href(this, "#Main Menu", 0);
5277 } else {
5278 gui_internal_menu_render(this);
5279 }
5280 }
5281 }
5282
5283 static void
5284 gui_internal_keynav_point(struct widget *w, int dx, int dy, struct point *p)
5285 {
5286 p->x=w->p.x+w->w/2;
5287 p->y=w->p.y+w->h/2;
5288 if (dx < 0)
5289 p->x=w->p.x;
5290 if (dx > 0)
5291 p->x=w->p.x+w->w;
5292 if (dy < 0)
5293 p->y=w->p.y;
5294 if (dy > 0)
5295 p->y=w->p.y+w->h;
5296 }
5297
5298 static void
5299 gui_internal_keynav_find_closest(struct widget *wi, struct point *p, int dx, int dy, int *distance, struct widget **result)
5300 {
5301 GList *l=wi->children;
5302 // Skip hidden elements
5303 if (wi->p.x==0 && wi->p.y==0 && wi->w==0 && wi->h==0)
5304 return;
5305 if ((wi->state & STATE_SENSITIVE) ) {
5306 int dist1,dist2;
5307 struct point wp;
5308 gui_internal_keynav_point(wi, -dx, -dy, &wp);
5309 if (dx) {
5310 dist1=(wp.x-p->x)*dx;
5311 dist2=wp.y-p->y;
5312 } else if (dy) {
5313 dist1=(wp.y-p->y)*dy;
5314 dist2=wp.x-p->x;
5315 } else {
5316 dist2=wp.x-p->x;
5317 dist1=wp.y-p->y;
5318 if (dist1 < 0)
5319 dist1=-dist1;
5320 }
5321 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);
5322 if (dist1 >= 0) {
5323 if (dist2 < 0)
5324 dist1-=dist2;
5325 else
5326 dist1+=dist2;
5327 if (dist1 < *distance) {
5328 *result=wi;
5329 *distance=dist1;
5330 }
5331 }
5332 }
5333 while (l) {
5334 struct widget *child=l->data;
5335 gui_internal_keynav_find_closest(child, p, dx, dy, distance, result);
5336 l=g_list_next(l);
5337 }
5338 }
5339
5340 static void
5341 gui_internal_keynav_highlight_next(struct gui_priv *this, int dx, int dy)
5342 {
5343 struct widget *result,*menu=g_list_last(this->root.children)->data;
5344 struct point p;
5345 int distance;
5346 if (this->highlighted && this->highlighted_menu == g_list_last(this->root.children)->data)
5347 gui_internal_keynav_point(this->highlighted, dx, dy, &p);
5348 else {
5349 p.x=0;
5350 p.y=0;
5351 distance=INT_MAX;
5352 result=NULL;
5353 gui_internal_keynav_find_closest(menu, &p, 0, 0, &distance, &result);
5354 if (result) {
5355 gui_internal_keynav_point(result, dx, dy, &p);
5356 dbg(1,"result origin=%p p=%d,%d\n", result, p.x, p.y);
5357 }
5358 }
5359 result=NULL;
5360 distance=INT_MAX;
5361 gui_internal_keynav_find_closest(menu, &p, dx, dy, &distance, &result);
5362 dbg(1,"result=%p\n", result);
5363 if (! result) {
5364 if (dx < 0)
5365 p.x=this->root.w;
5366 if (dx > 0)
5367 p.x=0;
5368 if (dy < 0)
5369 p.y=this->root.h;
5370 if (dy > 0)
5371 p.y=0;
5372 result=NULL;
5373 distance=INT_MAX;
5374 gui_internal_keynav_find_closest(menu, &p, dx, dy, &distance, &result);
5375 dbg(1,"wraparound result=%p\n", result);
5376 }
5377 gui_internal_highlight_do(this, result);
5378 if (result)
5379 gui_internal_say(this, result, 1);
5380 }
5381
5382 //##############################################################################################################
5383 //# Description:
5384 //# Comment:
5385 //# Authors: Martin Schaller (04/2008)
5386 //##############################################################################################################
5387 static void gui_internal_keypress(void *data, char *key)
5388 {
5389 struct gui_priv *this=data;
5390 int w,h;
5391 struct point p;
5392 if (!this->root.children) {
5393 transform_get_size(navit_get_trans(this->nav), &w, &h);
5394 switch (*key) {
5395 case NAVIT_KEY_UP:
5396 p.x=w/2;
5397 p.y=0;
5398 navit_set_center_screen(this->nav, &p, 1);
5399 break;
5400 case NAVIT_KEY_DOWN:
5401 p.x=w/2;
5402 p.y=h;
5403 navit_set_center_screen(this->nav, &p, 1);
5404 break;
5405 case NAVIT_KEY_LEFT:
5406 p.x=0;
5407 p.y=h/2;
5408 navit_set_center_screen(this->nav, &p, 1);
5409 break;
5410 case NAVIT_KEY_RIGHT:
5411 p.x=w;
5412 p.y=h/2;
5413 navit_set_center_screen(this->nav, &p, 1);
5414 break;
5415 case NAVIT_KEY_ZOOM_IN:
5416 navit_zoom_in(this->nav, 2, NULL);
5417 break;
5418 case NAVIT_KEY_ZOOM_OUT:
5419 navit_zoom_out(this->nav, 2, NULL);
5420 break;
5421 case NAVIT_KEY_RETURN:
5422 case NAVIT_KEY_MENU:
5423 gui_internal_cmd_menu(this, NULL, 0, NULL);
5424 break;
5425 }
5426 return;
5427 }
5428 graphics_draw_mode(this->gra, draw_mode_begin);
5429 switch (*key) {
5430 case NAVIT_KEY_LEFT:
5431 gui_internal_keynav_highlight_next(this,-1,0);
5432 break;
5433 case NAVIT_KEY_RIGHT:
5434 gui_internal_keynav_highlight_next(this,1,0);
5435 break;
5436 case NAVIT_KEY_UP:
5437 gui_internal_keynav_highlight_next(this,0,-1);
5438 break;
5439 case NAVIT_KEY_DOWN:
5440 gui_internal_keynav_highlight_next(this,0,1);
5441 break;
5442 case NAVIT_KEY_BACK:
5443 if (g_list_length(this->root.children) > 1)
5444 gui_internal_back(this, NULL, NULL);
5445 else
5446 gui_internal_prune_menu(this, NULL);
5447 break;
5448 case NAVIT_KEY_RETURN:
5449 if (this->highlighted && this->highlighted_menu == g_list_last(this->root.children)->data)
5450 gui_internal_call_highlighted(this);
5451 else
5452 gui_internal_keypress_do(this, key);
5453 break;
5454 default:
5455 gui_internal_keypress_do(this, key);
5456 }
5457 if (!event_main_loop_has_quit()) {
5458 graphics_draw_mode(this->gra, draw_mode_end);
5459 gui_internal_check_exit(this);
5460 }
5461 }
5462
5463
5464 //##############################################################################################################
5465 //# Description:
5466 //# Comment:
5467 //# Authors: Martin Schaller (04/2008)
5468 //##############################################################################################################
5469 static int gui_internal_set_graphics(struct gui_priv *this, struct graphics *gra)
5470 {
5471 struct window *win;
5472 struct transformation *trans=navit_get_trans(this->nav);
5473
5474 win=graphics_get_data(gra, "window");
5475 if (! win)
5476 return 1;
5477 navit_ignore_graphics_events(this->nav, 1);
5478 this->gra=gra;
5479 this->win=win;
5480 navit_ignore_graphics_events(this->nav, 1);
5481 transform_get_size(trans, &this->root.w, &this->root.h);
5482 this->resize_cb=callback_new_attr_1(callback_cast(gui_internal_resize), attr_resize, this);
5483 graphics_add_callback(gra, this->resize_cb);
5484 this->button_cb=callback_new_attr_1(callback_cast(gui_internal_button), attr_button, this);
5485 graphics_add_callback(gra, this->button_cb);
5486 this->motion_cb=callback_new_attr_1(callback_cast(gui_internal_motion), attr_motion, this);
5487 graphics_add_callback(gra, this->motion_cb);
5488 this->keypress_cb=callback_new_attr_1(callback_cast(gui_internal_keypress), attr_keypress, this);
5489 graphics_add_callback(gra, this->keypress_cb);
5490 this->window_closed_cb=callback_new_attr_1(callback_cast(gui_internal_window_closed), attr_window_closed, this);
5491 graphics_add_callback(gra, this->window_closed_cb);
5492
5493 // set fullscreen if needed
5494 if (this->fullscreen)
5495 this->win->fullscreen(this->win, this->fullscreen != 0);
5496 /* Was resize callback already issued? */
5497 if (navit_get_ready(this->nav) & 2)
5498 gui_internal_setup_gc(this);
5499 return 0;
5500 }
5501
5502 static void gui_internal_disable_suspend(struct gui_priv *this)
5503 {
5504 if (this->win->disable_suspend)
5505 this->win->disable_suspend(this->win);
5506 }
5507
5508 //##############################################################################################################
5509 //# Description:
5510 //# Comment:
5511 //# Authors: Martin Schaller (04/2008)
5512 //##############################################################################################################
5513 struct gui_methods gui_internal_methods = {
5514 NULL,
5515 NULL,
5516 gui_internal_set_graphics,
5517 NULL,
5518 NULL,
5519 NULL,
5520 gui_internal_disable_suspend,
5521 gui_internal_get_attr,
5522 gui_internal_add_attr,
5523 gui_internal_set_attr,
5524 };
5525
5526 static void
5527 gui_internal_get_data(struct gui_priv *priv, char *command, struct attr **in, struct attr ***out)
5528 {
5529 struct attr private_data = { attr_private_data, {(void *)&priv->data}};
5530 if (out)
5531 *out=attr_generic_add_attr(*out, &private_data);
5532 }
5533
5534 static void
5535 gui_internal_add_callback(struct gui_priv *priv, struct callback *cb)
5536 {
5537 callback_list_add(priv->cbl, cb);
5538 }
5539
5540 static void
5541 gui_internal_remove_callback(struct gui_priv *priv, struct callback *cb)
5542 {
5543 callback_list_remove(priv->cbl, cb);
5544 }
5545
5546
5547 static struct gui_internal_methods gui_internal_methods_ext = {
5548 gui_internal_add_callback,
5549 gui_internal_remove_callback,
5550 gui_internal_menu_render,
5551 image_new_xs,
5552 image_new_l,
5553 };
5554
5555
5556 static enum flags
5557 gui_internal_get_flags(struct widget *widget)
5558 {
5559 return widget->flags;
5560 }
5561
5562 static void
5563 gui_internal_set_flags(struct widget *widget, enum flags flags)
5564 {
5565 widget->flags=flags;
5566 }
5567
5568 static int
5569 gui_internal_get_state(struct widget *widget)
5570 {
5571 return widget->state;
5572 }
5573
5574 static void
5575 gui_internal_set_state(struct widget *widget, int state)
5576 {
5577 widget->state=state;
5578 }
5579
5580 static void
5581 gui_internal_set_func(struct widget *widget, void (*func)(struct gui_priv *priv, struct widget *widget, void *data))
5582 {
5583 widget->func=func;
5584 }
5585
5586 static void
5587 gui_internal_set_data(struct widget *widget, void *data)
5588 {
5589 widget->data=data;
5590 }
5591
5592 static void
5593 gui_internal_set_default_background(struct gui_priv *this, struct widget *widget)
5594 {
5595 widget->background=this->background;
5596 }
5597
5598 static struct gui_internal_widget_methods gui_internal_widget_methods = {
5599 gui_internal_widget_append,
5600 gui_internal_button_new,
5601 gui_internal_button_new_with_callback,
5602 gui_internal_box_new,
5603 gui_internal_label_new,
5604 gui_internal_image_new,
5605 gui_internal_keyboard,
5606 gui_internal_menu,
5607 gui_internal_get_flags,
5608 gui_internal_set_flags,
5609 gui_internal_get_state,
5610 gui_internal_set_state,
5611 gui_internal_set_func,
5612 gui_internal_set_data,
5613 gui_internal_set_default_background,
5614 };
5615
5616 static void
5617 gui_internal_cmd_write(struct gui_priv * this, char *function, struct attr **in, struct attr ***out, int *valid)
5618 {
5619 char *str=NULL,*str2=NULL;
5620 dbg(1,"enter %s %p %p %p\n",function,in,out,valid);
5621 if (!in || !in[0])
5622 return;
5623 dbg(1,"%s\n",attr_to_name(in[0]->type));
5624 if (ATTR_IS_STRING(in[0]->type)) {
5625 str=in[0]->u.str;
5626 }
5627 if (ATTR_IS_COORD_GEO(in[0]->type)) {
5628 str=str2=coordinates_geo(in[0]->u.coord_geo, '\n');
5629 }
5630 if (str) {
5631 str=g_strdup_printf("<html>%s</html>\n",str);
5632 xml_parse_text(str, this, gui_internal_html_start, gui_internal_html_end, gui_internal_html_text);
5633 }
5634 g_free(str);
5635 g_free(str2);
5636 }
5637
5638
5639 /**
5640 * @brief Creates a new table widget.
5641 *
5642 * Creates and returns a new table widget. This function will
5643 * setup next/previous buttons as children.
5644 *
5645 * @param this The graphics context.
5646 * @param flags widget sizing flags.
5647 * @returns The newly created widget
5648 */
5649 struct widget * gui_internal_widget_table_new(struct gui_priv * this, enum flags flags, int buttons)
5650 {
5651 struct widget * widget = g_new0(struct widget,1);
5652 struct table_data * data = NULL;
5653 widget->type=widget_table;
5654 widget->flags=flags;
5655 widget->data = g_new0(struct table_data,1);
5656 widget->data_free=gui_internal_table_data_free;
5657
5658 // We have to set background here explicitly
5659 // because it will be used by inner elements created later in this
5660 // function (navigation buttons). Else that elements won't have
5661 // any background.
5662 widget->background=this->background;
5663 data = (struct table_data*)widget->data;
5664
5665 if (buttons) {
5666 data->next_button = gui_internal_button_new_with_callback
5667 (this,"Next",image_new_xs(this, "gui_arrow_right") ,
5668 gravity_center |orientation_vertical,
5669 gui_internal_table_button_next,NULL);
5670 data->next_button->data=widget;
5671
5672
5673 data->prev_button = gui_internal_button_new_with_callback
5674 (this,"Prev",
5675 image_new_xs(this, "gui_arrow_left")
5676 ,gravity_center |orientation_vertical,
5677 gui_internal_table_button_prev,NULL);
5678
5679 data->prev_button->data=widget;
5680
5681 data->this=this;
5682
5683 data->button_box=gui_internal_box_new(this,
5684 gravity_center|orientation_horizontal);
5685 gui_internal_widget_append(widget, data->button_box);
5686 gui_internal_widget_append(data->button_box, data->prev_button);
5687 gui_internal_widget_append(data->button_box, data->next_button);
5688
5689 data->button_box->bl=this->spacing;
5690 gui_internal_widget_pack(this,data->button_box);
5691 }
5692
5693 return widget;
5694
5695 }
5696
5697 /**
5698 * @brief Clears all the rows from the table.
5699 * This function removes all rows from a table.
5700 * New rows can later be added to the table.
5701 */
5702 void gui_internal_widget_table_clear(struct gui_priv * this,struct widget * table)
5703 {
5704 GList * iter;
5705 struct table_data * table_data = (struct table_data* ) table->data;
5706
5707 iter = table->children;
5708 while(iter ) {
5709 if(iter->data != table_data->button_box) {
5710 struct widget * child = (struct widget*)iter->data;
5711 gui_internal_widget_destroy(this,child);
5712 if(table->children == iter) {
5713 table->children = g_list_remove(iter,iter->data);
5714 iter=table->children;
5715 }
5716 else
5717 iter = g_list_remove(iter,iter->data);
5718 }
5719 else {
5720 iter = g_list_next(iter);
5721 }
5722
5723 }
5724 table_data->top_row=NULL;
5725 table_data->bottom_row=NULL;
5726 if(table_data->page_headers)
5727 g_list_free(table_data->page_headers);
5728 table_data->page_headers=NULL;
5729 }
5730
5731
5732 /**
5733 * Creates a new table_row widget.
5734 * @param this The graphics context
5735 * @param flags Sizing flags for the row
5736 * @returns The new table_row widget.
5737 */
5738 struct widget * gui_internal_widget_table_row_new(struct gui_priv * this, enum flags flags)
5739 {
5740 struct widget * widget = g_new0(struct widget,1);
5741 widget->type=widget_table_row;
5742 widget->flags=flags;
5743 return widget;
5744 }
5745
5746
5747
5748 /**
5749 * @brief Computes the column dimensions for the table.
5750 *
5751 * @param w The table widget to compute dimensions for.
5752 *
5753 * This function examines all of the rows and columns for the table w
5754 * and returns a list (GList) of table_column_desc elements that
5755 * describe each column of the table.
5756 *
5757 * The caller is responsible for freeing the returned list.
5758 */
5759 static GList * gui_internal_compute_table_dimensions(struct gui_priv * this,struct widget * w)
5760 {
5761
5762 GList * column_desc = NULL;
5763 GList * current_desc=NULL;
5764 GList * cur_row = w->children;
5765 struct widget * cur_row_widget=NULL;
5766 GList * cur_column=NULL;
5767 struct widget * cell_w=NULL;
5768 struct table_column_desc * current_cell=NULL;
5769 struct table_data * table_data=NULL;
5770 int height=0;
5771 int width=0;
5772 int total_width=0;
5773 int column_count=0;
5774
5775 /**
5776 * Scroll through the the table and
5777 * 1. Compute the maximum width + height of each column across all rows.
5778 */
5779 table_data = (struct table_data*) w->data;
5780 for(cur_row=w->children; cur_row ; cur_row = g_list_next(cur_row) )
5781 {
5782 cur_row_widget = (struct widget*) cur_row->data;
5783 current_desc = column_desc;
5784 if(cur_row_widget == table_data->button_box)
5785 {
5786 continue;
5787 }
5788 column_count=0;
5789 for(cur_column = cur_row_widget->children; cur_column;
5790 cur_column=g_list_next(cur_column))
5791 {
5792 cell_w = (struct widget*) cur_column->data;
5793 gui_internal_widget_pack(this,cell_w);
5794 if(current_desc == 0)
5795 {
5796 current_cell = g_new0(struct table_column_desc,1);
5797 column_desc = g_list_append(column_desc,current_cell);
5798 current_desc = g_list_last(column_desc);
5799 current_cell->height=cell_w->h;
5800 current_cell->width=cell_w->w;
5801 total_width+=cell_w->w;
5802
5803 }
5804 else
5805 {
5806 current_cell = current_desc->data;
5807 height = cell_w->h;
5808 width = cell_w->w;
5809 if(current_cell->height < height )
5810 {
5811 current_cell->height = height;
5812 }
5813 if(current_cell->width < width)
5814 {
5815 total_width += (width-current_cell->width);
5816 current_cell->width = width;
5817
5818
5819
5820 }
5821 current_desc = g_list_next(current_desc);
5822 }
5823 column_count++;
5824
5825 }/* column loop */
5826
5827 } /*row loop */
5828
5829
5830 /**
5831 * If the width of all columns is less than the width off
5832 * the table expand each cell proportionally.
5833 *
5834 */
5835 if(total_width+(this->spacing*column_count) < w->w ) {
5836 for(current_desc=column_desc; current_desc; current_desc=g_list_next(current_desc)) {
5837 current_cell = (struct table_column_desc*) current_desc->data;
5838 current_cell->width= ( (current_cell->width+this->spacing)/(float)total_width) * w->w ;
5839 }
5840 }
5841
5842 return column_desc;
5843 }
5844
5845
5846 /**
5847 * @brief Computes the height and width for the table.
5848 *
5849 * The height and widht are computed to display all cells in the table
5850 * at the requested height/width.
5851 *
5852 * @param this The graphics context
5853 * @param w The widget to pack.
5854 *
5855 */
5856 void gui_internal_table_pack(struct gui_priv * this, struct widget * w)
5857 {
5858
5859 int height=0;
5860 int width=0;
5861 int count=0;
5862 GList * column_data = gui_internal_compute_table_dimensions(this,w);
5863 GList * current=0;
5864 struct table_column_desc * cell_desc=0;
5865 struct table_data * table_data = (struct table_data*)w->data;
5866
5867 for(current = column_data; current; current=g_list_next(current))
5868 {
5869 if(table_data->button_box == current->data )
5870 {
5871 continue;
5872 }
5873 cell_desc = (struct table_column_desc *) current->data;
5874 width = width + cell_desc->width + this->spacing;
5875 if(height < cell_desc->height)
5876 {
5877 height = cell_desc->height ;
5878 }
5879 }
5880
5881
5882
5883 for(current=w->children; current; current=g_list_next(current))
5884 {
5885 if(current->data!= table_data->button_box)
5886 {
5887 count++;
5888 }
5889 }
5890 if (table_data->button_box)
5891 gui_internal_widget_pack(this,table_data->button_box);
5892
5893
5894
5895 if(w->h + w->c.y > this->root.h )
5896 {
5897 /**
5898 * Do not allow the widget to exceed the screen.
5899 *
5900 */
5901 w->h = this->root.h- w->c.y - height;
5902 }
5903 w->w = width;
5904
5905 /**
5906 * Deallocate column descriptions.
5907 */
5908 current = column_data;
5909 while( (current = g_list_last(current)) )
5910 {
5911 current = g_list_remove(current,current->data);
5912 }
5913
5914 }
5915
5916 /**
5917 * @brief Invalidates coordinates for previosly rendered table widget rows.
5918 *
5919 * @param table_data Data from the table object.
5920 */
5921 void gui_internal_table_hide_rows(struct table_data * table_data)
5922 {
5923 GList*cur_row;
5924 for(cur_row=table_data->top_row; cur_row ; cur_row = g_list_next(cur_row))
5925 {
5926 struct widget * cur_row_widget = (struct widget*)cur_row->data;
5927 if (cur_row_widget->type!=widget_table_row)
5928 continue;
5929 cur_row_widget->p.x=0;
5930 cur_row_widget->p.y=0;
5931 cur_row_widget->w=0;
5932 cur_row_widget->h=0;
5933 if(cur_row==table_data->bottom_row)
5934 break;
5935 }
5936 }
5937
5938 /**
5939 * @brief Renders a table widget.
5940 *
5941 * @param this The graphics context
5942 * @param w The table widget to render.
5943 */
5944 void gui_internal_table_render(struct gui_priv * this, struct widget * w)
5945 {
5946
5947 int x;
5948 int y;
5949 GList * column_desc=NULL;
5950 GList * cur_row = NULL;
5951 GList * current_desc=NULL;
5952 struct table_data * table_data = (struct table_data*)w->data;
5953 int is_skipped=0;
5954 int is_first_page=1;
5955 struct table_column_desc * dim=NULL;
5956
5957 dbg_assert(table_data);
5958 column_desc = gui_internal_compute_table_dimensions(this,w);
5959 y=w->p.y;
5960 gui_internal_table_hide_rows(table_data);
5961 /**
5962 * Skip rows that are on previous pages.
5963 */
5964 cur_row = w->children;
5965 if(table_data->top_row && table_data->top_row != w->children )
5966 {
5967 cur_row = table_data->top_row;
5968 is_first_page=0;
5969 }
5970 /**
5971 * Loop through each row. Drawing each cell with the proper sizes,
5972 * at the proper positions.
5973 */
5974 for(table_data->top_row=cur_row; cur_row; cur_row = g_list_next(cur_row))
5975 {
5976 int max_height=0;
5977 struct widget * cur_row_widget;
5978 GList * cur_column=NULL;
5979 current_desc = column_desc;
5980 cur_row_widget = (struct widget*)cur_row->data;
5981 x =w->p.x+this->spacing;
5982 if(cur_row_widget == table_data->button_box )
5983 {
5984 continue;
5985 }
5986 dim = (struct table_column_desc*)current_desc->data;
5987
5988 if( y + dim->height + (table_data->button_box ? table_data->button_box->h : 0) + this->spacing >= w->p.y + w->h )
5989 {
5990 /*
5991 * No more drawing space left.
5992 */
5993 is_skipped=1;
5994 break;
5995 }
5996 for(cur_column = cur_row_widget->children; cur_column;
5997 cur_column=g_list_next(cur_column))
5998 {
5999 struct widget * cur_widget = (struct widget*) cur_column->data;
6000 dim = (struct table_column_desc*)current_desc->data;
6001
6002 cur_widget->p.x=x;
6003 cur_widget->w=dim->width;
6004 cur_widget->p.y=y;
6005 cur_widget->h=dim->height;
6006 x=x+cur_widget->w;
6007 max_height = dim->height;
6008 /* We pack the widget before rendering to ensure that the x and y
6009 * coordinates get pushed down.
6010 */
6011 gui_internal_widget_pack(this,cur_widget);
6012 gui_internal_widget_render(this,cur_widget);
6013
6014 if(dim->height > max_height)
6015 {
6016 max_height = dim->height;
6017 }
6018 }
6019
6020 /* Row object should have its coordinates in actual
6021 * state to be able to pass mouse clicks to Column objects
6022 */
6023 cur_row_widget->p.x=w->p.x;
6024 cur_row_widget->w=w->w;
6025 cur_row_widget->p.y=y;
6026 cur_row_widget->h=max_height;
6027 y = y + max_height;
6028 table_data->bottom_row=cur_row;
6029 current_desc = g_list_next(current_desc);
6030 }
6031 if(table_data->button_box && (is_skipped || !is_first_page) )
6032 {
6033 table_data->button_box->p.y =w->p.y+w->h-table_data->button_box->h -
6034 this->spacing;
6035 if(table_data->button_box->p.y < y )
6036 {
6037 table_data->button_box->p.y=y;
6038 }
6039 table_data->button_box->p.x = w->p.x;
6040 table_data->button_box->w = w->w;
6041 // table_data->button_box->h = w->h - y;
6042 // table_data->next_button->h=table_data->button_box->h;
6043 // table_data->prev_button->h=table_data->button_box->h;
6044 // table_data->next_button->c.y=table_data->button_box->c.y;
6045 // table_data->prev_button->c.y=table_data->button_box->c.y;
6046 gui_internal_widget_pack(this,table_data->button_box);
6047 if(table_data->next_button->p.y > w->p.y + w->h + table_data->next_button->h)
6048 {
6049 table_data->button_box->p.y = w->p.y + w->h -
6050 table_data->button_box->h;
6051 }
6052 if(is_skipped)
6053 {
6054 table_data->next_button->state|= STATE_SENSITIVE;
6055 }
6056 else
6057 {
6058 table_data->next_button->state&= ~STATE_SENSITIVE;
6059 }
6060
6061 if(table_data->top_row != w->children)
6062 {
6063 table_data->prev_button->state|= STATE_SENSITIVE;
6064 }
6065 else
6066 {
6067 table_data->prev_button->state&= ~STATE_SENSITIVE;
6068 }
6069 gui_internal_widget_render(this,table_data->button_box);
6070
6071
6072 }
6073
6074 /**
6075 * Deallocate column descriptions.
6076 */
6077 current_desc = column_desc;
6078 while( (current_desc = g_list_last(current_desc)) )
6079 {
6080 current_desc = g_list_remove(current_desc,current_desc->data);
6081 }
6082 }
6083
6084
6085 /**
6086 * @brief Displays Route information
6087 *
6088 * @li The name of the active vehicle
6089 * @param wm The button that was pressed.
6090 * @param v Unused
6091 */
6092 static void
6093 gui_internal_cmd2_route_description(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
6094 {
6095
6096
6097 struct widget * menu;
6098 struct widget * row;
6099 struct widget * box;
6100
6101
6102 if(! this->vehicle_cb)
6103 {
6104 /**
6105 * Register the callback on vehicle updates.
6106 */
6107 this->vehicle_cb = callback_new_attr_1(callback_cast(gui_internal_route_update),
6108 attr_position_coord_geo,this);
6109 navit_add_callback(this->nav,this->vehicle_cb);
6110 }
6111
6112 this->route_data.route_table = gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
6113 row = gui_internal_widget_table_row_new(this,gravity_left | orientation_horizontal | flags_fill);
6114
6115 row = gui_internal_widget_table_row_new(this,gravity_left | orientation_horizontal | flags_fill);
6116
6117
6118 menu=gui_internal_menu(this,_("Route Description"));
6119
6120 menu->free=gui_internal_route_screen_free;
6121 this->route_data.route_showing=1;
6122 this->route_data.route_table->spx = this->spacing;
6123
6124
6125 box = gui_internal_box_new(this, gravity_left_top| orientation_vertical | flags_fill | flags_expand);
6126
6127 // gui_internal_widget_append(box,gui_internal_box_new_with_label(this,"Test"));
6128 gui_internal_widget_append(box,this->route_data.route_table);
6129 box->w=menu->w;
6130 box->spx = this->spacing;
6131 this->route_data.route_table->w=box->w;
6132 gui_internal_widget_append(menu,box);
6133 gui_internal_populate_route_table(this,this->nav);
6134 gui_internal_menu_render(this);
6135
6136 }
6137
6138 static int
6139 line_intersection(struct coord* a1, struct coord *a2, struct coord * b1, struct coord *b2, struct coord *res)
6140 {
6141 int n, a, b;
6142 int adx=a2->x-a1->x;
6143 int ady=a2->y-a1->y;
6144 int bdx=b2->x-b1->x;
6145 int bdy=b2->y-b1->y;
6146 n = bdy * adx - bdx * ady;
6147 a = bdx * (a1->y - b1->y) - bdy * (a1->x - b1->x);
6148 b = adx * (a1->y - b1->y) - ady * (a1->x - b1->x);
6149 if (n < 0) {
6150 n = -n;
6151 a = -a;
6152 b = -b;
6153 }
6154 if (a < 0 || b < 0)
6155 return 0;
6156 if (a > n || b > n)
6157 return 0;
6158 if (n == 0) {
6159 dbg(0,"a=%d b=%d n=%d\n", a, b, n);
6160 dbg(0,"a1=0x%x,0x%x ad %d,%d\n", a1->x, a1->y, adx, ady);
6161 dbg(0,"b1=0x%x,0x%x bd %d,%d\n", b1->x, b1->y, bdx, bdy);
6162 dbg_assert(n != 0);
6163 }
6164 res->x = a1->x + a * adx / n;
6165 res->y = a1->y + a * ady / n;
6166 return 1;
6167 }
6168
6169 struct heightline {
6170 struct heightline *next;
6171 int height;
6172 struct coord_rect bbox;
6173 int count;
6174 struct coord c[0];
6175 };
6176
6177 struct diagram_point {
6178 struct diagram_point *next;
6179 struct coord c;
6180 };
6181
6182 static struct heightline *
6183 item_get_heightline(struct item *item)
6184 {
6185 struct heightline *ret=NULL;
6186 struct street_data *sd;
6187 struct attr attr;
6188 int i,height;
6189
6190 if (item_attr_get(item, attr_label, &attr)) {
6191 height=atoi(attr.u.str);
6192 sd=street_get_data(item);
6193 if (sd && sd->count > 1) {
6194 ret=g_malloc(sizeof(struct heightline)+sd->count*sizeof(struct coord));
6195 ret->bbox.lu=sd->c[0];
6196 ret->bbox.rl=sd->c[0];
6197 ret->count=sd->count;
6198 ret->height=height;
6199 for (i = 0 ; i < sd->count ; i++) {
6200 ret->c[i]=sd->c[i];
6201 coord_rect_extend(&ret->bbox, sd->c+i);
6202 }
6203 }
6204 street_data_free(sd);
6205 }
6206 return ret;
6207 }
6208
6209
6210 /**
6211 * @brief Displays Route Height Profile
6212 *
6213 * @li The name of the active vehicle
6214 * @param wm The button that was pressed.
6215 * @param v Unused
6216 */
6217 static void
6218 gui_internal_cmd2_route_height_profile(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
6219 {
6220
6221
6222 struct widget * menu, *box;
6223
6224 struct map * map=NULL;
6225 struct map_rect * mr=NULL;
6226 struct route * route;
6227 struct item * item =NULL;
6228 struct mapset *ms;
6229 struct mapset_handle *msh;
6230 int x,i,first=1,dist=0;
6231 struct coord c,last,res;
6232 struct coord_rect rbbox,dbbox;
6233 struct map_selection sel;
6234 struct heightline *heightline,*heightlines=NULL;
6235 struct diagram_point *min,*diagram_point,*diagram_points=NULL;
6236 sel.next=NULL;
6237 sel.order=18;
6238 sel.range.min=type_height_line_1;
6239 sel.range.max=type_height_line_3;
6240
6241
6242 menu=gui_internal_menu(this,_("Height Profile"));
6243 box = gui_internal_box_new(this, gravity_left_top| orientation_vertical | flags_fill | flags_expand);
6244 gui_internal_widget_append(menu, box);
6245 route = navit_get_route(this->nav);
6246 if (route)
6247 map = route_get_map(route);
6248 if(map)
6249 mr = map_rect_new(map,NULL);
6250 if(mr) {
6251 while((item = map_rect_get_item(mr))) {
6252 while (item_coord_get(item, &c, 1)) {
6253 if (first) {
6254 first=0;
6255 sel.u.c_rect.lu=c;
6256 sel.u.c_rect.rl=c;
6257 } else
6258 coord_rect_extend(&sel.u.c_rect, &c);
6259 }
6260 }
6261 map_rect_destroy(mr);
6262 ms=navit_get_mapset(this->nav);
6263 if (!first && ms) {
6264 msh=mapset_open(ms);
6265 while ((map=mapset_next(msh, 1))) {
6266 mr=map_rect_new(map, &sel);
6267 if (mr) {
6268 while((item = map_rect_get_item(mr))) {
6269 if (item->type >= sel.range.min && item->type <= sel.range.max) {
6270 heightline=item_get_heightline(item);
6271 if (heightline) {
6272 heightline->next=heightlines;
6273 heightlines=heightline;
6274 }
6275 }
6276 }
6277 map_rect_destroy(mr);
6278 }
6279 }
6280 mapset_close(msh);
6281 }
6282 }
6283 map=NULL;
6284 mr=NULL;
6285 if (route)
6286 map = route_get_map(route);
6287 if(map)
6288 mr = map_rect_new(map,NULL);
6289 if(mr && heightlines) {
6290 while((item = map_rect_get_item(mr))) {
6291 first=1;
6292 while (item_coord_get(item, &c, 1)) {
6293 if (first)
6294 first=0;
6295 else {
6296 heightline=heightlines;
6297 rbbox.lu=last;
6298 rbbox.rl=last;
6299 coord_rect_extend(&rbbox, &c);
6300 while (heightline)
6301 {
6302 dbg(0,"EEnter\n");
6303 if (coord_rect_overlap(&rbbox, &heightline->bbox))
6304 {
6305 for (i = 0 ; i < heightline->count - 1; i++) {
6306 if (heightline->c[i].x != heightline->c[i+1].x || heightline->c[i].y != heightline->c[i+1].y) {
6307 if (line_intersection(heightline->c+i, heightline->c+i+1, &last, &c, &res)) {
6308 diagram_point=g_new(struct diagram_point, 1);
6309 diagram_point->c.x=dist+transform_distance(projection_mg, &last, &res);
6310 diagram_point->c.y=heightline->height;
6311 diagram_point->next=diagram_points;
6312 diagram_points=diagram_point;
6313 dbg(0,"%d %d\n", diagram_point->c.x, diagram_point->c.y);
6314 }
6315 }
6316 }
6317 }
6318 heightline=heightline->next;
6319 }
6320 dist+=transform_distance(projection_mg, &last, &c);
6321 }
6322 last=c;
6323 }
6324
6325 }
6326 map_rect_destroy(mr);
6327 }
6328
6329
6330 gui_internal_menu_render(this);
6331 first=1;
6332 diagram_point=diagram_points;
6333 while (diagram_point) {
6334 if (first) {
6335 dbbox.lu=diagram_point->c;
6336 dbbox.rl=diagram_point->c;
6337 first=0;
6338 } else
6339 coord_rect_extend(&dbbox, &diagram_point->c);
6340 diagram_point=diagram_point->next;
6341 }
6342 dbg(0,"%d %d %d %d\n", dbbox.lu.x, dbbox.lu.y, dbbox.rl.x, dbbox.rl.y);
6343 if (dbbox.rl.x > dbbox.lu.x && dbbox.lu.x*100/(dbbox.rl.x-dbbox.lu.x) <= 25)
6344 dbbox.lu.x=0;
6345 if (dbbox.lu.y > dbbox.rl.y && dbbox.rl.y*100/(dbbox.lu.y-dbbox.rl.y) <= 25)
6346 dbbox.rl.y=0;
6347 dbg(0,"%d,%d %dx%d\n", box->p.x, box->p.y, box->w, box->h);
6348 x=dbbox.lu.x;
6349 first=1;
6350 for (;;) {
6351 struct point p[2];
6352 min=NULL;
6353 diagram_point=diagram_points;
6354 while (diagram_point) {
6355 if (diagram_point->c.x >= x && (!min || min->c.x > diagram_point->c.x))
6356 min=diagram_point;
6357 diagram_point=diagram_point->next;
6358 }
6359 if (! min)
6360 break;
6361 p[1].x=(min->c.x-dbbox.lu.x)*(box->w-10)/(dbbox.rl.x-dbbox.lu.x)+box->p.x+5;
6362 p[1].y=(min->c.y-dbbox.rl.y)*(box->h-10)/(dbbox.lu.y-dbbox.rl.y)+box->p.y+5;
6363 dbg(0,"%d,%d=%d,%d\n",min->c.x, min->c.y, p[1].x,p[1].y);
6364 graphics_draw_circle(this->gra, this->foreground, &p[1], 2);
6365 if (first)
6366 first=0;
6367 else
6368 graphics_draw_lines(this->gra, this->foreground, p, 2);
6369 p[0]=p[1];
6370 x=min->c.x+1;
6371 }
6372
6373
6374 }
6375
6376 static void
6377 gui_internal_cmd2_locale(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
6378 {
6379 struct widget *menu,*wb,*w;
6380 char *text;
6381
6382 graphics_draw_mode(this->gra, draw_mode_begin);
6383 menu=gui_internal_menu(this, "Show Locale");
6384 menu->spx=this->spacing*10;
6385 wb=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
6386 gui_internal_widget_append(menu, wb);
6387 text=g_strdup_printf("LANG=%1$s (1=%3$s 2=%2$s)",getenv("LANG"),"2","1");
6388 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6389 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
6390 g_free(text);
6391 #ifdef HAVE_API_WIN32_BASE
6392 {
6393 char country[32],lang[32];
6394 #ifdef HAVE_API_WIN32_CE
6395 wchar_t wcountry[32],wlang[32];
6396
6397 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, wlang, sizeof(wlang));
6398 WideCharToMultiByte(CP_ACP,0,wlang,-1,lang,sizeof(lang),NULL,NULL);
6399 #else
6400 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, lang, sizeof(lang));
6401 #endif
6402 text=g_strdup_printf("LOCALE_SABBREVLANGNAME=%s",lang);
6403 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6404 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
6405 g_free(text);
6406 #ifdef HAVE_API_WIN32_CE
6407 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVCTRYNAME, wcountry, sizeof(wcountry));
6408 WideCharToMultiByte(CP_ACP,0,wcountry,-1,country,sizeof(country),NULL,NULL);
6409 #else
6410 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVCTRYNAME, country, sizeof(country));
6411 #endif
6412 text=g_strdup_printf("LOCALE_SABBREVCTRYNAME=%s",country);
6413 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6414 w->flags=gravity_left_center|orientation_horizontal|flags_fill;
6415 g_free(text);
6416 }
6417 #endif
6418
6419 gui_internal_menu_render(this);
6420 graphics_draw_mode(this->gra, draw_mode_end);
6421 }
6422
6423 static void
6424 gui_internal_cmd2_about(struct gui_priv *this, char *function, struct attr **in, struct attr ***out, int *valid)
6425 {
6426 struct widget *menu,*wb,*w;
6427 char *text;
6428
6429 graphics_draw_mode(this->gra, draw_mode_begin);
6430 menu=gui_internal_menu(this, ("About ZANavi"));
6431 menu->spx=this->spacing*10;
6432 wb=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand);
6433 gui_internal_widget_append(menu, wb);
6434
6435 //Icon -> seems missing, try icon.png?
6436 gui_internal_widget_append(wb, w=gui_internal_image_new(this, image_new_xs(this, "icon")));
6437 w->flags=gravity_top_center|orientation_horizontal|flags_fill;
6438
6439 //app name
6440 text=g_strdup_printf("%s",(" "));
6441 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6442 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6443 g_free(text);
6444 text=g_strdup_printf("%s",PACKAGE_NAME);
6445 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6446 w->flags=gravity_top_center|orientation_horizontal|flags_expand;
6447 g_free(text);
6448
6449 //Version
6450 text=g_strdup_printf("%s",(" "));
6451 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6452 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6453 g_free(text);
6454 text=g_strdup_printf("%s",version);
6455 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6456 w->flags=gravity_top_center|orientation_horizontal|flags_expand;
6457 g_free(text);
6458
6459 //Site
6460 text=g_strdup_printf("%s",(" "));
6461 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6462 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6463 g_free(text);
6464 text=g_strdup_printf("http://zanavi.cc/");
6465 // gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6466 gui_internal_widget_append(wb, w=gui_internal_label_font_new(this, text,1));
6467 w->flags=gravity_top_center|orientation_horizontal|flags_expand;
6468 g_free(text);
6469
6470 //ZANavi
6471 text=g_strdup_printf("%s",(" "));
6472 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6473 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6474 g_free(text);
6475 text=g_strdup_printf("%s",("ZANavi"));
6476 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6477 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6478 g_free(text);
6479 text=g_strdup_printf("%s",("by Zoff"));
6480 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6481 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6482 g_free(text);
6483 text=g_strdup_printf("%s",(" "));
6484 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6485 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6486 g_free(text);
6487 text=g_strdup_printf("%s",(" "));
6488 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6489 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6490 g_free(text);
6491
6492 //Navit
6493 text=g_strdup_printf("%s:",("based on Navit by"));
6494 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6495 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6496 g_free(text);
6497 text=g_strdup_printf("Martin Schaller");
6498 gui_internal_widget_append(wb, w=gui_internal_label_new(this, text));
6499 w->flags=gravity_bottom_center|orientation_horizontal|flags_fill;
6500 g_free(text);
6501
6502 gui_internal_menu_render(this);
6503 graphics_draw_mode(this->gra, draw_mode_end);
6504 }
6505
6506 /**
6507 * @brief handles the 'next page' table event.
6508 * A callback function that is invoked when the 'next page' button is pressed
6509 * to advance the contents of a table widget.
6510 *
6511 * @param this The graphics context.
6512 * @param wm The button widget that was pressed.
6513 */
6514 static void gui_internal_table_button_next(struct gui_priv * this, struct widget * wm, void *data)
6515 {
6516 struct widget * table_widget = (struct widget * ) wm->data;
6517 struct table_data * table_data = NULL;
6518 int found=0;
6519 GList * iterator;
6520
6521 if(table_widget)
6522 {
6523 table_data = (struct table_data*) table_widget->data;
6524
6525 }
6526 if(table_data)
6527 {
6528 /**
6529 * Before advancing to the next page we need to ensure
6530 * that the current top_row is in the list of previous top_rows
6531 * so previous page can work.
6532 *
6533 */
6534 for(iterator=table_data->page_headers; iterator != NULL;
6535 iterator = g_list_next(iterator) )
6536 {
6537 if(iterator->data == table_data->top_row)
6538 {
6539 found=1;
6540 break;
6541 }
6542
6543 }
6544 if( ! found)
6545 {
6546 table_data->page_headers=g_list_append(table_data->page_headers,
6547 table_data->top_row);
6548 }
6549 /**
6550 * Invalidate row coordinates for all rows which were previously rendered
6551
6552 for(iterator=table_data->top_row; iterator && table_data->rows_on_page; iterator = g_list_next(iterator))
6553 {
6554 struct widget * cur_row_widget = (struct widget*)iterator->data;
6555 cur_row_widget->p.x=-1;
6556 cur_row_widget->p.y=-1;
6557 cur_row_widget->w=0;
6558 cur_row_widget->h=0;
6559 table_data->rows_on_page--;
6560 }
6561 */
6562 gui_internal_table_hide_rows(table_data);
6563 table_data->top_row=g_list_next(table_data->bottom_row);
6564 }
6565 wm->state&= ~STATE_HIGHLIGHTED;
6566 gui_internal_menu_render(this);
6567 }
6568
6569
6570
6571 /**
6572 * @brief handles the 'previous page' table event.
6573 * A callback function that is invoked when the 'previous page' button is pressed
6574 * to go back in the contents of a table widget.
6575 *
6576 * @param this The graphics context.
6577 * @param wm The button widget that was pressed.
6578 */
6579 static void gui_internal_table_button_prev(struct gui_priv * this, struct widget * wm, void *data)
6580 {
6581 struct widget * table_widget = (struct widget * ) wm->data;
6582 struct table_data * table_data = NULL;
6583 GList * current_page_top=NULL;
6584
6585 GList * iterator;
6586 if(table_widget)
6587 {
6588 table_data = (struct table_data*) table_widget->data;
6589 if(table_data)
6590 {
6591 gui_internal_table_hide_rows(table_data);
6592 current_page_top = table_data->top_row;
6593 for(iterator = table_data->page_headers; iterator != NULL;
6594 iterator = g_list_next(iterator))
6595 {
6596 if(current_page_top == iterator->data)
6597 {
6598 break;
6599 }
6600 table_data->top_row = (GList*) iterator->data;
6601 }
6602 }
6603 }
6604 wm->state&= ~STATE_HIGHLIGHTED;
6605 gui_internal_menu_render(this);
6606 }
6607
6608
6609 /**
6610 * @brief deallocates a table_data structure.
6611 *
6612 */
6613 void gui_internal_table_data_free(void * p)
6614 {
6615
6616
6617 /**
6618 * @note button_box and its children (next_button,prev_button)
6619 * have their memory managed by the table itself.
6620 */
6621 struct table_data * table_data = (struct table_data*) p;
6622 g_list_free(table_data->page_headers);
6623 g_free(p);
6624
6625
6626 }
6627
6628
6629 /**
6630 * @brief Called when the route is updated.
6631 */
6632 void gui_internal_route_update(struct gui_priv * this, struct navit * navit, struct vehicle *v)
6633 {
6634
6635 if(this->route_data.route_showing) {
6636 gui_internal_populate_route_table(this,navit);
6637 graphics_draw_mode(this->gra, draw_mode_begin);
6638 gui_internal_menu_render(this);
6639 graphics_draw_mode(this->gra, draw_mode_end);
6640 }
6641
6642
6643 }
6644
6645
6646 /**
6647 * @brief Called when the route screen is closed (deallocated).
6648 *
6649 * The main purpose of this function is to remove the widgets from
6650 * references route_data because those widgets are about to be freed.
6651 */
6652 void gui_internal_route_screen_free(struct gui_priv * this_,struct widget * w)
6653 {
6654 if(this_) {
6655 this_->route_data.route_showing=0;
6656 this_->route_data.route_table=NULL;
6657 g_free(w);
6658 }
6659
6660 }
6661
6662 /**
6663 * @brief Populates the route table with route information
6664 *
6665 * @param this The gui context
6666 * @param navit The navit object
6667 */
6668 void gui_internal_populate_route_table(struct gui_priv * this,
6669 struct navit * navit)
6670 {
6671 struct map * map=NULL;
6672 struct map_rect * mr=NULL;
6673 struct navigation * nav = NULL;
6674 struct item * item =NULL;
6675 struct attr attr;
6676 struct widget * label = NULL;
6677 struct widget * row = NULL;
6678 nav = navit_get_navigation(navit);
6679 if(!nav) {
6680 return;
6681 }
6682 map = navigation_get_map(nav);
6683 if(map)
6684 mr = map_rect_new(map,NULL);
6685 if(mr) {
6686 gui_internal_widget_table_clear(this,this->route_data.route_table);
6687 while((item = map_rect_get_item(mr))) {
6688 if(item_attr_get(item,attr_navigation_long,&attr)) {
6689 label = gui_internal_label_new(this,attr.u.str);
6690 row = gui_internal_widget_table_row_new(this,
6691 gravity_left
6692 | flags_fill
6693 | orientation_horizontal);
6694 row->children=g_list_append(row->children,label);
6695 gui_internal_widget_append(this->route_data.route_table,row);
6696 }
6697
6698 }
6699
6700 }
6701 }
6702
6703 static struct command_table commands[] = {
6704 {"abort_navigation",command_cast(gui_internal_cmd2_abort_navigation)},
6705 {"back",command_cast(gui_internal_cmd2_back)},
6706 {"back_to_map",command_cast(gui_internal_cmd2_back_to_map)},
6707 {"bookmarks",command_cast(gui_internal_cmd2_bookmarks)},
6708 {"get_data",command_cast(gui_internal_get_data)},
6709 {"locale",command_cast(gui_internal_cmd2_locale)},
6710 {"log",command_cast(gui_internal_cmd_log)},
6711 {"menu",command_cast(gui_internal_cmd_menu2)},
6712 {"position",command_cast(gui_internal_cmd2_position)},
6713 {"route_description",command_cast(gui_internal_cmd2_route_description)},
6714 {"route_height_profile",command_cast(gui_internal_cmd2_route_height_profile)},
6715 {"setting_layout",command_cast(gui_internal_cmd2_setting_layout)},
6716 {"setting_maps",command_cast(gui_internal_cmd2_setting_maps)},
6717 {"setting_rules",command_cast(gui_internal_cmd2_setting_rules)},
6718 {"setting_vehicle",command_cast(gui_internal_cmd2_setting_vehicle)},
6719 {"town",command_cast(gui_internal_cmd2_town)},
6720 {"quit",command_cast(gui_internal_cmd2_quit)},
6721 {"write",command_cast(gui_internal_cmd_write)},
6722 {"about",command_cast(gui_internal_cmd2_about)},
6723 };
6724
6725
6726 //##############################################################################################################
6727 //# Description:
6728 //# Comment:
6729 //# Authors: Martin Schaller (04/2008)
6730 //##############################################################################################################
6731 static struct gui_priv * gui_internal_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs, struct gui *gui)
6732 {
6733 struct color color_white={0xffff,0xffff,0xffff,0xffff};
6734 struct color color_black={0x0,0x0,0x0,0xffff};
6735 struct color back2_color={0x4141,0x4141,0x4141,0xffff};
6736
6737 struct gui_priv *this;
6738 struct attr *attr;
6739 *meth=gui_internal_methods;
6740 this=g_new0(struct gui_priv, 1);
6741 this->nav=nav;
6742
6743 this->self.type=attr_gui;
6744 this->self.u.gui=gui;
6745
6746 if ((attr=attr_search(attrs, NULL, attr_menu_on_map_click)))
6747 this->menu_on_map_click=attr->u.num;
6748 else
6749 this->menu_on_map_click=1;
6750 if ((attr=attr_search(attrs, NULL, attr_signal_on_map_click)))
6751 this->signal_on_map_click=attr->u.num;
6752
6753 if ((attr=attr_search(attrs, NULL, attr_callback_list))) {
6754 command_add_table(attr->u.callback_list, commands, sizeof(commands)/sizeof(struct command_table), this);
6755 }
6756
6757 if( (attr=attr_search(attrs,NULL,attr_font_size)))
6758 {
6759 this->config.font_size=attr->u.num;
6760 }
6761 else
6762 {
6763 this->config.font_size=-1;
6764 }
6765 if( (attr=attr_search(attrs,NULL,attr_icon_xs)))
6766 {
6767 this->config.icon_xs=attr->u.num;
6768 }
6769 else
6770 {
6771 this->config.icon_xs=-1;
6772 }
6773 if( (attr=attr_search(attrs,NULL,attr_icon_l)))
6774 {
6775 this->config.icon_l=attr->u.num;
6776 }
6777 else
6778 {
6779 this->config.icon_l=-1;
6780 }
6781 if( (attr=attr_search(attrs,NULL,attr_icon_s)))
6782 {
6783 this->config.icon_s=attr->u.num;
6784 }
6785 else
6786 {
6787 this->config.icon_s=-1;
6788 }
6789 if( (attr=attr_search(attrs,NULL,attr_spacing)))
6790 {
6791 this->config.spacing=attr->u.num;
6792 }
6793 else
6794 {
6795 this->config.spacing=-1;
6796 }
6797 if( (attr=attr_search(attrs,NULL,attr_gui_speech)))
6798 {
6799 this->speech=attr->u.num;
6800 }
6801 if( (attr=attr_search(attrs,NULL,attr_keyboard)))
6802 this->keyboard=attr->u.num;
6803 else
6804 this->keyboard=1;
6805
6806 if( (attr=attr_search(attrs,NULL,attr_fullscreen)))
6807 this->fullscreen=attr->u.num;
6808
6809 if( (attr=attr_search(attrs,NULL,attr_flags)))
6810 this->flags=attr->u.num;
6811 if( (attr=attr_search(attrs,NULL,attr_background_color)))
6812 this->background_color=*attr->u.color;
6813 else
6814 this->background_color=color_black;
6815 if( (attr=attr_search(attrs,NULL,attr_background_color2)))
6816 this->background2_color=*attr->u.color;
6817 else
6818 this->background2_color=back2_color;
6819 if( (attr=attr_search(attrs,NULL,attr_text_color)))
6820 this->text_foreground_color=*attr->u.color;
6821 else
6822 this->text_foreground_color=color_white;
6823 this->text_background_color=color_black;
6824 if( (attr=attr_search(attrs,NULL,attr_columns)))
6825 this->cols=attr->u.num;
6826 if( (attr=attr_search(attrs,NULL,attr_osd_configuration)))
6827 this->osd_configuration=*attr;
6828
6829 if( (attr=attr_search(attrs,NULL,attr_pitch)))
6830 this->pitch=attr->u.num;
6831 else
6832 this->pitch=20;
6833 if( (attr=attr_search(attrs,NULL,attr_flags_town)))
6834 this->flags_town=attr->u.num;
6835 else
6836 this->flags_town=-1;
6837 if( (attr=attr_search(attrs,NULL,attr_flags_street)))
6838 this->flags_street=attr->u.num;
6839 else
6840 this->flags_street=-1;
6841 if( (attr=attr_search(attrs,NULL,attr_flags_house_number)))
6842 this->flags_house_number=attr->u.num;
6843 else
6844 this->flags_house_number=-1;
6845 if( (attr=attr_search(attrs,NULL,attr_radius)))
6846 this->radius=attr->u.num;
6847 else
6848 this->radius=10;
6849 this->data.priv=this;
6850 this->data.gui=&gui_internal_methods_ext;
6851 this->data.widget=&gui_internal_widget_methods;
6852 this->cbl=callback_list_new();
6853
6854 return this;
6855 }
6856
6857 //##############################################################################################################
6858 //# Description:
6859 //# Comment:
6860 //# Authors: Martin Schaller (04/2008)
6861 //##############################################################################################################
6862 void plugin_init(void)
6863 {
6864 plugin_register_gui_type("internal", gui_internal_new);
6865 }
6866
6867 static void
6868 gui_internal_destroy(struct gui_priv *this)
6869 {
6870 g_free(this->country_iso2);
6871 g_free(this->href);
6872 g_free(this->html_text);
6873 g_free(this);
6874 }

   
Visit the ZANavi Wiki