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