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