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