]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Refactor: passed around map layer menu values
[andy/viking.git] / src / viktrwlayer.c
index d5c7abc8d91d96e33d5984d7e2d81e34f839a38f..aa7d08e0e356f3b79475a392f670613ff051d95e 100644 (file)
@@ -37,6 +37,7 @@
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_analysis.h"
 #include "viktrwlayer_tracklist.h"
+#include "viktrwlayer_waypointlist.h"
 #ifdef VIK_CONFIG_GEOTAG
 #include "viktrwlayer_geotag.h"
 #include "geotag_exif.h"
@@ -262,8 +263,6 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
 static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp );
 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp );
 
-static void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl );
-
 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] );
@@ -312,6 +311,7 @@ static void trw_layer_geotagging ( gpointer lav[2] );
 #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] );
 #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] );
@@ -327,6 +327,7 @@ static void trw_layer_gps_upload ( gpointer lav[2] );
 
 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] );
 
 // Specific route versions:
 //  Most track handling functions can handle operating on the route list
@@ -661,6 +662,7 @@ static void trw_layer_marshall ( VikTrwLayer *vtl, guint8 **data, gint *len );
 static VikTrwLayer *trw_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp );
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
+static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values );
 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
@@ -715,6 +717,7 @@ VikLayerInterface vik_trw_layer_interface = {
 
   (VikLayerFuncSetParam)                trw_layer_set_param,
   (VikLayerFuncGetParam)                trw_layer_get_param,
+  (VikLayerFuncChangeParam)             trw_layer_change_param,
 
   (VikLayerFuncReadFileData)            a_gpspoint_read_file,
   (VikLayerFuncWriteFileData)           a_gpspoint_write_file,
@@ -1107,6 +1110,75 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo
   return rv;
 }
 
+static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values )
+{
+  // This '-3' is to account for the first few parameters not in the properties
+  const gint OFFSET = -3;
+
+  switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
+    // Alter sensitivity of waypoint draw image related widgets according to the draw image setting.
+    case PARAM_DI: {
+      // Get new value
+      VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
+      GtkWidget **ww1 = values[UI_CHG_WIDGETS];
+      GtkWidget **ww2 = values[UI_CHG_LABELS];
+      GtkWidget *w1 = ww1[OFFSET + PARAM_IS];
+      GtkWidget *w2 = ww2[OFFSET + PARAM_IS];
+      GtkWidget *w3 = ww1[OFFSET + PARAM_IA];
+      GtkWidget *w4 = ww2[OFFSET + PARAM_IA];
+      GtkWidget *w5 = ww1[OFFSET + PARAM_ICS];
+      GtkWidget *w6 = ww2[OFFSET + PARAM_ICS];
+      if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
+      if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
+      if ( w3 ) gtk_widget_set_sensitive ( w3, vlpd.b );
+      if ( w4 ) gtk_widget_set_sensitive ( w4, vlpd.b );
+      if ( w5 ) gtk_widget_set_sensitive ( w5, vlpd.b );
+      if ( w6 ) gtk_widget_set_sensitive ( w6, vlpd.b );
+      break;
+    }
+    // Alter sensitivity of waypoint label related widgets according to the draw label setting.
+    case PARAM_DLA: {
+      // Get new value
+      VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
+      GtkWidget **ww1 = values[UI_CHG_WIDGETS];
+      GtkWidget **ww2 = values[UI_CHG_LABELS];
+      GtkWidget *w1 = ww1[OFFSET + PARAM_WPTC];
+      GtkWidget *w2 = ww2[OFFSET + PARAM_WPTC];
+      GtkWidget *w3 = ww1[OFFSET + PARAM_WPBC];
+      GtkWidget *w4 = ww2[OFFSET + PARAM_WPBC];
+      GtkWidget *w5 = ww1[OFFSET + PARAM_WPBA];
+      GtkWidget *w6 = ww2[OFFSET + PARAM_WPBA];
+      GtkWidget *w7 = ww1[OFFSET + PARAM_WPFONTSIZE];
+      GtkWidget *w8 = ww2[OFFSET + PARAM_WPFONTSIZE];
+      if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
+      if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
+      if ( w3 ) gtk_widget_set_sensitive ( w3, vlpd.b );
+      if ( w4 ) gtk_widget_set_sensitive ( w4, vlpd.b );
+      if ( w5 ) gtk_widget_set_sensitive ( w5, vlpd.b );
+      if ( w6 ) gtk_widget_set_sensitive ( w6, vlpd.b );
+      if ( w7 ) gtk_widget_set_sensitive ( w7, vlpd.b );
+      if ( w8 ) gtk_widget_set_sensitive ( w8, vlpd.b );
+      break;
+    }
+    // Alter sensitivity of all track colours according to the draw track mode.
+    case PARAM_DM: {
+      // Get new value
+      VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
+      gboolean sensitive = ( vlpd.u == DRAWMODE_ALL_SAME_COLOR );
+      GtkWidget **ww1 = values[UI_CHG_WIDGETS];
+      GtkWidget **ww2 = values[UI_CHG_LABELS];
+      GtkWidget *w1 = ww1[OFFSET + PARAM_TC];
+      GtkWidget *w2 = ww2[OFFSET + PARAM_TC];
+      if ( w1 ) gtk_widget_set_sensitive ( w1, sensitive );
+      if ( w2 ) gtk_widget_set_sensitive ( w2, sensitive );
+      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;
+  }
+}
+
 static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
 {
   guint8 *pd;
@@ -2258,7 +2330,7 @@ static VikTrwLayer* trw_layer_create ( VikViewport *vp )
 /*
  * Can accept a null symbol, and may return null value
  */
-static GdkPixbuf* get_wp_sym_small ( gchar *symbol )
+GdkPixbuf* get_wp_sym_small ( gchar *symbol )
 {
   GdkPixbuf* wp_icon = a_get_wp_sym (symbol);
   // ATM a_get_wp_sym returns a cached icon, with the size dependent on the preferences.
@@ -2648,7 +2720,7 @@ static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkp
   gboolean need2free = FALSE;
   if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
     // Otherwise use default
-    statusbar_format_code = g_strdup ( "KATDN" );
+    statusbar_format_code = g_strdup ( "KEATDN" );
     need2free = TRUE;
   }
 
@@ -3032,7 +3104,8 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, co
   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 )
+    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])) );
@@ -3040,17 +3113,6 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, co
       vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
       break;
     }
-    else
-    {
-      if ( a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
-      {
-        gtk_widget_hide ( file_selector );
-        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 )
@@ -3158,17 +3220,17 @@ static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
 
-  trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, trk, FILE_TYPE_GPX );
+  gchar *label = NULL;
+  if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    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 );
 
   g_free ( auto_save_name );
 }
 
-typedef struct {
-  VikWaypoint *wp; // input
-  gpointer uuid;   // output
-} wpu_udata;
-
-static gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata )
+gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata )
 {
   wpu_udata *user_data = udata;
   if ( wp == user_data->wp ) {
@@ -3316,9 +3378,20 @@ static void trw_layer_geotagging_track ( gpointer pass_along[6] )
   vtl->has_verified_thumbnails = FALSE;
 
   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                           vtl,
-                           track,
-                           track->name );
+                            vtl,
+                            NULL,
+                            track );
+}
+
+static void trw_layer_geotagging_waypoint ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
+  VikWaypoint *wpt = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+
+  trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+                            vtl,
+                            wpt,
+                            NULL );
 }
 
 static void trw_layer_geotagging ( gpointer lav[2] )
@@ -3328,26 +3401,31 @@ static void trw_layer_geotagging ( gpointer lav[2] )
   vtl->has_verified_thumbnails = FALSE;
 
   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
-                           vtl,
-                           NULL,
-                           NULL);
+                            vtl,
+                            NULL,
+                            NULL );
 }
 #endif
 
 // 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
 
-/*
- * Acquire into this TRW Layer straight from GPS Device
- */
-static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
+static void trw_layer_acquire ( gpointer lav[2], VikDataSourceInterface *datasource )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
+  a_acquire ( vw, vlp, vvp, datasource, NULL, NULL );
+}
+
+/*
+ * Acquire into this TRW Layer straight from GPS Device
+ */
+static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
+{
   vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
-  a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface, NULL, NULL );
+  trw_layer_acquire ( lav, &vik_datasource_gps_interface );
 }
 
 /*
@@ -3355,12 +3433,16 @@ static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
  */
 static void trw_layer_acquire_routing_cb ( gpointer lav[2] )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
-  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
-  VikViewport *vvp =  vik_window_viewport(vw);
+  trw_layer_acquire ( lav, &vik_datasource_routing_interface );
+}
 
-  a_acquire ( vw, vlp, vvp, &vik_datasource_routing_interface, NULL, NULL );
+/*
+ * Acquire into this TRW Layer from an entered URL
+ */
+static void trw_layer_acquire_url_cb ( gpointer lav[2] )
+{
+  vik_datasource_url_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
+  trw_layer_acquire ( lav, &vik_datasource_url_interface );
 }
 
 #ifdef VIK_CONFIG_OPENSTREETMAP
@@ -3369,12 +3451,7 @@ static void trw_layer_acquire_routing_cb ( gpointer lav[2] )
  */
 static void trw_layer_acquire_osm_cb ( gpointer lav[2] )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
-  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
-  VikViewport *vvp =  vik_window_viewport(vw);
-
-  a_acquire ( vw, vlp, vvp, &vik_datasource_osm_interface, NULL, NULL );
+  trw_layer_acquire ( lav, &vik_datasource_osm_interface );
 }
 
 /**
@@ -3382,12 +3459,7 @@ static void trw_layer_acquire_osm_cb ( gpointer lav[2] )
  */
 static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
-  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
-  VikViewport *vvp =  vik_window_viewport(vw);
-
-  a_acquire ( vw, vlp, vvp, &vik_datasource_osm_my_traces_interface, NULL, NULL );
+  trw_layer_acquire ( lav, &vik_datasource_osm_my_traces_interface );
 }
 #endif
 
@@ -3397,12 +3469,7 @@ static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] )
  */
 static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
-  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
-  VikViewport *vvp =  vik_window_viewport(vw);
-
-  a_acquire ( vw, vlp, vvp, &vik_datasource_gc_interface, NULL, NULL );
+  trw_layer_acquire ( lav, &vik_datasource_gc_interface );
 }
 #endif
 
@@ -3413,12 +3480,9 @@ static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
 static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
-  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
-  VikViewport *vvp =  vik_window_viewport(vw);
 
   vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
-  a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface, NULL, NULL );
+  trw_layer_acquire ( lav, &vik_datasource_geotag_interface );
 
   // Reverify thumbnails as they may have changed
   vtl->has_verified_thumbnails = FALSE;
@@ -3768,14 +3832,14 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  gchar* external1 = g_strconcat ( _("Open with External Program_1: "), a_vik_get_external_gpx_program_1(), NULL );
+  gchar* external1 = g_strdup_printf ( _("Open with External Program_1: %s"), a_vik_get_external_gpx_program_1() );
   item = gtk_menu_item_new_with_mnemonic ( external1 );
   g_free ( external1 );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  gchar* external2 = g_strconcat ( _("Open with External Program_2: "), a_vik_get_external_gpx_program_2(), NULL );
+  gchar* external2 = g_strdup_printf ( _("Open with External Program_2: %s"), a_vik_get_external_gpx_program_2() );
   item = gtk_menu_item_new_with_mnemonic ( external2 );
   g_free ( external2 );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along );
@@ -3848,6 +3912,11 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_widget_show ( item );
 #endif
 
+  item = gtk_menu_item_new_with_mnemonic ( _("From _URL...") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_url_cb), pass_along );
+  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_show ( item );
+
 #ifdef VIK_CONFIG_GEONAMES
   GtkWidget *wikipedia_submenu = gtk_menu_new();
   item = gtk_image_menu_item_new_with_mnemonic ( _("From _Wikipedia Waypoints") );
@@ -3886,6 +3955,7 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+  gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
   gtk_widget_show ( item );
 
   vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) );
@@ -3974,6 +4044,13 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
   gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->tracks)+g_hash_table_size (vtl->routes)) );
+
+  item = gtk_image_menu_item_new_with_mnemonic ( _("_Waypoint List...") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along );
+  gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+  gtk_widget_show ( item );
+  gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->waypoints)) );
 }
 
 // Fake Waypoint UUIDs vi simple increasing integer
@@ -4042,7 +4119,7 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 
   g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t );
 
-  trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(tr_uuid) );
+  trw_layer_update_treeview ( vtl, t );
 }
 
 // Fake Route UUIDs vi simple increasing integer
@@ -4075,7 +4152,7 @@ void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 
   g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t );
 
-  trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(rt_uuid) );
+  trw_layer_update_treeview ( vtl, t );
 }
 
 /* to be called whenever a track has been deleted or may have been changed. */
@@ -4647,7 +4724,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] )
 /**
  *  Rename waypoint and maintain corresponding name of waypoint in the treeview
  */
-static void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name )
+void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name )
 {
   vik_waypoint_set_name ( wp, new_name );
 
@@ -4669,6 +4746,28 @@ static void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const
   }
 }
 
+/**
+ *  Maintain icon of waypoint in the treeview
+ */
+void trw_layer_waypoint_reset_icon ( VikTrwLayer *vtl, VikWaypoint *wp )
+{
+  // update the treeview
+  wpu_udata udataU;
+  udataU.wp   = wp;
+  udataU.uuid = NULL;
+
+  // Need key of it for treeview update
+  gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+
+  if ( wpf && udataU.uuid ) {
+    GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
+
+    if ( it ) {
+      vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, it, get_wp_sym_small (wp->symbol) );
+    }
+  }
+}
+
 static void trw_layer_properties_item ( gpointer pass_along[7] )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
@@ -4705,7 +4804,6 @@ static void trw_layer_properties_item ( gpointer pass_along[7] )
                                   tr,
                                  pass_along[1], /* vlp */
                                  pass_along[5], /* vvp */
-                                  pass_along[6], /* iter */
                                   FALSE );
     }
   }
@@ -4733,7 +4831,6 @@ static void trw_layer_track_statistics ( gpointer pass_along[7] )
                                 trk,
                                 pass_along[1], // vlp
                                 pass_along[5], // vvp
-                                pass_along[6], // iter
                                 TRUE );
   }
 }
@@ -4741,7 +4838,7 @@ static void trw_layer_track_statistics ( gpointer pass_along[7] )
 /*
  * Update the treeview of the track id - primarily to update the icon
  */
-void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk, gpointer *trk_id )
+void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk )
 {
   trku_udata udata;
   udata.trk  = trk;
@@ -4921,6 +5018,8 @@ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
   VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
   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 );
@@ -6905,6 +7004,39 @@ static void trw_layer_routes_visibility_toggle ( gpointer lav[2] )
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
+/**
+ * vik_trw_layer_build_waypoint_list_t:
+ *
+ * Helper function to construct a list of #vik_trw_waypoint_list_t
+ */
+GList *vik_trw_layer_build_waypoint_list_t ( VikTrwLayer *vtl, GList *waypoints )
+{
+  GList *waypoints_and_layers = NULL;
+  // build waypoints_and_layers list
+  while ( waypoints ) {
+    vik_trw_waypoint_list_t *vtdl = g_malloc (sizeof(vik_trw_waypoint_list_t));
+    vtdl->wpt = VIK_WAYPOINT(waypoints->data);
+    vtdl->vtl = vtl;
+    waypoints_and_layers = g_list_prepend ( waypoints_and_layers, vtdl );
+    waypoints = g_list_next ( waypoints );
+  }
+  return waypoints_and_layers;
+}
+
+/**
+ * trw_layer_create_waypoint_list:
+ *
+ * Create the latest list of waypoints with the associated layer(s)
+ *  Although this will always be from a single layer here
+ */
+static GList* trw_layer_create_waypoint_list ( VikLayer *vl, gpointer user_data )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
+  GList *waypoints = g_hash_table_get_values ( vik_trw_layer_get_waypoints(vtl) );
+
+  return vik_trw_layer_build_waypoint_list_t ( vtl, waypoints );
+}
+
 /**
  * trw_layer_analyse_close:
  *
@@ -7210,18 +7342,15 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
 
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
     {
-      gboolean separator_created = FALSE;
+      // Always create separator as now there is always at least the transform menu option
+      item = gtk_menu_item_new ();
+      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_widget_show ( item );
 
       /* could be a right-click using the tool */
       if ( vlp != NULL ) {
-       item = gtk_menu_item_new ();
-       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-       gtk_widget_show ( item );
-
-       separator_created = TRUE;
-
         item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
-       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
+        gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
         gtk_widget_show ( item );
@@ -7231,30 +7360,22 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
 
       if ( wp && wp->name ) {
         if ( is_valid_geocache_name ( wp->name ) ) {
-
-          if ( !separator_created ) {
-            item = gtk_menu_item_new ();
-            gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-            gtk_widget_show ( item );
-            separator_created = TRUE;
-          }
-
           item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
           gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
           gtk_widget_show ( item );
         }
+#ifdef VIK_CONFIG_GEOTAG
+        item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
+        g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint), pass_along );
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+        gtk_widget_set_tooltip_text (item, _("Geotag multiple images against this waypoint"));
+        gtk_widget_show ( item );
+#endif
       }
 
       if ( wp && wp->image )
       {
-       if ( !separator_created ) {
-         item = gtk_menu_item_new ();
-         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-         gtk_widget_show ( item );
-         separator_created = TRUE;
-       }
-
        // Set up image paramater
        pass_along[5] = wp->image;
 
@@ -7295,7 +7416,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
           gtk_widget_show ( item );
         }
       }
-
     }
   }
 
@@ -7375,6 +7495,11 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_toggle), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
     gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("_List Waypoints...") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   }
 
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS )
@@ -7445,7 +7570,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
-
     gtk_widget_show ( item );
 
     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
@@ -9763,7 +9887,7 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl )
       VIK_TRACK(value)->has_color = TRUE;
     }
 
-    trw_layer_update_treeview ( vtl, VIK_TRACK(value), key );
+    trw_layer_update_treeview ( vtl, VIK_TRACK(value) );
 
     ii++;
     if (ii > VIK_TRW_LAYER_TRACK_GCS)
@@ -9785,7 +9909,7 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl )
       VIK_TRACK(value)->has_color = TRUE;
     }
 
-    trw_layer_update_treeview ( vtl, VIK_TRACK(value), key );
+    trw_layer_update_treeview ( vtl, VIK_TRACK(value) );
 
     ii = !ii;
   }
@@ -9795,7 +9919,7 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl )
  * (Re)Calculate the bounds of the waypoints in this layer,
  * This should be called whenever waypoints are changed
  */
-static void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl )
+void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl )
 {
   struct LatLon topleft = { 0.0, 0.0 };
   struct LatLon bottomright = { 0.0, 0.0 };
@@ -10241,3 +10365,13 @@ static void trw_layer_track_list_dialog ( gpointer lav[2] )
   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] )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+  //VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+
+  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 );
+  g_free ( title );
+}