]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
Make Google Map default map type.
[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 = 6;   /* index to __map_types[] */
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 #ifdef DEBUG
601       fputs(stderr, "DEBUG: Starting autodownload\n");
602 #endif
603       start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
604     }
605
606     if ( map_type->tilesize_x == 0 ) {
607       for ( x = xmin; x <= xmax; x++ ) {
608         for ( y = ymin; y <= ymax; y++ ) {
609           ulm.x = x;
610           ulm.y = y;
611           pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
612           if ( pixbuf ) {
613             width = gdk_pixbuf_get_width ( pixbuf );
614             height = gdk_pixbuf_get_height ( pixbuf );
615
616             map_type->mapcoord_to_center_coord ( &ulm, &coord );
617             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
618             xx -= (width/2);
619             yy -= (height/2);
620
621             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
622           }
623         }
624       }
625     } else { /* tilesize is known, don't have to keep converting coords */
626       gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
627       gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
628       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
629       gint tilesize_x_ceil = ceil ( tilesize_x );
630       gint tilesize_y_ceil = ceil ( tilesize_y );
631       gint8 xinc = (ulm.x == xmin) ? 1 : -1;
632       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
633       gdouble xx, yy; gint xx_tmp, yy_tmp;
634       gint base_yy, xend, yend;
635       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
636       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
637
638       map_type->mapcoord_to_center_coord ( &ulm, &coord );
639       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
640       xx = xx_tmp; yy = yy_tmp;
641       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
642        * eg if tile size 128, shrinkfactor 0.333 */
643       xx -= (tilesize_x/2);
644       base_yy = yy - (tilesize_y/2);
645
646       for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
647         yy = base_yy;
648         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
649           ulm.x = x;
650           ulm.y = y;
651           pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
652           if ( pixbuf )
653             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
654
655           yy += tilesize_y;
656         }
657         xx += tilesize_x;
658       }
659     }
660
661     g_free ( path_buf );
662   }
663 }
664
665 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
666 {
667   if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
668   {
669     VikCoord ul, br;
670
671     /* get corner coords */
672     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
673       /* UTM multi-zone stuff by Kit Transue */
674       gchar leftmost_zone, rightmost_zone, i;
675       leftmost_zone = vik_viewport_leftmost_zone( vvp );
676       rightmost_zone = vik_viewport_rightmost_zone( vvp );
677       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
678         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
679         maps_layer_draw_section ( vml, vvp, &ul, &br );
680       }
681     }
682     else {
683       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
684       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
685
686       maps_layer_draw_section ( vml, vvp, &ul, &br );
687     }
688   }
689 }
690
691 /*************************/
692 /****** DOWNLOADING ******/
693 /*************************/
694
695 /* pass along data to thread, exists even if layer is deleted. */
696 typedef struct {
697   gchar *cache_dir;
698   gchar *filename_buf;
699   gint x0, y0, xf, yf;
700   MapCoord mapcoord;
701   gint maptype;
702   gint maxlen;
703   gint mapstoget;
704   gint redownload;
705   gboolean refresh_display;
706   VikMapsLayer *vml;
707   VikViewport *vvp;
708   gboolean map_layer_alive;
709   GMutex *mutex;
710 } MapDownloadInfo;
711
712 static void mdi_free ( MapDownloadInfo *mdi )
713 {
714   g_mutex_free(mdi->mutex);
715   g_free ( mdi->cache_dir );
716   g_free ( mdi->filename_buf );
717   g_free ( mdi );
718 }
719
720 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
721 {
722   MapDownloadInfo *mdi = ptr;
723   g_mutex_lock(mdi->mutex);
724   mdi->map_layer_alive = FALSE;
725   g_mutex_unlock(mdi->mutex);
726 }
727
728 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
729 {
730   guint donemaps = 0;
731   gint x, y;
732   for ( x = mdi->x0; x <= mdi->xf; x++ )
733   {
734     for ( y = mdi->y0; y <= mdi->yf; y++ )
735     {
736       gboolean remove_mem_cache = FALSE;
737       gboolean need_download = FALSE;
738       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
739                      mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
740                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
741
742       donemaps++;
743       a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
744
745       if ( mdi->redownload == REDOWNLOAD_ALL)
746         remove ( mdi->filename_buf );
747
748       else if ( (mdi->redownload == REDOWNLOAD_BAD) && (access ( mdi->filename_buf, F_OK ) == 0) )
749       {
750         /* see if this one is bad or what */
751         GError *gx = NULL;
752         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
753         if (gx || (!pixbuf))
754           remove ( mdi->filename_buf );
755         if ( pixbuf )
756           g_object_unref ( pixbuf );
757         if ( gx )
758           g_error_free ( gx );
759       }
760
761       if ( access ( mdi->filename_buf, F_OK ) != 0 )
762       {
763         need_download = TRUE;
764         if (( mdi->redownload != REDOWNLOAD_NONE ) &&
765             ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
766           remove_mem_cache = TRUE;
767       } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
768         remove_mem_cache = TRUE;
769       } else
770         continue;
771
772       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
773
774       if (need_download) {
775         if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
776           continue;
777       }
778
779       gdk_threads_enter();
780       g_mutex_lock(mdi->mutex);
781       if (remove_mem_cache)
782           a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
783       if (mdi->refresh_display && mdi->map_layer_alive) {
784         /* TODO: check if it's on visible area */
785         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
786       }
787       g_mutex_unlock(mdi->mutex);
788       gdk_threads_leave();
789       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
790
791     }
792   }
793   g_mutex_lock(mdi->mutex);
794   if (mdi->map_layer_alive)
795     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
796   g_mutex_unlock(mdi->mutex); 
797 }
798
799 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
800 {
801   if ( mdi->mapcoord.x || mdi->mapcoord.y )
802   {
803     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
804                      mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
805                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
806     if ( access ( mdi->filename_buf, F_OK ) == 0)
807     {
808       remove ( mdi->filename_buf );
809     }
810   }
811 }
812
813 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
814 {
815   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
816   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
817   MapCoord ulm, brm;
818   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
819   if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) 
820     && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
821   {
822     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
823     gint a, b;
824
825     mdi->vml = vml;
826     mdi->vvp = vvp;
827     mdi->map_layer_alive = TRUE;
828     mdi->mutex = g_mutex_new();
829     mdi->refresh_display = TRUE;
830
831     /* cache_dir and buffer for dest filename */
832     mdi->cache_dir = g_strdup ( vml->cache_dir );
833     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
834     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
835     mdi->maptype = vml->maptype;
836
837     mdi->mapcoord = ulm;
838
839     mdi->redownload = redownload;
840
841     mdi->x0 = MIN(ulm.x, brm.x);
842     mdi->xf = MAX(ulm.x, brm.x);
843     mdi->y0 = MIN(ulm.y, brm.y);
844     mdi->yf = MAX(ulm.y, brm.y);
845
846     mdi->mapstoget = 0;
847
848     if ( mdi->redownload ) {
849       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
850     } else {
851       /* calculate how many we need */
852       for ( a = mdi->x0; a <= mdi->xf; a++ )
853       {
854         for ( b = mdi->y0; b <= mdi->yf; b++ )
855         {
856           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
857                        vml->cache_dir, map_type->uniq_id, ulm.scale,
858                        ulm.z, a, b );
859           if ( access ( mdi->filename_buf, F_OK ) != 0)
860             mdi->mapstoget++;
861         }
862       }
863     }
864
865     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
866
867     if ( mdi->mapstoget )
868     {
869       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" );
870
871       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
872       /* launch the thread */
873       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
874                             tmp,                                              /* description string */
875                             (vik_thr_func) map_download_thread,               /* function to call within thread */
876                             mdi,                                              /* pass along data */
877                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
878                             (vik_thr_free_func) mdi_cancel_cleanup,
879                             mdi->mapstoget );
880       g_free ( tmp );
881     }
882     else
883       mdi_free ( mdi );
884   }
885 }
886
887 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
888 {
889   MapCoord ulm, brm;
890   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
891
892   if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm) 
893     || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
894     g_warning("%s() coord_to_mapcoord() failed\n", __PRETTY_FUNCTION__);
895     return;
896   }
897
898   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
899   gint i, j;
900
901   mdi->vml = vml;
902   mdi->vvp = vvp;
903   mdi->map_layer_alive = TRUE;
904   mdi->mutex = g_mutex_new();
905   mdi->refresh_display = FALSE;
906
907   mdi->cache_dir = g_strdup ( vml->cache_dir );
908   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
909   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
910   mdi->maptype = vml->maptype;
911
912   mdi->mapcoord = ulm;
913
914   mdi->redownload = REDOWNLOAD_NONE;
915
916   mdi->x0 = MIN(ulm.x, brm.x);
917   mdi->xf = MAX(ulm.x, brm.x);
918   mdi->y0 = MIN(ulm.y, brm.y);
919   mdi->yf = MAX(ulm.y, brm.y);
920
921   mdi->mapstoget = 0;
922
923   for (i = mdi->x0; i <= mdi->xf; i++) {
924     for (j = mdi->y0; j <= mdi->yf; j++) {
925       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
926                    vml->cache_dir, map_type->uniq_id, ulm.scale,
927                    ulm.z, i, j );
928       if ( access ( mdi->filename_buf, F_OK ) != 0)
929             mdi->mapstoget++;
930     }
931   }
932
933   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
934
935   if (mdi->mapstoget) {
936     gchar *tmp = g_strdup_printf ( "%s %d %s %s...", "Downloading", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), (mdi->mapstoget == 1) ? "map" : "maps" );
937
938     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
939       /* launch the thread */
940     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
941       tmp,                                /* description string */
942       (vik_thr_func) map_download_thread, /* function to call within thread */
943       mdi,                                /* pass along data */
944       (vik_thr_free_func) mdi_free,       /* function to free pass along data */
945       (vik_thr_free_func) mdi_cancel_cleanup,
946       mdi->mapstoget );
947     g_free ( tmp );
948   }
949   else
950     mdi_free ( mdi );
951 }
952
953 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
954 {
955   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
956 }
957 static void maps_layer_redownload_all ( VikMapsLayer *vml )
958 {
959   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
960 }
961
962 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
963 {
964   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
965     return FALSE;
966   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
967   {
968     if ( event->button == 1 )
969     {
970       VikCoord ul, br;
971       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 );
972       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 );
973       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
974       vml->dl_tool_x = vml->dl_tool_y = -1;
975       return TRUE;
976     }
977     else
978     {
979       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) );
980       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) );
981
982       vml->redownload_vvp = vvp;
983
984       vml->dl_tool_x = vml->dl_tool_y = -1;
985
986       if ( ! vml->dl_right_click_menu ) {
987         GtkWidget *item;
988         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
989
990         item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
991         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
992         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
993
994         item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
995         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
996         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
997       }
998
999       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1000       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1001     }
1002   }
1003   return FALSE;
1004 }
1005
1006 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1007 {
1008   return vvp;
1009 }
1010
1011 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1012 {
1013   MapCoord tmp;
1014   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1015     return FALSE;
1016   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1017   if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1018        map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
1019            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1020            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1021            &tmp ) ) {
1022     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1023     return TRUE;
1024   }
1025   return FALSE;
1026
1027  
1028 #if 0
1029   if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1030   {
1031     VikCoord coord;
1032     MapCoord mapcoord;
1033     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1034     if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1035                 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1036                 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1037                 &mapcoord ) ) {
1038       gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1039                      vml->cache_dir, __map_types[vml->maptype].uniq_id,
1040                      mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1041
1042       __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1043       g_free ( filename_buf );
1044       vik_layer_emit_update ( VIK_LAYER(vml) );
1045       return TRUE;
1046     }
1047   }
1048   return FALSE;
1049 #endif
1050 }
1051
1052 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1053 {
1054   VikMapsLayer *vml = vml_vvp[0];
1055   VikViewport *vvp = vml_vvp[1];
1056
1057   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1058   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1059
1060   VikCoord ul, br;
1061   MapCoord ulm, brm;
1062
1063   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1064   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1065
1066   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1067   if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1068        map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1069        map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
1070     start_download_thread ( vml, vvp, &ul, &br, redownload );
1071   else
1072     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
1073
1074 }
1075
1076 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1077 {
1078   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1079 }
1080
1081 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1082 {
1083   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1084 }
1085
1086 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1087 {
1088   static gpointer pass_along[2];
1089   GtkWidget *item;
1090   pass_along[0] = vml;
1091   pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1092
1093   item = gtk_menu_item_new();
1094   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1095   gtk_widget_show ( item );
1096
1097   item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
1098   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1099   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1100   gtk_widget_show ( item );
1101
1102   item = gtk_menu_item_new_with_label ( "Refresh Onscreen Tiles" );
1103   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1104   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1105   gtk_widget_show ( item );
1106 }