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