]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
Create the geonames search as an VikXmlSearchTool
[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_NEAREST);
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             else {
703               /* retry with bigger shrinkfactor */
704               int scale_inc;
705               for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
706                 int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
707                 MapCoord ulm2 = ulm;
708                 ulm2.x = ulm.x / scale_factor;
709                 ulm2.y = ulm.y / scale_factor;
710                 ulm2.scale = ulm.scale + scale_inc;
711                 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
712                 if ( pixbuf ) {
713                   gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
714                   gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
715                   vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
716                   break;
717                 }
718               }
719             }
720           }
721
722           yy += tilesize_y;
723         }
724         xx += tilesize_x;
725       }
726     }
727
728     g_free ( path_buf );
729   }
730 }
731
732 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
733 {
734   if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
735   {
736     VikCoord ul, br;
737
738     /* get corner coords */
739     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
740       /* UTM multi-zone stuff by Kit Transue */
741       gchar leftmost_zone, rightmost_zone, i;
742       leftmost_zone = vik_viewport_leftmost_zone( vvp );
743       rightmost_zone = vik_viewport_rightmost_zone( vvp );
744       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
745         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
746         maps_layer_draw_section ( vml, vvp, &ul, &br );
747       }
748     }
749     else {
750       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
751       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
752
753       maps_layer_draw_section ( vml, vvp, &ul, &br );
754     }
755   }
756 }
757
758 /*************************/
759 /****** DOWNLOADING ******/
760 /*************************/
761
762 /* pass along data to thread, exists even if layer is deleted. */
763 typedef struct {
764   gchar *cache_dir;
765   gchar *filename_buf;
766   gint x0, y0, xf, yf;
767   MapCoord mapcoord;
768   gint maptype;
769   gint maxlen;
770   gint mapstoget;
771   gint redownload;
772   gboolean refresh_display;
773   VikMapsLayer *vml;
774   VikViewport *vvp;
775   gboolean map_layer_alive;
776   GMutex *mutex;
777 } MapDownloadInfo;
778
779 static void mdi_free ( MapDownloadInfo *mdi )
780 {
781   g_mutex_free(mdi->mutex);
782   g_free ( mdi->cache_dir );
783   mdi->cache_dir = NULL;
784   g_free ( mdi->filename_buf );
785   mdi->filename_buf = NULL;
786   g_free ( mdi );
787 }
788
789 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
790 {
791   MapDownloadInfo *mdi = ptr;
792   g_mutex_lock(mdi->mutex);
793   mdi->map_layer_alive = FALSE;
794   g_mutex_unlock(mdi->mutex);
795 }
796
797 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
798 {
799   guint donemaps = 0;
800   gint x, y;
801   for ( x = mdi->x0; x <= mdi->xf; x++ )
802   {
803     for ( y = mdi->y0; y <= mdi->yf; y++ )
804     {
805       gboolean remove_mem_cache = FALSE;
806       gboolean need_download = FALSE;
807       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
808                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
809                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
810
811       donemaps++;
812       int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
813       if (res != 0)
814         return -1;
815
816       if ( mdi->redownload == REDOWNLOAD_ALL)
817         g_remove ( mdi->filename_buf );
818
819       else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
820       {
821         /* see if this one is bad or what */
822         GError *gx = NULL;
823         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
824         if (gx || (!pixbuf))
825           g_remove ( mdi->filename_buf );
826         if ( pixbuf )
827           g_object_unref ( pixbuf );
828         if ( gx )
829           g_error_free ( gx );
830       }
831
832       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
833       {
834         need_download = TRUE;
835         if (( mdi->redownload != REDOWNLOAD_NONE ) &&
836             ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
837           remove_mem_cache = TRUE;
838       } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
839         remove_mem_cache = TRUE;
840       } else
841         continue;
842
843       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
844
845       if (need_download) {
846         if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf ))
847           continue;
848       }
849
850       gdk_threads_enter();
851       g_mutex_lock(mdi->mutex);
852       if (remove_mem_cache)
853           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 );
854       if (mdi->refresh_display && mdi->map_layer_alive) {
855         /* TODO: check if it's on visible area */
856         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
857       }
858       g_mutex_unlock(mdi->mutex);
859       gdk_threads_leave();
860       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
861
862     }
863   }
864   g_mutex_lock(mdi->mutex);
865   if (mdi->map_layer_alive)
866     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
867   g_mutex_unlock(mdi->mutex); 
868   return 0;
869 }
870
871 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
872 {
873   if ( mdi->mapcoord.x || mdi->mapcoord.y )
874   {
875     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
876                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
877                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
878     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
879     {
880       g_remove ( mdi->filename_buf );
881     }
882   }
883 }
884
885 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
886 {
887   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
888   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
889   MapCoord ulm, brm;
890   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
891   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
892     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
893   {
894     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
895     gint a, b;
896
897     mdi->vml = vml;
898     mdi->vvp = vvp;
899     mdi->map_layer_alive = TRUE;
900     mdi->mutex = g_mutex_new();
901     mdi->refresh_display = TRUE;
902
903     /* cache_dir and buffer for dest filename */
904     mdi->cache_dir = g_strdup ( vml->cache_dir );
905     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
906     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
907     mdi->maptype = vml->maptype;
908
909     mdi->mapcoord = ulm;
910
911     mdi->redownload = redownload;
912
913     mdi->x0 = MIN(ulm.x, brm.x);
914     mdi->xf = MAX(ulm.x, brm.x);
915     mdi->y0 = MIN(ulm.y, brm.y);
916     mdi->yf = MAX(ulm.y, brm.y);
917
918     mdi->mapstoget = 0;
919
920     if ( mdi->redownload ) {
921       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
922     } else {
923       /* calculate how many we need */
924       for ( a = mdi->x0; a <= mdi->xf; a++ )
925       {
926         for ( b = mdi->y0; b <= mdi->yf; b++ )
927         {
928           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
929                        vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
930                        ulm.z, a, b );
931           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
932             mdi->mapstoget++;
933         }
934       }
935     }
936
937     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
938
939     if ( mdi->mapstoget )
940     {
941       const gchar *tmp_str;
942       gchar *tmp;
943
944       if (redownload) 
945       {
946         if (redownload == REDOWNLOAD_BAD)
947           tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
948         else
949           tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
950       } 
951       else 
952       {
953         tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
954       }
955       tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
956  
957       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
958       /* launch the thread */
959       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
960                             tmp,                                              /* description string */
961                             (vik_thr_func) map_download_thread,               /* function to call within thread */
962                             mdi,                                              /* pass along data */
963                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
964                             (vik_thr_free_func) mdi_cancel_cleanup,
965                             mdi->mapstoget );
966       g_free ( tmp );
967     }
968     else
969       mdi_free ( mdi );
970   }
971 }
972
973 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
974 {
975   MapCoord ulm, brm;
976   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
977
978   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
979     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
980     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
981     return;
982   }
983
984   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
985   gint i, j;
986
987   mdi->vml = vml;
988   mdi->vvp = vvp;
989   mdi->map_layer_alive = TRUE;
990   mdi->mutex = g_mutex_new();
991   mdi->refresh_display = FALSE;
992
993   mdi->cache_dir = g_strdup ( vml->cache_dir );
994   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
995   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
996   mdi->maptype = vml->maptype;
997
998   mdi->mapcoord = ulm;
999
1000   mdi->redownload = REDOWNLOAD_NONE;
1001
1002   mdi->x0 = MIN(ulm.x, brm.x);
1003   mdi->xf = MAX(ulm.x, brm.x);
1004   mdi->y0 = MIN(ulm.y, brm.y);
1005   mdi->yf = MAX(ulm.y, brm.y);
1006
1007   mdi->mapstoget = 0;
1008
1009   for (i = mdi->x0; i <= mdi->xf; i++) {
1010     for (j = mdi->y0; j <= mdi->yf; j++) {
1011       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1012                    vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1013                    ulm.z, i, j );
1014       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1015             mdi->mapstoget++;
1016     }
1017   }
1018
1019   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1020
1021   if (mdi->mapstoget) {
1022     gchar *tmp;
1023     const gchar *fmt;
1024     fmt = ngettext("Downloading %d %s map...",
1025                    "Downloading %d %s maps...",
1026                    mdi->mapstoget);
1027     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1028
1029     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1030       /* launch the thread */
1031     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1032       tmp,                                /* description string */
1033       (vik_thr_func) map_download_thread, /* function to call within thread */
1034       mdi,                                /* pass along data */
1035       (vik_thr_free_func) mdi_free,       /* function to free pass along data */
1036       (vik_thr_free_func) mdi_cancel_cleanup,
1037       mdi->mapstoget );
1038     g_free ( tmp );
1039   }
1040   else
1041     mdi_free ( mdi );
1042 }
1043
1044 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1045 {
1046   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1047 }
1048 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1049 {
1050   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1051 }
1052
1053 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1054 {
1055   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1056     return FALSE;
1057   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1058   {
1059     if ( event->button == 1 )
1060     {
1061       VikCoord ul, br;
1062       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 );
1063       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 );
1064       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1065       vml->dl_tool_x = vml->dl_tool_y = -1;
1066       return TRUE;
1067     }
1068     else
1069     {
1070       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) );
1071       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) );
1072
1073       vml->redownload_vvp = vvp;
1074
1075       vml->dl_tool_x = vml->dl_tool_y = -1;
1076
1077       if ( ! vml->dl_right_click_menu ) {
1078         GtkWidget *item;
1079         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1080
1081         item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
1082         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1083         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1084
1085         item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
1086         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1087         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1088       }
1089
1090       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1091       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1092     }
1093   }
1094   return FALSE;
1095 }
1096
1097 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1098 {
1099   return vvp;
1100 }
1101
1102 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1103 {
1104   MapCoord tmp;
1105   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1106     return FALSE;
1107   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1108   if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1109        vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1110            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1111            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1112            &tmp ) ) {
1113     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1114     return TRUE;
1115   }
1116   return FALSE;
1117
1118  
1119 #if 0
1120   if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1121   {
1122     VikCoord coord;
1123     MapCoord mapcoord;
1124     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1125     if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1126                 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1127                 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1128                 &mapcoord ) ) {
1129       gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1130                      vml->cache_dir, __map_types[vml->maptype].uniq_id,
1131                      mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1132
1133       __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1134       g_free ( filename_buf );
1135       vik_layer_emit_update ( VIK_LAYER(vml) );
1136       return TRUE;
1137     }
1138   }
1139   return FALSE;
1140 #endif
1141 }
1142
1143 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1144 {
1145   VikMapsLayer *vml = vml_vvp[0];
1146   VikViewport *vvp = vml_vvp[1];
1147   VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1148
1149   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1150   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1151
1152   VikCoord ul, br;
1153   MapCoord ulm, brm;
1154
1155   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1156   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1157
1158   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1159   if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1160        vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1161        vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1162     start_download_thread ( vml, vvp, &ul, &br, redownload );
1163   else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1164     const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1165     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1166     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1167     g_free(err);
1168   }
1169   else
1170     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1171
1172 }
1173
1174 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1175 {
1176   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1177 }
1178
1179 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1180 {
1181   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1182 }
1183
1184 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1185 {
1186   static gpointer pass_along[2];
1187   GtkWidget *item;
1188   pass_along[0] = vml;
1189   pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1190
1191   item = gtk_menu_item_new();
1192   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1193   gtk_widget_show ( item );
1194
1195   item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
1196   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1197   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1198   gtk_widget_show ( item );
1199
1200   /* TODO Add GTK_STOCK_REFRESH icon */
1201   item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
1202   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1203   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1204   gtk_widget_show ( item );
1205 }