711804aa4d2b5397b507143e9cd6ea90bdc16736
[navit-package] / src / navit.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <glib.h>
8 #include <libintl.h>
9 #include <math.h>
10 #include "debug.h"
11 #include "navit.h"
12 #include "callback.h"
13 #include "gui.h"
14 #include "item.h"
15 #include "projection.h"
16 #include "map.h"
17 #include "mapset.h"
18 #include "main.h"
19 #include "coord.h"
20 #include "point.h"
21 #include "transform.h"
22 #include "param.h"
23 #include "menu.h"
24 #include "graphics.h"
25 #include "cursor.h"
26 #include "popup.h"
27 #include "data_window.h"
28 #include "route.h"
29 #include "navigation.h"
30 #include "speech.h"
31 #include "track.h"
32 #include "vehicle.h"
33 #include "color.h"
34
35 #define _(STRING)    gettext(STRING)
36 /**
37  * @defgroup navit the navit core instance
38  * @{
39  */
40
41 struct navit_vehicle {
42         char *name;
43         int update;
44         int update_curr;
45         int follow;
46         int follow_curr;
47         struct color c;
48         struct menu *menu;
49         struct cursor *cursor;
50         struct vehicle *vehicle;
51         struct callback *update_cb;
52 };
53
54 struct navit {
55         GList *mapsets;
56         GList *layouts;
57         struct gui *gui;
58         char *gui_type;
59         struct layout *layout_current;
60         struct graphics *gra;
61         char *gra_type;
62         struct action *action;
63         struct transformation *trans;
64         struct compass *compass;
65         struct menu *menu;
66         struct menu *toolbar;
67         struct statusbar *statusbar;
68         struct menu *menubar;
69         struct route *route;
70         struct navigation *navigation;
71         struct speech *speech;
72         struct tracking *tracking;
73         int ready;
74         struct window *win;
75         struct displaylist *displaylist;
76         int cursor_flag;
77         int tracking_flag;
78         int orient_north_flag;
79         GList *vehicles;
80         GList *windows_items;
81         struct navit_vehicle *vehicle;
82         struct callback_list *vehicle_cbl;
83         struct callback_list *init_cbl;
84         int pid;
85         struct callback *nav_speech_cb;
86         struct callback *roadbook_callback;
87         struct datawindow *roadbook_window;
88         struct menu *bookmarks;
89         GHashTable *bookmarks_hash;
90         struct menu *destinations;
91         struct point pressed, last, current;
92         int button_pressed,moved,popped;
93         guint button_timeout, motion_timeout;
94 };
95
96 struct gui *main_loop_gui;
97
98 static void navit_cursor_update(struct navit *this_, struct cursor *cursor);
99
100 void
101 navit_add_mapset(struct navit *this_, struct mapset *ms)
102 {
103         this_->mapsets = g_list_append(this_->mapsets, ms);
104 }
105
106 struct mapset *
107 navit_get_mapset(struct navit *this_)
108 {
109         return this_->mapsets->data;
110 }
111
112 struct tracking *
113 navit_get_tracking(struct navit *this_)
114 {
115         return this_->tracking;
116 }
117
118 void
119 navit_add_layout(struct navit *this_, struct layout *lay)
120 {
121         this_->layouts = g_list_append(this_->layouts, lay);
122 }
123
124 void
125 navit_draw(struct navit *this_)
126 {
127         GList *l;
128         struct navit_vehicle *nv;
129
130         transform_setup_source_rect(this_->trans);
131         graphics_draw(this_->gra, this_->displaylist, this_->mapsets, this_->trans, this_->layouts, this_->route);
132         l=this_->vehicles;
133         while (l) {
134                 nv=l->data;
135                 cursor_redraw(nv->cursor);
136                 l=g_list_next(l);
137         }
138         this_->ready=1;
139 }
140
141 void
142 navit_draw_displaylist(struct navit *this_)
143 {
144         if (this_->ready) {
145                 graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layouts, this_->route);
146         }
147 }
148
149 static void
150 navit_resize(void *data, int w, int h)
151 {
152         struct navit *this_=data;
153         transform_set_size(this_->trans, w, h);
154         navit_draw(this_);
155 }
156
157 static gboolean
158 navit_popup(void *data)
159 {
160         struct navit *this_=data;
161         popup(this_, 1, &this_->pressed);
162         this_->button_timeout=0;
163         this_->popped=1;
164         return FALSE;
165 }
166
167 static void
168 navit_button(void *data, int pressed, int button, struct point *p)
169 {
170         struct navit *this_=data;
171         int border=16;
172
173         if (pressed) {
174                 this_->pressed=*p;
175                 this_->last=*p;
176                 if (button == 1) {
177                         this_->button_pressed=1;
178                         this_->moved=0;
179                         this_->popped=0;
180                         this_->button_timeout=g_timeout_add(500, navit_popup, data);
181                 }
182                 if (button == 2)
183                         navit_set_center_screen(this_, p);
184                 if (button == 3)
185                         popup(this_, button, p);
186                 if (button == 4)
187                         navit_zoom_in(this_, 2, p);
188                 if (button == 5)
189                         navit_zoom_out(this_, 2, p);
190         } else {
191                 this_->button_pressed=0;
192                 if (this_->button_timeout) {
193                         g_source_remove(this_->button_timeout); 
194                         this_->button_timeout=0;
195                         if (! this_->moved && ! transform_within_border(this_->trans, p, border))
196                                 navit_set_center_screen(this_, p);
197                                 
198                 }
199                 if (this_->motion_timeout) {
200                         g_source_remove(this_->motion_timeout); 
201                         this_->motion_timeout=0;
202                 }
203                 if (this_->moved) {
204                         struct point p;
205                         transform_get_size(this_->trans, &p.x, &p.y);
206                         p.x/=2;
207                         p.y/=2;
208                         p.x-=this_->last.x-this_->pressed.x;
209                         p.y-=this_->last.y-this_->pressed.y;
210                         navit_set_center_screen(this_, &p);
211                 }
212         }
213 }
214
215
216 static gboolean
217 navit_motion_timeout(void *data)
218 {
219         struct navit *this_=data;
220         int dx, dy;
221
222         dx=(this_->current.x-this_->last.x);
223         dy=(this_->current.y-this_->last.y);
224         if (dx || dy) {
225                 this_->last=this_->current;
226                 graphics_displaylist_move(this_->displaylist, dx, dy);
227                 graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layouts, this_->route);
228                 this_->moved=1;
229         }
230         this_->motion_timeout=0;
231         return FALSE;
232 }
233
234 static void
235 navit_motion(void *data, struct point *p)
236 {
237         struct navit *this_=data;
238         int dx, dy;
239
240         if (this_->button_pressed && !this_->popped) {
241                 dx=(p->x-this_->pressed.x);
242                 dy=(p->y-this_->pressed.y);
243                 if (dx < -8 || dx > 8 || dy < -8 || dy > 8) {
244                         if (this_->button_timeout) {
245                                 g_source_remove(this_->button_timeout); 
246                                 this_->button_timeout=0;
247                         }
248                         this_->current=*p;
249                         if (! this_->motion_timeout)
250                                 this_->motion_timeout=g_timeout_add(100, navit_motion_timeout, data);
251                 }
252         }
253 }
254
255 static void
256 navit_scale(struct navit *this_, long scale, struct point *p)
257 {
258         struct coord c1, c2, *center;
259         if (p)
260                 transform_reverse(this_->trans, p, &c1);
261         transform_set_scale(this_->trans, scale);
262         if (p) {
263                 transform_reverse(this_->trans, p, &c2);
264                 center = transform_center(this_->trans);
265                 center->x += c1.x - c2.x;
266                 center->y += c1.y - c2.y;
267         }
268         navit_draw(this_);
269 }
270
271 /**
272  * Change the current zoom level, zooming closer to the ground
273  *
274  * @param navit The navit instance
275  * @param factor The zoom factor, usually 2
276  * @param p The invariant point (if set to NULL, default to center)
277  * @returns nothing
278  */
279 void
280 navit_zoom_in(struct navit *this_, int factor, struct point *p)
281 {
282         long scale=transform_get_scale(this_->trans)/factor;
283         if (scale < 1)
284                 scale=1;
285         navit_scale(this_, scale, p);
286 }
287
288 /**
289  * Change the current zoom level
290  *
291  * @param navit The navit instance
292  * @param factor The zoom factor, usually 2
293  * @param p The invariant point (if set to NULL, default to center)
294  * @returns nothing
295  */
296 void
297 navit_zoom_out(struct navit *this_, int factor, struct point *p)
298 {
299         long scale=transform_get_scale(this_->trans)*factor;
300         navit_scale(this_, scale, p);
301 }
302
303 struct navit *
304 navit_new(struct pcoord *center, int zoom)
305 {
306         struct navit *this_=g_new0(struct navit, 1);
307         FILE *f;
308
309         main_add_navit(this_);
310         this_->vehicle_cbl=callback_list_new();
311         this_->init_cbl=callback_list_new();
312
313         f=popen("pidof /usr/bin/ipaq-sleep","r");
314         if (f) {
315                 fscanf(f,"%d",&this_->pid);
316                 dbg(1,"ipaq_sleep pid=%d\n", this_->pid);
317                 pclose(f);
318         }
319
320         this_->bookmarks_hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
321         this_->cursor_flag=1;
322         this_->tracking_flag=1;
323         this_->trans=transform_new();
324         transform_setup(this_->trans, center, zoom, 0);
325         this_->displaylist=graphics_displaylist_new();
326         return this_;
327 }
328
329 void
330 navit_set_gui(struct navit *this_, struct gui *gui, char *type)
331 {
332         this_->gui=gui;
333         this_->gui_type=g_strdup(type);
334         if (gui_has_main_loop(this_->gui)) {
335                 if (! main_loop_gui) {
336                         main_loop_gui=this_->gui;
337                 } else {
338                         g_warning("gui with main loop already active, ignoring this instance");
339                         return;
340                 }
341         }
342         this_->menubar=gui_menubar_new(this_->gui);
343         this_->toolbar=gui_toolbar_new(this_->gui);
344         this_->statusbar=gui_statusbar_new(this_->gui);
345 }
346
347 void
348 navit_set_graphics(struct navit *this_, struct graphics *gra, char *type)
349 {
350         this_->gra=gra;
351         this_->gra_type=g_strdup(type);
352         graphics_register_resize_callback(this_->gra, navit_resize, this_);
353         graphics_register_button_callback(this_->gra, navit_button, this_);
354         graphics_register_motion_callback(this_->gra, navit_motion, this_);
355 }
356
357 struct graphics *
358 navit_get_graphics(struct navit *this_)
359 {
360         return this_->gra;
361 }
362
363 static void
364 navit_map_toggle(struct menu *menu, struct navit *this_, struct map *map)
365 {
366         if ((menu_get_toggle(menu) != 0) != (map_get_active(map) != 0)) {
367                 map_set_active(map, (menu_get_toggle(menu) != 0));
368                 navit_draw(this_);
369         }
370 }
371
372 static void
373 navit_projection_set(struct navit *this_, enum projection pro)
374 {
375         struct coord_geo g;
376         struct coord *c;
377
378         c=transform_center(this_->trans);
379         transform_to_geo(transform_get_projection(this_->trans), c, &g);
380         transform_set_projection(this_->trans, pro);
381         transform_from_geo(pro, &g, c);
382         navit_draw(this_);
383 }
384
385 static void
386 navit_add_menu_destinations(struct navit *this_, char *name, struct menu *rmen, GHashTable *h, struct callback *cb)
387 {
388         char buffer2[2048];
389         char *i,*n;
390         struct menu *men,*nmen;
391
392         if (rmen) {
393                 i=name;
394                 n=name;
395                 men=rmen;
396                 while (h && (i=index(n, '/'))) {
397                         strcpy(buffer2, name);
398                         buffer2[i-name]='\0';
399                         if (!(nmen=g_hash_table_lookup(h, buffer2))) {
400                                 nmen=menu_add(men, buffer2+(n-name), menu_type_submenu, NULL);
401                                 g_hash_table_insert(h, g_strdup(buffer2), nmen);
402                         }
403                         n=i+1;
404                         men=nmen;
405                 }
406                 menu_add(men, n, menu_type_menu, cb);
407         }
408 }
409
410 static const char *
411 navit_proj2str(enum projection pro)
412 {
413         switch (pro) {
414                 case projection_mg:
415                         return "mg";
416                 case projection_garmin:
417                         return "garmin";
418                 default:
419                         return "";
420         }
421 }
422 static void
423 navit_append_coord(struct navit *this_, char *file, struct pcoord *c, char *type, char *description, struct menu *rmen, GHashTable *h, void (*cb_func)(void))
424 {
425         FILE *f;
426         int offset=0;
427         char *buffer;
428         const char *prostr;
429         struct callback *cb;
430
431         f=fopen(file, "a");
432         if (f) {
433                 offset=ftell(f);
434                 if (c) {
435                         prostr = navit_proj2str(c->pro);
436                         fprintf(f,"%s%s0x%x 0x%x type=%s label=\"%s\"\n",
437                                  prostr, *prostr ? ":" : "", c->x, c->y, type, description);
438                 } else
439                         fprintf(f,"\n");
440                 fclose(f);
441         }
442         if (c) {
443                 buffer=g_strdup(description);
444                 cb=callback_new_2(cb_func, this_, (void *)offset);
445                 navit_add_menu_destinations(this_, buffer, rmen, h, cb);
446                 g_free(buffer);
447         }
448 }
449
450 static int
451 parse_line(FILE *f, char *buffer, char **name, struct pcoord *c)
452 {
453         int pos;
454         char *s,*i;
455         struct coord co;
456         char *cp;
457         enum projection pro = projection_mg;
458         *name=NULL;
459         if (! fgets(buffer, 2048, f))
460                 return -3;
461         cp = buffer;
462         pos=coord_parse(cp, pro, &co);
463         if (!pos)
464                 return -2;
465         if (!cp[pos] || cp[pos] == '\n') 
466                 return -1;
467         cp[strlen(cp)-1]='\0';
468         s=cp+pos+1;
469         if (!strncmp(s,"type=", 5)) {
470                 i=index(s, '"');
471                 if (i) {
472                         s=i+1;
473                         i=index(s, '"');
474                         if (i) 
475                                 *i='\0';
476                 }
477         }
478         *name=s;
479         c->x = co.x;
480         c->y = co.y;
481         c->pro = pro;
482         return pos;
483 }
484
485
486 static void
487 navit_set_destination_from_file(struct navit *this_, char *file, int bookmark, int offset)
488 {
489         FILE *f;
490         char *name, *description, buffer[2048];
491         struct pcoord c;
492         
493         f=fopen(file, "r");
494         if (! f)
495                 return;
496         fseek(f, offset, SEEK_SET);
497         if (parse_line(f, buffer, &name, &c) <= 0)
498                 return;
499         if (bookmark) {
500                 description=g_strdup_printf("Bookmark %s", name);
501                 navit_set_destination(this_, &c, description);
502                 g_free(description);
503         } else 
504                 navit_set_destination(this_, &c, name);
505 }
506
507 static void
508 navit_set_destination_from_destination(struct navit *this_, void *offset_p)
509 {
510         navit_set_destination_from_file(this_, "destination.txt", 0, (int)offset_p);
511 }
512
513 static void
514 navit_set_destination_from_bookmark(struct navit *this_, void *offset_p)
515 {
516         navit_set_destination_from_file(this_, "bookmark.txt", 1, (int)offset_p);
517 }
518
519 /**
520  * Start the route computing to a given set of coordinates
521  *
522  * @param navit The navit instance
523  * @param c The coordinate to start routing to
524  * @param description A label which allows the user to later identify this destination in the former destinations selection
525  * @returns nothing
526  */
527 void
528 navit_set_destination(struct navit *this_, struct pcoord *c, char *description)
529 {
530         navit_append_coord(this_, "destination.txt", c, "former_destination", description, this_->destinations, NULL, callback_cast(navit_set_destination_from_destination));
531         if (this_->route) {
532                 route_set_destination(this_->route, c);
533                 navit_draw(this_);
534         }
535 }
536
537 /**
538  * Record the given set of coordinates as a bookmark
539  *
540  * @param navit The navit instance
541  * @param c The coordinate to store
542  * @param description A label which allows the user to later identify this bookmark
543  * @returns nothing
544  */
545 void
546 navit_add_bookmark(struct navit *this_, struct pcoord *c, char *description)
547 {
548         navit_append_coord(this_,"bookmark.txt", c, "bookmark", description, this_->bookmarks, this_->bookmarks_hash, callback_cast(navit_set_destination_from_bookmark));
549 }
550
551 struct navit *global_navit;
552
553
554 /**
555  * Deprecated
556  */
557 static void
558 navit_debug(struct navit *this_)
559 {
560 #if 0
561         struct attr attr;
562 #include "search.h"
563         struct search_list *sl;
564         struct search_list_result *res;
565
566         debug_level_set("data_mg:town_search_get_item",9);
567         debug_level_set("data_mg:town_search_compare",9);
568         debug_level_set("data_mg:tree_search_next",9);
569         debug_level_set("data_mg:map_search_new_mg",9);
570         sl=search_list_new(this_->mapsets->data);
571         attr.type=attr_country_all;
572         attr.u.str="Fra";
573         search_list_search(sl, &attr, 1);
574         while ((res=search_list_get_result(sl))) {
575                 printf("country result\n");
576         }
577         attr.type=attr_town_name;
578         attr.u.str="seclin";
579         search_list_search(sl, &attr, 1);
580         while ((res=search_list_get_result(sl))) {
581                 printf("town result\n");
582         }
583         attr.type=attr_street_name;
584         attr.u.str="rue";
585         search_list_search(sl, &attr, 1);
586         while ((res=search_list_get_result(sl))) {
587                 printf("street result\n");
588         }
589         search_list_destroy(sl);
590         exit(0);
591 #endif
592 }
593
594 void
595 navit_add_menu_layouts(struct navit *this_, struct menu *men)
596 {
597         menu_add(men, "Test", menu_type_menu, NULL);
598 }
599
600 void
601 navit_add_menu_layout(struct navit *this_, struct menu *men)
602 {
603         navit_add_menu_layouts(this_, menu_add(men, _("Layout"), menu_type_submenu, NULL));
604 }
605
606 void
607 navit_add_menu_projections(struct navit *this_, struct menu *men)
608 {
609         struct callback *cb;
610         cb=callback_new_2(callback_cast(navit_projection_set), this_, (void *)projection_mg);
611         menu_add(men, "M&G", menu_type_menu, cb);
612         cb=callback_new_2(callback_cast(navit_projection_set), this_, (void *)projection_garmin);
613         menu_add(men, "Garmin", menu_type_menu, cb);
614 }
615
616 void
617 navit_add_menu_projection(struct navit *this_, struct menu *men)
618 {
619         navit_add_menu_projections(this_, menu_add(men, _("Projection"), menu_type_submenu, NULL));
620 }
621
622 void
623 navit_add_menu_maps(struct navit *this_, struct mapset *ms, struct menu *men)
624 {
625         struct mapset_handle *handle;
626         struct map *map;
627         struct menu *mmen;
628         struct callback *cb;
629
630         handle=mapset_open(ms);
631         while ((map=mapset_next(handle,0))) {
632                 char *s=g_strdup_printf("%s:%s", map_get_type(map), map_get_filename(map));
633                 cb=callback_new_3(callback_cast(navit_map_toggle), NULL, this_, map);
634                 mmen=menu_add(men, s, menu_type_toggle, cb);
635                 callback_set_arg(cb, 0, mmen);
636                 menu_set_toggle(mmen, map_get_active(map));
637                 g_free(s);
638         }
639         mapset_close(handle);
640 }
641
642 static void
643 navit_add_menu_destinations_from_file(struct navit *this_, char *file, struct menu *rmen, GHashTable *h, struct route *route, void (*cb_func)(void))
644 {
645         int pos,flag=0;
646         FILE *f;
647         char buffer[2048];
648         struct pcoord c;
649         char *name;
650         int offset=0;
651         struct callback *cb;
652         
653         f=fopen(file, "r");
654         if (f) {
655                 while (! feof(f) && (pos=parse_line(f, buffer, &name, &c)) > -3) {
656                         if (pos > 0) {
657                                 cb=callback_new_2(cb_func, this_, (void *)offset);
658                                 navit_add_menu_destinations(this_, name, rmen, h, cb);
659                                 flag=1;
660                         } else
661                                 flag=0;
662                         offset=ftell(f);
663                 }
664                 fclose(f);
665                 if (route && flag)
666                         route_set_destination(route, &c);
667         }
668 }
669
670 void
671 navit_add_menu_former_destinations(struct navit *this_, struct menu *men, struct route *route)
672 {
673         if (men)
674                 this_->destinations=menu_add(men, _("Former Destinations"), menu_type_submenu, NULL);
675         else
676                 this_->destinations=NULL;
677         navit_add_menu_destinations_from_file(this_, "destination.txt", this_->destinations, NULL, route, callback_cast(navit_set_destination_from_destination));
678 }
679
680 void
681 navit_add_menu_bookmarks(struct navit *this_, struct menu *men)
682 {
683         if (men)
684                 this_->bookmarks=menu_add(men, _("Bookmarks"), menu_type_submenu, NULL);
685         else
686                 this_->bookmarks=NULL;
687         navit_add_menu_destinations_from_file(this_, "bookmark.txt", this_->bookmarks, this_->bookmarks_hash, NULL, callback_cast(navit_set_destination_from_bookmark));
688 }
689
690 static void
691 navit_vehicle_toggle(struct navit *this_, struct navit_vehicle *nv)
692 {
693         if (menu_get_toggle(nv->menu)) {
694                 if (this_->vehicle && this_->vehicle != nv) 
695                         menu_set_toggle(this_->vehicle->menu, 0);
696                 this_->vehicle=nv;
697         } else {
698                 if (this_->vehicle == nv) 
699                         this_->vehicle=NULL;
700         }
701 }
702
703 void
704 navit_add_menu_vehicles(struct navit *this_, struct menu *men)
705 {
706         struct navit_vehicle *nv;
707         struct callback *cb;
708         GList *l;
709         l=this_->vehicles;
710         while (l) {
711                 nv=l->data;
712                 cb=callback_new_2(callback_cast(navit_vehicle_toggle), this_, nv);
713                 nv->menu=menu_add(men, nv->name, menu_type_toggle, cb);
714                 menu_set_toggle(nv->menu, this_->vehicle == nv);
715                 l=g_list_next(l);
716         }
717 }
718
719 void
720 navit_add_menu_vehicle(struct navit *this_, struct menu *men)
721 {
722         men=menu_add(men, _("Vehicle"), menu_type_submenu, NULL);
723         navit_add_menu_vehicles(this_, men);
724 }
725
726 void
727 navit_speak(struct navit *this_)
728 {
729         struct navigation *nav=this_->navigation;
730         struct navigation_list *list;
731         struct item *item;
732         struct attr attr;
733
734         list=navigation_list_new(nav);  
735         item=navigation_list_get_item(list);
736         if (item_attr_get(item, attr_navigation_speech, &attr)) 
737                 speech_say(this_->speech, attr.u.str);
738         navigation_list_destroy(list);
739 }
740
741 static void
742 navit_window_roadbook_update(struct navit *this_)
743 {
744         struct navigation *nav=this_->navigation;
745         struct navigation_list *list;
746         struct item *item;
747         struct attr attr;
748         struct param_list param[1];
749
750         dbg(1,"enter\n");       
751         datawindow_mode(this_->roadbook_window, 1);
752         list=navigation_list_new(nav);
753         while ((item=navigation_list_get_item(list))) {
754                 attr.u.str=NULL;
755                 item_attr_get(item, attr_navigation_long, &attr);
756                 dbg(2, "Command='%s'\n", attr.u.str);
757                 param[0].name="Command";
758                 param[0].value=attr.u.str;
759                 datawindow_add(this_->roadbook_window, param, 1);
760         }
761         navigation_list_destroy(list);
762         datawindow_mode(this_->roadbook_window, 0);
763 }
764
765 void
766 navit_window_roadbook_destroy(struct navit *this_)
767 {
768         dbg(0, "enter\n");
769         navigation_unregister_callback(this_->navigation, attr_navigation_long, this_->roadbook_callback);
770         this_->roadbook_window=NULL;
771         this_->roadbook_callback=NULL;
772 }
773 void
774 navit_window_roadbook_new(struct navit *this_)
775 {
776         this_->roadbook_callback=callback_new_1(callback_cast(navit_window_roadbook_update), this_);
777         navigation_register_callback(this_->navigation, attr_navigation_long, this_->roadbook_callback);
778         this_->roadbook_window=gui_datawindow_new(this_->gui, _("Roadbook"), NULL, callback_new_1(callback_cast(navit_window_roadbook_destroy), this_));
779         navit_window_roadbook_update(this_);
780 }
781
782 static void
783 get_direction(char *buffer, int angle, int mode)
784 {
785         angle=angle%360;
786         switch (mode) {
787         case 0:
788                 sprintf(buffer,"%d",angle);
789                 break;
790         case 1:
791                 if (angle < 69 || angle > 291)
792                         *buffer++='N';
793                 if (angle > 111 && angle < 249)
794                         *buffer++='S';
795                 if (angle > 22 && angle < 158)
796                         *buffer++='E';
797                 if (angle > 202 && angle < 338)
798                         *buffer++='W';  
799                 *buffer++='\0';
800                 break;
801         case 2:
802                 angle=(angle+15)/30;
803                 if (! angle)
804                         angle=12;
805                 sprintf(buffer,"%d H", angle);
806                 break;
807         }
808 }
809
810 struct navit_window_items {
811         struct datawindow *win;
812         struct callback *click;
813         char *name;
814         int distance;
815         GHashTable *hash;
816         GList *list;
817 };
818
819 static void
820 navit_window_items_click(struct navit *this_, struct navit_window_items *nwi, char **col)
821 {
822         struct pcoord c;
823         char *description;
824
825         // FIXME
826         dbg(0,"enter col=%s,%s,%s,%s,%s\n", col[0], col[1], col[2], col[3], col[4]);
827         sscanf(col[4], "0x%x,0x%x", &c.x, &c.y);
828         c.pro = projection_mg;
829         dbg(0,"0x%x,0x%x\n", c.x, c.y);
830         description=g_strdup_printf("%s %s", nwi->name, col[3]);
831         navit_set_destination(this_, &c, description);
832         g_free(description);
833 }
834
835 static void
836 navit_window_items_open(struct navit *this_, struct navit_window_items *nwi)
837 {
838         struct map_selection sel;
839         struct coord c,*center;
840         struct mapset_handle *h;
841         struct map *m;
842         struct map_rect *mr;
843         struct item *item;
844         struct attr attr;
845         int idist,dist;
846         struct param_list param[5];
847         char distbuf[32];
848         char dirbuf[32];
849         char coordbuf[64];
850         
851         dbg(0, "distance=%d\n", nwi->distance);
852         if (nwi->distance == -1) 
853                 dist=40000000;
854         else
855                 dist=nwi->distance*1000;
856         param[0].name="Distance";
857         param[1].name="Direction";
858         param[2].name="Type";
859         param[3].name="Name";
860         param[4].name=NULL;
861         sel.next=NULL;
862 #if 0
863         sel.order[layer_town]=18;
864         sel.order[layer_street]=18;
865         sel.order[layer_poly]=18;
866 #else
867         sel.order[layer_town]=0;
868         sel.order[layer_street]=0;
869         sel.order[layer_poly]=0;
870 #endif
871         center=transform_center(this_->trans);
872         sel.u.c_rect.lu.x=center->x-dist;
873         sel.u.c_rect.lu.y=center->y+dist;
874         sel.u.c_rect.rl.x=center->x+dist;
875         sel.u.c_rect.rl.y=center->y-dist;
876         dbg(2,"0x%x,0x%x - 0x%x,0x%x\n", sel.u.c_rect.lu.x, sel.u.c_rect.lu.y, sel.u.c_rect.rl.x, sel.u.c_rect.rl.y);
877         nwi->click=callback_new_2(callback_cast(navit_window_items_click), this_, nwi);
878         nwi->win=gui_datawindow_new(this_->gui, nwi->name, nwi->click, NULL);
879         h=mapset_open(navit_get_mapset(this_));
880         while ((m=mapset_next(h, 1))) {
881                 dbg(2,"m=%p %s\n", m, map_get_filename(m));
882                 mr=map_rect_new(m, &sel);
883                 dbg(2,"mr=%p\n", mr);
884                 while ((item=map_rect_get_item(mr))) {
885                         if (item_coord_get(item, &c, 1)) {
886                                 if (coord_rect_contains(&sel.u.c_rect, &c) && g_hash_table_lookup(nwi->hash, &item->type)) {
887                                         if (! item_attr_get(item, attr_label, &attr)) 
888                                                 attr.u.str="";
889                                         idist=transform_distance(map_projection(item->map), center, &c);
890                                         if (idist < dist) {
891                                                 get_direction(dirbuf, transform_get_angle_delta(center, &c, 0), 1);
892                                                 param[0].value=distbuf; 
893                                                 param[1].value=dirbuf;
894                                                 param[2].value=item_to_name(item->type);
895                                                 sprintf(distbuf,"%d", idist/1000);
896                                                 param[3].value=attr.u.str;
897                                                 sprintf(coordbuf, "0x%x,0x%x", c.x, c.y);
898                                                 param[4].value=coordbuf;
899                                                 datawindow_add(nwi->win, param, 5);
900                                         }
901                                         /* printf("gefunden %s %s %d\n",item_to_name(item->type), attr.u.str, idist/1000); */
902                                 }
903                                 if (item->type >= type_line) 
904                                         while (item_coord_get(item, &c, 1));
905                         }
906                 }
907                 map_rect_destroy(mr);   
908         }
909         mapset_close(h);
910 }
911
912 struct navit_window_items *
913 navit_window_items_new(const char *name, int distance)
914 {
915         struct navit_window_items *nwi=g_new0(struct navit_window_items, 1);
916         nwi->name=g_strdup(name);
917         nwi->distance=distance;
918         nwi->hash=g_hash_table_new(g_int_hash, g_int_equal);
919
920         return nwi;
921 }
922
923 void
924 navit_window_items_add_item(struct navit_window_items *nwi, enum item_type type)
925 {
926         nwi->list=g_list_prepend(nwi->list, (void *)type);
927         g_hash_table_insert(nwi->hash, &nwi->list->data, (void *)1);
928 }
929
930 void
931 navit_add_window_items(struct navit *this_, struct navit_window_items *nwi)
932 {
933         this_->windows_items=g_list_append(this_->windows_items, nwi);
934 }
935
936 void
937 navit_add_menu_windows_items(struct navit *this_, struct menu *men)
938 {
939         struct navit_window_items *nwi;
940         struct callback *cb;
941         GList *l;
942         l=this_->windows_items;
943         while (l) {
944                 nwi=l->data;
945                 cb=callback_new_2(callback_cast(navit_window_items_open), this_, nwi);
946                 menu_add(men, nwi->name, menu_type_menu, cb);
947                 l=g_list_next(l);
948         }
949 }
950
951 void
952 navit_init(struct navit *this_)
953 {
954         struct menu *men;
955         struct mapset *ms;
956         GList *l;
957         struct navit_vehicle *nv;
958
959         if (!this_->gui) {
960                 g_warning("failed to instantiate gui '%s'\n",this_->gui_type);
961                 navit_destroy(this_);
962                 return;
963         }
964         if (!this_->gra) {
965                 g_warning("failed to instantiate gui '%s'\n",this_->gra_type);
966                 navit_destroy(this_);
967                 return;
968         }
969         if (gui_set_graphics(this_->gui, this_->gra)) {
970                 g_warning("failed to connect graphics '%s' to gui '%s'\n", this_->gra_type, this_->gui_type);
971                 g_warning(" Please see http://navit.sourceforge.net/wiki/index.php/Failed_to_connect_graphics_to_gui\n");
972                 g_warning(" for explanations and solutions\n");
973
974                 navit_destroy(this_);
975                 return;
976         }
977         graphics_init(this_->gra);
978         l=this_->vehicles;
979         while (l) {
980                 dbg(0,"parsed one vehicle\n");
981                 nv=l->data;
982                 nv->cursor=cursor_new(this_->gra, nv->vehicle, &nv->c, this_->trans);
983                 nv->update_cb=callback_new_1(callback_cast(navit_cursor_update), this_);
984                 cursor_add_callback(nv->cursor, nv->update_cb);
985                 vehicle_set_navit(nv->vehicle, this_);
986                 l=g_list_next(l);
987         }
988         if (this_->mapsets) {
989                 ms=this_->mapsets->data;
990                 if (this_->route)
991                         route_set_mapset(this_->route, ms);
992                 if (this_->tracking)
993                         tracking_set_mapset(this_->tracking, ms);
994                 if (this_->navigation)
995                         navigation_set_mapset(this_->navigation, ms);
996                 if (this_->menubar) {
997                         men=menu_add(this_->menubar, _("Map"), menu_type_submenu, NULL);
998                         if (men) {
999                                 navit_add_menu_layout(this_, men);
1000                                 navit_add_menu_projection(this_, men);
1001                                 navit_add_menu_vehicle(this_, men);
1002                                 navit_add_menu_maps(this_, ms, men);
1003                         }
1004                         men=menu_add(this_->menubar, _("Route"), menu_type_submenu, NULL);
1005                         if (men) {
1006                                 navit_add_menu_former_destinations(this_, men, this_->route);
1007                                 navit_add_menu_bookmarks(this_, men);
1008                         }
1009                 } else
1010                         navit_add_menu_former_destinations(this_, NULL, this_->route);
1011         }
1012         if (this_->navigation && this_->speech) {
1013                 this_->nav_speech_cb=callback_new_1(callback_cast(navit_speak), this_);
1014                 navigation_register_callback(this_->navigation, attr_navigation_speech, this_->nav_speech_cb);
1015 #if 0
1016 #endif
1017         }
1018         if (this_->menubar) {
1019                 men=menu_add(this_->menubar, "Data", menu_type_submenu, NULL);
1020                 if (men) {
1021                         navit_add_menu_windows_items(this_, men);
1022                 }
1023         }
1024         global_navit=this_;
1025 #if 0
1026         navit_window_roadbook_new(this_);
1027         navit_window_items_new(this_);
1028 #endif
1029         navit_debug(this_);
1030         callback_list_call_1(this_->init_cbl, this_);
1031 }
1032
1033 void
1034 navit_set_center(struct navit *this_, struct coord *center)
1035 {
1036         struct coord *c=transform_center(this_->trans);
1037         *c=*center;
1038         if (this_->ready)
1039                 navit_draw(this_);
1040 }
1041
1042 static void
1043 navit_set_center_cursor(struct navit *this_, struct coord *cursor, int dir, int xpercent, int ypercent)
1044 {
1045         struct coord *c=transform_center(this_->trans);
1046         int width, height;
1047         struct point p;
1048         struct coord cnew;
1049
1050         transform_get_size(this_->trans, &width, &height);
1051         *c=*cursor;
1052         transform_set_angle(this_->trans, dir);
1053         p.x=(100-xpercent)*width/100;
1054         p.y=(100-ypercent)*height/100;
1055         transform_reverse(this_->trans, &p, &cnew);
1056         *c=cnew;
1057         if (this_->ready)
1058                 navit_draw(this_);
1059                 
1060 }
1061
1062
1063 void
1064 navit_set_center_screen(struct navit *this_, struct point *p)
1065 {
1066         struct coord c;
1067         transform_reverse(this_->trans, p, &c);
1068         navit_set_center(this_, &c);
1069 }
1070
1071 void
1072 navit_toggle_cursor(struct navit *this_)
1073 {
1074         this_->cursor_flag=1-this_->cursor_flag;
1075 }
1076
1077 /**
1078  * Toggle the tracking : automatic centering of the map on the main vehicle
1079  *
1080  * @param navit The navit instance
1081  * @returns nothing
1082  */
1083 void
1084 navit_toggle_tracking(struct navit *this_)
1085 {
1086         this_->tracking_flag=1-this_->tracking_flag;
1087 }
1088
1089 /**
1090  * Toggle the north orientation : forces the map to be aimed at north
1091  *
1092  * @param navit The navit instance
1093  * @returns nothing
1094  */
1095 void
1096 navit_toggle_orient_north(struct navit *this_)
1097 {
1098         this_->orient_north_flag=1-this_->orient_north_flag;
1099 }
1100
1101 /**
1102  * Toggle the cursor update : refresh the map each time the cursor has moved (instead of only when it reaches a border)
1103  *
1104  * @param navit The navit instance
1105  * @returns nothing
1106  */
1107
1108 static void
1109 navit_cursor_update(struct navit *this_, struct cursor *cursor)
1110 {
1111         struct point pnt;
1112         struct coord *cursor_c=cursor_pos_get(cursor);
1113         struct pcoord pc;
1114         int dir=cursor_get_dir(cursor);
1115         int speed=cursor_get_speed(cursor);
1116         enum projection pro;
1117         int border=30;
1118
1119         if (!this_->vehicle || this_->vehicle->cursor != cursor)
1120                 return;
1121
1122         cursor_c=cursor_pos_get(cursor);
1123         dir=cursor_get_dir(cursor);
1124         speed=cursor_get_speed(cursor);
1125         pro=vehicle_projection(this_->vehicle->vehicle);
1126
1127         /* This transform is useless cursor and vehicle are in the same projection */
1128         if (!transform(this_->trans, pro, cursor_c, &pnt) || !transform_within_border(this_->trans, &pnt, border)) {
1129                 if (!this_->cursor_flag)
1130                         return;
1131                 if (this_->orient_north_flag)
1132                         navit_set_center_cursor(this_, cursor_c, 0, 50 - 30.*sin(M_PI*dir/180.), 50 + 30.*cos(M_PI*dir/180.));
1133                 else
1134                         navit_set_center_cursor(this_, cursor_c, dir, 50, 80);
1135                 transform(this_->trans, pro, cursor_c, &pnt);
1136         }
1137
1138         if (this_->pid && speed > 2)
1139                 kill(this_->pid, SIGWINCH);
1140         if (this_->tracking && this_->tracking_flag) {
1141                 struct coord c=*cursor_c;
1142                 if (tracking_update(this_->tracking, &c, dir)) {
1143                         cursor_c=&c;
1144                         cursor_pos_set(cursor, cursor_c);
1145                         if (this_->route && this_->vehicle->update_curr == 1) 
1146                                 route_set_position_from_tracking(this_->route, this_->tracking);
1147                 }
1148         } else {
1149                 if (this_->route && this_->vehicle->update_curr == 1) {
1150                         pc.pro = pro;
1151                         pc.x = cursor_c->x;
1152                         pc.y = cursor_c->y;
1153                         route_set_position(this_->route, &pc);
1154                 }
1155         }
1156         if (this_->route && this_->vehicle->update_curr == 1)
1157                 navigation_update(this_->navigation, this_->route);
1158         if (this_->cursor_flag) {
1159                 if (this_->vehicle->follow_curr == 1)
1160                         navit_set_center_cursor(this_, cursor_c, dir, 50, 80);
1161         }
1162         if (this_->vehicle->follow_curr > 1)
1163                 this_->vehicle->follow_curr--;
1164         else
1165                 this_->vehicle->follow_curr=this_->vehicle->follow;
1166         if (this_->vehicle->update_curr > 1)
1167                 this_->vehicle->update_curr--;
1168         else
1169                 this_->vehicle->update_curr=this_->vehicle->update;
1170         callback_list_call_2(this_->vehicle_cbl, this_, this_->vehicle->vehicle);
1171 }
1172
1173 /**
1174  * Set the position of the vehicle
1175  *
1176  * @param navit The navit instance
1177  * @param c The coordinate to set as position
1178  * @returns nothing
1179  */
1180
1181 void
1182 navit_set_position(struct navit *this_, struct pcoord *c)
1183 {
1184         if (this_->route) {
1185                 route_set_position(this_->route, c);
1186                 if (this_->navigation) {
1187                         navigation_update(this_->navigation, this_->route);
1188                 }
1189         }
1190         navit_draw(this_);
1191 }
1192
1193 /**
1194  * Register a new vehicle
1195  *
1196  * @param navit The navit instance
1197  * @param v The vehicle instance
1198  * @param name Guess? :)
1199  * @param c The color to use for the cursor, currently only used in GTK
1200  * @param update Wether to refresh the map each time this vehicle position changes (instead of only when it reaches a border)
1201  * @param follow Wether to center the map on this vehicle position
1202  * @returns a vehicle instance
1203  */
1204 struct navit_vehicle *
1205 navit_add_vehicle(struct navit *this_, struct vehicle *v, const char *name, struct color *c, int update, int follow)
1206 {
1207         struct navit_vehicle *nv=g_new0(struct navit_vehicle, 1);
1208         nv->vehicle=v;
1209         nv->name=g_strdup(name);
1210         nv->update_curr=nv->update=update;
1211         nv->follow_curr=nv->follow=follow;
1212         nv->c=*c;
1213
1214         this_->vehicles=g_list_append(this_->vehicles, nv);
1215         return nv;
1216 }
1217
1218 void
1219 navit_add_vehicle_cb(struct navit *this_, struct callback *cb)
1220 {
1221         callback_list_add(this_->vehicle_cbl, cb);
1222 }
1223
1224 void
1225 navit_remove_vehicle_cb(struct navit *this_, struct callback *cb)
1226 {
1227         callback_list_remove(this_->vehicle_cbl, cb);
1228 }
1229
1230 void
1231 navit_add_init_cb(struct navit *this_, struct callback *cb)
1232 {
1233         callback_list_add(this_->init_cbl, cb);
1234 }
1235
1236 void
1237 navit_remove_init_cb(struct navit *this_, struct callback *cb)
1238 {
1239         callback_list_remove(this_->init_cbl, cb);
1240 }
1241
1242 void
1243 navit_set_vehicle(struct navit *this_, struct navit_vehicle *nv)
1244 {
1245         this_->vehicle=nv;
1246 }
1247
1248 void
1249 navit_tracking_add(struct navit *this_, struct tracking *tracking)
1250 {
1251         this_->tracking=tracking;
1252 }
1253
1254 void
1255 navit_route_add(struct navit *this_, struct route *route)
1256 {
1257         this_->route=route;
1258 }
1259
1260 void
1261 navit_navigation_add(struct navit *this_, struct navigation *navigation)
1262 {
1263         this_->navigation=navigation;
1264 }
1265
1266 void
1267 navit_set_speech(struct navit *this_, struct speech *speech)
1268 {
1269         this_->speech=speech;
1270 }
1271
1272
1273 struct gui *
1274 navit_get_gui(struct navit *this_)
1275 {
1276         return this_->gui;
1277 }
1278
1279 struct transformation *
1280 navit_get_trans(struct navit *this_)
1281 {
1282         return this_->trans;
1283 }
1284
1285 struct route *
1286 navit_get_route(struct navit *this_)
1287 {
1288         return this_->route;
1289 }
1290
1291 struct navigation *
1292 navit_get_navigation(struct navit *this_)
1293 {
1294         return this_->navigation;
1295 }
1296
1297 struct displaylist *
1298 navit_get_displaylist(struct navit *this_)
1299 {
1300         return this_->displaylist;
1301 }
1302
1303 void
1304 navit_destroy(struct navit *this_)
1305 {
1306         /* TODO: destroy objects contained in this_ */
1307         main_remove_navit(this_);
1308         g_free(this_);
1309 }
1310
1311 void
1312 navit_toggle_routegraph_display(struct navit *nav)
1313 {
1314         if (!nav->route)
1315                 return;
1316         route_toggle_routegraph_display(nav->route);
1317         navit_draw(nav);
1318 }
1319
1320 /** @} */