]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
Merge 'viking-0.9.8'
[andy/viking.git] / src / vikmapslayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5  * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
6  * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
29 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
30
31 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
32
33 #include <gtk/gtk.h>
34 #include <gdk-pixbuf/gdk-pixdata.h>
35 #include <glib.h>
36 #include <glib/gstdio.h>
37 #include <glib/gi18n.h>
38
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #ifdef HAVE_MATH_H
43 #include <math.h>
44 #endif
45
46 #include "globals.h"
47 #include "coords.h"
48 #include "vikcoord.h"
49 #include "viktreeview.h"
50 #include "vikviewport.h"
51 #include "viklayer.h"
52 #include "vikmapslayer.h"
53
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57
58 #include "mapcache.h"
59 /* only for dialog.h -- ugh */
60 #include "vikwaypoint.h"
61 #include "dialog.h"
62
63 #include "vikstatus.h"
64 #include "background.h"
65
66 #include "vikaggregatelayer.h"
67 #include "viklayerspanel.h"
68
69 #include "mapcoord.h"
70 #include "terraserver.h"
71
72 #include "icons/icons.h"
73
74 /****** MAP TYPES ******/
75
76 static GList *__map_types = NULL;
77
78 #define NUM_MAP_TYPES g_list_length(__map_types)
79
80 /* List of label for each map type */
81 static GList *params_maptypes = NULL;
82
83 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
84 static GList *params_maptypes_ids = NULL;
85
86 /******** MAPZOOMS *********/
87
88 static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
89 static gdouble __mapzooms_x[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
90 static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
91
92 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
93
94 /**************************/
95
96
97 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
98 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
99 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
100 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
101 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
102 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
103 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
104 static void maps_layer_free ( VikMapsLayer *vml );
105 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
106 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
107 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
108 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
109 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
110 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
111
112
113 static VikLayerParamScale params_scales[] = {
114   /* min, max, step, digits (decimal places) */
115  { 0, 255, 3, 0 }, /* alpha */
116 };
117
118 VikLayerParam maps_layer_params[] = {
119   { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
120   { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory (Optional):"), VIK_LAYER_WIDGET_FILEENTRY },
121   { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
122   { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
123   { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
124 };
125
126 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
127
128 static VikToolInterface maps_tools[] = {
129   { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
130     (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
131     (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
132 };
133
134 VikLayerInterface vik_maps_layer_interface = {
135   N_("Map"),
136   &vikmapslayer_pixbuf,
137
138   maps_tools,
139   sizeof(maps_tools) / sizeof(maps_tools[0]),
140
141   maps_layer_params,
142   NUM_PARAMS,
143   NULL,
144   0,
145
146   VIK_MENU_ITEM_ALL,
147
148   (VikLayerFuncCreate)                  maps_layer_new,
149   (VikLayerFuncRealize)                 NULL,
150                                         maps_layer_post_read,
151   (VikLayerFuncFree)                    maps_layer_free,
152
153   (VikLayerFuncProperties)              NULL,
154   (VikLayerFuncDraw)                    maps_layer_draw,
155   (VikLayerFuncChangeCoordMode)         NULL,
156
157   (VikLayerFuncSetMenuItemsSelection)   NULL,
158   (VikLayerFuncGetMenuItemsSelection)   NULL,
159
160   (VikLayerFuncAddMenuItems)            maps_layer_add_menu_items,
161   (VikLayerFuncSublayerAddMenuItems)    NULL,
162
163   (VikLayerFuncSublayerRenameRequest)   NULL,
164   (VikLayerFuncSublayerToggleVisible)   NULL,
165
166   (VikLayerFuncMarshall)                maps_layer_marshall,
167   (VikLayerFuncUnmarshall)              maps_layer_unmarshall,
168
169   (VikLayerFuncSetParam)                maps_layer_set_param,
170   (VikLayerFuncGetParam)                maps_layer_get_param,
171
172   (VikLayerFuncReadFileData)            NULL,
173   (VikLayerFuncWriteFileData)           NULL,
174
175   (VikLayerFuncDeleteItem)              NULL,
176   (VikLayerFuncCopyItem)                NULL,
177   (VikLayerFuncPasteItem)               NULL,
178   (VikLayerFuncFreeCopiedItem)          NULL,
179   (VikLayerFuncDragDropRequest)         NULL,
180 };
181
182 struct _VikMapsLayer {
183   VikLayer vl;
184   guint maptype;
185   gchar *cache_dir;
186   guint8 alpha;
187   guint mapzoom_id;
188   gdouble xmapzoom, ymapzoom;
189
190   gboolean autodownload;
191   VikCoord *last_center;
192   gdouble last_xmpp;
193   gdouble last_ympp;
194
195   gint dl_tool_x, dl_tool_y;
196
197   GtkMenu *dl_right_click_menu;
198   VikCoord redownload_ul, redownload_br; /* right click menu only */
199   VikViewport *redownload_vvp;
200 };
201
202 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
203
204
205 /****************************************/
206 /******** MAPS LAYER TYPES **************/
207 /****************************************/
208
209 void maps_layer_register_map_source ( const char *label, VikMapSource *map )
210 {
211   g_assert(label != NULL);
212   g_assert(map != NULL);
213   
214   guint id = vik_map_source_get_uniq_id(map);
215
216   /* Add the label */
217   params_maptypes = g_list_append(params_maptypes, g_strdup(label));
218
219   /* Add the id */
220   params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
221
222   /* We have to clone */
223   VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
224   /* Register the clone in the list */
225   __map_types = g_list_append(__map_types, clone);
226
227   /* Hack
228      We have to ensure the mode LayerParam reference the up-to-date
229      GLists.
230   */
231   /*
232   memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
233   memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
234   */
235   maps_layer_params[0].widget_data = params_maptypes;
236   maps_layer_params[0].extra_widget_data = params_maptypes_ids;
237 }
238
239 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
240 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
241 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
242
243 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
244 {
245   return(vml->maptype);
246 }
247
248 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
249 {
250   return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
251 }
252
253 /****************************************/
254 /******** CACHE DIR STUFF ***************/
255 /****************************************/
256
257 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
258 #define MAPS_CACHE_DIR maps_layer_default_dir()
259
260 #ifdef WINDOWS
261 #include <io.h>
262 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
263 #define LOCAL_MAPS_DIR "VIKING-MAPS"
264 #else /* POSIX */
265 #include <stdlib.h>
266 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
267 #define LOCAL_MAPS_DIR ".viking-maps"
268 #endif
269
270 gchar *maps_layer_default_dir ()
271 {
272   static gchar *defaultdir = NULL;
273   if ( ! defaultdir )
274   {
275     /* Thanks to Mike Davison for the $VIKING_MAPS usage */
276     const gchar *mapdir = g_getenv("VIKING_MAPS");
277     if ( mapdir ) {
278       defaultdir = g_strdup ( mapdir );
279     } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
280       defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
281     } else {
282       const gchar *home = g_get_home_dir();
283       if (!home || g_access(home, W_OK))
284         home = g_get_home_dir ();
285       if ( home )
286         defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
287       else
288         defaultdir = g_strdup ( LOCAL_MAPS_DIR );
289     }
290     if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
291     {
292       /* Add the separator at the end */
293       gchar *tmp = defaultdir;
294       defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
295       g_free(tmp);
296     }
297     g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
298   }
299   return defaultdir;
300 }
301
302 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
303 {
304   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
305   {
306     g_mkdir ( vml->cache_dir, 0777 );
307   }
308 }
309
310 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
311 {
312   guint len;
313   g_assert ( vml != NULL);
314   g_free ( vml->cache_dir );
315   vml->cache_dir = NULL;
316
317   if ( dir == NULL || dir[0] == '\0' )
318     vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
319   else
320   {
321     len = strlen(dir);
322     if ( dir[len-1] != G_DIR_SEPARATOR )
323     {
324       vml->cache_dir = g_malloc ( len+2 );
325       strncpy ( vml->cache_dir, dir, len );
326       vml->cache_dir[len] = G_DIR_SEPARATOR;
327       vml->cache_dir[len+1] = '\0';
328     }
329     else
330       vml->cache_dir = g_strdup ( dir );
331   }
332   maps_layer_mkdir_if_default_dir ( vml );
333 }
334
335 /****************************************/
336 /******** GOBJECT STUFF *****************/
337 /****************************************/
338
339 GType vik_maps_layer_get_type ()
340 {
341   static GType vml_type = 0;
342
343   if (!vml_type)
344   {
345     static const GTypeInfo vml_info =
346     {
347       sizeof (VikMapsLayerClass),
348       NULL, /* base_init */
349       NULL, /* base_finalize */
350       NULL, /* class init */
351       NULL, /* class_finalize */
352       NULL, /* class_data */
353       sizeof (VikMapsLayer),
354       0,
355       NULL /* instance init */
356     };
357     vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
358   }
359
360   return vml_type;
361 }
362
363 /****************************************/
364 /************** PARAMETERS **************/
365 /****************************************/
366
367 static guint map_index_to_uniq_id (guint8 index)
368 {
369   g_assert ( index < NUM_MAP_TYPES );
370   return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
371 }
372
373 static guint map_uniq_id_to_index ( guint uniq_id )
374 {
375   gint i;
376   for ( i = 0; i < NUM_MAP_TYPES; i++ )
377     if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
378       return i;
379   return NUM_MAP_TYPES; /* no such thing */
380 }
381
382 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
383 {
384   switch ( id )
385   {
386     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
387     case PARAM_MAPTYPE: {
388       gint maptype = map_uniq_id_to_index(data.u);
389       if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
390       else vml->maptype = maptype;
391       break;
392     }
393     case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
394     case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
395     case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
396                           vml->mapzoom_id = data.u;
397                           vml->xmapzoom = __mapzooms_x [data.u];
398                           vml->ymapzoom = __mapzooms_y [data.u];
399                         }else g_warning (_("Unknown Map Zoom")); break;
400   }
401   return TRUE;
402 }
403
404 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
405 {
406   VikLayerParamData rv;
407   switch ( id )
408   {
409     case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
410     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
411     case PARAM_ALPHA: rv.u = vml->alpha; break;
412     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
413     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
414   }
415   return rv;
416 }
417
418 /****************************************/
419 /****** CREATING, COPYING, FREEING ******/
420 /****************************************/
421
422 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
423 {
424   int idx;
425   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
426   vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
427   idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
428     vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
429   vml->alpha = 255;
430   vml->mapzoom_id = 0;
431   vml->dl_tool_x = vml->dl_tool_y = -1;
432   maps_layer_set_cache_dir ( vml, NULL );
433   vml->autodownload = FALSE;
434   vml->last_center = NULL;
435   vml->last_xmpp = 0.0;
436   vml->last_ympp = 0.0;
437
438   vml->dl_right_click_menu = NULL;
439
440   return vml;
441 }
442
443 static void maps_layer_free ( VikMapsLayer *vml )
444 {
445   g_free ( vml->cache_dir );
446   vml->cache_dir = NULL;
447   if ( vml->dl_right_click_menu )
448     gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
449   g_free(vml->last_center);
450   vml->last_center = NULL;
451 }
452
453 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
454 {
455   if (from_file != TRUE)
456   {
457     /* If this method is not called in file reading context
458      * it is called in GUI context.
459      * So, we can check if we have to inform the user about inconsistency */
460     VikViewportDrawMode vp_drawmode;
461     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
462     VikMapSource *map = NULL;
463  
464     vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
465     map = MAPS_LAYER_NTH_TYPE(vml->maptype);
466     if (vik_map_source_get_drawmode(map) != vp_drawmode) {
467       const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
468       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
469       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
470       g_free(msg);
471     }
472   }
473 }
474
475 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
476 {
477   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
478 }
479
480 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
481 {
482   VikMapsLayer *rv = maps_layer_new ( vvp );
483   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
484   return rv;
485 }
486
487 /*********************/
488 /****** DRAWING ******/
489 /*********************/
490
491 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
492 {
493   guchar *pixels;
494   gint width, height, iii, jjj;
495
496   if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
497   {
498     GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
499     g_object_unref(G_OBJECT(pixbuf));
500     pixbuf = tmp;
501   }
502
503   pixels = gdk_pixbuf_get_pixels(pixbuf);
504   width = gdk_pixbuf_get_width(pixbuf);
505   height = gdk_pixbuf_get_height(pixbuf);
506
507   /* r,g,b,a,r,g,b,a.... */
508   for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
509   {
510     pixels += 3;
511     *pixels++ = alpha;
512   }
513   return pixbuf;
514 }
515
516 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
517 {
518   GdkPixbuf *tmp;
519   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
520   tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
521   g_object_unref ( G_OBJECT(pixbuf) );
522   return tmp;
523 }
524
525 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
526 {
527   GdkPixbuf *pixbuf;
528
529   /* get the thing */
530   pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
531                             mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
532
533   if ( ! pixbuf ) {
534     g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
535                      vml->cache_dir, mode,
536                      mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
537     if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
538     {
539       GError *gx = NULL;
540       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
541
542       if (gx)
543       {
544         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
545           g_warning ( _("Couldn't open image file: %s"), gx->message );
546
547           g_error_free ( gx );
548           if ( pixbuf )
549             g_object_unref ( G_OBJECT(pixbuf) );
550           pixbuf = NULL;
551         } else {
552           if ( vml->alpha < 255 )
553             pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
554           if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
555             pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
556
557           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
558               mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
559               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
560         }
561       }
562     }
563   }
564   return pixbuf;
565 }
566
567 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
568 {
569   const VikCoord *center = vik_viewport_get_center ( vvp );
570
571   if (vml->last_center == NULL) {
572     VikCoord *new_center = g_malloc(sizeof(VikCoord));
573     *new_center = *center;
574     vml->last_center = new_center;
575     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
576     vml->last_ympp = vik_viewport_get_ympp(vvp);
577     return TRUE;
578   }
579
580   /* TODO: perhaps vik_coord_diff() */
581   if (vik_coord_equals(vml->last_center, center)
582       && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
583       && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
584     return FALSE;
585
586   *(vml->last_center) = *center;
587     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
588     vml->last_ympp = vik_viewport_get_ympp(vvp);
589   return TRUE;
590 }
591
592 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
593 {
594   MapCoord ulm, brm;
595   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
596   gdouble yzoom = vik_viewport_get_ympp ( vvp );
597   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
598   gdouble existence_only = FALSE;
599
600   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
601     xshrinkfactor = vml->xmapzoom / xzoom;
602     yshrinkfactor = vml->ymapzoom / yzoom;
603     xzoom = vml->xmapzoom;
604     yzoom = vml->xmapzoom;
605     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
606          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
607       if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
608         existence_only = TRUE;
609       else {
610         g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
611         return;
612       }
613     }
614   }
615
616   /* coord -> ID */
617   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
618   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
619        vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
620
621     /* loop & draw */
622     gint x, y;
623     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
624     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
625     gint mode = vik_map_source_get_uniq_id(map);
626
627     VikCoord coord;
628     gint xx, yy, width, height;
629     GdkPixbuf *pixbuf;
630
631     guint max_path_len = strlen(vml->cache_dir) + 40;
632     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
633
634     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
635 #ifdef DEBUG
636       fputs(stderr, "DEBUG: Starting autodownload\n");
637 #endif
638       start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
639     }
640
641     if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
642       for ( x = xmin; x <= xmax; x++ ) {
643         for ( y = ymin; y <= ymax; y++ ) {
644           ulm.x = x;
645           ulm.y = y;
646           pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
647           if ( pixbuf ) {
648             width = gdk_pixbuf_get_width ( pixbuf );
649             height = gdk_pixbuf_get_height ( pixbuf );
650
651             vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
652             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
653             xx -= (width/2);
654             yy -= (height/2);
655
656             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
657           }
658         }
659       }
660     } else { /* tilesize is known, don't have to keep converting coords */
661       gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
662       gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
663       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
664       gint tilesize_x_ceil = ceil ( tilesize_x );
665       gint tilesize_y_ceil = ceil ( tilesize_y );
666       gint8 xinc = (ulm.x == xmin) ? 1 : -1;
667       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
668       gdouble xx, yy; gint xx_tmp, yy_tmp;
669       gint base_yy, xend, yend;
670
671       GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
672
673       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
674       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
675
676       vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
677       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
678       xx = xx_tmp; yy = yy_tmp;
679       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
680        * eg if tile size 128, shrinkfactor 0.333 */
681       xx -= (tilesize_x/2);
682       base_yy = yy - (tilesize_y/2);
683
684       for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
685         yy = base_yy;
686         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
687           ulm.x = x;
688           ulm.y = y;
689
690           if ( existence_only ) {
691             g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
692                      vml->cache_dir, mode,
693                      ulm.scale, ulm.z, ulm.x, ulm.y );
694             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
695               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
696             }
697           } else {
698             pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
699             if ( pixbuf )
700               vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
701           }
702
703           yy += tilesize_y;
704         }
705         xx += tilesize_x;
706       }
707     }
708
709     g_free ( path_buf );
710   }
711 }
712
713 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
714 {
715   if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
716   {
717     VikCoord ul, br;
718
719     /* get corner coords */
720     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
721       /* UTM multi-zone stuff by Kit Transue */
722       gchar leftmost_zone, rightmost_zone, i;
723       leftmost_zone = vik_viewport_leftmost_zone( vvp );
724       rightmost_zone = vik_viewport_rightmost_zone( vvp );
725       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
726         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
727         maps_layer_draw_section ( vml, vvp, &ul, &br );
728       }
729     }
730     else {
731       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
732       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
733
734       maps_layer_draw_section ( vml, vvp, &ul, &br );
735     }
736   }
737 }
738
739 /*************************/
740 /****** DOWNLOADING ******/
741 /*************************/
742
743 /* pass along data to thread, exists even if layer is deleted. */
744 typedef struct {
745   gchar *cache_dir;
746   gchar *filename_buf;
747   gint x0, y0, xf, yf;
748   MapCoord mapcoord;
749   gint maptype;
750   gint maxlen;
751   gint mapstoget;
752   gint redownload;
753   gboolean refresh_display;
754   VikMapsLayer *vml;
755   VikViewport *vvp;
756   gboolean map_layer_alive;
757   GMutex *mutex;
758 } MapDownloadInfo;
759
760 static void mdi_free ( MapDownloadInfo *mdi )
761 {
762   g_mutex_free(mdi->mutex);
763   g_free ( mdi->cache_dir );
764   mdi->cache_dir = NULL;
765   g_free ( mdi->filename_buf );
766   mdi->filename_buf = NULL;
767   g_free ( mdi );
768 }
769
770 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
771 {
772   MapDownloadInfo *mdi = ptr;
773   g_mutex_lock(mdi->mutex);
774   mdi->map_layer_alive = FALSE;
775   g_mutex_unlock(mdi->mutex);
776 }
777
778 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
779 {
780   guint donemaps = 0;
781   gint x, y;
782   for ( x = mdi->x0; x <= mdi->xf; x++ )
783   {
784     for ( y = mdi->y0; y <= mdi->yf; y++ )
785     {
786       gboolean remove_mem_cache = FALSE;
787       gboolean need_download = FALSE;
788       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
789                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
790                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
791
792       donemaps++;
793       a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
794
795       if ( mdi->redownload == REDOWNLOAD_ALL)
796         g_remove ( mdi->filename_buf );
797
798       else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
799       {
800         /* see if this one is bad or what */
801         GError *gx = NULL;
802         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
803         if (gx || (!pixbuf))
804           g_remove ( mdi->filename_buf );
805         if ( pixbuf )
806           g_object_unref ( pixbuf );
807         if ( gx )
808           g_error_free ( gx );
809       }
810
811       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
812       {
813         need_download = TRUE;
814         if (( mdi->redownload != REDOWNLOAD_NONE ) &&
815             ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
816           remove_mem_cache = TRUE;
817       } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
818         remove_mem_cache = TRUE;
819       } else
820         continue;
821
822       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
823
824       if (need_download) {
825         if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf ))
826           continue;
827       }
828
829       gdk_threads_enter();
830       g_mutex_lock(mdi->mutex);
831       if (remove_mem_cache)
832           a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)), mdi->mapcoord.scale );
833       if (mdi->refresh_display && mdi->map_layer_alive) {
834         /* TODO: check if it's on visible area */
835         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
836       }
837       g_mutex_unlock(mdi->mutex);
838       gdk_threads_leave();
839       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
840
841     }
842   }
843   g_mutex_lock(mdi->mutex);
844   if (mdi->map_layer_alive)
845     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
846   g_mutex_unlock(mdi->mutex); 
847 }
848
849 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
850 {
851   if ( mdi->mapcoord.x || mdi->mapcoord.y )
852   {
853     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
854                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
855                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
856     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
857     {
858       g_remove ( mdi->filename_buf );
859     }
860   }
861 }
862
863 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
864 {
865   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
866   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
867   MapCoord ulm, brm;
868   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
869   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
870     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
871   {
872     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
873     gint a, b;
874
875     mdi->vml = vml;
876     mdi->vvp = vvp;
877     mdi->map_layer_alive = TRUE;
878     mdi->mutex = g_mutex_new();
879     mdi->refresh_display = TRUE;
880
881     /* cache_dir and buffer for dest filename */
882     mdi->cache_dir = g_strdup ( vml->cache_dir );
883     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
884     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
885     mdi->maptype = vml->maptype;
886
887     mdi->mapcoord = ulm;
888
889     mdi->redownload = redownload;
890
891     mdi->x0 = MIN(ulm.x, brm.x);
892     mdi->xf = MAX(ulm.x, brm.x);
893     mdi->y0 = MIN(ulm.y, brm.y);
894     mdi->yf = MAX(ulm.y, brm.y);
895
896     mdi->mapstoget = 0;
897
898     if ( mdi->redownload ) {
899       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
900     } else {
901       /* calculate how many we need */
902       for ( a = mdi->x0; a <= mdi->xf; a++ )
903       {
904         for ( b = mdi->y0; b <= mdi->yf; b++ )
905         {
906           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
907                        vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
908                        ulm.z, a, b );
909           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
910             mdi->mapstoget++;
911         }
912       }
913     }
914
915     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
916
917     if ( mdi->mapstoget )
918     {
919       const gchar *tmp_str;
920       gchar *tmp;
921
922       if (redownload) 
923       {
924         if (redownload == REDOWNLOAD_BAD)
925           tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
926         else
927           tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
928       } 
929       else 
930       {
931         tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
932       }
933       tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
934  
935       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
936       /* launch the thread */
937       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
938                             tmp,                                              /* description string */
939                             (vik_thr_func) map_download_thread,               /* function to call within thread */
940                             mdi,                                              /* pass along data */
941                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
942                             (vik_thr_free_func) mdi_cancel_cleanup,
943                             mdi->mapstoget );
944       g_free ( tmp );
945     }
946     else
947       mdi_free ( mdi );
948   }
949 }
950
951 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
952 {
953   MapCoord ulm, brm;
954   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
955
956   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
957     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
958     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
959     return;
960   }
961
962   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
963   gint i, j;
964
965   mdi->vml = vml;
966   mdi->vvp = vvp;
967   mdi->map_layer_alive = TRUE;
968   mdi->mutex = g_mutex_new();
969   mdi->refresh_display = FALSE;
970
971   mdi->cache_dir = g_strdup ( vml->cache_dir );
972   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
973   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
974   mdi->maptype = vml->maptype;
975
976   mdi->mapcoord = ulm;
977
978   mdi->redownload = REDOWNLOAD_NONE;
979
980   mdi->x0 = MIN(ulm.x, brm.x);
981   mdi->xf = MAX(ulm.x, brm.x);
982   mdi->y0 = MIN(ulm.y, brm.y);
983   mdi->yf = MAX(ulm.y, brm.y);
984
985   mdi->mapstoget = 0;
986
987   for (i = mdi->x0; i <= mdi->xf; i++) {
988     for (j = mdi->y0; j <= mdi->yf; j++) {
989       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
990                    vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
991                    ulm.z, i, j );
992       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
993             mdi->mapstoget++;
994     }
995   }
996
997   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
998
999   if (mdi->mapstoget) {
1000     gchar *tmp;
1001     const gchar *fmt;
1002     fmt = ngettext("Downloading %d %s map...",
1003                    "Downloading %d %s maps...",
1004                    mdi->mapstoget);
1005     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1006
1007     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1008       /* launch the thread */
1009     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1010       tmp,                                /* description string */
1011       (vik_thr_func) map_download_thread, /* function to call within thread */
1012       mdi,                                /* pass along data */
1013       (vik_thr_free_func) mdi_free,       /* function to free pass along data */
1014       (vik_thr_free_func) mdi_cancel_cleanup,
1015       mdi->mapstoget );
1016     g_free ( tmp );
1017   }
1018   else
1019     mdi_free ( mdi );
1020 }
1021
1022 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1023 {
1024   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1025 }
1026 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1027 {
1028   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1029 }
1030
1031 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1032 {
1033   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1034     return FALSE;
1035   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1036   {
1037     if ( event->button == 1 )
1038     {
1039       VikCoord ul, br;
1040       vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &ul );
1041       vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &br );
1042       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1043       vml->dl_tool_x = vml->dl_tool_y = -1;
1044       return TRUE;
1045     }
1046     else
1047     {
1048       vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &(vml->redownload_ul) );
1049       vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &(vml->redownload_br) );
1050
1051       vml->redownload_vvp = vvp;
1052
1053       vml->dl_tool_x = vml->dl_tool_y = -1;
1054
1055       if ( ! vml->dl_right_click_menu ) {
1056         GtkWidget *item;
1057         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1058
1059         item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
1060         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1061         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1062
1063         item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
1064         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1065         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1066       }
1067
1068       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1069       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1070     }
1071   }
1072   return FALSE;
1073 }
1074
1075 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1076 {
1077   return vvp;
1078 }
1079
1080 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1081 {
1082   MapCoord tmp;
1083   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1084     return FALSE;
1085   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1086   if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1087        vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1088            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1089            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1090            &tmp ) ) {
1091     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1092     return TRUE;
1093   }
1094   return FALSE;
1095
1096  
1097 #if 0
1098   if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1099   {
1100     VikCoord coord;
1101     MapCoord mapcoord;
1102     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1103     if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1104                 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1105                 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1106                 &mapcoord ) ) {
1107       gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1108                      vml->cache_dir, __map_types[vml->maptype].uniq_id,
1109                      mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1110
1111       __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1112       g_free ( filename_buf );
1113       vik_layer_emit_update ( VIK_LAYER(vml) );
1114       return TRUE;
1115     }
1116   }
1117   return FALSE;
1118 #endif
1119 }
1120
1121 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1122 {
1123   VikMapsLayer *vml = vml_vvp[0];
1124   VikViewport *vvp = vml_vvp[1];
1125   VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1126
1127   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1128   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1129
1130   VikCoord ul, br;
1131   MapCoord ulm, brm;
1132
1133   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1134   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1135
1136   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1137   if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1138        vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1139        vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1140     start_download_thread ( vml, vvp, &ul, &br, redownload );
1141   else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1142     const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1143     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1144     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1145     g_free(err);
1146   }
1147   else
1148     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1149
1150 }
1151
1152 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1153 {
1154   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1155 }
1156
1157 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1158 {
1159   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1160 }
1161
1162 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1163 {
1164   static gpointer pass_along[2];
1165   GtkWidget *item;
1166   pass_along[0] = vml;
1167   pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1168
1169   item = gtk_menu_item_new();
1170   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1171   gtk_widget_show ( item );
1172
1173   item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
1174   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1175   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1176   gtk_widget_show ( item );
1177
1178   /* TODO Add GTK_STOCK_REFRESH icon */
1179   item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
1180   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1181   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1182   gtk_widget_show ( item );
1183 }