]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Relax dependencies about glib
[andy/viking.git] / src / viktrwlayer.c
index f5b182b3355305e71a6db9f2f294ceadfee4d9d9..149b39da7598b5eac6fd8705c001a753b16f912b 100644 (file)
 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
 /* viktrwlayer.c -- 2200 lines can make a difference in the state of things */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include "viking.h"
+#include "vikmapslayer.h"
 #include "viktrwlayer_pixmap.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "thumbnails.h"
 #include "background.h"
 #include "gpx.h"
+#include "babel.h"
+#include "dem.h"
+#include "dems.h"
+#ifdef VIK_CONFIG_OPENSTREETMAP
+#include "osm-traces.h"
+#endif
+
+#include "icons/icons.h"
 
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 
+/* Relax some dependencies */
+#if ! GLIB_CHECK_VERSION(2,12,0)
+static gboolean return_true (gpointer a, gpointer b, gpointer c) { return TRUE; }
+static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
+#endif
+
+#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%f,%f to %f,%f&output=js\" 2>/dev/null)"
 #define VIK_TRW_LAYER_TRACK_GC 13
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
@@ -93,6 +113,7 @@ struct _VikTrwLayer {
   gdouble velocity_min, velocity_max;
   GArray *track_gc;
   guint16 track_gc_iter;
+  GdkGC *current_track_gc;
   GdkGC *track_bg_gc;
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
@@ -121,6 +142,14 @@ struct _VikTrwLayer {
   /* track editing tool -- more specifically, moving tps */
   gboolean moving_tp;
 
+  /* magic scissors tool */
+  gboolean magic_scissors_started;
+  VikCoord magic_scissors_coord;
+  gboolean magic_scissors_check_added_track;
+  gchar *magic_scissors_added_track_name;
+  VikTrack *magic_scissors_current_track;
+  gboolean magic_scissors_append;
+
   gboolean drawlabels;
   gboolean drawimages;
   guint8 image_alpha;
@@ -179,6 +208,7 @@ static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] );
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
+static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]);
 static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
 static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type );
 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
@@ -194,7 +224,6 @@ static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pas
 static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
 
 
-static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp );
 static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len );
 static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp );
 
@@ -223,10 +252,15 @@ static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
 static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
 static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
+static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+
 
 static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str );
 
@@ -245,24 +279,31 @@ static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_
 
 static VikToolInterface trw_layer_tools[] = {
   { "Create Waypoint", (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL },
+    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, &cursor_addwp },
 
   { "Create Track",    (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_new_track_click,       NULL, NULL },
+    (VikToolMouseFunc) tool_new_track_click,       NULL, NULL, &cursor_addtr },
+
+  { "Begin Track",    (VikToolConstructorFunc) tool_begin_track_create,       NULL, NULL, NULL, 
+    (VikToolMouseFunc) tool_begin_track_click,       NULL, NULL, &cursor_begintr },
 
   { "Edit Waypoint",   (VikToolConstructorFunc) tool_edit_waypoint_create,   NULL, NULL, NULL, 
     (VikToolMouseFunc) tool_edit_waypoint_click,   
     (VikToolMouseFunc) tool_edit_waypoint_move,
-    (VikToolMouseFunc) tool_edit_waypoint_release },
+    (VikToolMouseFunc) tool_edit_waypoint_release, &cursor_edwp },
 
   { "Edit Trackpoint", (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, 
     (VikToolMouseFunc) tool_edit_trackpoint_click,
     (VikToolMouseFunc) tool_edit_trackpoint_move,
-    (VikToolMouseFunc) tool_edit_trackpoint_release },
+    (VikToolMouseFunc) tool_edit_trackpoint_release, &cursor_edtr },
 
   { "Show Picture",    (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL },
+    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, &cursor_showpic },
+
+  { "Magic Scissors",  (VikToolConstructorFunc) tool_magic_scissors_create,  NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, &cursor_iscissors },
 };
+enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
 
 /****** PARAMETERS ******/
 
@@ -324,6 +365,11 @@ VikLayerParam trw_layer_params[] = {
 
 enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS };
 
+/*** TO ADD A PARAM:
+ *** 1) Add to trw_layer_params and enumeration
+ *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
+ ***/
+
 /****** END PARAMETERS ******/
 
 VikLayerInterface vik_trw_layer_interface = {
@@ -358,7 +404,6 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncSublayerRenameRequest)   vik_trw_layer_sublayer_rename_request,
   (VikLayerFuncSublayerToggleVisible)   vik_trw_layer_sublayer_toggle_visible,
 
-  (VikLayerFuncCopy)                    trw_layer_copy,
   (VikLayerFuncMarshall)                trw_layer_marshall,
   (VikLayerFuncUnmarshall)              trw_layer_unmarshall,
 
@@ -452,7 +497,6 @@ static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer subla
   guint8 *id;
   guint il;
 
-  fprintf(stderr, "%s:%s() called\n", __FILE__, __PRETTY_FUNCTION__);
   if (!sublayer) {
     *item = NULL;
     return;
@@ -509,11 +553,6 @@ static void trw_layer_free_copied_item ( gint subtype, gpointer item )
   }
 }
 
-static void waypoint_copy ( const gchar *name, VikWaypoint *wp, GHashTable *dest )
-{
-  g_hash_table_insert ( dest, g_strdup(name), vik_waypoint_copy(wp) );
-}
-
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp )
 {
   switch ( id )
@@ -607,11 +646,6 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id )
   return rv;
 }
 
-static void track_copy ( const gchar *name, VikTrack *tr, GHashTable *dest )
-{
-  g_hash_table_insert ( dest, g_strdup ( name ), vik_track_copy(tr) );
-}
-
 static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
 {
   guint8 *pd, *dd;
@@ -665,58 +699,6 @@ static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *
   return rv;
 }
 
-static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
-{
-  VikTrwLayer *rv = vik_trw_layer_new ( vtl->drawmode );
-  PangoFontDescription *pfd;
-  rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
-  pfd = pango_font_description_from_string (WAYPOINT_FONT);
-  pango_layout_set_font_description (rv->wplabellayout, pfd);
-  /* freeing PangoFontDescription, cause it has been copied by prev. call */
-  pango_font_description_free (pfd);
-
-  rv->tracks_visible = vtl->tracks_visible;
-  rv->waypoints_visible = vtl->waypoints_visible;
-  rv->drawpoints = vtl->drawpoints;
-  rv->drawstops = vtl->drawstops;
-  rv->drawelevation = vtl->drawelevation;
-  rv->elevation_factor = vtl->elevation_factor;
-  rv->drawlines = vtl->drawlines;
-  rv->stop_length = vtl->stop_length;
-  rv->line_thickness = vtl->line_thickness;
-  rv->bg_line_thickness = vtl->bg_line_thickness;
-  rv->velocity_min = vtl->velocity_min;
-  rv->velocity_max = vtl->velocity_max;
-  rv->drawlabels = vtl->drawlabels;
-  rv->drawimages = vtl->drawimages;
-  rv->image_size = vtl->image_size;
-  rv->image_alpha = vtl->image_alpha;
-  rv->image_cache_size = vtl->image_cache_size;
-  rv->has_verified_thumbnails = TRUE;
-  rv->coord_mode = vtl->coord_mode;
-  rv->wp_symbol = vtl->wp_symbol;
-  rv->wp_size = vtl->wp_size;
-  rv->wp_draw_symbols = vtl->wp_draw_symbols;
-
-  trw_layer_new_track_gcs ( rv, VIK_VIEWPORT(vp) );
-
-  rv->waypoint_gc = gdk_gc_new ( GTK_WIDGET(vp)->window );
-  gdk_gc_set_line_attributes ( rv->waypoint_gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
-
-  rv->waypoint_text_gc = gdk_gc_new ( GTK_WIDGET(vp)->window );
-  rv->waypoint_bg_gc = gdk_gc_new ( GTK_WIDGET(vp)->window );
-  gdk_gc_copy ( rv->waypoint_gc, vtl->waypoint_gc );
-  gdk_gc_copy ( rv->waypoint_text_gc, vtl->waypoint_text_gc );
-  gdk_gc_copy ( rv->waypoint_bg_gc, vtl->waypoint_bg_gc );
-
-  rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
-
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_copy, rv->waypoints );
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) track_copy, rv->tracks );
-
-  return rv;
-}
-
 static GList * a_array_to_glist(gpointer data[])
 {
   GList *gl = NULL;
@@ -767,6 +749,13 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
   rv->current_tp_track_name = NULL;
   rv->moving_tp = FALSE;
   rv->moving_wp = FALSE;
+
+  rv->magic_scissors_started = FALSE;
+  rv->magic_scissors_check_added_track = FALSE;
+  rv->magic_scissors_added_track_name = NULL;
+  rv->magic_scissors_current_track = NULL;
+  rv->magic_scissors_append = FALSE;
+
   rv->waypoint_rightclick = FALSE;
   rv->last_tpl = NULL;
   rv->last_tp_track_name = NULL;
@@ -886,6 +875,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
 {
   /* TODO: this function is a mess, get rid of any redundancy */
   GList *list = track->trackpoints;
+  GdkGC *main_gc;
   gboolean useoldvals = TRUE;
 
   gboolean drawpoints;
@@ -918,6 +908,11 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     drawstops = dp->vtl->drawstops;
   }
 
+  if ( track == dp->vtl->current_track )
+    main_gc = dp->vtl->current_track_gc;
+  else
+    main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+
   if (list) {
     int x, y, oldx, oldy;
     VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
@@ -929,7 +924,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC )
     {
       GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} };
-      vik_viewport_draw_polygon ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, trian, 3 );
+      vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 );
     }
 
     oldx = x;
@@ -954,16 +949,16 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
         if ( drawpoints && ! drawing_white_background )
         {
           if ( list->next ) {
-            vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
+            vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
 
-            vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
+            vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
 
             /* stops */
             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
               vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
           }
           else
-            vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
+            vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
         }
 
         if ((!tp->newsegment) && (dp->vtl->drawlines))
@@ -972,7 +967,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
 
           /* UTM only: zone check */
           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
-            draw_utm_skip_insignia (  dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y);
+            draw_utm_skip_insignia (  dp->vp, main_gc, x, y);
 
           if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY )
             dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
@@ -985,7 +980,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           }
           else {
 
-            vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y);
+            vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
             if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
               GdkPoint tmp[4];
               #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
@@ -1006,7 +1001,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
                   tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
                 vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
               }
-              vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
+              vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
             }
           }
         }
@@ -1028,12 +1023,12 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
             if ( drawing_white_background )
               vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
             else
-              vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y);
+              vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
           }
           else 
           {
             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
-            draw_utm_skip_insignia ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y );
+            draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
           }
         }
         useoldvals = FALSE;
@@ -1200,6 +1195,11 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
     g_object_unref ( vtl->track_bg_gc );
     vtl->track_bg_gc = NULL;
   }
+  if ( vtl->current_track_gc ) 
+  {
+    g_object_unref ( vtl->current_track_gc );
+    vtl->current_track_gc = NULL;
+  }
 
   if ( ! vtl->track_gc )
     return;
@@ -1221,6 +1221,11 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
     g_object_unref ( vtl->track_bg_gc );
   vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
 
+  if ( vtl->current_track_gc )
+    g_object_unref ( vtl->current_track_gc );
+  vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
+  gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+
   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
 
   gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
@@ -1443,6 +1448,7 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type )
   const gchar *fn;
   gboolean failed = FALSE;
   file_selector = gtk_file_selection_new ("Export Layer");
+  gtk_file_selection_set_filename (GTK_FILE_SELECTION(file_selector), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])));
 
   while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_OK )
   {
@@ -1562,6 +1568,7 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl
 {
   static gpointer pass_along[2];
   GtkWidget *item;
+  GtkWidget *export_submenu;
   pass_along[0] = vtl;
   pass_along[1] = vlp;
 
@@ -1579,25 +1586,38 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Export Layer as GPSPoint" );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
+  export_submenu = gtk_menu_new ();
+  item = gtk_menu_item_new_with_label ( "Export layer" );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
+  
+  item = gtk_menu_item_new_with_label ( "Export as GPSPoint" );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+  gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Export Layer as GPSMapper" );
+  item = gtk_menu_item_new_with_label ( "Export as GPSMapper" );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Export Layer as GPX" );
+  item = gtk_menu_item_new_with_label ( "Export as GPX" );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
   item = gtk_menu_item_new_with_label ( "New Waypoint" );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
+
+#ifdef VIK_CONFIG_OPENSTREETMAP 
+  item = gtk_menu_item_new_with_label ( "Upload to OSM" );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+#endif
 }
 
 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
@@ -1700,9 +1720,22 @@ void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypo
 }
 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
 {
-  vik_trw_layer_add_track ( vtl,
-                        get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name),
-                        tr );
+  if ( vtl->magic_scissors_append && vtl->magic_scissors_current_track ) {
+    vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
+    vik_track_steal_and_append_trackpoints ( vtl->magic_scissors_current_track, tr );
+    vik_track_free ( tr );
+    vtl->magic_scissors_append = FALSE; /* this means we have added it */
+  } else {
+    gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
+    vik_trw_layer_add_track ( vtl, new_name, tr );
+
+    if ( vtl->magic_scissors_check_added_track ) {
+      vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
+      if ( vtl->magic_scissors_added_track_name ) /* for google routes */
+        g_free ( vtl->magic_scissors_added_track_name );
+      vtl->magic_scissors_added_track_name = g_strdup(new_name);
+    }
+  }
 }
 
 static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l )
@@ -1771,6 +1804,8 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
     was_visible = t->visible;
     if ( t == vtl->current_track )
       vtl->current_track = NULL;
+    if ( t == vtl->magic_scissors_current_track )
+      vtl->magic_scissors_current_track = NULL;
 
     /* could be current_tp, so we have to check */
     trw_layer_cancel_tps_of_track ( vtl, trk_name );
@@ -1810,6 +1845,43 @@ gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name
   return was_visible;
 }
 
+static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt)
+{
+    vik_treeview_item_delete (vt, it );
+}
+
+void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
+{
+
+  vtl->current_track = NULL;
+  vtl->magic_scissors_current_track = NULL;
+  if (vtl->current_tp_track_name)
+    trw_layer_cancel_current_tp(vtl, FALSE);
+  if (vtl->last_tp_track_name)
+    trw_layer_cancel_last_tp ( vtl );
+
+  g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->tracks_iters);
+  g_hash_table_remove_all(vtl->tracks);
+
+  /* TODO: only update if the layer is visible (ticked) */
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+}
+
+void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
+{
+  vtl->current_wp = NULL;
+  vtl->current_wp_name = NULL;
+  vtl->moving_wp = FALSE;
+
+  g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->waypoints_iters);
+  g_hash_table_remove_all(vtl->waypoints);
+
+  /* TODO: only update if the layer is visible (ticked) */
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+}
+
 static void trw_layer_delete_item ( gpointer pass_along[5] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
@@ -1914,6 +1986,7 @@ static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] )
 
 static void trw_layer_goto_track_center ( gpointer pass_along[5] )
 {
+  /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
   GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
   if ( trps && *trps )
   {
@@ -1927,6 +2000,27 @@ static void trw_layer_goto_track_center ( gpointer pass_along[5] )
   }
 }
 
+static void trw_layer_extend_track_end ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+
+  vtl->current_track = track;
+  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
+
+  if ( track->trackpoints )
+    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
+}
+
+static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
+{
+  /* TODO: check & warn if no DEM data, or no applicable DEM data. */
+  /* Also warn if overwrite old elevation data */
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+
+  vik_track_apply_dem_data ( track );
+}
+
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
 {
   GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
@@ -2287,7 +2381,34 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
 static gboolean is_valid_geocache_name ( gchar *str )
 {
   gint len = strlen ( str );
-  return len >= 3 && len <= 6 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5]));
+  return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
+}
+
+static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name )
+{
+  VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_name );
+  return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
+}
+
+static void trw_layer_track_google_route_webpage( gpointer *pass_along )
+{
+  gchar *track_name = (gchar *) pass_along[3];
+  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
+  if ( tr ) {
+    gchar *escaped = uri_escape ( tr->comment );
+    gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
+    GError *err = NULL;
+    gchar *cmd = g_strdup_printf ( "%s %s", UNIX_WEB_BROWSER, webpage );
+
+    if ( ! g_spawn_command_line_async ( cmd, &err ) )
+    {
+      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), "Could not launch web browser." );
+      g_error_free ( err );
+    }
+    g_free ( escaped );
+    g_free ( cmd );
+    g_free ( webpage );
+  }
 }
 
 /* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
@@ -2380,6 +2501,37 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
+
+    item = gtk_menu_item_new_with_label ( "Download maps along track..." );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    item = gtk_menu_item_new_with_label ( "Apply DEM Data" );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    item = gtk_menu_item_new_with_label ( "Extend track end" );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+#ifdef VIK_CONFIG_OPENSTREETMAP
+    item = gtk_menu_item_new_with_label ( "Upload to OSM" );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+#endif
+
+    if ( is_valid_google_route ( l, (gchar *) sublayer ) )
+    {
+      item = gtk_menu_item_new_with_label ( "View Google Directions" );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
+    }
+
   }
 
   if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
@@ -2757,7 +2909,7 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
   {
     /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
     marker_begin_move(t, event->x, event->y);
-    printf("Abort: shouldn't be here\n");
+    g_critical("shouldn't be here");
     exit(1);
   }
   else if ( params.closest_wp )
@@ -2871,6 +3023,18 @@ static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *e
   return FALSE;
 }
 
+/**** Begin track ***/
+static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  vtl->current_track = NULL;
+  return tool_new_track_click ( vtl, event, vvp );
+}
+
 /*** New track ****/
 
 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
@@ -2909,6 +3073,7 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
       /* undo last, then end */
       vtl->current_track = NULL;
     }
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
 
@@ -2920,6 +3085,9 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
       vtl->current_track = vik_track_new();
       vtl->current_track->visible = TRUE;
       vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+
+      /* incase it was created by begin track */
+      vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
     }
     else
       return TRUE;
@@ -3052,7 +3220,6 @@ static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *ev
   if ( t->holding )
   {
     VikCoord new_coord;
-    GdkGC *gc;
     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
 
     /* snap to TP */
@@ -3112,6 +3279,85 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton
 }
 
 
+/*** Magic Scissors ***/
+static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  VikCoord tmp;
+  if ( !vtl ) return FALSE;
+  vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
+  if ( event->button == 3 && vtl->magic_scissors_current_track ) {
+    VikCoord *new_end;
+    new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track );
+    if ( new_end ) {
+      vtl->magic_scissors_coord = *new_end;
+      g_free ( new_end );
+      vik_layer_emit_update ( VIK_LAYER(vtl) );
+      /* remove last ' to:...' */
+      if ( vtl->magic_scissors_current_track->comment ) {
+        gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' );
+        if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) {
+          gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment,
+                                           last_to - vtl->magic_scissors_current_track->comment - 1);
+          vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+        }
+      }
+    }
+  }
+  else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) {
+    struct LatLon start, end;
+    gchar *cmd;
+
+    vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start );
+    vik_coord_to_latlon ( &(tmp), &end );
+    cmd = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, start.lat, start.lon, end.lat, end.lon );
+    vtl->magic_scissors_coord = tmp; /* for continuations */
+
+    /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
+    if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) {
+      vtl->magic_scissors_append = TRUE;  // merge tracks. keep started true.
+    } else {
+      vtl->magic_scissors_check_added_track = TRUE;
+      vtl->magic_scissors_started = FALSE;
+    }
+
+    a_babel_convert_from_shellcommand ( vtl, cmd, "google", NULL, NULL );
+    g_free ( cmd );
+
+    /* see if anything was done -- a track was added or appended to */
+    if ( vtl->magic_scissors_check_added_track && vtl->magic_scissors_added_track_name ) {
+      VikTrack *tr;
+
+      tr = g_hash_table_lookup ( vtl->tracks, vtl->magic_scissors_added_track_name );
+
+      if ( tr )
+        vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f%f", start.lat, start.lon, end.lat, end.lon ) ); 
+      vtl->magic_scissors_current_track = tr;
+
+      g_free ( vtl->magic_scissors_added_track_name );
+      vtl->magic_scissors_added_track_name = NULL;
+    } else if ( vtl->magic_scissors_append == FALSE && vtl->magic_scissors_current_track ) {
+      /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
+      gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->magic_scissors_current_track->comment, end.lat, end.lon );
+      vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+    }
+    vtl->magic_scissors_check_added_track = FALSE;
+    vtl->magic_scissors_append = FALSE;
+
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+  } else {
+    vtl->magic_scissors_started = TRUE;
+    vtl->magic_scissors_coord = tmp;
+    vtl->magic_scissors_current_track = NULL;
+  }
+  return TRUE;
+}
+
 /*** Show picture ****/
 
 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
@@ -3266,3 +3512,226 @@ static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl)
   return(vtl->menu_selection);
 }
 
+/* ----------- Downloading maps along tracks --------------- */
+
+static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
+{
+  /* TODO: calculating based on current size of viewport */
+  const gdouble w_at_zoom_0_125 = 0.0013;
+  const gdouble h_at_zoom_0_125 = 0.0011;
+  gdouble zoom_factor = zoom_level/0.125;
+
+  wh->lat = h_at_zoom_0_125 * zoom_factor;
+  wh->lon = w_at_zoom_0_125 * zoom_factor;
+
+  return 0;   /* all OK */
+}
+
+static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
+{
+  if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
+      (dist->lat >= ABS(to->north_south - from->north_south)))
+    return NULL;
+
+  VikCoord *coord = g_malloc(sizeof(VikCoord));
+  coord->mode = VIK_COORD_LATLON;
+
+  if (ABS(gradient) < 1) {
+    if (from->east_west > to->east_west)
+      coord->east_west = from->east_west - dist->lon;
+    else
+      coord->east_west = from->east_west + dist->lon;
+    coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
+  } else {
+    if (from->north_south > to->north_south)
+      coord->north_south = from->north_south - dist->lat;
+    else
+      coord->north_south = from->north_south + dist->lat;
+    coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
+  }
+
+  return coord;
+}
+
+static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
+{
+  /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
+  gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
+
+  VikCoord *next = from;
+  while (TRUE) {
+    if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
+        break;
+    list = g_list_prepend(list, next);
+  }
+
+  return list;
+}
+
+void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
+{
+  typedef struct _Rect {
+    VikCoord tl;
+    VikCoord br;
+    VikCoord center;
+  } Rect;
+#define GLRECT(iter) ((Rect *)((iter)->data))
+
+  struct LatLon wh;
+  GList *rects_to_download = NULL;
+  GList *rect_iter;
+
+  if (get_download_area_width(vvp, zoom_level, &wh))
+    return;
+
+  GList *iter = tr->trackpoints;
+  if (!iter)
+    return;
+
+  gboolean new_map = TRUE;
+  VikCoord *cur_coord, tl, br;
+  Rect *rect;
+  while (iter) {
+    cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
+    if (new_map) {
+      vik_coord_set_area(cur_coord, &wh, &tl, &br);
+      rect = g_malloc(sizeof(Rect));
+      rect->tl = tl;
+      rect->br = br;
+      rect->center = *cur_coord;
+      rects_to_download = g_list_prepend(rects_to_download, rect);
+      new_map = FALSE;
+      iter = iter->next;
+      continue;
+    }
+    gboolean found = FALSE;
+    for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
+      if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
+        found = TRUE;
+        break;
+      }
+    }
+    if (found)
+        iter = iter->next;
+    else
+      new_map = TRUE;
+  }
+
+  /* fill-ins for far apart points */
+  GList *cur_rect, *next_rect;
+  GList *fillins = NULL;
+  for (cur_rect = rects_to_download;
+      (next_rect = cur_rect->next) != NULL;
+      cur_rect = cur_rect->next) {
+    if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
+        (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
+      fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
+    }
+  }
+
+  if (fillins) {
+    GList *iter = fillins;
+    while (iter) {
+      cur_coord = (VikCoord *)(iter->data);
+      vik_coord_set_area(cur_coord, &wh, &tl, &br);
+      rect = g_malloc(sizeof(Rect));
+      rect->tl = tl;
+      rect->br = br;
+      rect->center = *cur_coord;
+      rects_to_download = g_list_prepend(rects_to_download, rect);
+      iter = iter->next;
+    }
+  }
+
+  for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
+    maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
+  }
+
+  if (fillins) {
+    for (iter = fillins; iter; iter = iter->next)
+      g_free(iter->data);
+    g_list_free(fillins);
+  }
+  if (rects_to_download) {
+    for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
+      g_free(rect_iter->data);
+    g_list_free(rects_to_download);
+  }
+}
+
+static void trw_layer_download_map_along_track_cb(gpointer pass_along[6])
+{
+  VikMapsLayer *vml;
+  gint selected_map, default_map;
+  gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
+  gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
+  gint selected_zoom, default_zoom;
+  int i,j;
+
+
+  VikTrwLayer *vtl = pass_along[0];
+  VikLayersPanel *vlp = pass_along[1];
+  VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
+
+  GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS);
+  int num_maps = g_list_length(vmls);
+
+  if (!num_maps) {
+    a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR,"No map layer in use. Create one first", NULL);
+    return;
+  }
+
+  gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
+  VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
+
+  gchar **np = map_names;
+  VikMapsLayer **lp = map_layers;
+  for (i = 0; i < num_maps; i++) {
+    gboolean dup = FALSE;
+    vml = (VikMapsLayer *)(vmls->data);
+    for (j = 0; j < i; j++) { /* no duplicate allowed */
+      if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) {
+        dup = TRUE;
+        break;
+      }
+    }
+    if (!dup) {
+      *lp++ = vml;
+      *np++ = vik_maps_layer_get_map_label(vml);
+    }
+    vmls = vmls->next;
+  }
+  *lp = NULL;
+  *np = NULL;
+  num_maps = lp - map_layers;
+
+  for (default_map = 0; default_map < num_maps; default_map++) {
+    /* TODO: check for parent layer's visibility */
+    if (VIK_LAYER(map_layers[default_map])->visible)
+      break;
+  }
+  default_map = (default_map == num_maps) ? 0 : default_map;
+
+  gdouble cur_zoom = vik_viewport_get_zoom(vvp);
+  for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
+    if (cur_zoom == zoom_vals[default_zoom])
+      break;
+  }
+  default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
+
+  if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom))
+    goto done;
+
+  vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
+
+done:
+  for (i = 0; i < num_maps; i++)
+    g_free(map_names[i]);
+  g_free(map_names);
+  g_free(map_layers);
+
+  g_list_free(vmls);
+
+}
+