]> err.no Git - mapper/blob - src/map.c
Use lat, lon for location query
[mapper] / src / map.c
1 #include <config.h>
2
3 #define _GNU_SOURCE
4
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <strings.h>
9 #include <stddef.h>
10 #include <locale.h>
11 #include <math.h>
12 #include <errno.h>
13 #include <sys/wait.h>
14 #include <glib/gstdio.h>
15 #include <gtk/gtk.h>
16 #include <fcntl.h>
17 #include <libintl.h>
18 #include <locale.h>
19
20 #include "hildon-mapper.h"
21
22 #include "utils.h"
23 #include "map.h"
24 #include "osm.h"
25 #include "db.h"
26 #include "osm-db.h"
27 #include "poi.h"
28 #include "route.h"
29 #include "track.h"
30 #include "gps.h"
31 #include "bt.h"
32 #include "mapper-types.h"
33 #include "ui-common.h"
34 #include "settings.h"
35 #include "latlon.h"
36 #include "gpx.h"
37 #include "speak.h"
38 #include "map-poi.h"
39 #include "map-download.h"
40
41 #include "gtkcompass.h"
42
43 /** The "base tile" is the upper-left tile in the pixmap. */
44 guint _base_tilex = -5;
45 guint _base_tiley = -5;
46
47 guint _zoom = 3;                /* zoom level, from 0 to MAX_ZOOM. */
48
49 Point _min_center = { -1, -1 };
50 Point _max_center = { -1, -1 };
51 Point _focus = { -1, -1 };
52 Point _center = { -1, -1 };     /* current center location, X. */
53
54 CenterMode _center_mode = CENTER_LEAD;
55
56 /* Drag */
57 static guint press[2] = { 0, 0 };
58 static guint release[2] = { 0, 0 };
59 static guint before[2] = { 0, 0 };
60 static guint map_drag_id = 0;
61
62 /** VARIABLES FOR ACCESSING THE LOCATION/BOUNDS OF THE CURRENT MARK. */
63 static gint _mark_x1;
64 static gint _mark_x2;
65 static gint _mark_y1;
66 static gint _mark_y2;
67 static gint _mark_minx;
68 static gint _mark_miny;
69 static gint _mark_width;
70 static gint _mark_height;
71
72 static gint zoom_timeout_sid=0;
73 static gint map_mode=0;
74 static gboolean map_data_needs_refresh=FALSE;
75
76 static osm_location map_loc = {NULL, NULL, NULL, FALSE, FALSE, 0, 0, 0.0, 0.0, 0 };
77
78 typedef struct _map_tile_rdata map_tile_rdata;
79 struct _map_tile_rdata {
80         guint tilex, tiley, zoom;
81         guint destx, desty;
82 };
83
84 /* Tile max age, 1 week */
85 #define TILE_MAX_AGE (604800)
86
87 void map_render_paths();
88 void map_force_redraw();
89 static void map_update_location(gdouble lat, gdouble lon, gboolean force);
90 void map_draw_position_icon(Position *pos);
91
92 /******************************************************************************/
93
94 GtkWidget * 
95 map_new(void) 
96 {
97 return GTK_WIDGET(gtk_drawing_area_new());
98 }
99
100 gboolean 
101 map_cb_configure(GtkWidget *widget, GdkEventConfigure *event)
102 {
103 _screen_width_pixels = _map_widget->allocation.width;
104 _screen_height_pixels = _map_widget->allocation.height;
105 _screen_grids_halfwidth = pixel2grid(_screen_width_pixels) / 2;
106 _screen_grids_halfheight = pixel2grid(_screen_height_pixels) / 2;
107
108 /* Set _scale_rect. */
109 _scale_rect.x = (_screen_width_pixels - SCALE_WIDTH) / 2;
110 _scale_rect.width = SCALE_WIDTH;
111 pango_layout_set_text(_scale_layout, "0", -1);
112 pango_layout_get_pixel_size(_scale_layout, NULL, &_scale_rect.height);
113 _scale_rect.y = _screen_height_pixels - _scale_rect.height - 1;
114
115 MACRO_RECALC_FOCUS_BASE();
116 MACRO_RECALC_FOCUS_SIZE();
117
118 _min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth));
119 _min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight));
120 _max_center.unitx = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfwidth) - 1;
121 _max_center.unity = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfheight) - 1;
122
123 map_center_unit(_center.unitx, _center.unity);
124
125 return TRUE;
126 }
127
128 /**
129  * Draw the current mark (representing the current GPS location) onto
130  * _map_widget.  This method does not queue the draw area.
131  */
132 static void 
133 map_draw_mark(void)
134 {
135 gdk_draw_arc(_map_widget->window, _conn_state == RCVR_FIXED ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD], FALSE,
136      _mark_x1 - _draw_width, _mark_y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, 360 * 64);
137 gdk_draw_line(_map_widget->window, _conn_state == RCVR_FIXED ? (_show_velvec ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK]) : _gc[COLORABLE_MARK_OLD],
138       _mark_x1, _mark_y1, _mark_x2, _mark_y2);
139 }
140
141 /**
142  * "Set" the mark, which translates the current GPS position into on-screen
143  * units in preparation for drawing the mark with map_draw_mark().
144  */
145 void 
146 map_set_mark(void)
147 {
148 _mark_x1 = unit2x(_pos.unitx);
149 _mark_y1 = unit2y(_pos.unity);
150 _mark_x2 = _mark_x1 + (_show_velvec ? _gps.vel_offsetx : 0);
151 _mark_y2 = _mark_y1 + (_show_velvec ? _gps.vel_offsety : 0);
152 _mark_minx = MIN(_mark_x1, _mark_x2) - (2 * _draw_width);
153 _mark_miny = MIN(_mark_y1, _mark_y2) - (2 * _draw_width);
154 _mark_width = abs(_mark_x1 - _mark_x2) + (4 * _draw_width);
155 _mark_height = abs(_mark_y1 - _mark_y2) + (4 * _draw_width);
156 }
157
158 /**
159  * Do an in-place scaling of a pixbuf's pixels at the given ratio from the
160  * given source location.  It would have been nice if gdk_pixbuf provided
161  * this method, but I guess it's not general-purpose enough.
162  */
163 static void
164 map_pixbuf_scale_inplace(GdkPixbuf * pixbuf, guint ratio_p2, guint src_x, guint src_y)
165 {
166 guint dest_x = 0, dest_y = 0, dest_dim = TILE_SIZE_PIXELS;
167 guint rowstride = gdk_pixbuf_get_rowstride(pixbuf);
168 guint n_channels = gdk_pixbuf_get_n_channels(pixbuf);
169 guchar *pixels = gdk_pixbuf_get_pixels(pixbuf);
170
171 /* Sweep through the entire dest area, copying as necessary, but
172  * DO NOT OVERWRITE THE SOURCE AREA.  We'll copy it afterward. */
173 do {
174         guint src_dim = dest_dim >> ratio_p2;
175         guint src_endx = src_x - dest_x + src_dim;
176         gint x, y;
177
178         for (y = dest_dim - 1; y >= 0; y--) {
179                 guint src_offset_y, dest_offset_y;
180
181                 src_offset_y = (src_y + (y >> ratio_p2)) * rowstride;
182                 dest_offset_y = (dest_y + y) * rowstride;
183                 x = dest_dim - 1;
184
185                 if ((unsigned)(dest_y + y - src_y) < src_dim && (unsigned)(dest_x + x - src_x) < src_dim)
186                         x -= src_dim;
187
188                 for (; x >= 0; x--) {
189                         guint src_offset, dest_offset, i;
190
191                         src_offset = src_offset_y + (src_x + (x >> ratio_p2)) * n_channels;
192                         dest_offset = dest_offset_y + (dest_x + x) * n_channels;
193
194                         pixels[dest_offset] = pixels[src_offset];
195                         for (i = n_channels - 1; i; i--)
196                                 pixels[dest_offset + i] = pixels[src_offset + i];
197
198                         if ((unsigned)(dest_y + y - src_y) < src_dim && x == src_endx)
199                                 x -= src_dim;
200                 }
201         }
202
203         /* Reuse src_dim and src_endx to store new src_x and src_y. */
204         src_dim = src_x + ((src_x - dest_x) >> ratio_p2);
205         src_endx = src_y + ((src_y - dest_y) >> ratio_p2);
206         dest_x = src_x;
207         dest_y = src_y;
208         src_x = src_dim;
209         src_y = src_endx;
210 }
211 while ((dest_dim >>= ratio_p2) > 1);
212 }
213
214 /**
215  * Trim pixbufs that are bigger than tiles. (Those pixbufs result, when
216  * captions should be cut off.)
217  */
218 static GdkPixbuf *
219 pixbuf_trim(GdkPixbuf * pixbuf)
220 {
221 GdkPixbuf *mpixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha(pixbuf),
222                    8, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
223
224 gdk_pixbuf_copy_area(pixbuf,
225                      (gdk_pixbuf_get_width(pixbuf) - TILE_SIZE_PIXELS) / 2,
226                      (gdk_pixbuf_get_height(pixbuf) - TILE_SIZE_PIXELS) / 2, 
227                      TILE_SIZE_PIXELS,
228                      TILE_SIZE_PIXELS, mpixbuf, 0, 0);
229
230 g_object_unref(pixbuf);
231 return mpixbuf;
232 }
233
234 static GdkPixbuf *
235 map_tile_load(guint tilex, guint tiley, gint zoff, gboolean download)
236 {
237 GdkPixbuf *pixbuf;
238 GError *error = NULL;
239 gchar buffer[BUFFER_SIZE];
240 struct stat tstat;
241 gint se;
242
243 snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg", _curr_repo->cache_dir, _zoom + zoff, (tilex >> zoff), (tiley >> zoff));
244
245 pixbuf=gdk_pixbuf_new_from_file(buffer, &error);
246 if (error || !pixbuf) {
247         g_unlink(buffer);
248
249         if (_auto_download && _curr_repo->type != REPOTYPE_NONE && !((_zoom + zoff - (_curr_repo->double_size ? 1 : 0)) % _curr_repo->dl_zoom_steps)) {
250                 if (download)
251                         map_initiate_download(tilex >> zoff, tiley >> zoff, _zoom + zoff, -INITIAL_DOWNLOAD_RETRIES);
252         }
253
254         return NULL;
255 }
256
257 /* Check tile age, if file date is ower a week old, redownload if autodownload enabled */
258 se=stat(buffer, &tstat);
259 if (se==0) {
260         time_t t;
261         t=time(NULL);
262         if (t-tstat.st_mtime>TILE_MAX_AGE) {
263                 if (_auto_download && _curr_repo->type != REPOTYPE_NONE && !((_zoom + zoff - (_curr_repo->double_size ? 1 : 0)) % _curr_repo->dl_zoom_steps)) {
264                         if (download) {
265                                 g_printf("Tile: %s is old, re-downloading\n", buffer);
266                                 map_initiate_download(tilex >> zoff, tiley >> zoff, _zoom + zoff, -INITIAL_DOWNLOAD_RETRIES);
267                         }
268                 }
269         }
270 }
271
272 return pixbuf;
273 }
274
275 void
276 map_render_tile(guint tilex, guint tiley, guint destx, guint desty, gboolean fast_fail)
277 {
278 GdkPixbuf *pixbuf=NULL;
279 gint zoff;
280
281 if (tilex<_world_size_tiles && tiley<_world_size_tiles) {
282         /* The tile is possible. */
283         for (zoff = (_curr_repo->double_size ? 1 : 0); !pixbuf && (_zoom + zoff) <= MAX_ZOOM && zoff <= TILE_SIZE_P2; zoff += 1) {
284                 pixbuf=map_tile_load(tilex, tiley, zoff, !fast_fail);
285                 if (!pixbuf) {
286                         if (!fast_fail)
287                                 fast_fail=TRUE;
288                 } else {
289                         /* Check if we need to trim. */
290                         if (gdk_pixbuf_get_width(pixbuf) != TILE_SIZE_PIXELS || gdk_pixbuf_get_height(pixbuf) != TILE_SIZE_PIXELS)
291                                 pixbuf = pixbuf_trim(pixbuf);
292
293                         /* Check if we need to blit. */
294                         if (zoff) {
295                                 map_pixbuf_scale_inplace(pixbuf, zoff,
296                                                  (tilex - ((tilex >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff),
297                                                  (tiley - ((tiley >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff));
298                         }
299                 }
300         }
301 }
302
303 if (pixbuf) {
304         gdk_draw_pixbuf(_map_pixmap, _gc[COLORABLE_MARK], pixbuf, 0, 0, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS, GDK_RGB_DITHER_NONE, 0, 0);
305         g_object_unref(pixbuf);
306         return;
307 }
308 gdk_draw_rectangle(_map_pixmap, _map_widget->style->black_gc, TRUE, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
309 }
310
311 gboolean 
312 map_render_tile_idle(map_tile_rdata *mtr)
313 {
314 map_render_tile(mtr->tilex, mtr->tiley, mtr->destx, mtr->desty, FALSE);
315 gtk_widget_queue_draw_area(_map_widget, mtr->destx, mtr->desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
316
317 g_slice_free(map_tile_rdata, mtr);
318 return FALSE;
319 }
320
321 void
322 map_render_data(void)
323 {
324 /* Don't update if dragging, too much lag */
325 if (map_drag_id>0)
326         return;
327
328 if (_home.valid)
329         map_draw_position_icon(&_home);
330 if(_show_poi)
331         map_render_poi();
332 if(_show_tracks>0)
333         map_render_paths();
334 }
335
336 /**
337  * Force a redraw of the entire _map_pixmap, including fetching the
338  * background maps from disk and redrawing the tracks on top of them.
339  */
340 void 
341 map_force_redraw(void)
342 {
343 guint new_x, new_y;
344
345 for (new_y = 0; new_y < BUF_HEIGHT_TILES; ++new_y)
346         for (new_x = 0; new_x < BUF_WIDTH_TILES; ++new_x) {
347                 map_render_tile(_base_tilex + new_x,
348                                 _base_tiley + new_y,
349                                 new_x * TILE_SIZE_PIXELS,
350                                 new_y * TILE_SIZE_PIXELS, FALSE);
351         }
352 map_render_data();
353 MACRO_QUEUE_DRAW_AREA();
354 }
355
356 /**
357  * Set the current zoom level.  If the given zoom level is the same as the
358  * current zoom level, or if the new zoom is invalid
359  * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing.
360  */
361 void 
362 map_set_zoom(guint new_zoom)
363 {
364 /* Note that, since new_zoom is a guint and MIN_ZOOM is 0, this if
365  * condition also checks for new_zoom >= MIN_ZOOM. */
366 if (new_zoom > (MAX_ZOOM - 1))
367         return;
368 if (new_zoom == _zoom)
369         return;
370
371 _zoom = new_zoom / _curr_repo->view_zoom_steps * _curr_repo->view_zoom_steps;
372 _world_size_tiles = unit2tile(WORLD_SIZE_UNITS);
373
374 /* If we're leading, update the center to reflect new zoom level. */
375 MACRO_RECALC_CENTER(_center.unitx, _center.unity);
376
377 /* Update center bounds to reflect new zoom level. */
378 _min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth));
379 _min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight));
380 _max_center.unitx = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfwidth) - 1;
381 _max_center.unity = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfheight) - 1;
382
383 BOUND(_center.unitx, _min_center.unitx, _max_center.unitx);
384 BOUND(_center.unity, _min_center.unity, _max_center.unity);
385
386 _base_tilex = grid2tile((gint) pixel2grid((gint) unit2pixel((gint) _center.unitx)) - (gint) _screen_grids_halfwidth);
387 _base_tiley = grid2tile(pixel2grid(unit2pixel(_center.unity)) - _screen_grids_halfheight);
388
389 /* New zoom level, so we can't reuse the old buffer's pixels. */
390 /* Update state variables. */
391 MACRO_RECALC_OFFSET();
392 MACRO_RECALC_FOCUS_BASE();
393 MACRO_RECALC_FOCUS_SIZE();
394
395 map_set_mark();
396 map_force_redraw();
397 }
398
399 /**
400  * Center the view on the given unitx/unity.
401  */
402 void 
403 map_center_unit(guint new_center_unitx, guint new_center_unity)
404 {
405 gint new_base_tilex, new_base_tiley;
406 guint new_x, new_y;
407 guint j, k, base_new_x, base_old_x, old_x, old_y, iox, ioy;
408
409 /* Assure that _center.unitx/y are bounded. */
410 BOUND(new_center_unitx, _min_center.unitx, _max_center.unitx);
411 BOUND(new_center_unity, _min_center.unity, _max_center.unity);
412
413 _center.unitx = new_center_unitx;
414 _center.unity = new_center_unity;
415
416 new_base_tilex = grid2tile((gint) pixel2grid((gint)unit2pixel((gint) _center.unitx))
417                            - (gint)_screen_grids_halfwidth);
418 new_base_tiley = grid2tile(pixel2grid(unit2pixel(_center.unity))
419                            - _screen_grids_halfheight);
420
421 /* Same zoom level, so it's likely that we can reuse some of the old
422  * buffer's pixels. */
423
424 if (new_base_tilex != _base_tilex || new_base_tiley != _base_tiley) {
425         /* If copying from old parts to new parts, we need to make sure we
426          * don't overwrite the old parts when copying, so set up new_x,
427          * new_y, old_x, old_y, iox, and ioy with that in mind. */
428         if (new_base_tiley < _base_tiley) {
429                 /* New is lower than old - start at bottom and go up. */
430                 new_y = BUF_HEIGHT_TILES - 1;
431                 ioy = -1;
432         } else {
433                 /* New is higher than old - start at top and go down. */
434                 new_y = 0;
435                 ioy = 1;
436         }
437         if (new_base_tilex < _base_tilex) {
438                 /* New is righter than old - start at right and go left. */
439                 base_new_x = BUF_WIDTH_TILES - 1;
440                 iox = -1;
441         } else {
442                 /* New is lefter than old - start at left and go right. */
443                 base_new_x = 0;
444                 iox = 1;
445         }
446
447         /* Iterate over the y tile values. */
448         old_y = new_y + new_base_tiley - _base_tiley;
449         base_old_x = base_new_x + new_base_tilex - _base_tilex;
450         _base_tilex = new_base_tilex;
451         _base_tiley = new_base_tiley;
452         for (j = 0; j < BUF_HEIGHT_TILES; ++j, new_y += ioy, old_y += ioy) {
453                 new_x = base_new_x;
454                 old_x = base_old_x;
455                 /* Iterate over the x tile values. */
456                 for (k = 0; k < BUF_WIDTH_TILES;
457                      ++k, new_x += iox, old_x += iox) {
458                         /* Can we get this grid block from the old buffer?. */
459                         if (old_x >= 0 && old_x < BUF_WIDTH_TILES
460                             && old_y >= 0 && old_y < BUF_HEIGHT_TILES) {
461                                 /* Copy from old buffer to new buffer. */
462                                 gdk_draw_drawable(_map_pixmap,
463                                                   _gc[COLORABLE_MARK],
464                                                   _map_pixmap,
465                                                   old_x * TILE_SIZE_PIXELS,
466                                                   old_y * TILE_SIZE_PIXELS,
467                                                   new_x * TILE_SIZE_PIXELS,
468                                                   new_y * TILE_SIZE_PIXELS,
469                                                   TILE_SIZE_PIXELS,
470                                                   TILE_SIZE_PIXELS);
471                         } else {
472                                 map_render_tile(new_base_tilex + new_x,
473                                                 new_base_tiley + new_y,
474                                                 new_x * TILE_SIZE_PIXELS,
475                                                 new_y * TILE_SIZE_PIXELS,
476                                                 FALSE);
477                         }
478                 }
479         }
480         map_render_data();
481 }
482
483 MACRO_RECALC_OFFSET();
484 MACRO_RECALC_FOCUS_BASE();
485
486 map_set_mark();
487 MACRO_QUEUE_DRAW_AREA();
488 }
489
490 /**
491  * Pan the view by the given number of units in the X and Y directions.
492  */
493 void 
494 map_pan(gint delta_unitx, gint delta_unity)
495 {
496 if (_center_mode > 0)
497         set_action_activate("autocenter_none", TRUE);
498
499 map_center_unit(_center.unitx + delta_unitx, _center.unity + delta_unity);
500 }
501
502 /**
503  * Helper to center map on given lat/lon
504  */
505 void
506 map_center_latlon(gdouble lat, gdouble lon)
507 {
508 guint unitx, unity;
509
510 latlon2unit(lat, lon, unitx, unity);
511 map_center_unit(unitx, unity);
512 }
513
514 /**
515  * Helper to goto given point and update location
516  * 
517  */
518 gboolean
519 map_goto_position(Position *pos)
520 {
521 if (pos->valid==FALSE)
522         return FALSE;
523
524 _center_mode=CENTER_MANUAL;
525 map_center_latlon(pos->lat, pos->lon);
526 map_set_autozoom(FALSE);
527 g_idle_add((GSourceFunc)map_update_location_from_center, NULL);
528 return TRUE;
529 }
530
531 /**
532  * Initiate a move of the mark from the old location to the current
533  * location.  This function queues the draw area of the old mark (to force
534  * drawing of the background map), then updates the mark, then queus the
535  * draw area of the new mark.
536  */
537 void 
538 map_move_mark(void)
539 {
540 /* Just queue the old and new draw areas. */
541 gtk_widget_queue_draw_area(_map_widget,
542                    _mark_minx<0 ? 0 : _mark_minx,
543                    _mark_miny<0 ? 0 : _mark_miny, 
544                    _mark_width, _mark_height);
545 map_set_mark();
546 gtk_widget_queue_draw_area(_map_widget,
547                    _mark_minx<0 ? 0 : _mark_minx,
548                    _mark_miny<0 ? 0 : _mark_miny, 
549                    _mark_width, _mark_height);
550 }
551
552 gboolean
553 map_update_location_from_gps(void)
554 {
555 map_update_location(_gps.lat, _gps.lon, FALSE);
556 return FALSE;
557 }
558
559 gboolean
560 map_update_location_from_center(void)
561 {
562 gdouble lat, lon;
563 /* Force re-validation of place if user is clicking around */
564 map_loc.valid=FALSE;
565 /* XXX: hmm, not the right place for this */
566 if (_gps.fix<2) {
567         _pos.unitx=_center.unitx;
568         _pos.unity=_center.unity;
569         unit2latlon(_pos.unitx, _pos.unity, _gps.lat, _gps.lon);
570 }
571 unit2latlon(_center.unitx, _center.unity, lat, lon);
572 map_update_location(lat, lon, TRUE);
573 return FALSE;
574 }
575
576 /**
577  * Draw given pixbuf on map, centered on x,y
578  */
579 void
580 map_draw_pixbuf(guint unitx, guint unity, GdkPixbuf *p)
581 {
582 gint x,y;
583 x = unit2bufx(unitx);
584 y = unit2bufy(unity);
585
586 gdk_draw_pixbuf(_map_pixmap, _gc[COLORABLE_POI],
587         p, 0, 0,
588         x - gdk_pixbuf_get_width(p) / 2,
589         y - gdk_pixbuf_get_height(p) / 2,
590         -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
591 }
592
593 /**
594  * Draw an icon on given Position.
595  * 
596  * XXX: don't hardcode as home.png !
597  */
598 void
599 map_draw_position_icon(Position *pos)
600 {
601 guint x,y, x1,y1;
602 GdkPixbuf *p;
603
604 latlon2unit(pos->lat, pos->lon, x, y);
605 x1=unit2bufx(x);
606 y1=unit2bufy(y);
607
608 if ((x1 > BUF_WIDTH_PIXELS) || (y1 > BUF_HEIGHT_PIXELS))
609         return;
610
611 p=gdk_pixbuf_new_from_file(DATADIR "/pixmaps/mapper/home.png", NULL);
612 if (p) {
613         map_draw_pixbuf(x,y,p);
614         g_object_unref(p);
615 }
616
617 }
618
619 /**
620  * Make sure the mark is up-to-date.  This function triggers a panning of
621  * the view if the mark is appropriately close to the edge of the view.
622  */
623 void
624 map_refresh_mark(void)
625 {
626 guint new_center_unitx;
627 guint new_center_unity;
628
629 MACRO_RECALC_CENTER(new_center_unitx, new_center_unity);
630
631 if ((new_center_unitx - _focus.unitx) < _focus_unitwidth
632     && (new_center_unity - _focus.unity) < _focus_unitheight)
633         /* We're not changing the view - just move the mark. */
634         map_move_mark();
635 else
636         map_center_unit(new_center_unitx, new_center_unity);
637
638 /* Draw speed info */
639 if (_speed_limit_on)
640         speed_limit();
641
642 if (_center_mode>0)
643         g_idle_add((GSourceFunc)map_update_location_from_gps, NULL);
644 }
645
646 /**
647  * Render a single track line to _map_pixmap.  If either point on the line
648  * is a break (defined as unity == 0), a circle is drawn at the other point.
649  * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK.
650  */
651 void
652 map_render_segment(GdkGC * gc_norm, GdkGC * gc_alt, guint unitx1, guint unity1, guint unitx2, guint unity2)
653 {
654         if (!unity1) {
655                 guint x2, y2;
656                 x2 = unit2bufx(unitx2);
657                 y2 = unit2bufy(unity2);
658                 /* Make sure this circle will be visible. */
659                 if ((x2 < BUF_WIDTH_PIXELS) && (y2 < BUF_HEIGHT_PIXELS))
660                         gdk_draw_arc(_map_pixmap, gc_alt, FALSE,        /* FALSE: not filled. */
661                                      x2 - _draw_width, y2 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
662                                      360 * 64);
663         } else if (!unity2) {
664                 guint x1, y1;
665                 x1 = unit2bufx(unitx1);
666                 y1 = unit2bufy(unity1);
667                 /* Make sure this circle will be visible. */
668                 if ((x1 < BUF_WIDTH_PIXELS) && ((unsigned)y1 < BUF_HEIGHT_PIXELS))
669                         gdk_draw_arc(_map_pixmap, gc_alt, FALSE,        /* FALSE: not filled. */
670                                      x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
671                                      360 * 64);
672         } else {
673                 gint x1, y1, x2, y2;
674                 x1 = unit2bufx(unitx1);
675                 y1 = unit2bufy(unity1);
676                 x2 = unit2bufx(unitx2);
677                 y2 = unit2bufy(unity2);
678                 /* Make sure this line could possibly be visible. */
679                 if (!((x1 > BUF_WIDTH_PIXELS && x2 > BUF_WIDTH_PIXELS)
680                       || (x1 < 0 && x2 < 0)
681                       || (y1 > BUF_HEIGHT_PIXELS && y2 > BUF_HEIGHT_PIXELS)
682                       || (y1 < 0 && y2 < 0)))
683                         gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
684         }
685 }
686
687 /**
688  * Render all track data onto the _map_pixmap.  Note that this does not
689  * clear the pixmap of previous track data (use map_force_redraw() for
690  * that), and also note that this method does not queue any redraws, so it
691  * is up to the caller to decide which part of the track really needs to be
692  * redrawn.
693  */
694 void 
695 map_render_path(Path * path, GdkGC ** gc)
696 {
697         Point *curr;
698         WayPoint *wcurr;
699
700         /* gc is a pointer to the first GC to use (for plain points).  (gc + 1)
701          * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer
702          * to the GC to use for breaks. */
703
704         /* else there is a route to draw. */
705         for (curr = path->head, wcurr = path->whead; curr++ != path->tail;) {
706                 /* Draw the line from (curr - 1) to (curr). */
707                 map_render_segment(gc[0], gc[2],
708                                    curr[-1].unitx, curr[-1].unity, curr->unitx,
709                                    curr->unity);
710
711                 /* Now, check if curr is a waypoint. */
712                 if (wcurr && wcurr <= path->wtail && wcurr->point == curr) {
713                         guint x1 = unit2bufx(wcurr->point->unitx);
714                         guint y1 = unit2bufy(wcurr->point->unity);
715                         if ((x1 < BUF_WIDTH_PIXELS)
716                             && (y1 < BUF_HEIGHT_PIXELS)) {
717                                 gdk_draw_arc(_map_pixmap, gc[1], FALSE, /* FALSE: not filled. */
718                                              x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
719                                              360 * 64);
720                         }
721                         wcurr++;
722                 }
723         }
724 }
725
726 void 
727 map_render_paths(void)
728 {
729 if ((_show_tracks & ROUTES_MASK) && _route.head != _route.tail) {
730         map_render_path(&_route, _gc + COLORABLE_ROUTE);
731
732         /* Now, draw the next waypoint on top of all other waypoints. */
733         if (_next_way) {
734                 guint x1 = unit2bufx(_next_way->point->unitx);
735                 guint y1 = unit2bufy(_next_way->point->unity);
736
737                 if ((x1 < BUF_WIDTH_PIXELS) && (y1 < BUF_HEIGHT_PIXELS)) {
738                         /* Draw the next waypoint as a break. */
739                         gdk_draw_arc(_map_pixmap, _gc[COLORABLE_ROUTE_BREAK], FALSE,    /* FALSE: not filled. */
740                              x1 - _draw_width, y1 - _draw_width, 4 * _draw_width, 4 * _draw_width, 0,   /* start at 0 degrees. */
741                              360 * 64);
742                 }
743         }
744 }
745 if (_show_tracks & TRACKS_MASK)
746         map_render_path(&_track, _gc + COLORABLE_TRACK);
747 }
748
749 /**
750  * 
751  *
752  */
753 static gboolean 
754 map_follow_move_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data)
755 {
756 GdkModifierType state;
757 gint xx, yy;
758 guint unitx, unity;
759 guint cx, cy;
760
761 if (!(event->state & GDK_BUTTON1_MASK))
762         return FALSE;
763
764 if (event->is_hint) {
765         gdk_window_get_pointer(event->window, &xx, &yy, &state);
766         state = event->state;
767 } else {
768         xx = event->x;
769         yy = event->y;
770         state = event->state;
771 }
772
773 unitx = x2unit((gint) (xx - before[0]));
774 unity = y2unit((gint) (yy - before[1]));
775 cx = unit2x(_center.unitx);
776 cy = unit2y(_center.unity);
777
778 map_center_unit(x2unit((gint) (cx - (xx - before[0]))), y2unit((gint) (cy - (yy - before[1]))));
779 map_data_needs_refresh=TRUE;
780
781 before[0] = xx;
782 before[1] = yy;
783 return FALSE;
784 }
785
786 gboolean 
787 map_key_zoom_timeout(void)
788 {
789 if (_key_zoom_new < _zoom) {
790         /* We're currently zooming in (_zoom is decreasing). */
791         guint test = _key_zoom_new - _curr_repo->view_zoom_steps;
792         if (test < MAX_ZOOM)
793                 _key_zoom_new = test;
794         else
795                 return FALSE;
796 } else {
797         /* We're currently zooming out (_zoom is increasing). */
798         guint test = _key_zoom_new + _curr_repo->view_zoom_steps;
799         if (test < MAX_ZOOM)
800                 _key_zoom_new = test;
801         else
802                 return FALSE;
803 }
804
805 return TRUE;
806 }
807
808 void 
809 map_scale_draw(GdkEventExpose *event)
810 {
811 gchar buffer[16];
812 gdouble distance;
813 gdouble lat1, lon1, lat2, lon2;
814 gint width;
815
816 gdk_rectangle_intersect(&event->area, &_scale_rect, &event->area);
817
818 if (event->area.width && event->area.height) {
819         gdk_draw_rectangle(_map_widget->window,
820                            _map_widget->style->
821                            bg_gc[GTK_WIDGET_STATE(_map_widget)],
822                            TRUE, _scale_rect.x, _scale_rect.y,
823                            _scale_rect.width,
824                            _scale_rect.height);
825         gdk_draw_rectangle(_map_widget->window,
826                            _map_widget->style->
827                            fg_gc[GTK_WIDGET_STATE(_map_widget)],
828                            FALSE, _scale_rect.x, _scale_rect.y,
829                            _scale_rect.width,
830                            _scale_rect.height);
831
832         /* Now calculate and draw the distance. */
833         unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4), _center.unity, lat1, lon1);
834         unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4), _center.unity, lat2, lon2);
835         distance = calculate_distance(lat1, lon1, lat2, lon2) * UNITS_CONVERT[_units];
836
837         if (distance < 1.f)
838                 snprintf(buffer, sizeof(buffer), "%0.2f %s", distance, UNITS_TEXT[_units]);
839         else if (distance < 10.f)
840                 snprintf(buffer, sizeof(buffer), "%0.1f %s", distance, UNITS_TEXT[_units]);
841         else
842                 snprintf(buffer, sizeof(buffer), "%0.f %s", distance, UNITS_TEXT[_units]);
843
844         pango_layout_set_text(_scale_layout, buffer, -1);
845         pango_layout_get_pixel_size(_scale_layout, &width, NULL);
846
847         /* Draw the layout itself. */
848         gdk_draw_layout(_map_widget->window,
849                         _map_widget->style->
850                         fg_gc[GTK_WIDGET_STATE(_map_widget)],
851                         _scale_rect.x +
852                         (_scale_rect.width - width) / 2,
853                         _scale_rect.y, _scale_layout);
854
855         /* Draw little hashes on the ends. */
856         gdk_draw_line(_map_widget->window,
857                       _map_widget->style->
858                       fg_gc[GTK_WIDGET_STATE(_map_widget)],
859                       _scale_rect.x + 4,
860                       _scale_rect.y +
861                       _scale_rect.height / 2 - 4,
862                       _scale_rect.x + 4,
863                       _scale_rect.y +
864                       _scale_rect.height / 2 + 4);
865         gdk_draw_line(_map_widget->window,
866                       _map_widget->style->
867                       fg_gc[GTK_WIDGET_STATE(_map_widget)],
868                       _scale_rect.x + 4,
869                       _scale_rect.y +
870                       _scale_rect.height / 2,
871                       _scale_rect.x +
872                       (_scale_rect.width - width) / 2 - 4,
873                       _scale_rect.y +
874                       _scale_rect.height / 2);
875         gdk_draw_line(_map_widget->window,
876                       _map_widget->style->
877                       fg_gc[GTK_WIDGET_STATE(_map_widget)],
878                       _scale_rect.x +
879                       _scale_rect.width - 4,
880                       _scale_rect.y +
881                       _scale_rect.height / 2 - 4,
882                       _scale_rect.x +
883                       _scale_rect.width - 4,
884                       _scale_rect.y +
885                       _scale_rect.height / 2 + 4);
886         gdk_draw_line(_map_widget->window,
887                       _map_widget->style->
888                       fg_gc[GTK_WIDGET_STATE(_map_widget)],
889                       _scale_rect.x +
890                       _scale_rect.width - 4,
891                       _scale_rect.y +
892                       _scale_rect.height / 2,
893                       _scale_rect.x +
894                       (_scale_rect.width + width) / 2 + 4,
895                       _scale_rect.y +
896                       _scale_rect.height / 2);
897         }
898 }
899
900 gboolean 
901 map_cb_expose(GtkWidget * widget, GdkEventExpose * event)
902 {
903 gdk_draw_drawable(GDK_DRAWABLE(_map_widget->window),
904                   _gc[COLORABLE_MARK],
905                   _map_pixmap,
906                   event->area.x + _offsetx, event->area.y + _offsety,
907                   event->area.x, event->area.y,
908                   event->area.width, event->area.height);
909 map_draw_mark();
910
911 /* Draw scale, if necessary. */
912 if (_show_scale)
913         map_scale_draw(event);
914
915 return TRUE;
916 }
917
918 int 
919 map_zoom(gint zdir)
920 {
921 gint nzoom;
922
923 nzoom=_zoom+zdir;
924 if ((nzoom > 0) && (nzoom < MAX_ZOOM - 1)) {
925         map_set_zoom(nzoom);
926 }
927 return nzoom;
928 }
929
930 static gboolean
931 map_autozoomer(void)
932 {
933 static gfloat z=5.0;
934 static gint last=5;
935 gint iz;
936
937 if (zoom_timeout_sid==0)
938         return FALSE;
939
940 z=(z+_gps.speed+1)/5;
941 if (z>5) z=5.0; else if (z<1) z=1.0;
942 iz=(gint)roundf(z);
943 #ifdef DEBUG
944 g_printf("Setting autozoom to: %f %d S:%f\n", z, iz, _gps.speed);
945 #endif
946 if (iz>last) 
947         iz=last+1; 
948 else if (iz<last) 
949         iz=last-1;
950 last=iz;
951 map_set_zoom(iz);
952
953 return TRUE;
954 }
955
956 void
957 map_set_autozoom(gboolean az)
958 {
959 if (az==TRUE) {
960         MACRO_BANNER_SHOW_INFO(_window, "Autozoom enabled");
961         zoom_timeout_sid=g_timeout_add(_gps.speed<5 ? 2000 : 5000, (GSourceFunc) map_autozoomer, NULL);
962         return;
963 } else {
964         if (zoom_timeout_sid) {
965                 g_source_remove(zoom_timeout_sid);
966                 zoom_timeout_sid=0;
967                 MACRO_BANNER_SHOW_INFO(_window, "Autozoom disabled");
968         }
969         return;
970 }
971
972 }
973
974 static void 
975 map_draw_route(gint x, gint y)
976 {
977 cmenu_route_add_way(x, y);
978 }
979
980 static void 
981 map_draw_track(gint x, gint y)
982 {
983 _pos.unitx = x2unit((gint) (x + 0.5));
984 _pos.unity = y2unit((gint) (y + 0.5));
985 unit2latlon(_pos.unitx, _pos.unity, _gps.lat, _gps.lon);
986 _gps.speed = 20.f;
987 integerize_data(&_gps, &_pos);
988 track_add(time(NULL), FALSE);
989 map_refresh_mark();
990 }
991
992 static void
993 map_set_place_information(osm_way *s, osm_place *mp, osm_place *sp)
994 {
995 gchar buffer[256];
996
997 if (!s && !mp && !sp) {
998         snprintf(buffer, sizeof(buffer), _("Unknown location"));
999 } else {
1000         /* oh, fun */
1001         snprintf(buffer, sizeof(buffer), "%s%s%s%s%s%s%s%s%s%s", 
1002         s ? s->name ? s->name : "" : "",
1003         s ? s->ref ? ", " : "" : "",
1004         s ? s->ref ? s->ref : "" : "",
1005         s ? s->int_ref ? " (" : "" : "",
1006         s ? s->int_ref ? s->int_ref : "" : "",
1007         s ? s->int_ref ? ") " : "" : "",
1008         (sp && sp->name) ? " in " : "",
1009         (sp && sp->name) ? sp->name : "",
1010         (mp && mp->name) ? " in " : "",
1011         (mp && mp->name) ? mp->name : "");
1012 }
1013 gtk_label_set_label(GTK_LABEL(info_banner.location), buffer);
1014 }
1015
1016 #define KM10KNOTS 5.39956803
1017
1018 static void
1019 map_update_destination(gdouble lat, gdouble lon)
1020 {
1021 gdouble dh=0.0;
1022 gdouble dt;
1023 static gdouble prev_dt=99999.0;
1024 static gboolean dest_reached=FALSE;
1025 gchar buffer[64];
1026
1027 if (_dest.valid) {
1028         dt=calculate_distance(lat, lon, _dest.lat, _dest.lon);
1029         dh=calculate_course(lat, lon, _dest.lat, _dest.lon);
1030         snprintf(buffer, sizeof(buffer), "%.02f %s (%0.02f)", dt * UNITS_CONVERT[_units], UNITS_TEXT[_units], dh<0 ? 360+dh : dh);
1031         gtk_label_set_label(GTK_LABEL(info_banner.distance), buffer);
1032         if (dt<0.005 && dest_reached==FALSE) {
1033                 if (_center_mode>0)
1034                         speak_text("You have reached your destination.");
1035                 dest_reached=TRUE;
1036         } else if (dt<prev_dt-KM10KNOTS) {
1037                 if (_center_mode>0) {
1038                         snprintf(buffer, sizeof(buffer), "Distance to destination: %.02f %s", dt * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
1039                         speak_text(buffer);
1040                 }
1041                 prev_dt=dt;
1042         } else if (dt>prev_dt+KM10KNOTS/4) {
1043                 prev_dt=dt;
1044         }
1045         if (dt>0.05) {
1046                 dest_reached=FALSE;
1047         }
1048 #if 0
1049         g_printf("%f (Prev:%f)\n", prev_dt, dt);
1050 #endif
1051 } else {
1052         dest_reached=FALSE;
1053         prev_dt=99999.0;
1054         gtk_label_set_label(GTK_LABEL(info_banner.distance), "");
1055 }
1056 gtk_compass_set_dest_heading(_gps_compass, _dest.valid, (gfloat)dh);
1057 gtk_compass_set_dest_heading(_tab_compass, _dest.valid, (gfloat)dh);
1058
1059 if (_next_way && _next_way->point) {
1060         gdouble wp_lat, wp_lon;
1061         gfloat wc;
1062
1063         unit2latlon(_next_way->point->unitx,_next_way->point->unity, wp_lat, wp_lon);
1064         wc=calculate_course(lat, lon, wp_lat, wp_lon);
1065         gtk_compass_set_way_heading(_gps_compass, TRUE, wc);
1066         gtk_compass_set_way_heading(_tab_compass, TRUE, wc);
1067 } else {
1068         gtk_compass_set_way_heading(_gps_compass, FALSE, 0);
1069         gtk_compass_set_way_heading(_tab_compass, FALSE, 0);
1070 }
1071
1072 }
1073
1074 static void 
1075 map_update_location(gdouble lat, gdouble lon, gboolean force)
1076 {
1077 gint ilat, ilon;
1078 static gboolean inp=FALSE;
1079
1080 /* We run the gtk mainloop in progress callback so we can be called again, we don't like that */
1081 if (inp==TRUE)
1082         return;
1083 inp=TRUE;
1084
1085 ilat=lat2mp_int(lat);
1086 ilon=lon2mp_int(lon);
1087
1088 if (_gps.fix>1 && !force)
1089         osm_set_way_range_from_speed(_gps.speed);
1090 else
1091         osm_set_way_range(OSM_RANGE_WAY/4);
1092
1093 osm_progress_set_widget(_db, _progress_item);
1094 _map_location_known=osm_get_location_data(ilat, ilon, &map_loc);
1095 _map_location_dist=map_loc.street ? map_loc.street->dist : 900000.0;
1096 if (map_loc.valid)
1097         map_set_place_information(map_loc.street, map_loc.primary, map_loc.secondary);
1098 else
1099         map_set_place_information(NULL, NULL, NULL);
1100 osm_progress_set_widget(_db, NULL);
1101
1102 map_update_destination(lat, lon);
1103
1104 inp=FALSE;
1105 }
1106
1107 /**
1108  * Mouse scroller zoom in/out callback
1109  */
1110 gboolean 
1111 map_cb_scroll_event(GtkWidget * widget, GdkEventScroll * event)
1112 {
1113 if (event->direction == GDK_SCROLL_UP) {
1114         map_center_unit(x2unit((gint) (event->x + 0.5)), y2unit((gint) (event->y + 0.5)));
1115         map_set_zoom(_zoom - 1);
1116 } else if (event->direction == GDK_SCROLL_DOWN) {
1117         map_center_unit(x2unit((gint) (event->x + 0.5)), y2unit((gint) (event->y + 0.5)));
1118         map_set_zoom(_zoom + 1);
1119 }
1120 return FALSE;
1121 }
1122
1123 /** 
1124  * Start map drag operation
1125  */
1126 static void
1127 map_drag_start(gint x,gint y)
1128 {
1129 press[0] = x;
1130 press[1] = y;
1131 before[0] = press[0];
1132 before[1] = press[1];
1133 _center_mode=CENTER_MANUAL;
1134 if (map_drag_id!=0)
1135         g_signal_handler_disconnect(G_OBJECT(_map_widget), map_drag_id);
1136
1137 map_drag_id=g_signal_connect(G_OBJECT(_map_widget), "motion_notify_event", G_CALLBACK(map_follow_move_cb), NULL);
1138 }
1139
1140 /**
1141  * Stop map drag operation
1142  */
1143 static void
1144 map_drag_stop(gint x, gint y)
1145 {
1146 if (map_drag_id==0)
1147         return;
1148
1149 g_signal_handler_disconnect(G_OBJECT(_map_widget), map_drag_id);
1150
1151 release[0]=x;
1152 release[1]=y;
1153 press[0]=0;
1154 press[1]=0;
1155 release[0]=0;
1156 release[1]=0;
1157 before[0]=0;
1158 before[1]=0;
1159 map_drag_id=0;
1160 }
1161
1162 /* Workaround hildon content menu problem */
1163 static gboolean
1164 map_cb_show_poi_info_dialog(gpointer data)
1165 {
1166 guint poi_id=GPOINTER_TO_INT(data);
1167 if (poi_info_dialog(poi_id)==FALSE)
1168         g_printerr("Huh? Failed to display info dialog\n");
1169 return FALSE;
1170 }
1171
1172 gboolean 
1173 map_cb_button_press(GtkWidget * widget, GdkEventButton * event)
1174 {
1175 gdouble lat, lon;
1176 guint poi_id;
1177 gint ux, uy;
1178
1179 _cmenu_position_x = event->x + 0.5;
1180 _cmenu_position_y = event->y + 0.5;
1181
1182 g_printf("BtnPress\n");
1183 switch (event->button) {
1184 case 1:
1185         if (event->type==GDK_2BUTTON_PRESS) {
1186                 map_center_unit(x2unit((gint) (event->x + 0.5)), y2unit((gint) (event->y + 0.5)));
1187                 map_set_zoom(_zoom-1);
1188                 map_data_needs_refresh=TRUE;
1189                 return FALSE;
1190         }
1191         if (event->type==GDK_3BUTTON_PRESS) {
1192                 return FALSE;
1193         }
1194
1195         ux=x2unit(_cmenu_position_x);
1196         uy=y2unit(_cmenu_position_y);
1197
1198         unit2latlon(ux, uy, lat, lon);
1199         if (map_poi_find_at_latlon(lat, lon, &poi_id)==TRUE) {
1200                 g_printf("POI: %d\n", poi_id);
1201                 g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_cb_show_poi_info_dialog, GINT_TO_POINTER(poi_id), NULL);
1202         } else {
1203                 map_drag_start(event->x, event->y);
1204         }
1205         return FALSE;
1206 break;
1207 case 2:
1208         map_set_zoom(_zoom - 1);
1209 break;
1210 case 3:
1211 #ifndef WITH_HILDON
1212         gtk_menu_popup(GTK_MENU(_menu_map), NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time());
1213 #endif
1214 break;
1215 }
1216 /* Return FALSE to allow context menu to work. */
1217 return FALSE;
1218 }
1219
1220 gboolean 
1221 map_cb_button_release(GtkWidget *widget, GdkEventButton *event)
1222 {
1223 g_printf("BtnRelease\n");
1224 switch (event->button) {
1225 case 1:
1226         if (_center_mode>0)
1227                 set_action_activate("autocenter_none", TRUE);
1228
1229         switch (map_mode) {
1230         case MAP_MODE_DRAW_TRACK:
1231                 map_draw_track(event->x, event->y);
1232         break;
1233         case MAP_MODE_DRAW_ROUTE:
1234                 map_draw_route(event->x, event->y);
1235         break;
1236         case MAP_MODE_SET_ROUTE_FROM:
1237         case MAP_MODE_SET_ROUTE_POINT:
1238         case MAP_MODE_SET_ROUTE_TO:
1239         break;
1240         default:
1241                 map_drag_stop(event->x, event->y);
1242                 if (map_data_needs_refresh==TRUE) {
1243                         map_data_needs_refresh=FALSE;
1244                         map_render_data();
1245                         g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
1246                 }
1247         break;
1248         }
1249 break;
1250 case 2:
1251         /* */
1252 break;
1253 case 3:
1254 break;
1255 }
1256
1257 /* Return FALSE to avoid context menu (if it hasn't popped up already). */
1258 return FALSE;
1259 }