FIX:build: Make --disable-nls and --with-included-gettext work.
[navit-package] / navit / navit.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <glib.h>
27 #include <math.h>
28 #include "config.h"
29 #include "debug.h"
30 #include "navit.h"
31 #include "callback.h"
32 #include "gui.h"
33 #include "item.h"
34 #include "projection.h"
35 #include "map.h"
36 #include "mapset.h"
37 #include "main.h"
38 #include "coord.h"
39 #include "point.h"
40 #include "transform.h"
41 #include "param.h"
42 #include "menu.h"
43 #include "graphics.h"
44 #include "cursor.h"
45 #include "popup.h"
46 #include "data_window.h"
47 #include "route.h"
48 #include "navigation.h"
49 #include "speech.h"
50 #include "track.h"
51 #include "vehicle.h"
52 #include "color.h"
53 #include "layout.h"
54 #include "log.h"
55 #include "attr.h"
56 #include "navit_nls.h"
57
58 /**
59  * @defgroup navit the navit core instance. navit is the object containing nearly everything: A set of maps, one or more vehicle, a graphics object for rendering the map, a gui object for displaying the user interface, a route object, a navigation object and so on. Be warned that it is theoretically possible to have more than one navit object
60  * @{
61  */
62
63 //! The navit_vehicule
64 struct navit_vehicle {
65         int update;
66         /*! Limit of the update counter. See navit_add_vehicle */
67         int update_curr;
68         /*! Deprecated : Update counter itself. When it reaches 'update' counts, route is updated */
69         int follow;
70         /*! Limit of the follow counter. See navit_add_vehicle */
71         int follow_curr;
72         /*! Deprecated : follow counter itself. When it reaches 'update' counts, map is recentered*/
73         struct coord coord;
74         int dir;
75         int speed;
76         struct color c;
77         struct color *c2;
78         struct cursor *cursor;
79         struct vehicle *vehicle;
80         struct attr callback;
81         int animate_cursor;
82 };
83
84 struct navit {
85         struct attr self;
86         GList *mapsets;
87         GList *layouts;
88         struct gui *gui;
89         struct layout *layout_current;
90         struct graphics *gra;
91         struct action *action;
92         struct transformation *trans;
93         struct compass *compass;
94         struct route *route;
95         struct navigation *navigation;
96         struct speech *speech;
97         struct tracking *tracking;
98         int ready;
99         struct window *win;
100         struct displaylist *displaylist;
101         int cursor_flag;
102         int tracking_flag;
103         int orient_north_flag;
104         int recentdest_count;
105         GList *vehicles;
106         GList *windows_items;
107         struct navit_vehicle *vehicle;
108         struct callback_list *attr_cbl;
109         int pid;
110         struct callback *nav_speech_cb;
111         struct callback *roadbook_callback;
112         struct callback *popup_callback;
113         struct datawindow *roadbook_window;
114         struct map *bookmark;
115         struct map *former_destination;
116         GHashTable *bookmarks_hash;
117         struct point pressed, last, current;
118         int button_pressed,moved,popped;
119         struct event_timer *button_timeout, *motion_timeout;
120         struct callback *motion_timeout_callback;
121         int ignore_button;
122         struct log *textfile_debug_log;
123         struct pcoord destination;
124         int destination_valid;
125         int blocked;
126         int w,h;
127         int drag_bitmap;
128         GHashTable *commands;
129         struct callback *resize_callback,*button_callback,*motion_callback;
130 };
131
132 struct gui *main_loop_gui;
133
134 struct attr_iter {
135         union {
136                 GList *list;
137                 struct mapset_handle *mapset_handle;
138         } u;
139 };
140
141 static void navit_vehicle_update(struct navit *this_, struct navit_vehicle *nv);
142 static void navit_vehicle_draw(struct navit *this_, struct navit_vehicle *nv, struct point *pnt);
143 static int navit_add_vehicle(struct navit *this_, struct vehicle *v);
144
145 void
146 navit_add_mapset(struct navit *this_, struct mapset *ms)
147 {
148         this_->mapsets = g_list_append(this_->mapsets, ms);
149 }
150
151 struct mapset *
152 navit_get_mapset(struct navit *this_)
153 {
154         if(this_->mapsets){
155                 return this_->mapsets->data;
156         } else {
157                 dbg(0,"No mapsets enabled! Is it on purpose? Navit can't draw a map. Please check your navit.xml\n");
158         }
159         return NULL;
160 }
161
162 struct tracking *
163 navit_get_tracking(struct navit *this_)
164 {
165         return this_->tracking;
166 }
167
168 void
169 navit_draw(struct navit *this_)
170 {
171         GList *l;
172         struct navit_vehicle *nv;
173
174         if (this_->blocked) {
175                 this_->blocked |= 2;
176                 return;
177         }
178         transform_setup_source_rect(this_->trans);
179         graphics_draw(this_->gra, this_->displaylist, this_->mapsets, this_->trans, this_->layout_current);
180         l=this_->vehicles;
181         while (l) {
182                 nv=l->data;
183                 navit_vehicle_draw(this_, nv, NULL);
184                 l=g_list_next(l);
185         }
186 }
187
188 void
189 navit_draw_displaylist(struct navit *this_)
190 {
191         if (this_->ready == 3)
192                 graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layout_current, 1);
193 }
194
195 void
196 navit_resize(void *data, int w, int h)
197 {
198         struct navit *this_=data;
199         struct map_selection sel;
200         memset(&sel, 0, sizeof(sel));
201         sel.u.p_rect.rl.x=w;
202         sel.u.p_rect.rl.y=h;
203         this_->w=w;
204         this_->h=h;
205         transform_set_screen_selection(this_->trans, &sel);
206         this_->ready |= 2;
207         if (this_->ready == 3)
208                 navit_draw(this_);
209 }
210
211 int
212 navit_get_width(struct navit *this_)
213 {
214         return this_->w;
215 }
216
217
218 int
219 navit_get_height(struct navit *this_)
220 {
221         return this_->h;
222 }
223
224 static void
225 navit_popup(void *data)
226 {
227         struct navit *this_=data;
228         popup(this_, 1, &this_->pressed);
229         this_->button_timeout=NULL;
230         this_->popped=1;
231 }
232
233
234 int
235 navit_ignore_button(struct navit *this_)
236 {
237         this_->ignore_button=1;
238 }
239
240 int
241 navit_handle_button(struct navit *this_, int pressed, int button, struct point *p, struct callback *popup_callback)
242 {
243         int border=16;
244
245         callback_list_call_attr_4(this_->attr_cbl, attr_button, this_, pressed, button, p);
246         if (this_->ignore_button) {
247                 this_->ignore_button=0;
248                 return 0;
249         }
250         if (pressed) {
251                 this_->pressed=*p;
252                 this_->last=*p;
253                 if (button == 1) {
254                         this_->button_pressed=1;
255                         this_->moved=0;
256                         this_->popped=0;
257                         if (popup_callback)
258                                 this_->button_timeout=event_add_timeout(500, 0, popup_callback);
259                 }
260                 if (button == 2)
261                         navit_set_center_screen(this_, p);
262                 if (button == 3)
263                         popup(this_, button, p);
264                 if (button == 4)
265                         navit_zoom_in(this_, 2, p);
266                 if (button == 5)
267                         navit_zoom_out(this_, 2, p);
268         } else {
269                 this_->button_pressed=0;
270                 if (this_->button_timeout) {
271                         event_remove_timeout(this_->button_timeout);
272                         this_->button_timeout=NULL;
273                         if (! this_->moved && ! transform_within_border(this_->trans, p, border))
274                                 navit_set_center_screen(this_, p);
275
276                 }
277                 if (this_->motion_timeout) {
278                         event_remove_timeout(this_->motion_timeout);
279                         this_->motion_timeout=NULL;
280                 }
281                 if (this_->moved) {
282                         struct point pt;
283                         this_->last=*p;
284                         transform_get_size(this_->trans, &pt.x, &pt.y);
285                         pt.x/=2;
286                         pt.y/=2;
287                         pt.x-=this_->last.x-this_->pressed.x;
288                         pt.y-=this_->last.y-this_->pressed.y;
289                         graphics_draw_drag(this_->gra, NULL);
290                         graphics_overlay_disable(this_->gra, 0);
291                         navit_set_center_screen(this_, &pt);
292                 } else
293                         return 1;
294         }
295         return 0;
296 }
297
298 static void
299 navit_button(void *data, int pressed, int button, struct point *p)
300 {
301         struct navit *this=data;
302         if (! this->popup_callback)
303                 this->popup_callback=callback_new_1(navit_popup, this);
304         navit_handle_button(this, pressed, button, p, this->popup_callback);
305 }
306
307
308 static void
309 navit_motion_timeout(struct navit *this_)
310 {
311         int dx, dy;
312
313         if (this_->drag_bitmap) {
314                 struct point point;
315                 point.x=(this_->current.x-this_->pressed.x);
316                 point.y=(this_->current.y-this_->pressed.y);
317                 if (graphics_draw_drag(this_->gra, &point)) {
318                         graphics_overlay_disable(this_->gra, 1);
319                         graphics_draw_mode(this_->gra, draw_mode_end);
320                         this_->moved=1;
321                         this_->motion_timeout=NULL;
322                         return;
323                 }
324         } 
325         dx=(this_->current.x-this_->last.x);
326         dy=(this_->current.y-this_->last.y);
327         if (dx || dy) {
328                 this_->last=this_->current;
329                 graphics_overlay_disable(this_->gra, 1);
330                 graphics_displaylist_move(this_->displaylist, dx, dy);
331                 graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layout_current, 0);
332                 this_->moved=1;
333         }
334         this_->motion_timeout=NULL;
335         return;
336 }
337
338 void
339 navit_handle_motion(struct navit *this_, struct point *p)
340 {
341         int dx, dy;
342
343         if (this_->button_pressed && !this_->popped) {
344                 dx=(p->x-this_->pressed.x);
345                 dy=(p->y-this_->pressed.y);
346                 if (dx < -8 || dx > 8 || dy < -8 || dy > 8) {
347                         if (this_->button_timeout) {
348                                 event_remove_timeout(this_->button_timeout);
349                                 this_->button_timeout=NULL;
350                         }
351                         this_->current=*p;
352                         if (! this_->motion_timeout_callback)
353                                 this_->motion_timeout_callback=callback_new_1(callback_cast(navit_motion_timeout), this_);
354                         if (! this_->motion_timeout)
355                                 this_->motion_timeout=event_add_timeout(100, 0, this_->motion_timeout_callback);
356                 }
357         }
358 }
359
360 static void
361 navit_motion(void *data, struct point *p)
362 {
363         navit_handle_motion((struct navit *)data, p);
364 }
365
366 static void
367 navit_scale(struct navit *this_, long scale, struct point *p)
368 {
369         struct coord c1, c2, *center;
370         if (p)
371                 transform_reverse(this_->trans, p, &c1);
372         transform_set_scale(this_->trans, scale);
373         if (p) {
374                 transform_reverse(this_->trans, p, &c2);
375                 center = transform_center(this_->trans);
376                 center->x += c1.x - c2.x;
377                 center->y += c1.y - c2.y;
378         }
379         navit_draw(this_);
380 }
381
382 /**
383  * Change the current zoom level, zooming closer to the ground
384  *
385  * @param navit The navit instance
386  * @param factor The zoom factor, usually 2
387  * @param p The invariant point (if set to NULL, default to center)
388  * @returns nothing
389  */
390 void
391 navit_zoom_in(struct navit *this_, int factor, struct point *p)
392 {
393         long scale=transform_get_scale(this_->trans)/factor;
394         if (scale < 1)
395                 scale=1;
396         navit_scale(this_, scale, p);
397 }
398
399 /**
400  * Change the current zoom level
401  *
402  * @param navit The navit instance
403  * @param factor The zoom factor, usually 2
404  * @param p The invariant point (if set to NULL, default to center)
405  * @returns nothing
406  */
407 void
408 navit_zoom_out(struct navit *this_, int factor, struct point *p)
409 {
410         long scale=transform_get_scale(this_->trans)*factor;
411         navit_scale(this_, scale, p);
412 }
413
414 struct navit *
415 navit_new(struct attr *parent, struct attr **attrs)
416 {
417         struct navit *this_=g_new0(struct navit, 1);
418         struct pcoord center;
419         struct coord co;
420         struct coord_geo g;
421         enum projection pro=projection_mg;
422         int zoom = 256;
423         FILE *f;
424         g.lat=53.13;
425         g.lng=11.70;
426
427         main_add_navit(this_);
428         this_->self.type=attr_navit;
429         this_->self.u.navit=this_;
430         this_->attr_cbl=callback_list_new();
431
432 #if !defined(_WIN32) && !defined(__CEGCC__)
433         f=popen("pidof /usr/bin/ipaq-sleep","r");
434         if (f) {
435                 fscanf(f,"%d",&this_->pid);
436                 dbg(1,"ipaq_sleep pid=%d\n", this_->pid);
437                 pclose(f);
438         }
439 #endif
440
441         this_->bookmarks_hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
442
443         this_->cursor_flag=1;
444         this_->orient_north_flag=0;
445         this_->tracking_flag=1;
446         this_->recentdest_count=10;
447
448         for (;*attrs; attrs++) {
449                 switch((*attrs)->type) {
450                 case attr_zoom:
451                         zoom=(*attrs)->u.num;
452                         break;
453                 case attr_center:
454                         g=*((*attrs)->u.coord_geo);
455                         break;
456                 case attr_cursor:
457                         this_->cursor_flag=!!(*attrs)->u.num;
458                         break;
459                 case attr_orientation:
460                         this_->orient_north_flag=!!(*attrs)->u.num;
461                         break;
462                 case attr_tracking:
463                         this_->tracking_flag=!!(*attrs)->u.num;
464                         break;
465                 case attr_recent_dest:
466                         this_->recentdest_count=(*attrs)->u.num;
467                         break;
468                 case attr_drag_bitmap:
469                         this_->drag_bitmap=!!(*attrs)->u.num;
470                         break;
471                 default:
472                         dbg(0, "Unexpected attribute %x\n",(*attrs)->type);
473                         break;
474                 }
475         }
476         transform_from_geo(pro, &g, &co);
477         center.x=co.x;
478         center.y=co.y;
479         center.pro = pro;
480
481         this_->trans=transform_new();
482         transform_setup(this_->trans, &center, zoom, 0);
483         this_->displaylist=graphics_displaylist_new();
484         this_->commands=g_hash_table_new(g_str_hash, g_str_equal);
485         navit_command_register(this_, "zoom_in", callback_new_3(navit_zoom_in, this_, 2, NULL));
486         navit_command_register(this_, "zoom_out", callback_new_3(navit_zoom_out, this_, 2, NULL));
487         return this_;
488 }
489
490 static int
491 navit_set_gui(struct navit *this_, struct gui *gui)
492 {
493         if (this_->gui)
494                 return 0;
495         this_->gui=gui;
496         if (gui_has_main_loop(this_->gui)) {
497                 if (! main_loop_gui) {
498                         main_loop_gui=this_->gui;
499                 } else {
500                         dbg(0,"gui with main loop already active, ignoring this instance");
501                         return 0;
502                 }
503         }
504         return 1;
505 }
506
507 static int
508 navit_set_graphics(struct navit *this_, struct graphics *gra)
509 {
510         if (this_->gra)
511                 return 0;
512         this_->gra=gra;
513         this_->resize_callback=callback_new_attr_1(navit_resize, attr_resize, this_);
514         graphics_add_callback(gra, this_->resize_callback);
515         this_->button_callback=callback_new_attr_1(navit_button, attr_button, this_);
516         graphics_add_callback(gra, this_->button_callback);
517         this_->motion_callback=callback_new_attr_1(navit_motion, attr_motion, this_);
518         graphics_add_callback(gra, this_->motion_callback);
519         return 1;
520 }
521
522 struct graphics *
523 navit_get_graphics(struct navit *this_)
524 {
525         return this_->gra;
526 }
527
528 static void
529 navit_projection_set(struct navit *this_, enum projection pro)
530 {
531         struct coord_geo g;
532         struct coord *c;
533
534         c=transform_center(this_->trans);
535         transform_to_geo(transform_get_projection(this_->trans), c, &g);
536         transform_set_projection(this_->trans, pro);
537         transform_from_geo(pro, &g, c);
538         navit_draw(this_);
539 }
540
541 /**
542  * @param limit Limits the number of entries in the "backlog". Set to 0 for "infinite"
543  */
544 static void
545 navit_append_coord(struct navit *this_, char *file, struct pcoord *c, char *type, char *description, GHashTable *h, int limit)
546 {
547         FILE *f;
548         int offset=0;
549         char *buffer;
550         int ch,prev,lines=0;
551         int numc,readc;
552         int fd;
553         const char *prostr;
554         struct callback *cb;
555
556         f=fopen(file, "r");
557         if (!f)
558                 goto new_file;
559         if (limit != 0) {
560                 prev = '\n';
561                 while ((ch = fgetc(f)) != EOF) {
562                         if ((ch == '\n') && (prev != '\n')) {
563                                 lines++;
564                         }
565                         prev = ch;
566                 }
567
568                 if (prev != '\n') { // Last line did not end with a newline
569                         lines++;
570                 }
571
572                 fclose(f);
573                 f = fopen(file, "r+");
574                 fd = fileno(f);
575                 while (lines >= limit) { // We have to "scroll up"
576                         rewind(f);
577                         numc = 0; // Counts how many bytes we have in our line to scroll up
578                         while ((ch = fgetc(f)) != EOF) {
579                                 numc++;
580                                 if (ch == '\n') {
581                                         break;
582                                 }
583                         }
584
585                         buffer=g_malloc(numc);
586                         offset = numc; // Offset holds where we currently are
587                         
588                         do {
589                                 fseek(f,offset,SEEK_SET);
590                                 readc = fread(buffer,1,numc,f);
591                                 
592                                 fseek(f,-(numc+readc),SEEK_CUR);
593                                 fwrite(buffer,1,readc,f);
594
595                                 offset += readc;
596                         } while (readc == numc);
597
598                         g_free(buffer);
599                         fflush(f);
600                         ftruncate(fd,(offset-numc));
601 #ifdef HAVE_FSYNC
602                         fsync(fd);
603 #endif
604
605                         lines--;
606                 }
607                 fclose(f);
608         }
609
610 new_file:
611         f=fopen(file, "a");
612         if (f) {
613                 if (c) {
614                         prostr = projection_to_name(c->pro);
615                         fprintf(f,"%s%s%s0x%x %s0x%x type=%s label=\"%s\"\n",
616                                  prostr, *prostr ? ":" : "", 
617                                  c->x >= 0 ? "":"-", c->x >= 0 ? c->x : -c->x, 
618                                  c->y >= 0 ? "":"-", c->y >= 0 ? c->y : -c->y, 
619                                  type, description);
620                 } else
621                         fprintf(f,"\n");
622                 fclose(f);
623         }
624 }
625
626 static int
627 parse_line(FILE *f, char *buffer, char **name, struct pcoord *c)
628 {
629         int pos;
630         char *s,*i;
631         struct coord co;
632         char *cp;
633         enum projection pro = projection_mg;
634         *name=NULL;
635         if (! fgets(buffer, 2048, f))
636                 return -3;
637         cp = buffer;
638         pos=coord_parse(cp, pro, &co);
639         if (!pos)
640                 return -2;
641         if (!cp[pos] || cp[pos] == '\n')
642                 return -1;
643         cp[strlen(cp)-1]='\0';
644         s=cp+pos+1;
645         if (!strncmp(s,"type=", 5)) {
646                 i=strchr(s, '"');
647                 if (i) {
648                         s=i+1;
649                         i=strchr(s, '"');
650                         if (i)
651                                 *i='\0';
652                 }
653         }
654         *name=s;
655         c->x = co.x;
656         c->y = co.y;
657         c->pro = pro;
658         return pos;
659 }
660
661 /*
662  * navit_get_user_data_directory
663  * 
664  * returns the directory used to store user data files (center.txt,
665  * destination.txt, bookmark.txt, ...)
666  *
667  * arg: gboolean create: create the directory if it does not exist
668  */
669 static char*
670 navit_get_user_data_directory(gboolean create) {
671         char *dir;
672         dir = getenv("NAVIT_USER_DATADIR");
673         if (create && !file_exists(dir)) {
674                 dbg(0,"creating dir %s\n", dir);
675                 if (file_mkdir(dir,0)) {
676                         perror(dir);
677                         return;
678                 }
679         }
680
681         return dir;
682 }
683
684 /*
685  * navit_get_destination_file
686  * 
687  * returns the name of the file used to store destinations with its
688  * full path
689  *
690  * arg: gboolean create: create the directory where the file is stored
691  * if it does not exist
692  */
693 static char*
694 navit_get_destination_file(gboolean create)
695 {
696         return g_strjoin(NULL, navit_get_user_data_directory(create), "destination.txt", NULL);
697 }
698
699 /*
700  * navit_get_bookmark_file
701  * 
702  * returns the name of the file used to store bookmarks with its
703  * full path
704  *
705  * arg: gboolean create: create the directory where the file is stored
706  * if it does not exist
707  */
708 static char*
709 navit_get_bookmark_file(gboolean create)
710 {
711         return g_strjoin(NULL, navit_get_user_data_directory(create), "bookmark.txt", NULL);
712 }
713
714
715 /*
716  * navit_get_bookmark_file
717  * 
718  * returns the name of the file used to store the center file  with its
719  * full path
720  *
721  * arg: gboolean create: create the directory where the file is stored
722  * if it does not exist
723  */
724 static char*
725 navit_get_center_file(gboolean create)
726 {
727         return g_strjoin(NULL, navit_get_user_data_directory(create), "center.txt", NULL);
728 }
729
730 static void
731 navit_set_center_from_file(struct navit *this_, char *file)
732 {
733         FILE *f;
734         char *line = NULL;
735
736         size_t line_size = 0;
737         enum projection pro;
738         struct coord *center;
739
740         f = fopen(file, "r");
741         if (! f)
742                 return;
743         getline(&line, &line_size, f);
744         fclose(f);
745         if (line) {
746                 center = transform_center(this_->trans);
747                 pro = transform_get_projection(this_->trans);
748                 coord_parse(g_strchomp(line), pro, center);
749                 free(line);
750         }
751         return;
752 }
753  
754 static void
755 navit_write_center_to_file(struct navit *this_, char *file)
756 {
757         FILE *f;
758         enum projection pro;
759         struct coord *center;
760
761         f = fopen(file, "w+");
762         if (f) {
763                 center = transform_center(this_->trans);
764                 pro = transform_get_projection(this_->trans);
765                 coord_print(pro, center, f);
766                 fclose(f);
767         } else {
768                 perror(file);
769         }
770         return;
771 }
772
773
774 /**
775  * Start the route computing to a given set of coordinates
776  *
777  * @param navit The navit instance
778  * @param c The coordinate to start routing to
779  * @param description A label which allows the user to later identify this destination in the former destinations selection
780  * @returns nothing
781  */
782 void
783 navit_set_destination(struct navit *this_, struct pcoord *c, char *description)
784 {
785         if (c) {
786                 this_->destination=*c;
787                 this_->destination_valid=1;
788         } else
789                 this_->destination_valid=0;
790         char *destination_file = navit_get_destination_file(TRUE);
791         navit_append_coord(this_, destination_file, c, "former_destination", description, NULL, this_->recentdest_count);
792         g_free(destination_file);
793         callback_list_call_attr_0(this_->attr_cbl, attr_destination);
794         if (this_->route) {
795                 route_set_destination(this_->route, c);
796                 if (this_->navigation) {
797                         navigation_flush(this_->navigation);
798                         navigation_update(this_->navigation, this_->route);
799                 }
800
801                 navit_draw(this_);
802         }
803 }
804
805 /**
806  * @brief Checks if a route is calculated
807  *
808  * This function checks if a route is calculated.
809  *
810  * @param this_ The navit struct whose route should be checked.
811  * @return True if the route is set, false otherwise.
812  */
813 int
814 navit_check_route(struct navit *this_)
815 {
816         if (this_->route) {
817                 return route_get_path_set(this_->route);
818         }
819
820         return 0;
821 }
822
823 /**
824  * Record the given set of coordinates as a bookmark
825  *
826  * @param navit The navit instance
827  * @param c The coordinate to store
828  * @param description A label which allows the user to later identify this bookmark
829  * @returns nothing
830  */
831 void
832 navit_add_bookmark(struct navit *this_, struct pcoord *c, const char *description)
833 {
834         char *bookmark_file = navit_get_bookmark_file(TRUE);
835         navit_append_coord(this_,bookmark_file, c, "bookmark", description, this_->bookmarks_hash,0);
836         g_free(bookmark_file);
837
838         callback_list_call_attr_0(this_->attr_cbl, attr_bookmark_map);
839 }
840
841 struct navit *global_navit;
842
843 static void
844 navit_add_bookmarks_from_file(struct navit *this_)
845 {
846         char *bookmark_file = navit_get_bookmark_file(FALSE);
847         struct attr parent={attr_navit, .u.navit=this_};
848         struct attr type={attr_type, {"textfile"}}, data={attr_data, {bookmark_file}};
849         struct attr *attrs[]={&type, &data, NULL};
850
851         this_->bookmark=map_new(&parent, attrs);
852         g_free(bookmark_file);
853 }
854
855 static int
856 navit_former_destinations_active(struct navit *this_)
857 {
858         char *destination_file = navit_get_destination_file(FALSE);
859         FILE *f;
860         int active=0;
861         char buffer[3];
862         f=fopen(destination_file,"r");
863         if (f) {
864                 if(!fseek(f, -2, SEEK_END) && fread(buffer, 2, 1, f) == 1 && buffer[0]!='\n' || buffer[1]!='\n') 
865                         active=1;
866                 fclose(f);
867         }
868         g_free(destination_file);
869         return active;
870 }
871
872 static void
873 navit_add_former_destinations_from_file(struct navit *this_)
874 {
875         char *destination_file = navit_get_destination_file(FALSE);
876         struct attr parent={attr_navit, .u.navit=this_};
877         struct attr type={attr_type, {"textfile"}}, data={attr_data, {destination_file}};
878         struct attr *attrs[]={&type, &data, NULL};
879         struct map_rect *mr;
880         struct item *item;
881         int valid=0;
882         struct coord c;
883         struct pcoord pc;
884
885         this_->former_destination=map_new(&parent, attrs);
886         g_free(destination_file);
887         if (!this_->route || !navit_former_destinations_active(this_))
888                 return; 
889         mr=map_rect_new(this_->former_destination, NULL);
890         while ((item=map_rect_get_item(mr))) {
891                 if (item->type == type_former_destination && item_coord_get(item, &c, 1)) 
892                         valid=1;
893         }
894         map_rect_destroy(mr);
895         pc.pro=map_projection(this_->former_destination);
896         pc.x=c.x;
897         pc.y=c.y;
898         if (valid) 
899                 route_set_destination(this_->route, &pc);
900 }
901
902
903 static void
904 navit_textfile_debug_log(struct navit *this_, const char *fmt, ...)
905 {
906         va_list ap;
907         char *str1,*str2;
908         va_start(ap, fmt);
909         if (this_->textfile_debug_log && this_->vehicle) {
910                 str1=g_strdup_vprintf(fmt, ap);
911                 str2=g_strdup_printf("0x%x 0x%x%s%s\n", this_->vehicle->coord.x, this_->vehicle->coord.y, strlen(str1) ? " " : "", str1);
912                 log_write(this_->textfile_debug_log, str2, strlen(str2));
913                 g_free(str2);
914                 g_free(str1);
915         }
916         va_end(ap);
917 }
918
919 void
920 navit_say(struct navit *this_, char *text)
921 {
922         speech_say(this_->speech, text);
923 }
924
925 void
926 navit_speak(struct navit *this_)
927 {
928         struct navigation *nav=this_->navigation;
929         struct map *map=NULL;
930         struct map_rect *mr=NULL;
931         struct item *item;
932         struct attr attr;
933
934         if (nav)
935                 map=navigation_get_map(nav);
936         if (map)
937                 mr=map_rect_new(map, NULL);
938         if (mr) {
939                 item=map_rect_get_item(mr);
940                 if (item && item_attr_get(item, attr_navigation_speech, &attr)) {
941                         speech_say(this_->speech, attr.u.str);
942                         navit_textfile_debug_log(this_, "item=point_debug debug=\"speech_say('%s')\"", attr.u.str);
943                 }
944                 map_rect_destroy(mr);
945         }
946 }
947
948 static void
949 navit_window_roadbook_update(struct navit *this_)
950 {
951         struct navigation *nav=this_->navigation;
952         struct map *map=NULL;
953         struct map_rect *mr=NULL;
954         struct item *item;
955         struct attr attr;
956         struct param_list param[5];
957         int secs;
958
959         dbg(1,"enter\n");
960         datawindow_mode(this_->roadbook_window, 1);
961         if (nav)
962                 map=navigation_get_map(nav);
963         if (map)
964                 mr=map_rect_new(map, NULL);
965         dbg(0,"nav=%p map=%p mr=%p\n", nav, map, mr);
966         if (mr) {
967                 dbg(0,"while loop\n");
968                 while ((item=map_rect_get_item(mr))) {
969                         dbg(0,"item=%p\n", item);
970                         attr.u.str=NULL;
971                         item_attr_get(item, attr_navigation_long, &attr);
972                         dbg(2, "Command='%s'\n", attr.u.str);
973                         param[0].name=_("Command");
974                         param[0].value=g_strdup(attr.u.str);
975
976                         item_attr_get(item, attr_length, &attr);
977                         dbg(2, "Length=%d\n", attr.u.num);
978                         param[1].name=_("Length");
979
980                         if ( attr.u.num >= 2000 )
981                         {
982                                 param[1].value=g_strdup_printf("%5.1f %s",(float)attr.u.num / 1000, _("km") );
983                         }
984                         else
985                         {
986                                 param[1].value=g_strdup_printf("%7d %s",attr.u.num, _("m"));
987                         }
988
989                         item_attr_get(item, attr_time, &attr);
990                         dbg(2, "Time=%d\n", attr.u.num);
991                         secs=attr.u.num/10;
992                         param[2].name=_("Time");
993                         if ( secs >= 3600 )
994                         {
995                                 param[2].value=g_strdup_printf("%d:%02d:%02d",secs / 60, ( secs / 60 ) % 60 , secs % 60);
996                         }
997                         else
998                         {
999                                 param[2].value=g_strdup_printf("%d:%02d",secs / 60, secs % 60);
1000                         }
1001
1002                         item_attr_get(item, attr_destination_length, &attr);
1003                         dbg(2, "Destlength=%d\n", attr.u.num);
1004                         param[3].name=_("Destination Length");
1005                         if ( attr.u.num >= 2000 )
1006                         {
1007                                 param[3].value=g_strdup_printf("%5.1f %s",(float)attr.u.num / 1000, _("km") );
1008                         }
1009                         else
1010                         {
1011                                 param[3].value=g_strdup_printf("%d %s",attr.u.num, _("m"));
1012                         }
1013
1014                         item_attr_get(item, attr_destination_time, &attr);
1015                         dbg(2, "Desttime=%d\n", attr.u.num);
1016                         secs=attr.u.num/10;
1017                         param[4].name=_("Destination Time");
1018                         if ( secs >= 3600 )
1019                         {
1020                                 param[4].value=g_strdup_printf("%d:%02d:%02d",secs / 3600, (secs / 60 ) % 60 , secs % 60);
1021                         }
1022                         else
1023                         {
1024                                 param[4].value=g_strdup_printf("%d:%02d",secs / 60, secs % 60);
1025                         }
1026                         datawindow_add(this_->roadbook_window, param, 5);
1027                 }
1028                 map_rect_destroy(mr);
1029         }
1030         datawindow_mode(this_->roadbook_window, 0);
1031 }
1032
1033 void
1034 navit_window_roadbook_destroy(struct navit *this_)
1035 {
1036         dbg(0, "enter\n");
1037         navigation_unregister_callback(this_->navigation, attr_navigation_long, this_->roadbook_callback);
1038         this_->roadbook_window=NULL;
1039         this_->roadbook_callback=NULL;
1040 }
1041 void
1042 navit_window_roadbook_new(struct navit *this_)
1043 {
1044         if (this_->roadbook_callback || this_->roadbook_window) {
1045                 return;
1046         }
1047
1048         this_->roadbook_callback=callback_new_1(callback_cast(navit_window_roadbook_update), this_);
1049         navigation_register_callback(this_->navigation, attr_navigation_long, this_->roadbook_callback);
1050         this_->roadbook_window=gui_datawindow_new(this_->gui, _("Roadbook"), NULL, callback_new_1(callback_cast(navit_window_roadbook_destroy), this_));
1051         navit_window_roadbook_update(this_);
1052 }
1053
1054 static void
1055 get_direction(char *buffer, int angle, int mode)
1056 {
1057         angle=angle%360;
1058         switch (mode) {
1059         case 0:
1060                 sprintf(buffer,"%d",angle);
1061                 break;
1062         case 1:
1063                 if (angle < 69 || angle > 291)
1064                         *buffer++='N';
1065                 if (angle > 111 && angle < 249)
1066                         *buffer++='S';
1067                 if (angle > 22 && angle < 158)
1068                         *buffer++='E';
1069                 if (angle > 202 && angle < 338)
1070                         *buffer++='W';
1071                 *buffer++='\0';
1072                 break;
1073         case 2:
1074                 angle=(angle+15)/30;
1075                 if (! angle)
1076                         angle=12;
1077                 sprintf(buffer,"%d H", angle);
1078                 break;
1079         }
1080 }
1081
1082 struct navit_window_items {
1083         struct datawindow *win;
1084         struct callback *click;
1085         char *name;
1086         int distance;
1087         GHashTable *hash;
1088         GList *list;
1089 };
1090
1091 static void
1092 navit_window_items_click(struct navit *this_, struct navit_window_items *nwi, char **col)
1093 {
1094         struct pcoord c;
1095         char *description;
1096
1097         // FIXME
1098         dbg(0,"enter col=%s,%s,%s,%s,%s\n", col[0], col[1], col[2], col[3], col[4]);
1099         sscanf(col[4], "0x%x,0x%x", &c.x, &c.y);
1100         c.pro = projection_mg;
1101         dbg(0,"0x%x,0x%x\n", c.x, c.y);
1102         description=g_strdup_printf("%s %s", nwi->name, col[3]);
1103         navit_set_destination(this_, &c, description);
1104         g_free(description);
1105 }
1106
1107 static void
1108 navit_window_items_open(struct navit *this_, struct navit_window_items *nwi)
1109 {
1110         struct map_selection sel;
1111         struct coord c,*center;
1112         struct mapset_handle *h;
1113         struct map *m;
1114         struct map_rect *mr;
1115         struct item *item;
1116         struct attr attr;
1117         int idist,dist;
1118         struct param_list param[5];
1119         char distbuf[32];
1120         char dirbuf[32];
1121         char coordbuf[64];
1122
1123         dbg(0, "distance=%d\n", nwi->distance);
1124         if (nwi->distance == -1)
1125                 dist=40000000;
1126         else
1127                 dist=nwi->distance*1000;
1128         param[0].name="Distance";
1129         param[1].name="Direction";
1130         param[2].name="Type";
1131         param[3].name="Name";
1132         param[4].name=NULL;
1133         sel.next=NULL;
1134 #if 0
1135         sel.order[layer_town]=18;
1136         sel.order[layer_street]=18;
1137         sel.order[layer_poly]=18;
1138 #else
1139         sel.order[layer_town]=0;
1140         sel.order[layer_street]=0;
1141         sel.order[layer_poly]=0;
1142 #endif
1143         center=transform_center(this_->trans);
1144         sel.u.c_rect.lu.x=center->x-dist;
1145         sel.u.c_rect.lu.y=center->y+dist;
1146         sel.u.c_rect.rl.x=center->x+dist;
1147         sel.u.c_rect.rl.y=center->y-dist;
1148         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);
1149         nwi->click=callback_new_2(callback_cast(navit_window_items_click), this_, nwi);
1150         nwi->win=gui_datawindow_new(this_->gui, nwi->name, nwi->click, NULL);
1151         h=mapset_open(navit_get_mapset(this_));
1152         while ((m=mapset_next(h, 1))) {
1153 #if 0
1154                 dbg(2,"m=%p %s\n", m, map_get_filename(m));
1155 #endif
1156                 mr=map_rect_new(m, &sel);
1157                 dbg(2,"mr=%p\n", mr);
1158                 while ((item=map_rect_get_item(mr))) {
1159                         if (item_coord_get(item, &c, 1)) {
1160                                 if (coord_rect_contains(&sel.u.c_rect, &c) && g_hash_table_lookup(nwi->hash, &item->type)) {
1161                                         if (! item_attr_get(item, attr_label, &attr))
1162                                                 attr.u.str="";
1163                                         idist=transform_distance(map_projection(item->map), center, &c);
1164                                         if (idist < dist) {
1165                                                 get_direction(dirbuf, transform_get_angle_delta(center, &c, 0), 1);
1166                                                 param[0].value=distbuf;
1167                                                 param[1].value=dirbuf;
1168                                                 param[2].value=item_to_name(item->type);
1169                                                 sprintf(distbuf,"%d", idist/1000);
1170                                                 param[3].value=attr.u.str;
1171                                                 sprintf(coordbuf, "0x%x,0x%x", c.x, c.y);
1172                                                 param[4].value=coordbuf;
1173                                                 datawindow_add(nwi->win, param, 5);
1174                                         }
1175                                         /* printf("gefunden %s %s %d\n",item_to_name(item->type), attr.u.str, idist/1000); */
1176                                 }
1177                                 if (item->type >= type_line)
1178                                         while (item_coord_get(item, &c, 1));
1179                         }
1180                 }
1181                 map_rect_destroy(mr);
1182         }
1183         mapset_close(h);
1184 }
1185
1186 struct navit_window_items *
1187 navit_window_items_new(const char *name, int distance)
1188 {
1189         struct navit_window_items *nwi=g_new0(struct navit_window_items, 1);
1190         nwi->name=g_strdup(name);
1191         nwi->distance=distance;
1192         nwi->hash=g_hash_table_new(g_int_hash, g_int_equal);
1193
1194         return nwi;
1195 }
1196
1197 void
1198 navit_window_items_add_item(struct navit_window_items *nwi, enum item_type type)
1199 {
1200         nwi->list=g_list_prepend(nwi->list, (void *)type);
1201         g_hash_table_insert(nwi->hash, &nwi->list->data, (void *)1);
1202 }
1203
1204 void
1205 navit_add_window_items(struct navit *this_, struct navit_window_items *nwi)
1206 {
1207         this_->windows_items=g_list_append(this_->windows_items, nwi);
1208 }
1209
1210 static void
1211 navit_add_menu_windows_items(struct navit *this_, struct menu *men)
1212 {
1213         struct navit_window_items *nwi;
1214         struct callback *cb;
1215         GList *l;
1216         l=this_->windows_items;
1217         while (l) {
1218                 nwi=l->data;
1219                 cb=callback_new_2(callback_cast(navit_window_items_open), this_, nwi);
1220                 menu_add(men, nwi->name, menu_type_menu, cb);
1221                 l=g_list_next(l);
1222         }
1223 }
1224
1225 void
1226 navit_init(struct navit *this_)
1227 {
1228         struct mapset *ms;
1229         struct map *map;
1230         GList *l;
1231         struct navit_vehicle *nv;
1232
1233         if (!this_->gui) {
1234                 dbg(0,"no gui\n");
1235                 navit_destroy(this_);
1236                 return;
1237         }
1238         if (!this_->gra) {
1239                 dbg(0,"no graphics\n");
1240                 navit_destroy(this_);
1241                 return;
1242         }
1243         if (gui_set_graphics(this_->gui, this_->gra)) {
1244                 struct attr attr_type_gui, attr_type_graphics;
1245                 gui_get_attr(this_->gui, attr_type, &attr_type_gui, NULL);
1246                 graphics_get_attr(this_->gra, attr_type, &attr_type_graphics, NULL);
1247                 dbg(0,"failed to connect graphics '%s' to gui '%s'\n", attr_type_graphics.u.str, attr_type_gui.u.str);
1248                 dbg(0," Please see http://wiki.navit-project.org/index.php/Failed_to_connect_graphics_to_gui\n");
1249                 dbg(0," for explanations and solutions\n");
1250
1251                 navit_destroy(this_);
1252                 return;
1253         }
1254         graphics_init(this_->gra);
1255         l=this_->vehicles;
1256         while (l) {
1257                 dbg(1,"parsed one vehicle\n");
1258                 nv=l->data;
1259                 nv->cursor=cursor_new(this_->gra, &nv->c, nv->c2, nv->animate_cursor);
1260                 nv->callback.type=attr_callback;
1261                 nv->callback.u.callback=callback_new_2(callback_cast(navit_vehicle_update), this_, nv);
1262                 vehicle_add_attr(nv->vehicle, &nv->callback);
1263                 vehicle_set_attr(nv->vehicle, &this_->self, NULL);
1264                 l=g_list_next(l);
1265         }
1266         if (this_->mapsets) {
1267                 ms=this_->mapsets->data;
1268                 if (this_->route) {
1269                         if ((map=route_get_map(this_->route)))
1270                                 mapset_add_attr(ms, &(struct attr){attr_map,.u.map=map});
1271                         if ((map=route_get_graph_map(this_->route))) {
1272                                 mapset_add_attr(ms, &(struct attr){attr_map,.u.map=map});
1273                                 map_set_attr(map, &(struct attr ){attr_active,.u.num=0});
1274                         }
1275                         route_set_mapset(this_->route, ms);
1276                         route_set_projection(this_->route, transform_get_projection(this_->trans));
1277                 }
1278                 if (this_->tracking) {
1279                         tracking_set_mapset(this_->tracking, ms);
1280                         if (this_->route)
1281                                 tracking_set_route(this_->tracking, this_->route);
1282                 }
1283                 if (this_->navigation) {
1284                         if ((map=navigation_get_map(this_->navigation))) {
1285                                 mapset_add_attr(ms, &(struct attr){attr_map,.u.map=map});
1286                                 map_set_attr(map, &(struct attr ){attr_active,.u.num=0});
1287                         }
1288                 }
1289                 if (this_->tracking) {
1290                         if ((map=tracking_get_map(this_->tracking))) {
1291                                 mapset_add_attr(ms, &(struct attr){attr_map,.u.map=map});
1292                                 map_set_attr(map, &(struct attr ){attr_active,.u.num=0});
1293                         }
1294                 }
1295                 navit_add_bookmarks_from_file(this_);
1296                 navit_add_former_destinations_from_file(this_);
1297         }
1298         if (this_->navigation && this_->speech) {
1299                 this_->nav_speech_cb=callback_new_1(callback_cast(navit_speak), this_);
1300                 navigation_register_callback(this_->navigation, attr_navigation_speech, this_->nav_speech_cb);
1301         }
1302         char *center_file = navit_get_center_file(FALSE);
1303         navit_set_center_from_file(this_, center_file);
1304         g_free(center_file);
1305 #if 0
1306         if (this_->menubar) {
1307                 men=menu_add(this_->menubar, "Data", menu_type_submenu, NULL);
1308                 if (men) {
1309                         navit_add_menu_windows_items(this_, men);
1310                 }
1311         }
1312 #endif
1313         global_navit=this_;
1314 #if 0
1315         navit_window_roadbook_new(this_);
1316         navit_window_items_new(this_);
1317 #endif
1318         callback_list_call_attr_1(this_->attr_cbl, attr_navit, this_);
1319         this_->ready|=1;
1320         if (this_->ready == 3)
1321                 navit_draw(this_);
1322 }
1323
1324 /**
1325  * Change the current zoom level
1326  *
1327  * @param navit The navit instance
1328  * @param center The point where to center the map, including its projection
1329  * @returns nothing
1330  */
1331 void
1332 navit_set_center(struct navit *this_, struct pcoord *center)
1333 {
1334         struct coord *c=transform_center(this_->trans);
1335         struct coord c1,c2;
1336         enum projection pro = transform_get_projection(this_->trans);
1337         if (pro != center->pro) {
1338                 c1.x = center->x;
1339                 c1.y = center->y;
1340                 transform_from_to(&c1, center->pro, &c2, pro);
1341         } else {
1342                 c2.x = center->x;
1343                 c2.y = center->y;
1344         }
1345         *c=c2;
1346         if (this_->ready == 3)
1347                 navit_draw(this_);
1348 }
1349
1350 static void
1351 navit_set_center_cursor(struct navit *this_, struct coord *cursor, int dir, int xpercent, int ypercent)
1352 {
1353         struct coord *c=transform_center(this_->trans);
1354         int width, height;
1355         struct point p;
1356         struct coord cnew;
1357
1358         transform_get_size(this_->trans, &width, &height);
1359         *c=*cursor;
1360         transform_set_angle(this_->trans, dir);
1361         p.x=(100-xpercent)*width/100;
1362         p.y=(100-ypercent)*height/100;
1363         transform_reverse(this_->trans, &p, &cnew);
1364         *c=cnew;
1365         if (this_->ready == 3)
1366                 navit_draw(this_);
1367 }
1368
1369
1370 void
1371 navit_set_center_screen(struct navit *this_, struct point *p)
1372 {
1373         struct coord c;
1374         struct pcoord pc;
1375         transform_reverse(this_->trans, p, &c);
1376         pc.x = c.x;
1377         pc.y = c.y;
1378         pc.pro = transform_get_projection(this_->trans);
1379         navit_set_center(this_, &pc);
1380 }
1381
1382 int
1383 navit_set_attr(struct navit *this_, struct attr *attr)
1384 {
1385         int dir=0, orient_old=0, attr_updated=0;
1386
1387         switch (attr->type) {
1388         case attr_cursor:
1389                 if (this_->cursor_flag != !!attr->u.num) {
1390                         this_->cursor_flag=!!attr->u.num;
1391                         attr_updated=1;
1392                 }
1393                 break;
1394         case attr_layout:
1395                 if(this_->layout_current!=attr->u.layout) {
1396                         this_->layout_current=attr->u.layout;
1397                         graphics_font_destroy_all(this_->gra);
1398                         navit_draw(this_);
1399                         attr_updated=1;
1400                 }
1401                 break;
1402         case attr_orientation:
1403                 orient_old=this_->orient_north_flag;
1404                 this_->orient_north_flag=!!attr->u.num;
1405                 if (this_->orient_north_flag) {
1406                         dir = 0;
1407                 } else {
1408                         if (this_->vehicle) {
1409                                 dir = this_->vehicle->dir;
1410                         }
1411                 }
1412                 transform_set_angle(this_->trans, dir);
1413                 if (orient_old != this_->orient_north_flag) {
1414                         navit_draw(this_);
1415                         attr_updated=1;
1416                 }
1417                 break;
1418         case attr_projection:
1419                 if(this_->trans && transform_get_projection(this_->trans) != attr->u.projection) {
1420                         navit_projection_set(this_, attr->u.projection);
1421                         attr_updated=1;
1422                 }
1423                 break;
1424         case attr_tracking:
1425                 if (this_->tracking_flag != !!attr->u.num) {
1426                         this_->tracking_flag=!!attr->u.num;
1427                         attr_updated=1;
1428                 }
1429                 break;
1430         case attr_vehicle:
1431                 if (!this_->vehicle || this_->vehicle->vehicle != attr->u.vehicle) {
1432                         GList *l;
1433                         l=this_->vehicles;
1434                         while(l) {
1435                                 if (((struct navit_vehicle *)l->data)->vehicle == attr->u.vehicle) {
1436                                         this_->vehicle=(struct navit_vehicle *)l->data;
1437                                         attr_updated=1;
1438                                 }
1439                                 l=g_list_next(l);
1440                         }
1441                 }
1442                 break;
1443         default:
1444                 return 0;
1445         }
1446         if (attr_updated) {
1447                 callback_list_call_attr_2(this_->attr_cbl, attr->type, this_, attr);
1448         }
1449         return 1;
1450 }
1451
1452 int
1453 navit_get_attr(struct navit *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
1454 {
1455         switch (type) {
1456         case attr_bookmark_map:
1457                 attr->u.map=this_->bookmark;
1458                 break;
1459         case attr_cursor:
1460                 attr->u.num=this_->cursor_flag;
1461                 break;
1462         case attr_destination:
1463                 if (! this_->destination_valid)
1464                         return 0;
1465                 attr->u.pcoord=&this_->destination;
1466                 break;
1467         case attr_former_destination_map:
1468                 attr->u.map=this_->former_destination;
1469                 break;
1470         case attr_layout:
1471                 if (iter) {
1472                         if (iter->u.list) {
1473                                 iter->u.list=g_list_next(iter->u.list);
1474                         } else { 
1475                                 iter->u.list=this_->layouts;
1476                         }
1477                         if (!iter->u.list)
1478                                 return 0;
1479                         attr->u.layout=(struct layout *)iter->u.list->data;
1480                 } else {
1481                         attr->u.layout=this_->layout_current;
1482                 }
1483                 break;
1484         case attr_map:
1485                 if (iter && this_->mapsets) {
1486                         if (!iter->u.mapset_handle) {
1487                                 iter->u.mapset_handle=mapset_open((struct mapset *)this_->mapsets->data);
1488                         }
1489                         attr->u.map=mapset_next(iter->u.mapset_handle, 0);
1490                         if(!attr->u.map) {
1491                                 mapset_close(iter->u.mapset_handle);
1492                                 return 0;
1493                         }
1494                 } else {
1495                         return 0;
1496                 }
1497                 break;
1498         case attr_orientation:
1499                 attr->u.num=this_->orient_north_flag;
1500                 break;
1501         case attr_projection:
1502                 if(this_->trans) {
1503                         attr->u.num=transform_get_projection(this_->trans);
1504                 } else {
1505                         return 0;
1506                 }
1507                 break;
1508         case attr_tracking:
1509                 attr->u.num=this_->tracking_flag;
1510                 break;
1511         case attr_vehicle:
1512                 if(iter) {
1513                         if(iter->u.list) {
1514                                 iter->u.list=g_list_next(iter->u.list);
1515                         } else { 
1516                                 iter->u.list=this_->vehicles;
1517                         }
1518                         if(!iter->u.list)
1519                                 return 0;
1520                         attr->u.vehicle=((struct navit_vehicle*)iter->u.list->data)->vehicle;
1521                 } else {
1522                         if(this_->vehicle) {
1523                                 attr->u.vehicle=this_->vehicle->vehicle;
1524                         } else {
1525                                 return 0;
1526                         }
1527                 }
1528                 break;
1529         default:
1530                 return 0;
1531         }
1532         attr->type=type;
1533         return 1;
1534 }
1535
1536 static int
1537 navit_add_log(struct navit *this_, struct log *log)
1538 {
1539         struct attr type_attr;
1540         if (!log_get_attr(log, attr_type, &type_attr, NULL))
1541                 return 0;
1542         if (!strcmp(type_attr.u.str, "textfile_debug")) {
1543                 if (this_->textfile_debug_log)
1544                         return 0;
1545                 this_->textfile_debug_log=log;
1546                 return 1;
1547         }
1548         return 0;
1549 }
1550
1551 int
1552 navit_add_attr(struct navit *this_, struct attr *attr)
1553 {
1554         switch (attr->type) {
1555         case attr_log:
1556                 return navit_add_log(this_, attr->u.log);
1557         case attr_gui:
1558                 return navit_set_gui(this_, attr->u.gui);
1559         case attr_graphics:
1560                 return navit_set_graphics(this_, attr->u.graphics);
1561         case attr_layout:
1562                 this_->layouts = g_list_append(this_->layouts, attr->u.layout);
1563                 if(!this_->layout_current) 
1564                         this_->layout_current=attr->u.layout;
1565                 return 1;
1566         case attr_route:
1567                 this_->route=attr->u.route;
1568                 break;
1569         case attr_mapset:
1570                 this_->mapsets = g_list_append(this_->mapsets, attr->u.mapset);
1571                 break;
1572         case attr_navigation:
1573                 this_->navigation=attr->u.navigation;
1574                 break;
1575         case attr_recent_dest:
1576                 this_->recentdest_count = attr->u.num;
1577                 break;
1578         case attr_speech:
1579                 this_->speech=attr->u.speech;
1580                 break;
1581         case attr_tracking:
1582                 this_->tracking=attr->u.tracking;
1583                 break;
1584         case attr_vehicle:
1585                 return navit_add_vehicle(this_, attr->u.vehicle);
1586         default:
1587                 return 0;
1588         }
1589         return 1;
1590 }
1591
1592 struct attr_iter *
1593 navit_attr_iter_new()
1594 {
1595         return g_new0(struct attr_iter, 1);
1596 }
1597
1598 void
1599 navit_attr_iter_destroy(struct attr_iter *iter)
1600 {
1601         g_free(iter);
1602 }
1603
1604 void
1605 navit_add_callback(struct navit *this_, struct callback *cb)
1606 {
1607         callback_list_add(this_->attr_cbl, cb);
1608 }
1609
1610 void
1611 navit_remove_callback(struct navit *this_, struct callback *cb)
1612 {
1613         callback_list_remove(this_->attr_cbl, cb);
1614 }
1615
1616 /**
1617  * Toggle the cursor update : refresh the map each time the cursor has moved (instead of only when it reaches a border)
1618  *
1619  * @param navit The navit instance
1620  * @returns nothing
1621  */
1622
1623 static void
1624 navit_vehicle_draw(struct navit *this_, struct navit_vehicle *nv, struct point *pnt)
1625 {
1626         struct point pnt2;
1627         enum projection pro;
1628         if (this_->blocked)
1629                 return;
1630         if (pnt)
1631                 pnt2=*pnt;
1632         else {
1633                 pro=transform_get_projection(this_->trans);
1634                 transform(this_->trans, pro, &nv->coord, &pnt2, 1, 0);
1635         }
1636 #if 1
1637         cursor_draw(nv->cursor, &pnt2, nv->dir-transform_get_angle(this_->trans, 0), nv->speed > 2, pnt == NULL);
1638 #else
1639         cursor_draw(nv->cursor, &pnt2, nv->dir-transform_get_angle(this_->trans, 0), nv->speed > 2, 1);
1640 #endif
1641 }
1642
1643 static void
1644 navit_vehicle_update(struct navit *this_, struct navit_vehicle *nv)
1645 {
1646         struct attr attr_dir, attr_speed, attr_pos;
1647         struct pcoord cursor_pc;
1648         struct point cursor_pnt, *pnt=&cursor_pnt;
1649         enum projection pro;
1650         int border=16;
1651         int route_path_set=0;
1652
1653         if (this_->ready != 3)
1654                 return;
1655
1656         if (! vehicle_get_attr(nv->vehicle, attr_position_direction, &attr_dir, NULL) ||
1657             ! vehicle_get_attr(nv->vehicle, attr_position_speed, &attr_speed, NULL) ||
1658             ! vehicle_get_attr(nv->vehicle, attr_position_coord_geo, &attr_pos, NULL))
1659                 return;
1660         nv->dir=*attr_dir.u.numd;
1661         nv->speed=*attr_speed.u.numd;
1662         pro=transform_get_projection(this_->trans);
1663         transform_from_geo(pro, attr_pos.u.coord_geo, &nv->coord);
1664         if (nv != this_->vehicle) {
1665                 navit_vehicle_draw(this_, nv, NULL);
1666                 return;
1667         }
1668         if (this_->route)
1669                 route_path_set=route_get_path_set(this_->route);
1670         if (this_->tracking && this_->tracking_flag) {
1671                 if (tracking_update(this_->tracking, &nv->coord, nv->dir)) {
1672                         if (this_->route && nv->update_curr == 1) {
1673                                 route_set_position_from_tracking(this_->route, this_->tracking);
1674                                 callback_list_call_attr_0(this_->attr_cbl, attr_position);
1675                         }
1676                 }
1677         } else {
1678                 if (this_->route && nv->update_curr == 1) {
1679                         cursor_pc.pro = pro;
1680                         cursor_pc.x = nv->coord.x;
1681                         cursor_pc.y = nv->coord.y;
1682                         navit_set_position(this_, &cursor_pc);
1683                 }
1684         }
1685         transform(this_->trans, pro, &nv->coord, &cursor_pnt, 1, 0);
1686         if (!transform_within_border(this_->trans, &cursor_pnt, border)) {
1687                 if (!this_->cursor_flag)
1688                         return;
1689                 if (nv->follow_curr != 1) {
1690                         if (this_->orient_north_flag)
1691                                 navit_set_center_cursor(this_, &nv->coord, 0, 50 - 30.*sin(M_PI*nv->dir/180.), 50 + 30.*cos(M_PI*nv->dir/180.));
1692                         else
1693                                 navit_set_center_cursor(this_, &nv->coord, nv->dir, 50, 80);
1694                         pnt=NULL;
1695                 }
1696         }
1697
1698 #ifndef _WIN32
1699         if (this_->pid && nv->speed > 2)
1700                 kill(this_->pid, SIGWINCH);
1701 #endif
1702         if (this_->route && nv->update_curr == 1)
1703                 navigation_update(this_->navigation, this_->route);
1704         if (this_->cursor_flag && nv->follow_curr == 1) {
1705                 navit_set_center_cursor(this_, &nv->coord, nv->dir, 50, 80);
1706                 pnt=NULL;
1707         }
1708         if (pnt && this_->route && !route_path_set && route_get_path_set(this_->route))
1709                 navit_draw(this_);
1710         if (nv->follow_curr > 1)
1711                 nv->follow_curr--;
1712         else
1713                 nv->follow_curr=nv->follow;
1714         if (nv->update_curr > 1)
1715                 nv->update_curr--;
1716         else
1717                 nv->update_curr=nv->update;
1718         callback_list_call_attr_2(this_->attr_cbl, attr_position_coord_geo, this_, nv->vehicle);
1719         if (pnt)
1720                 navit_vehicle_draw(this_, nv, pnt);
1721
1722         /* Finally, if we reached our destination, stop navigation. */
1723         if (route_destination_reached(this_->route)) {
1724                 navit_set_destination(this_, NULL, NULL);
1725         }
1726 }
1727
1728 /**
1729  * Set the position of the vehicle
1730  *
1731  * @param navit The navit instance
1732  * @param c The coordinate to set as position
1733  * @returns nothing
1734  */
1735
1736 void
1737 navit_set_position(struct navit *this_, struct pcoord *c)
1738 {
1739         if (this_->route) {
1740                 route_set_position(this_->route, c);
1741                 callback_list_call_attr_0(this_->attr_cbl, attr_position);
1742                 if (this_->navigation) {
1743                         navigation_update(this_->navigation, this_->route);
1744                 }
1745         }
1746         navit_draw(this_);
1747 }
1748
1749 static void
1750 navit_set_vehicle(struct navit *this_, struct navit_vehicle *nv)
1751 {
1752         this_->vehicle=nv;
1753 }
1754
1755 /**
1756  * Register a new vehicle
1757  *
1758  * @param navit The navit instance
1759  * @param v The vehicle instance
1760  * @returns 1 for success
1761  */
1762 static int
1763 navit_add_vehicle(struct navit *this_, struct vehicle *v)
1764 {
1765         struct navit_vehicle *nv=g_new0(struct navit_vehicle, 1);
1766         struct attr update,follow,color,active, color2, animate;
1767         nv->vehicle=v;
1768         nv->update=1;
1769         nv->follow=0;
1770         nv->animate_cursor=0;
1771         if ((vehicle_get_attr(v, attr_update, &update, NULL)))
1772                 nv->update=nv->update=update.u.num;
1773         if ((vehicle_get_attr(v, attr_follow, &follow, NULL)))
1774                 nv->follow=nv->follow=follow.u.num;
1775         if ((vehicle_get_attr(v, attr_color, &color, NULL)))
1776                 nv->c=*(color.u.color);
1777         if ((vehicle_get_attr(v, attr_color2, &color2, NULL)))
1778                 nv->c2=color2.u.color;
1779         else
1780                 nv->c2=NULL;
1781         nv->update_curr=nv->update;
1782         nv->follow_curr=nv->follow;
1783         this_->vehicles=g_list_append(this_->vehicles, nv);
1784         if ((vehicle_get_attr(v, attr_active, &active, NULL)) && active.u.num)
1785                 navit_set_vehicle(this_, nv);
1786         if ((vehicle_get_attr(v, attr_animate, &animate, NULL)))
1787                 nv->animate_cursor=animate.u.num;
1788         return 1;
1789 }
1790
1791
1792
1793
1794 struct gui *
1795 navit_get_gui(struct navit *this_)
1796 {
1797         return this_->gui;
1798 }
1799
1800 struct transformation *
1801 navit_get_trans(struct navit *this_)
1802 {
1803         return this_->trans;
1804 }
1805
1806 struct route *
1807 navit_get_route(struct navit *this_)
1808 {
1809         return this_->route;
1810 }
1811
1812 struct navigation *
1813 navit_get_navigation(struct navit *this_)
1814 {
1815         return this_->navigation;
1816 }
1817
1818 struct displaylist *
1819 navit_get_displaylist(struct navit *this_)
1820 {
1821         return this_->displaylist;
1822 }
1823
1824 int
1825 navit_block(struct navit *this_, int block)
1826 {
1827         if (block) {
1828                 this_->blocked |= 1;
1829                 return;
1830         }
1831         if (this_->blocked & 2) {
1832                 this_->blocked=0;
1833                 navit_draw(this_);
1834                 return 1;
1835         }
1836         this_->blocked=0;
1837         return 0;
1838 }
1839
1840 int
1841 navit_command_register(struct navit *this_, char *command, struct callback *cb)
1842 {
1843         dbg(1,"registering '%s'\n", command);
1844         g_hash_table_insert(this_->commands, command, cb);
1845
1846         return 0;
1847 }
1848
1849 struct callback *
1850 navit_command_unregister(struct navit *this_, char *command)
1851 {
1852         struct callback *ret=g_hash_table_lookup(this_->commands, command);
1853         if (ret) {
1854                 g_hash_table_remove(this_->commands, command);
1855         }
1856
1857         return ret;
1858 }
1859
1860 int
1861 navit_command_call(struct navit *this_, char *command)
1862 {
1863         struct callback *cb=g_hash_table_lookup(this_->commands, command);
1864         dbg(0,"calling callback %p for '%s'\n", cb, command);
1865         if (! cb)
1866                 return 1;
1867         callback_call_1(cb, command);
1868 }
1869
1870 void
1871 navit_destroy(struct navit *this_)
1872 {
1873         /* TODO: destroy objects contained in this_ */
1874         main_remove_navit(this_);
1875         char *center_file = navit_get_center_file(TRUE);
1876         navit_write_center_to_file(this_, center_file);
1877         g_free(center_file);
1878         callback_destroy(navit_command_unregister(this_, "zoom_in"));
1879         callback_destroy(navit_command_unregister(this_, "zoom_out"));
1880         g_hash_table_destroy(this_->commands);
1881         g_free(this_);
1882 }
1883
1884 /** @} */