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