]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Maintain trackpoint selected when moving it.
[andy/viking.git] / src / viktrwlayer.c
index b741bd428093b13f4e743382bd7791a12ef34b77..a5d79e1db0bf9712043ac953d7c550cc2b130b3a 100644 (file)
@@ -56,6 +56,7 @@
 #include "datasource_gps.h"
 #include "vikexttool_datasources.h"
 #include "util.h"
 #include "datasource_gps.h"
 #include "vikexttool_datasources.h"
 #include "util.h"
+#include "vikutils.h"
 
 #include "vikrouting.h"
 
 
 #include "vikrouting.h"
 
@@ -459,8 +460,8 @@ enum {
 
 /****** PARAMETERS ******/
 
 
 /****** PARAMETERS ******/
 
-static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
-enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
+static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced") };
+enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV };
 
 static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL };
 static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
 
 static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL };
 static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
@@ -545,29 +546,27 @@ VikLayerParam trw_layer_params[] = {
 
   { VIK_LAYER_TRW, "trackdrawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
     N_("Note: the individual track controls what labels may be displayed"), vik_lpd_true_default, NULL, NULL },
 
   { VIK_LAYER_TRW, "trackdrawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
     N_("Note: the individual track controls what labels may be displayed"), vik_lpd_true_default, NULL, NULL },
-  { VIK_LAYER_TRW, "trackfontsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Labels Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, tnfontsize_default, NULL, NULL },
+  { VIK_LAYER_TRW, "trackfontsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Labels Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, tnfontsize_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default, NULL, NULL },
-  { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default },
   { VIK_LAYER_TRW, "trackcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("All Tracks Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL,
     N_("The color used when 'All Tracks Same Color' drawing mode is selected"), black_color_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "trackcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("All Tracks Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL,
     N_("The color used when 'All Tracks Same Color' drawing mode is selected"), black_color_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
-  { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[0], NULL, NULL, line_thickness_default, NULL, NULL },
+  { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[0], NULL, NULL, line_thickness_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
-  { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL },
+  { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
-  { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL },
+  { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
-  { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL },
-
+  { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
     N_("Whether to draw a marker when trackpoints are at the same position but over the minimum stop length apart in time"), vik_lpd_false_default, NULL, NULL },
   { VIK_LAYER_TRW, "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
     N_("Whether to draw a marker when trackpoints are at the same position but over the minimum stop length apart in time"), vik_lpd_false_default, NULL, NULL },
-  { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[8], NULL, NULL, stop_length_default, NULL, NULL },
+  { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[8], NULL, NULL, stop_length_default, NULL, NULL },
 
 
-  { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL },
-  { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL },
-  { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[1], NULL,
+  { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL },
+  { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS_ADV, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL },
+  { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS_ADV, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[1], NULL,
     N_("The percentage factor away from the average speed determining the color used"), speed_factor_default, NULL, NULL },
     N_("The percentage factor away from the average speed determining the color used"), speed_factor_default, NULL, NULL },
-  { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL },
+  { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL },
 
   { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, wpfontsize_default, NULL, NULL },
 
   { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, wpfontsize_default, NULL, NULL },
@@ -2630,52 +2629,30 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
   return NULL;
 }
 
   return NULL;
 }
 
-/*
- * Function to show basic track point information on the statusbar
+#define VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT "trkpt_selected_statusbar_format"
+
+/**
+ * set_statusbar_msg_info_trkpt:
+ *
+ * Function to show track point information on the statusbar
+ *  Items displayed is controlled by the settings format code
  */
 static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt )
 {
  */
 static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt )
 {
-  gchar tmp_buf1[64];
-  switch (a_vik_get_units_height ()) {
-  case VIK_UNITS_HEIGHT_FEET:
-    g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(trkpt->altitude)));
-    break;
-  default:
-    //VIK_UNITS_HEIGHT_METRES:
-    g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dm"), (int)round(trkpt->altitude));
-  }
-  
-  gchar tmp_buf2[64];
-  tmp_buf2[0] = '\0';
-  if ( trkpt->has_timestamp ) {
-    // Compact date time format
-    strftime (tmp_buf2, sizeof(tmp_buf2), _(" | Time %x %X"), localtime(&(trkpt->timestamp)));
+  gchar *statusbar_format_code = NULL;
+  gboolean need2free = FALSE;
+  if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
+    // Otherwise use default
+    statusbar_format_code = g_strdup ( "KATDN" );
+    need2free = TRUE;
   }
 
   }
 
-  // Position part
-  // Position is put later on, as this bit may not be seen if the display is not big enough,
-  //   one can easily use the current pointer position to see this if needed
-  gchar *lat = NULL, *lon = NULL;
-  static struct LatLon ll;
-  vik_coord_to_latlon (&(trkpt->coord), &ll);
-  a_coords_latlon_to_string ( &ll, &lat, &lon );
-
-  // Track name
-  // Again is put later on, as this bit may not be seen if the display is not big enough
-  //  trackname can be seen from the treeview (when enabled)
-  // Also name could be very long to not leave room for anything else
-  gchar tmp_buf3[64];
-  tmp_buf3[0] = '\0';
-  if ( vtl->current_tp_track ) {
-    g_snprintf(tmp_buf3, sizeof(tmp_buf3),  _(" | Track: %s"), vtl->current_tp_track->name );
-  }
-
-  // Combine parts to make overall message
-  gchar *msg = g_strdup_printf (_("%s%s | %s %s %s"), tmp_buf1, tmp_buf2, lat, lon, tmp_buf3);
+  gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, NULL, vtl->current_tp_track );
   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
-  g_free ( lat );
-  g_free ( lon );
   g_free ( msg );
   g_free ( msg );
+
+  if ( need2free )
+    g_free ( statusbar_format_code );
 }
 
 /*
 }
 
 /*
@@ -3247,9 +3224,7 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC
   wp->coord = *def_coord;
   
   // Attempt to auto set height if DEM data is available
   wp->coord = *def_coord;
   
   // Attempt to auto set height if DEM data is available
-  gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST );
-  if ( elev != VIK_DEM_INVALID_ELEVATION )
-    wp->altitude = (gdouble)elev;
+  vik_waypoint_apply_dem_data ( wp, TRUE );
 
   returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated );
 
 
   returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated );
 
@@ -4611,7 +4586,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
         // Get confirmation from the user
         // Maybe this Waypoint Delete should be optional as is it could get annoying...
         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
         // Get confirmation from the user
         // Maybe this Waypoint Delete should be optional as is it could get annoying...
         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-            _("Are you sure you want to delete the waypoint \"%s\""),
+            _("Are you sure you want to delete the waypoint \"%s\"?"),
             wp->name ) )
           return;
       was_visible = trw_layer_delete_waypoint ( vtl, wp );
             wp->name ) )
           return;
       was_visible = trw_layer_delete_waypoint ( vtl, wp );
@@ -4624,7 +4599,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
       if ( GPOINTER_TO_INT ( pass_along[4]) )
         // Get confirmation from the user
         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
       if ( GPOINTER_TO_INT ( pass_along[4]) )
         // Get confirmation from the user
         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                                 _("Are you sure you want to delete the track \"%s\""),
+                                 _("Are you sure you want to delete the track \"%s\"?"),
                                  trk->name ) )
           return;
       was_visible = vik_trw_layer_delete_track ( vtl, trk );
                                  trk->name ) )
           return;
       was_visible = vik_trw_layer_delete_track ( vtl, trk );
@@ -4637,7 +4612,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
       if ( GPOINTER_TO_INT ( pass_along[4]) )
         // Get confirmation from the user
         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
       if ( GPOINTER_TO_INT ( pass_along[4]) )
         // Get confirmation from the user
         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                                    _("Are you sure you want to delete the route \"%s\""),
+                                    _("Are you sure you want to delete the route \"%s\"?"),
                                     trk->name ) )
           return;
       was_visible = vik_trw_layer_delete_route ( vtl, trk );
                                     trk->name ) )
           return;
       was_visible = vik_trw_layer_delete_route ( vtl, trk );
@@ -4708,11 +4683,39 @@ static void trw_layer_properties_item ( gpointer pass_along[7] )
                                   tr,
                                  pass_along[1], /* vlp */
                                  pass_along[5], /* vvp */
                                   tr,
                                  pass_along[1], /* vlp */
                                  pass_along[5], /* vvp */
-                                  pass_along[6]); /* iter */
+                                  pass_along[6], /* iter */
+                                  FALSE );
     }
   }
 }
 
     }
   }
 }
 
+/**
+ * trw_layer_track_statistics:
+ *
+ * Show track statistics.
+ * ATM jump to the stats page in the properties
+ * TODO: consider separating the stats into an individual dialog?
+ */
+static void trw_layer_track_statistics ( gpointer pass_along[7] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrack *trk;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
+    trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  else
+    trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
+
+  if ( trk && trk->name ) {
+    vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                                vtl,
+                                trk,
+                                pass_along[1], // vlp
+                                pass_along[5], // vvp
+                                pass_along[6], // iter
+                                TRUE );
+  }
+}
+
 /*
  * Update the treeview of the track id - primarily to update the icon
  */
 /*
  * Update the treeview of the track id - primarily to update the icon
  */
@@ -4855,6 +4858,18 @@ static void trw_layer_convert_track_route ( gpointer pass_along[6] )
   vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
 }
 
   vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
 }
 
+static void trw_layer_anonymize_times ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( track )
+    vik_track_anonymize_times ( track );
+}
 
 static void trw_layer_extend_track_end ( gpointer pass_along[6] )
 {
 
 static void trw_layer_extend_track_end ( gpointer pass_along[6] )
 {
@@ -4896,10 +4911,43 @@ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
 
 }
 
 
 }
 
-static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
+/**
+ *
+ */
+static gboolean trw_layer_dem_test ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+  // If have a vlp then perform a basic test to see if any DEM info available...
+  if ( vlp ) {
+    GList *dems = vik_layers_panel_get_all_layers_of_type (vlp, VIK_LAYER_DEM, TRUE); // Includes hidden DEM layer types
+
+    if ( !g_list_length(dems) ) {
+      a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No DEM layers available, thus no DEM values can be applied.") );
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * apply_dem_data_common:
+ *
+ * A common function for applying the DEM values and reporting the results.
+ */
+static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTrack *track, gboolean skip_existing_elevations )
+{
+  if ( !trw_layer_dem_test ( vtl, vlp ) )
+    return;
+
+  gulong changed = vik_track_apply_dem_data ( track, skip_existing_elevations );
+  // Inform user how much was changed
+  gchar str[64];
+  const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
+  g_snprintf(str, 64, tmp_str, changed);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
+}
+
+static void trw_layer_apply_dem_data_all ( gpointer pass_along[6] )
 {
 {
-  /* TODO: check & warn if no DEM data, or no applicable DEM data. */
-  /* Also warn if overwrite old elevation data */
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
   VikTrack *track;
   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
   VikTrack *track;
   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
@@ -4908,7 +4956,137 @@ static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
 
   if ( track )
     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
 
   if ( track )
-    vik_track_apply_dem_data ( track );
+    apply_dem_data_common ( vtl, pass_along[1], track, FALSE );
+}
+
+static void trw_layer_apply_dem_data_only_missing ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( track )
+    apply_dem_data_common ( vtl, pass_along[1], track, TRUE );
+}
+
+/**
+ * smooth_it:
+ *
+ * A common function for applying the elevation smoothing and reporting the results.
+ */
+static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat )
+{
+  gulong changed = vik_track_smooth_missing_elevation_data ( track, flat );
+  // Inform user how much was changed
+  gchar str[64];
+  const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
+  g_snprintf(str, 64, tmp_str, changed);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
+}
+
+/**
+ *
+ */
+static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
+
+  smooth_it ( vtl, track, FALSE );
+}
+
+static void trw_layer_missing_elevation_data_flat ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( !track )
+    return;
+
+  smooth_it ( vtl, track, TRUE );
+}
+
+/**
+ * Commonal helper function
+ */
+static void wp_changed_message ( VikTrwLayer *vtl, gint changed )
+{
+  gchar str[64];
+  const gchar *tmp_str = ngettext("%ld waypoint changed", "%ld waypoints changed", changed);
+  g_snprintf(str, 64, tmp_str, changed);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
+}
+
+static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
+
+  if ( !trw_layer_dem_test ( vtl, vlp ) )
+    return;
+
+  gint changed = 0;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+    // Single Waypoint
+    VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+    if ( wp )
+      changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
+  }
+  else {
+    // All waypoints
+    GHashTableIter iter;
+    gpointer key, value;
+
+    g_hash_table_iter_init ( &iter, vtl->waypoints );
+    while ( g_hash_table_iter_next (&iter, &key, &value) ) {
+      VikWaypoint *wp = VIK_WAYPOINT(value);
+      changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
+    }
+  }
+  wp_changed_message ( vtl, changed );
+}
+
+static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
+
+  if ( !trw_layer_dem_test ( vtl, vlp ) )
+    return;
+
+  gint changed = 0;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+    // Single Waypoint
+    VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+    if ( wp )
+      changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
+  }
+  else {
+    // All waypoints
+    GHashTableIter iter;
+    gpointer key, value;
+
+    g_hash_table_iter_init ( &iter, vtl->waypoints );
+    while ( g_hash_table_iter_next (&iter, &key, &value) ) {
+      VikWaypoint *wp = VIK_WAYPOINT(value);
+      changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
+    }
+  }
+  wp_changed_message ( vtl, changed );
 }
 
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
 }
 
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
@@ -5008,6 +5186,91 @@ static void trw_layer_auto_track_view ( gpointer pass_along[6] )
   }
 }
 
   }
 }
 
+/*
+ * Refine the selected track/route with a routing engine.
+ * The routing engine is selected by the user, when requestiong the job.
+ */
+static void trw_layer_route_refine ( gpointer pass_along[6] )
+{
+  static gint last_engine = 0;
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrack *trk;
+
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+  else
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+  if ( trk && trk->trackpoints )
+  {
+    /* Check size of the route */
+    int nb = vik_track_get_tp_count(trk);
+    if (nb > 100) {
+      GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER (vtl),
+                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                  GTK_MESSAGE_WARNING,
+                                                  GTK_BUTTONS_OK_CANCEL,
+                                                  _("Refining a track with many points (%d) is unlikely to yield sensible results. Do you want to Continue?"),
+                                                  nb);
+      gint response = gtk_dialog_run ( GTK_DIALOG(dialog) );
+      gtk_widget_destroy ( dialog );
+      if (response != GTK_RESPONSE_OK )
+        return;
+    }
+    /* Select engine from dialog */
+    GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Refine Route with Routing Engine..."),
+                                                  VIK_GTK_WINDOW_FROM_LAYER (vtl),
+                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                  GTK_STOCK_CANCEL,
+                                                  GTK_RESPONSE_REJECT,
+                                                  GTK_STOCK_OK,
+                                                  GTK_RESPONSE_ACCEPT,
+                                                  NULL);
+    GtkWidget *label = gtk_label_new ( _("Select routing engine") );
+    gtk_widget_show_all(label);
+
+    gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 0 );
+
+    GtkWidget * combo = vik_routing_ui_selector_new ( (Predicate)vik_routing_engine_supports_refine, NULL );
+    gtk_combo_box_set_active (GTK_COMBO_BOX (combo), last_engine);
+    gtk_widget_show_all(combo);
+
+    gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), combo, TRUE, TRUE, 0 );
+
+    gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+
+    if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
+    {
+        /* Dialog validated: retrieve selected engine and do the job */
+        last_engine = gtk_combo_box_get_active ( GTK_COMBO_BOX(combo) );
+        VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine);
+
+        /* Change cursor */
+        vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
+
+        /* Force saving track */
+        /* FIXME: remove or rename this hack */
+        vtl->route_finder_check_added_track = TRUE;
+
+        /* the job */
+        vik_routing_engine_refine (routing, vtl, trk);
+
+        /* FIXME: remove or rename this hack */
+        if ( vtl->route_finder_added_track )
+          vik_track_calculate_bounds ( vtl->route_finder_added_track );
+
+        vtl->route_finder_added_track = NULL;
+        vtl->route_finder_check_added_track = FALSE;
+
+        vik_layer_emit_update ( VIK_LAYER(vtl) );
+
+        /* Restore cursor */
+        vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
+    }
+    gtk_widget_destroy ( dialog );
+  }
+}
+
 static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
 static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
@@ -7190,6 +7453,11 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
+    item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_statistics), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
+
     GtkWidget *goto_submenu;
     goto_submenu = gtk_menu_new ();
     item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
     GtkWidget *goto_submenu;
     goto_submenu = gtk_menu_new ();
     item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
@@ -7331,6 +7599,70 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
     gtk_widget_show ( item );
 
     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
     gtk_widget_show ( item );
 
+    GtkWidget *transform_submenu;
+    transform_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
+
+    GtkWidget *dem_submenu;
+    dem_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
+    gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_all), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
+    gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_only_missing), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
+    gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
+    gtk_widget_show ( item );
+
+    GtkWidget *smooth_submenu;
+    smooth_submenu = gtk_menu_new ();
+    item = gtk_menu_item_new_with_mnemonic ( _("_Smooth Missing Elevation Data") );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+    gtk_widget_show ( item );
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smooth_submenu );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolated") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_interp), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
+    gtk_widget_set_tooltip_text (item, _("Interpolate between known elevation values to derive values for the missing elevations"));
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Flat") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_flat), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
+    gtk_widget_set_tooltip_text (item, _("Set unknown elevation values to the last known value"));
+    gtk_widget_show ( item );
+
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") );
+    else
+      item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+    gtk_widget_show ( item );
+
+    // Routes don't have timestamps - so this is only available for tracks
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+      gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01"));
+      gtk_widget_show ( item );
+    }
+
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
     else
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
     else
@@ -7340,6 +7672,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
+    if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("Refine Route...") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_route_refine), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
+    }
+
     /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
     if ( vlp ) {
       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
     /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
     if ( vlp ) {
       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
@@ -7352,12 +7692,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
       gtk_widget_show ( item );
     }
 
       gtk_widget_show ( item );
     }
 
-    item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
-    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-    gtk_widget_show ( item );
-
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") );
     else
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") );
     else
@@ -7376,15 +7710,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
-    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
-      item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") );
-    else
-      item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") );
-    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
-    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along );
-    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-    gtk_widget_show ( item );
-
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
       item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
       item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
@@ -7473,6 +7798,37 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     }
   }
 
     }
   }
 
+  if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+    GtkWidget *transform_submenu;
+    transform_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
+
+    GtkWidget *dem_submenu;
+    dem_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
+    gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_all), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
+    gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_only_missing), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
+    gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
+    gtk_widget_show ( item );
+  }
+
+  gtk_widget_show_all ( GTK_WIDGET(menu) );
+
   return rv;
 }
 
   return rv;
 }
 
@@ -7938,8 +8294,12 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve
 
     // Determine if working on a waypoint or a trackpoint
     if ( t->is_waypoint ) {
 
     // Determine if working on a waypoint or a trackpoint
     if ( t->is_waypoint ) {
+      // Update waypoint position
       vtl->current_wp->coord = new_coord;
       trw_layer_calculate_bounds_waypoints ( vtl );
       vtl->current_wp->coord = new_coord;
       trw_layer_calculate_bounds_waypoints ( vtl );
+      // Reset waypoint pointer
+      vtl->current_wp    = NULL;
+      vtl->current_wp_id = NULL;
     }
     else {
       if ( vtl->current_tpl ) {
     }
     else {
       if ( vtl->current_tpl ) {
@@ -7948,17 +8308,13 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve
         if ( vtl->current_tp_track )
           vik_track_calculate_bounds ( vtl->current_tp_track );
 
         if ( vtl->current_tp_track )
           vik_track_calculate_bounds ( vtl->current_tp_track );
 
-       if ( vtl->tpwin )
+        if ( vtl->tpwin )
           if ( vtl->current_tp_track )
             vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
           if ( vtl->current_tp_track )
             vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+        // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin
       }
     }
 
       }
     }
 
-    // Reset
-    vtl->current_wp    = NULL;
-    vtl->current_wp_id = NULL;
-    trw_layer_cancel_current_tp ( vtl, FALSE );
-
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
@@ -8777,7 +9133,7 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
   {
     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
   {
     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
-    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name, FALSE ) ) )
+    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ) ) )
     {
       new_track_create_common ( vtl, name );
       g_free ( name );
     {
       new_track_create_common ( vtl, name );
       g_free ( name );
@@ -8810,7 +9166,7 @@ static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event,
   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
   {
     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
   {
     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
-    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->routes, name, TRUE ) ) ) {
+    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ) ) ) {
       new_route_create_common ( vtl, name );
       g_free ( name );
     }
       new_route_create_common ( vtl, name );
       g_free ( name );
     }
@@ -9356,7 +9712,8 @@ static void trw_layer_sort_all ( VikTrwLayer *vtl )
 
 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
 {
 
 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
 {
-  trw_layer_verify_thumbnails ( vtl, vvp );
+  if ( VIK_LAYER(vtl)->realized )
+    trw_layer_verify_thumbnails ( vtl, vvp );
   trw_layer_track_alloc_colors ( vtl );
 
   trw_layer_calculate_bounds_waypoints ( vtl );
   trw_layer_track_alloc_colors ( vtl );
 
   trw_layer_calculate_bounds_waypoints ( vtl );
@@ -9577,12 +9934,10 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g
 static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
 {
   VikMapsLayer *vml;
 static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
 {
   VikMapsLayer *vml;
-  gint selected_map, default_map;
+  gint selected_map;
   gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
   gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
   gint selected_zoom, default_zoom;
   gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
   gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
   gint selected_zoom, default_zoom;
-  int i,j;
-
 
   VikTrwLayer *vtl = pass_along[0];
   VikLayersPanel *vlp = pass_along[1];
 
   VikTrwLayer *vtl = pass_along[0];
   VikLayersPanel *vlp = pass_along[1];
@@ -9600,49 +9955,35 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
   int num_maps = g_list_length(vmls);
 
   if (!num_maps) {
   int num_maps = g_list_length(vmls);
 
   if (!num_maps) {
-    a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR, _("No map layer in use. Create one first"), NULL);
+    a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No map layer in use. Create one first") );
     return;
   }
 
     return;
   }
 
+  // Convert from list of vmls to list of names. Allowing the user to select one of them
   gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
   VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
 
   gchar **np = map_names;
   VikMapsLayer **lp = map_layers;
   gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
   VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
 
   gchar **np = map_names;
   VikMapsLayer **lp = map_layers;
+  int i;
   for (i = 0; i < num_maps; i++) {
   for (i = 0; i < num_maps; i++) {
-    gboolean dup = FALSE;
     vml = (VikMapsLayer *)(vmls->data);
     vml = (VikMapsLayer *)(vmls->data);
-    for (j = 0; j < i; j++) { /* no duplicate allowed */
-      if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) {
-        dup = TRUE;
-        break;
-      }
-    }
-    if (!dup) {
-      *lp++ = vml;
-      *np++ = vik_maps_layer_get_map_label(vml);
-    }
+    *lp++ = vml;
+    *np++ = vik_maps_layer_get_map_label(vml);
     vmls = vmls->next;
   }
     vmls = vmls->next;
   }
+  // Mark end of the array lists
   *lp = NULL;
   *np = NULL;
   *lp = NULL;
   *np = NULL;
-  num_maps = lp - map_layers;
-
-  for (default_map = 0; default_map < num_maps; default_map++) {
-    /* TODO: check for parent layer's visibility */
-    if (VIK_LAYER(map_layers[default_map])->visible)
-      break;
-  }
-  default_map = (default_map == num_maps) ? 0 : default_map;
 
   gdouble cur_zoom = vik_viewport_get_zoom(vvp);
 
   gdouble cur_zoom = vik_viewport_get_zoom(vvp);
-  for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
+  for (default_zoom = 0; default_zoom < G_N_ELEMENTS(zoom_vals); default_zoom++) {
     if (cur_zoom == zoom_vals[default_zoom])
       break;
   }
     if (cur_zoom == zoom_vals[default_zoom])
       break;
   }
-  default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
+  default_zoom = (default_zoom == G_N_ELEMENTS(zoom_vals)) ? G_N_ELEMENTS(zoom_vals) - 1 : default_zoom;
 
 
-  if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom))
+  if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, 0, zoomlist, default_zoom, &selected_map, &selected_zoom))
     goto done;
 
   vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
     goto done;
 
   vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);