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