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