]> 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 d51423998e1720dbdf3f62334a716f311b6d4e4c..4402f96995c9298bcd33a327f556b6febfb6e39f 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
  * Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
  * Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
  * Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
+ * Copyright (c) 2012, Rob Norris <rw_norris@hotmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-
-#define WAYPOINT_FONT "Sans 8"
-
 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
-/* viktrwlayer.c -- 2200 lines can make a difference in the state of things */
+/* viktrwlayer.c -- 8000+ lines can make a difference in the state of things */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 
 #include "viking.h"
 #include "vikmapslayer.h"
 
 #include "viking.h"
 #include "vikmapslayer.h"
+#include "vikgpslayer.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
+#ifdef VIK_CONFIG_GEOTAG
+#include "viktrwlayer_geotag.h"
+#include "geotag_exif.h"
+#endif
 #include "garminsymbols.h"
 #include "thumbnails.h"
 #include "background.h"
 #include "garminsymbols.h"
 #include "thumbnails.h"
 #include "background.h"
@@ -47,6 +50,8 @@
 #include "osm-traces.h"
 #endif
 #include "acquire.h"
 #include "osm-traces.h"
 #endif
 #include "acquire.h"
+#include "datasources.h"
+#include "datasource_gps.h"
 #include "util.h"
 
 #include "icons/icons.h"
 #include "util.h"
 
 #include "icons/icons.h"
 #include <glib/gstdio.h>
 #include <glib/gi18n.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 ); }
+#ifdef VIK_CONFIG_GOOGLE
+#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js"
 #endif
 
 #endif
 
-#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml"
-#define VIK_TRW_LAYER_TRACK_GC 13
+#define VIK_TRW_LAYER_TRACK_GC 16
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
 #define VIK_TRW_LAYER_TRACK_GC_MAX 11
 #define VIK_TRW_LAYER_TRACK_GC_BLACK 12
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
 #define VIK_TRW_LAYER_TRACK_GC_MAX 11
 #define VIK_TRW_LAYER_TRACK_GC_BLACK 12
+#define VIK_TRW_LAYER_TRACK_GC_SLOW 13
+#define VIK_TRW_LAYER_TRACK_GC_AVER 14
+#define VIK_TRW_LAYER_TRACK_GC_FAST 15
 
 #define DRAWMODE_BY_TRACK 0
 
 #define DRAWMODE_BY_TRACK 0
-#define DRAWMODE_BY_VELOCITY 1
+#define DRAWMODE_BY_SPEED 1
 #define DRAWMODE_ALL_BLACK 2
 #define DRAWMODE_ALL_BLACK 2
+// Note using DRAWMODE_BY_SPEED may be slow especially for vast numbers of trackpoints
+//  as we are (re)calculating the colour for every point
 
 #define POINTS 1
 #define LINES 2
 
 #define POINTS 1
 #define LINES 2
@@ -96,78 +103,89 @@ static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove (
 #define MAX_STOP_LENGTH 86400
 #define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
                                  /* this is multiplied by user-inputted value from 1-100. */
 #define MAX_STOP_LENGTH 86400
 #define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
                                  /* this is multiplied by user-inputted value from 1-100. */
-enum {
-VIK_TRW_LAYER_SUBLAYER_TRACKS,
-VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
-VIK_TRW_LAYER_SUBLAYER_TRACK,
-VIK_TRW_LAYER_SUBLAYER_WAYPOINT
-};
 
 enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
 
 
 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;
 struct _VikTrwLayer {
   VikLayer vl;
   GHashTable *tracks;
   GHashTable *tracks_iters;
+  GHashTable *routes;
+  GHashTable *routes_iters;
   GHashTable *waypoints_iters;
   GHashTable *waypoints;
   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 drawmode;
   guint8 drawpoints;
+  guint8 drawpoints_size;
   guint8 drawelevation;
   guint8 elevation_factor;
   guint8 drawstops;
   guint32 stop_length;
   guint8 drawlines;
   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;
   guint8 line_thickness;
   guint8 bg_line_thickness;
 
   guint8 wp_symbol;
   guint8 wp_size;
   gboolean wp_draw_symbols;
+  font_size_t wp_font_size;
 
 
-  gdouble velocity_min, velocity_max;
+  gdouble track_draw_speed_factor;
   GArray *track_gc;
   GArray *track_gc;
-  guint16 track_gc_iter;
   GdkGC *current_track_gc;
   GdkGC *current_track_gc;
+  // Separate GC for a track's potential new point as drawn via separate method
+  //  (compared to the actual track points drawn in the main trw_layer_draw_track function)
+  GdkGC *current_track_newpoint_gc;
   GdkGC *track_bg_gc;
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
   GdkGC *waypoint_bg_gc;
   GdkFont *waypoint_font;
   GdkGC *track_bg_gc;
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
   GdkGC *waypoint_bg_gc;
   GdkFont *waypoint_font;
-  VikTrack *current_track;
+  VikTrack *current_track; // ATM shared between new tracks and new routes
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
-  gboolean ct_sync_done;
-
+  gboolean draw_sync_done;
+  gboolean draw_sync_do;
 
   VikCoordMode coord_mode;
 
   /* wp editing tool */
   VikWaypoint *current_wp;
 
   VikCoordMode coord_mode;
 
   /* wp editing tool */
   VikWaypoint *current_wp;
-  gchar *current_wp_name;
+  gpointer current_wp_id;
   gboolean moving_wp;
   gboolean waypoint_rightclick;
 
   /* track editing tool */
   GList *current_tpl;
   gboolean moving_wp;
   gboolean waypoint_rightclick;
 
   /* track editing tool */
   GList *current_tpl;
-  gchar *current_tp_track_name;
+  VikTrack *current_tp_track;
+  gpointer current_tp_id;
   VikTrwLayerTpwin *tpwin;
 
   VikTrwLayerTpwin *tpwin;
 
-  /* weird hack for joining tracks */
-  GList *last_tpl;
-  gchar *last_tp_track_name;
-
   /* track editing tool -- more specifically, moving tps */
   gboolean moving_tp;
 
   /* track editing tool -- more specifically, moving tps */
   gboolean moving_tp;
 
-  /* magic scissors tool */
-  gboolean magic_scissors_started;
-  VikCoord magic_scissors_coord;
-  gboolean magic_scissors_check_added_track;
-  gchar *magic_scissors_added_track_name;
-  VikTrack *magic_scissors_current_track;
-  gboolean magic_scissors_append;
+  /* route finder tool */
+  gboolean route_finder_started;
+  VikCoord route_finder_coord;
+  gboolean route_finder_check_added_track;
+  VikTrack *route_finder_added_track;
+  VikTrack *route_finder_current_track;
+  gboolean route_finder_append;
 
   gboolean drawlabels;
   gboolean drawimages;
 
   gboolean drawlabels;
   gboolean drawimages;
@@ -182,6 +200,7 @@ struct _VikTrwLayer {
   gboolean has_verified_thumbnails;
 
   GtkMenu *wp_right_click_menu;
   gboolean has_verified_thumbnails;
 
   GtkMenu *wp_right_click_menu;
+  GtkMenu *track_right_click_menu;
 
   /* menu */
   VikStdLayerMenuItem menu_selection;
 
   /* menu */
   VikStdLayerMenuItem menu_selection;
@@ -200,80 +219,107 @@ struct DrawingParams {
   VikTrwLayer *vtl;
   gdouble xmpp, ympp;
   guint16 width, height;
   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;
   gdouble ce1, ce2, cn1, cn2;
 };
 
   const VikCoord *center;
   gint track_gc_iter;
   gboolean one_zone, lat_lon;
   gdouble ce1, ce2, cn1, cn2;
 };
 
-static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16);
-static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl);
+static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
 
 
-static void trw_layer_delete_item ( gpointer *pass_along );
-static void trw_layer_copy_item_cb( gpointer *pass_along);
-static void trw_layer_cut_item_cb( gpointer *pass_along);
+static void trw_layer_delete_item ( gpointer pass_along[6] );
+static void trw_layer_copy_item_cb ( gpointer pass_along[6] );
+static void trw_layer_cut_item_cb ( gpointer pass_along[6] );
 
 static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] );
 
 static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] );
-static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] );    
+static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *trk, struct LatLon maxmin[2] );
 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
 
 static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
 
 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
 
 static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
 
-static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 );
 static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp );
 static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp );
 
 static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp );
 static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp );
 
-static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
-static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
-
-static void goto_coord ( VikLayersPanel *vlp, const VikCoord *coord );
-static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] );
+static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
+static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] );
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
-static void trw_layer_goto_track_max_speed ( gpointer pass_along[5] );
-static void trw_layer_goto_track_max_alt ( gpointer pass_along[5] );
-static void trw_layer_goto_track_min_alt ( gpointer pass_along[5] );
-static void trw_layer_auto_track_view ( gpointer pass_along[5] );
+static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] );
+static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
+static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
+static void trw_layer_goto_track_center ( gpointer pass_along[6] );
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] );
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
+static void trw_layer_merge_with_other ( gpointer pass_along[6] );
+static void trw_layer_append_track ( gpointer pass_along[6] );
 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
-static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]);
+static void trw_layer_split_by_n_points ( gpointer pass_along[6] );
+static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] );
+static void trw_layer_split_segments ( gpointer pass_along[6] );
+static void trw_layer_delete_points_same_position ( gpointer pass_along[6] );
+static void trw_layer_delete_points_same_time ( gpointer pass_along[6] );
+static void trw_layer_reverse ( gpointer pass_along[6] );
+static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] );
+static void trw_layer_edit_trackpoint ( gpointer pass_along[6] );
+static void trw_layer_show_picture ( gpointer pass_along[6] );
+static void trw_layer_gps_upload_any ( gpointer pass_along[6] );
+
 static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
 static void trw_layer_auto_view ( gpointer layer_and_vlp[2] );
 static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
 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, const gchar* trackname, guint file_type );
+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_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_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] );
+static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] );
+static void trw_layer_delete_all_waypoints ( gpointer lav[2] );
+static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] );
 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] );
 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] );
 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] );
 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] );
-static void trw_layer_merge_with_other ( gpointer pass_along[6] );
-
-/* pop-up items */
-static void trw_layer_properties_item ( gpointer pass_along[5] );
-static void trw_layer_goto_waypoint ( gpointer pass_along[5] );
-static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] );
-
-static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[4] );
-static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] );
-static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
-
-
-static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len );
-static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
+#ifdef VIK_CONFIG_GEOTAG
+static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] );
+static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] );
+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
+static void trw_layer_acquire_google_cb ( gpointer lav[2] );
+#endif
+#ifdef VIK_CONFIG_OPENSTREETMAP
+static void trw_layer_acquire_osm_cb ( gpointer lav[2] );
+#endif
+#ifdef VIK_CONFIG_GEOCACHES
+static void trw_layer_acquire_geocache_cb ( gpointer lav[2] );
+#endif
+#ifdef VIK_CONFIG_GEOTAG
+static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] );
+#endif
+static void trw_layer_acquire_file_cb ( gpointer lav[2] );
+static void trw_layer_gps_upload ( gpointer lav[2] );
 
 
-static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
-static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
+// 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] );
 
 
-static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
-static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
+/* pop-up items */
+static void trw_layer_properties_item ( gpointer pass_along[7] );
+static void trw_layer_goto_waypoint ( gpointer pass_along[6] );
+static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] );
 
 
-static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
-static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
-static void trw_layer_free_copied_item ( gint subtype, gpointer item );
-static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
+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, VikTrwLayer *vtl, VikViewport *vp );
 
 static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
 
 static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl );
 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
 static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
 static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
@@ -288,29 +334,27 @@ 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 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 ); 
 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 ); 
+static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 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 );
 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 );
-static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp);
-static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-
+#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
 
 static void cached_pixbuf_free ( CachedPixbuf *cp );
 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
 
 static void cached_pixbuf_free ( CachedPixbuf *cp );
 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
-static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp );
 
 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
 
 
 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
 
-static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
-
-static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name);
-static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode );
+static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode );
 static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode );
 
 static gchar *highest_wp_number_get(VikTrwLayer *vtl);
 static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode );
 
 static gchar *highest_wp_number_get(VikTrwLayer *vtl);
@@ -318,80 +362,134 @@ static void highest_wp_number_reset(VikTrwLayer *vtl);
 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
 
 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
 
-
+// Note for the following tool GtkRadioActionEntry texts:
+//  the very first text value is an internal name not displayed anywhere
+//  the first N_ text value is the name used for menu entries - hence has an underscore for the keyboard accelerator
+//    * remember not to clash with the values used for VikWindow level tools (Pan, Zoom, Ruler + Select)
+//  the second N_ text value is used for the button tooltip (i.e. generally don't want an underscore here)
+//  the value is always set to 0 and the tool loader in VikWindow will set the actual appropriate value used
 static VikToolInterface trw_layer_tools[] = {
 static VikToolInterface trw_layer_tools[] = {
-  { N_("Create Waypoint"), (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
-
-  { N_("Create Track"),    (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_new_track_click, (VikToolMouseMoveFunc) tool_new_track_move, NULL,
-    (VikToolKeyFunc) tool_new_track_key_press, GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
-
-  { N_("Begin Track"),    (VikToolConstructorFunc) tool_begin_track_create,       NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_begin_track_click,       NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
-
-  { N_("Edit Waypoint"),   (VikToolConstructorFunc) tool_edit_waypoint_create,   NULL, NULL, NULL, 
+  { { "CreateWaypoint", "vik-icon-Create Waypoint", N_("Create _Waypoint"), "<control><shift>W", N_("Create Waypoint"), 0 },
+    (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
+
+  { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
+    (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_new_track_click,
+    (VikToolMouseMoveFunc) tool_new_track_move,
+    (VikToolMouseFunc) tool_new_track_release,
+    (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_addtr_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,
     (VikToolMouseFunc) tool_edit_waypoint_click,   
     (VikToolMouseMoveFunc) tool_edit_waypoint_move,
     (VikToolMouseFunc) tool_edit_waypoint_click,   
     (VikToolMouseMoveFunc) tool_edit_waypoint_move,
-    (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
+    (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
 
 
-  { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, 
+  { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
+    (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
     (VikToolMouseFunc) tool_edit_trackpoint_click,
     (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
     (VikToolMouseFunc) tool_edit_trackpoint_click,
     (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
-    (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
-
-  { N_("Show Picture"),    (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL, 
-    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
-
-  { N_("Magic Scissors"),  (VikToolConstructorFunc) tool_magic_scissors_create,  NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_iscissors_pixbuf },
+    (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
+
+  { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
+    (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
+
+#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,
+    FALSE,
+    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 ******/
 
 static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
 enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
 
 
 /****** PARAMETERS ******/
 
 static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
 enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
 
-static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 };
+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 };
 
 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 */
  {  1,   10,    1,   0 }, /* line_thickness */
 
 static VikLayerParamScale params_scales[] = {
  /* min  max    step digits */
  {  1,   10,    1,   0 }, /* line_thickness */
- {  0.0, 99.0,  1,   2 }, /* velocity_min */
- {  1.0, 100.0, 1.0, 2 }, /* velocity_max */
+ {  0,   100,   1,   0 }, /* track draw speed factor */
+ {  1.0, 100.0, 1.0, 2 }, /* UNUSED */
                 /* 5 * step == how much to turn */
                 /* 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,  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 },
 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 },
 
   { "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 },
   { "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 },
 
   { "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 },
   { "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 },
-  { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Min Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
-  { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Max Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 },
+  { "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 },
 
   { "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 },
   { "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 },
@@ -406,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 },
 };
 
   { "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_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS };
+// 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
 
 /*** TO ADD A PARAM:
  *** 1) Add to trw_layer_params and enumeration
@@ -415,8 +550,42 @@ enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PAR
 
 /****** END PARAMETERS ******/
 
 
 /****** END PARAMETERS ******/
 
+static VikTrwLayer* trw_layer_new ( gint drawmode );
+/* Layer Interface function definitions */
+static VikTrwLayer* trw_layer_create ( VikViewport *vp );
+static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter );
+static void trw_layer_free ( VikTrwLayer *trwlayer );
+static void trw_layer_draw ( VikTrwLayer *l, gpointer data );
+static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
+static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 );
+static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl );
+static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp );
+static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp );
+static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter );
+static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer );
+static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
+static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
+static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp );
+static void trw_layer_marshall ( VikTrwLayer *vtl, guint8 **data, gint *len );
+static VikTrwLayer *trw_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp );
+static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
+static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
+static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
+static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
+static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
+static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
+static void trw_layer_free_copied_item ( gint subtype, gpointer item );
+static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
+static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+/* End Layer Interface function definitions */
+
 VikLayerInterface vik_trw_layer_interface = {
   "TrackWaypoint",
 VikLayerInterface vik_trw_layer_interface = {
   "TrackWaypoint",
+  N_("TrackWaypoint"),
+  "<control><shift>Y",
   &viktrwlayer_pixbuf,
 
   trw_layer_tools,
   &viktrwlayer_pixbuf,
 
   trw_layer_tools,
@@ -429,25 +598,26 @@ VikLayerInterface vik_trw_layer_interface = {
 
   VIK_MENU_ITEM_ALL,
 
 
   VIK_MENU_ITEM_ALL,
 
-  (VikLayerFuncCreate)                  vik_trw_layer_create,
-  (VikLayerFuncRealize)                 vik_trw_layer_realize,
+  (VikLayerFuncCreate)                  trw_layer_create,
+  (VikLayerFuncRealize)                 trw_layer_realize,
   (VikLayerFuncPostRead)                trw_layer_verify_thumbnails,
   (VikLayerFuncPostRead)                trw_layer_verify_thumbnails,
-  (VikLayerFuncFree)                    vik_trw_layer_free,
+  (VikLayerFuncFree)                    trw_layer_free,
 
   (VikLayerFuncProperties)              NULL,
 
   (VikLayerFuncProperties)              NULL,
-  (VikLayerFuncDraw)                    vik_trw_layer_draw,
+  (VikLayerFuncDraw)                    trw_layer_draw,
   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
 
   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
 
-  (VikLayerFuncSetMenuItemsSelection)   vik_trw_layer_set_menu_selection,
-  (VikLayerFuncGetMenuItemsSelection)   vik_trw_layer_get_menu_selection,
+  (VikLayerFuncSetMenuItemsSelection)   trw_layer_set_menu_selection,
+  (VikLayerFuncGetMenuItemsSelection)   trw_layer_get_menu_selection,
 
 
-  (VikLayerFuncAddMenuItems)            vik_trw_layer_add_menu_items,
-  (VikLayerFuncSublayerAddMenuItems)    vik_trw_layer_sublayer_add_menu_items,
+  (VikLayerFuncAddMenuItems)            trw_layer_add_menu_items,
+  (VikLayerFuncSublayerAddMenuItems)    trw_layer_sublayer_add_menu_items,
 
 
-  (VikLayerFuncSublayerRenameRequest)   vik_trw_layer_sublayer_rename_request,
-  (VikLayerFuncSublayerToggleVisible)   vik_trw_layer_sublayer_toggle_visible,
+  (VikLayerFuncSublayerRenameRequest)   trw_layer_sublayer_rename_request,
+  (VikLayerFuncSublayerToggleVisible)   trw_layer_sublayer_toggle_visible,
   (VikLayerFuncSublayerTooltip)         trw_layer_sublayer_tooltip,
   (VikLayerFuncLayerTooltip)            trw_layer_layer_tooltip,
   (VikLayerFuncSublayerTooltip)         trw_layer_sublayer_tooltip,
   (VikLayerFuncLayerTooltip)            trw_layer_layer_tooltip,
+  (VikLayerFuncLayerSelected)           trw_layer_selected,
 
   (VikLayerFuncMarshall)                trw_layer_marshall,
   (VikLayerFuncUnmarshall)              trw_layer_unmarshall,
 
   (VikLayerFuncMarshall)                trw_layer_marshall,
   (VikLayerFuncUnmarshall)              trw_layer_unmarshall,
@@ -465,14 +635,17 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncFreeCopiedItem)          trw_layer_free_copied_item,
   
   (VikLayerFuncDragDropRequest)         trw_layer_drag_drop_request,
   (VikLayerFuncFreeCopiedItem)          trw_layer_free_copied_item,
   
   (VikLayerFuncDragDropRequest)         trw_layer_drag_drop_request,
+
+  (VikLayerFuncSelectClick)             trw_layer_select_click,
+  (VikLayerFuncSelectMove)              trw_layer_select_move,
+  (VikLayerFuncSelectRelease)           trw_layer_select_release,
+  (VikLayerFuncSelectedViewportMenu)    trw_layer_show_selected_viewport_menu,
 };
 
 };
 
-/* for copy & paste (I think?) */
+// for copy & paste
 typedef struct {
   guint len;
   guint8 data[0];
 typedef struct {
   guint len;
   guint8 data[0];
-  //  gchar *name;
-  //  VikWaypoint *wp;
 } FlatItem;
 
 GType vik_trw_layer_get_type ()
 } FlatItem;
 
 GType vik_trw_layer_get_type ()
@@ -501,7 +674,7 @@ GType vik_trw_layer_get_type ()
 
 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
 
 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
-  static gpointer pass_along[5];
+  static gpointer pass_along[6];
   if (!sublayer) {
     return;
   }
   if (!sublayer) {
     return;
   }
@@ -510,14 +683,15 @@ static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublay
   pass_along[1] = NULL;
   pass_along[2] = GINT_TO_POINTER (subtype);
   pass_along[3] = sublayer;
   pass_along[1] = NULL;
   pass_along[2] = GINT_TO_POINTER (subtype);
   pass_along[3] = sublayer;
-  pass_along[4] = NULL;
+  pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
+  pass_along[5] = NULL;
 
   trw_layer_delete_item ( pass_along );
 }
 
 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
 
   trw_layer_delete_item ( pass_along );
 }
 
 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
-  static gpointer pass_along[5];
+  static gpointer pass_along[6];
   if (!sublayer) {
     return;
   }
   if (!sublayer) {
     return;
   }
@@ -526,13 +700,14 @@ static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublay
   pass_along[1] = NULL;
   pass_along[2] = GINT_TO_POINTER (subtype);
   pass_along[3] = sublayer;
   pass_along[1] = NULL;
   pass_along[2] = GINT_TO_POINTER (subtype);
   pass_along[3] = sublayer;
-  pass_along[4] = NULL;
+  pass_along[4] = GINT_TO_POINTER (0); // No delete confirmation needed for auto delete
+  pass_along[5] = NULL;
 
   trw_layer_copy_item_cb(pass_along);
   trw_layer_cut_item_cb(pass_along);
 }
 
 
   trw_layer_copy_item_cb(pass_along);
   trw_layer_cut_item_cb(pass_along);
 }
 
-static void trw_layer_copy_item_cb( gpointer pass_along[5])
+static void trw_layer_copy_item_cb ( gpointer pass_along[6])
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gint subtype = GPOINTER_TO_INT (pass_along[2]);
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gint subtype = GPOINTER_TO_INT (pass_along[2]);
@@ -543,17 +718,47 @@ static void trw_layer_copy_item_cb( gpointer pass_along[5])
   trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
 
   if (data) {
   trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
 
   if (data) {
+    const gchar* name;
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+      VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, sublayer);
+      if ( wp && wp->name )
+        name = wp->name;
+      else
+        name = NULL; // Broken :(
+    }
+    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,
     a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
-       subtype, len, data);
+                     subtype, len, name, data);
   }
 }
 
   }
 }
 
-static void trw_layer_cut_item_cb( gpointer pass_along[5])
+static void trw_layer_cut_item_cb ( gpointer pass_along[6])
 {
   trw_layer_copy_item_cb(pass_along);
 {
   trw_layer_copy_item_cb(pass_along);
+  pass_along[4] = GINT_TO_POINTER (0); // Never need to confirm automatic delete
   trw_layer_delete_item(pass_along);
 }
 
   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;
 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
 {
   FlatItem *fi;
@@ -568,15 +773,27 @@ static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer subla
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
     vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
     vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
-  } else {
+    // 'Simple' memory copy of byte array from the marshalling above
+    *len = sizeof(FlatItem) + 1 + il; // not sure what the 1 is for yet...
+    fi = g_malloc ( *len );
+    fi->len = *len;
+    memcpy(fi->data, id, il);
+  } else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
     vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
     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);
   }
 
   }
 
-  *len = sizeof(FlatItem) + strlen(sublayer) + 1 + il;
-  fi = g_malloc ( *len );
-  fi->len = strlen(sublayer) + 1;
-  memcpy(fi->data, sublayer, fi->len);
-  memcpy(fi->data + fi->len, id, il);
   g_free(id);
   *item = (guint8 *)fi;
 }
   g_free(id);
   *item = (guint8 *)fi;
 }
@@ -590,26 +807,47 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i
     VikWaypoint *w;
     gchar *name;
 
     VikWaypoint *w;
     gchar *name;
 
-    name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, (gchar *)fi->data);
-    w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
+    w = vik_waypoint_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_WAYPOINT, w->name);
     vik_trw_layer_add_waypoint ( vtl, name, w );
     vik_trw_layer_add_waypoint ( vtl, name, w );
-    waypoint_convert(name, w, &vtl->coord_mode);
+    waypoint_convert (NULL, w, &vtl->coord_mode);
+
     // Consider if redraw necessary for the new item
     if ( vtl->vl.visible && vtl->waypoints_visible && w->visible )
     // Consider if redraw necessary for the new item
     if ( vtl->vl.visible && vtl->waypoints_visible && w->visible )
-      vik_layer_emit_update ( VIK_LAYER(vtl) );
+      vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi )
   {
     VikTrack *t;
     gchar *name;
     return TRUE;
   }
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi )
   {
     VikTrack *t;
     gchar *name;
-    name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, (gchar *)fi->data);
-    t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
+
+    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_TRACK, t->name);
     vik_trw_layer_add_track ( vtl, name, t );
     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 )
     // Consider if redraw necessary for the new item
     if ( vtl->vl.visible && vtl->tracks_visible && t->visible )
-      vik_layer_emit_update ( VIK_LAYER(vtl) );
+      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;
     return TRUE;
   }
   return FALSE;
@@ -628,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_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_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_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;
     case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
                      vtl->stop_length = data.u;
                    break;
@@ -651,39 +899,8 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
                      trw_layer_new_track_gcs ( vtl, vp );
                    }
                    break;
                      trw_layer_new_track_gcs ( vtl, vp );
                    }
                    break;
-    case PARAM_VMIN:
-    {
-      /* Convert to store internally
-         NB file operation always in internal units (metres per second) */
-      vik_units_speed_t speed_units = a_vik_get_units_speed ();
-      if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
-       vtl->velocity_min = data.d;
-      else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
-       vtl->velocity_min = VIK_KPH_TO_MPS(data.d);
-      else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
-       vtl->velocity_min = VIK_MPH_TO_MPS(data.d);
-      else
-       /* Knots */
-       vtl->velocity_min = VIK_KNOTS_TO_MPS(data.d);
-      break;
-    }
-    case PARAM_VMAX:
-    {
-      /* Convert to store internally
-         NB file operation always in internal units (metres per second) */
-      vik_units_speed_t speed_units = a_vik_get_units_speed ();
-      if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
-       vtl->velocity_max = data.d;
-      else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
-       vtl->velocity_max = VIK_KPH_TO_MPS(data.d);
-      else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
-       vtl->velocity_max = VIK_MPH_TO_MPS(data.d);
-      else
-       /* Knots */
-       vtl->velocity_max = VIK_KNOTS_TO_MPS(data.d);
-      break;
-    }
     case PARAM_TBGC: gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(data.c)); break;
     case PARAM_TBGC: gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(data.c)); break;
+    case PARAM_TDSF: vtl->track_draw_speed_factor = data.d; break;
     case PARAM_DLA: vtl->drawlabels = data.b; break;
     case PARAM_DI: vtl->drawimages = data.b; break;
     case PARAM_IS: if ( data.u != vtl->image_size )
     case PARAM_DLA: vtl->drawlabels = data.b; break;
     case PARAM_DI: vtl->drawimages = data.b; break;
     case PARAM_IS: if ( data.u != vtl->image_size )
@@ -706,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_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;
 }
   }
   return TRUE;
 }
@@ -717,50 +935,23 @@ 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_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_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_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_LT: rv.u = vtl->line_thickness; break;
     case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
-    case PARAM_VMIN:
-    {
-      /* Convert to store internally
-         NB file operation always in internal units (metres per second) */
-      vik_units_speed_t speed_units = a_vik_get_units_speed ();
-      if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
-       rv.d = vtl->velocity_min;
-      else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
-       rv.d = VIK_MPS_TO_KPH(vtl->velocity_min);
-      else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
-       rv.d = VIK_MPS_TO_MPH(vtl->velocity_min);
-      else
-       /* Knots */
-       rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_min);
-      break;
-    }
-    case PARAM_VMAX:
-    {
-      /* Convert to store internally
-         NB file operation always in internal units (metres per second) */
-      vik_units_speed_t speed_units = a_vik_get_units_speed ();
-      if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
-       rv.d = vtl->velocity_max;
-      else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
-       rv.d = VIK_MPS_TO_KPH(vtl->velocity_max);
-      else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
-       rv.d = VIK_MPS_TO_MPH(vtl->velocity_max);
-      else
-       /* Knots */
-       rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_max);
-      break;
-    }
     case PARAM_DLA: rv.b = vtl->drawlabels; break;
     case PARAM_DI: rv.b = vtl->drawimages; break;
     case PARAM_TBGC: vik_gc_get_fg_color(vtl->track_bg_gc, &(rv.c)); break;
     case PARAM_DLA: rv.b = vtl->drawlabels; break;
     case PARAM_DI: rv.b = vtl->drawimages; break;
     case PARAM_TBGC: vik_gc_get_fg_color(vtl->track_bg_gc, &(rv.c)); break;
+    case PARAM_TDSF: rv.d = vtl->track_draw_speed_factor; break;
     case PARAM_IS: rv.u = vtl->image_size; break;
     case PARAM_IA: rv.u = vtl->image_alpha; break;
     case PARAM_ICS: rv.u = vtl->image_cache_size; break;
     case PARAM_IS: rv.u = vtl->image_size; break;
     case PARAM_IA: rv.u = vtl->image_alpha; break;
     case PARAM_ICS: rv.u = vtl->image_cache_size; break;
@@ -771,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_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;
 }
   }
   return rv;
 }
@@ -787,7 +979,7 @@ static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
   *data = NULL;
 
   if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
   *data = NULL;
 
   if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
-    a_gpx_write_file(vtl, f);
+    a_gpx_write_file(vtl, f, NULL);
     vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
     fclose(f);
     f = NULL;
     vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
     fclose(f);
     f = NULL;
@@ -832,26 +1024,14 @@ static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *v
   return rv;
 }
 
   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));
-}
-
-static gboolean strcase_equal(gconstpointer s1, gconstpointer s2)
-{
-  return (strcasecmp(s1, s2) == 0);
-}
-
+// Keep interesting hash function at least visible
+/*
 static guint strcase_hash(gconstpointer v)
 {
 static guint strcase_hash(gconstpointer v)
 {
-  /* 31 bit hash function */
+  // 31 bit hash function
   int i;
   const gchar *t = v;
   int i;
   const gchar *t = v;
-  gchar s[128];   /* malloc is too slow for reading big files */
+  gchar s[128];   // malloc is too slow for reading big files
   gchar *p = s;
 
   for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
   gchar *p = s;
 
   for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
@@ -867,8 +1047,9 @@ static guint strcase_hash(gconstpointer v)
 
   return h;  
 }
 
   return h;  
 }
+*/
 
 
-VikTrwLayer *vik_trw_layer_new ( gint drawmode )
+static VikTrwLayer* trw_layer_new ( gint drawmode )
 {
   if (trw_layer_params[PARAM_DM].widget_data == NULL)
     trw_layer_params[PARAM_DM].widget_data = str_array_to_glist(params_drawmodes);
 {
   if (trw_layer_params[PARAM_DM].widget_data == NULL)
     trw_layer_params[PARAM_DM].widget_data = str_array_to_glist(params_drawmodes);
@@ -876,17 +1057,33 @@ VikTrwLayer *vik_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 ) );
     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
 
 
-  rv->waypoints = g_hash_table_new_full ( strcase_hash, strcase_equal, g_free, (GDestroyNotify) vik_waypoint_free );
-  rv->tracks = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_track_free );
-  rv->tracks_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
-  rv->waypoints_iters = g_hash_table_new_full ( strcase_hash, strcase_equal, NULL, g_free );
+  // For this reworking I've choosen to keep the use of hash tables since for the expected data sizes
+  // - even many hundreds of waypoints and tracks is quite small in the grand scheme of things,
+  //  and with normal PC processing capabilities - it has negligibile performance impact
+  // This also minimized the amount of rework - as the management of the hash tables already exists.
+
+  // The hash tables are indexed by simple integers acting as a UUID hash, which again shouldn't affect performance much
+  //   we have to maintain a uniqueness (as before when multiple names where not allowed),
+  //   this is to ensure it refers to the same item in the data structures used on the viewport and on the layers panel
+
+  rv->waypoints = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_waypoint_free );
+  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 */
 
   /* 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->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;
   rv->drawstops = FALSE;
   rv->drawelevation = FALSE;
   rv->elevation_factor = 30;
@@ -894,33 +1091,32 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
   rv->drawlines = TRUE;
   rv->wplabellayout = NULL;
   rv->wp_right_click_menu = NULL;
   rv->drawlines = TRUE;
   rv->wplabellayout = NULL;
   rv->wp_right_click_menu = NULL;
+  rv->track_right_click_menu = NULL;
   rv->waypoint_gc = NULL;
   rv->waypoint_text_gc = NULL;
   rv->waypoint_bg_gc = NULL;
   rv->track_gc = NULL;
   rv->waypoint_gc = NULL;
   rv->waypoint_text_gc = NULL;
   rv->waypoint_bg_gc = NULL;
   rv->track_gc = NULL;
-  rv->velocity_max = 5.0;
-  rv->velocity_min = 0.0;
+  rv->track_draw_speed_factor = 30.0;
   rv->line_thickness = 1;
   rv->bg_line_thickness = 0;
   rv->current_wp = NULL;
   rv->line_thickness = 1;
   rv->bg_line_thickness = 0;
   rv->current_wp = NULL;
-  rv->current_wp_name = NULL;
+  rv->current_wp_id = NULL;
   rv->current_track = NULL;
   rv->current_tpl = NULL;
   rv->current_track = NULL;
   rv->current_tpl = NULL;
-  rv->current_tp_track_name = NULL;
+  rv->current_tp_track = NULL;
+  rv->current_tp_id = NULL;
   rv->moving_tp = FALSE;
   rv->moving_wp = FALSE;
 
   rv->moving_tp = FALSE;
   rv->moving_wp = FALSE;
 
-  rv->ct_sync_done = TRUE;
+  rv->draw_sync_done = TRUE;
+  rv->draw_sync_do = TRUE;
 
 
-  rv->magic_scissors_started = FALSE;
-  rv->magic_scissors_check_added_track = FALSE;
-  rv->magic_scissors_added_track_name = NULL;
-  rv->magic_scissors_current_track = NULL;
-  rv->magic_scissors_append = FALSE;
+  rv->route_finder_started = FALSE;
+  rv->route_finder_check_added_track = FALSE;
+  rv->route_finder_current_track = NULL;
+  rv->route_finder_append = FALSE;
 
   rv->waypoint_rightclick = FALSE;
 
   rv->waypoint_rightclick = FALSE;
-  rv->last_tpl = NULL;
-  rv->last_tp_track_name = NULL;
   rv->tpwin = NULL;
   rv->image_cache = g_queue_new();
   rv->image_size = 64;
   rv->tpwin = NULL;
   rv->image_cache = g_queue_new();
   rv->image_size = 64;
@@ -932,7 +1128,7 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
 }
 
 
 }
 
 
-void vik_trw_layer_free ( VikTrwLayer *trwlayer )
+static void trw_layer_free ( VikTrwLayer *trwlayer )
 {
   g_hash_table_destroy(trwlayer->waypoints);
   g_hash_table_destroy(trwlayer->tracks);
 {
   g_hash_table_destroy(trwlayer->waypoints);
   g_hash_table_destroy(trwlayer->tracks);
@@ -941,7 +1137,10 @@ void vik_trw_layer_free ( VikTrwLayer *trwlayer )
   trw_layer_free_track_gcs ( trwlayer );
 
   if ( trwlayer->wp_right_click_menu )
   trw_layer_free_track_gcs ( trwlayer );
 
   if ( trwlayer->wp_right_click_menu )
-    gtk_object_sink ( GTK_OBJECT(trwlayer->wp_right_click_menu) );
+    g_object_ref_sink ( G_OBJECT(trwlayer->wp_right_click_menu) );
+
+  if ( trwlayer->track_right_click_menu )
+    gtk_object_sink ( GTK_OBJECT(trwlayer->track_right_click_menu) );
 
   if ( trwlayer->wplabellayout != NULL)
     g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) );
 
   if ( trwlayer->wplabellayout != NULL)
     g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) );
@@ -955,9 +1154,6 @@ void vik_trw_layer_free ( VikTrwLayer *trwlayer )
   if ( trwlayer->waypoint_bg_gc != NULL )
     g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
 
   if ( trwlayer->waypoint_bg_gc != NULL )
     g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
 
-  if ( trwlayer->waypoint_font != NULL )
-    gdk_font_unref ( trwlayer->waypoint_font );
-
   if ( trwlayer->tpwin != NULL )
     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
 
   if ( trwlayer->tpwin != NULL )
     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
 
@@ -965,13 +1161,17 @@ void vik_trw_layer_free ( VikTrwLayer *trwlayer )
   g_queue_free ( trwlayer->image_cache );
 }
 
   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->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;
   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;
@@ -1002,30 +1202,31 @@ static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp )
   dp->track_gc_iter = 0;
 }
 
   dp->track_gc_iter = 0;
 }
 
-static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 )
-{
-  static gdouble rv = 0;
-  if ( tp1->has_timestamp && tp2->has_timestamp )
-  {
-    rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) )
-           / (tp1->timestamp - tp2->timestamp) ) - vtl->velocity_min;
-
-    if ( rv < 0 )
-      return VIK_TRW_LAYER_TRACK_GC_MIN;
-    else if ( vtl->velocity_min >= vtl->velocity_max )
-      return VIK_TRW_LAYER_TRACK_GC_MAX;
-
-    rv *= (VIK_TRW_LAYER_TRACK_GC_RATES / (vtl->velocity_max - vtl->velocity_min));
-
-    if ( rv >= VIK_TRW_LAYER_TRACK_GC_MAX )
-      return VIK_TRW_LAYER_TRACK_GC_MAX;
-    return (gint) rv;
- }
- else
-   return VIK_TRW_LAYER_TRACK_GC_BLACK;
+/*
+ * Determine the colour of the trackpoint (and/or trackline) relative to the average speed
+ * Here a simple traffic like light colour system is used:
+ *  . slow points are red
+ *  . average is yellow
+ *  . fast points are green
+ */
+static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2, gdouble average_speed, gdouble low_speed, gdouble high_speed )
+{
+  gdouble rv = 0;
+  if ( tp1->has_timestamp && tp2->has_timestamp ) {
+    if ( average_speed > 0 ) {
+      rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) ) / (tp1->timestamp - tp2->timestamp) );
+      if ( rv < low_speed )
+        return VIK_TRW_LAYER_TRACK_GC_SLOW;
+      else if ( rv > high_speed )
+        return VIK_TRW_LAYER_TRACK_GC_FAST;
+      else
+        return VIK_TRW_LAYER_TRACK_GC_AVER;
+    }
+  }
+  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 );
 {
   vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y );
   vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 );
@@ -1033,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 );
 }
 
   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;
 {
   /* TODO: this function is a mess, get rid of any redundancy */
   GList *list = track->trackpoints;
@@ -1045,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;
 
   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 )
   guint8 tp_size;
 
   if ( dp->vtl->drawelevation )
@@ -1060,23 +1261,47 @@ 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... */
     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 );
 
     trw_layer_draw_track ( name, track, dp, TRUE );
 
-  if ( drawing_white_background )
+  if ( draw_track_outline )
     drawpoints = drawstops = FALSE;
   else {
     drawpoints = dp->vtl->drawpoints;
     drawstops = dp->vtl->drawstops;
   }
 
     drawpoints = drawstops = FALSE;
   else {
     drawpoints = dp->vtl->drawpoints;
     drawstops = dp->vtl->drawstops;
   }
 
-  if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
-    dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK;
-
+  gboolean drawing_highlight = FALSE;
+  /* Current track - used for creation */
   if ( track == dp->vtl->current_track )
     main_gc = dp->vtl->current_track_gc;
   if ( track == dp->vtl->current_track )
     main_gc = dp->vtl->current_track_gc;
-  else
-    main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+  else {
+    if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
+      /* Draw all tracks of the layer in special colour */
+      /* if track is member of selected layer or is the current selected track
+        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) ) ) ||
+                       ( !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;
+      }
+      else {
+       if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
+         dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK;
+
+       main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+      }
+    }
+    else {
+      if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
+       dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK;
+         
+      main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+    }
+  }
 
   if (list) {
     int x, y, oldx, oldy;
 
   if (list) {
     int x, y, oldx, oldy;
@@ -1095,6 +1320,17 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     oldx = x;
     oldy = y;
 
     oldx = x;
     oldy = y;
 
+    gdouble average_speed = 0.0;
+    gdouble low_speed = 0.0;
+    gdouble high_speed = 0.0;
+    // If necessary calculate these values - which is done only once per track redraw
+    if ( dp->vtl->drawmode == DRAWMODE_BY_SPEED ) {
+      // the percentage factor away from the average speed determines transistions between the levels
+      average_speed = vik_track_get_average_speed_moving(track, dp->vtl->stop_length);
+      low_speed = average_speed - (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
+      high_speed = average_speed + (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
+    }
+
     while ((list = g_list_next(list)))
     {
       tp = VIK_TRACKPOINT(list->data);
     while ((list = g_list_next(list)))
     {
       tp = VIK_TRACKPOINT(list->data);
@@ -1108,66 +1344,111 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
       {
         vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
 
       {
         vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
 
-        if ( drawpoints && ! drawing_white_background )
+       /*
+        * If points are the same in display coordinates, don't draw.
+        */
+       if ( useoldvals && x == oldx && y == oldy )
+       {
+         // Still need to process points to ensure 'stops' are drawn if required
+         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 );
+
+         goto skip;
+       }
+
+        VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
+        if ( drawpoints || dp->vtl->drawlines ) {
+          // setup main_gc for both point and line drawing
+          if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
+            dp->track_gc_iter = track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed );
+            main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+          }
+        }
+
+        if ( drawpoints && ! draw_track_outline )
         {
         {
-          if ( list->next ) {
-            vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
 
 
+          if ( list->next ) {
+           /*
+            * The concept of drawing stops is that a trackpoint
+            * that is if the next trackpoint has a timestamp far into
+            * the future, we draw a circle of 6x trackpoint size,
+            * instead of a rectangle of 2x trackpoint size.
+            * This is drawn first so the trackpoint will be drawn on top
+            */
             /* stops */
             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
             /* stops */
             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
+             /* Stop point.  Draw 6x circle. */
               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 );
               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 );
+
+           /* Regular point - draw 2x square. */
+           vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
           }
           else
           }
           else
+           /* Final point - draw 4x circle. */
             vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
         }
 
         if ((!tp->newsegment) && (dp->vtl->drawlines))
         {
             vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
         }
 
         if ((!tp->newsegment) && (dp->vtl->drawlines))
         {
-          VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
 
           /* UTM only: zone check */
           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
             draw_utm_skip_insignia (  dp->vp, main_gc, x, y);
 
 
           /* UTM only: zone check */
           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
             draw_utm_skip_insignia (  dp->vp, main_gc, x, y);
 
-          if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
-            dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
-            main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
-          }
-
           if (!useoldvals)
             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
 
           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);
             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 && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
+
+            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)
               GdkPoint tmp[4];
               #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
-              if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
-                tmp[0].x = oldx;
-                tmp[0].y = oldy;
-                tmp[1].x = oldx;
-                tmp[1].y = oldy-FIXALTITUDE(list->data);
-                tmp[2].x = x;
-                tmp[2].y = y-FIXALTITUDE(list->next->data);
-                tmp[3].x = x;
-                tmp[3].y = y;
-
-                GdkGC *tmp_gc;
-                if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
-                  tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
-                else
-                  tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
-                vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
-              }
+
+             tmp[0].x = oldx;
+             tmp[0].y = oldy;
+             tmp[1].x = oldx;
+             tmp[1].y = oldy-FIXALTITUDE(list->data);
+             tmp[2].x = x;
+             tmp[2].y = y-FIXALTITUDE(list->next->data);
+             tmp[3].x = x;
+             tmp[3].y = y;
+
+             GdkGC *tmp_gc;
+             if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
+               tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
+             else
+               tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
+             vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
+
               vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
             }
           }
         }
 
               vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
             }
           }
         }
 
+        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;
         useoldvals = TRUE;
         oldx = x;
         oldy = y;
         useoldvals = TRUE;
@@ -1179,20 +1460,33 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
           {
             vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
           if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
           {
             vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
-            if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
-              dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
-              main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
-            }
 
 
-            if ( drawing_white_background )
-              vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
-            else
-              vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
+            if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
+              dp->track_gc_iter = track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed );
+              main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+           }
+
+           /*
+            * If points are the same in display coordinates, don't draw.
+            */
+           if ( x != oldx || y != oldy )
+             {
+               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);
+             }
           }
           else 
           {
           }
           else 
           {
-            vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
-            draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
+           /*
+            * If points are the same in display coordinates, don't draw.
+            */
+           if ( x != oldx && y != oldy )
+             {
+               vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
+               draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
+             }
           }
         }
         useoldvals = FALSE;
           }
         }
         useoldvals = FALSE;
@@ -1200,7 +1494,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     }
   }
   if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
     }
   }
   if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
-    if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC )
+    if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC_MAX )
       dp->track_gc_iter = 0;
 }
 
       dp->track_gc_iter = 0;
 }
 
@@ -1292,6 +1586,18 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct
 
         if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
         {
 
         if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
         {
+         if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
+           if ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
+                dp->vtl->waypoints == vik_window_get_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
+                wp == vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) {
+             // Highlighted - so draw a little border around the chosen one
+             // single line seems a little weak so draw 2 of them
+             vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
+                                          x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 );
+             vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
+                                          x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
+           }
+         }
           if ( dp->vtl->image_alpha == 255 )
             vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
           else
           if ( dp->vtl->image_alpha == 255 )
             vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
           else
@@ -1329,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;
       /* 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, 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)
       pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
       label_x = x - width/2;
       if (sym)
@@ -1337,23 +1667,36 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct
       else
         label_y = y - dp->vtl->wp_size - height - 2;
 
       else
         label_y = y - dp->vtl->wp_size - height - 2;
 
-      vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
+      /* if highlight mode on, then draw background text in highlight colour */
+      if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
+       if ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
+            dp->vtl->waypoints == vik_window_get_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
+            wp == vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) )
+         vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2);
+       else
+         vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
+      }
+      else {
+       vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
+      }
       vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout );
     }
   }
 }
 
       vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout );
     }
   }
 }
 
-void vik_trw_layer_draw ( VikTrwLayer *l, gpointer data )
+static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
 {
   static struct DrawingParams dp;
   g_assert ( l != NULL );
 
 {
   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->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 );
 }
   if (l->waypoints_visible)
     g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint, &dp );
 }
@@ -1371,6 +1714,11 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
     g_object_unref ( vtl->current_track_gc );
     vtl->current_track_gc = NULL;
   }
     g_object_unref ( vtl->current_track_gc );
     vtl->current_track_gc = NULL;
   }
+  if ( vtl->current_track_newpoint_gc )
+  {
+    g_object_unref ( vtl->current_track_newpoint_gc );
+    vtl->current_track_newpoint_gc = NULL;
+  }
 
   if ( ! vtl->track_gc )
     return;
 
   if ( ! vtl->track_gc )
     return;
@@ -1392,10 +1740,20 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
     g_object_unref ( vtl->track_bg_gc );
   vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
 
     g_object_unref ( vtl->track_bg_gc );
   vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
 
+  // Ensure new track drawing heeds line thickness setting
+  //  however always have a minium of 2, as 1 pixel is really narrow
+  gint new_track_width = (vtl->line_thickness < 2) ? 2 : vtl->line_thickness;
+  
   if ( vtl->current_track_gc )
     g_object_unref ( vtl->current_track_gc );
   if ( vtl->current_track_gc )
     g_object_unref ( vtl->current_track_gc );
-  vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
-  gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+  vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
+  gdk_gc_set_line_attributes ( vtl->current_track_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+
+  // 'newpoint' gc is exactly the same as the current track gc
+  if ( vtl->current_track_newpoint_gc )
+    g_object_unref ( vtl->current_track_newpoint_gc );
+  vtl->current_track_newpoint_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
+  gdk_gc_set_line_attributes ( vtl->current_track_newpoint_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
 
   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
 
 
   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
 
@@ -1412,25 +1770,30 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
   gc[9] = vik_viewport_new_gc ( vp, "#96059f", width );
   gc[10] = vik_viewport_new_gc ( vp, "#f22ef2", width );
 
   gc[9] = vik_viewport_new_gc ( vp, "#96059f", width );
   gc[10] = vik_viewport_new_gc ( vp, "#f22ef2", width );
 
-  gc[11] = vik_viewport_new_gc ( vp, "#ff0000", width ); /* above range */
+  gc[11] = vik_viewport_new_gc ( vp, "#874200", width ); /* above range */
 
   gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */
 
 
   gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */
 
+  gc[VIK_TRW_LAYER_TRACK_GC_SLOW] = vik_viewport_new_gc ( vp, "#E6202E", width ); // red-ish
+  gc[VIK_TRW_LAYER_TRACK_GC_AVER] = vik_viewport_new_gc ( vp, "#D2CD26", width ); // yellow-ish
+  gc[VIK_TRW_LAYER_TRACK_GC_FAST] = vik_viewport_new_gc ( vp, "#2B8700", width ); // green-ish
+
   g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
 }
 
   g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
 }
 
-VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
+static VikTrwLayer* trw_layer_create ( VikViewport *vp )
 {
 {
-  VikTrwLayer *rv = vik_trw_layer_new ( 0 );
-  PangoFontDescription *pfd;
-  rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
-  pfd = pango_font_description_from_string (WAYPOINT_FONT);
-  pango_layout_set_font_description (rv->wplabellayout, pfd);
-  /* freeing PangoFontDescription, cause it has been copied by prev. call */
-  pango_font_description_free (pfd);
-
+  VikTrwLayer *rv = trw_layer_new ( DRAWMODE_BY_TRACK );
   vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
 
   vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
 
+  if ( vp == NULL || GTK_WIDGET(vp)->window == NULL ) {
+    /* early exit, as the rest is GUI related */
+    return rv;
+  }
+
+  rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
+  pango_layout_set_font_description (rv->wplabellayout, GTK_WIDGET(vp)->style->font_desc);
+
   trw_layer_new_track_gcs ( rv, vp );
 
   rv->waypoint_gc = vik_viewport_new_gc ( vp, "#000000", 2 );
   trw_layer_new_track_gcs ( rv, vp );
 
   rv->waypoint_gc = vik_viewport_new_gc ( vp, "#000000", 2 );
@@ -1438,12 +1801,11 @@ VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
   rv->waypoint_bg_gc = vik_viewport_new_gc ( vp, "#8383C4", 1 );
   gdk_gc_set_function ( rv->waypoint_bg_gc, GDK_AND );
 
   rv->waypoint_bg_gc = vik_viewport_new_gc ( vp, "#8383C4", 1 );
   gdk_gc_set_function ( rv->waypoint_bg_gc, GDK_AND );
 
-  rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
-
   rv->has_verified_thumbnails = FALSE;
   rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
   rv->wp_size = 4;
   rv->wp_draw_symbols = TRUE;
   rv->has_verified_thumbnails = FALSE;
   rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
   rv->wp_size = 4;
   rv->wp_draw_symbols = TRUE;
+  rv->wp_font_size = FS_MEDIUM;
 
   rv->coord_mode = vik_viewport_get_coord_mode ( vp );
 
 
   rv->coord_mode = vik_viewport_get_coord_mode ( vp );
 
@@ -1452,77 +1814,128 @@ VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
   return rv;
 }
 
   return rv;
 }
 
-static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] )
+#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));
 
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
 {
   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], name, pass_along[2], name, 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], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
 #else
 #else
-  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
+  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
 #endif
 
   *new_iter = *((GtkTreeIter *) pass_along[1]);
 #endif
 
   *new_iter = *((GtkTreeIter *) pass_along[1]);
-  g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, name, 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 );
 }
 
 
   if ( ! track->visible )
     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
 }
 
-static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[4] )
+static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] )
 {
   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
 {
   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
+
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-  vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, 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
 #else
-  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, GPOINTER_TO_INT (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]);
 #endif
 
   *new_iter = *((GtkTreeIter *) pass_along[1]);
-  g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, name, new_iter );
+  g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter );
 
   if ( ! wp->visible )
     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
 }
 
 
   if ( ! wp->visible )
     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
 }
 
-
-void vik_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, (gpointer) 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
 #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
 #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 ( g_hash_table_size (vtl->routes) > 0 ) {
+
+    trw_layer_add_sublayer_routes ( vtl, vt, layer_iter );
+
+    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 );
 
 
-  if ( ! vtl->waypoints_visible )
-    vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), FALSE ); 
+    pass_along[0] = &(vtl->waypoints_iter);
+    pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
 
 
-  pass_along[0] = &(vtl->waypoints_iter);
-  pass_along[4] = (gpointer) VIK_TRW_LAYER_SUBLAYER_WAYPOINT;
+    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
 
 
-  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 );
+  }
 
 }
 
 
 }
 
-gboolean vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
+static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
 {
   switch ( subtype )
   {
     case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1);
     case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1);
 {
   switch ( 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 );
     case VIK_TRW_LAYER_SUBLAYER_TRACK:
     {
       VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer );
@@ -1539,10 +1952,26 @@ gboolean vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, g
       else
         return TRUE;
     }
       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;
 }
 
   }
   return TRUE;
 }
 
+/*
+ * Return a property about tracks for this layer
+ */
+gint vik_trw_layer_get_property_tracks_line_thickness ( VikTrwLayer *vtl )
+{
+  return vtl->line_thickness;
+}
+
 // Structure to hold multiple track information for a layer
 typedef struct {
   gdouble length;
 // Structure to hold multiple track information for a layer
 typedef struct {
   gdouble length;
@@ -1639,7 +2068,7 @@ static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
       // Setup info dependent on distance units
       if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) {
        g_snprintf (tbuf4, sizeof(tbuf4), "miles");
       // Setup info dependent on distance units
       if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) {
        g_snprintf (tbuf4, sizeof(tbuf4), "miles");
-       len_in_units = tt.length/1600.0;
+       len_in_units = VIK_METERS_TO_MILES(tt.length);
       }
       else {
        g_snprintf (tbuf4, sizeof(tbuf4), "kms");
       }
       else {
        g_snprintf (tbuf4, sizeof(tbuf4), "kms");
@@ -1660,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),
 
     // 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);
 
     g_date_free (gdate_start);
     g_date_free (gdate_end);
@@ -1675,11 +2104,37 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
 {
   switch ( subtype )
   {
 {
   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:
     {
     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];
       if ( tr ) {
        // Could be a better way of handling strings - but this works...
        gchar time_buf1[20];
@@ -1706,7 +2161,7 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
          g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f km %s"), time_buf1, tr_len/1000.0, time_buf2);
          break;
        case VIK_UNITS_DISTANCE_MILES:
          g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f km %s"), time_buf1, tr_len/1000.0, time_buf2);
          break;
        case VIK_UNITS_DISTANCE_MILES:
-         g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, tr_len/1600.0, time_buf2);
+         g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, VIK_METERS_TO_MILES(tr_len), time_buf2);
          break;
        default:
          break;
          break;
        default:
          break;
@@ -1715,11 +2170,22 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
       }
     }
     break;
       }
     }
     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 );
       // NB It's OK to return NULL
     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
     {
       VikWaypoint *w = g_hash_table_lookup ( l->waypoints, sublayer );
       // NB It's OK to return NULL
-      return w->comment;
+      if ( w )
+        return w->comment;
     }
     break;
     default: break;
     }
     break;
     default: break;
@@ -1727,17 +2193,248 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
   return NULL;
 }
 
   return NULL;
 }
 
-
-GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
+/*
+ * Function to show basic track point information on the statusbar
+ */
+static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt )
+{
+  gchar tmp_buf1[64];
+  switch (a_vik_get_units_height ()) {
+  case VIK_UNITS_HEIGHT_FEET:
+    g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(trkpt->altitude)));
+    break;
+  default:
+    //VIK_UNITS_HEIGHT_METRES:
+    g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dm"), (int)round(trkpt->altitude));
+  }
+  
+  gchar tmp_buf2[64];
+  tmp_buf2[0] = '\0';
+  if ( trkpt->has_timestamp ) {
+    // Compact date time format
+    strftime (tmp_buf2, sizeof(tmp_buf2), _(" | Time %x %X"), localtime(&(trkpt->timestamp)));
+  }
+
+  // Position part
+  // Position is put later on, as this bit may not be seen if the display is not big enough,
+  //   one can easily use the current pointer position to see this if needed
+  gchar *lat = NULL, *lon = NULL;
+  static struct LatLon ll;
+  vik_coord_to_latlon (&(trkpt->coord), &ll);
+  a_coords_latlon_to_string ( &ll, &lat, &lon );
+
+  // Track name
+  // Again is put later on, as this bit may not be seen if the display is not big enough
+  //  trackname can be seen from the treeview (when enabled)
+  // Also name could be very long to not leave room for anything else
+  gchar tmp_buf3[64];
+  tmp_buf3[0] = '\0';
+  if ( vtl->current_tp_track ) {
+    g_snprintf(tmp_buf3, sizeof(tmp_buf3),  _(" | Track: %s"), vtl->current_tp_track->name );
+  }
+
+  // Combine parts to make overall message
+  gchar *msg = g_strdup_printf (_("%s%s | %s %s %s"), tmp_buf1, tmp_buf2, lat, lon, tmp_buf3);
+  vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
+  g_free ( lat );
+  g_free ( lon );
+  g_free ( msg );
+}
+
+/*
+ * Function to show basic waypoint information on the statusbar
+ */
+static void set_statusbar_msg_info_wpt ( VikTrwLayer *vtl, VikWaypoint *wpt )
+{
+  gchar tmp_buf1[64];
+  switch (a_vik_get_units_height ()) {
+  case VIK_UNITS_HEIGHT_FEET:
+    g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(wpt->altitude)));
+    break;
+  default:
+    //VIK_UNITS_HEIGHT_METRES:
+    g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dm"), (int)round(wpt->altitude));
+  }
+  
+  // Position part
+  // Position is put last, as this bit is most likely not to be seen if the display is not big enough,
+  //   one can easily use the current pointer position to see this if needed
+  gchar *lat = NULL, *lon = NULL;
+  static struct LatLon ll;
+  vik_coord_to_latlon (&(wpt->coord), &ll);
+  a_coords_latlon_to_string ( &ll, &lat, &lon );
+
+  // Combine parts to make overall message
+  gchar *msg;
+  if ( wpt->comment )
+    // Add comment if available
+    msg = g_strdup_printf ( _("%s | %s %s | Comment: %s"), tmp_buf1, lat, lon, wpt->comment );
+  else
+    msg = g_strdup_printf ( _("%s | %s %s"), tmp_buf1, lat, lon );
+  vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
+  g_free ( lat );
+  g_free ( lon );
+  g_free ( msg );
+}
+
+/**
+ * General layer selection function, find out which bit is selected and take appropriate action
+ */
+static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp )
+{
+  // Reset
+  l->current_wp    = NULL;
+  l->current_wp_id = NULL;
+  trw_layer_cancel_current_tp ( l, FALSE );
+
+  // Clear statusbar
+  vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l))), VIK_STATUSBAR_INFO, "" );
+
+  switch ( type )
+    {
+    case VIK_TREEVIEW_TYPE_LAYER:
+      {
+       vik_window_set_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l );
+       /* Mark for redraw */
+       return TRUE;
+      }
+      break;
+
+    case VIK_TREEVIEW_TYPE_SUBLAYER:
+      {
+       switch ( subtype )
+         {
+         case VIK_TRW_LAYER_SUBLAYER_TRACKS:
+           {
+             vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->tracks, l );
+             /* Mark for redraw */
+             return TRUE;
+           }
+           break;
+         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 );
+             /* 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;
+           }
+           break;
+         case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
+           {
+             vik_window_set_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->waypoints, l );
+             /* Mark for redraw */
+             return TRUE;
+           }
+           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 );
+                // Show some waypoint info
+                set_statusbar_msg_info_wpt ( l, wpt );
+                /* Mark for redraw */
+                return TRUE;
+              }
+           }
+           break;
+         default:
+           {
+             return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
+           }
+           break;
+         }
+       return FALSE;
+      }
+      break;
+
+    default:
+      return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
+      break;
+    }
+}
+
+GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
 {
   return l->tracks;
 }
 
 {
   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;
 }
 
 GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l )
 {
   return l->waypoints;
 }
 
+/*
+ * ATM use a case sensitive find
+ * Finds the first one
+ */
+static gboolean trw_layer_waypoint_find ( const gpointer id, const VikWaypoint *wp, const gchar *name )
+{
+  if ( wp && wp->name )
+    if ( ! strcmp ( wp->name, name ) )
+      return TRUE;
+  return FALSE;
+}
+
+/*
+ * Get waypoint by name - not guaranteed to be unique
+ * Finds the first one
+ */
+VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, const gchar *name )
+{
+  return g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find, (gpointer) name );
+}
+
+/*
+ * ATM use a case sensitive find
+ * Finds the first one
+ */
+static gboolean trw_layer_track_find ( const gpointer id, const VikTrack *trk, const gchar *name )
+{
+  if ( trk && trk->name )
+    if ( ! strcmp ( trk->name, name ) )
+      return TRUE;
+  return FALSE;
+}
+
+/*
+ * Get track by name - not guaranteed to be unique
+ * Finds the first one
+ */
+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;
 static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] )
 {
   static VikCoord fixme;
@@ -1752,9 +2449,9 @@ static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoi
     maxmin[1].lon = VIK_LATLON(&fixme)->lon;
 }
 
     maxmin[1].lon = VIK_LATLON(&fixme)->lon;
 }
 
-static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] )
+static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *trk, struct LatLon maxmin[2] )
 {
 {
-  GList *tr = *t;
+  GList *tr = trk->trackpoints;
   static VikCoord fixme;
 
   while ( tr )
   static VikCoord fixme;
 
   while ( tr )
@@ -1774,35 +2471,10 @@ static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct
 
 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2])
 {
 
 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 )
 }
 
 gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
@@ -1824,7 +2496,7 @@ static void trw_layer_centerize ( gpointer layer_and_vlp[2] )
 {
   VikCoord coord;
   if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
 {
   VikCoord coord;
   if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
-    goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp[1]), &coord );
+    goto_coord ( layer_and_vlp[1], NULL, NULL, &coord );
   else
     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
 }
   else
     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
 }
@@ -1900,7 +2572,7 @@ static void trw_layer_auto_view ( gpointer layer_and_vlp[2] )
     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
 }
 
     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
 }
 
-static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, const gchar* trackname, guint file_type )
+static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type )
 {
   GtkWidget *file_selector;
   const gchar *fn;
 {
   GtkWidget *file_selector;
   const gchar *fn;
@@ -1919,15 +2591,15 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, co
     if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE )
     {
       gtk_widget_hide ( file_selector );
     if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE )
     {
       gtk_widget_hide ( file_selector );
-      failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname);
+      failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
       break;
     }
     else
     {
       break;
     }
     else
     {
-      if ( a_dialog_overwrite ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
+      if ( a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
       {
         gtk_widget_hide ( file_selector );
       {
         gtk_widget_hide ( file_selector );
-       failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname);
+       failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
         break;
       }
     }
         break;
       }
     }
@@ -1949,7 +2621,70 @@ static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] )
 
 static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
 {
 
 static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
 {
-  trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPX );
+  /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
+  gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
+  if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
+    auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
+
+  trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
+
+  g_free ( auto_save_name );
+}
+
+static void trw_layer_export_kml ( gpointer layer_and_vlp[2] )
+{
+  /* Auto append '.kml' to the name (providing it's not already there) for the default filename */
+  gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
+  if ( ! check_file_ext ( auto_save_name, ".kml" ) )
+    auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL );
+
+  trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
+
+  g_free ( auto_save_name );
+}
+
+/**
+ * Convert the given TRW layer into a temporary GPX file and open it with the specified program
+ *
+ */
+static void trw_layer_export_external_gpx ( gpointer layer_and_vlp[2], const gchar* external_program )
+{
+  gchar *name_used = NULL;
+  int fd;
+
+  if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) {
+    gboolean failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), name_used, FILE_TYPE_GPX, NULL, TRUE);
+    if (failed) {
+      a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Could not create temporary file for export.") );
+    }
+    else {
+      GError *err = NULL;
+      gchar *quoted_file = g_shell_quote ( name_used );
+      gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file );
+      g_free ( quoted_file );
+      if ( ! g_spawn_command_line_async ( cmd, &err ) )
+       {
+         a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( layer_and_vlp[0]), _("Could not launch %s."), external_program );
+         g_error_free ( err );
+       }
+      g_free ( cmd );
+    }
+    // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous
+    //g_remove ( name_used );
+    // Perhaps should be deleted when the program ends?
+    // For now leave it to the user to delete it / use system temp cleanup methods.
+    g_free ( name_used );
+  }
+}
+
+static void trw_layer_export_external_gpx_1 ( gpointer layer_and_vlp[2] )
+{
+  trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_1() );
+}
+
+static void trw_layer_export_external_gpx_2 ( gpointer layer_and_vlp[2] )
+{
+  trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_2() );
 }
 
 static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
 }
 
 static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
@@ -1958,19 +2693,43 @@ static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
   layer_and_vlp[0] = pass_along[0];
   layer_and_vlp[1] = pass_along[1];
 
   layer_and_vlp[0] = pass_along[0];
   layer_and_vlp[1] = pass_along[1];
 
+  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;
+
   /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
   /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( pass_along[3] );
+  gchar *auto_save_name = g_strdup ( trk->name );
   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
 
   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
 
-  trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, pass_along[3], FILE_TYPE_GPX );
+  trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, trk, FILE_TYPE_GPX );
 
   g_free ( auto_save_name );
 }
 
 
   g_free ( auto_save_name );
 }
 
+typedef struct {
+  VikWaypoint *wp; // input
+  gpointer uuid;   // output
+} wpu_udata;
+
+static gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata )
+{
+  wpu_udata *user_data = udata;
+  if ( wp == user_data->wp ) {
+    user_data->uuid = id;
+    return TRUE;
+  }
+  return FALSE;
+}
+
 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
 {
 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
 {
-  GHashTable *wps = vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp[0]) );
   GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
                                                  VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
   GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
                                                  VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1993,26 +2752,34 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
 
   while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
   {
 
   while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
   {
-    VikWaypoint *wp;
-    gchar *upname = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
-    int i;
-
-    for ( i = strlen(upname)-1; i >= 0; i-- )
-      upname[i] = toupper(upname[i]);
+    gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+    // Find *first* wp with the given name
+    VikWaypoint *wp = vik_trw_layer_get_waypoint ( VIK_TRW_LAYER(layer_and_vlp[0]), name );
 
 
-    wp = g_hash_table_lookup ( wps, upname );
-
-    if (!wp)
+    if ( !wp )
       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
     else
     {
       vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
     else
     {
       vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
-      vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, upname ) );
+
+      // Find and select on the side panel
+      wpu_udata udata;
+      udata.wp   = wp;
+      udata.uuid = NULL;
+
+      // Hmmm, want key of it
+      gpointer *wpf = g_hash_table_find ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+      if ( wpf && udata.uuid ) {
+        GtkTreeIter *it = g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, udata.uuid );
+        vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, it, TRUE );
+      }
+
       break;
     }
 
       break;
     }
 
-    g_free ( upname );
+    g_free ( name );
 
   }
   gtk_widget_destroy ( dia );
 
   }
   gtk_widget_destroy ( dia );
@@ -2020,16 +2787,28 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
 
 gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
 {
 
 gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
 {
-  gchar *name = highest_wp_number_get(vtl);
+  gchar *default_name = highest_wp_number_get(vtl);
   VikWaypoint *wp = vik_waypoint_new();
   VikWaypoint *wp = vik_waypoint_new();
+  gchar *returned_name;
+  gboolean updated;
   wp->coord = *def_coord;
   wp->coord = *def_coord;
+  
+  // Attempt to auto set height if DEM data is available
+  gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST );
+  if ( elev != VIK_DEM_INVALID_ELEVATION )
+    wp->altitude = (gdouble)elev;
+
+  returned_name = a_dialog_waypoint ( w, default_name, wp, vtl->coord_mode, TRUE, &updated );
 
 
-  if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) )
+  if ( returned_name )
   {
     wp->visible = TRUE;
   {
     wp->visible = TRUE;
-    vik_trw_layer_add_waypoint ( vtl, name, wp );
+    vik_trw_layer_add_waypoint ( vtl, returned_name, wp );
+    g_free (default_name);
+    g_free (returned_name);
     return TRUE;
   }
     return TRUE;
   }
+  g_free (default_name);
   vik_waypoint_free(wp);
   return FALSE;
 }
   vik_waypoint_free(wp);
   return FALSE;
 }
@@ -2077,145 +2856,616 @@ static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] )
   a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin);
 }
 
   a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin);
 }
 
-static void trw_layer_new_wp ( gpointer lav[2] )
+#ifdef VIK_CONFIG_GEOTAG
+static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] )
+{
+  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  if ( wp )
+    // Update directly - not changing the mtime
+    a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE );
+}
+
+static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] )
+{
+  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  if ( wp )
+    // Update directly
+    a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE );
+}
+
+/*
+ * Use code in separate file for this feature as reasonably complex
+ */
+static void trw_layer_geotagging_track ( 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] );
+  // Unset so can be reverified later if necessary
+  vtl->has_verified_thumbnails = FALSE;
+
+  trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                           vtl,
+                           track,
+                           track->name );
+}
+
+static void trw_layer_geotagging ( gpointer lav[2] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
-  /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
-     instead return true if you want to update. */
-  if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible )
-    vik_layers_panel_emit_update ( vlp );
+  // Unset so can be reverified later if necessary
+  vtl->has_verified_thumbnails = FALSE;
+
+  trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                           vtl,
+                           NULL,
+                           NULL);
 }
 }
+#endif
 
 
-static void trw_layer_auto_tracks_view ( gpointer lav[2] )
+// 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
+
+/*
+ * Acquire into this TRW Layer straight from GPS Device
+ */
+static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+  VikViewport *vvp =  vik_window_viewport(vw);
 
 
-  if ( g_hash_table_size (vtl->tracks) > 0 ) {
-    struct LatLon maxmin[2] = { {0,0}, {0,0} };
-    g_hash_table_foreach ( vtl->tracks, (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 );
-  }
+  vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
+  a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface );
 }
 
 }
 
-static void trw_layer_single_waypoint_jump ( const gchar *name, const VikWaypoint *wp, gpointer vvp )
+#ifdef VIK_CONFIG_GOOGLE
+/*
+ * Acquire into this TRW Layer from Google Directions
+ */
+static void trw_layer_acquire_google_cb ( gpointer lav[2] )
 {
 {
-  /* NB do not care if wp is visible or not */
-  vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+  VikViewport *vvp =  vik_window_viewport(vw);
+
+  a_acquire ( vw, vlp, vvp, &vik_datasource_google_interface );
 }
 }
+#endif
 
 
-static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
+#ifdef VIK_CONFIG_OPENSTREETMAP
+/*
+ * Acquire into this TRW Layer from OSM
+ */
+static void trw_layer_acquire_osm_cb ( gpointer lav[2] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+  VikViewport *vvp =  vik_window_viewport(vw);
 
 
-  /* Only 1 waypoint - jump straight to it */
-  if ( g_hash_table_size (vtl->waypoints) == 1 ) {
-    VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
-    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
-  }
-  /* If at least 2 waypoints - find center and then zoom to fit */
-  else if ( g_hash_table_size (vtl->waypoints) > 1 )
-  {
-    struct LatLon maxmin[2] = { {0,0}, {0,0} };
-    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin );
-    trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
-  }
-
-  vik_layers_panel_emit_update ( vlp );
+  a_acquire ( vw, vlp, vvp, &vik_datasource_osm_interface );
 }
 }
+#endif
 
 
-void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
+#ifdef VIK_CONFIG_GEOCACHES
+/*
+ * Acquire into this TRW Layer from Geocaching.com
+ */
+static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
 {
 {
-  static gpointer pass_along[2];
-  GtkWidget *item;
-  GtkWidget *export_submenu;
-  GtkWidget *wikipedia_submenu;
-  pass_along[0] = vtl;
-  pass_along[1] = vlp;
-
-  item = gtk_menu_item_new();
-  gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-  gtk_widget_show ( item );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+  VikViewport *vvp =  vik_window_viewport(vw);
 
 
-  item = gtk_menu_item_new_with_mnemonic ( _("_View Layer") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show ( item );
+  a_acquire ( vw, vlp, vvp, &vik_datasource_gc_interface );
+}
+#endif
 
 
-  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 );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show ( item );
+#ifdef VIK_CONFIG_GEOTAG
+/*
+ * Acquire into this TRW Layer from images
+ */
+static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+  VikViewport *vvp =  vik_window_viewport(vw);
 
 
-  item = gtk_menu_item_new_with_mnemonic ( _("V_iew 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_widget_show ( item );
+  vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
+  a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface );
 
 
-  item = gtk_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show ( item );
+  // Reverify thumbnails as they may have changed
+  vtl->has_verified_thumbnails = FALSE;
+  trw_layer_verify_thumbnails ( vtl, NULL );
+}
+#endif
 
 
-  item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show ( item );
+static void trw_layer_gps_upload ( gpointer lav[2] )
+{
+  gpointer pass_along[6];
+  pass_along[0] = lav[0];
+  pass_along[1] = lav[1];
+  pass_along[2] = NULL; // No track - operate on the layer
+  pass_along[3] = NULL;
+  pass_along[4] = NULL;
+  pass_along[5] = NULL;
 
 
-  export_submenu = gtk_menu_new ();
-  item = gtk_menu_item_new_with_mnemonic ( _("_Export Layer") );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show ( item );
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
-  
-  item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
-  gtk_widget_show ( item );
+  trw_layer_gps_upload_any ( pass_along );
+}
 
 
-  item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper") );
+/**
+ * If pass_along[3] is defined that this will upload just that track
+ */
+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[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;
+
+  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 (track && !track->visible) {
+    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") );
+    return;
+  }
+
+  GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
+                                                    VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
+                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                    GTK_STOCK_OK,
+                                                    GTK_RESPONSE_ACCEPT,
+                                                    GTK_STOCK_CANCEL,
+                                                    GTK_RESPONSE_REJECT,
+                                                    NULL );
+
+  gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+  GtkWidget *response_w = NULL;
+#if GTK_CHECK_VERSION (2, 20, 0)
+  response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+#endif
+
+  if ( response_w )
+    gtk_widget_grab_focus ( response_w );
+
+  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 );
+    gtk_widget_destroy ( dialog );
+    return;
+  }
+
+  // Get info from reused datasource dialog widgets
+  gchar* protocol = datasource_gps_get_protocol ( dgs );
+  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 );
+
+  gtk_widget_destroy ( dialog );
+
+  // When called from the viewport - work the corresponding layerspanel:
+  if ( !vlp ) {
+    vlp = vik_window_layers_panel ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
+  }
+
+  // Apply settings to transfer to the GPS device
+  vik_gps_comm ( vtl,
+                 track,
+                 GPS_UP,
+                 protocol,
+                 port,
+                 FALSE,
+                 vik_layers_panel_get_viewport (vlp),
+                 vlp,
+                 do_tracks,
+                 do_routes,
+                 do_waypoints,
+                 turn_off );
+}
+
+/*
+ * Acquire into this TRW Layer from any GPS Babel supported file
+ */
+static void trw_layer_acquire_file_cb ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+  VikViewport *vvp =  vik_window_viewport(vw);
+
+  a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface );
+}
+
+static void trw_layer_new_wp ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
+     instead return true if you want to update. */
+  if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible )
+    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]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+
+  if ( g_hash_table_size (vtl->tracks) > 0 ) {
+    struct LatLon maxmin[2] = { {0,0}, {0,0} };
+    g_hash_table_foreach ( vtl->tracks, (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_single_waypoint_jump ( const gchar *name, const VikWaypoint *wp, gpointer vvp )
+{
+  /* NB do not care if wp is visible or not */
+  vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
+}
+
+static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+
+  /* Only 1 waypoint - jump straight to it */
+  if ( g_hash_table_size (vtl->waypoints) == 1 ) {
+    VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
+    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
+  }
+  /* If at least 2 waypoints - find center and then zoom to fit */
+  else if ( g_hash_table_size (vtl->waypoints) > 1 )
+  {
+    struct LatLon maxmin[2] = { {0,0}, {0,0} };
+    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, 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_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
+{
+  static gpointer pass_along[2];
+  GtkWidget *item;
+  GtkWidget *export_submenu;
+  pass_along[0] = vtl;
+  pass_along[1] = vlp;
+
+  item = gtk_menu_item_new();
+  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) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+
+  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 ( _("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 (view_submenu), item);
+  gtk_widget_show ( item );
+
+  item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+
+  item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+
+  export_submenu = gtk_menu_new ();
+  item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Layer") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, 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), export_submenu );
+  
+  item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+  gtk_widget_show ( item );
+
+  item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper...") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX") );
+  item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX...") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint") );
+  item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+  gtk_widget_show ( item );
+
+  gchar* external1 = g_strconcat ( _("Open with External Program_1: "), a_vik_get_external_gpx_program_1(), NULL );
+  item = gtk_menu_item_new_with_mnemonic ( external1 );
+  g_free ( external1 );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+  gtk_widget_show ( item );
+
+  gchar* external2 = g_strconcat ( _("Open with External Program_2: "), a_vik_get_external_gpx_program_2(), NULL );
+  item = gtk_menu_item_new_with_mnemonic ( external2 );
+  g_free ( external2 );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+  gtk_widget_show ( item );
+
+  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 );
   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 );
   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
 
 #ifdef VIK_CONFIG_GEONAMES
-  wikipedia_submenu = gtk_menu_new();
-  item = gtk_menu_item_new_with_mnemonic ( _("_Add Wikipedia Waypoints") );
+  GtkWidget *wikipedia_submenu = gtk_menu_new();
+  item = gtk_image_menu_item_new_with_mnemonic ( _("_Add Wikipedia Waypoints") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, 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), wikipedia_submenu);
 
   gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
   gtk_widget_show(item);
   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), wikipedia_submenu);
 
-  item = gtk_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
+  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_new_wikipedia_wp_layer), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
   gtk_widget_show ( item );
 
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_mnemonic ( _("Within _Current View") );
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Current View") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU) );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
   gtk_widget_show ( item );
 #endif
 
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
   gtk_widget_show ( item );
 #endif
 
+#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), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+#endif
+
+  GtkWidget *acquire_submenu = gtk_menu_new ();
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Ac_quire") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, 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), acquire_submenu );
+  
+  item = gtk_menu_item_new_with_mnemonic ( _("From _GPS...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_gps_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_show ( item );
+
+#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);
+  gtk_widget_show ( item );
+#endif
+
+#ifdef VIK_CONFIG_OPENSTREETMAP
+  item = gtk_menu_item_new_with_mnemonic ( _("From _OSM Traces...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_show ( item );
+#endif
+
+#ifdef VIK_CONFIG_GEOCACHES
+  item = gtk_menu_item_new_with_mnemonic ( _("From Geo_caching...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geocache_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_show ( item );
+#endif
+
+#ifdef VIK_CONFIG_GEOTAG
+  item = gtk_menu_item_new_with_mnemonic ( _("From Geotagged _Images...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geotagged_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_show ( item );
+#endif
+
+  item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_show ( item );
+
+  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 );
+
+  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 
 #ifdef VIK_CONFIG_OPENSTREETMAP 
-  item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM") );
+  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) );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
   gtk_widget_show ( item );
 #endif
 
   gtk_widget_show ( item );
 #endif
 
+  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) );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
+  
+  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 );
+  gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+  gtk_widget_show ( item );
+  
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Tracks _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_tracks_from_selection), pass_along );
+  gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+  gtk_widget_show ( item );
+  
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") );
+  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_waypoints), pass_along );
+  gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+  gtk_widget_show ( item );
+  
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Waypoints 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_waypoints_from_selection), pass_along );
+  gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+  gtk_widget_show ( item );
+  
   item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
                                   vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
   if ( item ) {
   item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
                                   vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
   if ( item ) {
@@ -2231,129 +3481,212 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl
   }  
 }
 
   }  
 }
 
+// Fake Waypoint UUIDs vi simple increasing integer
+static guint wp_uuid = 0;
+
 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
 {
 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
 {
+  wp_uuid++;
+
+  vik_waypoint_set_name (wp, name);
+
   if ( VIK_LAYER(vtl)->realized )
   {
   if ( VIK_LAYER(vtl)->realized )
   {
-    VikWaypoint *oldwp = VIK_WAYPOINT ( g_hash_table_lookup ( vtl->waypoints, name ) );
-    if ( oldwp )
-      wp->visible = oldwp->visible; /* same visibility so we don't have to update viktreeview */
-    else
-    {
-      GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
-      // Visibility column always needed for waypoints
+    // 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
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-      vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, 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
 #else
-      vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, 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
 #endif
-      // Actual setting of visibility dependent on the waypoint
-      vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
-      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter );
-      g_hash_table_insert ( vtl->waypoints_iters, name, iter );
-    }
+    // Actual setting of visibility dependent on the waypoint
+    vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
+
+    g_hash_table_insert ( vtl->waypoints_iters, GUINT_TO_POINTER(wp_uuid), iter );
   }
 
   highest_wp_number_add_wp(vtl, name);
   }
 
   highest_wp_number_add_wp(vtl, name);
-  g_hash_table_insert ( vtl->waypoints, name, wp );
+  g_hash_table_insert ( vtl->waypoints, GUINT_TO_POINTER(wp_uuid), wp );
  
 }
 
  
 }
 
+// Fake Track UUIDs vi simple increasing integer
+static guint tr_uuid = 0;
+
 void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 {
 void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 {
+  tr_uuid++;
+
+  vik_track_set_name (t, name);
+
   if ( VIK_LAYER(vtl)->realized )
   {
   if ( VIK_LAYER(vtl)->realized )
   {
-    VikTrack *oldt = VIK_TRACK ( g_hash_table_lookup ( vtl->tracks, name ) );
-    if ( oldt )
-      t->visible = oldt->visible; /* same visibility so we don't have to update viktreeview */
-    else
-    {
-      GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
-      // Visibility column always needed for tracks
+    // 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
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-      vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
+    vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
 #else
 #else
-      vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
+    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
 #endif
 #endif
-      // Actual setting of visibility dependent on the track
-      vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
-      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter );
-      g_hash_table_insert ( vtl->tracks_iters, name, iter );
-    }
+    // 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->tracks_iters, GUINT_TO_POINTER(tr_uuid), iter );
   }
 
   }
 
-  g_hash_table_insert ( vtl->tracks, name, t );
+  g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_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, const gchar *trk_name )
-{
-  if (vtl->current_tp_track_name && g_strcasecmp(trk_name, vtl->current_tp_track_name) == 0)
-    trw_layer_cancel_current_tp ( vtl, FALSE );
-  else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0)
-    trw_layer_cancel_last_tp ( vtl );
-}
-       
-static gchar *get_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++;
-  }
-  return newname;
-}
+// Fake Route UUIDs vi simple increasing integer
+static guint rt_uuid = 0;
 
 
-void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
+void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 {
 {
-  vik_trw_layer_add_waypoint ( vtl,
-                        get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name),
-                        wp );
+  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);
+
+  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;
 }
 }
+
+void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
+{
+  // No more uniqueness of name forced when loading from a file
+  // This now makes this function a little redunant as we just flow the parameters through
+  vik_trw_layer_add_waypoint ( vtl, name, wp );
+}
+
 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
 {
 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
 {
-  if ( vtl->magic_scissors_append && vtl->magic_scissors_current_track ) {
+  if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
     vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
     vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
-    vik_track_steal_and_append_trackpoints ( vtl->magic_scissors_current_track, tr );
+    vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
     vik_track_free ( tr );
     vik_track_free ( tr );
-    vtl->magic_scissors_append = FALSE; /* this means we have added it */
+    vtl->route_finder_append = FALSE; /* this means we have added it */
   } else {
   } else {
-    gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
-    vik_trw_layer_add_track ( vtl, new_name, tr );
 
 
-    if ( vtl->magic_scissors_check_added_track ) {
+    // No more uniqueness of name forced when loading from a file
+    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 */
       vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
-      if ( vtl->magic_scissors_added_track_name ) /* for google routes */
-        g_free ( vtl->magic_scissors_added_track_name );
-      vtl->magic_scissors_added_track_name = g_strdup(new_name);
+      vtl->route_finder_added_track = tr;
     }
   }
 }
 
     }
   }
 }
 
-static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l )
+static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l )
 {
 {
-  *l = g_list_append(*l, (gpointer)name);
+  *l = g_list_append(*l, id);
 }
 
 }
 
-static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type )
+/*
+ * Move an item from one TRW layer to another TRW layer
+ */
+static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
 {
 {
-  gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name);
   if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
   if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
-    VikTrack *t;
-    t = vik_track_copy(vik_trw_layer_get_track(vtl_src, name));
-    vik_trw_layer_delete_track(vtl_src, name);
-    vik_trw_layer_add_track(vtl_dest, newname, t);
+    VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
+
+    gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name);
+
+    VikTrack *trk2 = vik_track_copy ( trk );
+    vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
+    vik_trw_layer_delete_track ( vtl_src, trk );
   }
   }
-  if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
-    VikWaypoint *w;
-    w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, name));
-    vik_trw_layer_delete_waypoint(vtl_src, name);
-    vik_trw_layer_add_waypoint(vtl_dest, newname, w);
+
+  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 );
+
+    gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, wp->name);
+
+    VikWaypoint *wp2 = vik_waypoint_copy ( wp );
+    vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
+    trw_layer_delete_waypoint ( vtl_src, wp );
   }
 }
 
   }
 }
 
@@ -2372,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_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) {
     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 {
       } 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;
     }
       }
       iter = iter->next;
     }
@@ -2390,87 +3729,290 @@ static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl
   }
 }
 
   }
 }
 
+typedef struct {
+  VikTrack *trk; // input
+  gpointer uuid;   // output
+} trku_udata;
+
+static gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata )
+{
+  trku_udata *user_data = udata;
+  if ( trk == user_data->trk ) {
+    user_data->uuid = id;
+    return TRUE;
+  }
+  return FALSE;
+}
+
+gboolean vik_trw_layer_delete_track ( 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->tracks, (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->tracks_iters, udata.uuid );
+
+      if ( it ) {
+        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_track ( VikTrwLayer *vtl, const gchar *trk_name )
+gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
 {
 {
-  VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name );
   gboolean was_visible = FALSE;
   gboolean was_visible = FALSE;
-  if ( t )
-  {
-    GtkTreeIter *it;
-    was_visible = t->visible;
-    if ( t == vtl->current_track )
+
+  if ( trk && trk->name ) {
+
+    if ( trk == vtl->current_track ) {
       vtl->current_track = NULL;
       vtl->current_track = NULL;
-    if ( t == vtl->magic_scissors_current_track )
-      vtl->magic_scissors_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 );
 
 
-    /* could be current_tp, so we have to check */
-    trw_layer_cancel_tps_of_track ( vtl, trk_name );
+      GtkTreeIter *it = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
 
 
-    g_assert ( ( it = g_hash_table_lookup ( vtl->tracks_iters, trk_name ) ) );
-    vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
-    g_hash_table_remove ( vtl->tracks_iters, trk_name );
+      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 );
 
 
-    /* do this last because trk_name may be pointing to actual orig key */
-    g_hash_table_remove ( vtl->tracks, trk_name );
+        // 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) );
+        }
+      }
+    }
   }
   return was_visible;
 }
 
   }
   return was_visible;
 }
 
-gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name )
+static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
 {
   gboolean was_visible = FALSE;
 {
   gboolean was_visible = FALSE;
-  VikWaypoint *wp;
 
 
-  wp = g_hash_table_lookup ( vtl->waypoints, wp_name );
-  if ( wp ) {
-    GtkTreeIter *it;
+  if ( wp && wp->name ) {
 
     if ( wp == vtl->current_wp ) {
       vtl->current_wp = NULL;
 
     if ( wp == vtl->current_wp ) {
       vtl->current_wp = NULL;
-      vtl->current_wp_name = NULL;
+      vtl->current_wp_id = NULL;
       vtl->moving_wp = FALSE;
     }
 
     was_visible = wp->visible;
       vtl->moving_wp = FALSE;
     }
 
     was_visible = wp->visible;
-    g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) wp_name ) ) );
-    vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
-    g_hash_table_remove ( vtl->waypoints_iters, (gchar *) wp_name );
+    
+    wpu_udata udata;
+    udata.wp   = wp;
+    udata.uuid = NULL;
+
+    // Hmmm, want key of it
+    gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+    if ( wpf && udata.uuid ) {
+      GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+    
+      if ( it ) {
+        vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
+        g_hash_table_remove ( vtl->waypoints_iters, udata.uuid );
+
+        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) );
+       }
+      }
+    }
 
 
-    highest_wp_number_remove_wp(vtl, wp_name);
-    g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */
   }
 
   return was_visible;
 }
 
   }
 
   return was_visible;
 }
 
+// Only for temporary use by trw_layer_delete_waypoint_by_name
+static gboolean trw_layer_waypoint_find_uuid_by_name ( const gpointer id, const VikWaypoint *wp, gpointer udata )
+{
+  wpu_udata *user_data = udata;
+  if ( ! strcmp ( wp->name, user_data->wp->name ) ) {
+    user_data->uuid = id;
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*
+ * Delete a waypoint by the given name
+ * NOTE: ATM this will delete the first encountered Waypoint with the specified name
+ *   as there be multiple waypoints with the same name
+ */
+static gboolean trw_layer_delete_waypoint_by_name ( VikTrwLayer *vtl, const gchar *name )
+{
+  wpu_udata udata;
+  // Fake a waypoint with the given name
+  udata.wp   = vik_waypoint_new ();
+  vik_waypoint_set_name (udata.wp, name);
+  // Currently only the name is used in this waypoint find function
+  udata.uuid = NULL;
+
+  // Hmmm, want key of it
+  gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
+
+  vik_waypoint_free (udata.wp);
+
+  if ( wpf && udata.uuid )
+    return trw_layer_delete_waypoint (vtl, g_hash_table_lookup ( vtl->waypoints, udata.uuid ));
+  else
+    return FALSE;
+}
+
+typedef struct {
+  VikTrack *trk; // input
+  gpointer uuid; // output
+} tpu_udata;
+
+// Only for temporary use by trw_layer_delete_track_by_name
+static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const VikTrack *trk, gpointer udata )
+{
+  tpu_udata *user_data = udata;
+  if ( ! strcmp ( trk->name, user_data->trk->name ) ) {
+    user_data->uuid = id;
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*
+ * Delete a track by the given name
+ * NOTE: ATM this will delete the first encountered Track with the specified 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, GHashTable *ht_tracks )
+{
+  tpu_udata udata;
+  // Fake a track with the given name
+  udata.trk   = vik_track_new ();
+  vik_track_set_name (udata.trk, name);
+  // Currently only the name is used in this waypoint find function
+  udata.uuid = NULL;
+
+  // Hmmm, want key of it
+  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 ) {
+    // 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;
+}
+
 static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt)
 {
     vik_treeview_item_delete (vt, it );
 }
 
 static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt)
 {
     vik_treeview_item_delete (vt, it );
 }
 
+void vik_trw_layer_delete_all_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 )
 {
 
   vtl->current_track = NULL;
 void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
 {
 
   vtl->current_track = NULL;
-  vtl->magic_scissors_current_track = NULL;
-  if (vtl->current_tp_track_name)
+  vtl->route_finder_current_track = NULL;
+  vtl->route_finder_added_track = NULL;
+  if (vtl->current_tp_track)
     trw_layer_cancel_current_tp(vtl, FALSE);
     trw_layer_cancel_current_tp(vtl, FALSE);
-  if (vtl->last_tp_track_name)
-    trw_layer_cancel_last_tp ( vtl );
 
   g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
   g_hash_table_remove_all(vtl->tracks_iters);
   g_hash_table_remove_all(vtl->tracks);
 
 
   g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
   g_hash_table_remove_all(vtl->tracks_iters);
   g_hash_table_remove_all(vtl->tracks);
 
-  /* TODO: only update if the layer is visible (ticked) */
-  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
+
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
 }
 
 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
 {
   vtl->current_wp = NULL;
 }
 
 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
 {
   vtl->current_wp = NULL;
-  vtl->current_wp_name = NULL;
+  vtl->current_wp_id = NULL;
   vtl->moving_wp = FALSE;
 
   highest_wp_number_reset(vtl);
   vtl->moving_wp = FALSE;
 
   highest_wp_number_reset(vtl);
@@ -2479,615 +4021,1822 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
   g_hash_table_remove_all(vtl->waypoints_iters);
   g_hash_table_remove_all(vtl->waypoints);
 
   g_hash_table_remove_all(vtl->waypoints_iters);
   g_hash_table_remove_all(vtl->waypoints);
 
-  /* TODO: only update if the layer is visible (ticked) */
-  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
+
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+}
+
+static void trw_layer_delete_all_tracks ( 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 tracks in %s?"),
+                           vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
+    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]);
+  // 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 waypoints in %s?"),
+                           vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
+    vik_trw_layer_delete_all_waypoints (vtl);
 }
 
 }
 
-static void trw_layer_delete_item ( gpointer pass_along[5] )
+static void trw_layer_delete_item ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gboolean was_visible = FALSE;
   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gboolean was_visible = FALSE;
   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
-    was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
+    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+    if ( wp && wp->name ) {
+      if ( GPOINTER_TO_INT ( pass_along[4]) )
+        // Get confirmation from the user
+        // Maybe this Waypoint Delete should be optional as is it could get annoying...
+        if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+            _("Are you sure you want to delete the waypoint \"%s\""),
+            wp->name ) )
+          return;
+      was_visible = trw_layer_delete_waypoint ( vtl, wp );
+    }
+  }
+  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 ) {
+      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 track \"%s\""),
+                                 trk->name ) )
+          return;
+      was_visible = vik_trw_layer_delete_track ( vtl, trk );
+    }
   }
   else
   {
   }
   else
   {
-    was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
+    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 )
   }
   if ( was_visible )
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
 }
 
 
 }
 
 
-static void trw_layer_properties_item ( gpointer pass_along[5] )
+static void trw_layer_properties_item ( gpointer pass_along[7] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
-    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
-    if ( wp )
+    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); // sublayer
+
+    if ( wp && wp->name )
     {
     {
-      if ( a_dialog_new_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), NULL, wp, NULL, vtl->coord_mode ) )
+      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 ( VIK_LAYER(vtl)->visible )
-        vik_layer_emit_update ( VIK_LAYER(vtl) );
+      if ( updated && VIK_LAYER(vtl)->visible )
+       vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     }
   }
   else
   {
     }
   }
   else
   {
-    VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
-    if ( tr )
+    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),
     {
       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                     vtl, tr,
-                     pass_along[1], /* vlp */ 
-                     pass_along[3]  /* track name */);
+                                 vtl, tr,
+                                 pass_along[1], /* vlp */
+                                 pass_along[5] );  /* vvp */
     }
   }
 }
 
     }
   }
 }
 
-static void goto_coord ( VikLayersPanel *vlp, const VikCoord *coord )
-{
-  vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), coord );
-  vik_layers_panel_emit_update ( vlp );
+/*
+   Parameter 1 -> VikLayersPanel
+   Parameter 2 -> VikLayer
+   Parameter 3 -> VikViewport
+*/
+static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord )
+{
+  if ( vlp ) {
+    vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord );
+    vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
+  }
+  else {
+    /* since vlp not set, vl & vvp should be valid instead! */
+    if ( vl && vvp ) {
+      vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord );
+      vik_layer_emit_update ( VIK_LAYER(vl), FALSE );
+    }
+  }
 }
 
 }
 
-static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] )
+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 ( VIK_LAYERS_PANEL(pass_along[1]), &(((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[5] )
+static void trw_layer_goto_track_center ( gpointer pass_along[6] )
 {
 {
-  /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
-  GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
-  if ( trps && *trps )
+  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} };
     VikCoord coord;
   {
     struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
     VikCoord coord;
-    trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
+    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;
     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 );
-    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &coord);
+    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] )
 static void trw_layer_extend_track_end ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(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;
+
+  vtl->current_track = 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
+/**
+ * extend a track using route finder
+ */
+static void trw_layer_extend_track_end_route_finder ( 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] );
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord);
+
+  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, NUM_TOOLS );
+  vtl->route_finder_coord =  last_coord;
+  vtl->route_finder_current_track = track;
+  vtl->route_finder_started = TRUE;
+
+  if ( track->trackpoints )
+    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
+
+}
+#endif
+
+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 */
+  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 )
+    vik_track_apply_dem_data ( track );
+}
+
+static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
+{
+  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);
+  goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
+}
+
+static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
+{
+  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));
+}
+
+static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
+{
+  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));
+}
+
+static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
+{
+  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));
+}
+
+/*
+ * Automatically change the viewport to center on the track and zoom to see the extent of the track
+ */
+static void trw_layer_auto_track_view ( 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 && trk->trackpoints )
+  {
+    struct LatLon maxmin[2] = { {0,0}, {0,0} };
+    trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
+    trw_layer_zoom_to_show_latlons ( VIK_TRW_LAYER(pass_along[0]), pass_along[5], maxmin );
+    if ( pass_along[1] )
+      vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
+    else
+      vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE );
+  }
+}
+
+static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  trw_layer_tpwin_init ( vtl );
+}
+
+/*************************************
+ * merge/split by time routines 
+ *************************************/
+
+/* called for each key in track hash table.
+ * If the current track has the same time stamp type, add it to the result,
+ * except the one pointed by "exclude".
+ * set exclude to NULL if there is no exclude to check.
+ * Note that the result is in reverse (for performance reasons).
+ */
+typedef struct {
+  GList **result;
+  GList  *exclude;
+  gboolean with_timestamps;
+} twt_udata;
+static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata)
+{
+  twt_udata *user_data = udata;
+  VikTrackpoint *p1, *p2;
+
+  if (VIK_TRACK(value)->trackpoints == user_data->exclude) {
+    return;
+  }
+
+  if (VIK_TRACK(value)->trackpoints) {
+    p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
+    p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+
+    if ( user_data->with_timestamps ) {
+      if (!p1->has_timestamp || !p2->has_timestamp) {
+       return;
+      }
+    }
+    else {
+      // Don't add tracks with timestamps when getting non timestamp tracks
+      if (p1->has_timestamp || p2->has_timestamp) {
+       return;
+      }
+    }
+  }
+
+  *(user_data->result) = g_list_prepend(*(user_data->result), key);
+}
+
+/* called for each key in track hash table. if original track user_data[1] is close enough
+ * to the passed one, add it to list in user_data[0] 
+ */
+static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
+{
+  time_t t1, t2;
+  VikTrackpoint *p1, *p2;
+  VikTrack *trk = VIK_TRACK(value);
+
+  GList **nearby_tracks = ((gpointer *)user_data)[0];
+  GList *tpoints = ((gpointer *)user_data)[1];
+
+  /* outline: 
+   * detect reasons for not merging, and return
+   * if no reason is found not to merge, then do it.
+   */
+
+  // Exclude the original track from the compiled list
+  if (trk->trackpoints == tpoints) {
+    return;
+  }
+
+  t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp;
+  t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp;
+
+  if (trk->trackpoints) {
+    p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data);
+    p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data);
+
+    if (!p1->has_timestamp || !p2->has_timestamp) {
+      //g_print("no timestamp\n");
+      return;
+    }
+
+    guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
+    //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
+    if (! (abs(t1 - p2->timestamp) < threshold ||
+       /*  p1 p2      t1 t2 */
+          abs(p1->timestamp - t2) < threshold)
+       /*  t1 t2      p1 p2 */
+       ) {
+      return;
+    }
+  }
+
+  *nearby_tracks = g_list_prepend(*nearby_tracks, value);
+}
+
+/* comparison function used to sort tracks; a and b are hash table keys */
+/* Not actively used - can be restored if needed
+static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  GHashTable *tracks = user_data;
+  time_t t1, t2;
+
+  t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
+  t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
+  
+  if (t1 < t2) return -1;
+  if (t1 > t2) return 1;
+  return 0;
+}
+*/
+
+/* comparison function used to sort trackpoints */
+static gint trackpoint_compare(gconstpointer a, gconstpointer b)
+{
+  time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
+  
+  if (t1 < t2) return -1;
+  if (t1 > t2) return 1;
+  return 0;
+}
+
+/**
+ * comparison function which can be used to sort tracks or waypoints by name
+ */
+static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  const gchar* namea = (const gchar*) a;
+  const gchar* nameb = (const gchar*) b;
+  if ( namea == NULL || nameb == NULL)
+    return 0;
+  else
+    // Same sort method as used in the vik_treeview_*_alphabetize functions
+    return strcmp ( namea, nameb );
+}
+
+/**
+ * Attempt to merge selected track with other tracks specified by the user
+ * Tracks to merge with must be of the same 'type' as the selected track -
+ *  either all with timestamps, or all without timestamps
+ */
+static void trw_layer_merge_with_other ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  GList *other_tracks = NULL;
+  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;
+
+  twt_udata udata;
+  udata.result = &other_tracks;
+  udata.exclude = track->trackpoints;
+  // Allow merging with 'similar' time type time tracks
+  // i.e. either those times, or those without
+  udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp);
+
+  g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
+  other_tracks = g_list_reverse(other_tracks);
+
+  if ( !other_tracks ) {
+    if ( udata.with_timestamps )
+      a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks with timestamps in this layer found"));
+    else
+      a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks without timestamps in this layer found"));
+    return;
+  }
+
+  // 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...
+  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 (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..."),
+                                                track->is_route ? _("Select route to merge with") : _("Select track to merge with"));
+  g_list_free(other_tracks);
+  g_list_free(other_tracks_names);
+
+  if (merge_list)
+  {
+    GList *l;
+    for (l = merge_list; l != NULL; l = g_list_next(l)) {
+      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;
+        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);
+      }
+    }
+    /* TODO: free data before free merge_list */
+    for (l = merge_list; l != NULL; l = g_list_next(l))
+      g_free(l->data);
+    g_list_free(merge_list);
+    vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+  }
+}
+
+// c.f. trw_layer_sorted_track_id_by_name_list
+//  but don't add the specified track to the list (normally current track)
+static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer id, const VikTrack *trk, gpointer udata)
+{
+  twt_udata *user_data = udata;
+
+  // Skip self
+  if (trk->trackpoints == user_data->exclude) {
+    return;
+  }
+
+  // Sort named list alphabetically
+  *(user_data->result) = g_list_insert_sorted_with_data (*(user_data->result), trk->name, sort_alphabetically, NULL);
+}
+
+/**
+ * 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
+ */
+static void trw_layer_append_track ( gpointer pass_along[6] )
+{
+
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  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;
+
+  // 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_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,
+                                                 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);
+
+  // 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...
+      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;
+        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))
+      g_free(l->data);
+    g_list_free(append_list);
+    vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+  }
+}
+
+/* merge by segments */
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  guint segments = vik_track_merge_segments ( trk );
+  // NB currently no need to redraw as segments not actually shown on the display
+  // However inform the user of what happened:
+  gchar str[64];
+  const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
+  g_snprintf(str, 64, tmp_str, segments);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
+}
+
+/* merge by time routine */
+static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+
+  //time_t t1, t2;
+
+  GList *tracks_with_timestamp = NULL;
+  VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  if (orig_trk->trackpoints &&
+      !VIK_TRACKPOINT(orig_trk->trackpoints->data)->has_timestamp) {
+    a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
+    return;
+  }
+
+  twt_udata udata;
+  udata.result = &tracks_with_timestamp;
+  udata.exclude = orig_trk->trackpoints;
+  udata.with_timestamps = TRUE;
+  g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
+  tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
+
+  if (!tracks_with_timestamp) {
+    a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
+    return;
+  }
+  g_list_free(tracks_with_timestamp);
+
+  static guint threshold_in_minutes = 1;
+  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                               _("Merge Threshold..."),
+                               _("Merge when time between tracks less than:"),
+                               &threshold_in_minutes)) {
+    return;
+  }
+
+  // keep attempting to merge all tracks until no merges within the time specified is possible
+  gboolean attempt_merge = TRUE;
+  GList *nearby_tracks = NULL;
+  GList *trps;
+  static gpointer params[3];
+
+  while ( attempt_merge ) {
+
+    // Don't try again unless tracks have changed
+    attempt_merge = FALSE;
+
+    trps = orig_trk->trackpoints;
+    if ( !trps )
+      return;
+
+    if (nearby_tracks) {
+      g_list_free(nearby_tracks);
+      nearby_tracks = NULL;
+    }
+
+    //t1 = ((VikTrackpoint *)trps->data)->timestamp;
+    //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
+    
+    /*    g_print("Original track times: %d and %d\n", t1, t2);  */
+    params[0] = &nearby_tracks;
+    params[1] = (gpointer)trps;
+    params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
+
+    /* get a list of adjacent-in-time tracks */
+    g_hash_table_foreach(vtl->tracks, find_nearby_tracks_by_time, params);
+
+    /* merge them */
+    GList *l = nearby_tracks;
+    while ( l ) {
+       /*
+#define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data)
+#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data)
+        time_t t1, t2;
+        t1 = get_first_trackpoint(l)->timestamp;
+        t2 = get_last_trackpoint(l)->timestamp;
+#undef get_first_trackpoint
+#undef get_last_trackpoint
+        g_print("     %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2);
+       */
+
+      /* remove trackpoints from merged track, delete track */
+      orig_trk->trackpoints = g_list_concat(orig_trk->trackpoints, VIK_TRACK(l->data)->trackpoints);
+      VIK_TRACK(l->data)->trackpoints = NULL;
+      vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
+
+      // Tracks have changed, therefore retry again against all the remaining tracks
+      attempt_merge = TRUE;
+
+      l = g_list_next(l);
+    }
+
+    orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
+  }
+
+  g_list_free(nearby_tracks);
+  vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+}
+
+/**
+ * Split a track at the currently selected trackpoint
+ */
+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, subtype, vtl->current_tp_track->name);
+    if ( name ) {
+      VikTrack *tr = vik_track_new ();
+      GList *newglist = g_list_alloc ();
+      newglist->prev = NULL;
+      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;
+
+      vtl->current_tpl = newglist; /* change tp to first of new track. */
+      vtl->current_tp_track = 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;
+      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
+        vtl->current_tp_id = NULL;
+
+      vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
+    }
+  }
+}
+
+/* split by time routine */
+static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  GList *trps = track->trackpoints;
+  GList *iter;
+  GList *newlists = NULL;
+  GList *newtps = NULL;
+  static guint thr = 1;
+
+  time_t ts, prev_ts;
+
+  if ( !trps )
+    return;
+
+  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
+                              _("Split Threshold..."), 
+                              _("Split when time between trackpoints exceeds:"), 
+                              &thr)) {
+    return;
+  }
+
+  /* iterate through trackpoints, and copy them into new lists without touching original list */
+  prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
+  iter = trps;
+
+  while (iter) {
+    ts = VIK_TRACKPOINT(iter->data)->timestamp;
+    if (ts < prev_ts) {
+      g_print("panic: ts < prev_ts: this should never happen!\n");
+      return;
+    }
+    if (ts - prev_ts > thr*60) {
+      /* flush accumulated trackpoints into new list */
+      newlists = g_list_append(newlists, g_list_reverse(newtps));
+      newtps = NULL;
+    }
+
+    /* accumulate trackpoint copies in newtps, in reverse order */
+    newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
+    prev_ts = ts;
+    iter = g_list_next(iter);
+  }
+  if (newtps) {
+      newlists = g_list_append(newlists, g_list_reverse(newtps));
+  }
+
+  /* put lists of trackpoints into tracks */
+  iter = newlists;
+  // Only bother updating if the split results in new tracks
+  if (g_list_length (newlists) > 1) {
+    while (iter) {
+      gchar *new_tr_name;
+      VikTrack *tr;
+
+      tr = vik_track_new();
+      tr->visible = track->visible;
+      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);
+      /*    g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
+         VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
+
+      iter = g_list_next(iter);
+    }
+    // Remove original track and then update the display
+    vik_trw_layer_delete_track (vtl, track);
+    vik_layer_emit_update(VIK_LAYER(pass_along[0]), FALSE);
+  }
+  g_list_free(newlists);
+}
+
+/**
+ * Split a track by the number of points as specified by the user
+ */
+static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
+{
+  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;
+
+  // Check valid track
+  GList *trps = track->trackpoints;
+  if ( !trps )
+    return;
+
+  gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
+                                            _("Split Every Nth Point"),
+                                            _("Split on every Nth point:"),
+                                            250,   // Default value as per typical limited track capacity of various GPS devices
+                                            2,     // Min
+                                            65536, // Max
+                                            5);    // Step
+  // Was a valid number returned?
+  if (!points)
+    return;
+
+  // Now split...
+  GList *iter;
+  GList *newlists = NULL;
+  GList *newtps = NULL;
+  gint count = 0;
+  iter = trps;
+
+  while (iter) {
+    /* accumulate trackpoint copies in newtps, in reverse order */
+    newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
+    count++;
+    if (count >= points) {
+      /* flush accumulated trackpoints into new list */
+      newlists = g_list_append(newlists, g_list_reverse(newtps));
+      newtps = NULL;
+      count = 0;
+    }
+    iter = g_list_next(iter);
+  }
+
+  // If there is a remaining chunk put that into the new split list
+  // This may well be the whole track if no split points were encountered
+  if (newtps) {
+      newlists = g_list_append(newlists, g_list_reverse(newtps));
+  }
+
+  /* put lists of trackpoints into tracks */
+  iter = newlists;
+  // Only bother updating if the split results in new tracks
+  if (g_list_length (newlists) > 1) {
+    while (iter) {
+      gchar *new_tr_name;
+      VikTrack *tr;
+
+      tr = vik_track_new();
+      tr->visible = track->visible;
+      tr->is_route = track->is_route;
+      tr->trackpoints = (GList *)(iter->data);
+
+      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
+    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);
+}
+
+/**
+ * Split a track at the currently selected trackpoint
+ */
+static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  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 = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !trk )
+    return;
+
+  guint ntracks;
+
+  VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
+  gchar *new_tr_name;
+  guint i;
+  for ( i = 0; i < ntracks; i++ ) {
+    if ( tracks[i] ) {
+      new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, trk->name);
+      vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
+    }
+  }
+  if ( tracks ) {
+    g_free ( tracks );
+    // Remove original track
+    vik_trw_layer_delete_track ( vtl, trk );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+  }
+  else {
+    a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments"));
+  }
+}
+/* end of split/merge routines */
+
+/**
+ * Delete adjacent track points at the same position
+ * AKA Delete Dulplicates on the Properties Window
+ */
+static void trw_layer_delete_points_same_position ( 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;
+
+  gulong removed = vik_track_remove_dup_points ( trk );
+
+  // Track has been updated so update tps:
+  trw_layer_cancel_tps_of_track ( vtl, trk );
+
+  // Inform user how much was deleted as it's not obvious from the normal view
+  gchar str[64];
+  const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
+  g_snprintf(str, 64, tmp_str, removed);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
+
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+}
+
+/**
+ * Delete adjacent track points with the same timestamp
+ * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
+ */
+static void trw_layer_delete_points_same_time ( 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;
+
+  gulong removed = vik_track_remove_same_time_points ( trk );
+
+  // Track has been updated so update tps:
+  trw_layer_cancel_tps_of_track ( vtl, trk );
 
 
-  vtl->current_track = track;
-  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK);
+  // Inform user how much was deleted as it's not obvious from the normal view
+  gchar str[64];
+  const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
+  g_snprintf(str, 64, tmp_str, removed);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
 
 
-  if ( track->trackpoints )
-    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
 }
 
 /**
 }
 
 /**
- * extend a track using magic scissors
+ * Reverse a track
  */
  */
-static void trw_layer_extend_track_end_ms ( gpointer pass_along[6] )
+static void trw_layer_reverse ( 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] );
-  VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->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] );
 
 
-  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, NUM_TOOLS );
-  vtl->magic_scissors_coord =  last_coord;
-  vtl->magic_scissors_current_track = track;
-  vtl->magic_scissors_started = TRUE;
+  if ( ! track )
+    return;
 
 
-  if ( track->trackpoints )
-    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &last_coord) ;
+  // Check valid track
+  GList *trps = track->trackpoints;
+  if ( !trps )
+    return;
 
 
+  vik_track_reverse ( track );
+  vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE );
 }
 
 }
 
-static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
+/**
+ * Similar to trw_layer_enum_item, but this uses a sorted method
+ */
+/* Currently unused
+static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata)
 {
 {
-  /* TODO: check & warn if no DEM data, or no applicable DEM data. */
-  /* Also warn if overwrite old elevation data */
-  VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
-
-  vik_track_apply_dem_data ( track );
+  GList **list = (GList**)udata;
+  // *list = g_list_prepend(*all, key); //unsorted method
+  // Sort named list alphabetically
+  *list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL);
 }
 }
+*/
 
 
-static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
+/**
+ * Now Waypoint specific sort
+ */
+static void trw_layer_sorted_wp_id_by_name_list (const gpointer id, const VikWaypoint *wp, gpointer udata)
 {
 {
-  GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
-  if ( !trps )
-    return;
-  trps = g_list_last(trps);
-  goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *) trps->data)->coord));
+  GList **list = (GList**)udata;
+  // Sort named list alphabetically
+  *list = g_list_insert_sorted_with_data (*list, wp->name, sort_alphabetically, NULL);
 }
 
 }
 
-static void trw_layer_goto_track_max_speed ( gpointer pass_along[5] )
+/**
+ * Track specific sort
+ */
+static void trw_layer_sorted_track_id_by_name_list (const gpointer id, const VikTrack *trk, gpointer udata)
 {
 {
-  VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
-  if ( !vtp )
-    return;
-  goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(vtp->coord));
+  GList **list = (GList**)udata;
+  // Sort named list alphabetically
+  *list = g_list_insert_sorted_with_data (*list, trk->name, sort_alphabetically, NULL);
 }
 
 }
 
-static void trw_layer_goto_track_max_alt ( gpointer pass_along[5] )
-{
-  VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
-  if ( !vtp )
-    return;
-  goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(vtp->coord));
-}
 
 
-static void trw_layer_goto_track_min_alt ( gpointer pass_along[5] )
-{
-  VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
-  if ( !vtp )
-    return;
-  goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(vtp->coord));
-}
+typedef struct {
+  gboolean    has_same_track_name;
+  const gchar *same_track_name;
+} same_track_name_udata;
 
 
-/* 
- * Automatically change the viewport to center on the track and zoom to see the extent of the track
- */ 
-static void trw_layer_auto_track_view ( gpointer pass_along[5] )
+static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
 {
 {
-  GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
-  if ( trps && *trps )
-  {
-    struct LatLon maxmin[2] = { {0,0}, {0,0} };
-    trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
+  const gchar* namea = (const gchar*) aa;
+  const gchar* nameb = (const gchar*) bb;
+
+  // the test
+  gint result = strcmp ( namea, nameb );
 
 
-    trw_layer_zoom_to_show_latlons ( VIK_TRW_LAYER(pass_along[0]), vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(pass_along[1])), maxmin );
-    vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
+  if ( result == 0 ) {
+    // Found two names the same
+    same_track_name_udata *user_data = udata;
+    user_data->has_same_track_name = TRUE;
+    user_data->same_track_name = namea;
   }
   }
-}
 
 
-/*************************************
- * merge/split by time routines 
- *************************************/
+  // Leave ordering the same
+  return 0;
+}
 
 
-/* called for each key in track hash table.
- * If the current track has time stamp, add it to the result,
- * except the one pointed by "exclude".
- * set exclude to NULL if there is no exclude to check.
- * Not that result is in reverse (for performance reason).
+/**
+ * Find out if any tracks have the same name in this hash table
  */
  */
-typedef struct {
-  GList **result;
-  GList  *exclude;
-} twt_udata;
-static void find_tracks_with_timestamp(gpointer key, gpointer value, gpointer udata)
+static gboolean trw_layer_has_same_track_names ( GHashTable *ht_tracks )
 {
 {
-  twt_udata *user_data = udata;
-  VikTrackpoint *p1, *p2;
+  // Sort items by name, then compare if any next to each other are the same
 
 
-  if (VIK_TRACK(value)->trackpoints == user_data->exclude) {
-    return;
-  }
+  GList *track_names = NULL;
+  g_hash_table_foreach ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
 
 
-  if (VIK_TRACK(value)->trackpoints) {
-    p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
-    p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+  // No tracks
+  if ( ! track_names )
+    return FALSE;
 
 
-    if (!p1->has_timestamp || !p2->has_timestamp) {
-      g_print("no timestamp\n");
-      return;
-    }
+  same_track_name_udata udata;
+  udata.has_same_track_name = FALSE;
 
 
-  }
+  // Use sort routine to traverse list comparing items
+  // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
+  GList *dummy_list = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
+  // Still no tracks...
+  if ( ! dummy_list )
+    return FALSE;
 
 
-  *(user_data->result) = g_list_prepend(*(user_data->result), key);
+  return udata.has_same_track_name;
 }
 
 }
 
-/* called for each key in track hash table. if original track user_data[1] is close enough
- * to the passed one, add it to list in user_data[0] 
+/**
+ * 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 find_nearby_track(gpointer key, gpointer value, gpointer user_data)
+static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp, GHashTable *track_table, gboolean ontrack )
 {
 {
-  time_t t1, t2;
-  VikTrackpoint *p1, *p2;
+  // . Search list for an instance of repeated name
+  // . get track of this name
+  // . create new name
+  // . rename track & update equiv. treeview iter
+  // . repeat until all different
 
 
-  GList **nearby_tracks = ((gpointer *)user_data)[0];
-  GList *orig_track = ((gpointer *)user_data)[1];
-  guint thr = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
+  same_track_name_udata udata;
 
 
-  /* outline: 
-   * detect reasons for not merging, and return
-   * if no reason is found not to merge, then do it.
-   */
+  GList *track_names = NULL;
+  udata.has_same_track_name = FALSE;
+  udata.same_track_name = NULL;
+
+  g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
 
 
-  if (VIK_TRACK(value)->trackpoints == orig_track) {
+  // No tracks
+  if ( ! track_names )
     return;
     return;
-  }
 
 
-  t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
-  t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
+  GList *dummy_list1 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
 
 
-  if (VIK_TRACK(value)->trackpoints) {
-    p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
-    p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+  // Still no tracks...
+  if ( ! dummy_list1 )
+    return;
 
 
-    if (!p1->has_timestamp || !p2->has_timestamp) {
-      g_print("no timestamp\n");
-      return;
-    }
+  while ( udata.has_same_track_name ) {
 
 
-    /*  g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
-    if (! (abs(t1 - p2->timestamp) < thr*60 ||
-       /*  p1 p2      t1 t2 */
-          abs(p1->timestamp - t2) < thr*60)
-       /*  t1 t2      p1 p2 */
-       ) {
+    // Find a track with the same 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 :(
+      g_critical("Houston, we've had a problem.");
+      vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
+                                  _("Internal Error in vik_trw_layer_uniquify_tracks") );
       return;
     }
       return;
     }
-  }
 
 
-  *nearby_tracks = g_list_prepend(*nearby_tracks, key);
-}
+    // Rename it
+    gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, udata.same_track_name );
+    vik_track_set_name ( trk, newname );
 
 
-/* comparison function used to sort tracks; a and b are hash table keys */
-static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-  GHashTable *tracks = user_data;
-  time_t t1, t2;
+    trku_udata udataU;
+    udataU.trk  = trk;
+    udataU.uuid = NULL;
 
 
-  t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
-  t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
-  
-  if (t1 < t2) return -1;
-  if (t1 > t2) return 1;
-  return 0;
-}
+    // Need want key of it for treeview update
+    gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
 
 
-/* comparison function used to sort trackpoints */
-static gint trackpoint_compare(gconstpointer a, gconstpointer b)
-{
-  time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
-  
-  if (t1 < t2) return -1;
-  if (t1 > t2) return 1;
-  return 0;
-}
+    if ( trkf && 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 );
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-/**
- * comparison function which can be used to sort tracks or waypoints by name
- */
-static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user_data)
-{
-  const gchar* namea = (const gchar*) a;
-  const gchar* nameb = (const gchar*) b;
-  if ( namea == NULL || nameb == NULL)
-    return 0;
-  else
-    // Same sort method as used in the vik_treeview_*_alphabetize functions
-    return strcmp ( namea, nameb );
-}
+        vik_treeview_sublayer_realphabetize ( VIK_LAYER(vtl)->vt, it, newname );
 #endif
 #endif
+      }
+    }
 
 
-static void trw_layer_merge_with_other ( gpointer pass_along[6] )
-{
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  gchar *orig_track_name = pass_along[3];
-  GList *tracks_with_timestamp = NULL;
-  VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
+    // Start trying to find same names again...
+    track_names = NULL;
+    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 );
 
 
-  if (track->trackpoints &&
-      !VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp) {
-    a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
-    return;
+    // No tracks any more - give up searching
+    if ( ! dummy_list2 )
+      udata.has_same_track_name = FALSE;
   }
 
   }
 
-  if (1) {
+  // Update
+  vik_layers_panel_emit_update ( vlp );
+}
+
+/**
+ *
+ */
+static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  GList *all = NULL;
 
 
-    twt_udata udata;
-    udata.result = &tracks_with_timestamp;
-    udata.exclude = track->trackpoints;
-    g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp, (gpointer)&udata);
-    tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
+  // Ensure list of track names offered is unique
+  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]), vtl->tracks, TRUE );
+    }
+    else
+      return;
   }
 
   }
 
-  if (!tracks_with_timestamp) {
-    a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
+  // Sort list alphabetically for better presentation
+  g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
+
+  if ( ! all ) {
+    a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl),        _("No tracks found"));
     return;
   }
 
     return;
   }
 
-  GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
-      tracks_with_timestamp, TRUE,
-      _("Merge with..."), _("Select track to merge with"));
-  g_list_free(tracks_with_timestamp);
+  // 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 tracks to delete"));
+  g_list_free(all);
 
 
-  if (merge_list)
-  {
+  // Delete requested tracks
+  // since specificly requested, IMHO no need for extra confirmation
+  if ( delete_list ) {
     GList *l;
     GList *l;
-    for (l = merge_list; l != NULL; l = g_list_next(l)) {
-      VikTrack *merge_track = (VikTrack *) g_hash_table_lookup (vtl->tracks, 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, l->data);
-        track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
-      }
+    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, vtl->tracks);
     }
     }
-    /* TODO: free data before free merge_list */
-    for (l = merge_list; l != NULL; l = g_list_next(l))
-      g_free(l->data);
-    g_list_free(merge_list);
-    vik_layer_emit_update( VIK_LAYER(vtl) );
+    g_list_free(delete_list);
+    vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
   }
 }
 
   }
 }
 
-/* merge by time routine */
-static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
+/**
+ *
+ */
+static void trw_layer_delete_routes_from_selection ( gpointer lav[2] )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  gchar *orig_track_name = strdup(pass_along[3]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  GList *all = NULL;
 
 
-  time_t t1, t2;
-  GList *nearby_tracks;
-  VikTrack *track;
-  GList *trps;
-  static  guint thr = 1;
-  guint track_count = 0;
+  // 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;
+  }
 
 
-  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl), 
-                              _("Merge Threshold..."), 
-                              _("Merge when time between tracks less than:"), 
-                              &thr)) {
-    free(orig_track_name);
+  // 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;
   }
 
     return;
   }
 
-  /* merge tracks until we can't */
-  nearby_tracks = NULL;
-  do {
-    gpointer params[3];
+  // 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);
 
 
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
-    trps = track->trackpoints;
-    if ( !trps )
-      return;
+  // 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 );
+  }
+}
 
 
+typedef struct {
+  gboolean    has_same_waypoint_name;
+  const gchar *same_waypoint_name;
+} same_waypoint_name_udata;
 
 
-    if (nearby_tracks) {
-      g_list_free(nearby_tracks);
-      nearby_tracks = NULL;
-    }
+static gint check_waypoints_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
+{
+  const gchar* namea = (const gchar*) aa;
+  const gchar* nameb = (const gchar*) bb;
 
 
-    t1 = ((VikTrackpoint *)trps->data)->timestamp;
-    t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
-    
-    /*    g_print("Original track times: %d and %d\n", t1, t2);  */
-    params[0] = &nearby_tracks;
-    params[1] = trps;
-    params[2] = GUINT_TO_POINTER (thr);
+  // the test
+  gint result = strcmp ( namea, nameb );
 
 
-    /* get a list of adjacent-in-time tracks */
-    g_hash_table_foreach(vtl->tracks, find_nearby_track, (gpointer)params);
+  if ( result == 0 ) {
+    // Found two names the same
+    same_waypoint_name_udata *user_data = udata;
+    user_data->has_same_waypoint_name = TRUE;
+    user_data->same_waypoint_name = namea;
+  }
 
 
-    /* add original track */
-    nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name);
+  // Leave ordering the same
+  return 0;
+}
 
 
-    /* merge them */
-    { 
-#define get_track(x) VIK_TRACK(g_hash_table_lookup(vtl->tracks, (gchar *)((x)->data)))
-#define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
-#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
-      GList *l = nearby_tracks;
-      VikTrack *tr = vik_track_new();
-      tr->visible = track->visible;
-      track_count = 0;
-      while (l) {
-       /*
-       time_t t1, t2;
-       t1 = get_first_trackpoint(l)->timestamp;
-       t2 = get_last_trackpoint(l)->timestamp;
-       g_print("     %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
-       */
+/**
+ * Find out if any waypoints have the same name in this layer
+ */
+gboolean trw_layer_has_same_waypoint_names ( VikTrwLayer *vtl )
+{
+  // Sort items by name, then compare if any next to each other are the same
 
 
+  GList *waypoint_names = NULL;
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
 
 
-       /* remove trackpoints from merged track, delete track */
-       tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints);
-       get_track(l)->trackpoints = NULL;
-       vik_trw_layer_delete_track(vtl, l->data);
+  // No waypoints
+  if ( ! waypoint_names )
+    return FALSE;
 
 
-       track_count ++;
-       l = g_list_next(l);
-      }
-      tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare);
-      vik_trw_layer_add_track(vtl, strdup(orig_track_name), tr);
+  same_waypoint_name_udata udata;
+  udata.has_same_waypoint_name = FALSE;
 
 
-#undef get_first_trackpoint
-#undef get_last_trackpoint
-#undef get_track
-    }
-  } while (track_count > 1);
-  g_list_free(nearby_tracks);
-  free(orig_track_name);
-  vik_layer_emit_update( VIK_LAYER(vtl) );
+  // Use sort routine to traverse list comparing items
+  // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
+  GList *dummy_list = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+  // Still no waypoints...
+  if ( ! dummy_list )
+    return FALSE;
+
+  return udata.has_same_waypoint_name;
 }
 
 }
 
-/* split by time routine */
-static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
+/**
+ * Force unqiue waypoint names for this layer
+ * Note the panel is a required parameter to enable the update of the names displayed
+ */
+static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel *vlp )
 {
 {
-  VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
-  GList *trps = track->trackpoints;
-  GList *iter;
-  GList *newlists = NULL;
-  GList *newtps = NULL;
-  guint i;
-  static guint thr = 1;
+  // . Search list for an instance of repeated name
+  // . get waypoint of this name
+  // . create new name
+  // . rename waypoint & update equiv. treeview iter
+  // . repeat until all different
 
 
-  time_t ts, prev_ts;
+  same_waypoint_name_udata udata;
 
 
-  if ( !trps )
+  GList *waypoint_names = NULL;
+  udata.has_same_waypoint_name = FALSE;
+  udata.same_waypoint_name = NULL;
+
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+
+  // No waypoints
+  if ( ! waypoint_names )
     return;
 
     return;
 
-  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
-                              _("Split Threshold..."), 
-                              _("Split when time between trackpoints exceeds:"), 
-                              &thr)) {
+  GList *dummy_list1 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+
+  // Still no waypoints...
+  if ( ! dummy_list1 )
     return;
     return;
-  }
 
 
-  /* iterate through trackpoints, and copy them into new lists without touching original list */
-  prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
-  iter = trps;
+  while ( udata.has_same_waypoint_name ) {
 
 
-  while (iter) {
-    ts = VIK_TRACKPOINT(iter->data)->timestamp;
-    if (ts < prev_ts) {
-      g_print("panic: ts < prev_ts: this should never happen!\n");
+    // Find a waypoint with the same name
+    VikWaypoint *waypoint = vik_trw_layer_get_waypoint ( vtl, (gpointer) udata.same_waypoint_name );
+
+    if ( ! waypoint ) {
+      // Broken :(
+      g_critical("Houston, we've had a problem.");
+      vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
+                                  _("Internal Error in vik_trw_layer_uniquify_waypoints") );
       return;
     }
       return;
     }
-    if (ts - prev_ts > thr*60) {
-      /* flush accumulated trackpoints into new list */
-      newlists = g_list_prepend(newlists, g_list_reverse(newtps));
-      newtps = NULL;
+
+    // Rename it
+    gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, udata.same_waypoint_name );
+    vik_waypoint_set_name ( waypoint, newname );
+
+    wpu_udata udataU;
+    udataU.wp   = waypoint;
+    udataU.uuid = NULL;
+
+    // Need want key of it for treeview update
+    gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+
+    if ( wpf && udataU.uuid ) {
+
+      GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
+
+      if ( it ) {
+        vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+        vik_treeview_sublayer_realphabetize ( VIK_LAYER(vtl)->vt, it, newname );
+#endif
+      }
     }
 
     }
 
-    /* accumulate trackpoint copies in newtps, in reverse order */
-    newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
-    prev_ts = ts;
-    iter = g_list_next(iter);
-  }
-  if (newtps) {
-      newlists = g_list_prepend(newlists, g_list_reverse(newtps));
+    // Start trying to find same names again...
+    waypoint_names = NULL;
+    g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+    udata.has_same_waypoint_name = FALSE;
+    GList *dummy_list2 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+
+    // No waypoints any more - give up searching
+    if ( ! dummy_list2 )
+      udata.has_same_waypoint_name = FALSE;
   }
 
   }
 
-  /* put lists of trackpoints into tracks */
-  iter = newlists;
-  i = 1;
-  while (iter) {
-    gchar *new_tr_name;
-    VikTrack *tr;
+  // Update
+  vik_layers_panel_emit_update ( vlp );
+}
 
 
-    tr = vik_track_new();
-    tr->visible = track->visible;
-    tr->trackpoints = (GList *)(iter->data);
+/**
+ *
+ */
+static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  GList *all = NULL;
 
 
-    new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
-    vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
-    /*    g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
-         VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
+  // Ensure list of waypoint names offered is unique
+  if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
+    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_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) );
+    }
+    else
+      return;
+  }
 
 
-    iter = g_list_next(iter);
+  // Sort list alphabetically for better presentation
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all);
+  if ( ! all ) {
+    a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl),        _("No waypoints found"));
+    return;
   }
   }
-  g_list_free(newlists);
-  vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
-  vik_layer_emit_update(VIK_LAYER(pass_along[0]));
-}
 
 
-/* end of split/merge routines */
+  all = g_list_sort_with_data(all, sort_alphabetically, NULL);
+
+  // 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 waypoints to delete"));
+  g_list_free(all);
+
+  // Delete requested waypoints
+  // 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 waypoint it finds of that name (but uniqueness is enforced above)
+      trw_layer_delete_waypoint_by_name (vtl, l->data);
+    }
+    g_list_free(delete_list);
+    vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+  }
 
 
+}
 
 
-static void trw_layer_goto_waypoint ( gpointer pass_along[5] )
+static void trw_layer_goto_waypoint ( gpointer pass_along[6] )
 {
   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
   if ( wp )
 {
   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
   if ( wp )
-    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(wp->coord) );
+    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(wp->coord) );
 }
 
 }
 
-static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] )
+static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] )
 {
   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] );
   open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
   g_free ( webpage );
 }
 
 {
   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] );
   open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
   g_free ( webpage );
 }
 
-const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
+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 )
   {
 {
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
-    gchar *rv;
-    VikWaypoint *wp;
+    VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
 
 
-    if (strcmp(newname, sublayer) == 0 )
+    // No actual change to the name supplied
+    if (strcmp(newname, wp->name) == 0 )
       return NULL;
 
       return NULL;
 
-    if (strcasecmp(newname, sublayer)) { /* Not just changing case */
-      if (g_hash_table_lookup( l->waypoints, newname))
-      {
-        a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Waypoint Already Exists") );
+    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;
         return NULL;
-      }
     }
 
     }
 
-    iter = g_hash_table_lookup ( l->waypoints_iters, sublayer );
-    g_hash_table_steal ( l->waypoints_iters, sublayer );
-
-    wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) );
-    highest_wp_number_remove_wp(l, sublayer);
-    g_hash_table_remove ( l->waypoints, sublayer );
+    // Update WP name and refresh the treeview
+    vik_waypoint_set_name (wp, newname);
 
 
-    rv = g_strdup(newname);
-
-    vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
-
-    highest_wp_number_add_wp(l, rv);
-    g_hash_table_insert ( l->waypoints, rv, wp );
-    g_hash_table_insert ( l->waypoints_iters, rv, iter );
-
-    /* it hasn't been updated yet so we pass new name */
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-    vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
+    vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname );
 #endif
 
     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
 #endif
 
     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
-    return rv;
+
+    return newname;
   }
   }
+
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
-    gchar *rv;
-    VikTrack *tr;
-    GtkTreeIter *iter;
-    gchar *orig_key;
+    VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
 
 
-    if (strcmp(newname, sublayer) == 0)
+    // No actual change to the name supplied
+    if (strcmp(newname, trk->name) == 0)
       return NULL;
 
       return NULL;
 
-    if (strcasecmp(newname, sublayer)) { /* Not just changing case */
-      if (g_hash_table_lookup( l->tracks, newname))
-      {
-        a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Track Already Exists") );
+    VikTrack *trkf = vik_trw_layer_get_track ( 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 rename to the same name?"),
+          newname ) )
         return NULL;
         return NULL;
-      }
     }
     }
+    // Update track name and refresh GUI parts
+    vik_track_set_name (trk, 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 );
 
 
-    g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
-    g_hash_table_steal ( l->tracks, sublayer );
+#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) );
 
 
-    iter = g_hash_table_lookup ( l->tracks_iters, sublayer );
-    g_hash_table_steal ( l->tracks_iters, sublayer );
+    return newname;
+  }
 
 
-    rv = g_strdup(newname);
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+  {
+    VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer );
 
 
-    vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
+    // No actual change to the name supplied
+    if (strcmp(newname, trk->name) == 0)
+      return NULL;
 
 
-    g_hash_table_insert ( l->tracks, rv, tr );
-    g_hash_table_insert ( l->tracks_iters, rv, iter );
+    VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname );
 
 
-    /* don't forget about current_tp_track_name, update that too */
-    if ( l->current_tp_track_name && g_strcasecmp(orig_key,l->current_tp_track_name) == 0 )
-    {
-      l->current_tp_track_name = rv;
-      if ( l->tpwin )
-        vik_trw_layer_tpwin_set_track_name ( l->tpwin, rv );
+    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 route with the name \"%s\" already exists. Really rename to the same name?"),
+          newname ) )
+        return NULL;
     }
     }
-    else if ( l->last_tp_track_name && g_strcasecmp(orig_key,l->last_tp_track_name) == 0 )
-      l->last_tp_track_name = rv;
+    // Update track name and refresh GUI parts
+    vik_track_set_name (trk, newname);
 
 
-    g_free ( orig_key );
+    // 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
 
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
-    vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
+    vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname );
 #endif
 
     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
 #endif
 
     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
-    return rv;
+
+    return newname;
   }
   return NULL;
 }
   }
   return NULL;
 }
@@ -3098,23 +5847,22 @@ static gboolean is_valid_geocache_name ( gchar *str )
   return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
 }
 
   return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
 }
 
-static void trw_layer_track_use_with_filter ( gpointer *pass_along )
+static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
 {
 {
-  gchar *track_name = (gchar *) pass_along[3];
-  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
-  a_acquire_set_filter_track ( tr, track_name );
+  VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  a_acquire_set_filter_track ( trk );
 }
 
 }
 
-static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name )
+#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_name );
+  VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_id );
   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
 }
 
   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
 }
 
-static void trw_layer_track_google_route_webpage( gpointer *pass_along )
+static void trw_layer_track_google_route_webpage ( gpointer pass_along[6] )
 {
 {
-  gchar *track_name = (gchar *) pass_along[3];
-  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
+  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
   if ( tr ) {
     gchar *escaped = uri_escape ( tr->comment );
     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
   if ( tr ) {
     gchar *escaped = uri_escape ( tr->comment );
     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
@@ -3123,12 +5871,13 @@ static void trw_layer_track_google_route_webpage( gpointer *pass_along )
     g_free ( webpage );
   }
 }
     g_free ( webpage );
   }
 }
+#endif
 
 
-/* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
-gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
+/* vlp can be NULL if necessary - i.e. right-click from a tool */
+/* viewpoint is now available instead */
+static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
 {
 {
-  static GtkTreeIter staticiter;
-  static gpointer pass_along[5];
+  static gpointer pass_along[8];
   GtkWidget *item;
   gboolean rv = FALSE;
 
   GtkWidget *item;
   gboolean rv = FALSE;
 
@@ -3136,10 +5885,12 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
   pass_along[1] = vlp;
   pass_along[2] = GINT_TO_POINTER (subtype);
   pass_along[3] = sublayer;
   pass_along[1] = vlp;
   pass_along[2] = GINT_TO_POINTER (subtype);
   pass_along[3] = sublayer;
-  staticiter = *iter; /* will exist after function has ended */
-  pass_along[4] = &staticiter;
+  pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
+  pass_along[5] = vvp;
+  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;
 
   {
     rv = TRUE;
 
@@ -3149,8 +5900,12 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
     gtk_widget_show ( item );
 
     if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
     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 );
     }
       if (tr && tr->property_dialog)
         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
     }
@@ -3182,152 +5937,531 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
 
        separator_created = TRUE;
 
 
        separator_created = TRUE;
 
-        item = gtk_menu_item_new_with_mnemonic ( _("_Goto") );
+        item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
+       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
         gtk_widget_show ( item );
       }
 
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
         gtk_widget_show ( item );
       }
 
-      if ( is_valid_geocache_name ( (gchar *) sublayer ) )
+      VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
+
+      if ( wp && wp->name ) {
+        if ( is_valid_geocache_name ( wp->name ) ) {
+
+          if ( !separator_created ) {
+            item = gtk_menu_item_new ();
+            gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+            gtk_widget_show ( item );
+            separator_created = TRUE;
+          }
+
+          item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
+          g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
+          gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+          gtk_widget_show ( item );
+        }
+      }
+
+      if ( wp && wp->image )
       {
        if ( !separator_created ) {
          item = gtk_menu_item_new ();
          gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
          gtk_widget_show ( item );
       {
        if ( !separator_created ) {
          item = gtk_menu_item_new ();
          gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
          gtk_widget_show ( item );
+         separator_created = TRUE;
        }
 
        }
 
-        item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
-        g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
+       // Set up image paramater
+       pass_along[5] = wp->image;
+
+        item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
+       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
+        g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along );
         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
+       GtkWidget *geotag_submenu = gtk_menu_new ();
+       item = gtk_image_menu_item_new_with_mnemonic ( _("Update Geotag on _Image") );
+       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, 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), geotag_submenu );
+  
+       item = gtk_menu_item_new_with_mnemonic ( _("_Update") );
+       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_update), pass_along );
+       gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
+       gtk_widget_show ( item );
+
+       item = gtk_menu_item_new_with_mnemonic ( _("Update and _Keep File Timestamp") );
+       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_keep), pass_along );
+       gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
+       gtk_widget_show ( item );
+#endif
       }
 
     }
   }
 
       }
 
     }
   }
 
+  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) )
   {
   if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
   {
-    item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint") );
+    rv = TRUE;
+    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_widget_show ( item );
   }
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
     gtk_widget_show ( item );
   }
 
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS )
+  {
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
+    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_waypoints_view), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") );
+    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_waypoints), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Waypoints 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_waypoints_from_selection), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+  }
+
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS )
+  {
+    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 );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Tracks 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_tracks_from_selection), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+  }
+
+  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 )
   {
   {
-    GtkWidget *goto_submenu;
     item = gtk_menu_item_new ();
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     item = gtk_menu_item_new ();
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
+    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 );
+    gtk_widget_show ( item );
+
+    GtkWidget *goto_submenu;
     goto_submenu = gtk_menu_new ();
     goto_submenu = gtk_menu_new ();
-    item = gtk_menu_item_new_with_mnemonic ( _("_Goto") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, 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), goto_submenu );
 
     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
     gtk_widget_show ( item );
     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), goto_submenu );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Startpoint") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Startpoint") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("\"_Center\"") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("\"_Center\"") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Endpoint") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Endpoint") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
-    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 );
+    }
 
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_View Track") );
-    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 );
+    GtkWidget *combine_submenu;
+    combine_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Co_mbine") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU) );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
     gtk_widget_show ( item );
     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(menu), 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 );
 
     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(menu), item );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
     gtk_widget_show ( item );
 
     gtk_widget_show ( item );
 
-    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(menu), item );
+    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 );
+
+    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 );
+
+    GtkWidget *split_submenu;
+    split_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Split") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, 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), split_submenu );
+
+    // 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 );
+
+    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 );
+    gtk_widget_show ( item );
+    // Make it available only when a trackpoint is selected.
+    gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
+
+    GtkWidget *delete_submenu;
+    delete_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, 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), delete_submenu );
+
+    item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
     gtk_widget_show ( item );
 
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
+    item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Time") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_time), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+    gtk_widget_show ( item );
+
+    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 );
     gtk_widget_show ( item );
 
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
+    /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
+    if ( vlp ) {
+      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 );
+      gtk_widget_show ( item );
+    }
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("DEM Download/Import", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_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 );
 
     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_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 );
 
     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 );
 
-    item = gtk_menu_item_new_with_mnemonic ( _("Extend _Using Magic Scissors") );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_ms), pass_along );
+    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 );
     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 );
+#endif
+
+    // 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
 #ifdef VIK_CONFIG_OPENSTREETMAP
-    item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM") );
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
+    // Convert internal pointer into actual track for usage outside this file
+    pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer);
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
     gtk_widget_show ( item );
 #endif
 
     gtk_widget_show ( item );
 #endif
 
-    if ( is_valid_google_route ( l, (gchar *) sublayer ) )
+    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 );
+
+#ifdef VIK_CONFIG_GOOGLE
+    if ( is_valid_google_route ( l, sublayer ) )
     {
     {
-      item = gtk_menu_item_new_with_mnemonic ( _("_View Google Directions") );
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along );
       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
       gtk_widget_show ( item );
     }
       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along );
       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
       gtk_widget_show ( item );
     }
+#endif
 
 
-    item = gtk_menu_item_new_with_mnemonic ( _("Use with _Filter") );
+    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) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    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 ) );
-    if ( item ) {
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    /* 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 ) );
+      if ( 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 );
+#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
+      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 ( _("_Edit Trackpoint") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU) );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_edit_trackpoint), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
       gtk_widget_show ( item );
       gtk_widget_show ( item );
-    }  
+    }
   }
 
   return rv;
   }
 
   return rv;
@@ -3378,21 +6512,18 @@ 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 */
     /* 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_track_name );
-    gint index =  g_list_index ( tr->trackpoints, tp_current );
-    if ( index > -1 ) {
-      tr->trackpoints = g_list_insert (tr->trackpoints, tp_new, index+1 );
-    }
-  }
-}
+    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;
 
 
-/* to be called when last_tpl no long exists. */
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
-{
-  if ( vtl->tpwin ) /* can't join with a non-existant TP. */
-    vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
-  vtl->last_tpl = NULL;
-  vtl->last_tp_track_name = NULL;
+    gint index =  g_list_index ( trk->trackpoints, tp_current );
+    if ( index > -1 ) {
+      trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index+1 );
+    }
+  }
 }
 
 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
 }
 
 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
@@ -3410,8 +6541,9 @@ static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
   if ( vtl->current_tpl )
   {
     vtl->current_tpl = NULL;
   if ( vtl->current_tpl )
   {
     vtl->current_tpl = NULL;
-    vtl->current_tp_track_name = NULL;
-    vik_layer_emit_update(VIK_LAYER(vtl));
+    vtl->current_tp_track = NULL;
+    vtl->current_tp_id = NULL;
+    vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
   }
 }
 
   }
 }
 
@@ -3420,123 +6552,71 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
   g_assert ( vtl->tpwin != NULL );
   if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
     trw_layer_cancel_current_tp ( vtl, TRUE );
   g_assert ( vtl->tpwin != NULL );
   if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
     trw_layer_cancel_current_tp ( vtl, TRUE );
-  else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
-  {
-    gchar *name;
-    if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks, NULL ) ) )
-    {
-      VikTrack *tr = vik_track_new ();
-      GList *newglist = g_list_alloc ();
-      newglist->prev = NULL;
-      newglist->next = vtl->current_tpl->next;
-      newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
-      tr->trackpoints = newglist;
-
-      vtl->current_tpl->next->prev = newglist; /* end old track here */
-      vtl->current_tpl->next = NULL;
-
-      vtl->current_tpl = newglist; /* change tp to first of new track. */
-      vtl->current_tp_track_name = name;
 
 
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
-
-      tr->visible = TRUE;
+  if ( vtl->current_tpl == NULL )
+    return;
 
 
-      vik_trw_layer_add_track ( vtl, name, tr );
-      vik_layer_emit_update(VIK_LAYER(vtl));
-    }
+  if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
+  {
+    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 )
   {
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
   {
-    VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
-    GList *new_tpl;
-    g_assert(tr != NULL);
+    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;
 
 
-    /* can't join with a non-existent trackpoint */
-    vtl->last_tpl = NULL;
-    vtl->last_tp_track_name = NULL;
+    GList *new_tpl;
 
 
+    // Find available adjacent trackpoint
     if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
     {
       if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
         VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
 
     if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
     {
       if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
         VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
 
-      tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl ); /* this nulls current_tpl->prev and next */
+      // Delete current trackpoint
+      vik_trackpoint_free ( vtl->current_tpl->data );
+      tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
 
 
-      /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track_name );
+      // Set to current to the available adjacent trackpoint
+      vtl->current_tpl = new_tpl;
 
 
-      trw_layer_cancel_last_tp ( vtl );
+      // Reset dialog with the available adjacent trackpoint
+      if ( vtl->current_tp_track )
+        vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name );
 
 
-      g_free ( vtl->current_tpl->data ); /* TODO: vik_trackpoint_free() */
-      g_list_free_1 ( vtl->current_tpl );
-      vtl->current_tpl = new_tpl;
-      vik_layer_emit_update(VIK_LAYER(vtl));
+      vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
     }
     else
     {
     }
     else
     {
-      tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl );
-      g_free ( vtl->current_tpl->data ); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
-      g_list_free_1 ( vtl->current_tpl );
+      // Delete current trackpoint
+      vik_trackpoint_free ( vtl->current_tpl->data );
+      tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
       trw_layer_cancel_current_tp ( vtl, FALSE );
     }
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
   {
       trw_layer_cancel_current_tp ( vtl, FALSE );
     }
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
   {
-    vtl->last_tpl = vtl->current_tpl;
-    vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track_name );
-    vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
+    if ( vtl->current_tp_track )
+      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name );
+    vik_layer_emit_update(VIK_LAYER(vtl), FALSE); /* TODO longone: either move or only update if tp is inside drawing window */
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
   {
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
   {
-    vtl->last_tpl = vtl->current_tpl;
-    vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track_name );
-    vik_layer_emit_update(VIK_LAYER(vtl));
-  }
-  else if ( response == VIK_TRW_LAYER_TPWIN_JOIN )
-  {
-    VikTrack *tr1 = g_hash_table_lookup ( vtl->tracks, vtl->last_tp_track_name );
-    VikTrack *tr2 = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
-
-    VikTrack *tr_first = tr1, *tr_last = tr2;
-
-    gchar *tmp;
-
-    if ( (!vtl->last_tpl->next) && (!vtl->current_tpl->next) ) /* both endpoints */
-      vik_track_reverse ( tr2 ); /* reverse the second, that way second track clicked will be later. */
-    else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->prev) )
-      vik_track_reverse ( tr1 );
-    else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->next) ) /* clicked startpoint, then endpoint -- concat end to start */
-    {
-      tr_first = tr2;
-      tr_last = tr1;
-    }
-    /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
-
-    if ( tr_last->trackpoints ) /* deleting this part here joins them into 1 segmented track. useful but there's no place in the UI for this feature. segments should be deprecated anyway. */
-      VIK_TRACKPOINT(tr_last->trackpoints->data)->newsegment = FALSE;
-    tr1->trackpoints = g_list_concat ( tr_first->trackpoints, tr_last->trackpoints );
-    tr2->trackpoints = NULL;
-
-    tmp = vtl->current_tp_track_name;
-
-    vtl->current_tp_track_name = vtl->last_tp_track_name; /* current_tp stays the same (believe it or not!) */
-    vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
-
-    /* if we did this before, trw_layer_delete_track would have canceled the current tp because
-     * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
-    vik_trw_layer_delete_track ( vtl, tmp );
-
-    trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
-    vik_layer_emit_update(VIK_LAYER(vtl));
+    if ( vtl->current_tp_track )
+      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name );
+    vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
   {
     trw_layer_insert_tp_after_current_tp ( vtl );
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
   {
     trw_layer_insert_tp_after_current_tp ( vtl );
-    vik_layer_emit_update(VIK_LAYER(vtl));
+    vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
-    vik_layer_emit_update (VIK_LAYER(vtl));
+    vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
 }
 
 static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
 }
 
 static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
@@ -3550,7 +6630,8 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
     gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
   }
   if ( vtl->current_tpl )
     gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
   }
   if ( vtl->current_tpl )
-    vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
+    if ( vtl->current_tp_track )
+      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
   /* set layer name and TP data */
 }
 
   /* set layer name and TP data */
 }
 
@@ -3560,93 +6641,436 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
 
 /*** Utility data structures and functions ****/
 
 
 /*** Utility data structures and functions ****/
 
-typedef struct {
-  gint x, y;
-  gint closest_x, closest_y;
-  gchar *closest_wp_name;
-  VikWaypoint *closest_wp;
-  VikViewport *vvp;
-} WPSearchParams;
+typedef struct {
+  gint x, y;
+  gint closest_x, closest_y;
+  gpointer *closest_wp_id;
+  VikWaypoint *closest_wp;
+  VikViewport *vvp;
+} WPSearchParams;
+
+typedef struct {
+  gint x, y;
+  gint closest_x, closest_y;
+  gpointer closest_track_id;
+  VikTrackpoint *closest_tp;
+  VikViewport *vvp;
+  GList *closest_tpl;
+} TPSearchParams;
+
+static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchParams *params )
+{
+  gint x, y;
+  if ( !wp->visible )
+    return;
+
+  vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
+
+  // If waypoint has an image then use the image size to select
+  if ( wp->image ) {
+    gint slackx, slacky;
+    slackx = wp->image_width / 2;
+    slacky = wp->image_height / 2;
+
+    if (    x <= params->x + slackx && x >= params->x - slackx
+         && y <= params->y + slacky && y >= params->y - slacky ) {
+      params->closest_wp_id = id;
+      params->closest_wp = wp;
+      params->closest_x = x;
+      params->closest_y = y;
+    }
+  }
+  else if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
+           ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
+            abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
+    {
+      params->closest_wp_id = id;
+      params->closest_wp = wp;
+      params->closest_x = x;
+      params->closest_y = y;
+    }
+}
+
+static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams *params )
+{
+  GList *tpl = t->trackpoints;
+  VikTrackpoint *tp;
+
+  if ( !t->visible )
+    return;
+
+  while (tpl)
+  {
+    gint x, y;
+    tp = VIK_TRACKPOINT(tpl->data);
+
+    vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
+    if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
+        ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
+          abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
+    {
+      params->closest_track_id = id;
+      params->closest_tp = tp;
+      params->closest_tpl = tpl;
+      params->closest_x = x;
+      params->closest_y = y;
+    }
+    tpl = tpl->next;
+  }
+}
+
+// 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;
+  params.x = x;
+  params.y = y;
+  params.vvp = vvp;
+  params.closest_track_id = NULL;
+  params.closest_tp = NULL;
+  g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
+  return params.closest_tp;
+}
+
+static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
+{
+  WPSearchParams params;
+  params.x = x;
+  params.y = y;
+  params.vvp = vvp;
+  params.closest_wp = NULL;
+  params.closest_wp_id = NULL;
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
+  return params.closest_wp;
+}
+
+
+// Some forward declarations
+static void marker_begin_move ( tool_ed_t *t, gint x, gint y );
+static void marker_moveto ( tool_ed_t *t, gint x, gint y );
+static void marker_end_move ( tool_ed_t *t );
+//
+
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
+{
+  if ( t->holding ) {
+    VikCoord new_coord;
+    vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
+
+    // Here always allow snapping back to the original location
+    //  this is useful when one decides not to move the thing afterall
+    // If one wants to move the item only a little bit then don't hold down the 'snap' key!
+    // snap to TP
+    if ( event->state & GDK_CONTROL_MASK )
+    {
+      VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
+      if ( tp )
+        new_coord = tp->coord;
+    }
+
+    // snap to WP
+    if ( event->state & GDK_SHIFT_MASK )
+    {
+      VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
+      if ( wp )
+        new_coord = wp->coord;
+    }
+    
+    gint x, y;
+    vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
+
+    marker_moveto ( t, x, y );
+
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
+{
+  if ( t->holding && event->button == 1 )
+  {
+    VikCoord new_coord;
+    vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
+
+    // snap to TP
+    if ( event->state & GDK_CONTROL_MASK )
+    {
+      VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
+      if ( tp )
+        new_coord = tp->coord;
+    }
+
+    // snap to WP
+    if ( event->state & GDK_SHIFT_MASK )
+    {
+      VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
+      if ( wp )
+        new_coord = wp->coord;
+    }
+
+    marker_end_move ( t );
+
+    // Determine if working on a waypoint or a trackpoint
+    if ( t->is_waypoint )
+      vtl->current_wp->coord = new_coord;
+    else {
+      if ( vtl->current_tpl ) {
+        VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
+      
+       if ( vtl->tpwin )
+          if ( vtl->current_tp_track )
+            vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+      }
+    }
+
+    // Reset
+    vtl->current_wp    = NULL;
+    vtl->current_wp_id = NULL;
+    trw_layer_cancel_current_tp ( vtl, FALSE );
+
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*
+  Returns true if a waypoint or track is found near the requested event position for this particular layer
+  The item found is automatically selected
+  This is a tool like feature but routed via the layer interface, since it's instigated by a 'global' layer tool in vikwindow.c
+ */
+static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* tet )
+{
+  if ( event->button != 1 )
+    return FALSE;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
+  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
+
+  if (vtl->waypoints_visible) {
+    WPSearchParams wp_params;
+    wp_params.vvp = vvp;
+    wp_params.x = event->x;
+    wp_params.y = event->y;
+    wp_params.closest_wp_id = NULL;
+    wp_params.closest_wp = NULL;
+
+    g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params);
+
+    if ( wp_params.closest_wp )  {
+
+      // Select
+      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_id ), TRUE );
+
+      // Too easy to move it so must be holding shift to start immediately moving it
+      //   or otherwise be previously selected but not have an image (otherwise clicking within image bounds (again) moves it)
+      if ( event->state & GDK_SHIFT_MASK ||
+          ( vtl->current_wp == wp_params.closest_wp && !vtl->current_wp->image ) ) {
+       // Put into 'move buffer'
+       // NB vvp & vw already set in tet
+       tet->vtl = (gpointer)vtl;
+       tet->is_waypoint = TRUE;
+      
+       marker_begin_move (tet, event->x, event->y);
+      }
+
+      vtl->current_wp =    wp_params.closest_wp;
+      vtl->current_wp_id = wp_params.closest_wp_id;
+
+      vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+
+      return TRUE;
+    }
+  }
+
+  // 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 )  {
+
+      // Always select + highlight the track
+      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_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->tracks, 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;
+    }
+  }
+
+  // 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;
+  trw_layer_cancel_current_tp ( vtl, FALSE );
+
+  // Blank info
+  vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, "" );
+
+  return FALSE;
+}
+
+static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  if ( event->button != 3 )
+    return FALSE;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
+  if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
+    return FALSE;
+
+  /* Post menu for the currently selected item */
+
+  /* See if a track is selected */
+  VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
+  if ( track && track->visible ) {
+
+    if ( track->name ) {
+
+      if ( vtl->track_right_click_menu )
+        gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
+
+      vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
+      
+      trku_udata udataU;
+      udataU.trk  = track;
+      udataU.uuid = NULL;
+
+      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 );
 
 
-typedef struct {
-  gint x, y;
-  gint closest_x, closest_y;
-  gchar *closest_track_name;
-  VikTrackpoint *closest_tp;
-  VikViewport *vvp;
-  GList *closest_tpl;
-} TPSearchParams;
+      if ( trkf && udataU.uuid ) {
 
 
-static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
-{
-  gint x, y;
-  if ( !wp->visible )
-    return;
+        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,
+                                            track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK,
+                                            udataU.uuid,
+                                            iter,
+                                            vvp );
+      }
 
 
-  vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
-  if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
-      ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
-        abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
-  {
-    params->closest_wp_name = name;
-    params->closest_wp = wp;
-    params->closest_x = x;
-    params->closest_y = y;
+      gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
+       
+      return TRUE;
+    }
   }
   }
-}
 
 
-static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
-{
-  GList *tpl = t->trackpoints;
-  VikTrackpoint *tp;
+  /* See if a waypoint is selected */
+  VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
+  if ( waypoint && waypoint->visible ) {
+    if ( waypoint->name ) {
 
 
-  if ( !t->visible )
-    return;
+      if ( vtl->wp_right_click_menu )
+        gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
 
 
-  while (tpl)
-  {
-    gint x, y;
-    tp = VIK_TRACKPOINT(tpl->data);
+      vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
 
 
-    vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
-    if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
-        ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
-          abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
-    {
-      params->closest_track_name = name;
-      params->closest_tp = tp;
-      params->closest_tpl = tpl;
-      params->closest_x = x;
-      params->closest_y = y;
+      wpu_udata udata;
+      udata.wp   = waypoint;
+      udata.uuid = NULL;
+
+      gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+      if ( wpf && udata.uuid ) {
+        GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+
+        trw_layer_sublayer_add_menu_items ( vtl,
+                                            vtl->wp_right_click_menu,
+                                            NULL,
+                                            VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
+                                            udata.uuid,
+                                            iter,
+                                            vvp );
+      }
+      gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
+
+      return TRUE;
     }
     }
-    tpl = tpl->next;
   }
   }
-}
-
-static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
-{
-  TPSearchParams params;
-  params.x = x;
-  params.y = y;
-  params.vvp = vvp;
-  params.closest_track_name = NULL;
-  params.closest_tp = NULL;
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
-  return params.closest_tp;
-}
 
 
-static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
-{
-  WPSearchParams params;
-  params.x = x;
-  params.y = y;
-  params.vvp = vvp;
-  params.closest_wp = NULL;
-  params.closest_wp_name = NULL;
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
-  return params.closest_wp;
+  return FALSE;
 }
 
 /* background drawing hook, to be passed the viewport */
 }
 
 /* background drawing hook, to be passed the viewport */
@@ -3662,13 +7086,6 @@ static gboolean tool_sync(gpointer data)
   return FALSE;
 }
 
   return FALSE;
 }
 
-typedef struct {
-  VikViewport *vvp;
-  gboolean holding;
-  GdkGC *gc;
-  int oldx, oldy;
-} tool_ed_t;
-
 static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
 {
   t->holding = TRUE;
 static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
 {
   t->holding = TRUE;
@@ -3748,16 +7165,16 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
   params.vvp = vvp;
   params.x = event->x;
   params.y = event->y;
   params.vvp = vvp;
   params.x = event->x;
   params.y = event->y;
-  params.closest_wp_name = NULL;
+  params.closest_wp_id = NULL;
   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_wp = NULL;
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
   if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
   {
   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_wp = NULL;
   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");
     marker_begin_move(t, event->x, event->y);
     g_critical("shouldn't be here");
-    exit(1);
+    return FALSE;
   }
   else if ( params.closest_wp )
   {
   }
   else if ( params.closest_wp )
   {
@@ -3766,21 +7183,20 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
     else
       vtl->waypoint_rightclick = FALSE;
 
     else
       vtl->waypoint_rightclick = FALSE;
 
-    vtl->current_wp = params.closest_wp;
-    vtl->current_wp_name = params.closest_wp_name;
+    vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, params.closest_wp_id ), TRUE );
 
 
-    if ( params.closest_wp )
-      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) );
+    vtl->current_wp = params.closest_wp;
+    vtl->current_wp_id = params.closest_wp_id;
 
     /* could make it so don't update if old WP is off screen and new is null but oh well */
 
     /* could make it so don't update if old WP is off screen and new is null but oh well */
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
 
   vtl->current_wp = NULL;
     return TRUE;
   }
 
   vtl->current_wp = NULL;
-  vtl->current_wp_name = NULL;
+  vtl->current_wp_id = NULL;
   vtl->waypoint_rightclick = FALSE;
   vtl->waypoint_rightclick = FALSE;
-  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
   return FALSE;
 }
 
   return FALSE;
 }
 
@@ -3855,34 +7271,24 @@ static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *e
     marker_end_move ( t );
 
     vtl->current_wp->coord = new_coord;
     marker_end_move ( t );
 
     vtl->current_wp->coord = new_coord;
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
   /* PUT IN RIGHT PLACE!!! */
   if ( event->button == 3 && vtl->waypoint_rightclick )
   {
     if ( vtl->wp_right_click_menu )
     return TRUE;
   }
   /* PUT IN RIGHT PLACE!!! */
   if ( event->button == 3 && vtl->waypoint_rightclick )
   {
     if ( vtl->wp_right_click_menu )
-      gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
-    vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
-    vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name  ) );
-    gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
+      g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
+    if ( vtl->current_wp ) {
+      vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
+      trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_id, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_id ), vvp );
+      gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
+    }
     vtl->waypoint_rightclick = FALSE;
   }
   return FALSE;
 }
 
     vtl->waypoint_rightclick = FALSE;
   }
   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)
 /*** New track ****/
 
 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
@@ -3892,49 +7298,208 @@ static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
 
 typedef struct {
   VikTrwLayer *vtl;
 
 typedef struct {
   VikTrwLayer *vtl;
-  VikViewport *vvp;
-  gint x1,y1,x2,y2;
-} new_track_move_passalong_t;
-
-/* sync and undraw, but only when we have time */
-static gboolean ct_sync ( gpointer passalong )
-{
-  new_track_move_passalong_t *p = (new_track_move_passalong_t *) passalong;
-  vik_viewport_sync ( p->vvp );
-  gdk_gc_set_function ( p->vtl->current_track_gc, GDK_INVERT );
-  vik_viewport_draw_line ( p->vvp, p->vtl->current_track_gc, p->x1, p->y1, p->x2, p->y2 );
-  gdk_gc_set_function ( p->vtl->current_track_gc, GDK_COPY );
-  p->vtl->ct_sync_done = TRUE;
-  g_free ( p );
+  GdkDrawable *drawable;
+  GdkGC *gc;
+  GdkPixmap *pixmap;
+} draw_sync_t;
+
+/*
+ * Draw specified pixmap
+ */
+static gboolean draw_sync ( gpointer data )
+{
+  draw_sync_t *ds = (draw_sync_t*) data;
+  // Sometimes don't want to draw
+  //  normally because another update has taken precedent such as panning the display
+  //   which means this pixmap is no longer valid
+  if ( ds->vtl->draw_sync_do ) {
+    gdk_threads_enter();
+    gdk_draw_drawable (ds->drawable,
+                       ds->gc,
+                       ds->pixmap,
+                       0, 0, 0, 0, -1, -1);
+    ds->vtl->draw_sync_done = TRUE;
+    gdk_threads_leave();
+  }
   return FALSE;
 }
 
   return FALSE;
 }
 
+static gchar* distance_string (gdouble distance)
+{
+  gchar str[128];
+
+  /* draw label with distance */
+  vik_units_distance_t dist_units = a_vik_get_units_distance ();
+  switch (dist_units) {
+  case VIK_UNITS_DISTANCE_MILES:
+    if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
+      g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
+    } else if (distance < 1609.4) {
+      g_sprintf(str, "%d yards", (int)(distance*1.0936133));
+    } else {
+      g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
+    }
+    break;
+  default:
+    // VIK_UNITS_DISTANCE_KILOMETRES
+    if (distance >= 1000 && distance < 100000) {
+      g_sprintf(str, "%3.2f km", distance/1000.0);
+    } else if (distance < 1000) {
+      g_sprintf(str, "%d m", (int)distance);
+    } else {
+      g_sprintf(str, "%d km", (int)distance/1000);
+    }
+    break;
+  }
+  return g_strdup (str);
+}
+
+/*
+ * Actually set the message in statusbar
+ */
+static void statusbar_write (const gchar *distance_string, gdouble elev_gain, gdouble elev_loss, VikTrwLayer *vtl )
+{
+  // Only show elevation data when track has some elevation properties
+  gchar str_gain_loss[64];
+  str_gain_loss[0] = '\0';
+  
+  if ( (elev_gain > 0.1) || (elev_loss > 0.1) ) {
+    if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
+      g_sprintf(str_gain_loss, _(" - Gain %dm:Loss %dm"), (int)elev_gain, (int)elev_loss);
+    else
+      g_sprintf(str_gain_loss, _(" - Gain %dft:Loss %dft"), (int)VIK_METERS_TO_FEET(elev_gain), (int)VIK_METERS_TO_FEET(elev_loss));
+  }
+
+  // Write with full gain/loss information
+  gchar *msg = g_strdup_printf ( "%s%s", distance_string, str_gain_loss);
+  vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
+  g_free ( msg );
+}
+
+/*
+ * Figure out what information should be set in the statusbar and then write it
+ */
+static void update_statusbar ( VikTrwLayer *vtl )
+{
+  // Get elevation data
+  gdouble elev_gain, elev_loss;
+  vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
+
+  /* Find out actual distance of current track */
+  gdouble distance = vik_track_get_length (vtl->current_track);
+  gchar *str = distance_string (distance);
+
+  statusbar_write (str, elev_gain, elev_loss, vtl);
+
+  g_free (str);
+}
+
+
 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
 {
   /* if we haven't sync'ed yet, we don't have time to do more. */
 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
 {
   /* if we haven't sync'ed yet, we don't have time to do more. */
-  if ( vtl->ct_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
-    GList *iter = vtl->current_track->trackpoints;
-    new_track_move_passalong_t *passalong;
+  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;
+    // Need to check in case window has been resized
+    w1 = vik_viewport_get_width(vvp);
+    h1 = vik_viewport_get_height(vvp);
+    if (!pixmap) {
+      pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+    }
+    gdk_drawable_get_size (pixmap, &w2, &h2);
+    if (w1 != w2 || h1 != h2) {
+      g_object_unref ( G_OBJECT ( pixmap ) );
+      pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+    }
+
+    // Reset to background
+    gdk_draw_drawable (pixmap,
+                       vtl->current_track_newpoint_gc,
+                       vik_viewport_get_pixmap(vvp),
+                       0, 0, 0, 0, -1, -1);
+
+    draw_sync_t *passalong;
     gint x1, y1;
 
     gint x1, y1;
 
-    while ( iter->next )
-      iter = iter->next;
-    gdk_gc_set_function ( vtl->current_track_gc, GDK_INVERT );
-    vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
-    vik_viewport_draw_line ( vvp, vtl->current_track_gc, x1, y1, event->x, event->y );
-    gdk_gc_set_function ( vtl->current_track_gc, GDK_COPY );
+    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,
+    //  thus when we come to reset to the background it would include what we have already drawn!!
+    gdk_draw_line ( pixmap,
+                    vtl->current_track_newpoint_gc,
+                    x1, y1, event->x, event->y );
+    // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
+
+    /* Find out actual distance of current track */
+    gdouble distance = vik_track_get_length (vtl->current_track);
+
+    // Now add distance to where the pointer is //
+    VikCoord coord;
+    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, &(last_tpt->coord));
+
+    // Get elevation data
+    gdouble elev_gain, elev_loss;
+    vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
+
+    // Adjust elevation data (if available) for the current pointer position
+    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 ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) {
+       // Adjust elevation of last track point
+       if ( elev_new > last_tpt->altitude )
+         // Going up
+         elev_gain += elev_new - last_tpt->altitude;
+       else
+         // Going down
+         elev_loss += last_tpt->altitude - elev_new;
+      }
+    }
+      
+    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);
+
+    pango_layout_set_text (pl, str, -1);
+    gint wd, hd;
+    pango_layout_get_pixel_size ( pl, &wd, &hd );
+
+    gint xd,yd;
+    // offset from cursor a bit depending on font size
+    xd = event->x + 10;
+    yd = event->y - hd;
+
+    // Create a background block to make the text easier to read over the background map
+    GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
+    gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
+    gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
+
+    g_object_unref ( G_OBJECT ( pl ) );
+    g_object_unref ( G_OBJECT ( background_block_gc ) );
 
 
-    passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
+    passalong = g_new(draw_sync_t,1); // freed by draw_sync()
     passalong->vtl = vtl;
     passalong->vtl = vtl;
-    passalong->vvp = vvp;
-    passalong->x1 = x1;
-    passalong->y1 = y1;
-    passalong->x2 = event->x;
-    passalong->y2 = event->y;
-
-    /* this will sync and undraw when we have time to */
-    g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, ct_sync, passalong, NULL);
-    vtl->ct_sync_done = FALSE;
+    passalong->pixmap = pixmap;
+    passalong->drawable = GTK_WIDGET(vvp)->window;
+    passalong->gc = vtl->current_track_newpoint_gc;
+
+    // Update statusbar with full gain/loss information
+    statusbar_write (str, elev_gain, elev_loss, vtl);
+
+    g_free (str);
+
+    // draw pixmap when we have time to
+    g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
+    vtl->draw_sync_done = FALSE;
     return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
   }
   return VIK_LAYER_TOOL_ACK;
     return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
   }
   return VIK_LAYER_TOOL_ACK;
@@ -3944,7 +7509,7 @@ static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event,
 {
   if ( vtl->current_track && event->keyval == GDK_Escape ) {
     vtl->current_track = NULL;
 {
   if ( vtl->current_track && event->keyval == GDK_Escape ) {
     vtl->current_track = NULL;
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
     /* undo */
     return TRUE;
   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
     /* undo */
@@ -3954,21 +7519,39 @@ static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event,
       g_free ( last->data );
       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
     }
       g_free ( last->data );
       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
     }
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    
+    update_statusbar ( vtl );
+
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
   return FALSE;
 }
 
     return TRUE;
   }
   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;
 
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
 {
   VikTrackpoint *tp;
 
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
-  if ( event->button == 3 && vtl->current_track )
+  if ( event->button == 2 ) {
+    // As the display is panning, the new track pixmap is now invalid so don't draw it
+    //  otherwise this drawing done results in flickering back to an old image
+    vtl->draw_sync_do = FALSE;
+    return FALSE;
+  }
+
+  if ( event->button == 3 )
   {
   {
+    if ( !vtl->current_track )
+      return FALSE;
     /* undo */
     if ( vtl->current_track->trackpoints )
     {
     /* undo */
     if ( vtl->current_track->trackpoints )
     {
@@ -3976,7 +7559,9 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
       g_free ( last->data );
       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
     }
       g_free ( last->data );
       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
     }
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    update_statusbar ( vtl );
+
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
 
     return TRUE;
   }
 
@@ -3991,25 +7576,10 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
       /* undo last, then end */
       vtl->current_track = NULL;
     }
       /* undo last, then end */
       vtl->current_track = NULL;
     }
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
 
     return TRUE;
   }
 
-  if ( ! vtl->current_track )
-  {
-    gchar *name = get_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) );
 
   tp = vik_trackpoint_new();
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
 
@@ -4024,17 +7594,74 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   tp->newsegment = FALSE;
   tp->has_timestamp = FALSE;
   tp->timestamp = 0;
   tp->newsegment = FALSE;
   tp->has_timestamp = FALSE;
   tp->timestamp = 0;
-  vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
+
+  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;
   vtl->ct_x2 = event->x;
   vtl->ct_y2 = event->y;
 
 
   vtl->ct_x1 = vtl->ct_x2;
   vtl->ct_y1 = vtl->ct_y2;
   vtl->ct_x2 = event->x;
   vtl->ct_y2 = event->y;
 
-  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
   return TRUE;
 }
 
   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 ) {
+    // Pan moving ended - enable potential point drawing again
+    vtl->draw_sync_do = TRUE;
+    vtl->draw_sync_done = TRUE;
+  }
+}
+
+/*** 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 ****/
 
 
 /*** New waypoint ****/
 
@@ -4050,7 +7677,7 @@ static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *even
     return FALSE;
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
   if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible)
     return FALSE;
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
   if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible)
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -4079,7 +7706,7 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
   params.vvp = vvp;
   params.x = event->x;
   params.y = event->y;
   params.vvp = vvp;
   params.x = event->x;
   params.y = event->y;
-  params.closest_track_name = NULL;
+  params.closest_track_id = NULL;
   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_tp = NULL;
 
   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_tp = NULL;
 
@@ -4089,17 +7716,18 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
   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 )
   {
     /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
     VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
     return FALSE;
 
   if ( vtl->current_tpl )
   {
     /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
     VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
-    VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name));
-    gint x, y;
-    g_assert ( current_tr );
+    VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
+    if ( !current_tr )
+      return FALSE;
 
 
+    gint x, y;
     vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
 
     if ( current_tr->visible && 
     vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
 
     if ( current_tr->visible && 
@@ -4109,19 +7737,35 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
       return TRUE;
     }
 
       return TRUE;
     }
 
-    vtl->last_tpl = vtl->current_tpl;
-    vtl->last_tp_track_name = vtl->current_tp_track_name;
   }
 
   }
 
-  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 )
+  {
+    vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_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->tracks, 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;
+  }
+
+  if ( vtl->routes_visible )
+    g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &params);
 
   if ( params.closest_tp )
   {
 
   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_tpl = params.closest_tpl;
-    vtl->current_tp_track_name = params.closest_track_name;
-    vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ) );
+    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 );
     trw_layer_tpwin_init ( vtl );
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
 
     return TRUE;
   }
 
@@ -4188,62 +7832,62 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton
     marker_end_move ( t );
 
     /* diff dist is diff from orig */
     marker_end_move ( t );
 
     /* diff dist is diff from orig */
-    vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
-    /* can't join with itself! */
-    trw_layer_cancel_last_tp ( vtl );
+    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) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
     return TRUE;
   }
   return FALSE;
 }
 
 
     return TRUE;
   }
   return FALSE;
 }
 
 
-/*** Magic Scissors ***/
-static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
+#ifdef VIK_CONFIG_GOOGLE
+/*** Route Finder ***/
+static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
 {
   return vvp;
 }
 
 {
   return vvp;
 }
 
-static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   VikCoord tmp;
   if ( !vtl ) return FALSE;
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
 {
   VikCoord tmp;
   if ( !vtl ) return FALSE;
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
-  if ( event->button == 3 && vtl->magic_scissors_current_track ) {
+  if ( event->button == 3 && vtl->route_finder_current_track ) {
     VikCoord *new_end;
     VikCoord *new_end;
-    new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track );
+    new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
     if ( new_end ) {
     if ( new_end ) {
-      vtl->magic_scissors_coord = *new_end;
+      vtl->route_finder_coord = *new_end;
       g_free ( new_end );
       g_free ( new_end );
-      vik_layer_emit_update ( VIK_LAYER(vtl) );
+      vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
       /* remove last ' to:...' */
       /* remove last ' to:...' */
-      if ( vtl->magic_scissors_current_track->comment ) {
-        gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' );
-        if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) {
-          gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment,
-                                           last_to - vtl->magic_scissors_current_track->comment - 1);
-          vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+      if ( vtl->route_finder_current_track->comment ) {
+        gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
+        if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
+          gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
+                                           last_to - vtl->route_finder_current_track->comment - 1);
+          vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
         }
       }
     }
   }
         }
       }
     }
   }
-  else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) {
+  else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
     struct LatLon start, end;
     gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE];
     gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE];
     gchar *url;
 
     struct LatLon start, end;
     gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE];
     gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE];
     gchar *url;
 
-    vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start );
+    vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
     vik_coord_to_latlon ( &(tmp), &end );
     vik_coord_to_latlon ( &(tmp), &end );
-    vtl->magic_scissors_coord = tmp; /* for continuations */
+    vtl->route_finder_coord = tmp; /* for continuations */
 
     /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
 
     /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
-    if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) {
-      vtl->magic_scissors_append = TRUE;  // merge tracks. keep started true.
+    if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
+      vtl->route_finder_append = TRUE;  // merge tracks. keep started true.
     } else {
     } else {
-      vtl->magic_scissors_check_added_track = TRUE;
-      vtl->magic_scissors_started = FALSE;
+      vtl->route_finder_check_added_track = TRUE;
+      vtl->route_finder_started = FALSE;
     }
 
     url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING,
     }
 
     url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING,
@@ -4251,38 +7895,30 @@ static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *ev
                           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));
                           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 */
     g_free ( url );
 
     /* see if anything was done -- a track was added or appended to */
-    if ( vtl->magic_scissors_check_added_track && vtl->magic_scissors_added_track_name ) {
-      VikTrack *tr;
-
-      tr = g_hash_table_lookup ( vtl->tracks, vtl->magic_scissors_added_track_name );
-
-      if ( tr )
-        vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
-      vtl->magic_scissors_current_track = tr;
-
-      g_free ( vtl->magic_scissors_added_track_name );
-      vtl->magic_scissors_added_track_name = NULL;
-    } else if ( vtl->magic_scissors_append == FALSE && vtl->magic_scissors_current_track ) {
-      /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
-      gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->magic_scissors_current_track->comment, end.lat, end.lon );
-      vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+    if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) {
+      vik_track_set_comment_no_copy ( vtl->route_finder_added_track, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
+    } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
+      /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
+      gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
+      vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
     }
     }
-    vtl->magic_scissors_check_added_track = FALSE;
-    vtl->magic_scissors_append = FALSE;
+    vtl->route_finder_added_track = NULL;
+    vtl->route_finder_check_added_track = FALSE;
+    vtl->route_finder_append = FALSE;
 
 
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
   } else {
   } else {
-    vtl->magic_scissors_started = TRUE;
-    vtl->magic_scissors_coord = tmp;
-    vtl->magic_scissors_current_track = NULL;
+    vtl->route_finder_started = TRUE;
+    vtl->route_finder_coord = tmp;
+    vtl->route_finder_current_track = NULL;
   }
   return TRUE;
 }
   }
   return TRUE;
 }
+#endif
 
 /*** Show picture ****/
 
 
 /*** Show picture ****/
 
@@ -4292,7 +7928,7 @@ static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
 }
 
 /* Params are: vvp, event, last match found or NULL */
 }
 
 /* Params are: vvp, event, last match found or NULL */
-static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] )
+static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[3] )
 {
   if ( wp->image && wp->visible )
   {
 {
   if ( wp->image && wp->visible )
   {
@@ -4312,6 +7948,25 @@ static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[
   }
 }
 
   }
 }
 
+static void trw_layer_show_picture ( gpointer pass_along[6] )
+{
+  /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
+#ifdef WINDOWS
+  ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL);
+#else /* WINDOWS */
+  GError *err = NULL;
+  gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
+  gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
+  g_free ( quoted_file );
+  if ( ! g_spawn_command_line_async ( cmd, &err ) )
+    {
+      a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch %s to open file."), a_vik_get_image_viewer() );
+      g_error_free ( err );
+    }
+  g_free ( cmd );
+#endif /* WINDOWS */
+}
+
 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   gpointer params[3] = { vvp, event, NULL };
 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   gpointer params[3] = { vvp, event, NULL };
@@ -4320,21 +7975,10 @@ static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *even
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
   if ( params[2] )
   {
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
   if ( params[2] )
   {
-    /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
-#ifdef WINDOWS
-    ShellExecute(NULL, NULL, (char *) params[2], NULL, ".\\", 0);
-#else /* WINDOWS */
-    GError *err = NULL;
-    gchar *quoted_file = g_shell_quote ( (gchar *) params[2] );
-    gchar *cmd = g_strdup_printf ( "eog %s", quoted_file );
-    g_free ( quoted_file );
-    if ( ! g_spawn_command_line_async ( cmd, &err ) )
-    {
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch eog to open file.") );
-      g_error_free ( err );
-    }
-    g_free ( cmd );
-#endif /* WINDOWS */
+    static gpointer pass_along[6];
+    pass_along[0] = vtl;
+    pass_along[5] = params[2];
+    trw_layer_show_picture ( pass_along );
     return TRUE; /* found a match */
   }
   else
     return TRUE; /* found a match */
   }
   else
@@ -4355,27 +7999,43 @@ static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
     *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
 }
 
     *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
 }
 
-static void create_thumbnails_thread ( GSList *pics, gpointer threaddata )
+/* Structure for thumbnail creating data used in the background thread */
+typedef struct {
+  VikTrwLayer *vtl; // Layer needed for redrawing
+  GSList *pics;     // Image list
+} thumbnail_create_thread_data;
+
+static int create_thumbnails_thread ( thumbnail_create_thread_data *tctd, gpointer threaddata )
 {
 {
-  guint total = g_slist_length(pics), done = 0;
-  while ( pics )
+  guint total = g_slist_length(tctd->pics), done = 0;
+  while ( tctd->pics )
   {
   {
-    a_thumbnails_create ( (gchar *) pics->data );
-    a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
-    pics = pics->next;
+    a_thumbnails_create ( (gchar *) tctd->pics->data );
+    int result = a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
+    if ( result != 0 )
+      return -1; /* Abort thread */
+
+    tctd->pics = tctd->pics->next;
   }
   }
+
+  // Redraw to show the thumbnails as they are now created
+  if ( IS_VIK_LAYER(tctd->vtl) )
+    vik_layer_emit_update ( VIK_LAYER(tctd->vtl), TRUE ); // Yes update from background thread
+
+  return 0;
 }
 
 }
 
-static void free_pics_slist ( GSList *pics )
+static void thumbnail_create_thread_free ( thumbnail_create_thread_data *tctd )
 {
 {
-  while ( pics )
+  while ( tctd->pics )
   {
   {
-    g_free ( pics->data );
-    pics = g_slist_delete_link ( pics, pics );
+    g_free ( tctd->pics->data );
+    tctd->pics = g_slist_delete_link ( tctd->pics, tctd->pics );
   }
   }
+  g_free ( tctd );
 }
 
 }
 
-static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
+void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
 {
   if ( ! vtl->has_verified_thumbnails )
   {
 {
   if ( ! vtl->has_verified_thumbnails )
   {
@@ -4385,7 +8045,16 @@ static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
     {
       gint len = g_slist_length ( pics );
       gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
     {
       gint len = g_slist_length ( pics );
       gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
-      a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl), tmp, (vik_thr_func) create_thumbnails_thread, pics, (vik_thr_free_func) free_pics_slist, NULL, len );
+      thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
+      tctd->vtl = vtl;
+      tctd->pics = pics;
+      a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                           tmp,
+                           (vik_thr_func) create_thumbnails_thread,
+                           tctd,
+                           (vik_thr_free_func) thumbnail_create_thread_free,
+                           NULL,
+                           len );
       g_free ( tmp );
     }
   }
       g_free ( tmp );
     }
   }
@@ -4396,9 +8065,23 @@ VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
   return vtl->coord_mode;
 }
 
   return vtl->coord_mode;
 }
 
+/**
+ * Uniquify the whole layer
+ * Also requires the layers panel as the names shown there need updating too
+ * Returns whether the operation was successful or not
+ */
+gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+  if ( 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;
+  }
+  return FALSE;
+}
 
 
-
-static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode )
+static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode )
 {
   vik_coord_convert ( &(wp->coord), *dest_mode );
 }
 {
   vik_coord_convert ( &(wp->coord), *dest_mode );
 }
@@ -4418,24 +8101,14 @@ static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mo
   }
 }
 
   }
 }
 
-VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, gchar *name )
-{
-  return g_hash_table_lookup ( vtl->waypoints, name );
-}
-
-VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name )
-{
-  return g_hash_table_lookup ( vtl->tracks, name );
-}
-
-static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection)
+static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 selection )
 {
   vtl->menu_selection = selection;
 }
 
 {
   vtl->menu_selection = selection;
 }
 
-static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl)
+static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl )
 {
 {
-  return(vtl->menu_selection);
+  return (vtl->menu_selection);
 }
 
 /* ----------- Downloading maps along tracks --------------- */
 }
 
 /* ----------- Downloading maps along tracks --------------- */
@@ -4575,7 +8248,7 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g
   }
 
   for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
   }
 
   for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
-    maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
+    maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
   }
 
   if (fillins) {
   }
 
   if (fillins) {
@@ -4590,7 +8263,7 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g
   }
 }
 
   }
 }
 
-static void trw_layer_download_map_along_track_cb(gpointer pass_along[6])
+static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
 {
   VikMapsLayer *vml;
   gint selected_map, default_map;
 {
   VikMapsLayer *vml;
   gint selected_map, default_map;
@@ -4602,10 +8275,17 @@ static void trw_layer_download_map_along_track_cb(gpointer pass_along[6])
 
   VikTrwLayer *vtl = pass_along[0];
   VikLayersPanel *vlp = pass_along[1];
 
   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)));
 
   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);
+  GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types
   int num_maps = g_list_length(vmls);
 
   if (!num_maps) {
   int num_maps = g_list_length(vmls);
 
   if (!num_maps) {
@@ -4654,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;
 
   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++)
 
 done:
   for (i = 0; i < num_maps; i++)
@@ -4699,13 +8379,13 @@ static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_na
   gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
   if ( vtl->highest_wp_number == old_wp_num ) {
     gchar buf[4];
   gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
   if ( vtl->highest_wp_number == old_wp_num ) {
     gchar buf[4];
-    vtl->highest_wp_number --;
+    vtl->highest_wp_number--;
 
     g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
     /* search down until we find something that *does* exist */
 
 
     g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
     /* search down until we find something that *does* exist */
 
-    while ( vtl->highest_wp_number > 0 && ! g_hash_table_lookup ( vtl->waypoints, buf ) ) {
-      vtl->highest_wp_number --;
+    while ( vtl->highest_wp_number > 0 && ! vik_trw_layer_get_waypoint ( vtl, buf )) {
+      vtl->highest_wp_number--;
       g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
     }
   }
       g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
     }
   }