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