]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Add Terraserver
[andy/viking.git] / src / viktrwlayer.c
index d16a737923d64c986fb72315099eb6845d0fb9ef..9fb218ed5059e281175b995af8529c5020c84358 100644 (file)
 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
 /* viktrwlayer.c -- 2200 lines can make a difference in the state of things */
 
 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
 /* viktrwlayer.c -- 2200 lines can make a difference in the state of things */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include "viking.h"
 #include "viking.h"
-#include "viktrwlayer_pixmap.h"
+#include "vikmapslayer.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "garminsymbols.h"
 #include "thumbnails.h"
 #include "background.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "garminsymbols.h"
 #include "thumbnails.h"
 #include "background.h"
+#include "gpx.h"
+#include "babel.h"
+#include "dem.h"
+#include "dems.h"
+#include "googlesearch.h"
+#ifdef VIK_CONFIG_OPENSTREETMAP
+#include "osm-traces.h"
+#endif
+#include "acquire.h"
+#include "util.h"
+
+#include "icons/icons.h"
 
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <ctype.h>
 
 #include <ctype.h>
 
+#include <gdk/gdkkeysyms.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+
+/* Relax some dependencies */
+#if ! GLIB_CHECK_VERSION(2,12,0)
+static gboolean return_true (gpointer a, gpointer b, gpointer c) { return TRUE; }
+static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
+#endif
+
+#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js"
 #define VIK_TRW_LAYER_TRACK_GC 13
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
 #define VIK_TRW_LAYER_TRACK_GC 13
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
@@ -92,6 +121,7 @@ struct _VikTrwLayer {
   gdouble velocity_min, velocity_max;
   GArray *track_gc;
   guint16 track_gc_iter;
   gdouble velocity_min, velocity_max;
   GArray *track_gc;
   guint16 track_gc_iter;
+  GdkGC *current_track_gc;
   GdkGC *track_bg_gc;
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
   GdkGC *track_bg_gc;
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
@@ -99,6 +129,8 @@ struct _VikTrwLayer {
   GdkFont *waypoint_font;
   VikTrack *current_track;
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
   GdkFont *waypoint_font;
   VikTrack *current_track;
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
+  gboolean ct_sync_done;
+
 
   VikCoordMode coord_mode;
 
 
   VikCoordMode coord_mode;
 
@@ -120,6 +152,14 @@ struct _VikTrwLayer {
   /* 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;
+
   gboolean drawlabels;
   gboolean drawimages;
   guint8 image_alpha;
   gboolean drawlabels;
   gboolean drawimages;
   guint8 image_alpha;
@@ -134,6 +174,10 @@ struct _VikTrwLayer {
 
   GtkMenu *wp_right_click_menu;
 
 
   GtkMenu *wp_right_click_menu;
 
+  /* menu */
+  VikStdLayerMenuItem menu_selection;
+
+  gint highest_wp_number;
 };
 
 /* A caached waypoint image. */
 };
 
 /* A caached waypoint image. */
@@ -153,6 +197,13 @@ struct DrawingParams {
   gdouble ce1, ce2, cn1, cn2;
 };
 
   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 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_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_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] );    
 
@@ -168,6 +219,7 @@ static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] );
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
+static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]);
 static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
 static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type );
 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
 static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
 static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type );
 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
@@ -182,31 +234,45 @@ static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer
 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_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] );
 static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
 
-static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 
 
-static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp );
+static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len );
+static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp );
+
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp );
 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id );
 
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp );
 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id );
 
-static gpointer trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
-static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer item );
+static void trw_layer_del_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 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_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name );
 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_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 gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 
 
-static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
+static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
+static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
+static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
+static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
+static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
+static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
+static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
+static gpointer tool_new_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 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 );
 
 
-static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str );
 
 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 );
@@ -218,23 +284,51 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie
 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 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 track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode );
+
+static gchar *highest_wp_number_get(VikTrwLayer *vtl);
+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 VikToolInterface trw_layer_tools[] = {
 
 static VikToolInterface trw_layer_tools[] = {
-  { "Create Waypoint", (VikToolInterfaceFunc) tool_new_waypoint, NULL },
-  { "Create Track", (VikToolInterfaceFunc) tool_new_track, NULL },
-  { "Edit Waypoint", (VikToolInterfaceFunc) tool_edit_waypoint, (VikToolInterfaceFunc) tool_edit_waypoint_release },
-  { "Edit Trackpoint", (VikToolInterfaceFunc) tool_edit_trackpoint, (VikToolInterfaceFunc) tool_edit_trackpoint_release },
-  { "Show Picture", (VikToolInterfaceFunc) tool_show_picture, NULL }, 
-};
+  { 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, 
+    (VikToolMouseFunc) tool_edit_waypoint_click,   
+    (VikToolMouseMoveFunc) tool_edit_waypoint_move,
+    (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
+
+  { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, 
+    (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 },
+};
+enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
 
 /****** PARAMETERS ******/
 
 
 /****** PARAMETERS ******/
 
-static gchar *params_groups[] = { "Waypoints", "Tracks", "Waypoint Images" };
+static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
 enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
 
 enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
 
-static gchar *params_drawmodes[] = { "Draw by Track", "Draw by Velocity", "All Tracks Black", 0 };
-static gchar *params_wpsymbols[] = { "Filled Square", "Square", "Circle", "X", 0 };
+static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 };
+static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
 
 
 static VikLayerParamScale params_scales[] = {
 
 
 static VikLayerParamScale params_scales[] = {
@@ -256,43 +350,48 @@ 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 },
 
   { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
   { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
 
-  { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Drawing Mode:", VIK_LAYER_WIDGET_RADIOGROUP, params_drawmodes },
-  { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Track Lines", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Trackpoints", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Elevation", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Draw Elevation Height %:", VIK_LAYER_WIDGET_HSCALE, params_scales + 9 },
-
-  { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Stops", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Min Stop Length (seconds):", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 },
-
-  { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
-  { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track BG Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 },
-  { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, "Track Background Color", VIK_LAYER_WIDGET_COLOR, 0 },
-  { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, "Min Track Velocity:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
-  { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, "Max Track Velocity:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 },
-
-  { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Draw Labels", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Waypoint Color:", VIK_LAYER_WIDGET_COLOR, 0 },
-  { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Waypoint Text:", VIK_LAYER_WIDGET_COLOR, 0 },
-  { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Background:", VIK_LAYER_WIDGET_COLOR, 0 },
-  { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Fake BG Color Translucency:", VIK_LAYER_WIDGET_CHECKBUTTON, 0 },
-  { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint marker:", VIK_LAYER_WIDGET_RADIOGROUP, params_wpsymbols },
-  { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint size:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 },
-  { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Draw Waypoint Symbols:", VIK_LAYER_WIDGET_CHECKBUTTON },
-
-  { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, "Draw Waypoint Images", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Size (pixels):", VIK_LAYER_WIDGET_HSCALE, params_scales + 3 },
-  { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales + 4 },
-  { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Memory Cache Size:", VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
+  { "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 },
+  { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "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 },
+  { "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 },
+
+  { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "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 },
+  { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, 0 },
+  { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL },
+  { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 },
+  { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON },
+
+  { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 3 },
+  { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 4 },
+  { "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 };
 
 };
 
 enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS };
 
+/*** TO ADD A PARAM:
+ *** 1) Add to trw_layer_params and enumeration
+ *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
+ ***/
+
 /****** END PARAMETERS ******/
 
 VikLayerInterface vik_trw_layer_interface = {
   "TrackWaypoint",
 /****** END PARAMETERS ******/
 
 VikLayerInterface vik_trw_layer_interface = {
   "TrackWaypoint",
-  &trwlayer_pixbuf,
+  &viktrwlayer_pixbuf,
 
   trw_layer_tools,
   sizeof(trw_layer_tools) / sizeof(VikToolInterface),
 
   trw_layer_tools,
   sizeof(trw_layer_tools) / sizeof(VikToolInterface),
@@ -302,6 +401,8 @@ VikLayerInterface vik_trw_layer_interface = {
   params_groups, /* params_groups */
   sizeof(params_groups)/sizeof(params_groups[0]),    /* number of groups */
 
   params_groups, /* params_groups */
   sizeof(params_groups)/sizeof(params_groups[0]),    /* number of groups */
 
+  VIK_MENU_ITEM_ALL,
+
   (VikLayerFuncCreate)                  vik_trw_layer_create,
   (VikLayerFuncRealize)                 vik_trw_layer_realize,
   (VikLayerFuncPostRead)                trw_layer_verify_thumbnails,
   (VikLayerFuncCreate)                  vik_trw_layer_create,
   (VikLayerFuncRealize)                 vik_trw_layer_realize,
   (VikLayerFuncPostRead)                trw_layer_verify_thumbnails,
@@ -311,13 +412,17 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncDraw)                    vik_trw_layer_draw,
   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
 
   (VikLayerFuncDraw)                    vik_trw_layer_draw,
   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
 
+  (VikLayerFuncSetMenuItemsSelection)   vik_trw_layer_set_menu_selection,
+  (VikLayerFuncGetMenuItemsSelection)   vik_trw_layer_get_menu_selection,
+
   (VikLayerFuncAddMenuItems)            vik_trw_layer_add_menu_items,
   (VikLayerFuncSublayerAddMenuItems)    vik_trw_layer_sublayer_add_menu_items,
 
   (VikLayerFuncSublayerRenameRequest)   vik_trw_layer_sublayer_rename_request,
   (VikLayerFuncSublayerToggleVisible)   vik_trw_layer_sublayer_toggle_visible,
 
   (VikLayerFuncAddMenuItems)            vik_trw_layer_add_menu_items,
   (VikLayerFuncSublayerAddMenuItems)    vik_trw_layer_sublayer_add_menu_items,
 
   (VikLayerFuncSublayerRenameRequest)   vik_trw_layer_sublayer_rename_request,
   (VikLayerFuncSublayerToggleVisible)   vik_trw_layer_sublayer_toggle_visible,
 
-  (VikLayerFuncCopy)                    trw_layer_copy,
+  (VikLayerFuncMarshall)                trw_layer_marshall,
+  (VikLayerFuncUnmarshall)              trw_layer_unmarshall,
 
   (VikLayerFuncSetParam)                trw_layer_set_param,
   (VikLayerFuncGetParam)                trw_layer_get_param,
 
   (VikLayerFuncSetParam)                trw_layer_set_param,
   (VikLayerFuncGetParam)                trw_layer_get_param,
@@ -325,6 +430,7 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncReadFileData)            a_gpspoint_read_file,
   (VikLayerFuncWriteFileData)           a_gpspoint_write_file,
 
   (VikLayerFuncReadFileData)            a_gpspoint_read_file,
   (VikLayerFuncWriteFileData)           a_gpspoint_write_file,
 
+  (VikLayerFuncDeleteItem)              trw_layer_del_item,
   (VikLayerFuncCopyItem)                trw_layer_copy_item,
   (VikLayerFuncPasteItem)               trw_layer_paste_item,
   (VikLayerFuncFreeCopiedItem)          trw_layer_free_copied_item,
   (VikLayerFuncCopyItem)                trw_layer_copy_item,
   (VikLayerFuncPasteItem)               trw_layer_paste_item,
   (VikLayerFuncFreeCopiedItem)          trw_layer_free_copied_item,
@@ -334,14 +440,11 @@ VikLayerInterface vik_trw_layer_interface = {
 
 /* for copy & paste (I think?) */
 typedef struct {
 
 /* for copy & paste (I think?) */
 typedef struct {
-  gchar *name;
-  VikWaypoint *wp;
-} NamedWaypoint;
-
-typedef struct {
-  gchar *name;
-  VikTrack *tr;
-} NamedTrack;
+  guint len;
+  guint8 data[0];
+  //  gchar *name;
+  //  VikWaypoint *wp;
+} FlatItem;
 
 GType vik_trw_layer_get_type ()
 {
 
 GType vik_trw_layer_get_type ()
 {
@@ -367,43 +470,94 @@ GType vik_trw_layer_get_type ()
   return vtl_type;
 }
 
   return vtl_type;
 }
 
+static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
+{
+  static gpointer pass_along[5];
+  if (!sublayer) {
+    return;
+  }
+  
+  pass_along[0] = vtl;
+  pass_along[1] = NULL;
+  pass_along[2] = GINT_TO_POINTER (subtype);
+  pass_along[3] = sublayer;
+  pass_along[4] = NULL;
+
+  trw_layer_delete_item ( pass_along );
+}
+
+static void trw_layer_copy_item_cb( gpointer pass_along[5])
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  gint subtype = GPOINTER_TO_INT (pass_along[2]);
+  gpointer * sublayer = pass_along[3];
+  guint8 *data = NULL;
+  guint len;
+
+  trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
+
+  if (data) {
+    a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
+       subtype, len, data);
+  }
+}
+
+static void trw_layer_cut_item_cb( gpointer pass_along[5])
+{
+  trw_layer_copy_item_cb(pass_along);
+  trw_layer_delete_item(pass_along);
+}
 
 
-static gpointer trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
+static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
 {
 {
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && sublayer )
-  {
-    NamedWaypoint *nw = g_malloc ( sizeof ( NamedWaypoint ) );
-    nw->name = g_strdup(sublayer);
-    nw->wp = vik_waypoint_copy ( g_hash_table_lookup ( vtl->waypoints, sublayer ) );
-    return nw;
+  FlatItem *fi;
+  guint8 *id;
+  guint il;
+
+  if (!sublayer) {
+    *item = NULL;
+    return;
   }
   }
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && sublayer )
+
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
   {
-    NamedTrack *nt = g_malloc ( sizeof ( NamedTrack ) );
-    nt->name = g_strdup(sublayer);
-    nt->tr = g_hash_table_lookup ( vtl->tracks, sublayer );
-    vik_track_ref(nt->tr);
-    return nt;
+    vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
+  } else {
+    vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
   }
   }
-  return NULL;
+
+  *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;
 }
 
 }
 
-static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer item )
+static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len )
 {
 {
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && item )
+  FlatItem *fi = (FlatItem *) item;
+
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && fi )
   {
   {
-    NamedWaypoint *nw = (NamedWaypoint *) item;
-    vik_trw_layer_add_waypoint ( vtl,
-        get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, nw->name),
-        vik_waypoint_copy(nw->wp) );
+    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);
+    vik_trw_layer_add_waypoint ( vtl, name, w );
+    waypoint_convert(name, w, &vtl->coord_mode);
     return TRUE;
   }
     return TRUE;
   }
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item )
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi )
   {
   {
-    NamedTrack *nt = (NamedTrack *) item;
-    vik_trw_layer_add_track ( vtl,
-       get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, nt->name),
-       vik_track_copy(nt->tr) );
+    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);
+    vik_trw_layer_add_track ( vtl, name, t );
+    track_convert(name, t, &vtl->coord_mode);
     return TRUE;
   }
   return FALSE;
     return TRUE;
   }
   return FALSE;
@@ -411,25 +565,9 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer
 
 static void trw_layer_free_copied_item ( gint subtype, gpointer item )
 {
 
 static void trw_layer_free_copied_item ( gint subtype, gpointer item )
 {
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && item )
-  {
-    NamedWaypoint *nw = (NamedWaypoint *) item;
-    g_free ( nw->name );
-    vik_waypoint_free ( nw->wp );
-    g_free ( nw );
+  if (item) {
+    g_free(item);
   }
   }
-  if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item )
-  {
-    NamedTrack *nt = (NamedTrack *) item;
-    g_free ( nt->name );
-    vik_track_free ( nt->tr );
-    g_free ( nt );
-  }
-}
-
-static void waypoint_copy ( const gchar *name, VikWaypoint *wp, GHashTable *dest )
-{
-  g_hash_table_insert ( dest, g_strdup(name), vik_waypoint_copy(wp) );
 }
 
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp )
 }
 
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp )
@@ -525,72 +663,111 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id )
   return rv;
 }
 
   return rv;
 }
 
-static void track_copy ( const gchar *name, VikTrack *tr, GHashTable *dest )
+static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
 {
 {
-  g_hash_table_insert ( dest, g_strdup ( name ), vik_track_copy(tr) );
+  guint8 *pd, *dd;
+  gint pl, dl;
+  gchar *tmpname;
+  FILE *f;
+
+  *data = NULL;
+
+  if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
+    a_gpx_write_file(vtl, f);
+    vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
+    fclose(f);
+    f = NULL;
+    g_file_get_contents(tmpname, (void *)&dd, (void *)&dl, NULL);
+    *len = sizeof(pl) + pl + dl;
+    *data = g_malloc(*len);
+    memcpy(*data, &pl, sizeof(pl));
+    memcpy(*data + sizeof(pl), pd, pl);
+    memcpy(*data + sizeof(pl) + pl, dd, dl);
+    
+    g_free(pd);
+    g_free(dd);
+    g_remove(tmpname);
+    g_free(tmpname);
+  }
 }
 
 }
 
-static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
+static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp )
 {
 {
-  VikTrwLayer *rv = vik_trw_layer_new ( vtl->drawmode );
-  PangoFontDescription *pfd;
-  rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
-  pfd = pango_font_description_from_string (WAYPOINT_FONT);
-  pango_layout_set_font_description (rv->wplabellayout, pfd);
-  /* freeing PangoFontDescription, cause it has been copied by prev. call */
-  pango_font_description_free (pfd);
-
-  rv->tracks_visible = vtl->tracks_visible;
-  rv->waypoints_visible = vtl->waypoints_visible;
-  rv->drawpoints = vtl->drawpoints;
-  rv->drawstops = vtl->drawstops;
-  rv->drawelevation = vtl->drawelevation;
-  rv->elevation_factor = vtl->elevation_factor;
-  rv->drawlines = vtl->drawlines;
-  rv->stop_length = vtl->stop_length;
-  rv->line_thickness = vtl->line_thickness;
-  rv->bg_line_thickness = vtl->bg_line_thickness;
-  rv->velocity_min = vtl->velocity_min;
-  rv->velocity_max = vtl->velocity_max;
-  rv->drawlabels = vtl->drawlabels;
-  rv->drawimages = vtl->drawimages;
-  rv->image_size = vtl->image_size;
-  rv->image_alpha = vtl->image_alpha;
-  rv->image_cache_size = vtl->image_cache_size;
-  rv->has_verified_thumbnails = TRUE;
-  rv->coord_mode = vtl->coord_mode;
-  rv->wp_symbol = vtl->wp_symbol;
-  rv->wp_size = vtl->wp_size;
-  rv->wp_draw_symbols = vtl->wp_draw_symbols;
-
-  trw_layer_new_track_gcs ( rv, VIK_VIEWPORT(vp) );
-
-  rv->waypoint_gc = gdk_gc_new ( GTK_WIDGET(vp)->window );
-  gdk_gc_set_line_attributes ( rv->waypoint_gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
-
-  rv->waypoint_text_gc = gdk_gc_new ( GTK_WIDGET(vp)->window );
-  rv->waypoint_bg_gc = gdk_gc_new ( GTK_WIDGET(vp)->window );
-  gdk_gc_copy ( rv->waypoint_gc, vtl->waypoint_gc );
-  gdk_gc_copy ( rv->waypoint_text_gc, vtl->waypoint_text_gc );
-  gdk_gc_copy ( rv->waypoint_bg_gc, vtl->waypoint_bg_gc );
+  VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
+  guint pl;
+  gchar *tmpname;
+  FILE *f;
 
 
-  rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
 
 
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_copy, rv->waypoints );
-  g_hash_table_foreach ( vtl->tracks, (GHFunc) track_copy, rv->tracks );
+  memcpy(&pl, data, sizeof(pl));
+  data += sizeof(pl);
+  vik_layer_unmarshall_params ( VIK_LAYER(rv), data, pl, vvp );
+  data += pl;
 
 
+  if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
+    g_critical("couldn't open temp file");
+    exit(1);
+  }
+  fwrite(data, len - pl - sizeof(pl), 1, f);
+  rewind(f);
+  a_gpx_read_file(rv, f);
+  fclose(f);
+  f = NULL;
+  g_remove(tmpname);
+  g_free(tmpname);
   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);
+}
+
+static guint strcase_hash(gconstpointer v)
+{
+  /* 31 bit hash function */
+  int i;
+  const gchar *t = v;
+  gchar s[128];   /* malloc is too slow for reading big files */
+  gchar *p = s;
+
+  for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
+      p[i] = toupper(t[i]);
+  p[i] = '\0';
+
+  p = s;
+  guint32 h = *p;
+  if (h) {
+    for (p += 1; *p != '\0'; p++)
+      h = (h << 5) - h + *p;
+  }
+
+  return h;  
+}
+
 VikTrwLayer *vik_trw_layer_new ( gint drawmode )
 {
 VikTrwLayer *vik_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_WPSYM].widget_data == 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 );
 
   VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) );
   vik_layer_init ( VIK_LAYER(rv), VIK_LAYER_TRW );
 
-  rv->waypoints = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_waypoint_free );
+  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->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 ( g_str_hash, g_str_equal, NULL, g_free );
+  rv->waypoints_iters = g_hash_table_new_full ( strcase_hash, strcase_equal, NULL, g_free );
 
   /* TODO: constants at top */
   rv->waypoints_visible = rv->tracks_visible = TRUE;
 
   /* TODO: constants at top */
   rv->waypoints_visible = rv->tracks_visible = TRUE;
@@ -618,6 +795,15 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
   rv->current_tp_track_name = NULL;
   rv->moving_tp = FALSE;
   rv->moving_wp = FALSE;
   rv->current_tp_track_name = NULL;
   rv->moving_tp = FALSE;
   rv->moving_wp = FALSE;
+
+  rv->ct_sync_done = 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->waypoint_rightclick = FALSE;
   rv->last_tpl = NULL;
   rv->last_tp_track_name = NULL;
   rv->waypoint_rightclick = FALSE;
   rv->last_tpl = NULL;
   rv->last_tp_track_name = NULL;
@@ -737,12 +923,13 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
 {
   /* TODO: this function is a mess, get rid of any redundancy */
   GList *list = track->trackpoints;
 {
   /* TODO: this function is a mess, get rid of any redundancy */
   GList *list = track->trackpoints;
+  GdkGC *main_gc;
   gboolean useoldvals = TRUE;
 
   gboolean drawpoints;
   gboolean drawstops;
   gboolean drawelevation;
   gboolean useoldvals = TRUE;
 
   gboolean drawpoints;
   gboolean drawstops;
   gboolean drawelevation;
-  gdouble min_alt, max_alt, alt_diff;
+  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 = 2;
   const guint8 tp_size_cur = 4;
@@ -769,6 +956,11 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     drawstops = dp->vtl->drawstops;
   }
 
     drawstops = dp->vtl->drawstops;
   }
 
+  if ( track == dp->vtl->current_track )
+    main_gc = dp->vtl->current_track_gc;
+  else
+    main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+
   if (list) {
     int x, y, oldx, oldy;
     VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
   if (list) {
     int x, y, oldx, oldy;
     VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
@@ -780,7 +972,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC )
     {
       GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} };
     if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC )
     {
       GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} };
-      vik_viewport_draw_polygon ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, trian, 3 );
+      vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 );
     }
 
     oldx = x;
     }
 
     oldx = x;
@@ -805,16 +997,16 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
         if ( drawpoints && ! drawing_white_background )
         {
           if ( list->next ) {
         if ( drawpoints && ! drawing_white_background )
         {
           if ( list->next ) {
-            vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
+            vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
 
 
-            vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
+            vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
 
             /* stops */
             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
               vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
           }
           else
 
             /* stops */
             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
               vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
           }
           else
-            vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
+            vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
         }
 
         if ((!tp->newsegment) && (dp->vtl->drawlines))
         }
 
         if ((!tp->newsegment) && (dp->vtl->drawlines))
@@ -823,7 +1015,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
 
           /* UTM only: zone check */
           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
 
           /* UTM only: zone check */
           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
-            draw_utm_skip_insignia (  dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y);
+            draw_utm_skip_insignia (  dp->vp, main_gc, x, y);
 
           if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY )
             dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
 
           if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY )
             dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
@@ -836,7 +1028,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           }
           else {
 
           }
           else {
 
-            vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y);
+            vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
             if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
               GdkPoint tmp[4];
               #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
             if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
               GdkPoint tmp[4];
               #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
@@ -857,7 +1049,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
                   tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
                 vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
               }
                   tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
                 vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
               }
-              vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
+              vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
             }
           }
         }
             }
           }
         }
@@ -879,12 +1071,12 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
             if ( drawing_white_background )
               vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
             else
             if ( drawing_white_background )
               vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
             else
-              vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y);
+              vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
           }
           else 
           {
             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
           }
           else 
           {
             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
-            draw_utm_skip_insignia ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y );
+            draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
           }
         }
         useoldvals = FALSE;
           }
         }
         useoldvals = FALSE;
@@ -916,7 +1108,7 @@ static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name )
 static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp )
 {
   if ( wp->visible )
 static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp )
 {
   if ( wp->visible )
-  if ( (!dp->one_zone) || ( wp->coord.utm_zone == dp->center->utm_zone && 
+  if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) && 
              wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 && 
              wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
   {
              wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 && 
              wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
   {
@@ -1051,6 +1243,11 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
     g_object_unref ( vtl->track_bg_gc );
     vtl->track_bg_gc = NULL;
   }
     g_object_unref ( vtl->track_bg_gc );
     vtl->track_bg_gc = NULL;
   }
+  if ( vtl->current_track_gc ) 
+  {
+    g_object_unref ( vtl->current_track_gc );
+    vtl->current_track_gc = NULL;
+  }
 
   if ( ! vtl->track_gc )
     return;
 
   if ( ! vtl->track_gc )
     return;
@@ -1072,6 +1269,11 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
     g_object_unref ( vtl->track_bg_gc );
   vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
 
     g_object_unref ( vtl->track_bg_gc );
   vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
 
+  if ( vtl->current_track_gc )
+    g_object_unref ( vtl->current_track_gc );
+  vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
+  gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+
   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
 
   gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
 
   gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
@@ -1122,6 +1324,8 @@ VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
 
   rv->coord_mode = vik_viewport_get_coord_mode ( vp );
 
 
   rv->coord_mode = vik_viewport_get_coord_mode ( vp );
 
+  rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection;
+
   return rv;
 }
 
   return rv;
 }
 
@@ -1130,7 +1334,7 @@ static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pas
   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, (gint) pass_along[4], NULL, TRUE, TRUE );
+  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 );
 #else
   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
 #endif
 #else
   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
 #endif
@@ -1146,7 +1350,7 @@ static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer
 {
   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, (gint) pass_along[4], NULL, TRUE, TRUE );
+  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 );
 #else
   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
 #endif
 #else
   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
 #endif
@@ -1165,9 +1369,9 @@ void vik_trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *lay
   gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, (gpointer) VIK_TRW_LAYER_SUBLAYER_TRACK };
 
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
   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 );
+  vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
 #else
 #else
-  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), "Tracks", vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
+  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 ); 
 #endif
   if ( ! vtl->tracks_visible )
     vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), FALSE ); 
@@ -1175,9 +1379,9 @@ void vik_trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *lay
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
 
 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
 
 #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 );
+  vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
 #else
 #else
-  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), "Waypoints", vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
+  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
 #endif
 
   if ( ! vtl->waypoints_visible )
 #endif
 
   if ( ! vtl->waypoints_visible )
@@ -1283,7 +1487,7 @@ static void trw_layer_centerize ( gpointer layer_and_vlp[2] )
   if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
     goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp[1]), &coord );
   else
   if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
     goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp[1]), &coord );
   else
-    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], guint file_type )
 }
 
 static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type )
@@ -1291,12 +1495,18 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type )
   GtkWidget *file_selector;
   const gchar *fn;
   gboolean failed = FALSE;
   GtkWidget *file_selector;
   const gchar *fn;
   gboolean failed = FALSE;
-  file_selector = gtk_file_selection_new ("Export Layer");
-
-  while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_OK )
+  file_selector = gtk_file_chooser_dialog_new (_("Export Layer"),
+                                     NULL,
+                                     GTK_FILE_CHOOSER_ACTION_SAVE,
+                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                     GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                     NULL);
+  gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(file_selector), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])));
+
+  while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT )
   {
   {
-    fn = gtk_file_selection_get_filename (GTK_FILE_SELECTION(file_selector) );
-    if ( access ( fn, F_OK ) != 0 )
+    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(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 );
     {
       gtk_widget_hide ( file_selector );
       failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type );
@@ -1304,7 +1514,7 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type )
     }
     else
     {
     }
     else
     {
-      if ( a_dialog_overwrite ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "The file \"%s\" exists, do you wish to overwrite it?", a_file_basename ( fn ) ) )
+      if ( a_dialog_overwrite ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
       {
         gtk_widget_hide ( file_selector );
         failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type );
       {
         gtk_widget_hide ( file_selector );
         failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type );
@@ -1314,7 +1524,7 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type )
   }
   gtk_widget_destroy ( file_selector );
   if ( failed )
   }
   gtk_widget_destroy ( file_selector );
   if ( failed )
-    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "The filename you requested could not be opened for writing." );
+    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The filename you requested could not be opened for writing.") );
 }
 
 static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] )
 }
 
 static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] )
@@ -1335,7 +1545,7 @@ static void trw_layer_export_gpx ( 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]) );
 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 ("Create",
+  GtkWidget *dia = gtk_dialog_new_with_buttons (_("Create"),
                                                  VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                  GTK_STOCK_CANCEL,
                                                  VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                  GTK_STOCK_CANCEL,
@@ -1345,7 +1555,7 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
                                                  NULL);
 
   GtkWidget *label, *entry;
                                                  NULL);
 
   GtkWidget *label, *entry;
-  label = gtk_label_new("Waypoint Name:");
+  label = gtk_label_new(_("Waypoint Name:"));
   entry = gtk_entry_new();
 
   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), label, FALSE, FALSE, 0);
   entry = gtk_entry_new();
 
   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), label, FALSE, FALSE, 0);
@@ -1365,7 +1575,7 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
     wp = g_hash_table_lookup ( wps, upname );
 
     if (!wp)
     wp = g_hash_table_lookup ( wps, upname );
 
     if (!wp)
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "Waypoint not found in this layer." );
+      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) );
     else
     {
       vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
@@ -1382,13 +1592,14 @@ 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;
+  gchar *name = highest_wp_number_get(vtl);
   VikWaypoint *wp = vik_waypoint_new();
   wp->coord = *def_coord;
   wp->altitude = VIK_DEFAULT_ALTITUDE;
 
   if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) )
   {
   VikWaypoint *wp = vik_waypoint_new();
   wp->coord = *def_coord;
   wp->altitude = VIK_DEFAULT_ALTITUDE;
 
   if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) )
   {
+    wp->visible = TRUE;
     vik_trw_layer_add_waypoint ( vtl, name, wp );
     return TRUE;
   }
     vik_trw_layer_add_waypoint ( vtl, name, wp );
     return TRUE;
   }
@@ -1410,6 +1621,7 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl
 {
   static gpointer pass_along[2];
   GtkWidget *item;
 {
   static gpointer pass_along[2];
   GtkWidget *item;
+  GtkWidget *export_submenu;
   pass_along[0] = vtl;
   pass_along[1] = vlp;
 
   pass_along[0] = vtl;
   pass_along[1] = vlp;
 
@@ -1417,35 +1629,62 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
 
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Goto Center of Layer" );
+  item = gtk_menu_item_new_with_label ( _("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 );
 
   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_label ( "Goto Waypoint" );
+  item = gtk_menu_item_new_with_label ( _("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 );
 
   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_menu_item_new_with_label ( "Export Layer as GPSPoint" );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
+  export_submenu = gtk_menu_new ();
+  item = gtk_menu_item_new_with_label ( _("Export layer") );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
+  
+  item = gtk_menu_item_new_with_label ( _("Export as GPSPoint") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+  gtk_widget_show ( item );
 
 
-  item = gtk_menu_item_new_with_label ( "Export Layer as GPSMapper" );
+  item = gtk_menu_item_new_with_label ( _("Export as GPSMapper") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Export Layer as GPX" );
+  item = gtk_menu_item_new_with_label ( _("Export as GPX") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "New Waypoint" );
+  item = gtk_menu_item_new_with_label ( _("New Waypoint") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
+
+#ifdef VIK_CONFIG_OPENSTREETMAP 
+  item = gtk_menu_item_new_with_label ( _("Upload to OSM") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+#endif
+
+  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 ) {
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+  }  
+
+  item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
+       vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
+  if ( item ) {
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+  }  
 }
 
 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
 }
 
 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
@@ -1471,6 +1710,7 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp
   else
     wp->visible = TRUE;
 
   else
     wp->visible = TRUE;
 
+  highest_wp_number_add_wp(vtl, name);
   g_hash_table_insert ( vtl->waypoints, name, wp );
  
 }
   g_hash_table_insert ( vtl->waypoints, name, wp );
  
 }
@@ -1492,33 +1732,18 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 #endif
       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter );
       g_hash_table_insert ( vtl->tracks_iters, name, iter );
 #endif
       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter );
       g_hash_table_insert ( vtl->tracks_iters, name, iter );
-      t->visible = TRUE;
+      /* t->visible = TRUE; */
     }
   }
   else
     }
   }
   else
-    t->visible = TRUE;
+    ; /* t->visible = TRUE; // this is now used by file input functions */
 
   g_hash_table_insert ( vtl->tracks, name, t );
  
 }
 
 
   g_hash_table_insert ( vtl->tracks, name, t );
  
 }
 
-static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str )
-{
-  gchar *upp = g_strdup ( str );
-  gboolean rv;
-  char *tmp = upp;
-  while  ( *tmp )
-  {
-    *tmp = toupper(*tmp);
-    tmp++;
-  }
-  rv = g_hash_table_lookup ( hash, upp ) ? TRUE : FALSE;
-  g_free (upp);
-  return rv;
-}
-
 /* to be called whenever a track has been deleted or may have been changed. */
 /* to be called whenever a track has been deleted or may have been changed. */
-static void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name )
+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 );
 {
   if (vtl->current_tp_track_name && g_strcasecmp(trk_name, vtl->current_tp_track_name) == 0)
     trw_layer_cancel_current_tp ( vtl, FALSE );
@@ -1531,7 +1756,7 @@ static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type
  gint i = 2;
  gchar *newname = g_strdup(name);
  while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ?
  gint i = 2;
  gchar *newname = g_strdup(name);
  while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ?
-         vik_trw_layer_get_track(vtl, newname) : vik_trw_layer_get_waypoint(vtl, newname)) {
+         (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;
     gchar *new_newname = g_strdup_printf("%s#%d", name, i);
     g_free(newname);
     newname = new_newname;
@@ -1540,29 +1765,84 @@ static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type
   return newname;
 }
 
   return newname;
 }
 
+void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
+{
+  vik_trw_layer_add_waypoint ( vtl,
+                        get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name),
+                        wp );
+}
+void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
+{
+  if ( vtl->magic_scissors_append && vtl->magic_scissors_current_track ) {
+    vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
+    vik_track_steal_and_append_trackpoints ( vtl->magic_scissors_current_track, tr );
+    vik_track_free ( tr );
+    vtl->magic_scissors_append = FALSE; /* this means we have added it */
+  } else {
+    gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
+    vik_trw_layer_add_track ( vtl, new_name, tr );
+
+    if ( vtl->magic_scissors_check_added_track ) {
+      vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
+      if ( vtl->magic_scissors_added_track_name ) /* for google routes */
+        g_free ( vtl->magic_scissors_added_track_name );
+      vtl->magic_scissors_added_track_name = g_strdup(new_name);
+    }
+  }
+}
+
+static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l )
+{
+  *l = g_list_append(*l, (gpointer)name);
+}
+
+static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type )
+{
+  gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name);
+  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);
+  }
+  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);
+  }
+}
+
 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
 {
   VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
 {
   VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
+  gint type = vik_treeview_item_get_data(vt, src_item_iter);
+
   if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
   if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
-    g_print("moving a trw container: not implemented yet.\n");
-  } else {
-    gint type = vik_treeview_item_get_data(vt, src_item_iter);
-    gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
+    GList *items = NULL;
+    GList *iter;
 
 
-    if (type==VIK_TRW_LAYER_SUBLAYER_TRACK) {
-      VikTrack *t;
-      gchar *newname = get_new_unique_sublayer_name(vtl_dest, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
-      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);
-    }
-    if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
-      VikWaypoint *w;
-      gchar *newname = get_new_unique_sublayer_name(vtl_dest, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name);
-      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_TRACKS) {
+      g_hash_table_foreach ( vtl_src->tracks, (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);
+    }    
+      
+    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);
+      } else {
+       trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
+      }
+      iter = iter->next;
     }
     }
+    if (items) 
+      g_list_free(items);
+  } else {
+    gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
+    trw_layer_move_item(vtl_src, vtl_dest, name, type);
   }
 }
 
   }
 }
 
@@ -1577,6 +1857,8 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
     was_visible = t->visible;
     if ( t == vtl->current_track )
       vtl->current_track = NULL;
     was_visible = t->visible;
     if ( t == vtl->current_track )
       vtl->current_track = NULL;
+    if ( t == vtl->magic_scissors_current_track )
+      vtl->magic_scissors_current_track = NULL;
 
     /* could be current_tp, so we have to check */
     trw_layer_cancel_tps_of_track ( vtl, trk_name );
 
     /* could be current_tp, so we have to check */
     trw_layer_cancel_tps_of_track ( vtl, trk_name );
@@ -1610,17 +1892,58 @@ gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name
     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 );
     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 );
+
+    highest_wp_number_remove_wp(vtl, wp_name);
     g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */
   }
 
   return was_visible;
 }
 
     g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */
   }
 
   return was_visible;
 }
 
+static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt)
+{
+    vik_treeview_item_delete (vt, it );
+}
+
+void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
+{
+
+  vtl->current_track = NULL;
+  vtl->magic_scissors_current_track = NULL;
+  if (vtl->current_tp_track_name)
+    trw_layer_cancel_current_tp(vtl, FALSE);
+  if (vtl->last_tp_track_name)
+    trw_layer_cancel_last_tp ( vtl );
+
+  g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->tracks_iters);
+  g_hash_table_remove_all(vtl->tracks);
+
+  /* TODO: only update if the layer is visible (ticked) */
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+}
+
+void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
+{
+  vtl->current_wp = NULL;
+  vtl->current_wp_name = NULL;
+  vtl->moving_wp = FALSE;
+
+  highest_wp_number_reset(vtl);
+
+  g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->waypoints_iters);
+  g_hash_table_remove_all(vtl->waypoints);
+
+  /* TODO: only update if the layer is visible (ticked) */
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+}
+
 static void trw_layer_delete_item ( gpointer pass_along[5] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gboolean was_visible = FALSE;
 static void trw_layer_delete_item ( gpointer pass_along[5] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gboolean was_visible = FALSE;
-  if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
     was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
   }
   {
     was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
   }
@@ -1636,7 +1959,7 @@ static void trw_layer_delete_item ( gpointer pass_along[5] )
 static void trw_layer_properties_item ( gpointer pass_along[5] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
 static void trw_layer_properties_item ( gpointer pass_along[5] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+  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] );
     if ( wp )
@@ -1652,56 +1975,10 @@ static void trw_layer_properties_item ( gpointer pass_along[5] )
     VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
     if ( tr )
     {
     VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
     if ( tr )
     {
-      gint resp = vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), tr, pass_along[1] /* vlp */ );
-      if ( resp == VIK_TRW_LAYER_PROPWIN_DEL_DUP )
-      {
-        vik_track_remove_dup_points(tr);
-        /* above operation could have deleted current_tp or last_tp */
-        trw_layer_cancel_tps_of_track ( vtl, (gchar *) pass_along[3] );
-        vik_layer_emit_update ( VIK_LAYER(vtl) );
-      }
-      if ( resp == VIK_TRW_LAYER_PROPWIN_REVERSE )
-      {
-        vik_track_reverse(tr);
-        vik_layer_emit_update ( VIK_LAYER(vtl) );
-      }
-      else if ( resp == VIK_TRW_LAYER_PROPWIN_SPLIT )
-      {
-        /* get new tracks, add them, resolve naming conflicts (free if cancel), and delete old. old can still exist on clipboard. */
-        guint ntracks;
-        VikTrack **tracks = vik_track_split_into_segments(tr, &ntracks);
-        gchar *new_tr_name;
-        guint i;
-        for ( i = 0; i < ntracks; i++ )
-        {
-          g_assert ( tracks[i] );
-          new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i+1);
-          /* if ( (wp_exists) && (! overwrite) ) */
-          /* don't need to upper case new_tr_name because old tr name was uppercase */
-          if ( g_hash_table_lookup ( vtl->tracks, new_tr_name ) && 
-             ( ! a_dialog_overwrite ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "The track \"%s\" exists, do you wish to overwrite it?", new_tr_name ) ) )
-          {
-            gchar *new_new_tr_name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks );
-            g_free ( new_tr_name );
-            if (new_new_tr_name)
-              new_tr_name = new_new_tr_name;
-            else
-            {
-              new_tr_name = NULL;
-              vik_track_free ( tracks[i] );
-            }
-          }
-          if ( new_tr_name )
-            vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
-         
-        }
-        if ( tracks )
-        {
-          g_free ( tracks );
-          vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
-          vik_layer_emit_update ( VIK_LAYER(vtl) ); /* chase thru the hoops */
-        }
-      }
+      vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                     vtl, tr,
+                     pass_along[1], /* vlp */ 
+                     pass_along[3]  /* track name */);
     }
   }
 }
     }
   }
 }
@@ -1721,6 +1998,7 @@ static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] )
 
 static void trw_layer_goto_track_center ( gpointer pass_along[5] )
 {
 
 static void trw_layer_goto_track_center ( gpointer pass_along[5] )
 {
+  /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
   GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
   if ( trps && *trps )
   {
   GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
   if ( trps && *trps )
   {
@@ -1734,6 +2012,45 @@ static void trw_layer_goto_track_center ( gpointer pass_along[5] )
   }
 }
 
   }
 }
 
+static void trw_layer_extend_track_end ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+
+  vtl->current_track = track;
+  vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK);
+
+  if ( track->trackpoints )
+    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
+}
+
+/**
+ * extend a track using magic scissors
+ */
+static void trw_layer_extend_track_end_ms ( 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);
+
+  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;
+
+  if ( track->trackpoints )
+    goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &last_coord) ;
+
+}
+
+static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
+{
+  /* TODO: check & warn if no DEM data, or no applicable DEM data. */
+  /* Also warn if overwrite old elevation data */
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+
+  vik_track_apply_dem_data ( track );
+}
+
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
 {
   GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
 {
   GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
@@ -1758,31 +2075,40 @@ static void find_nearby_track(gpointer key, gpointer value, gpointer user_data)
 
   GList **nearby_tracks = ((gpointer *)user_data)[0];
   GList *orig_track = ((gpointer *)user_data)[1];
 
   GList **nearby_tracks = ((gpointer *)user_data)[0];
   GList *orig_track = ((gpointer *)user_data)[1];
-  guint thr = (guint)((gpointer *)user_data)[2];
+  guint thr = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
 
 
-  t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
-  t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
+  /* outline: 
+   * detect reasons for not merging, and return
+   * if no reason is found not to merge, then do it.
+   */
 
   if (VIK_TRACK(value)->trackpoints == orig_track) {
     return;
   }
 
 
   if (VIK_TRACK(value)->trackpoints == orig_track) {
     return;
   }
 
-  p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
-  p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+  t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
+  t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
 
 
-  if (!p1->has_timestamp || !p2->has_timestamp) {
-    g_print("no timestamp\n");
-    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 (!p1->has_timestamp || !p2->has_timestamp) {
+      g_print("no timestamp\n");
+      return;
+    }
 
 
-  /*  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 */
-      ) {
-    *nearby_tracks = g_list_prepend(*nearby_tracks, key);
+    /*  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 */
+       ) {
+      return;
+    }
   }
   }
+
+  *nearby_tracks = g_list_prepend(*nearby_tracks, key);
 }
 
 /* comparison function used to sort tracks; a and b are hash table keys */
 }
 
 /* comparison function used to sort tracks; a and b are hash table keys */
@@ -1812,26 +2138,29 @@ static gint trackpoint_compare(gconstpointer a, gconstpointer b)
 /* merge by time routine */
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
 {
 /* merge by time routine */
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
 {
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  gchar *orig_track_name = strdup(pass_along[3]);
+
   time_t t1, t2;
   time_t t1, t2;
-  GList *nearby_tracks = NULL;
+  GList *nearby_tracks;
   VikTrack *track;
   GList *trps;
   static  guint thr = 1;
   guint track_count = 0;
   VikTrack *track;
   GList *trps;
   static  guint thr = 1;
   guint track_count = 0;
-  gchar *orig_track_name = strdup(pass_along[3]);
 
 
-  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
-                              "Merge Threshold..."
-                              "Merge when time between trackpoints less than:"
+  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl), 
+                              _("Merge Threshold...")
+                              _("Merge when time between tracks less than:")
                               &thr)) {
     return;
   }
 
   /* merge tracks until we can't */
                               &thr)) {
     return;
   }
 
   /* merge tracks until we can't */
+  nearby_tracks = NULL;
   do {
     gpointer params[3];
 
   do {
     gpointer params[3];
 
-    track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, orig_track_name );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
     trps = track->trackpoints;
     if ( !trps )
       return;
     trps = track->trackpoints;
     if ( !trps )
       return;
@@ -1848,20 +2177,17 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
     /*    g_print("Original track times: %d and %d\n", t1, t2);  */
     params[0] = &nearby_tracks;
     params[1] = trps;
     /*    g_print("Original track times: %d and %d\n", t1, t2);  */
     params[0] = &nearby_tracks;
     params[1] = trps;
-    params[2] = (gpointer)thr;
+    params[2] = GUINT_TO_POINTER (thr);
 
     /* get a list of adjacent-in-time tracks */
 
     /* get a list of adjacent-in-time tracks */
-    g_hash_table_foreach(VIK_TRW_LAYER(pass_along[0])->tracks, find_nearby_track, (gpointer)params);
+    g_hash_table_foreach(vtl->tracks, find_nearby_track, (gpointer)params);
 
     /* add original track */
     nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name);
 
 
     /* add original track */
     nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name);
 
-    /* sort by first trackpoint; assumes they don't overlap */
-    nearby_tracks = g_list_sort_with_data(nearby_tracks, track_compare, VIK_TRW_LAYER(pass_along[0])->tracks);
-
     /* merge them */
     { 
     /* merge them */
     { 
-#define get_track(x) VIK_TRACK(g_hash_table_lookup(VIK_TRW_LAYER(pass_along[0])->tracks, (gchar *)((x)->data)))
+#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;
 #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;
@@ -1880,13 +2206,13 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
        /* remove trackpoints from merged track, delete track */
        tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints);
        get_track(l)->trackpoints = NULL;
        /* 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(VIK_TRW_LAYER(pass_along[0]), l->data);
+       vik_trw_layer_delete_track(vtl, l->data);
 
        track_count ++;
        l = g_list_next(l);
       }
       tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare);
 
        track_count ++;
        l = g_list_next(l);
       }
       tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare);
-      vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), strdup(orig_track_name), tr);
+      vik_trw_layer_add_track(vtl, strdup(orig_track_name), tr);
 
 #undef get_first_trackpoint
 #undef get_last_trackpoint
 
 #undef get_first_trackpoint
 #undef get_last_trackpoint
@@ -1895,7 +2221,7 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
   } while (track_count > 1);
   g_list_free(nearby_tracks);
   free(orig_track_name);
   } while (track_count > 1);
   g_list_free(nearby_tracks);
   free(orig_track_name);
-  vik_layer_emit_update(VIK_LAYER(pass_along[0]));
+  vik_layer_emit_update( VIK_LAYER(vtl) );
 }
 
 /* split by time routine */
 }
 
 /* split by time routine */
@@ -1915,8 +2241,8 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
     return;
 
   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
     return;
 
   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
-                              "Split Threshold..."
-                              "Split when time between trackpoints exceeds:"
+                              _("Split Threshold...")
+                              _("Split when time between trackpoints exceeds:")
                               &thr)) {
     return;
   }
                               &thr)) {
     return;
   }
@@ -1982,18 +2308,7 @@ static void trw_layer_goto_waypoint ( gpointer pass_along[5] )
 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] )
 {
   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] );
 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] )
 {
   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] );
-#ifdef WINDOWS
-  ShellExecute(NULL, NULL, (char *) webpage, NULL, ".\\", 0);
-#else /* WINDOWS */
-  GError *err = NULL;
-  gchar *cmd = g_strdup_printf ( "%s %s", UNIX_WEB_BROWSER, webpage );
-  if ( ! g_spawn_command_line_async ( cmd, &err ) )
-  {
-    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), "Could not launch web browser." );
-    g_error_free ( err );
-  }
-  g_free ( cmd );
-#endif /* WINDOWS */
+  open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
   g_free ( webpage );
 }
 
   g_free ( webpage );
 }
 
@@ -2001,31 +2316,32 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
 {
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
 {
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
-    int i;
     gchar *rv;
     VikWaypoint *wp;
 
     gchar *rv;
     VikWaypoint *wp;
 
-    if ( strcasecmp ( newname, sublayer ) == 0 )
+    if (strcmp(newname, sublayer) == 0 )
       return NULL;
 
       return NULL;
 
-    if ( uppercase_exists_in_hash ( l->waypoints, newname ) )
-    {
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), "Waypoint Already Exists" );
-      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") );
+        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 )) );
     }
 
     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 );
 
     rv = g_strdup(newname);
     g_hash_table_remove ( l->waypoints, sublayer );
 
     rv = g_strdup(newname);
-    for ( i = strlen(rv) - 1; i >= 0; i-- )
-      rv[i] = toupper(rv[i]);
 
     vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
 
 
     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 );
 
     g_hash_table_insert ( l->waypoints, rv, wp );
     g_hash_table_insert ( l->waypoints_iters, rv, iter );
 
@@ -2039,19 +2355,20 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
   }
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
   }
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
-    int i;
     gchar *rv;
     VikTrack *tr;
     GtkTreeIter *iter;
     gchar *orig_key;
 
     gchar *rv;
     VikTrack *tr;
     GtkTreeIter *iter;
     gchar *orig_key;
 
-    if ( strcasecmp ( newname, sublayer ) == 0 )
+    if (strcmp(newname, sublayer) == 0)
       return NULL;
 
       return NULL;
 
-    if ( uppercase_exists_in_hash ( l->tracks, newname ) )
-    {
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), "Track Already Exists" );
-      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), _("Track Already Exists") );
+        return NULL;
+      }
     }
 
     g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
     }
 
     g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
@@ -2061,8 +2378,6 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
     g_hash_table_steal ( l->tracks_iters, sublayer );
 
     rv = g_strdup(newname);
     g_hash_table_steal ( l->tracks_iters, sublayer );
 
     rv = g_strdup(newname);
-    for ( i = strlen(rv) - 1; i >= 0; i-- )
-      rv[i] = toupper(rv[i]);
 
     vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
 
 
     vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
 
@@ -2094,7 +2409,33 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
 static gboolean is_valid_geocache_name ( gchar *str )
 {
   gint len = strlen ( str );
 static gboolean is_valid_geocache_name ( gchar *str )
 {
   gint len = strlen ( str );
-  return len >= 3 && len <= 6 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5]));
+  return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
+}
+
+static void trw_layer_track_use_with_filter ( gpointer *pass_along )
+{
+  gchar *track_name = (gchar *) pass_along[3];
+  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
+  a_acquire_set_filter_track ( tr, track_name );
+}
+
+static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name )
+{
+  VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_name );
+  return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
+}
+
+static void trw_layer_track_google_route_webpage( gpointer *pass_along )
+{
+  gchar *track_name = (gchar *) pass_along[3];
+  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
+  if ( tr ) {
+    gchar *escaped = uri_escape ( tr->comment );
+    gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
+    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
+    g_free ( escaped );
+    g_free ( webpage );
+  }
 }
 
 /* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
 }
 
 /* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
@@ -2107,7 +2448,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
 
   pass_along[0] = l;
   pass_along[1] = vlp;
 
   pass_along[0] = l;
   pass_along[1] = vlp;
-  pass_along[2] = (gpointer) subtype;
+  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[3] = sublayer;
   staticiter = *iter; /* will exist after function has ended */
   pass_along[4] = &staticiter;
@@ -2121,16 +2462,33 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
     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_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
+    if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
+      VikTrwLayer *vtl = l;
+      VikTrack *tr = g_hash_table_lookup ( vtl->tracks, sublayer );
+      if (tr && tr->property_dialog)
+        gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
+    }
+
+    item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), 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 );
 
-    if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
-    {
+    item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+    {
       /* could be a right-click using the tool */
       if ( vlp != NULL ) {
       /* could be a right-click using the tool */
       if ( vlp != NULL ) {
-        item = gtk_menu_item_new_with_label ( "Goto" );
+        item = gtk_menu_item_new_with_label ( _("Goto") );
         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 );
@@ -2138,7 +2496,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
 
       if ( is_valid_geocache_name ( (gchar *) sublayer ) )
       {
 
       if ( is_valid_geocache_name ( (gchar *) sublayer ) )
       {
-        item = gtk_menu_item_new_with_label ( "Visit Geocache Webpage" );
+        item = gtk_menu_item_new_with_label ( _("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 );
         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 );
@@ -2153,142 +2511,96 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
     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_label ( "Goto Startpoint" );
+    item = gtk_menu_item_new_with_label ( _("Goto Startpoint") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), 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_track_startpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_label ( "Goto \"Center\"" );
+    item = gtk_menu_item_new_with_label ( _("Goto \"Center\"") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), 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_track_center), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_label ( "Goto Endpoint" );
+    item = gtk_menu_item_new_with_label ( _("Goto Endpoint") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), 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_track_endpoint), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_label ( "Merge By Time" );
+    item = gtk_menu_item_new_with_label ( _("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 );
 
     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 );
 
-    item = gtk_menu_item_new_with_label ( "Split By Time" );
+    item = gtk_menu_item_new_with_label ( _("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 );
     gtk_widget_show ( item );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
-  }
 
 
-  if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
-  {
-    item = gtk_menu_item_new ();
+    item = gtk_menu_item_new_with_label ( _("Download maps along track...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    item = gtk_menu_item_new_with_label ( "New Waypoint" );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
-    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    item = gtk_menu_item_new_with_label ( _("Apply DEM Data") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
     gtk_widget_show ( item );
-  }
 
 
-  return rv;
-}
+    item = gtk_menu_item_new_with_label ( _("Extend track end") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
 
 
-/* Params are: vvp, event, last match found or NULL */
-static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] )
-{
-  if ( wp->image && wp->visible )
-  {
-    gint x, y, slackx, slacky;
-    GdkEventButton *event = (GdkEventButton *) params[1];
+    item = gtk_menu_item_new_with_label ( _("Extend using magic scissors") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_ms), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
 
 
-    vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
-    slackx = wp->image_width / 2;
-    slacky = wp->image_height / 2;
-    if (    x <= event->x + slackx && x >= event->x - slackx
-         && y <= event->y + slacky && y >= event->y - slacky )
-    {
-      params[2] = wp->image; /* we've found a match. however continue searching
-                              * since we want to find the last match -- that
-                              * is, the match that was drawn last. */
-    }
-  }
-}
+#ifdef VIK_CONFIG_OPENSTREETMAP
+    item = gtk_menu_item_new_with_label ( _("Upload to OSM") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+#endif
 
 
-static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
-{
-  gpointer params[3] = { vvp, event, NULL };
-  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 ) )
+    if ( is_valid_google_route ( l, (gchar *) sublayer ) )
     {
     {
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." );
-      g_error_free ( err );
+      item = gtk_menu_item_new_with_label ( _("View Google Directions") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
     }
     }
-    g_free ( cmd );
-#endif /* WINDOWS */
-    return TRUE; /* found a match */
-  }
-  else
-    return FALSE; /* go through other layers, searching for a match */
-}
-
-static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
-{
-  VikCoord coord;
-  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) );
-  return TRUE;
-}
-
-typedef struct {
-  gint x, y;
-  gint closest_x, closest_y;
-  gchar *closest_track_name;
-  VikTrackpoint *closest_tp;
-  VikViewport *vvp;
-  GList *closest_tpl;
-} TPSearchParams;
 
 
-static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
-{
-  GList *tpl = t->trackpoints;
-  VikTrackpoint *tp;
+    item = gtk_menu_item_new_with_label ( _("Use with filter") );
+    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 );
 
 
-  if ( !t->visible )
-    return;
+    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 );
+    }  
+  }
 
 
-  while (tpl)
+  if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
   {
   {
-    gint x, y;
-    tp = VIK_TRACKPOINT(tpl->data);
+    item = gtk_menu_item_new ();
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
 
 
-    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;
-    }
-    tpl = tpl->next;
+    item = gtk_menu_item_new_with_label ( _("New Waypoint") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
   }
   }
+
+  return rv;
 }
 
 }
 
+
 /* to be called when last_tpl no long exists. */
 static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
 {
 /* to be called when last_tpl no long exists. */
 static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
 {
@@ -2450,102 +2762,11 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
   /* set layer name and TP data */
 }
 
   /* set layer name and TP data */
 }
 
-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 gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
-{
-  if ( vtl->moving_tp )
-  {
-    /* vtl->moving_tp_x, vtl->moving_tp_y, etc. */
-    VikCoord new_coord;
-    vtl->moving_tp = FALSE;
-    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 && tp != vtl->current_tpl->data )
-        new_coord = tp->coord;
-    }
-
-    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
-
-    /* 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 );
-
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
-    return TRUE;
-  }
-  return FALSE;
-}
-
-static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
-{
-  TPSearchParams params;
-  /* OUTDATED DOCUMENTATION:
-   find 5 pixel range on each side. then put these UTM, and a pointer
-   to the winning track name (and maybe the winning track itself), and a
-   pointer to the winning trackpoint, inside an array or struct. pass 
-   this along, do a foreach on the tracks which will do a foreach on the 
-   trackpoints. */
-  params.vvp = vvp;
-  params.x = event->x;
-  params.y = event->y;
-  params.closest_track_name = 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;
-
-  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 );
-
-    vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
-
-    if ( current_tr->visible && 
-         abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
-         abs(y - event->y) < TRACKPOINT_SIZE_APPROX )
-    {
-      vtl->moving_tp = 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 ( params.closest_tp )
-  {
-    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 ) );
-    trw_layer_tpwin_init ( vtl );
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
-    return TRUE;
-  }
-
+/***************************************************************************
+ ** Tool code
+ ***************************************************************************/
 
 
-  /* these aren't the droids you're looking for */
-  return FALSE;
-}
+/*** Utility data structures and functions ****/
 
 typedef struct {
   gint x, y;
 
 typedef struct {
   gint x, y;
@@ -2555,6 +2776,15 @@ typedef struct {
   VikViewport *vvp;
 } WPSearchParams;
 
   VikViewport *vvp;
 } WPSearchParams;
 
+typedef struct {
+  gint x, y;
+  gint closest_x, closest_y;
+  gchar *closest_track_name;
+  VikTrackpoint *closest_tp;
+  VikViewport *vvp;
+  GList *closest_tpl;
+} TPSearchParams;
+
 static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
 {
   gint x, y;
 static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
 {
   gint x, y;
@@ -2574,45 +2804,45 @@ static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchP
   }
 }
 
   }
 }
 
-static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
 {
 {
-  if ( vtl->moving_wp )
-  {
-    VikCoord new_coord;
-    vtl->moving_wp = FALSE;
-    vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
+  GList *tpl = t->trackpoints;
+  VikTrackpoint *tp;
 
 
-    /* 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;
-    }
+  if ( !t->visible )
+    return;
 
 
-    /* snap to WP */
-    if ( event->state & GDK_SHIFT_MASK )
+  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)))
     {
     {
-      VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
-      if ( wp && wp != vtl->current_wp )
-        new_coord = wp->coord;
+      params->closest_track_name = name;
+      params->closest_tp = tp;
+      params->closest_tpl = tpl;
+      params->closest_x = x;
+      params->closest_y = y;
     }
     }
+    tpl = tpl->next;
+  }
+}
 
 
-    vtl->current_wp->coord = new_coord;
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
-    return TRUE;
-  }
-  /* PUT IN RIGHT PLACE!!! */
-  if ( 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() );
-    vtl->waypoint_rightclick = FALSE;
-  }
-  return FALSE;
+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 )
 }
 
 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
@@ -2627,9 +2857,80 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie
   return params.closest_wp;
 }
 
   return params.closest_wp;
 }
 
-static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+/* background drawing hook, to be passed the viewport */
+static gboolean tool_sync_done = TRUE;
+
+static gboolean tool_sync(gpointer data)
+{
+  VikViewport *vvp = data;
+  gdk_threads_enter();
+  vik_viewport_sync(vvp);
+  tool_sync_done = TRUE;
+  gdk_threads_leave();
+  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;
+  t->gc = vik_viewport_new_gc (t->vvp, "black", 2);
+  gdk_gc_set_function ( t->gc, GDK_INVERT );
+  vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
+  vik_viewport_sync(t->vvp);
+  t->oldx = x;
+  t->oldy = y;
+}
+
+static void marker_moveto ( tool_ed_t *t, gint x, gint y )
+{
+  VikViewport *vvp =  t->vvp;
+  vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
+  vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
+  t->oldx = x;
+  t->oldy = y;
+
+  if (tool_sync_done) {
+    g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
+    tool_sync_done = FALSE;
+  }
+}
+
+static void marker_end_move ( tool_ed_t *t )
+{
+  vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
+  g_object_unref ( t->gc );
+  t->holding = FALSE;
+}
+
+/*** Edit waypoint ****/
+
+static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp)
+{
+  tool_ed_t *t = g_new(tool_ed_t, 1);
+  t->vvp = vvp;
+  t->holding = FALSE;
+  return t;
+}
+
+static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
 {
   WPSearchParams params;
 {
   WPSearchParams params;
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
+  if ( t->holding ) {
+    return TRUE;
+  }
 
   if ( vtl->current_wp && vtl->current_wp->visible )
   {
 
   if ( vtl->current_wp && vtl->current_wp->visible )
   {
@@ -2637,13 +2938,14 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi
     gint x, y;
     vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
 
     gint x, y;
     vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
 
-    if ( abs(x - event->x) < WAYPOINT_SIZE_APPROX &&
-         abs(y - event->y) < WAYPOINT_SIZE_APPROX )
+    if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
+         abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
     {
       if ( event->button == 3 )
         vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
     {
       if ( event->button == 3 )
         vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
-      else
-        vtl->moving_wp = TRUE;
+      else {
+       marker_begin_move(t, event->x, event->y);
+      }
       return TRUE;
     }
   }
       return TRUE;
     }
   }
@@ -2657,7 +2959,10 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
   if ( vtl->current_wp == params.closest_wp && vtl->current_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 )
   {
-    vtl->moving_wp = TRUE;
+    /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
+    marker_begin_move(t, event->x, event->y);
+    g_critical("shouldn't be here");
+    exit(1);
   }
   else if ( params.closest_wp )
   {
   }
   else if ( params.closest_wp )
   {
@@ -2668,7 +2973,6 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi
 
     vtl->current_wp = params.closest_wp;
     vtl->current_wp_name = params.closest_wp_name;
 
     vtl->current_wp = params.closest_wp;
     vtl->current_wp_name = params.closest_wp_name;
-    vtl->moving_wp = FALSE;
 
     if ( params.closest_wp )
       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) );
 
     if ( params.closest_wp )
       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) );
@@ -2680,15 +2984,194 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi
 
   vtl->current_wp = NULL;
   vtl->current_wp_name = NULL;
 
   vtl->current_wp = NULL;
   vtl->current_wp_name = NULL;
-  vtl->moving_wp = FALSE;
   vtl->waypoint_rightclick = FALSE;
   vtl->waypoint_rightclick = FALSE;
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  return FALSE;
+}
+
+static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
+{
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
+  if ( t->holding ) {
+    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 && wp != vtl->current_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;
 }
 
   return FALSE;
 }
 
-static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
+{
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+  
+  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 && wp != vtl->current_wp )
+        new_coord = wp->coord;
+    }
+
+    marker_end_move ( t );
+
+    vtl->current_wp->coord = new_coord;
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    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() );
+    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)
+{
+  return vvp;
+}
+
+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 );
+  return FALSE;
+}
+
+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;
+    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 );
+
+    passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
+    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;
+    return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
+  }
+  return VIK_LAYER_TOOL_ACK;
+}
+
+static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
+{
+  if ( vtl->current_track && event->keyval == GDK_Escape ) {
+    vtl->current_track = NULL;
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    return TRUE;
+  } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
+    /* undo */
+    if ( vtl->current_track->trackpoints )
+    {
+      GList *last = g_list_last(vtl->current_track->trackpoints);
+      g_free ( last->data );
+      vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
+    }
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   VikTrackpoint *tp;
 
 {
   VikTrackpoint *tp;
 
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
   if ( event->button == 3 && vtl->current_track )
   {
     /* undo */
   if ( event->button == 3 && vtl->current_track )
   {
     /* undo */
@@ -2713,6 +3196,7 @@ static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikVie
       /* undo last, then end */
       vtl->current_track = NULL;
     }
       /* undo last, then end */
       vtl->current_track = NULL;
     }
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
 
     return TRUE;
   }
 
@@ -2724,6 +3208,9 @@ static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikVie
       vtl->current_track = vik_track_new();
       vtl->current_track->visible = TRUE;
       vik_trw_layer_add_track ( vtl, name, vtl->current_track );
       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;
     }
     else
       return TRUE;
@@ -2754,6 +3241,317 @@ static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikVie
   return TRUE;
 }
 
   return TRUE;
 }
 
+
+/*** New waypoint ****/
+
+static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  VikCoord coord;
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    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) );
+  return TRUE;
+}
+
+
+/*** Edit trackpoint ****/
+
+static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp)
+{
+  tool_ed_t *t = g_new(tool_ed_t, 1);
+  t->vvp = vvp;
+  t->holding = FALSE;
+  return t;
+}
+
+static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
+{
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
+  TPSearchParams params;
+  /* OUTDATED DOCUMENTATION:
+   find 5 pixel range on each side. then put these UTM, and a pointer
+   to the winning track name (and maybe the winning track itself), and a
+   pointer to the winning trackpoint, inside an array or struct. pass 
+   this along, do a foreach on the tracks which will do a foreach on the 
+   trackpoints. */
+  params.vvp = vvp;
+  params.x = event->x;
+  params.y = event->y;
+  params.closest_track_name = 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;
+
+  if ( event->button != 1 ) 
+    return FALSE;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    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 );
+
+    vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
+
+    if ( current_tr->visible && 
+         abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
+         abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
+      marker_begin_move ( t, event->x, event->y );
+      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 ( params.closest_tp )
+  {
+    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 ) );
+    trw_layer_tpwin_init ( vtl );
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    return TRUE;
+  }
+
+  /* these aren't the droids you're looking for */
+  return FALSE;
+}
+
+static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
+{
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
+  if ( t->holding )
+  {
+    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 && tp != vtl->current_tpl->data )
+        new_coord = tp->coord;
+    }
+    //    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_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 tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
+{
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+  if ( event->button != 1) 
+    return FALSE;
+
+  if ( t->holding ) {
+    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 && tp != vtl->current_tpl->data )
+        new_coord = tp->coord;
+    }
+
+    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
+
+    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 );
+
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    return TRUE;
+  }
+  return FALSE;
+}
+
+
+/*** Magic Scissors ***/
+static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  VikCoord tmp;
+  if ( !vtl ) return FALSE;
+  vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
+  if ( event->button == 3 && vtl->magic_scissors_current_track ) {
+    VikCoord *new_end;
+    new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track );
+    if ( new_end ) {
+      vtl->magic_scissors_coord = *new_end;
+      g_free ( new_end );
+      vik_layer_emit_update ( VIK_LAYER(vtl) );
+      /* remove last ' to:...' */
+      if ( vtl->magic_scissors_current_track->comment ) {
+        gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' );
+        if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) {
+          gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment,
+                                           last_to - vtl->magic_scissors_current_track->comment - 1);
+          vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+        }
+      }
+    }
+  }
+  else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) {
+    struct LatLon start, end;
+    gchar 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 ( &(tmp), &end );
+    vtl->magic_scissors_coord = tmp; /* for continuations */
+
+    /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
+    if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) {
+      vtl->magic_scissors_append = TRUE;  // merge tracks. keep started true.
+    } else {
+      vtl->magic_scissors_check_added_track = TRUE;
+      vtl->magic_scissors_started = FALSE;
+    }
+
+    url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING,
+                          g_ascii_dtostr (startlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lat),
+                          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, "google", NULL, NULL );
+    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 );
+    }
+    vtl->magic_scissors_check_added_track = FALSE;
+    vtl->magic_scissors_append = FALSE;
+
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+  } else {
+    vtl->magic_scissors_started = TRUE;
+    vtl->magic_scissors_coord = tmp;
+    vtl->magic_scissors_current_track = NULL;
+  }
+  return TRUE;
+}
+
+/*** Show picture ****/
+
+static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+/* Params are: vvp, event, last match found or NULL */
+static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] )
+{
+  if ( wp->image && wp->visible )
+  {
+    gint x, y, slackx, slacky;
+    GdkEventButton *event = (GdkEventButton *) params[1];
+
+    vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
+    slackx = wp->image_width / 2;
+    slacky = wp->image_height / 2;
+    if (    x <= event->x + slackx && x >= event->x - slackx
+         && y <= event->y + slacky && y >= event->y - slacky )
+    {
+      params[2] = wp->image; /* we've found a match. however continue searching
+                              * since we want to find the last match -- that
+                              * is, the match that was drawn last. */
+    }
+  }
+}
+
+static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  gpointer params[3] = { vvp, event, NULL };
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+  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 */
+    return TRUE; /* found a match */
+  }
+  else
+    return FALSE; /* go through other layers, searching for a match */
+}
+
+/***************************************************************************
+ ** End tool code 
+ ***************************************************************************/
+
+
+
+
+
 static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
 {
   if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
 static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
 {
   if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
@@ -2789,7 +3587,7 @@ static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
     if ( pics )
     {
       gint len = g_slist_length ( pics );
     if ( pics )
     {
       gint len = g_slist_length ( pics );
-      gchar *tmp = g_strdup_printf ( "Creating %d Image Thumbnails...", len );
+      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 );
       g_free ( tmp );
     }
       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 );
       g_free ( tmp );
     }
@@ -2832,3 +3630,291 @@ VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, gchar *name )
 {
   return g_hash_table_lookup ( vtl->tracks, name );
 }
 {
   return g_hash_table_lookup ( vtl->tracks, name );
 }
+
+static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection)
+{
+  vtl->menu_selection = selection;
+}
+
+static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl)
+{
+  return(vtl->menu_selection);
+}
+
+/* ----------- Downloading maps along tracks --------------- */
+
+static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
+{
+  /* TODO: calculating based on current size of viewport */
+  const gdouble w_at_zoom_0_125 = 0.0013;
+  const gdouble h_at_zoom_0_125 = 0.0011;
+  gdouble zoom_factor = zoom_level/0.125;
+
+  wh->lat = h_at_zoom_0_125 * zoom_factor;
+  wh->lon = w_at_zoom_0_125 * zoom_factor;
+
+  return 0;   /* all OK */
+}
+
+static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
+{
+  if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
+      (dist->lat >= ABS(to->north_south - from->north_south)))
+    return NULL;
+
+  VikCoord *coord = g_malloc(sizeof(VikCoord));
+  coord->mode = VIK_COORD_LATLON;
+
+  if (ABS(gradient) < 1) {
+    if (from->east_west > to->east_west)
+      coord->east_west = from->east_west - dist->lon;
+    else
+      coord->east_west = from->east_west + dist->lon;
+    coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
+  } else {
+    if (from->north_south > to->north_south)
+      coord->north_south = from->north_south - dist->lat;
+    else
+      coord->north_south = from->north_south + dist->lat;
+    coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
+  }
+
+  return coord;
+}
+
+static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
+{
+  /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
+  gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
+
+  VikCoord *next = from;
+  while (TRUE) {
+    if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
+        break;
+    list = g_list_prepend(list, next);
+  }
+
+  return list;
+}
+
+void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
+{
+  typedef struct _Rect {
+    VikCoord tl;
+    VikCoord br;
+    VikCoord center;
+  } Rect;
+#define GLRECT(iter) ((Rect *)((iter)->data))
+
+  struct LatLon wh;
+  GList *rects_to_download = NULL;
+  GList *rect_iter;
+
+  if (get_download_area_width(vvp, zoom_level, &wh))
+    return;
+
+  GList *iter = tr->trackpoints;
+  if (!iter)
+    return;
+
+  gboolean new_map = TRUE;
+  VikCoord *cur_coord, tl, br;
+  Rect *rect;
+  while (iter) {
+    cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
+    if (new_map) {
+      vik_coord_set_area(cur_coord, &wh, &tl, &br);
+      rect = g_malloc(sizeof(Rect));
+      rect->tl = tl;
+      rect->br = br;
+      rect->center = *cur_coord;
+      rects_to_download = g_list_prepend(rects_to_download, rect);
+      new_map = FALSE;
+      iter = iter->next;
+      continue;
+    }
+    gboolean found = FALSE;
+    for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
+      if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
+        found = TRUE;
+        break;
+      }
+    }
+    if (found)
+        iter = iter->next;
+    else
+      new_map = TRUE;
+  }
+
+  /* fill-ins for far apart points */
+  GList *cur_rect, *next_rect;
+  GList *fillins = NULL;
+  for (cur_rect = rects_to_download;
+      (next_rect = cur_rect->next) != NULL;
+      cur_rect = cur_rect->next) {
+    if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
+        (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
+      fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
+    }
+  }
+
+  if (fillins) {
+    GList *iter = fillins;
+    while (iter) {
+      cur_coord = (VikCoord *)(iter->data);
+      vik_coord_set_area(cur_coord, &wh, &tl, &br);
+      rect = g_malloc(sizeof(Rect));
+      rect->tl = tl;
+      rect->br = br;
+      rect->center = *cur_coord;
+      rects_to_download = g_list_prepend(rects_to_download, rect);
+      iter = iter->next;
+    }
+  }
+
+  for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
+    maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
+  }
+
+  if (fillins) {
+    for (iter = fillins; iter; iter = iter->next)
+      g_free(iter->data);
+    g_list_free(fillins);
+  }
+  if (rects_to_download) {
+    for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
+      g_free(rect_iter->data);
+    g_list_free(rects_to_download);
+  }
+}
+
+static void trw_layer_download_map_along_track_cb(gpointer pass_along[6])
+{
+  VikMapsLayer *vml;
+  gint selected_map, default_map;
+  gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
+  gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
+  gint selected_zoom, default_zoom;
+  int i,j;
+
+
+  VikTrwLayer *vtl = pass_along[0];
+  VikLayersPanel *vlp = pass_along[1];
+  VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
+
+  GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS);
+  int num_maps = g_list_length(vmls);
+
+  if (!num_maps) {
+    a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR, _("No map layer in use. Create one first"), NULL);
+    return;
+  }
+
+  gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
+  VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
+
+  gchar **np = map_names;
+  VikMapsLayer **lp = map_layers;
+  for (i = 0; i < num_maps; i++) {
+    gboolean dup = FALSE;
+    vml = (VikMapsLayer *)(vmls->data);
+    for (j = 0; j < i; j++) { /* no duplicate allowed */
+      if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) {
+        dup = TRUE;
+        break;
+      }
+    }
+    if (!dup) {
+      *lp++ = vml;
+      *np++ = vik_maps_layer_get_map_label(vml);
+    }
+    vmls = vmls->next;
+  }
+  *lp = NULL;
+  *np = NULL;
+  num_maps = lp - map_layers;
+
+  for (default_map = 0; default_map < num_maps; default_map++) {
+    /* TODO: check for parent layer's visibility */
+    if (VIK_LAYER(map_layers[default_map])->visible)
+      break;
+  }
+  default_map = (default_map == num_maps) ? 0 : default_map;
+
+  gdouble cur_zoom = vik_viewport_get_zoom(vvp);
+  for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
+    if (cur_zoom == zoom_vals[default_zoom])
+      break;
+  }
+  default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
+
+  if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom))
+    goto done;
+
+  vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
+
+done:
+  for (i = 0; i < num_maps; i++)
+    g_free(map_names[i]);
+  g_free(map_names);
+  g_free(map_layers);
+
+  g_list_free(vmls);
+
+}
+
+/**** lowest waypoint number calculation ***/
+static gint highest_wp_number_name_to_number(const gchar *name) {
+  if ( strlen(name) == 3 ) {
+    int n = atoi(name);
+    if ( n < 100 && name[0] != '0' )
+      return -1;
+    if ( n < 10 && name[0] != '0' )
+      return -1;
+    return n;
+  }
+  return -1;
+}
+
+
+static void highest_wp_number_reset(VikTrwLayer *vtl)
+{
+  vtl->highest_wp_number = -1;
+}
+
+static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name)
+{
+  /* if is bigger that top, add it */
+  gint new_wp_num = highest_wp_number_name_to_number(new_wp_name);
+  if ( new_wp_num > vtl->highest_wp_number )
+    vtl->highest_wp_number = new_wp_num;
+}
+
+static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name)
+{
+  /* if wasn't top, do nothing. if was top, count backwards until we find one used */
+  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 --;
+
+    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 --;
+      g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
+    }
+  }
+}
+
+/* get lowest unused number */
+static gchar *highest_wp_number_get(VikTrwLayer *vtl)
+{
+  gchar buf[4];
+  if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 )
+    return NULL;
+  g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 );
+  return g_strdup(buf);
+}