]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikmapslayer.c
Add copyright
[andy/viking.git] / src / vikmapslayer.c
index a1c2f96795d3dad81d890389fbb49e087ee567de..5e4bbc2ef9f0b91e31ec0ca26bee935237f26af6 100644 (file)
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
 
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
 
-#include <stdio.h>
+#ifdef HAVE_STRING_H
 #include <string.h>
 #include <string.h>
+#endif
+#ifdef HAVE_MATH_H
 #include <math.h>
 #include <math.h>
+#endif
+
 #include "globals.h"
 #include "coords.h"
 #include "vikcoord.h"
 #include "globals.h"
 #include "coords.h"
 #include "vikcoord.h"
@@ -46,7 +50,6 @@
 #include "vikviewport.h"
 #include "viklayer.h"
 #include "vikmapslayer.h"
 #include "vikviewport.h"
 #include "viklayer.h"
 #include "vikmapslayer.h"
-#include "vikmapslayer_pixmap.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -114,7 +117,7 @@ static VikLayerParamScale params_scales[] = {
 
 VikLayerParam maps_layer_params[] = {
   { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
 
 VikLayerParam maps_layer_params[] = {
   { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
-  { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory (Optional):"), VIK_LAYER_WIDGET_FILEENTRY },
+  { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
   { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
   { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
   { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
   { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
   { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
   { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
@@ -125,12 +128,12 @@ enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_
 static VikToolInterface maps_tools[] = {
   { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
     (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
 static VikToolInterface maps_tools[] = {
   { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
     (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
-    (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl },
+    (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
 };
 
 VikLayerInterface vik_maps_layer_interface = {
   N_("Map"),
 };
 
 VikLayerInterface vik_maps_layer_interface = {
   N_("Map"),
-  &mapslayer_pixbuf,
+  &vikmapslayer_pixbuf,
 
   maps_tools,
   sizeof(maps_tools) / sizeof(maps_tools[0]),
 
   maps_tools,
   sizeof(maps_tools) / sizeof(maps_tools[0]),
@@ -144,7 +147,7 @@ VikLayerInterface vik_maps_layer_interface = {
 
   (VikLayerFuncCreate)                  maps_layer_new,
   (VikLayerFuncRealize)                 NULL,
 
   (VikLayerFuncCreate)                  maps_layer_new,
   (VikLayerFuncRealize)                 NULL,
-                                        maps_layer_post_read,
+  (VikLayerFuncPostRead)                maps_layer_post_read,
   (VikLayerFuncFree)                    maps_layer_free,
 
   (VikLayerFuncProperties)              NULL,
   (VikLayerFuncFree)                    maps_layer_free,
 
   (VikLayerFuncProperties)              NULL,
@@ -203,20 +206,22 @@ enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH
 /******** MAPS LAYER TYPES **************/
 /****************************************/
 
 /******** MAPS LAYER TYPES **************/
 /****************************************/
 
-void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
+void maps_layer_register_map_source ( VikMapSource *map )
 {
 {
+  g_assert(map != NULL);
+  
+  guint id = vik_map_source_get_uniq_id(map);
+  const char *label = vik_map_source_get_label(map);
   g_assert(label != NULL);
   g_assert(label != NULL);
-  g_assert(map_type != NULL);
-  g_assert(id == map_type->uniq_id);
 
   /* Add the label */
   params_maptypes = g_list_append(params_maptypes, g_strdup(label));
 
   /* Add the id */
 
   /* Add the label */
   params_maptypes = g_list_append(params_maptypes, g_strdup(label));
 
   /* Add the id */
-  params_maptypes_ids = g_list_append(params_maptypes_ids, (gpointer)id);
+  params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
 
   /* We have to clone */
 
   /* We have to clone */
-  VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
+  VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
   /* Register the clone in the list */
   __map_types = g_list_append(__map_types, clone);
 
   /* Register the clone in the list */
   __map_types = g_list_append(__map_types, clone);
 
@@ -234,7 +239,7 @@ void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapTyp
 
 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
 
 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
-#define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
+#define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
 
 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
 {
 
 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
 {
@@ -251,14 +256,17 @@ gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
 /****************************************/
 
 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
 /****************************************/
 
 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
+#define MAPS_CACHE_DIR maps_layer_default_dir()
+
 #ifdef WINDOWS
 #ifdef WINDOWS
-#define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
+#include <io.h>
+#define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
+#define LOCAL_MAPS_DIR "VIKING-MAPS"
 #else /* POSIX */
 #else /* POSIX */
-
 #include <stdlib.h>
 #include <stdlib.h>
-
-#define MAPS_CACHE_DIR maps_layer_default_dir()
 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
+#define LOCAL_MAPS_DIR ".viking-maps"
+#endif
 
 gchar *maps_layer_default_dir ()
 {
 
 gchar *maps_layer_default_dir ()
 {
@@ -272,13 +280,13 @@ gchar *maps_layer_default_dir ()
     } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
       defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
     } else {
     } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
       defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
     } else {
-      const gchar *home = g_getenv("HOME");
+      const gchar *home = g_get_home_dir();
       if (!home || g_access(home, W_OK))
         home = g_get_home_dir ();
       if ( home )
       if (!home || g_access(home, W_OK))
         home = g_get_home_dir ();
       if ( home )
-        defaultdir = g_build_filename ( home, ".viking-maps", NULL );
+        defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
       else
       else
-        defaultdir = g_strdup ( ".viking-maps" );
+        defaultdir = g_strdup ( LOCAL_MAPS_DIR );
     }
     if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
     {
     }
     if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
     {
@@ -292,8 +300,6 @@ gchar *maps_layer_default_dir ()
   return defaultdir;
 }
 
   return defaultdir;
 }
 
-#endif
-
 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
 {
   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
 {
   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
@@ -362,14 +368,14 @@ GType vik_maps_layer_get_type ()
 static guint map_index_to_uniq_id (guint8 index)
 {
   g_assert ( index < NUM_MAP_TYPES );
 static guint map_index_to_uniq_id (guint8 index)
 {
   g_assert ( index < NUM_MAP_TYPES );
-  return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
+  return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
 }
 
 static guint map_uniq_id_to_index ( guint uniq_id )
 {
   gint i;
   for ( i = 0; i < NUM_MAP_TYPES; i++ )
 }
 
 static guint map_uniq_id_to_index ( guint uniq_id )
 {
   gint i;
   for ( i = 0; i < NUM_MAP_TYPES; i++ )
-    if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
+    if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
       return i;
   return NUM_MAP_TYPES; /* no such thing */
 }
       return i;
   return NUM_MAP_TYPES; /* no such thing */
 }
@@ -401,7 +407,7 @@ static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
   VikLayerParamData rv;
   switch ( id )
   {
   VikLayerParamData rv;
   switch ( id )
   {
-    case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
+    case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
     case PARAM_ALPHA: rv.u = vml->alpha; break;
     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
     case PARAM_ALPHA: rv.u = vml->alpha; break;
     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
@@ -454,12 +460,12 @@ static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_f
      * So, we can check if we have to inform the user about inconsistency */
     VikViewportDrawMode vp_drawmode;
     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
      * So, we can check if we have to inform the user about inconsistency */
     VikViewportDrawMode vp_drawmode;
     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
-    VikMapsLayer_MapType *map_type = NULL;
+    VikMapSource *map = NULL;
  
     vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
  
     vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
-    map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
-    if (map_type->drawmode != vp_drawmode) {
-      const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode);
+    map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+    if (vik_map_source_get_drawmode(map) != vp_drawmode) {
+      const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
       g_free(msg);
       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
       g_free(msg);
@@ -512,7 +518,7 @@ static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdou
 {
   GdkPixbuf *tmp;
   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
 {
   GdkPixbuf *tmp;
   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
-  tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
+  tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
   g_object_unref ( G_OBJECT(pixbuf) );
   return tmp;
 }
   g_object_unref ( G_OBJECT(pixbuf) );
   return tmp;
 }
@@ -550,7 +556,7 @@ static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord,
             pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
 
           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
             pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
 
           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
-              mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id, 
+              mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
         }
       }
               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
         }
       }
@@ -609,15 +615,15 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
   }
 
   /* coord -> ID */
   }
 
   /* coord -> ID */
-  VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
-  if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
-       map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
+  VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+  if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
+       vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
 
     /* loop & draw */
     gint x, y;
     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
 
     /* loop & draw */
     gint x, y;
     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
-    gint mode = map_type->uniq_id;
+    gint mode = vik_map_source_get_uniq_id(map);
 
     VikCoord coord;
     gint xx, yy, width, height;
 
     VikCoord coord;
     gint xx, yy, width, height;
@@ -633,7 +639,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
       start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
     }
 
       start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
     }
 
-    if ( map_type->tilesize_x == 0 && !existence_only ) {
+    if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
       for ( x = xmin; x <= xmax; x++ ) {
         for ( y = ymin; y <= ymax; y++ ) {
           ulm.x = x;
       for ( x = xmin; x <= xmax; x++ ) {
         for ( y = ymin; y <= ymax; y++ ) {
           ulm.x = x;
@@ -643,7 +649,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
             width = gdk_pixbuf_get_width ( pixbuf );
             height = gdk_pixbuf_get_height ( pixbuf );
 
             width = gdk_pixbuf_get_width ( pixbuf );
             height = gdk_pixbuf_get_height ( pixbuf );
 
-            map_type->mapcoord_to_center_coord ( &ulm, &coord );
+            vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
             xx -= (width/2);
             yy -= (height/2);
             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
             xx -= (width/2);
             yy -= (height/2);
@@ -653,8 +659,8 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
         }
       }
     } else { /* tilesize is known, don't have to keep converting coords */
         }
       }
     } else { /* tilesize is known, don't have to keep converting coords */
-      gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
-      gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
+      gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
+      gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
       gint tilesize_x_ceil = ceil ( tilesize_x );
       gint tilesize_y_ceil = ceil ( tilesize_y );
       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
       gint tilesize_x_ceil = ceil ( tilesize_x );
       gint tilesize_y_ceil = ceil ( tilesize_y );
@@ -668,7 +674,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
 
       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
 
-      map_type->mapcoord_to_center_coord ( &ulm, &coord );
+      vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
       xx = xx_tmp; yy = yy_tmp;
       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
       xx = xx_tmp; yy = yy_tmp;
       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
@@ -693,6 +699,24 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
             pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
             if ( pixbuf )
               vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
             pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
             if ( pixbuf )
               vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+            else {
+              /* retry with bigger shrinkfactor */
+              int scale_inc;
+              for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
+                int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
+                MapCoord ulm2 = ulm;
+                ulm2.x = ulm.x / scale_factor;
+                ulm2.y = ulm.y / scale_factor;
+                ulm2.scale = ulm.scale + scale_inc;
+                pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
+                if ( pixbuf ) {
+                  gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
+                  gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
+                  vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+                  break;
+                }
+              }
+            }
           }
 
           yy += tilesize_y;
           }
 
           yy += tilesize_y;
@@ -707,7 +731,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
 
 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
 {
 
 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
 {
-  if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
+  if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
   {
     VikCoord ul, br;
 
   {
     VikCoord ul, br;
 
@@ -770,7 +794,7 @@ static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
   g_mutex_unlock(mdi->mutex);
 }
 
   g_mutex_unlock(mdi->mutex);
 }
 
-static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
+static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 {
   guint donemaps = 0;
   gint x, y;
 {
   guint donemaps = 0;
   gint x, y;
@@ -781,14 +805,16 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
       gboolean remove_mem_cache = FALSE;
       gboolean need_download = FALSE;
       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
       gboolean remove_mem_cache = FALSE;
       gboolean need_download = FALSE;
       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
-                     mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
+                     mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
 
       donemaps++;
                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
 
       donemaps++;
-      a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
+      int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
+      if (res != 0)
+        return -1;
 
       if ( mdi->redownload == REDOWNLOAD_ALL)
 
       if ( mdi->redownload == REDOWNLOAD_ALL)
-        remove ( mdi->filename_buf );
+        g_remove ( mdi->filename_buf );
 
       else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
       {
 
       else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
       {
@@ -796,7 +822,7 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
         GError *gx = NULL;
         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
         if (gx || (!pixbuf))
         GError *gx = NULL;
         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
         if (gx || (!pixbuf))
-          remove ( mdi->filename_buf );
+          g_remove ( mdi->filename_buf );
         if ( pixbuf )
           g_object_unref ( pixbuf );
         if ( gx )
         if ( pixbuf )
           g_object_unref ( pixbuf );
         if ( gx )
@@ -817,14 +843,14 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
 
       if (need_download) {
       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
 
       if (need_download) {
-        if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
+        if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf ))
           continue;
       }
 
       gdk_threads_enter();
       g_mutex_lock(mdi->mutex);
       if (remove_mem_cache)
           continue;
       }
 
       gdk_threads_enter();
       g_mutex_lock(mdi->mutex);
       if (remove_mem_cache)
-          a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
+          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 );
       if (mdi->refresh_display && mdi->map_layer_alive) {
         /* TODO: check if it's on visible area */
         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
       if (mdi->refresh_display && mdi->map_layer_alive) {
         /* TODO: check if it's on visible area */
         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
@@ -839,6 +865,7 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
   if (mdi->map_layer_alive)
     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
   g_mutex_unlock(mdi->mutex); 
   if (mdi->map_layer_alive)
     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
   g_mutex_unlock(mdi->mutex); 
+  return 0;
 }
 
 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
 }
 
 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
@@ -846,11 +873,11 @@ static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
   if ( mdi->mapcoord.x || mdi->mapcoord.y )
   {
     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
   if ( mdi->mapcoord.x || mdi->mapcoord.y )
   {
     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
-                     mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
+                     mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
     {
                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
     {
-      remove ( mdi->filename_buf );
+      g_remove ( mdi->filename_buf );
     }
   }
 }
     }
   }
 }
@@ -860,9 +887,9 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
   MapCoord ulm, brm;
   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
   MapCoord ulm, brm;
-  VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
-  if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) 
-    && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
+  VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+  if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
+    && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
   {
     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
     gint a, b;
   {
     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
     gint a, b;
@@ -899,7 +926,7 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
         for ( b = mdi->y0; b <= mdi->yf; b++ )
         {
           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
         for ( b = mdi->y0; b <= mdi->yf; b++ )
         {
           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
-                       vml->cache_dir, map_type->uniq_id, ulm.scale,
+                       vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
                        ulm.z, a, b );
           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
             mdi->mapstoget++;
                        ulm.z, a, b );
           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
             mdi->mapstoget++;
@@ -946,10 +973,10 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
 {
   MapCoord ulm, brm;
 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
 {
   MapCoord ulm, brm;
-  VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
+  VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
 
 
-  if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm) 
-    || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
+  if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
+    || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
     return;
   }
     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
     return;
   }
@@ -982,7 +1009,7 @@ void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport
   for (i = mdi->x0; i <= mdi->xf; i++) {
     for (j = mdi->y0; j <= mdi->yf; j++) {
       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
   for (i = mdi->x0; i <= mdi->xf; i++) {
     for (j = mdi->y0; j <= mdi->yf; j++) {
       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
-                   vml->cache_dir, map_type->uniq_id, ulm.scale,
+                   vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
                    ulm.z, i, j );
       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
             mdi->mapstoget++;
                    ulm.z, i, j );
       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
             mdi->mapstoget++;
@@ -1077,9 +1104,9 @@ static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *e
   MapCoord tmp;
   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
     return FALSE;
   MapCoord tmp;
   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
     return FALSE;
-  VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
-  if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
-       map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
+  VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+  if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
+       vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
            &tmp ) ) {
            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
            &tmp ) ) {
@@ -1128,13 +1155,13 @@ static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
 
   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
 
-  VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
-  if ( map_type->drawmode == vp_drawmode &&
-       map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
-       map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
+  VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+  if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
+       vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
+       vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
     start_download_thread ( vml, vvp, &ul, &br, redownload );
     start_download_thread ( vml, vvp, &ul, &br, redownload );
-  else if (map_type->drawmode != vp_drawmode) {
-    const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
+  else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
+    const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
     g_free(err);
     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
     g_free(err);
@@ -1170,6 +1197,7 @@ static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLay
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
+  /* TODO Add GTK_STOCK_REFRESH icon */
   item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);