]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Display waypoint symbols in the layers panel tree view.
[andy/viking.git] / src / viktrwlayer.c
index 307f2ff2a2f5429ac05ef00e6c24235e57636d97..4402f96995c9298bcd33a327f556b6febfb6e39f 100644 (file)
@@ -23,7 +23,7 @@
  *
  */
 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
-/* viktrwlayer.c -- 5000+ lines can make a difference in the state of things */
+/* viktrwlayer.c -- 8000+ lines can make a difference in the state of things */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #include <glib/gstdio.h>
 #include <glib/gi18n.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
-
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
-// This is currently broken as Google have disabled the KML output in Google Maps API v3
-// It has been ifdefed out in the hope that Route Finding functionality will be restored one day...
-// Only have 'JSON' and 'XML' see:
-// https://developers.google.com/maps/documentation/directions/#DirectionsResponses
-#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml"
+#ifdef VIK_CONFIG_GOOGLE
+#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js"
 #endif
 
 #define VIK_TRW_LAYER_TRACK_GC 16
@@ -116,27 +106,45 @@ static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove (
 
 enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
 
+// See http://developer.gnome.org/pango/stable/PangoMarkupFormat.html
+typedef enum {
+  FS_XX_SMALL = 0, // 'xx-small'
+  FS_X_SMALL,
+  FS_SMALL,
+  FS_MEDIUM, // DEFAULT
+  FS_LARGE,
+  FS_X_LARGE,
+  FS_XX_LARGE,
+  FS_NUM_SIZES
+} font_size_t;
+
 struct _VikTrwLayer {
   VikLayer vl;
   GHashTable *tracks;
   GHashTable *tracks_iters;
+  GHashTable *routes;
+  GHashTable *routes_iters;
   GHashTable *waypoints_iters;
   GHashTable *waypoints;
-  GtkTreeIter waypoints_iter, tracks_iter;
-  gboolean tracks_visible, waypoints_visible;
+  GtkTreeIter tracks_iter, routes_iter, waypoints_iter;
+  gboolean tracks_visible, routes_visible, waypoints_visible;
   guint8 drawmode;
   guint8 drawpoints;
+  guint8 drawpoints_size;
   guint8 drawelevation;
   guint8 elevation_factor;
   guint8 drawstops;
   guint32 stop_length;
   guint8 drawlines;
+  guint8 drawdirections;
+  guint8 drawdirections_size;
   guint8 line_thickness;
   guint8 bg_line_thickness;
 
   guint8 wp_symbol;
   guint8 wp_size;
   gboolean wp_draw_symbols;
+  font_size_t wp_font_size;
 
   gdouble track_draw_speed_factor;
   GArray *track_gc;
@@ -148,7 +156,8 @@ struct _VikTrwLayer {
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
   GdkGC *waypoint_bg_gc;
-  VikTrack *current_track;
+  GdkFont *waypoint_font;
+  VikTrack *current_track; // ATM shared between new tracks and new routes
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
   gboolean draw_sync_done;
   gboolean draw_sync_do;
@@ -210,6 +219,8 @@ struct DrawingParams {
   VikTrwLayer *vtl;
   gdouble xmpp, ympp;
   guint16 width, height;
+  gdouble cc; // Cosine factor in track directions
+  gdouble ss; // Sine factor in track directions
   const VikCoord *center;
   gint track_gc_iter;
   gboolean one_zone, lat_lon;
@@ -260,6 +271,9 @@ static void trw_layer_auto_view ( gpointer layer_and_vlp[2] );
 static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type );
 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
 static void trw_layer_new_wp ( gpointer lav[2] );
+static void trw_layer_new_track ( gpointer lav[2] );
+static void trw_layer_new_route ( gpointer lav[2] );
+static void trw_layer_finish_track ( gpointer lav[2] );
 static void trw_layer_auto_waypoints_view ( gpointer lav[2] );
 static void trw_layer_auto_tracks_view ( gpointer lav[2] );
 static void trw_layer_delete_all_tracks ( gpointer lav[2] );
@@ -275,7 +289,7 @@ static void trw_layer_geotagging_track ( gpointer pass_along[6] );
 static void trw_layer_geotagging ( gpointer lav[2] );
 #endif
 static void trw_layer_acquire_gps_cb ( gpointer lav[2] );
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
 static void trw_layer_acquire_google_cb ( gpointer lav[2] );
 #endif
 #ifdef VIK_CONFIG_OPENSTREETMAP
@@ -290,6 +304,12 @@ static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] );
 static void trw_layer_acquire_file_cb ( gpointer lav[2] );
 static void trw_layer_gps_upload ( gpointer lav[2] );
 
+// Specific route versions:
+//  Most track handling functions can handle operating on the route list
+//  However these ones are easier in separate functions
+static void trw_layer_auto_routes_view ( gpointer lav[2] );
+static void trw_layer_delete_routes_from_selection ( gpointer lav[2] );
+
 /* pop-up items */
 static void trw_layer_properties_item ( gpointer pass_along[7] );
 static void trw_layer_goto_waypoint ( gpointer pass_along[6] );
@@ -297,7 +317,7 @@ static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] );
 
 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
-static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
+static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp );
 
 static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
@@ -314,8 +334,8 @@ 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, GdkEventMotion *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_route_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_new_route_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 VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp ); 
@@ -323,7 +343,7 @@ static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, Vi
 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *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 );
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 #endif
@@ -364,11 +384,14 @@ static VikToolInterface trw_layer_tools[] = {
     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
     GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
 
-  { { "BeginTrack", "vik-icon-Begin Track", N_("_Begin Track"), "<control><shift>B", N_("Begin Track"), 0 },
-    (VikToolConstructorFunc) tool_begin_track_create,       NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_begin_track_click,       NULL, NULL, (VikToolKeyFunc) NULL,
-    FALSE,
-    GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
+  { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "<control><shift>B", N_("Create Route"), 0 },
+    (VikToolConstructorFunc) tool_new_route_create,       NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_new_route_click,
+    (VikToolMouseMoveFunc) tool_new_track_move, // -\#
+    (VikToolMouseFunc) tool_new_track_release,  //   -> Reuse these track methods on a route
+    (VikToolKeyFunc) tool_new_track_key_press,  // -/#
+    TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
+    GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf },
 
   { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "<control><shift>E", N_("Edit Waypoint"), 0 },
     (VikToolConstructorFunc) tool_edit_waypoint_create,   NULL, NULL, NULL,
@@ -392,7 +415,7 @@ static VikToolInterface trw_layer_tools[] = {
     FALSE,
     GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
 
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
   { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
     (VikToolConstructorFunc) tool_route_finder_create,  NULL, NULL, NULL,
     (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
@@ -400,7 +423,7 @@ static VikToolInterface trw_layer_tools[] = {
     GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
 #endif
 };
-enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
+enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_CREATE_ROUTE, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
 
 /****** PARAMETERS ******/
 
@@ -410,6 +433,11 @@ enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
 static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Black"), 0 };
 static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
 
+#define MIN_POINT_SIZE 2
+#define MAX_POINT_SIZE 10
+
+#define MIN_ARROW_SIZE 3
+#define MAX_ARROW_SIZE 20
 
 static VikLayerParamScale params_scales[] = {
  /* min  max    step digits */
@@ -417,34 +445,51 @@ static VikLayerParamScale params_scales[] = {
  {  0,   100,   1,   0 }, /* track draw speed factor */
  {  1.0, 100.0, 1.0, 2 }, /* UNUSED */
                 /* 5 * step == how much to turn */
- {  16,   128,  3.2, 0 }, /* image_size */
- {   0,   255,  5,   0 }, /* image alpha */
- {   5,   500,  5,   0 }, /* image cache_size */
- {   0,   8,    1,   0 }, /* image cache_size */
+ {  16,   128,  4,   0 }, // 3: image_size - NB step size ignored when an HSCALE used
+ {   0,   255,  5,   0 }, // 4: image alpha -    "     "      "            "
+ {   5,   500,  5,   0 }, // 5: image cache_size -     "      "
+ {   0,   8,    1,   0 }, // 6: Background line thickness
  {   1,  64,    1,   0 }, /* wpsize */
  {   MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1,   0 }, /* stop_length */
- {   1, 100, 1,   0 }, /* stop_length */
+ {   1, 100, 1,   0 }, // 9: elevation factor
+ {   MIN_POINT_SIZE,  MAX_POINT_SIZE,  1,   0 }, // 10: track point size
+ {   MIN_ARROW_SIZE,  MAX_ARROW_SIZE,  1,   0 }, // 11: direction arrow size
 };
 
+static gchar* params_font_sizes[] = {
+  N_("Extra Extra Small"),
+  N_("Extra Small"),
+  N_("Small"),
+  N_("Medium"),
+  N_("Large"),
+  N_("Extra Large"),
+  N_("Extra Extra Large"),
+  NULL };
+
 VikLayerParam trw_layer_params[] = {
   { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
   { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
+  { "routes_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
 
   { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL },
   { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
+  { "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 11 },
   { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 10 },
   { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON },
   { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 9 },
 
   { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON },
   { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 },
 
-  { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
   { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 },
   { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, 0 },
-  { "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
+  { "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 1 },
 
   { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL },
   { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
   { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, 0 },
   { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, 0 },
@@ -459,7 +504,44 @@ VikLayerParam trw_layer_params[] = {
   { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
 };
 
-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_TDSF, 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 };
+// ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
+enum {
+  // Sublayer visibilities
+  PARAM_TV,
+  PARAM_WV,
+  PARAM_RV,
+  // Tracks
+  PARAM_DM,
+  PARAM_DL,
+  PARAM_LT,
+  PARAM_DD,
+  PARAM_DDS,
+  PARAM_DP,
+  PARAM_DPS,
+  PARAM_DE,
+  PARAM_EF,
+  PARAM_DS,
+  PARAM_SL,
+  PARAM_BLT,
+  PARAM_TBGC,
+  PARAM_TDSF,
+  // Waypoints
+  PARAM_DLA,
+  PARAM_WPFONTSIZE,
+  PARAM_WPC,
+  PARAM_WPTC,
+  PARAM_WPBC,
+  PARAM_WPBA,
+  PARAM_WPSYM,
+  PARAM_WPSIZE,
+  PARAM_WPSYMS,
+  // WP images
+  PARAM_DI,
+  PARAM_IS,
+  PARAM_IA,
+  PARAM_ICS,
+  NUM_PARAMS
+};
 
 /*** TO ADD A PARAM:
  *** 1) Add to trw_layer_params and enumeration
@@ -501,6 +583,7 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
 /* End Layer Interface function definitions */
 
 VikLayerInterface vik_trw_layer_interface = {
+  "TrackWaypoint",
   N_("TrackWaypoint"),
   "<control><shift>Y",
   &viktrwlayer_pixbuf,
@@ -643,13 +726,20 @@ static void trw_layer_copy_item_cb ( gpointer pass_along[6])
       else
         name = NULL; // Broken :(
     }
-    else {
+    else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
       VikTrack *trk = g_hash_table_lookup ( vtl->tracks, sublayer);
       if ( trk && trk->name )
         name = trk->name;
       else
         name = NULL; // Broken :(
     }
+    else {
+      VikTrack *trk = g_hash_table_lookup ( vtl->routes, sublayer);
+      if ( trk && trk->name )
+        name = trk->name;
+      else
+        name = NULL; // Broken :(
+    }
 
     a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
                      subtype, len, name, data);
@@ -663,6 +753,12 @@ static void trw_layer_cut_item_cb ( gpointer pass_along[6])
   trw_layer_delete_item(pass_along);
 }
 
+static void trw_layer_paste_item_cb ( gpointer pass_along[6])
+{
+  // Slightly cheating method, routing via the panels capability
+  a_clipboard_paste (VIK_LAYERS_PANEL(pass_along[1]));
+}
+
 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
 {
   FlatItem *fi;
@@ -682,14 +778,20 @@ static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer subla
     fi = g_malloc ( *len );
     fi->len = *len;
     memcpy(fi->data, id, il);
-  } else {
-
+  } else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
     vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
     // less magic than before...
     *len = sizeof(FlatItem) + 1 + il;
     fi = g_malloc ( *len );
     fi->len = *len;
     memcpy(fi->data, id, il);
+  } else {
+    vik_track_marshall ( g_hash_table_lookup ( vtl->routes, sublayer ), &id, &il );
+    // less magic than before...
+    *len = sizeof(FlatItem) + 1 + il;
+    fi = g_malloc ( *len );
+    fi->len = *len;
+    memcpy(fi->data, id, il);
   }
 
   g_free(id);
@@ -725,13 +827,29 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i
     // When copying - we'll create a new name based on the original
     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name);
     vik_trw_layer_add_track ( vtl, name, t );
-    track_convert (name, t, &vtl->coord_mode);
+    vik_track_convert (t, vtl->coord_mode);
 
     // Consider if redraw necessary for the new item
     if ( vtl->vl.visible && vtl->tracks_visible && t->visible )
       vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && fi )
+  {
+    VikTrack *t;
+    gchar *name;
+
+    t = vik_track_unmarshall(fi->data, fi->len);
+    // When copying - we'll create a new name based on the original
+    name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, t->name);
+    vik_trw_layer_add_route ( vtl, name, t );
+    vik_track_convert (t, vtl->coord_mode);
+
+    // Consider if redraw necessary for the new item
+    if ( vtl->vl.visible && vtl->routes_visible && t->visible )
+      vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+    return TRUE;
+  }
   return FALSE;
 }
 
@@ -748,11 +866,21 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
   {
     case PARAM_TV: vtl->tracks_visible = data.b; break;
     case PARAM_WV: vtl->waypoints_visible = data.b; break;
+    case PARAM_RV: vtl->routes_visible = data.b; break;
     case PARAM_DM: vtl->drawmode = data.u; break;
     case PARAM_DP: vtl->drawpoints = data.b; break;
+    case PARAM_DPS:
+      if ( data.u >= MIN_POINT_SIZE && data.u <= MAX_POINT_SIZE )
+        vtl->drawpoints_size = data.u;
+      break;
     case PARAM_DE: vtl->drawelevation = data.b; break;
     case PARAM_DS: vtl->drawstops = data.b; break;
     case PARAM_DL: vtl->drawlines = data.b; break;
+    case PARAM_DD: vtl->drawdirections = data.b; break;
+    case PARAM_DDS:
+      if ( data.u >= MIN_ARROW_SIZE && data.u <= MAX_ARROW_SIZE )
+        vtl->drawdirections_size = data.u;
+      break;
     case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
                      vtl->stop_length = data.u;
                    break;
@@ -795,6 +923,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
     case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
     case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
     case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
+    case PARAM_WPFONTSIZE: if ( data.u < FS_NUM_SIZES ) vtl->wp_font_size = data.u; break;
   }
   return TRUE;
 }
@@ -806,13 +935,17 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo
   {
     case PARAM_TV: rv.b = vtl->tracks_visible; break;
     case PARAM_WV: rv.b = vtl->waypoints_visible; break;
+    case PARAM_RV: rv.b = vtl->routes_visible; break;
     case PARAM_DM: rv.u = vtl->drawmode; break;
     case PARAM_DP: rv.b = vtl->drawpoints; break;
+    case PARAM_DPS: rv.u = vtl->drawpoints_size; break;
     case PARAM_DE: rv.b = vtl->drawelevation; break;
     case PARAM_EF: rv.u = vtl->elevation_factor; break;
     case PARAM_DS: rv.b = vtl->drawstops; break;
     case PARAM_SL: rv.u = vtl->stop_length; break;
     case PARAM_DL: rv.b = vtl->drawlines; break;
+    case PARAM_DD: rv.b = vtl->drawdirections; break;
+    case PARAM_DDS: rv.u = vtl->drawdirections_size; break;
     case PARAM_LT: rv.u = vtl->line_thickness; break;
     case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
     case PARAM_DLA: rv.b = vtl->drawlabels; break;
@@ -829,6 +962,7 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo
     case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
     case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
+    case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
   }
   return rv;
 }
@@ -890,15 +1024,6 @@ static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *v
   return rv;
 }
 
-static GList * str_array_to_glist(gchar* data[])
-{
-  GList *gl = NULL;
-  gpointer * p;
-  for (p = (gpointer)data; *p; p++)
-    gl = g_list_prepend(gl, *p);
-  return(g_list_reverse(gl));
-}
-
 // Keep interesting hash function at least visible
 /*
 static guint strcase_hash(gconstpointer v)
@@ -932,7 +1057,7 @@ static VikTrwLayer* trw_layer_new ( gint drawmode )
     trw_layer_params[PARAM_WPSYM].widget_data = str_array_to_glist(params_wpsymbols);
 
   VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) );
-  vik_layer_init ( VIK_LAYER(rv), VIK_LAYER_TRW );
+  vik_layer_set_type ( VIK_LAYER(rv), VIK_LAYER_TRW );
 
   // It's not entirely clear the benefits of hash tables usage here - possibly the simplicity of first implementation for unique names
   // Now with the name of the item stored as part of the item - these tables are effectively straightforward lists
@@ -950,11 +1075,15 @@ static VikTrwLayer* trw_layer_new ( gint drawmode )
   rv->waypoints_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
   rv->tracks = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free );
   rv->tracks_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
+  rv->routes = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free );
+  rv->routes_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
 
   /* TODO: constants at top */
-  rv->waypoints_visible = rv->tracks_visible = TRUE;
+  rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE;
   rv->drawmode = drawmode;
   rv->drawpoints = TRUE;
+  rv->drawpoints_size = MIN_POINT_SIZE;
+  rv->drawdirections_size = 5;
   rv->drawstops = FALSE;
   rv->drawelevation = FALSE;
   rv->elevation_factor = 30;
@@ -1032,13 +1161,17 @@ static void trw_layer_free ( VikTrwLayer *trwlayer )
   g_queue_free ( trwlayer->image_cache );
 }
 
-static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp )
+static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp )
 {
+  dp->vtl = vtl;
   dp->vp = vp;
   dp->xmpp = vik_viewport_get_xmpp ( vp );
   dp->ympp = vik_viewport_get_ympp ( vp );
   dp->width = vik_viewport_get_width ( vp );
   dp->height = vik_viewport_get_height ( vp );
+  dp->cc = vtl->drawdirections_size*cos(45 * DEG2RAD); // Calculate once per vtl update - even if not used
+  dp->ss = vtl->drawdirections_size*sin(45 * DEG2RAD); // Calculate once per vtl update - even if not used
+
   dp->center = vik_viewport_get_center ( vp );
   dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */
   dp->lat_lon = vik_viewport_get_coord_mode ( vp ) == VIK_COORD_LATLON;
@@ -1093,7 +1226,7 @@ static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1
   return VIK_TRW_LAYER_TRACK_GC_BLACK;
 }
 
-void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
+static void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
 {
   vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y );
   vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 );
@@ -1101,7 +1234,7 @@ void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
   vik_viewport_draw_line ( vvp, gc, x+5, y-5, x-5, y+5 );
 }
 
-static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct DrawingParams *dp, gboolean drawing_white_background )
+static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline )
 {
   /* TODO: this function is a mess, get rid of any redundancy */
   GList *list = track->trackpoints;
@@ -1113,8 +1246,8 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
   gboolean drawelevation;
   gdouble min_alt, max_alt, alt_diff = 0;
 
-  const guint8 tp_size_reg = 2;
-  const guint8 tp_size_cur = 4;
+  const guint8 tp_size_reg = dp->vtl->drawpoints_size;
+  const guint8 tp_size_cur = dp->vtl->drawpoints_size*2;
   guint8 tp_size;
 
   if ( dp->vtl->drawelevation )
@@ -1128,10 +1261,10 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     return;
 
   /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
-  if ( dp->vtl->bg_line_thickness && !drawing_white_background )
+  if ( dp->vtl->bg_line_thickness && !draw_track_outline )
     trw_layer_draw_track ( name, track, dp, TRUE );
 
-  if ( drawing_white_background )
+  if ( draw_track_outline )
     drawpoints = drawstops = FALSE;
   else {
     drawpoints = dp->vtl->drawpoints;
@@ -1149,7 +1282,8 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
         then draw in the highlight colour.
         NB this supercedes the drawmode */
       if ( dp->vtl && ( ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ||
-                       ( dp->vtl->tracks == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ||
+                       ( !track->is_route && ( dp->vtl->tracks == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) ||
+                       ( track->is_route && ( dp->vtl->routes == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) ||
                        track == vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) {
        main_gc = vik_viewport_get_gc_highlight (dp->vp);
        drawing_highlight = TRUE;
@@ -1216,7 +1350,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
        if ( useoldvals && x == oldx && y == oldy )
        {
          // Still need to process points to ensure 'stops' are drawn if required
-         if ( drawstops && drawpoints && ! drawing_white_background && list->next &&
+         if ( drawstops && drawpoints && ! draw_track_outline && list->next &&
               (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 );
 
@@ -1232,7 +1366,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           }
         }
 
-        if ( drawpoints && ! drawing_white_background )
+        if ( drawpoints && ! draw_track_outline )
         {
 
           if ( list->next ) {
@@ -1266,12 +1400,13 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           if (!useoldvals)
             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
 
-          if ( drawing_white_background ) {
+          if ( draw_track_outline ) {
             vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
           }
           else {
 
             vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
+
             if ( dp->vtl->drawelevation && 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)
@@ -1297,6 +1432,22 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           }
         }
 
+        if ( (!tp->newsegment) && dp->vtl->drawdirections ) {
+          // Draw an arrow at the mid point to show the direction of the track
+          // Code is a rework from vikwindow::draw_ruler()
+          gint midx = (oldx + x) / 2;
+          gint midy = (oldy + y) / 2;
+
+          gdouble len = sqrt ( ((midx-oldx) * (midx-oldx)) + ((midy-oldy) * (midy-oldy)) );
+          // Avoid divide by zero and ensure at least 1 pixel big
+          if ( len > 1 ) {
+            gdouble dx = (oldx - midx) / len;
+            gdouble dy = (oldy - midy) / len;
+            vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc + dy * dp->ss), midy + (dy * dp->cc - dx * dp->ss) );
+            vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc - dy * dp->ss), midy + (dy * dp->cc + dx * dp->ss) );
+          }
+        }
+
       skip:
         oldx = x;
         oldy = y;
@@ -1320,7 +1471,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
             */
            if ( x != oldx || y != oldy )
              {
-               if ( drawing_white_background )
+               if ( draw_track_outline )
                  vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
                else
                  vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
@@ -1484,7 +1635,31 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct
       /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
       gint label_x, label_y;
       gint width, height;
-      pango_layout_set_text ( dp->vtl->wplabellayout, wp->name, -1 );
+      // Hopefully name won't break the markup (may need to sanitize - g_markup_escape_text())
+
+      // Could this stored in the waypoint rather than recreating each pass?
+      gchar *fsize = NULL;
+      switch (dp->vtl->wp_font_size) {
+        case FS_XX_SMALL: fsize = g_strdup ( "xx-small" ); break;
+        case FS_X_SMALL: fsize = g_strdup ( "x-small" ); break;
+        case FS_SMALL: fsize = g_strdup ( "small" ); break;
+        case FS_LARGE: fsize = g_strdup ( "large" ); break;
+        case FS_X_LARGE: fsize = g_strdup ( "x-large" ); break;
+        case FS_XX_LARGE: fsize = g_strdup ( "xx-large" ); break;
+        default: fsize = g_strdup ( "medium" ); break;
+      }
+
+      gchar *wp_label_markup = g_strdup_printf ( "<span size=\"%s\">%s</span>", fsize, wp->name );
+
+      if ( pango_parse_markup ( wp_label_markup, -1, 0, NULL, NULL, NULL, NULL ) )
+        pango_layout_set_markup ( dp->vtl->wplabellayout, wp_label_markup, -1 );
+      else
+        // Fallback if parse failure
+        pango_layout_set_text ( dp->vtl->wplabellayout, wp->name, -1 );
+
+      g_free ( wp_label_markup );
+      g_free ( fsize );
+
       pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
       label_x = x - width/2;
       if (sym)
@@ -1514,12 +1689,14 @@ static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
   static struct DrawingParams dp;
   g_assert ( l != NULL );
 
-  init_drawing_params ( &dp, VIK_VIEWPORT(data) );
-  dp.vtl = l;
+  init_drawing_params ( &dp, l, VIK_VIEWPORT(data) );
 
   if ( l->tracks_visible )
     g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp );
 
+  if ( l->routes_visible )
+    g_hash_table_foreach ( l->routes, (GHFunc) trw_layer_draw_track_cb, &dp );
+
   if (l->waypoints_visible)
     g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint, &dp );
 }
@@ -1637,6 +1814,20 @@ static VikTrwLayer* trw_layer_create ( VikViewport *vp )
   return rv;
 }
 
+#define SMALL_ICON_SIZE 18
+/*
+ * Can accept a null symbol, and may return null value
+ */
+static GdkPixbuf* get_wp_sym_small ( gchar *symbol )
+{
+  GdkPixbuf* wp_icon = a_get_wp_sym (symbol);
+  // ATM a_get_wp_sym returns a cached icon, with the size dependent on the preferences.
+  //  So needing a small icon for the treeview may need some resizing:
+  if ( wp_icon && gdk_pixbuf_get_width ( wp_icon ) != SMALL_ICON_SIZE )
+    wp_icon = gdk_pixbuf_scale_simple ( wp_icon, SMALL_ICON_SIZE, SMALL_ICON_SIZE, GDK_INTERP_BILINEAR );
+  return wp_icon;
+}
+
 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] )
 {
   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
@@ -1648,7 +1839,10 @@ static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pas
 #endif
 
   *new_iter = *((GtkTreeIter *) pass_along[1]);
-  g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, id, new_iter );
+  if ( track->is_route )
+    g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->routes_iters, id, new_iter );
+  else
+    g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, id, new_iter );
 
   if ( ! track->visible )
     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
@@ -1657,10 +1851,11 @@ static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pas
 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] )
 {
   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
+
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-  vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
+  vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
 #else
-  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), NULL, TRUE, TRUE );
+  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
 #endif
 
   *new_iter = *((GtkTreeIter *) pass_along[1]);
@@ -1670,35 +1865,67 @@ static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer
     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
 }
 
-
-static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
+static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
 {
-  GtkTreeIter iter2;
-  gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACK) };
-
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
   vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
 #else
   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
 #endif
-  if ( ! vtl->tracks_visible )
-    vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), FALSE ); 
-
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
+}
 
+static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
+{
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
   vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
 #else
   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
 #endif
+}
+
+static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
+{
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+  vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE );
+#else
+  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE );
+#endif
+}
+
+static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
+{
+  GtkTreeIter iter2;
+  gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACK) };
+
+  if ( g_hash_table_size (vtl->tracks) > 0 ) {
+    trw_layer_add_sublayer_tracks ( vtl, vt , layer_iter );
+    g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
+
+    vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), vtl->tracks_visible );
+  }
 
-  if ( ! vtl->waypoints_visible )
-    vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), FALSE ); 
+  if ( g_hash_table_size (vtl->routes) > 0 ) {
 
-  pass_along[0] = &(vtl->waypoints_iter);
-  pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
+    trw_layer_add_sublayer_routes ( vtl, vt, layer_iter );
 
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
+    pass_along[0] = &(vtl->routes_iter);
+    pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTE);
+
+    g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_realize_track, pass_along );
+
+    vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->routes_iter), vtl->routes_visible );
+  }
+
+  if ( g_hash_table_size (vtl->waypoints) > 0 ) {
+    trw_layer_add_sublayer_waypoints ( vtl, vt, layer_iter );
+
+    pass_along[0] = &(vtl->waypoints_iter);
+    pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
+
+    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
+
+    vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), vtl->waypoints_visible );
+  }
 
 }
 
@@ -1708,6 +1935,7 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype
   {
     case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1);
     case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1);
+    case VIK_TRW_LAYER_SUBLAYER_ROUTES: return (l->routes_visible ^= 1);
     case VIK_TRW_LAYER_SUBLAYER_TRACK:
     {
       VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer );
@@ -1724,6 +1952,14 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype
       else
         return TRUE;
     }
+    case VIK_TRW_LAYER_SUBLAYER_ROUTE:
+    {
+      VikTrack *t = g_hash_table_lookup ( l->routes, sublayer );
+      if (t)
+        return (t->visible ^= 1);
+      else
+        return TRUE;
+    }
   }
   return TRUE;
 }
@@ -1853,8 +2089,8 @@ static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
 
     // Put together all the elements to form compact tooltip text
     g_snprintf (tmp_buf, sizeof(tmp_buf),
-               _("Tracks: %d - Waypoints: %d%s"),
-               g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), tbuf2);
+               _("Tracks: %d - Waypoints: %d - Routes: %d%s"),
+               g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2);
 
     g_date_free (gdate_start);
     g_date_free (gdate_end);
@@ -1868,11 +2104,37 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
 {
   switch ( subtype )
   {
-    case VIK_TRW_LAYER_SUBLAYER_TRACKS: return NULL;
-    case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return NULL;
+    case VIK_TRW_LAYER_SUBLAYER_TRACKS:
+    {
+      // Very simple tooltip - may expand detail in the future...
+      static gchar tmp_buf[32];
+      g_snprintf (tmp_buf, sizeof(tmp_buf),
+                  _("Tracks: %d"),
+                  g_hash_table_size (l->tracks));
+      return tmp_buf;
+    }
+    break;
+    case VIK_TRW_LAYER_SUBLAYER_ROUTES:
+    {
+      // Very simple tooltip - may expand detail in the future...
+      static gchar tmp_buf[32];
+      g_snprintf (tmp_buf, sizeof(tmp_buf),
+                  _("Routes: %d"),
+                  g_hash_table_size (l->routes));
+      return tmp_buf;
+    }
+    break;
+
+    case VIK_TRW_LAYER_SUBLAYER_ROUTE:
+      // Same tooltip for a route
     case VIK_TRW_LAYER_SUBLAYER_TRACK:
     {
-      VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer );
+      VikTrack *tr;
+      if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+        tr = g_hash_table_lookup ( l->tracks, sublayer );
+      else
+        tr = g_hash_table_lookup ( l->routes, sublayer );
+
       if ( tr ) {
        // Could be a better way of handling strings - but this works...
        gchar time_buf1[20];
@@ -1908,6 +2170,16 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
       }
     }
     break;
+    case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
+    {
+      // Very simple tooltip - may expand detail in the future...
+      static gchar tmp_buf[32];
+      g_snprintf (tmp_buf, sizeof(tmp_buf),
+                  _("Waypoints: %d"),
+                  g_hash_table_size (l->waypoints));
+      return tmp_buf;
+    }
+    break;
     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
     {
       VikWaypoint *w = g_hash_table_lookup ( l->waypoints, sublayer );
@@ -2042,7 +2314,22 @@ static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer subl
          case VIK_TRW_LAYER_SUBLAYER_TRACK:
            {
              VikTrack *track = g_hash_table_lookup ( l->tracks, sublayer );
-             vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l, sublayer );
+             vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l );
+             /* Mark for redraw */
+             return TRUE;
+           }
+           break;
+         case VIK_TRW_LAYER_SUBLAYER_ROUTES:
+           {
+             vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->routes, l );
+             /* Mark for redraw */
+             return TRUE;
+           }
+           break;
+         case VIK_TRW_LAYER_SUBLAYER_ROUTE:
+           {
+             VikTrack *track = g_hash_table_lookup ( l->routes, sublayer );
+             vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l );
              /* Mark for redraw */
              return TRUE;
            }
@@ -2056,14 +2343,14 @@ static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer subl
            break;
          case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
            {
-             VikWaypoint *wpt = g_hash_table_lookup ( l->waypoints, sublayer );
-             if ( wpt ) {
-            vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)wpt, l, sublayer );
-            // Show some waypoint info
-            set_statusbar_msg_info_wpt ( l, wpt );
-            /* Mark for redraw */
-            return TRUE;
-             }
+              VikWaypoint *wpt = g_hash_table_lookup ( l->waypoints, sublayer );
+              if ( wpt ) {
+                vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)wpt, l );
+                // Show some waypoint info
+                set_statusbar_msg_info_wpt ( l, wpt );
+                /* Mark for redraw */
+                return TRUE;
+              }
            }
            break;
          default:
@@ -2087,6 +2374,11 @@ GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
   return l->tracks;
 }
 
+GHashTable *vik_trw_layer_get_routes ( VikTrwLayer *l )
+{
+  return l->routes;
+}
+
 GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l )
 {
   return l->waypoints;
@@ -2134,6 +2426,15 @@ VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name )
   return g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find, (gpointer) name );
 }
 
+/*
+ * Get route by name - not guaranteed to be unique
+ * Finds the first one
+ */
+VikTrack *vik_trw_layer_get_route ( VikTrwLayer *vtl, const gchar *name )
+{
+  return g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find, (gpointer) name );
+}
+
 static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] )
 {
   static VikCoord fixme;
@@ -2170,35 +2471,10 @@ static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *tr
 
 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2])
 {
-  struct LatLon wpt_maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
-  struct LatLon trk_maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
-  
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, wpt_maxmin );
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, trk_maxmin );
-  if ((wpt_maxmin[0].lat != 0.0 && wpt_maxmin[0].lat > trk_maxmin[0].lat) || trk_maxmin[0].lat == 0.0) {
-    maxmin[0].lat = wpt_maxmin[0].lat;
-  }
-  else {
-    maxmin[0].lat = trk_maxmin[0].lat;
-  }
-  if ((wpt_maxmin[0].lon != 0.0 && wpt_maxmin[0].lon > trk_maxmin[0].lon) || trk_maxmin[0].lon == 0.0) {
-    maxmin[0].lon = wpt_maxmin[0].lon;
-  }
-  else {
-    maxmin[0].lon = trk_maxmin[0].lon;
-  }
-  if ((wpt_maxmin[1].lat != 0.0 && wpt_maxmin[1].lat < trk_maxmin[1].lat) || trk_maxmin[1].lat == 0.0) {
-    maxmin[1].lat = wpt_maxmin[1].lat;
-  }
-  else {
-    maxmin[1].lat = trk_maxmin[1].lat;
-  }
-  if ((wpt_maxmin[1].lon != 0.0 && wpt_maxmin[1].lon < trk_maxmin[1].lon) || trk_maxmin[1].lon == 0.0) {
-    maxmin[1].lon = wpt_maxmin[1].lon;
-  }
-  else {
-    maxmin[1].lon = trk_maxmin[1].lon;
-  }
+  // Continually reuse maxmin to find the latest maximum and minimum values
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin );
+  g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
+  g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
 }
 
 gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
@@ -2416,7 +2692,13 @@ static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
   gpointer layer_and_vlp[2];
   layer_and_vlp[0] = pass_along[0];
   layer_and_vlp[1] = pass_along[1];
-  VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
 
   if ( !trk || !trk->name )
     return;
@@ -2636,7 +2918,7 @@ static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
   a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface );
 }
 
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
 /*
  * Acquire into this TRW Layer from Google Directions
  */
@@ -2722,12 +3004,32 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(pass_along[1]);
 
-  // May not actually get a track here as pass_along[3] can be null
-  VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  // May not actually get a track here as pass_along[2&3] can be null
+  VikTrack *track = NULL;
+  vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
+  gboolean xfer_all = FALSE;
 
-  gboolean on_track = track ? TRUE : FALSE;
+  if ( pass_along[2] ) {
+    xfer_all = FALSE;
+    if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
+      track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+      xfer_type = RTE;
+    }
+    else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+      track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+      xfer_type = TRK;
+    }
+    else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) {
+      xfer_type = WPT;
+    }
+    else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
+      xfer_type = RTE;
+    }
+  }
+  else if ( !pass_along[4] )
+    xfer_all = TRUE; // i.e. whole layer
 
-  if (on_track && !track->visible) {
+  if (track && !track->visible) {
     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") );
     return;
   }
@@ -2750,7 +3052,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
   if ( response_w )
     gtk_widget_grab_focus ( response_w );
 
-  gpointer dgs = datasource_gps_setup ( dialog, on_track );
+  gpointer dgs = datasource_gps_setup ( dialog, xfer_type, xfer_all );
 
   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
     datasource_gps_clean_up ( dgs );
@@ -2763,6 +3065,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
   gchar* port = datasource_gps_get_descriptor ( dgs );
   // NB don't free the above strings as they're references to values held elsewhere
   gboolean do_tracks = datasource_gps_get_do_tracks ( dgs );
+  gboolean do_routes = datasource_gps_get_do_routes ( dgs );
   gboolean do_waypoints = datasource_gps_get_do_waypoints ( dgs );
   gboolean turn_off = datasource_gps_get_off ( dgs );
 
@@ -2783,6 +3086,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
                  vik_layers_panel_get_viewport (vlp),
                  vlp,
                  do_tracks,
+                 do_routes,
                  do_waypoints,
                  turn_off );
 }
@@ -2810,6 +3114,56 @@ static void trw_layer_new_wp ( gpointer lav[2] )
     vik_layers_panel_emit_update ( vlp );
 }
 
+static void trw_layer_new_track ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+
+  if ( ! vtl->current_track ) {
+    gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ;
+    vtl->current_track = vik_track_new();
+    vtl->current_track->visible = TRUE;
+    vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+
+    vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
+  }
+}
+
+static void trw_layer_new_route ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+
+  if ( ! vtl->current_track ) {
+    gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ;
+    vtl->current_track = vik_track_new();
+    vtl->current_track->visible = TRUE;
+    vtl->current_track->is_route = TRUE;
+    vik_trw_layer_add_route ( vtl, name, vtl->current_track );
+
+    vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_ROUTE );
+  }
+}
+
+static void trw_layer_auto_routes_view ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+
+  if ( g_hash_table_size (vtl->routes) > 0 ) {
+    struct LatLon maxmin[2] = { {0,0}, {0,0} };
+    g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
+    trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
+    vik_layers_panel_emit_update ( vlp );
+  }
+}
+
+
+static void trw_layer_finish_track ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  vtl->current_track = NULL;
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+}
+
 static void trw_layer_auto_tracks_view ( gpointer lav[2] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
@@ -2862,6 +3216,21 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
 
+  if ( vtl->current_track ) {
+    if ( vtl->current_track->is_route )
+      item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
+    else
+      item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+
+    // Add separator
+    item = gtk_menu_item_new ();
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+  }
+
   /* Now with icons */
   item = gtk_image_menu_item_new_with_mnemonic ( _("_View Layer") );
   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
@@ -2869,14 +3238,26 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_mnemonic ( _("View All Trac_ks") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
+  GtkWidget *view_submenu = gtk_menu_new();
+  item = gtk_image_menu_item_new_with_mnemonic ( _("V_iew") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), view_submenu );
 
-  item = gtk_menu_item_new_with_mnemonic ( _("V_iew All Waypoints") );
+  item = gtk_menu_item_new_with_mnemonic ( _("View All _Tracks") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
+  gtk_widget_show ( item );
+
+  item = gtk_menu_item_new_with_mnemonic ( _("View All _Routes") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
+  gtk_widget_show ( item );
+
+  item = gtk_menu_item_new_with_mnemonic ( _("View All _Waypoints") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
   gtk_widget_show ( item );
 
   item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
@@ -2931,11 +3312,34 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  item = gtk_image_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
+  GtkWidget *new_submenu = gtk_menu_new();
+  item = gtk_image_menu_item_new_with_mnemonic ( _("_New") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
+  gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
+  gtk_widget_show(item);
+  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_submenu);
+
+  item = gtk_image_menu_item_new_with_mnemonic ( _("New _Waypoint...") );
   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
   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_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
+  gtk_widget_show ( item );
+
+  item = gtk_image_menu_item_new_with_mnemonic ( _("New _Track") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
+  gtk_widget_show ( item );
+  // Make it available only when a new track *not* already in progress
+  gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
+
+  item = gtk_image_menu_item_new_with_mnemonic ( _("New _Route") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
   gtk_widget_show ( item );
+  // Make it available only when a new track *not* already in progress
+  gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
 
 #ifdef VIK_CONFIG_GEONAMES
   GtkWidget *wikipedia_submenu = gtk_menu_new();
@@ -2977,7 +3381,7 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
   gtk_widget_show ( item );
 
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
   item = gtk_menu_item_new_with_mnemonic ( _("From G_oogle Directions...") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_google_cb), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
@@ -3017,6 +3421,12 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_widget_show ( item );
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
 
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
+  gtk_widget_show ( item );
+
 #ifdef VIK_CONFIG_OPENSTREETMAP 
   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
@@ -3025,12 +3435,6 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_widget_show ( item );
 #endif
 
-  item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") );
-  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
-  gtk_widget_show ( item );
-
   GtkWidget *delete_submenu = gtk_menu_new ();
   item = gtk_image_menu_item_new_with_mnemonic ( _("De_lete") );
   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
@@ -3088,13 +3492,18 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp
 
   if ( VIK_LAYER(vtl)->realized )
   {
+    // Do we need to create the sublayer:
+    if ( g_hash_table_size (vtl->waypoints) == 0 ) {
+      trw_layer_add_sublayer_waypoints ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
+    }
+
     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
 
     // Visibility column always needed for waypoints
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-    vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE );
+    vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE );
 #else
-    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE );
+    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE );
 #endif
     // Actual setting of visibility dependent on the waypoint
     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
@@ -3118,6 +3527,11 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 
   if ( VIK_LAYER(vtl)->realized )
   {
+    // Do we need to create the sublayer:
+    if ( g_hash_table_size (vtl->tracks) == 0 ) {
+      trw_layer_add_sublayer_tracks ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
+    }
+
     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
     // Visibility column always needed for tracks
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
@@ -3135,24 +3549,74 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
  
 }
 
+// Fake Route UUIDs vi simple increasing integer
+static guint rt_uuid = 0;
+
+void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
+{
+  rt_uuid++;
+
+  vik_track_set_name (t, name);
+
+  if ( VIK_LAYER(vtl)->realized )
+  {
+    // Do we need to create the sublayer:
+    if ( g_hash_table_size (vtl->routes) == 0 ) {
+      trw_layer_add_sublayer_routes ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
+    }
+
+    GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
+    // Visibility column always needed for tracks
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+    vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE );
+#else
+    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE );
+#endif
+    // Actual setting of visibility dependent on the track
+    vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
+
+    g_hash_table_insert ( vtl->routes_iters, GUINT_TO_POINTER(rt_uuid), iter );
+  }
+
+  g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t );
+
+}
+
 /* to be called whenever a track has been deleted or may have been changed. */
 void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk )
 {
   if (vtl->current_tp_track == trk )
     trw_layer_cancel_current_tp ( vtl, FALSE );
 }
-       
+
 gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
 {
- gint i = 2;
- gchar *newname = g_strdup(name);
- while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ?
-         (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) {
-    gchar *new_newname = g_strdup_printf("%s#%d", name, i);
-    g_free(newname);
-    newname = new_newname;
-    i++;
-  }
+  gint i = 2;
+  gchar *newname = g_strdup(name);
+
+  gpointer id = NULL;
+  do {
+    id = NULL;
+    switch ( sublayer_type ) {
+    case VIK_TRW_LAYER_SUBLAYER_TRACK:
+      id = (gpointer) vik_trw_layer_get_track ( vtl, newname );
+      break;
+    case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
+      id = (gpointer) vik_trw_layer_get_waypoint ( vtl, newname );
+      break;
+    default:
+      id = (gpointer) vik_trw_layer_get_route ( vtl, newname );
+      break;
+    }
+    // If found a name already in use try adding 1 to it and we try again
+    if ( id ) {
+      gchar *new_newname = g_strdup_printf("%s#%d", name, i);
+      g_free(newname);
+      newname = new_newname;
+      i++;
+    }
+  } while ( id != NULL);
+
   return newname;
 }
 
@@ -3173,7 +3637,10 @@ void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t
   } else {
 
     // No more uniqueness of name forced when loading from a file
-    vik_trw_layer_add_track ( vtl, name, tr );
+    if ( tr->is_route )
+      vik_trw_layer_add_route ( vtl, name, tr );
+    else
+      vik_trw_layer_add_track ( vtl, name, tr );
 
     if ( vtl->route_finder_check_added_track ) {
       vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
@@ -3202,6 +3669,16 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g
     vik_trw_layer_delete_track ( vtl_src, trk );
   }
 
+  if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
+    VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id );
+
+    gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name);
+
+    VikTrack *trk2 = vik_track_copy ( trk );
+    vik_trw_layer_add_route ( vtl_dest, newname, trk2 );
+    vik_trw_layer_delete_route ( vtl_src, trk );
+  }
+
   if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
     VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
 
@@ -3228,13 +3705,19 @@ static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl
     if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) {
       g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items);
     }    
-      
+    if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
+      g_hash_table_foreach ( vtl_src->routes, (GHFunc)trw_layer_enum_item, &items);
+    }
+
     iter = items;
     while (iter) {
       if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
-       trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
+        trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
+      }
+      else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
+        trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_ROUTE);
       } else {
-       trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
+        trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
       }
       iter = iter->next;
     }
@@ -3299,6 +3782,60 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
         g_hash_table_remove ( vtl->tracks_iters, udata.uuid );
         g_hash_table_remove ( vtl->tracks, udata.uuid );
+
+       // If last sublayer, then remove sublayer container
+       if ( g_hash_table_size (vtl->tracks) == 0 ) {
+          vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
+       }
+      }
+    }
+  }
+  return was_visible;
+}
+
+gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
+{
+  gboolean was_visible = FALSE;
+
+  if ( trk && trk->name ) {
+
+    if ( trk == vtl->current_track ) {
+      vtl->current_track = NULL;
+      vtl->current_tp_track = NULL;
+      vtl->current_tp_id = NULL;
+      vtl->moving_tp = FALSE;
+    }
+
+    was_visible = trk->visible;
+
+    if ( trk == vtl->route_finder_current_track )
+      vtl->route_finder_current_track = NULL;
+
+    if ( trk == vtl->route_finder_added_track )
+      vtl->route_finder_added_track = NULL;
+
+    trku_udata udata;
+    udata.trk  = trk;
+    udata.uuid = NULL;
+
+    // Hmmm, want key of it
+    gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
+
+    if ( trkf && udata.uuid ) {
+      /* could be current_tp, so we have to check */
+      trw_layer_cancel_tps_of_track ( vtl, trk );
+
+      GtkTreeIter *it = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
+
+      if ( it ) {
+        vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
+        g_hash_table_remove ( vtl->routes_iters, udata.uuid );
+        g_hash_table_remove ( vtl->routes, udata.uuid );
+
+        // If last sublayer, then remove sublayer container
+        if ( g_hash_table_size (vtl->routes) == 0 ) {
+          vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
+        }
       }
     }
   }
@@ -3335,6 +3872,11 @@ static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
 
         highest_wp_number_remove_wp(vtl, wp->name);
         g_hash_table_remove ( vtl->waypoints, udata.uuid ); // last because this frees the name
+
+       // If last sublayer, then remove sublayer container
+       if ( g_hash_table_size (vtl->waypoints) == 0 ) {
+          vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
+       }
       }
     }
 
@@ -3398,9 +3940,9 @@ static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const Vik
 /*
  * Delete a track by the given name
  * NOTE: ATM this will delete the first encountered Track with the specified name
- *   as there be multiple track with the same name
+ *   as there may be multiple tracks with the same name within the specified hash table
  */
-static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name )
+static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name, GHashTable *ht_tracks )
 {
   tpu_udata udata;
   // Fake a track with the given name
@@ -3410,12 +3952,18 @@ static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *
   udata.uuid = NULL;
 
   // Hmmm, want key of it
-  gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
+  gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
 
   vik_track_free (udata.trk);
 
-  if ( trkf && udata.uuid )
-    return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( vtl->tracks, udata.uuid ));
+  if ( trkf && udata.uuid ) {
+    // This could be a little better written...
+    if ( vtl->tracks == ht_tracks )
+      return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
+    if ( vtl->routes == ht_tracks )
+      return vik_trw_layer_delete_route (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
+    return FALSE;
+  }
   else
     return FALSE;
 }
@@ -3425,6 +3973,24 @@ static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTre
     vik_treeview_item_delete (vt, it );
 }
 
+void vik_trw_layer_delete_all_routes ( VikTrwLayer *vtl )
+{
+
+  vtl->current_track = NULL;
+  vtl->route_finder_current_track = NULL;
+  vtl->route_finder_added_track = NULL;
+  if (vtl->current_tp_track)
+    trw_layer_cancel_current_tp(vtl, FALSE);
+
+  g_hash_table_foreach(vtl->routes_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->routes_iters);
+  g_hash_table_remove_all(vtl->routes);
+
+  vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
+
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+}
+
 void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
 {
 
@@ -3438,6 +4004,8 @@ void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
   g_hash_table_remove_all(vtl->tracks_iters);
   g_hash_table_remove_all(vtl->tracks);
 
+  vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
+
   vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
 }
 
@@ -3453,6 +4021,8 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
   g_hash_table_remove_all(vtl->waypoints_iters);
   g_hash_table_remove_all(vtl->waypoints);
 
+  vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
+
   vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
 }
 
@@ -3466,6 +4036,16 @@ static void trw_layer_delete_all_tracks ( gpointer lav[2] )
     vik_trw_layer_delete_all_tracks (vtl);
 }
 
+static void trw_layer_delete_all_routes ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  // Get confirmation from the user
+  if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                            _("Are you sure you want to delete all routes in %s?"),
+                            vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
+    vik_trw_layer_delete_all_routes (vtl);
+}
+
 static void trw_layer_delete_all_waypoints ( gpointer lav[2] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
@@ -3494,7 +4074,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
       was_visible = trw_layer_delete_waypoint ( vtl, wp );
     }
   }
-  else
+  else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
     if ( trk && trk->name ) {
@@ -3507,6 +4087,19 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
       was_visible = vik_trw_layer_delete_track ( vtl, trk );
     }
   }
+  else
+  {
+    VikTrack *trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
+    if ( trk && trk->name ) {
+      if ( GPOINTER_TO_INT ( pass_along[4]) )
+        // Get confirmation from the user
+        if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                                    _("Are you sure you want to delete the route \"%s\""),
+                                    trk->name ) )
+          return;
+      was_visible = vik_trw_layer_delete_route ( vtl, trk );
+    }
+  }
   if ( was_visible )
     vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
 }
@@ -3524,13 +4117,21 @@ static void trw_layer_properties_item ( gpointer pass_along[7] )
       gboolean updated = FALSE;
       a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, wp, vtl->coord_mode, FALSE, &updated );
 
+      if ( updated && pass_along[6] )
+        vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) );
+
       if ( updated && VIK_LAYER(vtl)->visible )
        vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     }
   }
   else
   {
-    VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    VikTrack *tr;
+    if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    else
+      tr = g_hash_table_lookup ( vtl->routes, pass_along[3] );
+
     if ( tr && tr->name )
     {
       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
@@ -3563,14 +4164,26 @@ static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoor
 
 static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] )
 {
-  GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
-  if ( trps && trps->data )
-    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( track && track->trackpoints )
+    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) track->trackpoints->data)->coord) );
 }
 
 static void trw_layer_goto_track_center ( gpointer pass_along[6] )
 {
-  VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
   if ( track && track->trackpoints )
   {
     struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
@@ -3578,24 +4191,83 @@ static void trw_layer_goto_track_center ( gpointer pass_along[6] )
     trw_layer_find_maxmin_tracks ( NULL, track, maxmin );
     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
-    vik_coord_load_from_latlon ( &coord, VIK_TRW_LAYER(pass_along[0])->coord_mode, &average );
+    vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord);
   }
 }
 
+static void trw_layer_convert_track_route ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !trk )
+    return;
+
+  // Converting a track to a route can be a bit more complicated,
+  //  so give a chance to change our minds:
+  if ( !trk->is_route &&
+       ( ( vik_track_get_segment_count ( trk ) > 1 ) ||
+         ( vik_track_get_average_speed ( trk ) > 0.0 ) ) ) {
+
+    if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                                _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) )
+      return;
+}
+
+  // Copy it
+  VikTrack *trk_copy = vik_track_copy ( trk );
+
+  // Convert
+  trk_copy->is_route = !trk_copy->is_route;
+
+  // ATM can't set name to self - so must create temporary copy
+  gchar *name = g_strdup ( trk_copy->name );
+
+  // Delete old one and then add new one
+  if ( trk->is_route ) {
+    vik_trw_layer_delete_route ( vtl, trk );
+    vik_trw_layer_add_track ( vtl, name, trk_copy );
+  }
+  else {
+    // Extra route conversion bits...
+    vik_track_merge_segments ( trk_copy );
+    vik_track_to_routepoints ( trk_copy );
+
+    vik_trw_layer_delete_track ( vtl, trk );
+    vik_trw_layer_add_route ( vtl, name, trk_copy );
+  }
+  g_free ( name );
+
+  // Update in case color of track / route changes when moving between sublayers
+  vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE );
+}
+
+
 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] );
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
 
   vtl->current_track = track;
-  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK);
+  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, track->is_route ? TOOL_CREATE_ROUTE : TOOL_CREATE_TRACK);
 
   if ( track->trackpoints )
     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
 }
 
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
 /**
  * extend a track using route finder
  */
@@ -3620,14 +4292,30 @@ 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] );
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
 
-  vik_track_apply_dem_data ( track );
+  if ( track )
+    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;
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
+
+  GList *trps = track->trackpoints;
   if ( !trps )
     return;
   trps = g_list_last(trps);
@@ -3636,7 +4324,17 @@ static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
 
 static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
 {
-  VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
+
+  VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track );
   if ( !vtp )
     return;
   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
@@ -3644,7 +4342,17 @@ static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
 
 static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
 {
-  VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
+
+  VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track );
   if ( !vtp )
     return;
   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
@@ -3652,7 +4360,17 @@ static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
 
 static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
 {
-  VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
+
+  VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track );
   if ( !vtp )
     return;
   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
@@ -3663,7 +4381,13 @@ static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
  */
 static void trw_layer_auto_track_view ( gpointer pass_along[6] )
 {
-  VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
   if ( trk && trk->trackpoints )
   {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
@@ -3823,7 +4547,16 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
   GList *other_tracks = NULL;
-  VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  GHashTable *ght_tracks;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    ght_tracks = vtl->routes;
+  else
+    ght_tracks = vtl->tracks;
+
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
+
+  if ( !track )
+    return;
 
   if ( !track->trackpoints )
     return;
@@ -3835,7 +4568,7 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] )
   // i.e. either those times, or those without
   udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp);
 
-  g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
+  g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
   other_tracks = g_list_reverse(other_tracks);
 
   if ( !other_tracks ) {
@@ -3852,15 +4585,17 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] )
   GList *other_tracks_names = NULL;
   GList *iter = g_list_first ( other_tracks );
   while ( iter ) {
-    other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (vtl->tracks, iter->data))->name );
+    other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (ght_tracks, iter->data))->name );
     iter = g_list_next ( iter );
   }
 
   other_tracks_names = g_list_sort_with_data (other_tracks_names, sort_alphabetically, NULL);
 
   GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                                                other_tracks_names, TRUE,
-                                                _("Merge with..."), _("Select track to merge with"));
+                                                other_tracks_names,
+                                                TRUE,
+                                                _("Merge with..."),
+                                                track->is_route ? _("Select route to merge with") : _("Select track to merge with"));
   g_list_free(other_tracks);
   g_list_free(other_tracks_names);
 
@@ -3868,11 +4603,19 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] )
   {
     GList *l;
     for (l = merge_list; l != NULL; l = g_list_next(l)) {
-      VikTrack *merge_track = vik_trw_layer_get_track ( vtl, l->data );
+      VikTrack *merge_track;
+      if ( track->is_route )
+        merge_track = vik_trw_layer_get_route ( vtl, l->data );
+      else
+        merge_track = vik_trw_layer_get_track ( vtl, l->data );
+
       if (merge_track) {
         track->trackpoints = g_list_concat(track->trackpoints, merge_track->trackpoints);
         merge_track->trackpoints = NULL;
-        vik_trw_layer_delete_track (vtl, merge_track);
+        if ( track->is_route )
+          vik_trw_layer_delete_route (vtl, merge_track);
+        else
+          vik_trw_layer_delete_track (vtl, merge_track);
         track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
       }
     }
@@ -3900,7 +4643,7 @@ static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer
 }
 
 /**
- * Join - this allows combining 'routes' and 'tracks'
+ * Join - this allows combining 'tracks' and 'track routes'
  *  i.e. doesn't care about whether tracks have consistent timestamps
  * ATM can only append one track at a time to the currently selected track
  */
@@ -3908,7 +4651,17 @@ static void trw_layer_append_track ( gpointer pass_along[6] )
 {
 
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *trk;
+  GHashTable *ght_tracks;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    ght_tracks = vtl->routes;
+  else
+    ght_tracks = vtl->tracks;
+
+  trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
+
+  if ( !trk )
+    return;
 
   GList *other_tracks_names = NULL;
 
@@ -3919,16 +4672,17 @@ static void trw_layer_append_track ( gpointer pass_along[6] )
   udata.result = &other_tracks_names;
   udata.exclude = trk->trackpoints;
 
-  g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
+  g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
 
   // Note the limit to selecting one track only
   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                                               other_tracks_names,
-                                               FALSE,
-                                               _("Append Track"),
-                                               _("Select the track to append after the current track"));
+                                                 other_tracks_names,
+                                                 FALSE,
+                                                 trk->is_route ? _("Append Route"): _("Append Track"),
+                                                 trk->is_route ? _("Select the route to append after the current route") :
+                                                                 _("Select the track to append after the current track") );
 
   g_list_free(other_tracks_names);
 
@@ -3938,11 +4692,115 @@ static void trw_layer_append_track ( gpointer pass_along[6] )
     for (l = append_list; l != NULL; l = g_list_next(l)) {
       // TODO: at present this uses the first track found by name,
       //  which with potential multiple same named tracks may not be the one selected...
-      VikTrack *append_track = vik_trw_layer_get_track ( vtl, l->data );
+      VikTrack *append_track;
+      if ( trk->is_route )
+        append_track = vik_trw_layer_get_route ( vtl, l->data );
+      else
+        append_track = vik_trw_layer_get_track ( vtl, l->data );
+
       if ( append_track ) {
         trk->trackpoints = g_list_concat(trk->trackpoints, append_track->trackpoints);
         append_track->trackpoints = NULL;
-        vik_trw_layer_delete_track (vtl, append_track);
+        if ( trk->is_route )
+          vik_trw_layer_delete_route (vtl, append_track);
+        else
+          vik_trw_layer_delete_track (vtl, append_track);
+      }
+    }
+    for (l = append_list; l != NULL; l = g_list_next(l))
+      g_free(l->data);
+    g_list_free(append_list);
+    vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+  }
+}
+
+/**
+ * Very similar to trw_layer_append_track for joining
+ * but this allows selection from the 'other' list
+ * If a track is selected, then is shows routes and joins the selected one
+ * If a route is selected, then is shows tracks and joins the selected one
+ */
+static void trw_layer_append_other ( gpointer pass_along[6] )
+{
+
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *trk;
+  GHashTable *ght_mykind, *ght_others;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
+    ght_mykind = vtl->routes;
+    ght_others = vtl->tracks;
+  }
+  else {
+    ght_mykind = vtl->tracks;
+    ght_others = vtl->routes;
+  }
+
+  trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, pass_along[3] );
+
+  if ( !trk )
+    return;
+
+  GList *other_tracks_names = NULL;
+
+  // Sort alphabetically for user presentation
+  // Convert into list of names for usage with dialog function
+  // TODO: Need to consider how to work best when we can have multiple tracks the same name...
+  twt_udata udata;
+  udata.result = &other_tracks_names;
+  udata.exclude = trk->trackpoints;
+
+  g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
+
+  // Note the limit to selecting one track only
+  //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
+  //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
+  GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                                                 other_tracks_names,
+                                                 FALSE,
+                                                 trk->is_route ? _("Append Track"): _("Append Route"),
+                                                 trk->is_route ? _("Select the track to append after the current route") :
+                                                                 _("Select the route to append after the current track") );
+
+  g_list_free(other_tracks_names);
+
+  // It's a list, but shouldn't contain more than one other track!
+  if ( append_list ) {
+    GList *l;
+    for (l = append_list; l != NULL; l = g_list_next(l)) {
+      // TODO: at present this uses the first track found by name,
+      //  which with potential multiple same named tracks may not be the one selected...
+
+      // Get FROM THE OTHER TYPE list
+      VikTrack *append_track;
+      if ( trk->is_route )
+        append_track = vik_trw_layer_get_track ( vtl, l->data );
+      else
+        append_track = vik_trw_layer_get_route ( vtl, l->data );
+
+      if ( append_track ) {
+
+        if ( !append_track->is_route &&
+             ( ( vik_track_get_segment_count ( append_track ) > 1 ) ||
+               ( vik_track_get_average_speed ( append_track ) > 0.0 ) ) ) {
+
+          if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                                      _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) ) {
+           vik_track_merge_segments ( append_track );
+           vik_track_to_routepoints ( append_track );
+         }
+          else {
+            break;
+          }
+        }
+
+        trk->trackpoints = g_list_concat(trk->trackpoints, append_track->trackpoints);
+        append_track->trackpoints = NULL;
+
+       // Delete copied which is FROM THE OTHER TYPE list
+        if ( trk->is_route )
+          vik_trw_layer_delete_track (vtl, append_track);
+       else
+          vik_trw_layer_delete_route (vtl, append_track);
       }
     }
     for (l = append_list; l != NULL; l = g_list_next(l))
@@ -4068,13 +4926,13 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
 /**
  * Split a track at the currently selected trackpoint
  */
-static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl )
+static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subtype )
 {
   if ( !vtl->current_tpl )
     return;
 
   if ( vtl->current_tpl->next && vtl->current_tpl->prev ) {
-    gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track->name);
+    gchar *name = trw_layer_new_unique_sublayer_name(vtl, subtype, vtl->current_tp_track->name);
     if ( name ) {
       VikTrack *tr = vik_track_new ();
       GList *newglist = g_list_alloc ();
@@ -4082,6 +4940,8 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl )
       newglist->next = vtl->current_tpl->next;
       newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
       tr->trackpoints = newglist;
+      tr->is_route = vtl->current_tp_track->is_route;
+      tr->visible = TRUE;
 
       vtl->current_tpl->next->prev = newglist; /* end old track here */
       vtl->current_tpl->next = NULL;
@@ -4089,16 +4949,22 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl )
       vtl->current_tpl = newglist; /* change tp to first of new track. */
       vtl->current_tp_track = tr;
 
-      tr->visible = TRUE;
-
-      vik_trw_layer_add_track ( vtl, name, tr );
+      if ( tr->is_route )
+        vik_trw_layer_add_route ( vtl, name, tr );
+      else
+        vik_trw_layer_add_track ( vtl, name, tr );
 
       trku_udata udata;
       udata.trk  = tr;
       udata.uuid = NULL;
 
       // Also need id of newly created track
-      gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
+      gpointer *trkf;
+      if ( tr->is_route )
+         trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
+      else
+         trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
+
       if ( trkf && udata.uuid )
         vtl->current_tp_id = udata.uuid;
       else
@@ -4189,7 +5055,14 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
 static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *track = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
 
   // Check valid track
   GList *trps = track->trackpoints;
@@ -4243,15 +5116,24 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
 
       tr = vik_track_new();
       tr->visible = track->visible;
+      tr->is_route = track->is_route;
       tr->trackpoints = (GList *)(iter->data);
 
-      new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
-      vik_trw_layer_add_track(vtl, new_tr_name, tr);
-
+      if ( track->is_route ) {
+        new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, track->name);
+        vik_trw_layer_add_route(vtl, new_tr_name, tr);
+      }
+      else {
+        new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
+        vik_trw_layer_add_track(vtl, new_tr_name, tr);
+      }
       iter = g_list_next(iter);
     }
     // Remove original track and then update the display
-    vik_trw_layer_delete_track (vtl, track);
+    if ( track->is_route )
+      vik_trw_layer_delete_route (vtl, track);
+    else
+      vik_trw_layer_delete_track (vtl, track);
     vik_layer_emit_update(VIK_LAYER(pass_along[0]), FALSE);
   }
   g_list_free(newlists);
@@ -4263,16 +5145,22 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
 static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  trw_layer_split_at_selected_trackpoint ( vtl );
+  gint subtype = GPOINTER_TO_INT (pass_along[2]);
+  trw_layer_split_at_selected_trackpoint ( vtl, subtype );
 }
 
 /**
  * Split a track by its segments
+ * Routes do not have segments so don't call this for routes
  */
 static void trw_layer_split_segments ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !trk )
+    return;
+
   guint ntracks;
 
   VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
@@ -4303,7 +5191,14 @@ static void trw_layer_split_segments ( gpointer pass_along[6] )
 static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !trk )
+    return;
 
   gulong removed = vik_track_remove_dup_points ( trk );
 
@@ -4326,7 +5221,14 @@ static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
 static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !trk )
+    return;
 
   gulong removed = vik_track_remove_same_time_points ( trk );
 
@@ -4348,7 +5250,14 @@ static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
 static void trw_layer_reverse ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *track = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( ! track )
+    return;
 
   // Check valid track
   GList *trps = track->trackpoints;
@@ -4419,14 +5328,14 @@ static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpo
 }
 
 /**
- * Find out if any tracks have the same name in this layer
+ * Find out if any tracks have the same name in this hash table
  */
-static gboolean trw_layer_has_same_track_names ( VikTrwLayer *vtl )
+static gboolean trw_layer_has_same_track_names ( GHashTable *ht_tracks )
 {
   // Sort items by name, then compare if any next to each other are the same
 
   GList *track_names = NULL;
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+  g_hash_table_foreach ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
 
   // No tracks
   if ( ! track_names )
@@ -4446,10 +5355,11 @@ static gboolean trw_layer_has_same_track_names ( VikTrwLayer *vtl )
 }
 
 /**
- * Force unqiue track names for this layer
+ * Force unqiue track names for the track table specified
  * Note the panel is a required parameter to enable the update of the names displayed
+ * Specify if on tracks or else on routes
  */
-static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp, GHashTable *track_table, gboolean ontrack )
 {
   // . Search list for an instance of repeated name
   // . get track of this name
@@ -4463,7 +5373,7 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
   udata.has_same_track_name = FALSE;
   udata.same_track_name = NULL;
 
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+  g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
 
   // No tracks
   if ( ! track_names )
@@ -4478,7 +5388,11 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
   while ( udata.has_same_track_name ) {
 
     // Find a track with the same name
-    VikTrack *trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name );
+    VikTrack *trk;
+    if ( ontrack )
+      trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name );
+    else
+      trk = vik_trw_layer_get_route ( vtl, (gpointer) udata.same_track_name );
 
     if ( ! trk ) {
       // Broken :(
@@ -4497,11 +5411,15 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
     udataU.uuid = NULL;
 
     // Need want key of it for treeview update
-    gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+    gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
 
     if ( trkf && udataU.uuid ) {
 
-      GtkTreeIter *it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
+      GtkTreeIter *it;
+      if ( ontrack )
+       it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
+      else
+       it = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
 
       if ( it ) {
         vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
@@ -4513,7 +5431,7 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
 
     // Start trying to find same names again...
     track_names = NULL;
-    g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+    g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
     udata.has_same_track_name = FALSE;
     GList *dummy_list2 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
 
@@ -4535,10 +5453,10 @@ static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
   GList *all = NULL;
 
   // Ensure list of track names offered is unique
-  if ( trw_layer_has_same_track_names ( vtl ) ) {
+  if ( trw_layer_has_same_track_names ( vtl->tracks ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                              _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
-      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]) );
+      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE );
     }
     else
       return;
@@ -4566,7 +5484,54 @@ static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
     GList *l;
     for (l = delete_list; l != NULL; l = g_list_next(l)) {
       // This deletes first trk it finds of that name (but uniqueness is enforced above)
-      trw_layer_delete_track_by_name (vtl, l->data);
+      trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
+    }
+    g_list_free(delete_list);
+    vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+  }
+}
+
+/**
+ *
+ */
+static void trw_layer_delete_routes_from_selection ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  GList *all = NULL;
+
+  // Ensure list of track names offered is unique
+  if ( trw_layer_has_same_track_names ( vtl->routes ) ) {
+    if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                              _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
+      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->routes, FALSE );
+    }
+    else
+      return;
+  }
+
+  // Sort list alphabetically for better presentation
+  g_hash_table_foreach(vtl->routes, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
+
+  if ( ! all ) {
+    a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No routes found"));
+    return;
+  }
+
+  // Get list of items to delete from the user
+  GList *delete_list = a_dialog_select_from_list ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                                                   all,
+                                                   TRUE,
+                                                   _("Delete Selection"),
+                                                   _("Select routes to delete") );
+  g_list_free(all);
+
+  // Delete requested routes
+  // since specificly requested, IMHO no need for extra confirmation
+  if ( delete_list ) {
+    GList *l;
+    for (l = delete_list; l != NULL; l = g_list_next(l)) {
+      // This deletes first route it finds of that name (but uniqueness is enforced above)
+      trw_layer_delete_track_by_name (vtl, l->data, vtl->routes);
     }
     g_list_free(delete_list);
     vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
@@ -4768,28 +5733,65 @@ static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] )
   g_free ( webpage );
 }
 
-static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
-{
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
+{
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+  {
+    VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
+
+    // No actual change to the name supplied
+    if (strcmp(newname, wp->name) == 0 )
+      return NULL;
+
+    VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname );
+
+    if ( wpf ) {
+      // An existing waypoint has been found with the requested name
+      if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
+           _("A waypoint with the name \"%s\" already exists. Really rename to the same name?"),
+           newname ) )
+        return NULL;
+    }
+
+    // Update WP name and refresh the treeview
+    vik_waypoint_set_name (wp, newname);
+
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+    vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname );
+#endif
+
+    vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
+
+    return newname;
+  }
+
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
-    VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
+    VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
 
     // No actual change to the name supplied
-    if (strcmp(newname, wp->name) == 0 )
+    if (strcmp(newname, trk->name) == 0)
       return NULL;
 
-    VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname );
+    VikTrack *trkf = vik_trw_layer_get_track ( l, (gpointer) newname );
 
-    if ( wpf ) {
-      // An existing waypoint has been found with the requested name
+    if ( trkf ) {
+      // An existing track has been found with the requested name
       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
-           _("A waypoint with the name \"%s\" already exists. Really create one with the same name?"), 
-           newname ) )
+          _("A track with the name \"%s\" already exists. Really rename to the same name?"),
+          newname ) )
         return NULL;
     }
+    // Update track name and refresh GUI parts
+    vik_track_set_name (trk, newname);
 
-    // Update WP name and refresh the treeview
-    vik_waypoint_set_name (wp, newname);
+    // Update any subwindows that could be displaying this track which has changed name
+    // Only one Track Edit Window
+    if ( l->current_tp_track == trk && l->tpwin ) {
+      vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
+    }
+    // Property Dialog of the track
+    vik_trw_layer_propwin_update ( trk );
 
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
     vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname );
@@ -4800,20 +5802,20 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc
     return newname;
   }
 
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
   {
-    VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
+    VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer );
 
     // No actual change to the name supplied
     if (strcmp(newname, trk->name) == 0)
       return NULL;
 
-    VikTrack *trkf = vik_trw_layer_get_track ( l, (gpointer) newname );
+    VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname );
 
     if ( trkf ) {
       // An existing track has been found with the requested name
       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
-          _("A track with the name \"%s\" already exists. Really create one with the same name?"),
+          _("A route with the name \"%s\" already exists. Really rename to the same name?"),
           newname ) )
         return NULL;
     }
@@ -4851,6 +5853,7 @@ static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
   a_acquire_set_filter_track ( trk );
 }
 
+#ifdef VIK_CONFIG_GOOGLE
 static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id )
 {
   VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_id );
@@ -4868,6 +5871,7 @@ static void trw_layer_track_google_route_webpage ( gpointer pass_along[6] )
     g_free ( webpage );
   }
 }
+#endif
 
 /* vlp can be NULL if necessary - i.e. right-click from a tool */
 /* viewpoint is now available instead */
@@ -4886,7 +5890,7 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
   pass_along[6] = iter;
   pass_along[7] = NULL; // For misc purposes - maybe track or waypoint
 
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
   {
     rv = TRUE;
 
@@ -4896,8 +5900,12 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_widget_show ( item );
 
     if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
-      VikTrwLayer *vtl = l;
-      VikTrack *tr = g_hash_table_lookup ( vtl->tracks, sublayer );
+      VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer );
+      if (tr && tr->property_dialog)
+        gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
+    }
+    if (subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
+      VikTrack *tr = g_hash_table_lookup ( l->routes, sublayer );
       if (tr && tr->property_dialog)
         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
     }
@@ -4996,6 +6004,23 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     }
   }
 
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
+    item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PASTE, NULL );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_paste_item_cb), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+    // TODO: only enable if suitable item is in clipboard - want to determine *which* sublayer type
+    if ( a_clipboard_type ( ) == VIK_CLIPBOARD_DATA_SUBLAYER )
+      gtk_widget_set_sensitive ( item, TRUE );
+    else
+      gtk_widget_set_sensitive ( item, FALSE );
+
+    // Add separator
+    item = gtk_menu_item_new ();
+    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) )
   {
     rv = TRUE;
@@ -5037,12 +6062,31 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
   {
     rv = TRUE;
 
+    if ( l->current_track && !l->current_track->is_route ) {
+      item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show ( item );
+      // Add separator
+      item = gtk_menu_item_new ();
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
+    }
+
     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Tracks") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
     gtk_widget_show ( item );
 
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_New Track") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+    // Make it available only when a new track *not* already in progress
+    gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
+
     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Tracks") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
@@ -5056,13 +6100,76 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_widget_show ( item );
   }
 
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES )
+  {
+    rv = TRUE;
+
+    if ( l->current_track && l->current_track->is_route ) {
+      item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
+      // Reuse finish track method
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show ( item );
+      // Add separator
+      item = gtk_menu_item_new ();
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
+    }
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Routes") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_New Route") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+    // Make it available only when a new track *not* already in progress
+    gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+  }
+
+  GtkWidget *upload_submenu = gtk_menu_new ();
+
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
   {
     item = gtk_menu_item_new ();
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
+    if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && !l->current_track->is_route )
+      item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
+    if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && l->current_track->is_route )
+      item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
+    if ( l->current_track ) {
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show ( item );
+
+      // Add separator
+      item = gtk_menu_item_new ();
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
+    }
+
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
+    else
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_View Route") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
@@ -5106,11 +6213,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
-    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
-    gtk_widget_show ( item );
+    // Routes don't have speeds
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
+      gtk_widget_show ( item );
+    }
 
     GtkWidget *combine_submenu;
     combine_submenu = gtk_menu_new ();
@@ -5120,23 +6230,37 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_widget_show ( item );
     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), combine_submenu );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
-    gtk_widget_show ( item );
+    // Routes don't have times or segments...
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+      item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
+      gtk_widget_show ( item );
+
+      item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
+      gtk_widget_show ( item );
+    }
 
     item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
+    else
+      item = gtk_menu_item_new_with_mnemonic ( _("_Append Route...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_menu_item_new_with_mnemonic ( _("Append _Route...") );
+    else
+      item = gtk_menu_item_new_with_mnemonic ( _("Append _Track...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_other), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
     gtk_widget_show ( item );
 
@@ -5148,22 +6272,25 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_widget_show ( item );
     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), split_submenu );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
-    gtk_widget_show ( item );
+    // Routes don't have times or segments...
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+      item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
+      gtk_widget_show ( item );
+
+      // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy
+      item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
+      gtk_widget_show ( item );
+    }
 
     item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
     gtk_widget_show ( item );
 
-    // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy
-    item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
-    gtk_widget_show ( item );
-
     item = gtk_menu_item_new_with_mnemonic ( _("Split at _Trackpoint") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_at_trackpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
@@ -5189,7 +6316,10 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
+    else
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Route") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_reverse), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
@@ -5197,7 +6327,10 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
 
     /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
     if ( vlp ) {
-      item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
+      if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+        item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
+      else
+        item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Route...") );
       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Maps Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
       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 );
@@ -5210,19 +6343,34 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_image_menu_item_new_with_mnemonic ( _("Export Trac_k as GPX...") );
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") );
+    else
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Route as GPX...") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") );
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") );
+    else
+      item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Route End") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
     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_GOOGLE_DIRECTIONS
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") );
+    else
+      item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+#ifdef VIK_CONFIG_GOOGLE
     item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
@@ -5230,13 +6378,24 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_widget_show ( item );
 #endif
 
-    GtkWidget *upload_submenu = gtk_menu_new ();
-    item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
-    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
-    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-    gtk_widget_show ( item );
-    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
+    // ATM can't upload a single waypoint but can do waypoints to a GPS
+    if ( subtype != VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show ( item );
+      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
+
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS...") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload_any), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
+      gtk_widget_show ( item );
+    }
+  }
 
+  // Some things aren't usable with routes
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
 #ifdef VIK_CONFIG_OPENSTREETMAP
     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
     // Convert internal pointer into actual track for usage outside this file
@@ -5253,6 +6412,7 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
     gtk_widget_show ( item );
 
+#ifdef VIK_CONFIG_GOOGLE
     if ( is_valid_google_route ( l, sublayer ) )
     {
       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") );
@@ -5261,6 +6421,7 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
       gtk_widget_show ( item );
     }
+#endif
 
     item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
@@ -5271,21 +6432,23 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     /* ATM This function is only available via the layers panel, due to needing a vlp */
     if ( vlp ) {
       item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp,
-                                   vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
-                                   g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
+                                    vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
+                                    g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
       if ( item ) {
-       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 );
       }
     }
 
 #ifdef VIK_CONFIG_GEOTAG
-  item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_track), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show ( item );
+    item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_track), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
 #endif
+  }
 
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
     // Only show on viewport popmenu when a trackpoint is selected
     if ( ! vlp && l->current_tpl ) {
       // Add separator
@@ -5299,7 +6462,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
       gtk_widget_show ( item );
     }
-
   }
 
   return rv;
@@ -5350,10 +6512,16 @@ static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl )
     /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */
 
     /* Insert new point into the trackpoints list after the current TP */
-    VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
-    gint index =  g_list_index ( tr->trackpoints, tp_current );
+    VikTrack *trk = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
+    if ( !trk )
+      // Otherwise try routes
+      trk = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
+    if ( !trk )
+      return;
+
+    gint index =  g_list_index ( trk->trackpoints, tp_current );
     if ( index > -1 ) {
-      tr->trackpoints = g_list_insert (tr->trackpoints, tp_new, index+1 );
+      trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index+1 );
     }
   }
 }
@@ -5390,12 +6558,14 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
 
   if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
   {
-    trw_layer_split_at_selected_trackpoint ( vtl );
+    trw_layer_split_at_selected_trackpoint ( vtl, vtl->current_tp_track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK );
     vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
   {
     VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
+    if ( tr == NULL )
+      tr = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
     if ( tr == NULL )
       return;
 
@@ -5550,6 +6720,8 @@ static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams *
   }
 }
 
+// ATM: Leave this as 'Track' only.
+//  Not overly bothered about having a snap to route trackpoint capability
 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
 {
   TPSearchParams params;
@@ -5679,7 +6851,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
-  if ( !vtl->tracks_visible && !vtl->waypoints_visible )
+  if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
     return FALSE;
 
   // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track
@@ -5720,14 +6892,15 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
     }
   }
 
-  if (vtl->tracks_visible) {
-    TPSearchParams tp_params;
-    tp_params.vvp = vvp;
-    tp_params.x = event->x;
-    tp_params.y = event->y;
-    tp_params.closest_track_id = NULL;
-    tp_params.closest_tp = NULL;
+  // Used for both track and route lists
+  TPSearchParams tp_params;
+  tp_params.vvp = vvp;
+  tp_params.x = event->x;
+  tp_params.y = event->y;
+  tp_params.closest_track_id = NULL;
+  tp_params.closest_tp = NULL;
 
+  if (vtl->tracks_visible) {
     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params);
 
     if ( tp_params.closest_tp )  {
@@ -5761,6 +6934,41 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
     }
   }
 
+  // Try again for routes
+  if (vtl->routes_visible) {
+    g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &tp_params);
+
+    if ( tp_params.closest_tp )  {
+
+      // Always select + highlight the track
+      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, tp_params.closest_track_id ), TRUE );
+
+      tet->is_waypoint = FALSE;
+
+      // Select the Trackpoint
+      // Can move it immediately when control held or it's the previously selected tp
+      if ( event->state & GDK_CONTROL_MASK ||
+          vtl->current_tpl == tp_params.closest_tpl ) {
+       // Put into 'move buffer'
+       // NB vvp & vw already set in tet
+       tet->vtl = (gpointer)vtl;
+       marker_begin_move (tet, event->x, event->y);
+      }
+
+      vtl->current_tpl = tp_params.closest_tpl;
+      vtl->current_tp_id = tp_params.closest_track_id;
+      vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, tp_params.closest_track_id );
+
+      set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
+
+      if ( vtl->tpwin )
+       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+
+      vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+      return TRUE;
+    }
+  }
+
   /* these aren't the droids you're looking for */
   vtl->current_wp    = NULL;
   vtl->current_wp_id = NULL;
@@ -5780,7 +6988,7 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
-  if ( !vtl->tracks_visible && !vtl->waypoints_visible )
+  if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
     return FALSE;
 
   /* Post menu for the currently selected item */
@@ -5800,16 +7008,24 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
       udataU.trk  = track;
       udataU.uuid = NULL;
 
-      gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+      gpointer *trkf;
+      if ( track->is_route )
+        trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+      else
+        trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
 
       if ( trkf && udataU.uuid ) {
 
-        GtkTreeIter *iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
+        GtkTreeIter *iter;
+        if ( track->is_route )
+          iter = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
+        else
+          iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
 
         trw_layer_sublayer_add_menu_items ( vtl,
                                             vtl->track_right_click_menu,
                                             NULL,
-                                            VIK_TRW_LAYER_SUBLAYER_TRACK,
+                                            track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK,
                                             udataU.uuid,
                                             iter,
                                             vvp );
@@ -5955,10 +7171,10 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
   if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
   {
-    /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
+    // how do we get here?
     marker_begin_move(t, event->x, event->y);
     g_critical("shouldn't be here");
-    exit(1);
+    return FALSE;
   }
   else if ( params.closest_wp )
   {
@@ -6073,18 +7289,6 @@ 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)
@@ -6120,7 +7324,7 @@ static gboolean draw_sync ( gpointer data )
   return FALSE;
 }
 
-static const gchar* distance_string (gdouble distance)
+static gchar* distance_string (gdouble distance)
 {
   gchar str[128];
 
@@ -6183,11 +7387,11 @@ static void update_statusbar ( VikTrwLayer *vtl )
 
   /* Find out actual distance of current track */
   gdouble distance = vik_track_get_length (vtl->current_track);
-  const gchar *str = distance_string (distance);
+  gchar *str = distance_string (distance);
 
   statusbar_write (str, elev_gain, elev_loss, vtl);
 
-  g_free ((gpointer)str);
+  g_free (str);
 }
 
 
@@ -6196,6 +7400,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
   /* if we haven't sync'ed yet, we don't have time to do more. */
   if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
     GList *iter = g_list_last ( vtl->current_track->trackpoints );
+    VikTrackpoint *last_tpt = VIK_TRACKPOINT(iter->data);
 
     static GdkPixmap *pixmap = NULL;
     int w1, h1, w2, h2;
@@ -6220,7 +7425,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
     draw_sync_t *passalong;
     gint x1, y1;
 
-    vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
+    vik_viewport_coord_to_screen ( vvp, &(last_tpt->coord), &x1, &y1 );
 
     // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method)
     //  otherwise using vik_viewport_draw_* functions puts the data into the base pixmap,
@@ -6238,7 +7443,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
     struct LatLon ll;
     vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
     vik_coord_to_latlon ( &coord, &ll );
-    distance = distance + vik_coord_diff( &coord, &(VIK_TRACKPOINT(iter->data)->coord));
+    distance = distance + vik_coord_diff( &coord, &(last_tpt->coord));
 
     // Get elevation data
     gdouble elev_gain, elev_loss;
@@ -6248,18 +7453,18 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
     gdouble elev_new;
     elev_new = (gdouble) a_dems_get_elev_by_coord ( &coord, VIK_DEM_INTERPOL_BEST );
     if ( elev_new != VIK_DEM_INVALID_ELEVATION ) {
-      if ( VIK_TRACKPOINT(iter->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
+      if ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) {
        // Adjust elevation of last track point
-       if ( elev_new > VIK_TRACKPOINT(iter->data)->altitude )
+       if ( elev_new > last_tpt->altitude )
          // Going up
-         elev_gain += elev_new - VIK_TRACKPOINT(iter->data)->altitude;
+         elev_gain += elev_new - last_tpt->altitude;
        else
          // Going down
-         elev_loss += VIK_TRACKPOINT(iter->data)->altitude - elev_new;
+         elev_loss += last_tpt->altitude - elev_new;
       }
     }
       
-    const gchar *str = distance_string (distance);
+    gchar *str = distance_string (distance);
 
     PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
     pango_layout_set_font_description (pl, GTK_WIDGET(vvp)->style->font_desc);
@@ -6290,7 +7495,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
     // Update statusbar with full gain/loss information
     statusbar_write (str, elev_gain, elev_loss, vtl);
 
-    g_free ((gpointer)str);
+    g_free (str);
 
     // draw pixmap when we have time to
     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
@@ -6323,7 +7528,13 @@ static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event,
   return FALSE;
 }
 
-static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+/*
+ * Common function to handle trackpoint button requests on either a route or a track
+ *  . enables adding a point via normal click
+ *  . enables removal of last point via right click
+ *  . finishing of the track or route via double clicking
+ */
+static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   VikTrackpoint *tp;
 
@@ -6337,8 +7548,10 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
     return FALSE;
   }
 
-  if ( event->button == 3 && vtl->current_track )
+  if ( event->button == 3 )
   {
+    if ( !vtl->current_track )
+      return FALSE;
     /* undo */
     if ( vtl->current_track->trackpoints )
     {
@@ -6367,21 +7580,6 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
     return TRUE;
   }
 
-  if ( ! vtl->current_track )
-  {
-    gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
-    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name ) ) )
-    {
-      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;
-  }
   tp = vik_trackpoint_new();
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
 
@@ -6396,9 +7594,12 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   tp->newsegment = FALSE;
   tp->has_timestamp = FALSE;
   tp->timestamp = 0;
-  vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
-  /* Auto attempt to get elevation from DEM data (if it's available) */
-  vik_track_apply_dem_data_last_trackpoint ( vtl->current_track );
+
+  if ( vtl->current_track ) {
+    vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
+    /* Auto attempt to get elevation from DEM data (if it's available) */
+    vik_track_apply_dem_data_last_trackpoint ( vtl->current_track );
+  }
 
   vtl->ct_x1 = vtl->ct_x2;
   vtl->ct_y1 = vtl->ct_y2;
@@ -6409,6 +7610,24 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   return TRUE;
 }
 
+static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  // ----------------------------------------------------- if current is a route - switch to new track
+  if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
+  {
+    gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
+    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name, FALSE ) ) )
+    {
+      vtl->current_track = vik_track_new();
+      vtl->current_track->visible = TRUE;
+      vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+    }
+    else
+      return TRUE;
+  }
+  return tool_new_track_or_route_click ( vtl, event, vvp );
+}
+
 static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   if ( event->button == 2 ) {
@@ -6418,6 +7637,32 @@ static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, Vi
   }
 }
 
+/*** New route ****/
+
+static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  // -------------------------- if current is a track - switch to new route
+  if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
+  {
+    gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
+    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->routes, name, TRUE ) ) )
+    {
+      vtl->current_track = vik_track_new();
+      vtl->current_track->visible = TRUE;
+      vtl->current_track->is_route = TRUE;
+      vik_trw_layer_add_route ( vtl, name, vtl->current_track );
+    }
+    else
+      return TRUE;
+  }
+  return tool_new_track_or_route_click ( vtl, event, vvp );
+}
+
 /*** New waypoint ****/
 
 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
@@ -6471,7 +7716,7 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
-  if ( !vtl->vl.visible || !vtl->tracks_visible )
+  if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible )
     return FALSE;
 
   if ( vtl->current_tpl )
@@ -6494,7 +7739,8 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
 
   }
 
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
+  if ( vtl->tracks_visible )
+    g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
 
   if ( params.closest_tp )
   {
@@ -6508,6 +7754,21 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
     return TRUE;
   }
 
+  if ( vtl->routes_visible )
+    g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &params);
+
+  if ( params.closest_tp )
+  {
+    vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, params.closest_track_id ), TRUE );
+    vtl->current_tpl = params.closest_tpl;
+    vtl->current_tp_id = params.closest_track_id;
+    vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, params.closest_track_id );
+    trw_layer_tpwin_init ( vtl );
+    set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+    return TRUE;
+  }
+
   /* these aren't the droids you're looking for */
   return FALSE;
 }
@@ -6581,7 +7842,7 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton
 }
 
 
-#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+#ifdef VIK_CONFIG_GOOGLE
 /*** Route Finder ***/
 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
 {
@@ -6634,7 +7895,7 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even
                           g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon),
                           g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat),
                           g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon));
-    a_babel_convert_from_url ( vtl, url, "kml", NULL, NULL );
+    a_babel_convert_from_url ( vtl, url, "google", NULL, NULL );
     g_free ( url );
 
     /* see if anything was done -- a track was added or appended to */
@@ -6812,7 +8073,8 @@ VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
 gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
 {
   if ( vtl && vlp ) {
-    vik_trw_layer_uniquify_tracks ( vtl, vlp );
+    vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->tracks, TRUE );
+    vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->routes, FALSE );
     vik_trw_layer_uniquify_waypoints ( vtl, vlp );
     return TRUE;
   }
@@ -7013,7 +8275,14 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
 
   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] );
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  if ( !trk )
+    return;
+
   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, TRUE); // Includes hidden map layer types
@@ -7065,7 +8334,7 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
   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]);
+  vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
 
 done:
   for (i = 0; i < num_maps; i++)