]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Extract a UI module for babel
[andy/viking.git] / src / viktrwlayer.c
index 00b59ab6f1b023cb114d85b8420dd7afc20812ac..c085e720220c78829d36856d07ec550f495c4f44 100644 (file)
@@ -33,6 +33,7 @@
 #include "viking.h"
 #include "vikmapslayer.h"
 #include "vikgpslayer.h"
 #include "viking.h"
 #include "vikmapslayer.h"
 #include "vikgpslayer.h"
+#include "viktrwlayer_export.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_analysis.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_analysis.h"
@@ -149,6 +150,9 @@ struct _VikTrwLayer {
   guint8 bg_line_thickness;
   vik_layer_sort_order_t track_sort_order;
 
   guint8 bg_line_thickness;
   vik_layer_sort_order_t track_sort_order;
 
+  // Metadata
+  VikTRWMetadata *metadata;
+
   PangoLayout *tracklabellayout;
   font_size_t track_font_size;
   gchar *track_fsize_str;
   PangoLayout *tracklabellayout;
   font_size_t track_font_size;
   gchar *track_fsize_str;
@@ -250,9 +254,24 @@ struct DrawingParams {
 
 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
 
 
 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
 
-static void trw_layer_delete_item ( gpointer pass_along[6] );
-static void trw_layer_copy_item_cb ( gpointer pass_along[6] );
-static void trw_layer_cut_item_cb ( gpointer pass_along[6] );
+typedef enum {
+  MA_VTL = 0,
+  MA_VLP,
+  MA_SUBTYPE, // OR END for Layer only
+  MA_SUBLAYER_ID,
+  MA_CONFIRM,
+  MA_VVP,
+  MA_TV_ITER,
+  MA_MISC,
+  MA_LAST,
+} menu_array_index;
+
+typedef gpointer menu_array_layer[2];
+typedef gpointer menu_array_sublayer[MA_LAST];
+
+static void trw_layer_delete_item ( menu_array_sublayer values );
+static void trw_layer_copy_item_cb ( menu_array_sublayer values );
+static void trw_layer_cut_item_cb ( menu_array_sublayer values );
 
 static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] );
 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
 
 static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] );
 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
@@ -264,83 +283,82 @@ static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct
 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp );
 
 static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp );
 
 static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
-static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] );
-static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
-static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] );
-static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
-static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
-static void trw_layer_goto_track_center ( gpointer pass_along[6] );
-static void trw_layer_merge_by_segment ( gpointer pass_along[6] );
-static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
-static void trw_layer_merge_with_other ( gpointer pass_along[6] );
-static void trw_layer_append_track ( gpointer pass_along[6] );
-static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
-static void trw_layer_split_by_n_points ( gpointer pass_along[6] );
-static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] );
-static void trw_layer_split_segments ( gpointer pass_along[6] );
-static void trw_layer_delete_point_selected ( gpointer pass_along[6] );
-static void trw_layer_delete_points_same_position ( gpointer pass_along[6] );
-static void trw_layer_delete_points_same_time ( gpointer pass_along[6] );
-static void trw_layer_reverse ( gpointer pass_along[6] );
-static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] );
-static void trw_layer_edit_trackpoint ( gpointer pass_along[6] );
-static void trw_layer_show_picture ( gpointer pass_along[6] );
-static void trw_layer_gps_upload_any ( gpointer pass_along[6] );
-
-static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
-static void trw_layer_auto_view ( gpointer layer_and_vlp[2] );
-static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type );
-static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
-static void trw_layer_new_wp ( gpointer lav[2] );
-static void trw_layer_new_track ( gpointer lav[2] );
-static void trw_layer_new_route ( gpointer lav[2] );
-static void trw_layer_finish_track ( gpointer lav[2] );
-static void trw_layer_auto_waypoints_view ( gpointer lav[2] );
-static void trw_layer_auto_tracks_view ( gpointer lav[2] );
-static void trw_layer_delete_all_tracks ( gpointer lav[2] );
-static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] );
-static void trw_layer_delete_all_waypoints ( gpointer lav[2] );
-static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] );
-static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] );
-static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] );
+static void trw_layer_goto_track_startpoint ( menu_array_sublayer values );
+static void trw_layer_goto_track_endpoint ( menu_array_sublayer values );
+static void trw_layer_goto_track_max_speed ( menu_array_sublayer values );
+static void trw_layer_goto_track_max_alt ( menu_array_sublayer values );
+static void trw_layer_goto_track_min_alt ( menu_array_sublayer values );
+static void trw_layer_goto_track_center ( menu_array_sublayer values );
+static void trw_layer_merge_by_segment ( menu_array_sublayer values );
+static void trw_layer_merge_by_timestamp ( menu_array_sublayer values );
+static void trw_layer_merge_with_other ( menu_array_sublayer values );
+static void trw_layer_append_track ( menu_array_sublayer values );
+static void trw_layer_split_by_timestamp ( menu_array_sublayer values );
+static void trw_layer_split_by_n_points ( menu_array_sublayer values );
+static void trw_layer_split_at_trackpoint ( menu_array_sublayer values );
+static void trw_layer_split_segments ( menu_array_sublayer values );
+static void trw_layer_delete_point_selected ( menu_array_sublayer values );
+static void trw_layer_delete_points_same_position ( menu_array_sublayer values );
+static void trw_layer_delete_points_same_time ( menu_array_sublayer values );
+static void trw_layer_reverse ( menu_array_sublayer values );
+static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values );
+static void trw_layer_edit_trackpoint ( menu_array_sublayer values );
+static void trw_layer_show_picture ( menu_array_sublayer values );
+static void trw_layer_gps_upload_any ( menu_array_sublayer values );
+
+static void trw_layer_centerize ( menu_array_layer values );
+static void trw_layer_auto_view ( menu_array_layer values );
+static void trw_layer_goto_wp ( menu_array_layer values );
+static void trw_layer_new_wp ( menu_array_layer values );
+static void trw_layer_new_track ( menu_array_layer values );
+static void trw_layer_new_route ( menu_array_layer values );
+static void trw_layer_finish_track ( menu_array_layer values );
+static void trw_layer_auto_waypoints_view ( menu_array_layer values );
+static void trw_layer_auto_tracks_view ( menu_array_layer values );
+static void trw_layer_delete_all_tracks ( menu_array_layer values );
+static void trw_layer_delete_tracks_from_selection ( menu_array_layer values );
+static void trw_layer_delete_all_waypoints ( menu_array_layer values );
+static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values );
+static void trw_layer_new_wikipedia_wp_viewport ( menu_array_layer values );
+static void trw_layer_new_wikipedia_wp_layer ( menu_array_layer values );
 #ifdef VIK_CONFIG_GEOTAG
 #ifdef VIK_CONFIG_GEOTAG
-static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] );
-static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] );
-static void trw_layer_geotagging_track ( gpointer pass_along[6] );
-static void trw_layer_geotagging ( gpointer lav[2] );
+static void trw_layer_geotagging_waypoint_mtime_keep ( menu_array_sublayer values );
+static void trw_layer_geotagging_waypoint_mtime_update ( menu_array_sublayer values );
+static void trw_layer_geotagging_track ( menu_array_sublayer values );
+static void trw_layer_geotagging ( menu_array_layer values );
 #endif
 #endif
-static void trw_layer_acquire_gps_cb ( gpointer lav[2] );
-static void trw_layer_acquire_routing_cb ( gpointer lav[2] );
-static void trw_layer_acquire_url_cb ( gpointer lav[2] );
+static void trw_layer_acquire_gps_cb ( menu_array_layer values );
+static void trw_layer_acquire_routing_cb ( menu_array_layer values );
+static void trw_layer_acquire_url_cb ( menu_array_layer values );
 #ifdef VIK_CONFIG_OPENSTREETMAP
 #ifdef VIK_CONFIG_OPENSTREETMAP
-static void trw_layer_acquire_osm_cb ( gpointer lav[2] );
-static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] );
+static void trw_layer_acquire_osm_cb ( menu_array_layer values );
+static void trw_layer_acquire_osm_my_traces_cb ( menu_array_layer values );
 #endif
 #ifdef VIK_CONFIG_GEOCACHES
 #endif
 #ifdef VIK_CONFIG_GEOCACHES
-static void trw_layer_acquire_geocache_cb ( gpointer lav[2] );
+static void trw_layer_acquire_geocache_cb ( menu_array_layer values );
 #endif
 #ifdef VIK_CONFIG_GEOTAG
 #endif
 #ifdef VIK_CONFIG_GEOTAG
-static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] );
+static void trw_layer_acquire_geotagged_cb ( menu_array_layer values );
 #endif
 #endif
-static void trw_layer_acquire_file_cb ( gpointer lav[2] );
-static void trw_layer_gps_upload ( gpointer lav[2] );
+static void trw_layer_acquire_file_cb ( menu_array_layer values );
+static void trw_layer_gps_upload ( menu_array_layer values );
 
 
-static void trw_layer_track_list_dialog_single ( gpointer pass_along[6] );
-static void trw_layer_track_list_dialog ( gpointer lav[2] );
-static void trw_layer_waypoint_list_dialog ( gpointer lav[2] );
+static void trw_layer_track_list_dialog_single ( menu_array_sublayer values );
+static void trw_layer_track_list_dialog ( menu_array_layer values );
+static void trw_layer_waypoint_list_dialog ( menu_array_layer values );
 
 // Specific route versions:
 //  Most track handling functions can handle operating on the route list
 //  However these ones are easier in separate functions
 
 // Specific route versions:
 //  Most track handling functions can handle operating on the route list
 //  However these ones are easier in separate functions
-static void trw_layer_auto_routes_view ( gpointer lav[2] );
-static void trw_layer_delete_all_routes ( gpointer lav[2] );
-static void trw_layer_delete_routes_from_selection ( gpointer lav[2] );
+static void trw_layer_auto_routes_view ( menu_array_layer values );
+static void trw_layer_delete_all_routes ( menu_array_layer values );
+static void trw_layer_delete_routes_from_selection ( menu_array_layer values );
 
 /* pop-up items */
 
 /* pop-up items */
-static void trw_layer_properties_item ( gpointer pass_along[7] );
-static void trw_layer_goto_waypoint ( gpointer pass_along[6] );
-static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] );
-static void trw_layer_waypoint_webpage ( gpointer pass_along[6] );
+static void trw_layer_properties_item ( gpointer pass_along[7] ); //TODO??
+static void trw_layer_goto_waypoint ( menu_array_sublayer values );
+static void trw_layer_waypoint_gc_webpage ( menu_array_sublayer values );
+static void trw_layer_waypoint_webpage ( menu_array_sublayer values );
 
 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
 
 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
@@ -466,8 +484,8 @@ enum {
 
 /****** PARAMETERS ******/
 
 
 /****** PARAMETERS ******/
 
-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_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced"), N_("Metadata") };
+enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV, GROUP_METADATA };
 
 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,6 +563,13 @@ static VikLayerParamData image_cache_size_default ( void ) { return VIK_LPD_UINT
 
 static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); }
 
 
 static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); }
 
+static VikLayerParamData string_default ( void )
+{
+  VikLayerParamData data;
+  data.s = "";
+  return data;
+}
+
 VikLayerParam trw_layer_params[] = {
   { VIK_LAYER_TRW, "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
 VikLayerParam trw_layer_params[] = {
   { VIK_LAYER_TRW, "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
@@ -589,6 +614,11 @@ VikLayerParam trw_layer_params[] = {
   { VIK_LAYER_TRW, "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[3], NULL, NULL, image_size_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[4], NULL, NULL, image_alpha_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[5], NULL, NULL, image_cache_size_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[3], NULL, NULL, image_size_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[4], NULL, NULL, image_alpha_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[5], NULL, NULL, image_cache_size_default, NULL, NULL },
+
+  { VIK_LAYER_TRW, "metadatadesc", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Description"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
+  { VIK_LAYER_TRW, "metadataauthor", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Author"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
+  { VIK_LAYER_TRW, "metadatatime", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Creation Time"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
+  { VIK_LAYER_TRW, "metadatakeywords", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Keywords"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
 };
 
 // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
 };
 
 // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
@@ -632,6 +662,11 @@ enum {
   PARAM_IS,
   PARAM_IA,
   PARAM_ICS,
   PARAM_IS,
   PARAM_IA,
   PARAM_ICS,
+  // Metadata
+  PARAM_MDDESC,
+  PARAM_MDAUTH,
+  PARAM_MDTIME,
+  PARAM_MDKEYS,
   NUM_PARAMS
 };
 
   NUM_PARAMS
 };
 
@@ -760,46 +795,147 @@ GType vik_trw_layer_get_type ()
   return vtl_type;
 }
 
   return vtl_type;
 }
 
+VikTRWMetadata *vik_trw_metadata_new()
+{
+  return (VikTRWMetadata*)g_malloc0(sizeof(VikTRWMetadata));
+}
+
+void vik_trw_metadata_free ( VikTRWMetadata *metadata)
+{
+  g_free (metadata);
+}
+
+VikTRWMetadata *vik_trw_layer_get_metadata ( VikTrwLayer *vtl )
+{
+  return vtl->metadata;
+}
+
+void vik_trw_layer_set_metadata ( VikTrwLayer *vtl, VikTRWMetadata *metadata)
+{
+  if ( vtl->metadata )
+    vik_trw_metadata_free ( vtl->metadata );
+  vtl->metadata = metadata;
+}
+
+typedef struct {
+  gboolean found;
+  const gchar *date_str;
+  const VikTrack *trk;
+  const VikWaypoint *wpt;
+  gpointer *trk_id;
+  gpointer *wpt_id;
+} date_finder_type;
+
+static gboolean trw_layer_find_date_track ( const gpointer id, const VikTrack *trk, date_finder_type *df )
+{
+  gchar date_buf[20];
+  date_buf[0] = '\0';
+  // Might be an easier way to compare dates rather than converting the strings all the time...
+  if ( trk->trackpoints && VIK_TRACKPOINT(trk->trackpoints->data)->has_timestamp ) {
+    strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(VIK_TRACKPOINT(trk->trackpoints->data)->timestamp)));
+
+    if ( ! g_strcmp0 ( df->date_str, date_buf ) ) {
+      df->found = TRUE;
+      df->trk = trk;
+      df->trk_id = id;
+    }
+  }
+  return df->found;
+}
+
+static gboolean trw_layer_find_date_waypoint ( const gpointer id, const VikWaypoint *wpt, date_finder_type *df )
+{
+  gchar date_buf[20];
+  date_buf[0] = '\0';
+  // Might be an easier way to compare dates rather than converting the strings all the time...
+  if ( wpt->has_timestamp ) {
+    strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(wpt->timestamp)));
+
+    if ( ! g_strcmp0 ( df->date_str, date_buf ) ) {
+      df->found = TRUE;
+      df->wpt = wpt;
+      df->wpt_id = id;
+    }
+  }
+  return df->found;
+}
+
+/**
+ * Find an item by date
+ */
+gboolean vik_trw_layer_find_date ( VikTrwLayer *vtl, const gchar *date_str, VikCoord *position, VikViewport *vvp, gboolean do_tracks, gboolean select )
+{
+  date_finder_type df;
+  df.found = FALSE;
+  df.date_str = date_str;
+  df.trk = NULL;
+  df.wpt = NULL;
+  // Only tracks ATM
+  if ( do_tracks )
+    g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_find_date_track, &df );
+  else
+    g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_find_date_waypoint, &df );
+
+  if ( select && df.found ) {
+    if ( do_tracks && df.trk ) {
+      struct LatLon maxmin[2] = { {0,0}, {0,0} };
+      trw_layer_find_maxmin_tracks ( NULL, df.trk, maxmin );
+      trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin );
+      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->tracks_iters, df.trk_id), TRUE );
+    }
+    else if ( df.wpt ) {
+      vik_viewport_set_center_coord ( vvp, &(df.wpt->coord) );
+      vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->waypoints_iters, df.wpt_id), TRUE );
+    }
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+  }
+  return df.found;
+}
+
 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
-  static gpointer pass_along[6];
+  static menu_array_sublayer values;
   if (!sublayer) {
     return;
   }
   if (!sublayer) {
     return;
   }
-  
-  pass_along[0] = vtl;
-  pass_along[1] = NULL;
-  pass_along[2] = GINT_TO_POINTER (subtype);
-  pass_along[3] = sublayer;
-  pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
-  pass_along[5] = NULL;
 
 
-  trw_layer_delete_item ( pass_along );
+  gint ii;
+  for ( ii = MA_VTL; ii < MA_LAST; ii++ )
+    values[ii] = NULL;
+
+  values[MA_VTL]         = vtl;
+  values[MA_SUBTYPE]     = GINT_TO_POINTER (subtype);
+  values[MA_SUBLAYER_ID] = sublayer;
+  values[MA_CONFIRM]     = GINT_TO_POINTER (1); // Confirm delete request
+
+  trw_layer_delete_item ( values );
 }
 
 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
 }
 
 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
-  static gpointer pass_along[6];
+  static menu_array_sublayer values;
   if (!sublayer) {
     return;
   }
 
   if (!sublayer) {
     return;
   }
 
-  pass_along[0] = vtl;
-  pass_along[1] = NULL;
-  pass_along[2] = GINT_TO_POINTER (subtype);
-  pass_along[3] = sublayer;
-  pass_along[4] = GINT_TO_POINTER (0); // No delete confirmation needed for auto delete
-  pass_along[5] = NULL;
+  gint ii;
+  for ( ii = MA_VTL; ii < MA_LAST; ii++ )
+    values[ii] = NULL;
 
 
-  trw_layer_copy_item_cb(pass_along);
-  trw_layer_cut_item_cb(pass_along);
+  values[MA_VTL]         = vtl;
+  values[MA_SUBTYPE]     = GINT_TO_POINTER (subtype);
+  values[MA_SUBLAYER_ID] = sublayer;
+  values[MA_CONFIRM]     = GINT_TO_POINTER (1); // Confirm delete request
+
+  trw_layer_copy_item_cb(values);
+  trw_layer_cut_item_cb(values);
 }
 
 }
 
-static void trw_layer_copy_item_cb ( gpointer pass_along[6])
+static void trw_layer_copy_item_cb ( menu_array_sublayer values)
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  gint subtype = GPOINTER_TO_INT (pass_along[2]);
-  gpointer * sublayer = pass_along[3];
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]);
+  gpointer * sublayer = values[MA_SUBLAYER_ID];
   guint8 *data = NULL;
   guint len;
 
   guint8 *data = NULL;
   guint len;
 
@@ -834,17 +970,17 @@ static void trw_layer_copy_item_cb ( gpointer pass_along[6])
   }
 }
 
   }
 }
 
-static void trw_layer_cut_item_cb ( gpointer pass_along[6])
+static void trw_layer_cut_item_cb ( menu_array_sublayer values)
 {
 {
-  trw_layer_copy_item_cb(pass_along);
-  pass_along[4] = GINT_TO_POINTER (0); // Never need to confirm automatic delete
-  trw_layer_delete_item(pass_along);
+  trw_layer_copy_item_cb(values);
+  values[MA_CONFIRM] = GINT_TO_POINTER (0); // Never need to confirm automatic delete
+  trw_layer_delete_item(values);
 }
 
 }
 
-static void trw_layer_paste_item_cb ( gpointer pass_along[6])
+static void trw_layer_paste_item_cb ( menu_array_sublayer values)
 {
   // Slightly cheating method, routing via the panels capability
 {
   // Slightly cheating method, routing via the panels capability
-  a_clipboard_paste (VIK_LAYERS_PANEL(pass_along[1]));
+  a_clipboard_paste (VIK_LAYERS_PANEL(values[MA_VLP]));
 }
 
 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
 }
 
 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
@@ -1062,6 +1198,12 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
       }
       break;
     case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break;
       }
       break;
     case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break;
+    // Metadata
+    case PARAM_MDDESC: if ( data.s && vtl->metadata ) vtl->metadata->description = g_strdup (data.s); break;
+    case PARAM_MDAUTH: if ( data.s && vtl->metadata ) vtl->metadata->author = g_strdup (data.s); break;
+    case PARAM_MDTIME: if ( data.s && vtl->metadata ) vtl->metadata->timestamp = g_strdup (data.s); break;
+    case PARAM_MDKEYS: if ( data.s && vtl->metadata ) vtl->metadata->keywords = g_strdup (data.s); break;
+    default: break;
   }
   return TRUE;
 }
   }
   return TRUE;
 }
@@ -1106,6 +1248,12 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo
     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
     case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
     case PARAM_WPSO: rv.u = vtl->wp_sort_order; break;
     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
     case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
     case PARAM_WPSO: rv.u = vtl->wp_sort_order; break;
+    // Metadata
+    case PARAM_MDDESC: if (vtl->metadata) { rv.s = vtl->metadata->description; } break;
+    case PARAM_MDAUTH: if (vtl->metadata) { rv.s = vtl->metadata->author; } break;
+    case PARAM_MDTIME: if (vtl->metadata) { rv.s = vtl->metadata->timestamp; } break;
+    case PARAM_MDKEYS: if (vtl->metadata) { rv.s = vtl->metadata->keywords; } break;
+    default: break;
   }
   return rv;
 }
   }
   return rv;
 }
@@ -1173,6 +1321,12 @@ static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values
       if ( w2 ) gtk_widget_set_sensitive ( w2, sensitive );
       break;
     }
       if ( w2 ) gtk_widget_set_sensitive ( w2, sensitive );
       break;
     }
+    case PARAM_MDTIME: {
+      // Force metadata->timestamp to be always read-only for now.
+      GtkWidget **ww = values[UI_CHG_WIDGETS];
+      GtkWidget *w1 = ww[OFFSET + PARAM_MDTIME];
+      if ( w1 ) gtk_widget_set_sensitive ( w1, FALSE );
+    }
     // NB Since other track settings have been split across tabs,
     // I don't think it's useful to set sensitivities on widgets you can't immediately see
     default: break;
     // NB Since other track settings have been split across tabs,
     // I don't think it's useful to set sensitivities on widgets you can't immediately see
     default: break;
@@ -1366,6 +1520,7 @@ static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp )
   // Force to on after processing params (which defaults them to off with a zero value)
   rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE;
 
   // Force to on after processing params (which defaults them to off with a zero value)
   rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE;
 
+  rv->metadata = vik_trw_metadata_new ();
   rv->draw_sync_done = TRUE;
   rv->draw_sync_do = TRUE;
   // Everything else is 0, FALSE or NULL
   rv->draw_sync_done = TRUE;
   rv->draw_sync_do = TRUE;
   // Everything else is 0, FALSE or NULL
@@ -1695,9 +1850,14 @@ static void trw_layer_draw_track_name_labels ( struct DrawingParams *dp, VikTrac
     // No other labels to draw
     return;
 
     // No other labels to draw
     return;
 
-  GList *ending = g_list_last ( trk->trackpoints );
-  VikCoord begin_coord = VIK_TRACKPOINT(trk->trackpoints->data)->coord;
-  VikCoord end_coord = VIK_TRACKPOINT(ending->data)->coord;
+  VikTrackpoint *tp_end = vik_track_get_tp_last ( trk );
+  if ( !tp_end )
+    return;
+  VikTrackpoint *tp_begin = vik_track_get_tp_first ( trk );
+  if ( !tp_begin )
+    return;
+  VikCoord begin_coord = tp_begin->coord;
+  VikCoord end_coord = tp_end->coord;
 
   gboolean done_start_end = FALSE;
 
 
   gboolean done_start_end = FALSE;
 
@@ -2498,12 +2658,12 @@ static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_
 
   // Ensure times are available
   if ( tr->trackpoints &&
 
   // Ensure times are available
   if ( tr->trackpoints &&
-       VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp &&
-       VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) {
+       vik_track_get_tp_first(tr)->has_timestamp &&
+       vik_track_get_tp_last(tr)->has_timestamp ) {
 
     time_t t1, t2;
 
     time_t t1, t2;
-    t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
-    t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
+    t1 = vik_track_get_tp_first(tr)->timestamp;
+    t2 = vik_track_get_tp_last(tr)->timestamp;
 
     // Assume never actually have a track with a time of 0 (1st Jan 1970)
     // Hence initialize to the first 'proper' value
 
     // Assume never actually have a track with a time of 0 (1st Jan 1970)
     // Hence initialize to the first 'proper' value
@@ -2653,11 +2813,11 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
        static gchar tmp_buf[100];
        // Compact info: Short date eg (11/20/99), duration and length
        // Hopefully these are the things that are most useful and so promoted into the tooltip
        static gchar tmp_buf[100];
        // Compact info: Short date eg (11/20/99), duration and length
        // Hopefully these are the things that are most useful and so promoted into the tooltip
-       if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp ) {
+       if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) {
          // %x     The preferred date representation for the current locale without the time.
          // %x     The preferred date representation for the current locale without the time.
-         strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(VIK_TRACKPOINT(tr->trackpoints->data)->timestamp)));
-         if ( VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) {
-           gint dur = ( (VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp) - (VIK_TRACKPOINT(tr->trackpoints->data)->timestamp) );
+         strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(vik_track_get_tp_first(tr)->timestamp)));
+         if ( vik_track_get_tp_last(tr)->has_timestamp ) {
+           gint dur = ( (vik_track_get_tp_last(tr)->timestamp) - (vik_track_get_tp_first(tr)->timestamp) );
            if ( dur > 0 )
              g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
          }
            if ( dur > 0 )
              g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
          }
@@ -3002,13 +3162,14 @@ gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
   }
 }
 
   }
 }
 
-static void trw_layer_centerize ( gpointer layer_and_vlp[2] )
+static void trw_layer_centerize ( menu_array_layer values )
 {
 {
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikCoord coord;
   VikCoord coord;
-  if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
-    goto_coord ( layer_and_vlp[1], NULL, NULL, &coord );
+  if ( vik_trw_layer_find_center ( vtl, &coord ) )
+    goto_coord ( values[MA_VLP], NULL, NULL, &coord );
   else
   else
-    a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
+    a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") );
 }
 
 void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
 }
 
 void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
@@ -3073,159 +3234,88 @@ gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp )
   }
 }
 
   }
 }
 
-static void trw_layer_auto_view ( gpointer layer_and_vlp[2] )
+static void trw_layer_auto_view ( menu_array_layer values )
 {
 {
-  if ( vik_trw_layer_auto_set_view ( VIK_TRW_LAYER(layer_and_vlp[0]), vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(layer_and_vlp[1])) ) ) {
-    vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
+  if ( vik_trw_layer_auto_set_view ( vtl, vik_layers_panel_get_viewport (vlp) ) ) {
+    vik_layers_panel_emit_update ( vlp );
   }
   else
   }
   else
-    a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
+    a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") );
 }
 
 }
 
-static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type )
+static void trw_layer_export_gpspoint ( menu_array_layer values )
 {
 {
-  GtkWidget *file_selector;
-  const gchar *fn;
-  gboolean failed = FALSE;
-  file_selector = gtk_file_chooser_dialog_new (title,
-                                              NULL,
-                                              GTK_FILE_CHOOSER_ACTION_SAVE,
-                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                              GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-                                              NULL);
-  gchar *cwd = g_get_current_dir();
-  if ( cwd ) {
-    gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(file_selector), cwd );
-    g_free ( cwd );
-  }
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPSPOINT );
 
 
-  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name);
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPSPOINT );
 
 
-  while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT )
-  {
-    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) );
-    if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE ||
-         a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
-    {
-      gtk_widget_hide ( file_selector );
-      vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
-      failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
-      vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
-      break;
-    }
-  }
-  gtk_widget_destroy ( file_selector );
-  if ( failed )
-    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The filename you requested could not be opened for writing.") );
+  g_free ( auto_save_name );
 }
 
 }
 
-static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] )
+static void trw_layer_export_gpsmapper ( menu_array_layer values )
 {
 {
-  trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSPOINT );
-}
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPSMAPPER );
 
 
-static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] )
-{
-  trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSMAPPER );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPSMAPPER );
+
+  g_free ( auto_save_name );
 }
 
 }
 
-static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
+static void trw_layer_export_gpx ( menu_array_layer values )
 {
 {
-  /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
-  if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
-    auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPX );
 
 
-  trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
 
   g_free ( auto_save_name );
 }
 
 
   g_free ( auto_save_name );
 }
 
-static void trw_layer_export_kml ( gpointer layer_and_vlp[2] )
+static void trw_layer_export_kml ( menu_array_layer values )
 {
 {
-  /* Auto append '.kml' to the name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
-  if ( ! check_file_ext ( auto_save_name, ".kml" ) )
-    auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL );
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_KML );
 
 
-  trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
 
   g_free ( auto_save_name );
 }
 
 
   g_free ( auto_save_name );
 }
 
-/**
- * Convert the given TRW layer into a temporary GPX file and open it with the specified program
- *
- */
-static void trw_layer_export_external_gpx ( gpointer layer_and_vlp[2], const gchar* external_program )
-{
-  gchar *name_used = NULL;
-  int fd;
-
-  if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) {
-    vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
-    gboolean failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), name_used, FILE_TYPE_GPX, NULL, TRUE);
-    vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
-    if (failed) {
-      a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Could not create temporary file for export.") );
-    }
-    else {
-      GError *err = NULL;
-      gchar *quoted_file = g_shell_quote ( name_used );
-      gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file );
-      g_free ( quoted_file );
-      if ( ! g_spawn_command_line_async ( cmd, &err ) )
-       {
-         a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( layer_and_vlp[0]), _("Could not launch %s."), external_program );
-         g_error_free ( err );
-       }
-      g_free ( cmd );
-    }
-    // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous
-    //g_remove ( name_used );
-    // Perhaps should be deleted when the program ends?
-    // For now leave it to the user to delete it / use system temp cleanup methods.
-    g_free ( name_used );
-  }
-}
 
 
-static void trw_layer_export_external_gpx_1 ( gpointer layer_and_vlp[2] )
+static void trw_layer_export_external_gpx_1 ( menu_array_layer values )
 {
 {
-  trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_1() );
+  vik_trw_layer_export_external_gpx ( VIK_TRW_LAYER (values[MA_VTL]), a_vik_get_external_gpx_program_1() );
 }
 
 }
 
-static void trw_layer_export_external_gpx_2 ( gpointer layer_and_vlp[2] )
+static void trw_layer_export_external_gpx_2 ( menu_array_layer values )
 {
 {
-  trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_2() );
+  vik_trw_layer_export_external_gpx ( VIK_TRW_LAYER (values[MA_VTL]), a_vik_get_external_gpx_program_2() );
 }
 
 }
 
-static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
+static void trw_layer_export_gpx_track ( menu_array_sublayer values )
 {
 {
-  gpointer layer_and_vlp[2];
-  layer_and_vlp[0] = pass_along[0];
-  layer_and_vlp[1] = pass_along[1];
+  menu_array_layer data;
+  data[MA_VTL] = values[MA_VTL];
+  data[MA_VLP] = values[MA_VLP];
 
 
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk || !trk->name )
     return;
 
 
   if ( !trk || !trk->name )
     return;
 
-  /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( trk->name );
-  if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
-    auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
+  gchar *auto_save_name = append_file_ext ( trk->name, FILE_TYPE_GPX );
 
   gchar *label = NULL;
 
   gchar *label = NULL;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
     label = _("Export Route as GPX");
   else
     label = _("Export Track as GPX");
     label = _("Export Route as GPX");
   else
     label = _("Export Track as GPX");
-  trw_layer_export ( layer_and_vlp, label, auto_save_name, trk, FILE_TYPE_GPX );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), label, auto_save_name, trk, FILE_TYPE_GPX );
 
   g_free ( auto_save_name );
 }
 
   g_free ( auto_save_name );
 }
@@ -3240,10 +3330,12 @@ gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp
   return FALSE;
 }
 
   return FALSE;
 }
 
-static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
+static void trw_layer_goto_wp ( menu_array_layer values )
 {
 {
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
   GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
-                                                 VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
+                                                 VIK_GTK_WINDOW_FROM_LAYER(vtl),
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                  GTK_STOCK_CANCEL,
                                                  GTK_RESPONSE_REJECT,
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                  GTK_STOCK_CANCEL,
                                                  GTK_RESPONSE_REJECT,
@@ -3266,14 +3358,14 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
   {
     gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
     // Find *first* wp with the given name
   {
     gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
     // Find *first* wp with the given name
-    VikWaypoint *wp = vik_trw_layer_get_waypoint ( VIK_TRW_LAYER(layer_and_vlp[0]), name );
+    VikWaypoint *wp = vik_trw_layer_get_waypoint ( vtl, name );
 
     if ( !wp )
 
     if ( !wp )
-      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
+      a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Waypoint not found in this layer.") );
     else
     {
     else
     {
-      vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
-      vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
+      vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), &(wp->coord) );
+      vik_layers_panel_emit_update ( vlp );
 
       // Find and select on the side panel
       wpu_udata udata;
 
       // Find and select on the side panel
       wpu_udata udata;
@@ -3281,11 +3373,11 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
       udata.uuid = NULL;
 
       // Hmmm, want key of it
       udata.uuid = NULL;
 
       // Hmmm, want key of it
-      gpointer *wpf = g_hash_table_find ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+      gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
 
       if ( wpf && udata.uuid ) {
 
       if ( wpf && udata.uuid ) {
-        GtkTreeIter *it = g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, udata.uuid );
-        vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, it, TRUE );
+        GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+        vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, it, TRUE );
       }
 
       break;
       }
 
       break;
@@ -3323,11 +3415,11 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC
   return FALSE;
 }
 
   return FALSE;
 }
 
-static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] )
+static void trw_layer_new_wikipedia_wp_viewport ( menu_array_layer values )
 {
   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
 {
   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
@@ -3338,10 +3430,10 @@ static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] )
   vik_layers_panel_emit_update ( vlp );
 }
 
   vik_layers_panel_emit_update ( vlp );
 }
 
-static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] )
+static void trw_layer_new_wikipedia_wp_layer ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
   
   trw_layer_find_maxmin (vtl, maxmin);
   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
   
   trw_layer_find_maxmin (vtl, maxmin);
@@ -3351,17 +3443,17 @@ static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] )
 }
 
 #ifdef VIK_CONFIG_GEOTAG
 }
 
 #ifdef VIK_CONFIG_GEOTAG
-static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] )
+static void trw_layer_geotagging_waypoint_mtime_keep ( menu_array_sublayer values )
 {
 {
-  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->waypoints, values[MA_SUBLAYER_ID] );
   if ( wp )
     // Update directly - not changing the mtime
     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE );
 }
 
   if ( wp )
     // Update directly - not changing the mtime
     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE );
 }
 
-static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] )
+static void trw_layer_geotagging_waypoint_mtime_update ( menu_array_sublayer values )
 {
 {
-  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->waypoints, values[MA_SUBLAYER_ID] );
   if ( wp )
     // Update directly
     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE );
   if ( wp )
     // Update directly
     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE );
@@ -3370,10 +3462,10 @@ static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6]
 /*
  * Use code in separate file for this feature as reasonably complex
  */
 /*
  * Use code in separate file for this feature as reasonably complex
  */
-static void trw_layer_geotagging_track ( gpointer pass_along[6] )
+static void trw_layer_geotagging_track ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikTrack *track = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
   // Unset so can be reverified later if necessary
   vtl->has_verified_thumbnails = FALSE;
 
   // Unset so can be reverified later if necessary
   vtl->has_verified_thumbnails = FALSE;
 
@@ -3383,10 +3475,10 @@ static void trw_layer_geotagging_track ( gpointer pass_along[6] )
                             track );
 }
 
                             track );
 }
 
-static void trw_layer_geotagging_waypoint ( gpointer pass_along[6] )
+static void trw_layer_geotagging_waypoint ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  VikWaypoint *wpt = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikWaypoint *wpt = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
 
   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                             vtl,
 
   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                             vtl,
@@ -3394,9 +3486,9 @@ static void trw_layer_geotagging_waypoint ( gpointer pass_along[6] )
                             NULL );
 }
 
                             NULL );
 }
 
-static void trw_layer_geotagging ( gpointer lav[2] )
+static void trw_layer_geotagging ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   // Unset so can be reverified later if necessary
   vtl->has_verified_thumbnails = FALSE;
 
   // Unset so can be reverified later if necessary
   vtl->has_verified_thumbnails = FALSE;
 
@@ -3409,10 +3501,10 @@ static void trw_layer_geotagging ( gpointer lav[2] )
 
 // 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
 
 
 // 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
 
-static void trw_layer_acquire ( gpointer lav[2], VikDataSourceInterface *datasource )
+static void trw_layer_acquire ( menu_array_layer values, VikDataSourceInterface *datasource )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
@@ -3422,44 +3514,44 @@ static void trw_layer_acquire ( gpointer lav[2], VikDataSourceInterface *datasou
 /*
  * Acquire into this TRW Layer straight from GPS Device
  */
 /*
  * Acquire into this TRW Layer straight from GPS Device
  */
-static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
+static void trw_layer_acquire_gps_cb ( menu_array_layer values )
 {
   vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
 {
   vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
-  trw_layer_acquire ( lav, &vik_datasource_gps_interface );
+  trw_layer_acquire ( values, &vik_datasource_gps_interface );
 }
 
 /*
  * Acquire into this TRW Layer from Directions
  */
 }
 
 /*
  * Acquire into this TRW Layer from Directions
  */
-static void trw_layer_acquire_routing_cb ( gpointer lav[2] )
+static void trw_layer_acquire_routing_cb ( menu_array_layer values )
 {
 {
-  trw_layer_acquire ( lav, &vik_datasource_routing_interface );
+  trw_layer_acquire ( values, &vik_datasource_routing_interface );
 }
 
 /*
  * Acquire into this TRW Layer from an entered URL
  */
 }
 
 /*
  * Acquire into this TRW Layer from an entered URL
  */
-static void trw_layer_acquire_url_cb ( gpointer lav[2] )
+static void trw_layer_acquire_url_cb ( menu_array_layer values )
 {
   vik_datasource_url_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
 {
   vik_datasource_url_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
-  trw_layer_acquire ( lav, &vik_datasource_url_interface );
+  trw_layer_acquire ( values, &vik_datasource_url_interface );
 }
 
 #ifdef VIK_CONFIG_OPENSTREETMAP
 /*
  * Acquire into this TRW Layer from OSM
  */
 }
 
 #ifdef VIK_CONFIG_OPENSTREETMAP
 /*
  * Acquire into this TRW Layer from OSM
  */
-static void trw_layer_acquire_osm_cb ( gpointer lav[2] )
+static void trw_layer_acquire_osm_cb ( menu_array_layer values )
 {
 {
-  trw_layer_acquire ( lav, &vik_datasource_osm_interface );
+  trw_layer_acquire ( values, &vik_datasource_osm_interface );
 }
 
 /**
  * Acquire into this TRW Layer from OSM for 'My' Traces
  */
 }
 
 /**
  * Acquire into this TRW Layer from OSM for 'My' Traces
  */
-static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] )
+static void trw_layer_acquire_osm_my_traces_cb ( menu_array_layer values )
 {
 {
-  trw_layer_acquire ( lav, &vik_datasource_osm_my_traces_interface );
+  trw_layer_acquire ( values, &vik_datasource_osm_my_traces_interface );
 }
 #endif
 
 }
 #endif
 
@@ -3467,9 +3559,9 @@ static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] )
 /*
  * Acquire into this TRW Layer from Geocaching.com
  */
 /*
  * Acquire into this TRW Layer from Geocaching.com
  */
-static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
+static void trw_layer_acquire_geocache_cb ( menu_array_layer values )
 {
 {
-  trw_layer_acquire ( lav, &vik_datasource_gc_interface );
+  trw_layer_acquire ( values, &vik_datasource_gc_interface );
 }
 #endif
 
 }
 #endif
 
@@ -3477,12 +3569,12 @@ static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
 /*
  * Acquire into this TRW Layer from images
  */
 /*
  * Acquire into this TRW Layer from images
  */
-static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
+static void trw_layer_acquire_geotagged_cb ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
   vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
 
   vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
-  trw_layer_acquire ( lav, &vik_datasource_geotag_interface );
+  trw_layer_acquire ( values, &vik_datasource_geotag_interface );
 
   // Reverify thumbnails as they may have changed
   vtl->has_verified_thumbnails = FALSE;
 
   // Reverify thumbnails as they may have changed
   vtl->has_verified_thumbnails = FALSE;
@@ -3490,50 +3582,49 @@ static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
 }
 #endif
 
 }
 #endif
 
-static void trw_layer_gps_upload ( gpointer lav[2] )
+static void trw_layer_gps_upload ( menu_array_layer values )
 {
 {
-  gpointer pass_along[6];
-  pass_along[0] = lav[0];
-  pass_along[1] = lav[1];
-  pass_along[2] = NULL; // No track - operate on the layer
-  pass_along[3] = NULL;
-  pass_along[4] = NULL;
-  pass_along[5] = NULL;
+  menu_array_sublayer data;
+  gint ii;
+  for ( ii = MA_VTL; ii < MA_LAST; ii++ )
+    data[ii] = NULL;
+  data[MA_VTL] = values[MA_VTL];
+  data[MA_VLP] = values[MA_VLP];
 
 
-  trw_layer_gps_upload_any ( pass_along );
+  trw_layer_gps_upload_any ( data );
 }
 
 /**
  * If pass_along[3] is defined that this will upload just that track
  */
 }
 
 /**
  * If pass_along[3] is defined that this will upload just that track
  */
-static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
+static void trw_layer_gps_upload_any ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(pass_along[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
 
 
-  // May not actually get a track here as pass_along[2&3] can be null
+  // May not actually get a track here as values[2&3] can be null
   VikTrack *track = NULL;
   vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
   gboolean xfer_all = FALSE;
 
   VikTrack *track = NULL;
   vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
   gboolean xfer_all = FALSE;
 
-  if ( pass_along[2] ) {
+  if ( values[MA_SUBTYPE] ) {
     xfer_all = FALSE;
     xfer_all = FALSE;
-    if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
-      track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+    if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
+      track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
       xfer_type = RTE;
     }
       xfer_type = RTE;
     }
-    else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
-      track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+      track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
       xfer_type = TRK;
     }
       xfer_type = TRK;
     }
-    else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) {
+    else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) {
       xfer_type = WPT;
     }
       xfer_type = WPT;
     }
-    else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
+    else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
       xfer_type = RTE;
     }
   }
       xfer_type = RTE;
     }
   }
-  else if ( !pass_along[4] )
+  else if ( !values[MA_CONFIRM] )
     xfer_all = TRUE; // i.e. whole layer
 
   if (track && !track->visible) {
     xfer_all = TRUE; // i.e. whole layer
 
   if (track && !track->visible) {
@@ -3542,7 +3633,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
   }
 
   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
   }
 
   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
-                                                    VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
+                                                    VIK_GTK_WINDOW_FROM_LAYER(vtl),
                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                                     GTK_STOCK_OK,
                                                     GTK_RESPONSE_ACCEPT,
                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                                     GTK_STOCK_OK,
                                                     GTK_RESPONSE_ACCEPT,
@@ -3601,20 +3692,20 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
 /*
  * Acquire into this TRW Layer from any GPS Babel supported file
  */
 /*
  * Acquire into this TRW Layer from any GPS Babel supported file
  */
-static void trw_layer_acquire_file_cb ( gpointer lav[2] )
+static void trw_layer_acquire_file_cb ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
   a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL );
 }
 
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
   a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL );
 }
 
-static void trw_layer_new_wp ( gpointer lav[2] )
+static void trw_layer_new_wp ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
      instead return true if you want to update. */
   if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) {
   /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
      instead return true if you want to update. */
   if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) {
@@ -3637,9 +3728,9 @@ static void new_track_create_common ( VikTrwLayer *vtl, gchar *name )
   vik_trw_layer_add_track ( vtl, name, vtl->current_track );
 }
 
   vik_trw_layer_add_track ( vtl, name, vtl->current_track );
 }
 
-static void trw_layer_new_track ( gpointer lav[2] )
+static void trw_layer_new_track ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
   if ( ! vtl->current_track ) {
     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ;
 
   if ( ! vtl->current_track ) {
     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ;
@@ -3662,9 +3753,9 @@ static void new_route_create_common ( VikTrwLayer *vtl, gchar *name )
   vik_trw_layer_add_route ( vtl, name, vtl->current_track );
 }
 
   vik_trw_layer_add_route ( vtl, name, vtl->current_track );
 }
 
-static void trw_layer_new_route ( gpointer lav[2] )
+static void trw_layer_new_route ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
   if ( ! vtl->current_track ) {
     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ;
 
   if ( ! vtl->current_track ) {
     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ;
@@ -3674,10 +3765,10 @@ static void trw_layer_new_route ( gpointer lav[2] )
   }
 }
 
   }
 }
 
-static void trw_layer_auto_routes_view ( gpointer lav[2] )
+static void trw_layer_auto_routes_view ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
 
   if ( g_hash_table_size (vtl->routes) > 0 ) {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
 
   if ( g_hash_table_size (vtl->routes) > 0 ) {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
@@ -3688,17 +3779,17 @@ static void trw_layer_auto_routes_view ( gpointer lav[2] )
 }
 
 
 }
 
 
-static void trw_layer_finish_track ( gpointer lav[2] )
+static void trw_layer_finish_track ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   vtl->current_track = NULL;
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
   vtl->current_track = NULL;
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
-static void trw_layer_auto_tracks_view ( gpointer lav[2] )
+static void trw_layer_auto_tracks_view ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
 
   if ( g_hash_table_size (vtl->tracks) > 0 ) {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
 
   if ( g_hash_table_size (vtl->tracks) > 0 ) {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
@@ -3714,10 +3805,10 @@ static void trw_layer_single_waypoint_jump ( const gpointer id, const VikWaypoin
   vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
 }
 
   vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
 }
 
-static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
+static void trw_layer_auto_waypoints_view ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
 
   /* Only 1 waypoint - jump straight to it */
   if ( g_hash_table_size (vtl->waypoints) == 1 ) {
 
   /* Only 1 waypoint - jump straight to it */
   if ( g_hash_table_size (vtl->waypoints) == 1 ) {
@@ -3738,26 +3829,26 @@ static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
   vik_layers_panel_emit_update ( vlp );
 }
 
   vik_layers_panel_emit_update ( vlp );
 }
 
-void trw_layer_osm_traces_upload_cb ( gpointer layer_and_vlp[2] )
+void trw_layer_osm_traces_upload_cb ( menu_array_layer values )
 {
 {
-  osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(layer_and_vlp[0]), NULL);
+  osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), NULL);
 }
 
 }
 
-void trw_layer_osm_traces_upload_track_cb ( gpointer pass_along[8] )
+void trw_layer_osm_traces_upload_track_cb ( menu_array_sublayer values )
 {
 {
-  if ( pass_along[7] ) {
-    VikTrack *trk = VIK_TRACK(pass_along[7]);
-    osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(pass_along[0]), trk);
+  if ( values[MA_MISC] ) {
+    VikTrack *trk = VIK_TRACK(values[MA_MISC]);
+    osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), trk);
   }
 }
 
 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
 {
   }
 }
 
 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
 {
-  static gpointer pass_along[2];
+  static menu_array_layer pass_along;
   GtkWidget *item;
   GtkWidget *export_submenu;
   GtkWidget *item;
   GtkWidget *export_submenu;
-  pass_along[0] = vtl;
-  pass_along[1] = vlp;
+  pass_along[MA_VTL] = vtl;
+  pass_along[MA_VLP] = vlp;
 
   item = gtk_menu_item_new();
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
 
   item = gtk_menu_item_new();
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
@@ -4656,9 +4747,9 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
-static void trw_layer_delete_all_tracks ( gpointer lav[2] )
+static void trw_layer_delete_all_tracks ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   // Get confirmation from the user
   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                            _("Are you sure you want to delete all tracks in %s?"),
   // Get confirmation from the user
   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                            _("Are you sure you want to delete all tracks in %s?"),
@@ -4666,9 +4757,9 @@ static void trw_layer_delete_all_tracks ( gpointer lav[2] )
     vik_trw_layer_delete_all_tracks (vtl);
 }
 
     vik_trw_layer_delete_all_tracks (vtl);
 }
 
-static void trw_layer_delete_all_routes ( gpointer lav[2] )
+static void trw_layer_delete_all_routes ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   // Get confirmation from the user
   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                             _("Are you sure you want to delete all routes in %s?"),
   // Get confirmation from the user
   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                             _("Are you sure you want to delete all routes in %s?"),
@@ -4676,9 +4767,9 @@ static void trw_layer_delete_all_routes ( gpointer lav[2] )
     vik_trw_layer_delete_all_routes (vtl);
 }
 
     vik_trw_layer_delete_all_routes (vtl);
 }
 
-static void trw_layer_delete_all_waypoints ( gpointer lav[2] )
+static void trw_layer_delete_all_waypoints ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   // Get confirmation from the user
   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                            _("Are you sure you want to delete all waypoints in %s?"),
   // Get confirmation from the user
   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                            _("Are you sure you want to delete all waypoints in %s?"),
@@ -4686,15 +4777,15 @@ static void trw_layer_delete_all_waypoints ( gpointer lav[2] )
     vik_trw_layer_delete_all_waypoints (vtl);
 }
 
     vik_trw_layer_delete_all_waypoints (vtl);
 }
 
-static void trw_layer_delete_item ( gpointer pass_along[6] )
+static void trw_layer_delete_item ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gboolean was_visible = FALSE;
   gboolean was_visible = FALSE;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
   {
-    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
     if ( wp && wp->name ) {
     if ( wp && wp->name ) {
-      if ( GPOINTER_TO_INT ( pass_along[4]) )
+      if ( GPOINTER_TO_INT (values[MA_CONFIRM]) )
         // 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),
@@ -4704,11 +4795,11 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
       was_visible = trw_layer_delete_waypoint ( vtl, wp );
     }
   }
       was_visible = trw_layer_delete_waypoint ( vtl, wp );
     }
   }
-  else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
+  else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
   {
   {
-    VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    VikTrack *trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
     if ( trk && trk->name ) {
     if ( trk && trk->name ) {
-      if ( GPOINTER_TO_INT ( pass_along[4]) )
+      if ( GPOINTER_TO_INT (values[MA_CONFIRM]) )
         // 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\"?"),
         // 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\"?"),
@@ -4719,9 +4810,9 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
   }
   else
   {
   }
   else
   {
-    VikTrack *trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
+    VikTrack *trk = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
     if ( trk && trk->name ) {
     if ( trk && trk->name ) {
-      if ( GPOINTER_TO_INT ( pass_along[4]) )
+      if ( GPOINTER_TO_INT (values[MA_CONFIRM]) )
         // 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\"?"),
         // 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\"?"),
@@ -4781,12 +4872,12 @@ void trw_layer_waypoint_reset_icon ( VikTrwLayer *vtl, VikWaypoint *wp )
   }
 }
 
   }
 }
 
-static void trw_layer_properties_item ( gpointer pass_along[7] )
+static void trw_layer_properties_item ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
   {
   {
-    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); // sublayer
+    VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
 
     if ( wp && wp->name )
     {
 
     if ( wp && wp->name )
     {
@@ -4795,8 +4886,8 @@ static void trw_layer_properties_item ( gpointer pass_along[7] )
       if ( new_name )
         trw_layer_waypoint_rename ( vtl, wp, new_name );
 
       if ( new_name )
         trw_layer_waypoint_rename ( vtl, wp, new_name );
 
-      if ( updated && pass_along[6] )
-        vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) );
+      if ( updated && values[MA_TV_ITER] )
+        vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, values[MA_TV_ITER], get_wp_sym_small (wp->symbol) );
 
       if ( updated && VIK_LAYER(vtl)->visible )
        vik_layer_emit_update ( VIK_LAYER(vtl) );
 
       if ( updated && VIK_LAYER(vtl)->visible )
        vik_layer_emit_update ( VIK_LAYER(vtl) );
@@ -4805,18 +4896,18 @@ static void trw_layer_properties_item ( gpointer pass_along[7] )
   else
   {
     VikTrack *tr;
   else
   {
     VikTrack *tr;
-    if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
-      tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
+      tr = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
     else
     else
-      tr = g_hash_table_lookup ( vtl->routes, pass_along[3] );
+      tr = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
 
     if ( tr && tr->name )
     {
       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
 
     if ( tr && tr->name )
     {
       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                                 vtl,
+                                  vtl,
                                   tr,
                                   tr,
-                                 pass_along[1], /* vlp */
-                                 pass_along[5], /* vvp */
+                                  values[MA_VLP],
+                                  values[MA_VVP],
                                   FALSE );
     }
   }
                                   FALSE );
     }
   }
@@ -4829,21 +4920,21 @@ static void trw_layer_properties_item ( gpointer pass_along[7] )
  * ATM jump to the stats page in the properties
  * TODO: consider separating the stats into an individual dialog?
  */
  * 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] )
+static void trw_layer_track_statistics ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikTrack *trk;
   VikTrack *trk;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
-    trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
+    trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
+    trk = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
 
   if ( trk && trk->name ) {
     vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                                 vtl,
                                 trk,
 
   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
+                                values[MA_VLP],
+                                values[MA_VVP],
                                 TRUE );
   }
 }
                                 TRUE );
   }
 }
@@ -4905,27 +4996,27 @@ static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoor
   }
 }
 
   }
 }
 
-static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] )
+static void trw_layer_goto_track_startpoint ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( track && track->trackpoints )
 
   if ( track && track->trackpoints )
-    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) track->trackpoints->data)->coord) );
+    goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_first(track)->coord) );
 }
 
 }
 
-static void trw_layer_goto_track_center ( gpointer pass_along[6] )
+static void trw_layer_goto_track_center ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( track && track->trackpoints )
   {
 
   if ( track && track->trackpoints )
   {
@@ -4935,18 +5026,18 @@ static void trw_layer_goto_track_center ( gpointer pass_along[6] )
     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
     vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
     vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
-    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord);
+    goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &coord);
   }
 }
 
   }
 }
 
-static void trw_layer_convert_track_route ( gpointer pass_along[6] )
+static void trw_layer_convert_track_route ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -4987,30 +5078,30 @@ static void trw_layer_convert_track_route ( gpointer pass_along[6] )
   g_free ( name );
 
   // Update in case color of track / route changes when moving between sublayers
   g_free ( name );
 
   // Update in case color of track / route changes when moving between sublayers
-  vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
 }
 
-static void trw_layer_anonymize_times ( gpointer pass_along[6] )
+static void trw_layer_anonymize_times ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( track )
     vik_track_anonymize_times ( track );
 }
 
 
   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 ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5019,30 +5110,27 @@ static void trw_layer_extend_track_end ( gpointer pass_along[6] )
   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, track->is_route ? TOOL_CREATE_ROUTE : TOOL_CREATE_TRACK);
 
   if ( track->trackpoints )
   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, track->is_route ? TOOL_CREATE_ROUTE : TOOL_CREATE_TRACK);
 
   if ( track->trackpoints )
-    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
+    goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_last(track)->coord) );
 }
 
 /**
  * extend a track using route finder
  */
 }
 
 /**
  * extend a track using route finder
  */
-static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
+static void trw_layer_extend_track_end_route_finder ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
-  VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikTrack *track = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   if ( !track )
     return;
   if ( !track->trackpoints )
     return;
   if ( !track )
     return;
   if ( !track->trackpoints )
     return;
-  VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord);
 
   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER );
 
   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER );
-  vtl->route_finder_coord =  last_coord;
+  vtl->route_finder_coord = vik_track_get_tp_last(track)->coord;
   vtl->route_finder_current_track = track;
   vtl->route_finder_started = TRUE;
 
   vtl->route_finder_current_track = track;
   vtl->route_finder_started = TRUE;
 
-  if ( track->trackpoints )
-    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
-
+  goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &vtl->route_finder_coord );
 }
 
 /**
 }
 
 /**
@@ -5080,30 +5168,30 @@ static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTr
   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
 }
 
   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
 }
 
-static void trw_layer_apply_dem_data_all ( gpointer pass_along[6] )
+static void trw_layer_apply_dem_data_all ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( track )
 
   if ( track )
-    apply_dem_data_common ( vtl, pass_along[1], track, FALSE );
+    apply_dem_data_common ( vtl, values[MA_VLP], track, FALSE );
 }
 
 }
 
-static void trw_layer_apply_dem_data_only_missing ( gpointer pass_along[6] )
+static void trw_layer_apply_dem_data_only_missing ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( track )
 
   if ( track )
-    apply_dem_data_common ( vtl, pass_along[1], track, TRUE );
+    apply_dem_data_common ( vtl, values[MA_VLP], track, TRUE );
 }
 
 /**
 }
 
 /**
@@ -5124,14 +5212,14 @@ static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] )
+static void trw_layer_missing_elevation_data_interp ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5139,14 +5227,14 @@ static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] )
   smooth_it ( vtl, track, FALSE );
 }
 
   smooth_it ( vtl, track, FALSE );
 }
 
-static void trw_layer_missing_elevation_data_flat ( gpointer pass_along[6] )
+static void trw_layer_missing_elevation_data_flat ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5165,18 +5253,18 @@ static void wp_changed_message ( VikTrwLayer *vtl, gint changed )
   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
 }
 
   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
 }
 
-static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] )
+static void trw_layer_apply_dem_data_wpt_all ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  VikLayersPanel *vlp = (VikLayersPanel *)values[MA_VLP];
 
   if ( !trw_layer_dem_test ( vtl, vlp ) )
     return;
 
   gint changed = 0;
 
   if ( !trw_layer_dem_test ( vtl, vlp ) )
     return;
 
   gint changed = 0;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
     // Single Waypoint
     // Single Waypoint
-    VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+    VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
     if ( wp )
       changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
   }
     if ( wp )
       changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
   }
@@ -5194,18 +5282,18 @@ static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] )
   wp_changed_message ( vtl, changed );
 }
 
   wp_changed_message ( vtl, changed );
 }
 
-static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] )
+static void trw_layer_apply_dem_data_wpt_only_missing ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  VikLayersPanel *vlp = (VikLayersPanel *)values[MA_VLP];
 
   if ( !trw_layer_dem_test ( vtl, vlp ) )
     return;
 
   gint changed = 0;
 
   if ( !trw_layer_dem_test ( vtl, vlp ) )
     return;
 
   gint changed = 0;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
     // Single Waypoint
     // Single Waypoint
-    VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+    VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
     if ( wp )
       changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
   }
     if ( wp )
       changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
   }
@@ -5223,33 +5311,30 @@ static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] )
   wp_changed_message ( vtl, changed );
 }
 
   wp_changed_message ( vtl, changed );
 }
 
-static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
+static void trw_layer_goto_track_endpoint ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
-
-  GList *trps = track->trackpoints;
-  if ( !trps )
+  if ( !track->trackpoints )
     return;
     return;
-  trps = g_list_last(trps);
-  goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
+  goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_last(track)->coord));
 }
 
 }
 
-static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
+static void trw_layer_goto_track_max_speed ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5257,17 +5342,17 @@ static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
   VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track );
   if ( !vtp )
     return;
   VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track );
   if ( !vtp )
     return;
-  goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
+  goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord));
 }
 
 }
 
-static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
+static void trw_layer_goto_track_max_alt ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5275,17 +5360,17 @@ static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
   VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track );
   if ( !vtp )
     return;
   VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track );
   if ( !vtp )
     return;
-  goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
+  goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord));
 }
 
 }
 
-static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
+static void trw_layer_goto_track_min_alt ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5293,28 +5378,28 @@ static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
   VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track );
   if ( !vtp )
     return;
   VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track );
   if ( !vtp )
     return;
-  goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
+  goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord));
 }
 
 /*
  * Automatically change the viewport to center on the track and zoom to see the extent of the track
  */
 }
 
 /*
  * Automatically change the viewport to center on the track and zoom to see the extent of the track
  */
-static void trw_layer_auto_track_view ( gpointer pass_along[6] )
+static void trw_layer_auto_track_view ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( trk && trk->trackpoints )
   {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
     trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
 
   if ( trk && trk->trackpoints )
   {
     struct LatLon maxmin[2] = { {0,0}, {0,0} };
     trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
-    trw_layer_zoom_to_show_latlons ( vtl, pass_along[5], maxmin );
-    if ( pass_along[1] )
-      vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
+    trw_layer_zoom_to_show_latlons ( vtl, values[MA_VVP], maxmin );
+    if ( values[MA_VLP] )
+      vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(values[MA_VLP]) );
     else
       vik_layer_emit_update ( VIK_LAYER(vtl) );
   }
     else
       vik_layer_emit_update ( VIK_LAYER(vtl) );
   }
@@ -5324,16 +5409,16 @@ 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.
  */
  * 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 void trw_layer_route_refine ( menu_array_sublayer values )
 {
   static gint last_engine = 0;
 {
   static gint last_engine = 0;
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikTrack *trk;
 
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( trk && trk->trackpoints )
   {
 
   if ( trk && trk->trackpoints )
   {
@@ -5380,7 +5465,7 @@ static void trw_layer_route_refine ( gpointer pass_along[6] )
         VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine);
 
         /* Change cursor */
         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])) );
+        vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
 
         /* Force saving track */
         /* FIXME: remove or rename this hack */
 
         /* Force saving track */
         /* FIXME: remove or rename this hack */
@@ -5399,15 +5484,15 @@ static void trw_layer_route_refine ( gpointer pass_along[6] )
         vik_layer_emit_update ( VIK_LAYER(vtl) );
 
         /* Restore cursor */
         vik_layer_emit_update ( VIK_LAYER(vtl) );
 
         /* Restore cursor */
-        vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
+        vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
     }
     gtk_widget_destroy ( dialog );
   }
 }
 
     }
     gtk_widget_destroy ( dialog );
   }
 }
 
-static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
+static void trw_layer_edit_trackpoint ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   trw_layer_tpwin_init ( vtl );
 }
 
   trw_layer_tpwin_init ( vtl );
 }
 
@@ -5430,14 +5515,14 @@ static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpoint
 {
   twt_udata *user_data = udata;
   VikTrackpoint *p1, *p2;
 {
   twt_udata *user_data = udata;
   VikTrackpoint *p1, *p2;
-
-  if (VIK_TRACK(value)->trackpoints == user_data->exclude) {
+  VikTrack *trk = VIK_TRACK(value);
+  if (trk == (VikTrack *)user_data->exclude) {
     return;
   }
 
     return;
   }
 
-  if (VIK_TRACK(value)->trackpoints) {
-    p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
-    p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+  if (trk->trackpoints) {
+    p1 = vik_track_get_tp_first(trk);
+    p2 = vik_track_get_tp_last(trk);
 
     if ( user_data->with_timestamps ) {
       if (!p1->has_timestamp || !p2->has_timestamp) {
 
     if ( user_data->with_timestamps ) {
       if (!p1->has_timestamp || !p2->has_timestamp) {
@@ -5477,12 +5562,12 @@ static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer u
     return;
   }
 
     return;
   }
 
-  t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp;
-  t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp;
+  t1 = vik_track_get_tp_first(trk)->timestamp;
+  t2 = vik_track_get_tp_last(trk)->timestamp;
 
   if (trk->trackpoints) {
 
   if (trk->trackpoints) {
-    p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data);
-    p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data);
+    p1 = vik_track_get_tp_first(trk);
+    p2 = vik_track_get_tp_last(trk);
 
     if (!p1->has_timestamp || !p2->has_timestamp) {
       //g_print("no timestamp\n");
 
     if (!p1->has_timestamp || !p2->has_timestamp) {
       //g_print("no timestamp\n");
@@ -5548,17 +5633,17 @@ static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user
  * Tracks to merge with must be of the same 'type' as the selected track -
  *  either all with timestamps, or all without timestamps
  */
  * Tracks to merge with must be of the same 'type' as the selected track -
  *  either all with timestamps, or all without timestamps
  */
-static void trw_layer_merge_with_other ( gpointer pass_along[6] )
+static void trw_layer_merge_with_other ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   GList *other_tracks = NULL;
   GHashTable *ght_tracks;
   GList *other_tracks = NULL;
   GHashTable *ght_tracks;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
     ght_tracks = vtl->routes;
   else
     ght_tracks = vtl->tracks;
 
     ght_tracks = vtl->routes;
   else
     ght_tracks = vtl->tracks;
 
-  VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -5571,7 +5656,7 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] )
   udata.exclude = track->trackpoints;
   // Allow merging with 'similar' time type time tracks
   // i.e. either those times, or those without
   udata.exclude = track->trackpoints;
   // Allow merging with 'similar' time type time tracks
   // i.e. either those times, or those without
-  udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp);
+  udata.with_timestamps = vik_track_get_tp_first(track)->has_timestamp;
 
   g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
   other_tracks = g_list_reverse(other_tracks);
 
   g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
   other_tracks = g_list_reverse(other_tracks);
@@ -5651,18 +5736,18 @@ static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer
  *  i.e. doesn't care about whether tracks have consistent timestamps
  * ATM can only append one track at a time to the currently selected track
  */
  *  i.e. doesn't care about whether tracks have consistent timestamps
  * ATM can only append one track at a time to the currently selected track
  */
-static void trw_layer_append_track ( gpointer pass_along[6] )
+static void trw_layer_append_track ( menu_array_sublayer values )
 {
 
 {
 
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *trk;
   GHashTable *ght_tracks;
   VikTrack *trk;
   GHashTable *ght_tracks;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
     ght_tracks = vtl->routes;
   else
     ght_tracks = vtl->tracks;
 
     ght_tracks = vtl->routes;
   else
     ght_tracks = vtl->tracks;
 
-  trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
+  trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -5724,13 +5809,13 @@ static void trw_layer_append_track ( gpointer pass_along[6] )
  * If a track is selected, then is shows routes and joins the selected one
  * If a route is selected, then is shows tracks and joins the selected one
  */
  * If a track is selected, then is shows routes and joins the selected one
  * If a route is selected, then is shows tracks and joins the selected one
  */
-static void trw_layer_append_other ( gpointer pass_along[6] )
+static void trw_layer_append_other ( menu_array_sublayer values )
 {
 
 {
 
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *trk;
   GHashTable *ght_mykind, *ght_others;
   VikTrack *trk;
   GHashTable *ght_mykind, *ght_others;
-  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
     ght_mykind = vtl->routes;
     ght_others = vtl->tracks;
   }
     ght_mykind = vtl->routes;
     ght_others = vtl->tracks;
   }
@@ -5739,7 +5824,7 @@ static void trw_layer_append_other ( gpointer pass_along[6] )
     ght_others = vtl->routes;
   }
 
     ght_others = vtl->routes;
   }
 
-  trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, pass_along[3] );
+  trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -5814,10 +5899,10 @@ static void trw_layer_append_other ( gpointer pass_along[6] )
 }
 
 /* merge by segments */
 }
 
 /* merge by segments */
-static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
+static void trw_layer_merge_by_segment ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
   guint segments = vik_track_merge_segments ( trk );
   // NB currently no need to redraw as segments not actually shown on the display
   // However inform the user of what happened:
   guint segments = vik_track_merge_segments ( trk );
   // NB currently no need to redraw as segments not actually shown on the display
   // However inform the user of what happened:
@@ -5828,16 +5913,16 @@ static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
 }
 
 /* merge by time routine */
 }
 
 /* merge by time routine */
-static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
+static void trw_layer_merge_by_timestamp ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
 
   //time_t t1, t2;
 
   GList *tracks_with_timestamp = NULL;
 
   //time_t t1, t2;
 
   GList *tracks_with_timestamp = NULL;
-  VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
   if (orig_trk->trackpoints &&
   if (orig_trk->trackpoints &&
-      !VIK_TRACKPOINT(orig_trk->trackpoints->data)->has_timestamp) {
+      !vik_track_get_tp_first(orig_trk)->has_timestamp) {
     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
     return;
   }
     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
     return;
   }
@@ -5883,10 +5968,6 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
       nearby_tracks = NULL;
     }
 
       nearby_tracks = NULL;
     }
 
-    //t1 = ((VikTrackpoint *)trps->data)->timestamp;
-    //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
-    
-    /*    g_print("Original track times: %d and %d\n", t1, t2);  */
     params[0] = &nearby_tracks;
     params[1] = (gpointer)trps;
     params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
     params[0] = &nearby_tracks;
     params[1] = (gpointer)trps;
     params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
@@ -5897,17 +5978,6 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
     /* merge them */
     GList *l = nearby_tracks;
     while ( l ) {
     /* merge them */
     GList *l = nearby_tracks;
     while ( l ) {
-       /*
-#define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data)
-#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data)
-        time_t t1, t2;
-        t1 = get_first_trackpoint(l)->timestamp;
-        t2 = get_last_trackpoint(l)->timestamp;
-#undef get_first_trackpoint
-#undef get_last_trackpoint
-        g_print("     %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2);
-       */
-
       /* remove trackpoints from merged track, delete track */
       vik_track_steal_and_append_trackpoints ( orig_trk, VIK_TRACK(l->data) );
       vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
       /* remove trackpoints from merged track, delete track */
       vik_track_steal_and_append_trackpoints ( orig_trk, VIK_TRACK(l->data) );
       vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
@@ -5984,10 +6054,10 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subt
 }
 
 /* split by time routine */
 }
 
 /* split by time routine */
-static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
+static void trw_layer_split_by_timestamp ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
   GList *trps = track->trackpoints;
   GList *iter;
   GList *newlists = NULL;
   GList *trps = track->trackpoints;
   GList *iter;
   GList *newlists = NULL;
@@ -5999,7 +6069,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
   if ( !trps )
     return;
 
   if ( !trps )
     return;
 
-  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
+  if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl), 
                               _("Split Threshold..."), 
                               _("Split when time between trackpoints exceeds:"), 
                               &thr)) {
                               _("Split Threshold..."), 
                               _("Split when time between trackpoints exceeds:"), 
                               &thr)) {
@@ -6020,7 +6090,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
       if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                                 _("Can not split track due to trackpoints not ordered in time - such as at %s.\n\nGoto this trackpoint?"),
                                 tmp_str ) ) {
       if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                                 _("Can not split track due to trackpoints not ordered in time - such as at %s.\n\nGoto this trackpoint?"),
                                 tmp_str ) ) {
-       goto_coord ( pass_along[1], vtl, pass_along[5], &(VIK_TRACKPOINT(iter->data)->coord) );
+        goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(VIK_TRACKPOINT(iter->data)->coord) );
       }
       return;
     }
       }
       return;
     }
@@ -6053,15 +6123,13 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
 
       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
       vik_trw_layer_add_track(vtl, new_tr_name, tr);
 
       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
       vik_trw_layer_add_track(vtl, new_tr_name, tr);
-      /*    g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
-         VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
       g_free ( new_tr_name );
       vik_track_calculate_bounds ( tr );
       iter = g_list_next(iter);
     }
     // Remove original track and then update the display
     vik_trw_layer_delete_track (vtl, track);
       g_free ( new_tr_name );
       vik_track_calculate_bounds ( tr );
       iter = g_list_next(iter);
     }
     // Remove original track and then update the display
     vik_trw_layer_delete_track (vtl, track);
-    vik_layer_emit_update(VIK_LAYER(pass_along[0]));
+    vik_layer_emit_update(VIK_LAYER(vtl));
   }
   g_list_free(newlists);
 }
   }
   g_list_free(newlists);
 }
@@ -6069,14 +6137,14 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
 /**
  * Split a track by the number of points as specified by the user
  */
 /**
  * Split a track by the number of points as specified by the user
  */
-static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
+static void trw_layer_split_by_n_points ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !track )
     return;
 
   if ( !track )
     return;
@@ -6086,7 +6154,7 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
   if ( !trps )
     return;
 
   if ( !trps )
     return;
 
-  gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
+  gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(vtl),
                                             _("Split Every Nth Point"),
                                             _("Split on every Nth point:"),
                                             250,   // Default value as per typical limited track capacity of various GPS devices
                                             _("Split Every Nth Point"),
                                             _("Split on every Nth point:"),
                                             250,   // Default value as per typical limited track capacity of various GPS devices
@@ -6152,7 +6220,7 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
       vik_trw_layer_delete_route (vtl, track);
     else
       vik_trw_layer_delete_track (vtl, track);
       vik_trw_layer_delete_route (vtl, track);
     else
       vik_trw_layer_delete_track (vtl, track);
-    vik_layer_emit_update(VIK_LAYER(pass_along[0]));
+    vik_layer_emit_update(VIK_LAYER(vtl));
   }
   g_list_free(newlists);
 }
   }
   g_list_free(newlists);
 }
@@ -6160,10 +6228,10 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
 /**
  * Split a track at the currently selected trackpoint
  */
 /**
  * Split a track at the currently selected trackpoint
  */
-static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
+static void trw_layer_split_at_trackpoint ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  gint subtype = GPOINTER_TO_INT (pass_along[2]);
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]);
   trw_layer_split_at_selected_trackpoint ( vtl, subtype );
 }
 
   trw_layer_split_at_selected_trackpoint ( vtl, subtype );
 }
 
@@ -6171,10 +6239,10 @@ static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
  * Split a track by its segments
  * Routes do not have segments so don't call this for routes
  */
  * Split a track by its segments
  * Routes do not have segments so don't call this for routes
  */
-static void trw_layer_split_segments ( gpointer pass_along[6] )
+static void trw_layer_split_segments ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
-  VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  VikTrack *trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -6234,14 +6302,14 @@ static void trw_layer_trackpoint_selected_delete ( VikTrwLayer *vtl, VikTrack *t
 /**
  * Delete the selected point
  */
 /**
  * Delete the selected point
  */
-static void trw_layer_delete_point_selected ( gpointer pass_along[6] )
+static void trw_layer_delete_point_selected ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -6261,14 +6329,14 @@ static void trw_layer_delete_point_selected ( gpointer pass_along[6] )
  * Delete adjacent track points at the same position
  * AKA Delete Dulplicates on the Properties Window
  */
  * Delete adjacent track points at the same position
  * AKA Delete Dulplicates on the Properties Window
  */
-static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
+static void trw_layer_delete_points_same_position ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -6291,14 +6359,14 @@ static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
  * Delete adjacent track points with the same timestamp
  * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
  */
  * Delete adjacent track points with the same timestamp
  * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
  */
-static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
+static void trw_layer_delete_points_same_time ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( !trk )
     return;
 
   if ( !trk )
     return;
@@ -6320,14 +6388,14 @@ static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
 /**
  * Insert a point
  */
 /**
  * Insert a point
  */
-static void trw_layer_insert_point_after ( gpointer pass_along[6] )
+static void trw_layer_insert_point_after ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( ! track )
     return;
 
   if ( ! track )
     return;
@@ -6337,14 +6405,14 @@ static void trw_layer_insert_point_after ( gpointer pass_along[6] )
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
-static void trw_layer_insert_point_before ( gpointer pass_along[6] )
+static void trw_layer_insert_point_before ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( ! track )
     return;
 
   if ( ! track )
     return;
@@ -6357,21 +6425,21 @@ static void trw_layer_insert_point_before ( gpointer pass_along[6] )
 /**
  * Reverse a track
  */
 /**
  * Reverse a track
  */
-static void trw_layer_reverse ( gpointer pass_along[6] )
+static void trw_layer_reverse ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
   VikTrack *track;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
 
   if ( ! track )
     return;
 
   vik_track_reverse ( track );
  
 
   if ( ! track )
     return;
 
   vik_track_reverse ( track );
  
-  vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
+  vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
 /**
 }
 
 /**
@@ -6550,12 +6618,12 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
   vik_layers_panel_emit_update ( vlp );
 }
 
   vik_layers_panel_emit_update ( vlp );
 }
 
-static void trw_layer_sort_order_a2z ( gpointer pass_along[6] )
+static void trw_layer_sort_order_a2z ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   GtkTreeIter *iter;
 
   GtkTreeIter *iter;
 
-  switch (GPOINTER_TO_INT (pass_along[2])) {
+  switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
     iter = &(vtl->tracks_iter);
     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
     iter = &(vtl->tracks_iter);
     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
@@ -6573,12 +6641,12 @@ static void trw_layer_sort_order_a2z ( gpointer pass_along[6] )
   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
 }
 
   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
 }
 
-static void trw_layer_sort_order_z2a ( gpointer pass_along[6] )
+static void trw_layer_sort_order_z2a ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   GtkTreeIter *iter;
 
   GtkTreeIter *iter;
 
-  switch (GPOINTER_TO_INT (pass_along[2])) {
+  switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
     iter = &(vtl->tracks_iter);
     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
     iter = &(vtl->tracks_iter);
     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
@@ -6599,16 +6667,16 @@ static void trw_layer_sort_order_z2a ( gpointer pass_along[6] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
+static void trw_layer_delete_tracks_from_selection ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   GList *all = NULL;
 
   // Ensure list of track names offered is unique
   if ( trw_layer_has_same_track_names ( vtl->tracks ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                              _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
   GList *all = NULL;
 
   // Ensure list of track names offered is unique
   if ( trw_layer_has_same_track_names ( vtl->tracks ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                              _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
-      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE );
+      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]), vtl->tracks, TRUE );
     }
     else
       return;
     }
     else
       return;
@@ -6646,16 +6714,16 @@ static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_delete_routes_from_selection ( gpointer lav[2] )
+static void trw_layer_delete_routes_from_selection ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   GList *all = NULL;
 
   // Ensure list of track names offered is unique
   if ( trw_layer_has_same_track_names ( vtl->routes ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
   GList *all = NULL;
 
   // Ensure list of track names offered is unique
   if ( trw_layer_has_same_track_names ( vtl->routes ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
-      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->routes, FALSE );
+      vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]), vtl->routes, FALSE );
     }
     else
       return;
     }
     else
       return;
@@ -6807,16 +6875,16 @@ static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] )
+static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   GList *all = NULL;
 
   // Ensure list of waypoint names offered is unique
   if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                              _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
   GList *all = NULL;
 
   // Ensure list of waypoint names offered is unique
   if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
                              _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
-      vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) );
+      vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]) );
     }
     else
       return;
     }
     else
       return;
@@ -6890,9 +6958,9 @@ static void trw_layer_waypoints_toggle_visibility ( gpointer id, VikWaypoint *wp
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_waypoints_visibility_off ( gpointer lav[2] )
+static void trw_layer_waypoints_visibility_off ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
@@ -6903,9 +6971,9 @@ static void trw_layer_waypoints_visibility_off ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_waypoints_visibility_on ( gpointer lav[2] )
+static void trw_layer_waypoints_visibility_on ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
@@ -6916,9 +6984,9 @@ static void trw_layer_waypoints_visibility_on ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_waypoints_visibility_toggle ( gpointer lav[2] )
+static void trw_layer_waypoints_visibility_toggle ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_toggle_visibility, NULL );
   // Redraw
   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_toggle_visibility, NULL );
   // Redraw
@@ -6944,9 +7012,9 @@ static void trw_layer_tracks_toggle_visibility ( gpointer id, VikTrack *trk )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_tracks_visibility_off ( gpointer lav[2] )
+static void trw_layer_tracks_visibility_off ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
@@ -6957,9 +7025,9 @@ static void trw_layer_tracks_visibility_off ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_tracks_visibility_on ( gpointer lav[2] )
+static void trw_layer_tracks_visibility_on ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
@@ -6970,9 +7038,9 @@ static void trw_layer_tracks_visibility_on ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] )
+static void trw_layer_tracks_visibility_toggle ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
   // Redraw
   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
   // Redraw
@@ -6982,9 +7050,9 @@ static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_routes_visibility_off ( gpointer lav[2] )
+static void trw_layer_routes_visibility_off ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
@@ -6995,9 +7063,9 @@ static void trw_layer_routes_visibility_off ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_routes_visibility_on ( gpointer lav[2] )
+static void trw_layer_routes_visibility_on ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
@@ -7008,9 +7076,9 @@ static void trw_layer_routes_visibility_on ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_routes_visibility_toggle ( gpointer lav[2] )
+static void trw_layer_routes_visibility_toggle ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
   // Redraw
   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
   // Redraw
@@ -7099,9 +7167,9 @@ static GList* trw_layer_create_track_list ( VikLayer *vl, gpointer user_data )
   return vik_trw_layer_build_track_list_t ( vtl, tracks );
 }
 
   return vik_trw_layer_build_track_list_t ( vtl, tracks );
 }
 
-static void trw_layer_tracks_stats ( gpointer lav[2] )
+static void trw_layer_tracks_stats ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   // There can only be one!
   if ( vtl->tracks_analysis_dialog )
     return;
   // There can only be one!
   if ( vtl->tracks_analysis_dialog )
     return;
@@ -7117,9 +7185,9 @@ static void trw_layer_tracks_stats ( gpointer lav[2] )
 /**
  *
  */
 /**
  *
  */
-static void trw_layer_routes_stats ( gpointer lav[2] )
+static void trw_layer_routes_stats ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   // There can only be one!
   if ( vtl->tracks_analysis_dialog )
     return;
   // There can only be one!
   if ( vtl->tracks_analysis_dialog )
     return;
@@ -7132,32 +7200,35 @@ static void trw_layer_routes_stats ( gpointer lav[2] )
                                                              trw_layer_analyse_close );
 }
 
                                                              trw_layer_analyse_close );
 }
 
-static void trw_layer_goto_waypoint ( gpointer pass_along[6] )
+static void trw_layer_goto_waypoint ( menu_array_sublayer values )
 {
 {
-  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
   if ( wp )
   if ( wp )
-    goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(wp->coord) );
+    goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(wp->coord) );
 }
 
 }
 
-static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] )
+static void trw_layer_waypoint_gc_webpage ( menu_array_sublayer values )
 {
 {
-  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
   if ( !wp )
     return;
   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", wp->name );
   if ( !wp )
     return;
   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", wp->name );
-  open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
+  open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), webpage);
   g_free ( webpage );
 }
 
   g_free ( webpage );
 }
 
-static void trw_layer_waypoint_webpage ( gpointer pass_along[6] )
+static void trw_layer_waypoint_webpage ( menu_array_sublayer values )
 {
 {
-  VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
   if ( !wp )
     return;
   if ( !strncmp(wp->comment, "http", 4) ) {
   if ( !wp )
     return;
   if ( !strncmp(wp->comment, "http", 4) ) {
-    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->comment);
+    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->comment);
   } else if ( !strncmp(wp->description, "http", 4) ) {
   } else if ( !strncmp(wp->description, "http", 4) ) {
-    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->description);
+    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->description);
   }
 }
 
   }
 }
 
@@ -7275,9 +7346,9 @@ static gboolean is_valid_geocache_name ( gchar *str )
   return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
 }
 
   return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
 }
 
-static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
+static void trw_layer_track_use_with_filter ( menu_array_sublayer values )
 {
 {
-  VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+  VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->tracks, values[MA_SUBLAYER_ID] );
   a_acquire_set_filter_track ( trk );
 }
 
   a_acquire_set_filter_track ( trk );
 }
 
@@ -7288,13 +7359,13 @@ static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_i
   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
 }
 
   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
 }
 
-static void trw_layer_google_route_webpage ( gpointer pass_along[6] )
+static void trw_layer_google_route_webpage ( menu_array_sublayer values )
 {
 {
-  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
+  VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->routes, values[MA_SUBLAYER_ID] );
   if ( tr ) {
     gchar *escaped = uri_escape ( tr->comment );
     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
   if ( tr ) {
     gchar *escaped = uri_escape ( tr->comment );
     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
-    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
+    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(values[MA_VTL])), webpage);
     g_free ( escaped );
     g_free ( webpage );
   }
     g_free ( escaped );
     g_free ( webpage );
   }
@@ -7305,18 +7376,18 @@ static void trw_layer_google_route_webpage ( gpointer pass_along[6] )
 /* viewpoint is now available instead */
 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
 {
 /* viewpoint is now available instead */
 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
 {
-  static gpointer pass_along[8];
+  static menu_array_sublayer pass_along;
   GtkWidget *item;
   gboolean rv = FALSE;
 
   GtkWidget *item;
   gboolean rv = FALSE;
 
-  pass_along[0] = l;
-  pass_along[1] = vlp;
-  pass_along[2] = GINT_TO_POINTER (subtype);
-  pass_along[3] = sublayer;
-  pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
-  pass_along[5] = vvp;
-  pass_along[6] = iter;
-  pass_along[7] = NULL; // For misc purposes - maybe track or waypoint
+  pass_along[MA_VTL]         = l;
+  pass_along[MA_VLP]         = vlp;
+  pass_along[MA_SUBTYPE]     = GINT_TO_POINTER (subtype);
+  pass_along[MA_SUBLAYER_ID] = sublayer;
+  pass_along[MA_CONFIRM]     = GINT_TO_POINTER (1); // Confirm delete request
+  pass_along[MA_VVP]         = vvp;
+  pass_along[MA_TV_ITER]     = iter;
+  pass_along[MA_MISC]        = NULL; // For misc purposes - maybe track or waypoint
 
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
   {
 
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
   {
@@ -7389,8 +7460,8 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
 
       if ( wp && wp->image )
       {
 
       if ( wp && wp->image )
       {
-       // Set up image paramater
-       pass_along[5] = wp->image;
+        // Set up image paramater
+        pass_along[MA_MISC] = wp->image;
 
         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
        gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
 
         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
        gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
@@ -8048,8 +8119,8 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
 #ifdef VIK_CONFIG_OPENSTREETMAP
     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
 #ifdef VIK_CONFIG_OPENSTREETMAP
     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
-    // Convert internal pointer into actual track for usage outside this file
-    pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer);
+    // Convert internal pointer into track
+    pass_along[MA_MISC] = g_hash_table_lookup ( l->tracks, sublayer);
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_track_cb), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_track_cb), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
@@ -8660,6 +8731,15 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
       vtl->current_wp =    wp_params.closest_wp;
       vtl->current_wp_id = wp_params.closest_wp_id;
 
       vtl->current_wp =    wp_params.closest_wp;
       vtl->current_wp_id = wp_params.closest_wp_id;
 
+      if ( event->type == GDK_2BUTTON_PRESS ) {
+        if ( vtl->current_wp->image ) {
+          menu_array_sublayer values;
+          values[MA_VTL] = vtl;
+          values[MA_MISC] = vtl->current_wp->image;
+          trw_layer_show_picture ( values );
+        }
+      }
+
       vik_layer_emit_update ( VIK_LAYER(vtl) );
 
       return TRUE;
       vik_layer_emit_update ( VIK_LAYER(vtl) );
 
       return TRUE;
@@ -8948,14 +9028,11 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
   params.y = event->y;
   params.draw_images = vtl->drawimages;
   params.closest_wp_id = NULL;
   params.y = event->y;
   params.draw_images = vtl->drawimages;
   params.closest_wp_id = NULL;
-  /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_wp = NULL;
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
   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 )
+  if ( vtl->current_wp && (vtl->current_wp == params.closest_wp) )
   {
   {
-    // how do we get here?
     marker_begin_move(t, event->x, event->y);
     marker_begin_move(t, event->x, event->y);
-    g_critical("shouldn't be here");
     return FALSE;
   }
   else if ( params.closest_wp )
     return FALSE;
   }
   else if ( params.closest_wp )
@@ -9193,8 +9270,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
 {
   /* if we haven't sync'ed yet, we don't have time to do more. */
   if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
 {
   /* if we haven't sync'ed yet, we don't have time to do more. */
   if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
-    GList *iter = g_list_last ( vtl->current_track->trackpoints );
-    VikTrackpoint *last_tpt = VIK_TRACKPOINT(iter->data);
+    VikTrackpoint *last_tpt = vik_track_get_tp_last(vtl->current_track);
 
     static GdkPixmap *pixmap = NULL;
     int w1, h1, w2, h2;
 
     static GdkPixmap *pixmap = NULL;
     int w1, h1, w2, h2;
@@ -9308,6 +9384,21 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
   return VIK_LAYER_TOOL_ACK;
 }
 
   return VIK_LAYER_TOOL_ACK;
 }
 
+// NB vtl->current_track must be valid
+static void undo_trackpoint_add ( VikTrwLayer *vtl )
+{
+  // 'undo'
+  if ( vtl->current_track->trackpoints ) {
+    // TODO rework this...
+    //vik_trackpoint_free ( vik_track_get_tp_last (vtl->current_track) );
+    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_track_calculate_bounds ( vtl->current_track );
+  }
+}
+
 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
 {
   if ( vtl->current_track && event->keyval == GDK_Escape ) {
 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
 {
   if ( vtl->current_track && event->keyval == GDK_Escape ) {
@@ -9315,16 +9406,8 @@ static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event,
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
-    /* undo */
-    if ( vtl->current_track->trackpoints )
-    {
-      GList *last = g_list_last(vtl->current_track->trackpoints);
-      g_free ( last->data );
-      vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
-    }
-
+    undo_trackpoint_add ( vtl );
     update_statusbar ( vtl );
     update_statusbar ( vtl );
-
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
@@ -9355,16 +9438,8 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton
   {
     if ( !vtl->current_track )
       return FALSE;
   {
     if ( !vtl->current_track )
       return FALSE;
-    /* 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_track_calculate_bounds ( vtl->current_track );
+    undo_trackpoint_add ( vtl );
     update_statusbar ( vtl );
     update_statusbar ( vtl );
-
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
   }
@@ -9374,10 +9449,8 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton
     /* 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 )
     {
     /* 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 */
       /* undo last, then end */
+      undo_trackpoint_add ( vtl );
       vtl->current_track = NULL;
     }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
       vtl->current_track = NULL;
     }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
@@ -9752,19 +9825,19 @@ static void tool_show_picture_wp ( const gpointer id, VikWaypoint *wp, gpointer
   }
 }
 
   }
 }
 
-static void trw_layer_show_picture ( gpointer pass_along[6] )
+static void trw_layer_show_picture ( menu_array_sublayer values )
 {
   /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
 #ifdef WINDOWS
 {
   /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
 #ifdef WINDOWS
-  ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL);
+  ShellExecute(NULL, "open", (char *) values[MA_MISC], NULL, NULL, SW_SHOWNORMAL);
 #else /* WINDOWS */
   GError *err = NULL;
 #else /* WINDOWS */
   GError *err = NULL;
-  gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
+  gchar *quoted_file = g_shell_quote ( (gchar *) values[MA_MISC] );
   gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
   g_free ( quoted_file );
   if ( ! g_spawn_command_line_async ( cmd, &err ) )
     {
   gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
   g_free ( quoted_file );
   if ( ! g_spawn_command_line_async ( cmd, &err ) )
     {
-      a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch %s to open file."), a_vik_get_image_viewer() );
+      a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(values[MA_VTL]), _("Could not launch %s to open file."), a_vik_get_image_viewer() );
       g_error_free ( err );
     }
   g_free ( cmd );
       g_error_free ( err );
     }
   g_free ( cmd );
@@ -9779,10 +9852,10 @@ static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *even
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
   if ( params[2] )
   {
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
   if ( params[2] )
   {
-    static gpointer pass_along[6];
-    pass_along[0] = vtl;
-    pass_along[5] = params[2];
-    trw_layer_show_picture ( pass_along );
+    static menu_array_sublayer values;
+    values[MA_VTL] = vtl;
+    values[MA_MISC] = params[2];
+    trw_layer_show_picture ( values );
     return TRUE; /* found a match */
   }
   else
     return TRUE; /* found a match */
   }
   else
@@ -10012,6 +10085,64 @@ static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean fro
   //  since the sorting of a treeview section is now very quick
   // NB sorting is also performed after every name change as well to maintain the list order
   trw_layer_sort_all ( vtl );
   //  since the sorting of a treeview section is now very quick
   // NB sorting is also performed after every name change as well to maintain the list order
   trw_layer_sort_all ( vtl );
+
+  // Setting metadata time if not otherwise set
+  if ( vtl->metadata ) {
+
+    gboolean need_to_set_time = TRUE;
+    if ( vtl->metadata->timestamp ) {
+      need_to_set_time = FALSE;
+      if ( !g_strcmp0(vtl->metadata->timestamp, "" ) )
+        need_to_set_time = TRUE;
+    }
+
+    if ( need_to_set_time ) {
+      // Could rewrite this as a general get first time of a TRW Layer function
+      GTimeVal timestamp;
+      timestamp.tv_usec = 0;
+      gboolean has_timestamp = FALSE;
+
+      GList *gl = NULL;
+      gl = g_hash_table_get_values ( vtl->tracks );
+      gl = g_list_sort ( gl, vik_track_compare_timestamp );
+      gl = g_list_first ( gl );
+
+      // Check times of tracks
+      if ( gl ) {
+        // Only need to check the first track as they have been sorted by time
+        VikTrack *trk = (VikTrack*)gl->data;
+        // Assume trackpoints already sorted by time
+        VikTrackpoint *tpt = vik_track_get_tp_first(trk);
+        if ( tpt && tpt->has_timestamp ) {
+          timestamp.tv_sec = tpt->timestamp;
+          has_timestamp = TRUE;
+        }
+        g_list_free ( gl );
+      }
+
+      if ( !has_timestamp ) {
+        // 'Last' resort - current time
+        // Get before waypoint tests - so that if a waypoint time value (in the past) is found it should be used
+        g_get_current_time ( &timestamp );
+
+        // Check times of waypoints
+        gl = g_hash_table_get_values ( vtl->waypoints );
+        GList *iter;
+        for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) {
+          VikWaypoint *wpt = (VikWaypoint*)iter->data;
+          if ( wpt->has_timestamp ) {
+            if ( timestamp.tv_sec > wpt->timestamp ) {
+              timestamp.tv_sec = wpt->timestamp;
+              has_timestamp = TRUE;
+            }
+          }
+        }
+        g_list_free ( gl );
+      }
+
+      vtl->metadata->timestamp = g_time_val_to_iso8601 ( &timestamp );
+    }
+  }
 }
 
 VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
 }
 
 VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
@@ -10218,7 +10349,7 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g
   }
 }
 
   }
 }
 
-static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
+static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values )
 {
   VikMapsLayer *vml;
   gint selected_map;
 {
   VikMapsLayer *vml;
   gint selected_map;
@@ -10226,13 +10357,13 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
   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;
 
   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;
 
-  VikTrwLayer *vtl = pass_along[0];
-  VikLayersPanel *vlp = pass_along[1];
+  VikTrwLayer *vtl = values[MA_VTL];
+  VikLayersPanel *vlp = values[MA_VLP];
   VikTrack *trk;
   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] );
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   else
   else
-    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+    trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
   if ( !trk )
     return;
 
   if ( !trk )
     return;
 
@@ -10355,34 +10486,32 @@ static GList* trw_layer_create_track_list_both ( VikLayer *vl, gpointer user_dat
   return vik_trw_layer_build_track_list_t ( vtl, tracks );
 }
 
   return vik_trw_layer_build_track_list_t ( vtl, tracks );
 }
 
-static void trw_layer_track_list_dialog_single ( gpointer pass_along[6] )
+static void trw_layer_track_list_dialog_single ( menu_array_sublayer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
   gchar *title = NULL;
 
   gchar *title = NULL;
-  if ( GPOINTER_TO_INT(pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
+  if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
     title = g_strdup_printf ( _("%s: Track List"), VIK_LAYER(vtl)->name );
   else
     title = g_strdup_printf ( _("%s: Route List"), VIK_LAYER(vtl)->name );
 
     title = g_strdup_printf ( _("%s: Track List"), VIK_LAYER(vtl)->name );
   else
     title = g_strdup_printf ( _("%s: Route List"), VIK_LAYER(vtl)->name );
 
-  vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), pass_along[2], trw_layer_create_track_list, FALSE );
+  vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), values[MA_SUBTYPE], trw_layer_create_track_list, FALSE );
   g_free ( title );
 }
 
   g_free ( title );
 }
 
-static void trw_layer_track_list_dialog ( gpointer lav[2] )
+static void trw_layer_track_list_dialog ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  //VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
   gchar *title = g_strdup_printf ( _("%s: Track and Route List"), VIK_LAYER(vtl)->name );
   vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_track_list_both, FALSE );
   g_free ( title );
 }
 
 
   gchar *title = g_strdup_printf ( _("%s: Track and Route List"), VIK_LAYER(vtl)->name );
   vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_track_list_both, FALSE );
   g_free ( title );
 }
 
-static void trw_layer_waypoint_list_dialog ( gpointer lav[2] )
+static void trw_layer_waypoint_list_dialog ( menu_array_layer values )
 {
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  //VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
   gchar *title = g_strdup_printf ( _("%s: Waypoint List"), VIK_LAYER(vtl)->name );
   vik_trw_layer_waypoint_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_waypoint_list, FALSE );
 
   gchar *title = g_strdup_printf ( _("%s: Waypoint List"), VIK_LAYER(vtl)->name );
   vik_trw_layer_waypoint_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_waypoint_list, FALSE );