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