]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Fix a bug that causes segfault on trackpoint properties dialog.
[andy/viking.git] / src / viktrwlayer.c
index c30fe0425bed85739db0e28a1a28108de59ad0b8..9e338ad340a7fc3964d0418734cfe6585d7f4a00 100644 (file)
 #include "viktrwlayer_pixmap.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_pixmap.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
+#include "garminsymbols.h"
 #include "thumbnails.h"
 #include "background.h"
 #include "thumbnails.h"
 #include "background.h"
+#include "gpx.h"
 
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 
+#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%f,%f to %f,%f&output=js\" 2>/dev/null)"
 #define VIK_TRW_LAYER_TRACK_GC 13
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
 #define VIK_TRW_LAYER_TRACK_GC 13
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
 #define TRACKPOINT_SIZE_APPROX 5
 #define WAYPOINT_SIZE_APPROX 5
 
 #define TRACKPOINT_SIZE_APPROX 5
 #define WAYPOINT_SIZE_APPROX 5
 
+#define MIN_STOP_LENGTH 15
+#define MAX_STOP_LENGTH 86400
+#define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
+                                 /* this is multiplied by user-inputted value from 1-100. */
 enum {
 VIK_TRW_LAYER_SUBLAYER_TRACKS,
 VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
 enum {
 VIK_TRW_LAYER_SUBLAYER_TRACKS,
 VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
@@ -72,12 +79,17 @@ struct _VikTrwLayer {
   gboolean tracks_visible, waypoints_visible;
   guint8 drawmode;
   guint8 drawpoints;
   gboolean tracks_visible, waypoints_visible;
   guint8 drawmode;
   guint8 drawpoints;
+  guint8 drawelevation;
+  guint8 elevation_factor;
+  guint8 drawstops;
+  guint32 stop_length;
   guint8 drawlines;
   guint8 line_thickness;
   guint8 bg_line_thickness;
 
   guint8 wp_symbol;
   guint8 wp_size;
   guint8 drawlines;
   guint8 line_thickness;
   guint8 bg_line_thickness;
 
   guint8 wp_symbol;
   guint8 wp_size;
+  gboolean wp_draw_symbols;
 
   gdouble velocity_min, velocity_max;
   GArray *track_gc;
 
   gdouble velocity_min, velocity_max;
   GArray *track_gc;
@@ -110,6 +122,10 @@ 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 drawlabels;
   gboolean drawimages;
   guint8 image_alpha;
   gboolean drawlabels;
   gboolean drawimages;
   guint8 image_alpha;
@@ -124,6 +140,9 @@ struct _VikTrwLayer {
 
   GtkMenu *wp_right_click_menu;
 
 
   GtkMenu *wp_right_click_menu;
 
+  /* menu */
+  VikStdLayerMenuItem menu_selection;
+
 };
 
 /* A caached waypoint image. */
 };
 
 /* A caached waypoint image. */
@@ -143,6 +162,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] );    
 
@@ -172,28 +198,43 @@ 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 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_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_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 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, GdkEventButton *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, GdkEventButton *event, gpointer data );
+static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
+static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
+static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+
 
 static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str );
 
 
 static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str );
 
@@ -206,14 +247,33 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie
 
 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
 
 
 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 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 }, 
-};
+  { "Create Waypoint", (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL, 
+    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL },
 
 
+  { "Create Track",    (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL, 
+    (VikToolMouseFunc) tool_new_track_click,       NULL, NULL },
+
+  { "Edit Waypoint",   (VikToolConstructorFunc) tool_edit_waypoint_create,   NULL, NULL, NULL, 
+    (VikToolMouseFunc) tool_edit_waypoint_click,   
+    (VikToolMouseFunc) tool_edit_waypoint_move,
+    (VikToolMouseFunc) tool_edit_waypoint_release },
+
+  { "Edit Trackpoint", (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, 
+    (VikToolMouseFunc) tool_edit_trackpoint_click,
+    (VikToolMouseFunc) tool_edit_trackpoint_move,
+    (VikToolMouseFunc) tool_edit_trackpoint_release },
+
+  { "Show Picture",    (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL, 
+    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL },
+
+  { "Magic Scissors",  (VikToolConstructorFunc) tool_magic_scissors_create,  NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL },
+};
 
 /****** PARAMETERS ******/
 
 
 /****** PARAMETERS ******/
 
@@ -223,6 +283,7 @@ 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[] = { "Draw by Track", "Draw by Velocity", "All Tracks Black", 0 };
 static gchar *params_wpsymbols[] = { "Filled Square", "Square", "Circle", "X", 0 };
 
+
 static VikLayerParamScale params_scales[] = {
  /* min  max    step digits */
  {  1,   10,    1,   0 }, /* line_thickness */
 static VikLayerParamScale params_scales[] = {
  /* min  max    step digits */
  {  1,   10,    1,   0 }, /* line_thickness */
@@ -234,15 +295,23 @@ static VikLayerParamScale params_scales[] = {
  {   5,   500,  5,   0 }, /* image cache_size */
  {   0,   8,    1,   0 }, /* image cache_size */
  {   1,  64,    1,   0 }, /* wpsize */
  {   5,   500,  5,   0 }, /* image cache_size */
  {   0,   8,    1,   0 }, /* image cache_size */
  {   1,  64,    1,   0 }, /* wpsize */
+ {   MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1,   0 }, /* stop_length */
+ {   1, 100, 1,   0 }, /* stop_length */
 };
 
 VikLayerParam trw_layer_params[] = {
   { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
   { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
 
 };
 
 VikLayerParam trw_layer_params[] = {
   { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
   { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
 
-  { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Drawing Mode:", VIK_LAYER_WIDGET_RADIOGROUP, params_drawmodes },
+  { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Drawing Mode:", VIK_LAYER_WIDGET_RADIOGROUP, NULL },
   { "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 },
   { "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 },
   { "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 },
@@ -254,8 +323,9 @@ VikLayerParam trw_layer_params[] = {
   { "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 },
   { "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 symbol:", VIK_LAYER_WIDGET_RADIOGROUP, params_wpsymbols },
+  { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint marker:", VIK_LAYER_WIDGET_RADIOGROUP, NULL },
   { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint size:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 },
   { "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 },
 
   { "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 },
@@ -263,7 +333,7 @@ VikLayerParam trw_layer_params[] = {
   { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Memory Cache Size:", VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
 };
 
   { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Memory Cache Size:", VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
 };
 
-enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, 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_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 };
 
 /****** END PARAMETERS ******/
 
 
 /****** END PARAMETERS ******/
 
@@ -279,6 +349,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,
@@ -288,6 +360,9 @@ 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,
 
   (VikLayerFuncAddMenuItems)            vik_trw_layer_add_menu_items,
   (VikLayerFuncSublayerAddMenuItems)    vik_trw_layer_sublayer_add_menu_items,
 
@@ -295,6 +370,8 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncSublayerToggleVisible)   vik_trw_layer_sublayer_toggle_visible,
 
   (VikLayerFuncCopy)                    trw_layer_copy,
   (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,
@@ -302,21 +379,21 @@ 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,
+  
+  (VikLayerFuncDragDropRequest)         trw_layer_drag_drop_request,
 };
 
 /* 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 ()
 {
@@ -342,39 +419,95 @@ 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] = (gpointer) 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 = (gint)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;
+
+  fprintf(stderr, "%s:%s() called\n", __FILE__, __PRETTY_FUNCTION__);
+  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, g_strdup(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, g_strdup(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;
@@ -382,19 +515,8 @@ 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 ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item )
-  {
-    NamedTrack *nt = (NamedTrack *) item;
-    g_free ( nt->name );
-    vik_track_free ( nt->tr );
-    g_free ( nt );
+  if (item) {
+    g_free(item);
   }
 }
 
   }
 }
 
@@ -411,7 +533,15 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
     case PARAM_WV: vtl->waypoints_visible = data.b; break;
     case PARAM_DM: vtl->drawmode = data.u; break;
     case PARAM_DP: vtl->drawpoints = data.b; break;
     case PARAM_WV: vtl->waypoints_visible = data.b; break;
     case PARAM_DM: vtl->drawmode = data.u; break;
     case PARAM_DP: vtl->drawpoints = data.b; break;
+    case PARAM_DE: vtl->drawelevation = data.b; break;
+    case PARAM_DS: vtl->drawstops = data.b; break;
     case PARAM_DL: vtl->drawlines = data.b; break;
     case PARAM_DL: vtl->drawlines = data.b; break;
+    case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
+                     vtl->stop_length = data.u;
+                   break;
+    case PARAM_EF: if ( data.u >= 1 && data.u <= 100 )
+                     vtl->elevation_factor = data.u;
+                   break;
     case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness )
                    {
                      vtl->line_thickness = data.u;
     case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness )
                    {
                      vtl->line_thickness = data.u;
@@ -448,6 +578,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
     case PARAM_WPBA: gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY ); break;
     case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
     case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
     case PARAM_WPBA: gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY ); break;
     case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
     case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
+    case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
   }
   return TRUE;
 }
   }
   return TRUE;
 }
@@ -461,6 +592,10 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id )
     case PARAM_WV: rv.b = vtl->waypoints_visible; break;
     case PARAM_DM: rv.u = vtl->drawmode; break;
     case PARAM_DP: rv.b = vtl->drawpoints; break;
     case PARAM_WV: rv.b = vtl->waypoints_visible; break;
     case PARAM_DM: rv.u = vtl->drawmode; break;
     case PARAM_DP: rv.b = vtl->drawpoints; break;
+    case PARAM_DE: rv.b = vtl->drawelevation; break;
+    case PARAM_EF: rv.u = vtl->elevation_factor; break;
+    case PARAM_DS: rv.b = vtl->drawstops; break;
+    case PARAM_SL: rv.u = vtl->stop_length; break;
     case PARAM_DL: rv.b = vtl->drawlines; break;
     case PARAM_LT: rv.u = vtl->line_thickness; break;
     case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
     case PARAM_DL: rv.b = vtl->drawlines; break;
     case PARAM_LT: rv.u = vtl->line_thickness; break;
     case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
@@ -478,6 +613,7 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id )
     case PARAM_WPBA: rv.b = (vik_gc_get_function(vtl->waypoint_bg_gc)==GDK_AND); break;
     case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
     case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
     case PARAM_WPBA: rv.b = (vik_gc_get_function(vtl->waypoint_bg_gc)==GDK_AND); break;
     case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
     case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
+    case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
   }
   return rv;
 }
   }
   return rv;
 }
@@ -487,6 +623,59 @@ static void track_copy ( const gchar *name, VikTrack *tr, GHashTable *dest )
   g_hash_table_insert ( dest, g_strdup ( name ), vik_track_copy(tr) );
 }
 
   g_hash_table_insert ( dest, g_strdup ( name ), vik_track_copy(tr) );
 }
 
+static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
+{
+  guint8 *pd, *dd;
+  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);
+    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);
+    remove(tmpname);
+    g_free(tmpname);
+  }
+}
+
+static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp )
+{
+  VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
+  guint pl;
+  gchar *tmpname;
+  FILE *f;
+
+
+  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\n");
+    exit(1);
+  }
+  fwrite(data, len - pl - sizeof(pl), 1, f);
+  rewind(f);
+  a_gpx_read_file(rv, f);
+  fclose(f);
+  remove(tmpname);
+  g_free(tmpname);
+  return rv;
+}
+
 static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
 {
   VikTrwLayer *rv = vik_trw_layer_new ( vtl->drawmode );
 static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
 {
   VikTrwLayer *rv = vik_trw_layer_new ( vtl->drawmode );
@@ -500,7 +689,11 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
   rv->tracks_visible = vtl->tracks_visible;
   rv->waypoints_visible = vtl->waypoints_visible;
   rv->drawpoints = vtl->drawpoints;
   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->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->line_thickness = vtl->line_thickness;
   rv->bg_line_thickness = vtl->bg_line_thickness;
   rv->velocity_min = vtl->velocity_min;
@@ -514,6 +707,7 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
   rv->coord_mode = vtl->coord_mode;
   rv->wp_symbol = vtl->wp_symbol;
   rv->wp_size = vtl->wp_size;
   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) );
 
 
   trw_layer_new_track_gcs ( rv, VIK_VIEWPORT(vp) );
 
@@ -534,8 +728,22 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
   return rv;
 }
 
   return rv;
 }
 
+static GList * a_array_to_glist(gpointer data[])
+{
+  GList *gl = NULL;
+  gpointer * p;
+  for (p = data; *p; p++)
+    gl = g_list_prepend(gl, *p);
+  return(g_list_reverse(gl));
+}
+
 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 = a_array_to_glist(params_drawmodes);
+  if (trw_layer_params[PARAM_WPSYM].widget_data == NULL)
+    trw_layer_params[PARAM_WPSYM].widget_data = a_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 );
 
@@ -548,6 +756,10 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
   rv->waypoints_visible = rv->tracks_visible = TRUE;
   rv->drawmode = drawmode;
   rv->drawpoints = TRUE;
   rv->waypoints_visible = rv->tracks_visible = TRUE;
   rv->drawmode = drawmode;
   rv->drawpoints = TRUE;
+  rv->drawstops = FALSE;
+  rv->drawelevation = FALSE;
+  rv->elevation_factor = 30;
+  rv->stop_length = 60;
   rv->drawlines = TRUE;
   rv->wplabellayout = NULL;
   rv->wp_right_click_menu = NULL;
   rv->drawlines = TRUE;
   rv->wplabellayout = NULL;
   rv->wp_right_click_menu = NULL;
@@ -558,7 +770,7 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
   rv->velocity_max = 5.0;
   rv->velocity_min = 0.0;
   rv->line_thickness = 1;
   rv->velocity_max = 5.0;
   rv->velocity_min = 0.0;
   rv->line_thickness = 1;
-  rv->line_thickness = 0;
+  rv->bg_line_thickness = 0;
   rv->current_wp = NULL;
   rv->current_wp_name = NULL;
   rv->current_track = NULL;
   rv->current_wp = NULL;
   rv->current_wp_name = NULL;
   rv->current_track = NULL;
@@ -566,6 +778,9 @@ 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->magic_scissors_started = 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;
@@ -688,11 +903,21 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
   gboolean useoldvals = TRUE;
 
   gboolean drawpoints;
   gboolean useoldvals = TRUE;
 
   gboolean drawpoints;
+  gboolean drawstops;
+  gboolean drawelevation;
+  gdouble min_alt, max_alt, alt_diff = 0;
 
   const guint8 tp_size_reg = 2;
   const guint8 tp_size_cur = 4;
   guint8 tp_size;
 
 
   const guint8 tp_size_reg = 2;
   const guint8 tp_size_cur = 4;
   guint8 tp_size;
 
+  if ( dp->vtl->drawelevation )
+  {
+    /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
+    if ( ( drawelevation = vik_track_get_minmax_alt ( track, &min_alt, &max_alt ) ) )
+      alt_diff = max_alt - min_alt;
+  }
+
   if ( ! track->visible )
     return;
 
   if ( ! track->visible )
     return;
 
@@ -701,9 +926,11 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
     trw_layer_draw_track ( name, track, dp, TRUE );
 
   if ( drawing_white_background )
     trw_layer_draw_track ( name, track, dp, TRUE );
 
   if ( drawing_white_background )
-    drawpoints = FALSE;
-  else
+    drawpoints = drawstops = FALSE;
+  else {
     drawpoints = dp->vtl->drawpoints;
     drawpoints = dp->vtl->drawpoints;
+    drawstops = dp->vtl->drawstops;
+  }
 
   if (list) {
     int x, y, oldx, oldy;
 
   if (list) {
     int x, y, oldx, oldy;
@@ -743,15 +970,10 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
           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 );
 
           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 );
 
-#if 0
-            if ( VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE )
-              vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y, x, y-(VIK_TRACKPOINT(list->next->data)->altitude-540)/5);
-#endif
-
             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 );
 
             /* stops */
             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 );
 
             /* stops */
-            if (0 && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > 60 )
+            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 *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
           }
           else
@@ -776,28 +998,28 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr
             vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
           }
           else {
             vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
           }
           else {
-            GdkPoint tmp[4];
-#define FIXALTITUDE(what) (pow((VIK_TRACKPOINT((what))->altitude-330),2)/1500/dp->xmpp)
-            if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
-              tmp[0].x = oldx;
-              tmp[0].y = oldy;
-              tmp[1].x = oldx;
-              tmp[1].y = oldy-FIXALTITUDE(list->data);
-              tmp[2].x = x;
-              tmp[2].y = y-FIXALTITUDE(list->next->data);
-              tmp[3].x = x;
-              tmp[3].y = y;
-
-              GdkGC *tmp_gc;
-              if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
-                tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
-              else
-                tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
-              vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
-            }
 
             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, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y);
-            if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
+            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 ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
+                tmp[0].x = oldx;
+                tmp[0].y = oldy;
+                tmp[1].x = oldx;
+                tmp[1].y = oldy-FIXALTITUDE(list->data);
+                tmp[2].x = x;
+                tmp[2].y = y-FIXALTITUDE(list->next->data);
+                tmp[3].x = x;
+                tmp[3].y = y;
+
+                GdkGC *tmp_gc;
+                if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
+                  tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
+                else
+                  tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
+                vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
+              }
               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, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
             }
           }
@@ -862,6 +1084,7 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct
              wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
   {
     gint x, y;
              wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
   {
     gint x, y;
+    GdkPixbuf *sym;
     vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y );
 
     /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
     vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y );
 
     /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
@@ -934,7 +1157,10 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct
     }
 
     /* DRAW ACTUAL DOT */
     }
 
     /* DRAW ACTUAL DOT */
-    if ( wp == dp->vtl->current_wp ) {
+    if ( dp->vtl->wp_draw_symbols && wp->symbol && (sym = a_get_wp_sym(wp->symbol)) ) {
+      vik_viewport_draw_pixbuf ( dp->vp, sym, 0, 0, x - gdk_pixbuf_get_width(sym)/2, y - gdk_pixbuf_get_height(sym)/2, -1, -1 );
+    } 
+    else if ( wp == dp->vtl->current_wp ) {
       switch ( dp->vtl->wp_symbol ) {
         case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
         case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
       switch ( dp->vtl->wp_symbol ) {
         case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
         case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
@@ -1055,9 +1281,12 @@ VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
   rv->has_verified_thumbnails = FALSE;
   rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
   rv->wp_size = 4;
   rv->has_verified_thumbnails = FALSE;
   rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
   rv->wp_size = 4;
+  rv->wp_draw_symbols = TRUE;
 
   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;
 }
 
@@ -1263,6 +1492,11 @@ static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] )
   trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSMAPPER );
 }
 
   trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSMAPPER );
 }
 
+static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
+{
+  trw_layer_export ( layer_and_vlp, FILE_TYPE_GPX );
+}
+
 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]) );
@@ -1314,17 +1548,17 @@ 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 )
 {
   gchar *name;
 gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
 {
   gchar *name;
-  static VikWaypoint st_wp;
-  st_wp.coord = *def_coord;
-  st_wp.altitude = VIK_DEFAULT_ALTITUDE;
+  VikWaypoint *wp = vik_waypoint_new();
+  wp->coord = *def_coord;
+  wp->altitude = VIK_DEFAULT_ALTITUDE;
 
 
-  if ( a_dialog_new_waypoint ( w, &name, &st_wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) )
+  if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) )
   {
   {
-    VikWaypoint *wp = vik_waypoint_new();
-    *wp = st_wp;
+    wp->visible = TRUE;
     vik_trw_layer_add_waypoint ( vtl, name, wp );
     return TRUE;
   }
     vik_trw_layer_add_waypoint ( vtl, name, wp );
     return TRUE;
   }
+  vik_waypoint_free(wp);
   return FALSE;
 }
 
   return FALSE;
 }
 
@@ -1369,6 +1603,11 @@ 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 ( "Export Layer as GPX" );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_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 ( "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);
@@ -1419,11 +1658,11 @@ 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 );
  
@@ -1452,8 +1691,91 @@ static void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_n
   else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0)
     trw_layer_cancel_last_tp ( vtl );
 }
   else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0)
     trw_layer_cancel_last_tp ( vtl );
 }
+       
+static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
+{
+ gint i = 2;
+ gchar *newname = g_strdup(name);
+ while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ?
+         (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) {
+    gchar *new_newname = g_strdup_printf("%s#%d", name, i);
+    g_free(newname);
+    newname = new_newname;
+    i++;
+  }
+  return newname;
+}
+
+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 )
+{
+  vik_trw_layer_add_track ( vtl,
+                        get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name),
+                        tr );
+}
+
+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;
+  gint type = vik_treeview_item_get_data(vt, src_item_iter);
+
+  if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
+    GList *items = NULL;
+    GList *iter;
+
+    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);
+  }
+}
+
 
 
-static gboolean trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
+gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
 {
   VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name );
   gboolean was_visible = FALSE;
 {
   VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name );
   gboolean was_visible = FALSE;
@@ -1477,36 +1799,79 @@ static gboolean trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name
   return was_visible;
 }
 
   return was_visible;
 }
 
+gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name )
+{
+  gboolean was_visible = FALSE;
+  VikWaypoint *wp;
+
+  wp = g_hash_table_lookup ( vtl->waypoints, wp_name );
+  if ( wp ) {
+    GtkTreeIter *it;
+
+    if ( wp == vtl->current_wp ) {
+      vtl->current_wp = NULL;
+      vtl->current_wp_name = NULL;
+      vtl->moving_wp = FALSE;
+    }
+
+    was_visible = wp->visible;
+    g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) wp_name ) ) );
+    vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
+    g_hash_table_remove ( vtl->waypoints_iters, (gchar *) wp_name );
+    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;
+  if (vtl->current_tp_track_name)
+    trw_layer_cancel_current_tp(vtl, FALSE);
+  if (vtl->last_tp_track_name)
+    trw_layer_cancel_last_tp ( vtl );
+
+  g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->tracks_iters);
+  g_hash_table_remove_all(vtl->tracks);
+
+  /* TODO: only update if the layer is visible (ticked) */
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+}
+
+void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
+{
+  vtl->current_wp = NULL;
+  vtl->current_wp_name = NULL;
+  vtl->moving_wp = FALSE;
+
+  g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
+  g_hash_table_remove_all(vtl->waypoints_iters);
+  g_hash_table_remove_all(vtl->waypoints);
+
+  /* TODO: only update if the layer is visible (ticked) */
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+}
+
 static void trw_layer_delete_item ( gpointer pass_along[5] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
   gboolean was_visible = FALSE;
   if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
 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 )
   {
-    VikWaypoint *wp;
-    wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
-    if ( wp )
-    {
-      GtkTreeIter *it;
-
-      if ( wp == vtl->current_wp ) {
-        vtl->current_wp = NULL;
-        vtl->current_wp_name = NULL;
-        vtl->moving_wp = FALSE;
-      }
-
-      was_visible = wp->visible;
-      g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) pass_along[3] ) ) );
-      vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
-      g_hash_table_remove ( vtl->waypoints_iters, (gchar *) pass_along[3] );
-      g_hash_table_remove ( vtl->waypoints, pass_along[3] ); /* last because this frees name */
-    }
+    was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
   }
   else
   {
   }
   else
   {
-    was_visible = trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
+    was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
   }
   }
-
   if ( was_visible )
     vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
   if ( was_visible )
     vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
@@ -1572,12 +1937,11 @@ static void trw_layer_properties_item ( gpointer pass_along[5] )
           }
           if ( new_tr_name )
             vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
           }
           if ( new_tr_name )
             vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
-         
         }
         if ( tracks )
         {
           g_free ( tracks );
         }
         if ( tracks )
         {
           g_free ( tracks );
-          trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
+          vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
           vik_layer_emit_update ( VIK_LAYER(vtl) ); /* chase thru the hoops */
         }
       }
           vik_layer_emit_update ( VIK_LAYER(vtl) ); /* chase thru the hoops */
         }
       }
@@ -1650,11 +2014,11 @@ static void find_nearby_track(gpointer key, gpointer value, gpointer user_data)
   p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
 
   if (!p1->has_timestamp || !p2->has_timestamp) {
   p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
 
   if (!p1->has_timestamp || !p2->has_timestamp) {
-    printf("no timestamp\n");
+    g_print("no timestamp\n");
     return;
   }
 
     return;
   }
 
-  /*  printf("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
+  /*  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
   if (abs(t1 - p2->timestamp) < thr*60 ||
       /*  p1 p2      t1 t2 */
       abs(p1->timestamp - t2) < thr*60
@@ -1724,7 +2088,7 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
     t1 = ((VikTrackpoint *)trps->data)->timestamp;
     t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
     
     t1 = ((VikTrackpoint *)trps->data)->timestamp;
     t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
     
-    /*    printf("Original track times: %d and %d\n", t1, t2);  */
+    /*    g_print("Original track times: %d and %d\n", t1, t2);  */
     params[0] = &nearby_tracks;
     params[1] = trps;
     params[2] = (gpointer)thr;
     params[0] = &nearby_tracks;
     params[1] = trps;
     params[2] = (gpointer)thr;
@@ -1752,14 +2116,14 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
        time_t t1, t2;
        t1 = get_first_trackpoint(l)->timestamp;
        t2 = get_last_trackpoint(l)->timestamp;
        time_t t1, t2;
        t1 = get_first_trackpoint(l)->timestamp;
        t2 = get_last_trackpoint(l)->timestamp;
-       printf("     %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
+       g_print("     %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
        */
 
 
        /* 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;
-       trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), l->data);
+       vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), l->data);
 
        track_count ++;
        l = g_list_next(l);
 
        track_count ++;
        l = g_list_next(l);
@@ -1807,7 +2171,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
   while (iter) {
     ts = VIK_TRACKPOINT(iter->data)->timestamp;
     if (ts < prev_ts) {
   while (iter) {
     ts = VIK_TRACKPOINT(iter->data)->timestamp;
     if (ts < prev_ts) {
-      printf("panic: ts < prev_ts: this should never happen!\n");
+      g_print("panic: ts < prev_ts: this should never happen!\n");
       return;
     }
     if (ts - prev_ts > thr*60) {
       return;
     }
     if (ts - prev_ts > thr*60) {
@@ -1838,13 +2202,13 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
 
     new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
     vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
 
     new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
     vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
-    /*    fprintf(stderr, "adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
+    /*    g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
          VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
 
     iter = g_list_next(iter);
   }
   g_list_free(newlists);
          VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
 
     iter = g_list_next(iter);
   }
   g_list_free(newlists);
-  trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
+  vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
   vik_layer_emit_update(VIK_LAYER(pass_along[0]));
 }
 
   vik_layer_emit_update(VIK_LAYER(pass_along[0]));
 }
 
@@ -1893,12 +2257,12 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
       return NULL;
     }
 
       return NULL;
     }
 
-    wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) );
-    g_hash_table_remove ( l->waypoints, sublayer );
-
     iter = g_hash_table_lookup ( l->waypoints_iters, sublayer );
     g_hash_table_steal ( l->waypoints_iters, 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 )) );
+    g_hash_table_remove ( l->waypoints, sublayer );
+
     rv = g_strdup(newname);
     for ( i = strlen(rv) - 1; i >= 0; i-- )
       rv[i] = toupper(rv[i]);
     rv = g_strdup(newname);
     for ( i = strlen(rv) - 1; i >= 0; i-- )
       rv[i] = toupper(rv[i]);
@@ -1933,7 +2297,7 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar
       return NULL;
     }
 
       return NULL;
     }
 
-    g_hash_table_lookup_extended ( l->tracks, sublayer, (gpointer *)&orig_key, (gpointer *)&tr );
+    g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
     g_hash_table_steal ( l->tracks, sublayer );
 
     iter = g_hash_table_lookup ( l->tracks_iters, sublayer );
     g_hash_table_steal ( l->tracks, sublayer );
 
     iter = g_hash_table_lookup ( l->tracks_iters, sublayer );
@@ -2000,6 +2364,16 @@ 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_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 );
+
+    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 );
     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 );
@@ -2073,146 +2447,52 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
   return rv;
 }
 
   return rv;
 }
 
-/* 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. */
-    }
-  }
+/* to be called when last_tpl no long exists. */
+static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
+{
+  if ( vtl->tpwin ) /* can't join with a non-existant TP. */
+    vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
+  vtl->last_tpl = NULL;
+  vtl->last_tp_track_name = NULL;
 }
 
 }
 
-static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
 {
 {
-  gpointer params[3] = { vvp, event, NULL };
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
-  if ( params[2] )
+  if ( vtl->tpwin )
   {
   {
-    /* 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 ( destroy)
     {
     {
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." );
-      g_error_free ( err );
+      gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
+      vtl->tpwin = NULL;
     }
     }
-    g_free ( cmd );
-#endif /* WINDOWS */
-    return TRUE; /* found a match */
+    else
+      vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
+  }
+  if ( vtl->current_tpl )
+  {
+    vtl->current_tpl = NULL;
+    vtl->current_tp_track_name = NULL;
+    vik_layer_emit_update(VIK_LAYER(vtl));
   }
   }
-  else
-    return FALSE; /* go through other layers, searching for a match */
 }
 
 }
 
-static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
 {
 {
-  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;
-
-  if ( !t->visible )
-    return;
-
-  while (tpl)
-  {
-    gint x, y;
-    tp = VIK_TRACKPOINT(tpl->data);
-
-    vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
-    if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
-        ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
-          abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
-    {
-      params->closest_track_name = name;
-      params->closest_tp = tp;
-      params->closest_tpl = tpl;
-      params->closest_x = x;
-      params->closest_y = y;
-    }
-    tpl = tpl->next;
-  }
-}
-
-/* to be called when last_tpl no long exists. */
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
-{
-  if ( vtl->tpwin ) /* can't join with a non-existant TP. */
-    vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
-  vtl->last_tpl = NULL;
-  vtl->last_tp_track_name = NULL;
-}
-
-static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
-{
-  if ( vtl->tpwin )
-  {
-    if ( destroy)
-    {
-      gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
-      vtl->tpwin = NULL;
-    }
-    else
-      vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
-  }
-  if ( vtl->current_tpl )
-  {
-    vtl->current_tpl = NULL;
-    vtl->current_tp_track_name = NULL;
-    vik_layer_emit_update(VIK_LAYER(vtl));
-  }
-}
-
-static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
-{
-  g_assert ( vtl->tpwin != NULL );
-  if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
-    trw_layer_cancel_current_tp ( vtl, TRUE );
-  else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
-  {
-    gchar *name;
-    if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks ) ) )
-    {
-      VikTrack *tr = vik_track_new ();
-      GList *newglist = g_list_alloc ();
-      newglist->prev = NULL;
-      newglist->next = vtl->current_tpl->next;
-      newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
-      tr->trackpoints = newglist;
+  g_assert ( vtl->tpwin != NULL );
+  if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
+    trw_layer_cancel_current_tp ( vtl, TRUE );
+  else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
+  {
+    gchar *name;
+    if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks ) ) )
+    {
+      VikTrack *tr = vik_track_new ();
+      GList *newglist = g_list_alloc ();
+      newglist->prev = NULL;
+      newglist->next = vtl->current_tpl->next;
+      newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
+      tr->trackpoints = newglist;
 
       vtl->current_tpl->next->prev = newglist; /* end old track here */
       vtl->current_tpl->next = NULL;
 
       vtl->current_tpl->next->prev = newglist; /* end old track here */
       vtl->current_tpl->next = NULL;
@@ -2305,7 +2585,7 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
 
     /* if we did this before, trw_layer_delete_track would have canceled the current tp because
      * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
 
     /* if we did this before, trw_layer_delete_track would have canceled the current tp because
      * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
-    trw_layer_delete_track ( vtl, tmp );
+    vik_trw_layer_delete_track ( vtl, tmp );
 
     trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
     vik_layer_emit_update(VIK_LAYER(vtl));
 
     trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
     vik_layer_emit_update(VIK_LAYER(vtl));
@@ -2329,6 +2609,77 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
   /* set layer name and TP data */
 }
 
   /* set layer name and TP data */
 }
 
+/***************************************************************************
+ ** Tool code
+ ***************************************************************************/
+
+/*** Utility data structures and functions ****/
+
+typedef struct {
+  gint x, y;
+  gint closest_x, closest_y;
+  gchar *closest_wp_name;
+  VikWaypoint *closest_wp;
+  VikViewport *vvp;
+} WPSearchParams;
+
+typedef struct {
+  gint x, y;
+  gint closest_x, closest_y;
+  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;
+  if ( !wp->visible )
+    return;
+
+  vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
+  if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
+      ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
+        abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
+  {
+    params->closest_wp_name = name;
+    params->closest_wp = wp;
+    params->closest_x = x;
+    params->closest_y = y;
+  }
+}
+
+static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
+{
+  GList *tpl = t->trackpoints;
+  VikTrackpoint *tp;
+
+  if ( !t->visible )
+    return;
+
+  while (tpl)
+  {
+    gint x, y;
+    tp = VIK_TRACKPOINT(tpl->data);
+
+    vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
+    if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
+        ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
+          abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
+    {
+      params->closest_track_name = name;
+      params->closest_tp = tp;
+      params->closest_tpl = tpl;
+      params->closest_x = x;
+      params->closest_y = y;
+    }
+    tpl = tpl->next;
+  }
+}
+
 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
 {
   TPSearchParams params;
 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
 {
   TPSearchParams params;
@@ -2341,38 +2692,348 @@ static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikV
   return params.closest_tp;
 }
 
   return params.closest_tp;
 }
 
-static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
+{
+  WPSearchParams params;
+  params.x = x;
+  params.y = y;
+  params.vvp = vvp;
+  params.closest_wp = NULL;
+  params.closest_wp_name = NULL;
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
+  return params.closest_wp;
+}
+
+/* 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;
+  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 )
+  {
+    /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
+    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 ( event->button == 3 )
+        vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
+      else {
+       marker_begin_move(t, event->x, event->y);
+      }
+      return TRUE;
+    }
+  }
+
+  params.vvp = vvp;
+  params.x = event->x;
+  params.y = event->y;
+  params.closest_wp_name = NULL;
+  /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
+  params.closest_wp = NULL;
+  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
+  if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
+  {
+    /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
+    marker_begin_move(t, event->x, event->y);
+    printf("Abort: shouldn't be here\n");
+    exit(1);
+  }
+  else if ( params.closest_wp )
+  {
+    if ( event->button == 3 )
+      vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
+    else
+      vtl->waypoint_rightclick = FALSE;
+
+    vtl->current_wp = params.closest_wp;
+    vtl->current_wp_name = params.closest_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 ) );
+
+    /* could make it so don't update if old WP is off screen and new is null but oh well */
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    return TRUE;
+  }
+
+  vtl->current_wp = NULL;
+  vtl->current_wp_name = NULL;
+  vtl->waypoint_rightclick = FALSE;
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  return FALSE;
+}
+
+static gboolean tool_edit_waypoint_move ( 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 ) {
+    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;
+}
+
+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;
+}
+
+/*** New track ****/
+
+static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  VikTrackpoint *tp;
+
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+
+  if ( event->button == 3 && vtl->current_track )
+  {
+    /* 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;
+  }
+
+  if ( event->type == GDK_2BUTTON_PRESS )
+  {
+    /* subtract last (duplicate from double click) tp then end */
+    if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
+    {
+      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 );
+      /* undo last, then end */
+      vtl->current_track = NULL;
+    }
+    return TRUE;
+  }
+
+  if ( ! vtl->current_track )
+  {
+    gchar *name;
+    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ) ) )
+    {
+      vtl->current_track = vik_track_new();
+      vtl->current_track->visible = TRUE;
+      vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+    }
+    else
+      return TRUE;
+  }
+  tp = vik_trackpoint_new();
+  vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
+
+  /* snap to other TP */
+  if ( event->state & GDK_CONTROL_MASK )
+  {
+    VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
+    if ( other_tp )
+      tp->coord = other_tp->coord;
+  }
+
+  tp->newsegment = FALSE;
+  tp->has_timestamp = FALSE;
+  tp->timestamp = 0;
+  tp->altitude = VIK_DEFAULT_ALTITUDE;
+  vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
+
+  vtl->ct_x1 = vtl->ct_x2;
+  vtl->ct_y1 = vtl->ct_y2;
+  vtl->ct_x2 = event->x;
+  vtl->ct_y2 = event->y;
+
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
+  return TRUE;
+}
+
+
+/*** New waypoint ****/
+
+static gpointer tool_new_waypoint_create ( VikWindow *vw, 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 );
+  return vvp;
+}
 
 
-    /* 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;
-    }
+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;
+}
 
 
-    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 );
+/*** Edit trackpoint ****/
 
 
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
-    return TRUE;
-  }
-  return FALSE;
+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 ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+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
   TPSearchParams params;
   /* OUTDATED DOCUMENTATION:
    find 5 pixel range on each side. then put these UTM, and a pointer
@@ -2387,6 +3048,12 @@ static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event,
   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_tp = NULL;
 
   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_tp = NULL;
 
+  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.) */
   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.) */
@@ -2399,9 +3066,8 @@ static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event,
 
     if ( current_tr->visible && 
          abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
 
     if ( current_tr->visible && 
          abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
-         abs(y - event->y) < TRACKPOINT_SIZE_APPROX )
-    {
-      vtl->moving_tp = TRUE;
+         abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
+      marker_begin_move ( t, event->x, event->y );
       return TRUE;
     }
 
       return TRUE;
     }
 
@@ -2421,217 +3087,171 @@ static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event,
     return TRUE;
   }
 
     return TRUE;
   }
 
-
   /* these aren't the droids you're looking for */
   return FALSE;
 }
 
   /* these aren't the droids you're looking for */
   return FALSE;
 }
 
-typedef struct {
-  gint x, y;
-  gint closest_x, closest_y;
-  gchar *closest_wp_name;
-  VikWaypoint *closest_wp;
-  VikViewport *vvp;
-} WPSearchParams;
-
-static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
+static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
 {
 {
-  gint x, y;
-  if ( !wp->visible )
-    return;
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
 
 
-  vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
-  if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
-      ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
-        abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
-  {
-    params->closest_wp_name = name;
-    params->closest_wp = wp;
-    params->closest_x = x;
-    params->closest_y = y;
-  }
-}
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
 
 
-static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
-{
-  if ( vtl->moving_wp )
+  if ( t->holding )
   {
     VikCoord new_coord;
   {
     VikCoord new_coord;
-    vtl->moving_wp = FALSE;
+    GdkGC *gc;
     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 );
     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 )
+      if ( tp && tp != vtl->current_tpl->data )
         new_coord = tp->coord;
     }
         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 );
+    } 
 
 
-    /* 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;
-    }
-
-    vtl->current_wp->coord = new_coord;
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
     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;
 }
 
   return FALSE;
 }
 
-static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
+static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
 {
 {
-  WPSearchParams params;
-  params.x = x;
-  params.y = y;
-  params.vvp = vvp;
-  params.closest_wp = NULL;
-  params.closest_wp_name = NULL;
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
-  return params.closest_wp;
-}
+  tool_ed_t *t = data;
+  VikViewport *vvp = t->vvp;
 
 
-static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
-{
-  WPSearchParams params;
+  if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
+    return FALSE;
+  if ( event->button != 1) 
+    return FALSE;
 
 
-  if ( vtl->current_wp && vtl->current_wp->visible )
-  {
-    /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
-    gint x, y;
-    vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
+  if ( t->holding ) {
+    VikCoord new_coord;
+    vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
 
 
-    if ( abs(x - event->x) < WAYPOINT_SIZE_APPROX &&
-         abs(y - event->y) < WAYPOINT_SIZE_APPROX )
+    /* snap to TP */
+    if ( event->state & GDK_CONTROL_MASK )
     {
     {
-      if ( event->button == 3 )
-        vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
-      else
-        vtl->moving_wp = TRUE;
-      return TRUE;
+      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;
     }
     }
-  }
 
 
-  params.vvp = vvp;
-  params.x = event->x;
-  params.y = event->y;
-  params.closest_wp_name = NULL;
-  /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
-  params.closest_wp = NULL;
-  g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
-  if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
-  {
-    vtl->moving_wp = TRUE;
-  }
-  else if ( params.closest_wp )
-  {
-    if ( event->button == 3 )
-      vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
-    else
-      vtl->waypoint_rightclick = FALSE;
+    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
 
 
-    vtl->current_wp = params.closest_wp;
-    vtl->current_wp_name = params.closest_wp_name;
-    vtl->moving_wp = FALSE;
+    marker_end_move ( t );
 
 
-    if ( params.closest_wp )
-      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) );
+    /* 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 );
 
 
-    /* could make it so don't update if old WP is off screen and new is null but oh well */
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
-
-  vtl->current_wp = NULL;
-  vtl->current_wp_name = NULL;
-  vtl->moving_wp = FALSE;
-  vtl->waypoint_rightclick = FALSE;
   return FALSE;
 }
 
   return FALSE;
 }
 
-static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+
+/*** Magic Scissors ***/
+static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
 {
 {
-  VikTrackpoint *tp;
+  return vvp;
+}
 
 
-  if ( event->button == 3 && vtl->current_track )
-  {
-    /* 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 );
-    }
+static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  VikCoord tmp;
+  vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
+  if ( vtl->magic_scissors_started ) {
+    struct LatLon start, end;
+    gchar *cmd;
+    vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start );
+    vik_coord_to_latlon ( &(tmp), &end );
+    cmd = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, start.lat, start.lon, end.lat, end.lon );
+    a_babel_convert_from_shellcommand ( vtl, cmd, "google", NULL, NULL );
+    g_free ( cmd );
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     vik_layer_emit_update ( VIK_LAYER(vtl) );
-    return TRUE;
+  } else {
+    vtl->magic_scissors_coord = tmp;
   }
   }
+  vtl->magic_scissors_started = !vtl->magic_scissors_started;
+  return TRUE;
+}
 
 
-  if ( event->type == GDK_2BUTTON_PRESS )
+/*** 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 )
   {
   {
-    /* subtract last (duplicate from double click) tp then end */
-    if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
+    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 )
     {
     {
-      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 );
-      /* undo last, then end */
-      vtl->current_track = NULL;
+      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. */
     }
     }
-    return TRUE;
   }
   }
+}
 
 
-  if ( ! vtl->current_track )
+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] )
   {
   {
-    gchar *name;
-    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ) ) )
+    /* 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 ) )
     {
     {
-      vtl->current_track = vik_track_new();
-      vtl->current_track->visible = TRUE;
-      vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." );
+      g_error_free ( err );
     }
     }
-    else
-      return TRUE;
+    g_free ( cmd );
+#endif /* WINDOWS */
+    return TRUE; /* found a match */
   }
   }
-  tp = vik_trackpoint_new();
-  vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
+  else
+    return FALSE; /* go through other layers, searching for a match */
+}
+
+/***************************************************************************
+ ** End tool code 
+ ***************************************************************************/
 
 
-  /* snap to other TP */
-  if ( event->state & GDK_CONTROL_MASK )
-  {
-    VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
-    if ( other_tp )
-      tp->coord = other_tp->coord;
-  }
 
 
-  tp->newsegment = FALSE;
-  tp->has_timestamp = FALSE;
-  tp->timestamp = 0;
-  tp->altitude = VIK_DEFAULT_ALTITUDE;
-  vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
 
 
-  vtl->ct_x1 = vtl->ct_x2;
-  vtl->ct_y1 = vtl->ct_y2;
-  vtl->ct_x2 = event->x;
-  vtl->ct_y2 = event->y;
 
 
-  vik_layer_emit_update ( VIK_LAYER(vtl) );
-  return TRUE;
-}
 
 static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
 {
 
 static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
 {
@@ -2701,3 +3321,24 @@ static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mo
     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
   }
 }
     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
   }
 }
+
+VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, gchar *name )
+{
+  return g_hash_table_lookup ( vtl->waypoints, name );
+}
+
+VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, gchar *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);
+}
+