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