]> git.street.me.uk Git - andy/viking.git/blob - src/viktrwlayer.c
Basic support of some GPX Metadata values common to GPX1.0 and GPX1.1
[andy/viking.git] / src / viktrwlayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2007, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
6  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
7  * Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
8  * Copyright (c) 2012, Rob Norris <rw_norris@hotmail.com>
9  * Copyright (c) 2012-2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  */
26 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
27 /* viktrwlayer.c -- 8000+ lines can make a difference in the state of things */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "viking.h"
34 #include "vikmapslayer.h"
35 #include "vikgpslayer.h"
36 #include "viktrwlayer_tpwin.h"
37 #include "viktrwlayer_propwin.h"
38 #include "viktrwlayer_analysis.h"
39 #include "viktrwlayer_tracklist.h"
40 #include "viktrwlayer_waypointlist.h"
41 #ifdef VIK_CONFIG_GEOTAG
42 #include "viktrwlayer_geotag.h"
43 #include "geotag_exif.h"
44 #endif
45 #include "garminsymbols.h"
46 #include "thumbnails.h"
47 #include "background.h"
48 #include "gpx.h"
49 #include "babel.h"
50 #include "dem.h"
51 #include "dems.h"
52 #include "geonamessearch.h"
53 #ifdef VIK_CONFIG_OPENSTREETMAP
54 #include "osm-traces.h"
55 #endif
56 #include "acquire.h"
57 #include "datasources.h"
58 #include "datasource_gps.h"
59 #include "vikexttool_datasources.h"
60 #include "util.h"
61 #include "vikutils.h"
62
63 #include "vikrouting.h"
64
65 #include "icons/icons.h"
66
67 #ifdef HAVE_MATH_H
68 #include <math.h>
69 #endif
70 #ifdef HAVE_STRING_H
71 #include <string.h>
72 #endif
73 #ifdef HAVE_STDLIB_H
74 #include <stdlib.h>
75 #endif
76 #include <stdio.h>
77 #include <ctype.h>
78
79 #include <gdk/gdkkeysyms.h>
80 #include <glib.h>
81 #include <glib/gstdio.h>
82 #include <glib/gi18n.h>
83
84 #define VIK_TRW_LAYER_TRACK_GC 6
85 #define VIK_TRW_LAYER_TRACK_GCS 10
86 #define VIK_TRW_LAYER_TRACK_GC_BLACK 0
87 #define VIK_TRW_LAYER_TRACK_GC_SLOW 1
88 #define VIK_TRW_LAYER_TRACK_GC_AVER 2
89 #define VIK_TRW_LAYER_TRACK_GC_FAST 3
90 #define VIK_TRW_LAYER_TRACK_GC_STOP 4
91 #define VIK_TRW_LAYER_TRACK_GC_SINGLE 5
92
93 #define DRAWMODE_BY_TRACK 0
94 #define DRAWMODE_BY_SPEED 1
95 #define DRAWMODE_ALL_SAME_COLOR 2
96 // Note using DRAWMODE_BY_SPEED may be slow especially for vast numbers of trackpoints
97 //  as we are (re)calculating the colour for every point
98
99 #define POINTS 1
100 #define LINES 2
101
102 /* this is how it knows when you click if you are clicking close to a trackpoint. */
103 #define TRACKPOINT_SIZE_APPROX 5
104 #define WAYPOINT_SIZE_APPROX 5
105
106 #define MIN_STOP_LENGTH 15
107 #define MAX_STOP_LENGTH 86400
108 #define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
109                                  /* this is multiplied by user-inputted value from 1-100. */
110
111 enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
112
113 // See http://developer.gnome.org/pango/stable/PangoMarkupFormat.html
114 typedef enum {
115   FS_XX_SMALL = 0, // 'xx-small'
116   FS_X_SMALL,
117   FS_SMALL,
118   FS_MEDIUM, // DEFAULT
119   FS_LARGE,
120   FS_X_LARGE,
121   FS_XX_LARGE,
122   FS_NUM_SIZES
123 } font_size_t;
124
125 struct _VikTrwLayer {
126   VikLayer vl;
127   GHashTable *tracks;
128   GHashTable *tracks_iters;
129   GHashTable *routes;
130   GHashTable *routes_iters;
131   GHashTable *waypoints_iters;
132   GHashTable *waypoints;
133   GtkTreeIter tracks_iter, routes_iter, waypoints_iter;
134   gboolean tracks_visible, routes_visible, waypoints_visible;
135   LatLonBBox waypoints_bbox;
136
137   gboolean track_draw_labels;
138   guint8 drawmode;
139   guint8 drawpoints;
140   guint8 drawpoints_size;
141   guint8 drawelevation;
142   guint8 elevation_factor;
143   guint8 drawstops;
144   guint32 stop_length;
145   guint8 drawlines;
146   guint8 drawdirections;
147   guint8 drawdirections_size;
148   guint8 line_thickness;
149   guint8 bg_line_thickness;
150   vik_layer_sort_order_t track_sort_order;
151
152   // Metadata
153   VikTRWMetadata *metadata;
154
155   PangoLayout *tracklabellayout;
156   font_size_t track_font_size;
157   gchar *track_fsize_str;
158
159   guint8 wp_symbol;
160   guint8 wp_size;
161   gboolean wp_draw_symbols;
162   font_size_t wp_font_size;
163   gchar *wp_fsize_str;
164   vik_layer_sort_order_t wp_sort_order;
165
166   gdouble track_draw_speed_factor;
167   GArray *track_gc;
168   GdkGC *track_1color_gc;
169   GdkColor track_color;
170   GdkGC *current_track_gc;
171   // Separate GC for a track's potential new point as drawn via separate method
172   //  (compared to the actual track points drawn in the main trw_layer_draw_track function)
173   GdkGC *current_track_newpoint_gc;
174   GdkGC *track_bg_gc; GdkColor track_bg_color;
175   GdkGC *waypoint_gc; GdkColor waypoint_color;
176   GdkGC *waypoint_text_gc; GdkColor waypoint_text_color;
177   GdkGC *waypoint_bg_gc; GdkColor waypoint_bg_color;
178   gboolean wpbgand;
179   GdkFont *waypoint_font;
180   VikTrack *current_track; // ATM shared between new tracks and new routes
181   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
182   gboolean draw_sync_done;
183   gboolean draw_sync_do;
184
185   VikCoordMode coord_mode;
186
187   /* wp editing tool */
188   VikWaypoint *current_wp;
189   gpointer current_wp_id;
190   gboolean moving_wp;
191   gboolean waypoint_rightclick;
192
193   /* track editing tool */
194   GList *current_tpl;
195   VikTrack *current_tp_track;
196   gpointer current_tp_id;
197   VikTrwLayerTpwin *tpwin;
198
199   /* track editing tool -- more specifically, moving tps */
200   gboolean moving_tp;
201
202   /* route finder tool */
203   gboolean route_finder_started;
204   VikCoord route_finder_coord;
205   gboolean route_finder_check_added_track;
206   VikTrack *route_finder_added_track;
207   VikTrack *route_finder_current_track;
208   gboolean route_finder_append;
209
210   gboolean drawlabels;
211   gboolean drawimages;
212   guint8 image_alpha;
213   GQueue *image_cache;
214   guint8 image_size;
215   guint16 image_cache_size;
216
217   /* for waypoint text */
218   PangoLayout *wplabellayout;
219
220   gboolean has_verified_thumbnails;
221
222   GtkMenu *wp_right_click_menu;
223   GtkMenu *track_right_click_menu;
224
225   /* menu */
226   VikStdLayerMenuItem menu_selection;
227
228   gint highest_wp_number;
229
230   // One per layer
231   GtkWidget *tracks_analysis_dialog;
232 };
233
234 /* A caached waypoint image. */
235 typedef struct {
236   GdkPixbuf *pixbuf;
237   gchar *image; /* filename */
238 } CachedPixbuf;
239
240 struct DrawingParams {
241   VikViewport *vp;
242   VikTrwLayer *vtl;
243   VikWindow *vw;
244   gdouble xmpp, ympp;
245   guint16 width, height;
246   gdouble cc; // Cosine factor in track directions
247   gdouble ss; // Sine factor in track directions
248   const VikCoord *center;
249   gboolean one_zone, lat_lon;
250   gdouble ce1, ce2, cn1, cn2;
251   LatLonBBox bbox;
252 };
253
254 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
255
256 typedef enum {
257   MA_VTL = 0,
258   MA_VLP,
259   MA_SUBTYPE, // OR END for Layer only
260   MA_SUBLAYER_ID,
261   MA_CONFIRM,
262   MA_VVP,
263   MA_TV_ITER,
264   MA_MISC,
265   MA_LAST,
266 } menu_array_index;
267
268 typedef gpointer menu_array_layer[2];
269 typedef gpointer menu_array_sublayer[MA_LAST];
270
271 static void trw_layer_delete_item ( menu_array_sublayer values );
272 static void trw_layer_copy_item_cb ( menu_array_sublayer values );
273 static void trw_layer_cut_item_cb ( menu_array_sublayer values );
274
275 static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] );
276 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
277
278 static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
279 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
280
281 static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp );
282 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp );
283
284 static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
285 static void trw_layer_goto_track_startpoint ( menu_array_sublayer values );
286 static void trw_layer_goto_track_endpoint ( menu_array_sublayer values );
287 static void trw_layer_goto_track_max_speed ( menu_array_sublayer values );
288 static void trw_layer_goto_track_max_alt ( menu_array_sublayer values );
289 static void trw_layer_goto_track_min_alt ( menu_array_sublayer values );
290 static void trw_layer_goto_track_center ( menu_array_sublayer values );
291 static void trw_layer_merge_by_segment ( menu_array_sublayer values );
292 static void trw_layer_merge_by_timestamp ( menu_array_sublayer values );
293 static void trw_layer_merge_with_other ( menu_array_sublayer values );
294 static void trw_layer_append_track ( menu_array_sublayer values );
295 static void trw_layer_split_by_timestamp ( menu_array_sublayer values );
296 static void trw_layer_split_by_n_points ( menu_array_sublayer values );
297 static void trw_layer_split_at_trackpoint ( menu_array_sublayer values );
298 static void trw_layer_split_segments ( menu_array_sublayer values );
299 static void trw_layer_delete_point_selected ( menu_array_sublayer values );
300 static void trw_layer_delete_points_same_position ( menu_array_sublayer values );
301 static void trw_layer_delete_points_same_time ( menu_array_sublayer values );
302 static void trw_layer_reverse ( menu_array_sublayer values );
303 static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values );
304 static void trw_layer_edit_trackpoint ( menu_array_sublayer values );
305 static void trw_layer_show_picture ( menu_array_sublayer values );
306 static void trw_layer_gps_upload_any ( menu_array_sublayer values );
307
308 static void trw_layer_centerize ( menu_array_layer values );
309 static void trw_layer_auto_view ( menu_array_layer values );
310 static void trw_layer_export ( menu_array_layer values, const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type );
311 static void trw_layer_goto_wp ( menu_array_layer values );
312 static void trw_layer_new_wp ( menu_array_layer values );
313 static void trw_layer_new_track ( menu_array_layer values );
314 static void trw_layer_new_route ( menu_array_layer values );
315 static void trw_layer_finish_track ( menu_array_layer values );
316 static void trw_layer_auto_waypoints_view ( menu_array_layer values );
317 static void trw_layer_auto_tracks_view ( menu_array_layer values );
318 static void trw_layer_delete_all_tracks ( menu_array_layer values );
319 static void trw_layer_delete_tracks_from_selection ( menu_array_layer values );
320 static void trw_layer_delete_all_waypoints ( menu_array_layer values );
321 static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values );
322 static void trw_layer_new_wikipedia_wp_viewport ( menu_array_layer values );
323 static void trw_layer_new_wikipedia_wp_layer ( menu_array_layer values );
324 #ifdef VIK_CONFIG_GEOTAG
325 static void trw_layer_geotagging_waypoint_mtime_keep ( menu_array_sublayer values );
326 static void trw_layer_geotagging_waypoint_mtime_update ( menu_array_sublayer values );
327 static void trw_layer_geotagging_track ( menu_array_sublayer values );
328 static void trw_layer_geotagging ( menu_array_layer values );
329 #endif
330 static void trw_layer_acquire_gps_cb ( menu_array_layer values );
331 static void trw_layer_acquire_routing_cb ( menu_array_layer values );
332 static void trw_layer_acquire_url_cb ( menu_array_layer values );
333 #ifdef VIK_CONFIG_OPENSTREETMAP
334 static void trw_layer_acquire_osm_cb ( menu_array_layer values );
335 static void trw_layer_acquire_osm_my_traces_cb ( menu_array_layer values );
336 #endif
337 #ifdef VIK_CONFIG_GEOCACHES
338 static void trw_layer_acquire_geocache_cb ( menu_array_layer values );
339 #endif
340 #ifdef VIK_CONFIG_GEOTAG
341 static void trw_layer_acquire_geotagged_cb ( menu_array_layer values );
342 #endif
343 static void trw_layer_acquire_file_cb ( menu_array_layer values );
344 static void trw_layer_gps_upload ( menu_array_layer values );
345
346 static void trw_layer_track_list_dialog_single ( menu_array_sublayer values );
347 static void trw_layer_track_list_dialog ( menu_array_layer values );
348 static void trw_layer_waypoint_list_dialog ( menu_array_layer values );
349
350 // Specific route versions:
351 //  Most track handling functions can handle operating on the route list
352 //  However these ones are easier in separate functions
353 static void trw_layer_auto_routes_view ( menu_array_layer values );
354 static void trw_layer_delete_all_routes ( menu_array_layer values );
355 static void trw_layer_delete_routes_from_selection ( menu_array_layer values );
356
357 /* pop-up items */
358 static void trw_layer_properties_item ( gpointer pass_along[7] ); //TODO??
359 static void trw_layer_goto_waypoint ( menu_array_sublayer values );
360 static void trw_layer_waypoint_gc_webpage ( menu_array_sublayer values );
361 static void trw_layer_waypoint_webpage ( menu_array_sublayer values );
362
363 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
364 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
365 static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp );
366
367 static void trw_layer_insert_tp_beside_current_tp ( VikTrwLayer *vtl, gboolean );
368 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
369 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
370 static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
371
372 static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
373 static void tool_edit_trackpoint_destroy ( tool_ed_t *t );
374 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
375 static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
376 static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
377 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp);
378 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
379 static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp);
380 static void tool_edit_waypoint_destroy ( tool_ed_t *t );
381 static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
382 static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
383 static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
384 static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp);
385 static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
386 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
387 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
388 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp ); 
389 static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
390 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ); 
391 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
392 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
393 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
394 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
395
396 static void cached_pixbuf_free ( CachedPixbuf *cp );
397 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
398
399 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
400 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
401
402 static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode );
403 static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode );
404
405 static gchar *highest_wp_number_get(VikTrwLayer *vtl);
406 static void highest_wp_number_reset(VikTrwLayer *vtl);
407 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
408 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
409
410 // Note for the following tool GtkRadioActionEntry texts:
411 //  the very first text value is an internal name not displayed anywhere
412 //  the first N_ text value is the name used for menu entries - hence has an underscore for the keyboard accelerator
413 //    * remember not to clash with the values used for VikWindow level tools (Pan, Zoom, Ruler + Select)
414 //  the second N_ text value is used for the button tooltip (i.e. generally don't want an underscore here)
415 //  the value is always set to 0 and the tool loader in VikWindow will set the actual appropriate value used
416 static VikToolInterface trw_layer_tools[] = {
417   { { "CreateWaypoint", "vik-icon-Create Waypoint", N_("Create _Waypoint"), "<control><shift>W", N_("Create Waypoint"), 0 },
418     (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL,
419     (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL,
420     FALSE,
421     GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
422
423   { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
424     (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL,
425     (VikToolMouseFunc) tool_new_track_click,
426     (VikToolMouseMoveFunc) tool_new_track_move,
427     (VikToolMouseFunc) tool_new_track_release,
428     (VikToolKeyFunc) tool_new_track_key_press,
429     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
430     GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
431
432   { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "<control><shift>B", N_("Create Route"), 0 },
433     (VikToolConstructorFunc) tool_new_route_create,       NULL, NULL, NULL,
434     (VikToolMouseFunc) tool_new_route_click,
435     (VikToolMouseMoveFunc) tool_new_track_move, // -\#
436     (VikToolMouseFunc) tool_new_track_release,  //   -> Reuse these track methods on a route
437     (VikToolKeyFunc) tool_new_track_key_press,  // -/#
438     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
439     GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf },
440
441   { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "<control><shift>E", N_("Edit Waypoint"), 0 },
442     (VikToolConstructorFunc) tool_edit_waypoint_create,
443     (VikToolDestructorFunc) tool_edit_waypoint_destroy,
444     NULL, NULL,
445     (VikToolMouseFunc) tool_edit_waypoint_click,   
446     (VikToolMouseMoveFunc) tool_edit_waypoint_move,
447     (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
448     FALSE,
449     GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
450
451   { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
452     (VikToolConstructorFunc) tool_edit_trackpoint_create,
453     (VikToolDestructorFunc) tool_edit_trackpoint_destroy,
454     NULL, NULL,
455     (VikToolMouseFunc) tool_edit_trackpoint_click,
456     (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
457     (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
458     FALSE,
459     GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
460
461   { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
462     (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL,
463     (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL,
464     FALSE,
465     GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
466
467   { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
468     (VikToolConstructorFunc) tool_route_finder_create,  NULL, NULL, NULL,
469     (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
470     FALSE,
471     GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
472 };
473
474 enum {
475   TOOL_CREATE_WAYPOINT=0,
476   TOOL_CREATE_TRACK,
477   TOOL_CREATE_ROUTE,
478   TOOL_EDIT_WAYPOINT,
479   TOOL_EDIT_TRACKPOINT,
480   TOOL_SHOW_PICTURE,
481   TOOL_ROUTE_FINDER,
482   NUM_TOOLS
483 };
484
485 /****** PARAMETERS ******/
486
487 static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced"), N_("Metadata") };
488 enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV, GROUP_METADATA };
489
490 static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL };
491 static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
492
493 #define MIN_POINT_SIZE 2
494 #define MAX_POINT_SIZE 10
495
496 #define MIN_ARROW_SIZE 3
497 #define MAX_ARROW_SIZE 20
498
499 static VikLayerParamScale params_scales[] = {
500  /* min  max    step digits */
501  {  1,   10,    1,   0 }, /* line_thickness */
502  {  0,   100,   1,   0 }, /* track draw speed factor */
503  {  1.0, 100.0, 1.0, 2 }, /* UNUSED */
504                 /* 5 * step == how much to turn */
505  {  16,   128,  4,   0 }, // 3: image_size - NB step size ignored when an HSCALE used
506  {   0,   255,  5,   0 }, // 4: image alpha -    "     "      "            "
507  {   5,   500,  5,   0 }, // 5: image cache_size -     "      "
508  {   0,   8,    1,   0 }, // 6: Background line thickness
509  {   1,  64,    1,   0 }, /* wpsize */
510  {   MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1,   0 }, /* stop_length */
511  {   1, 100, 1,   0 }, // 9: elevation factor
512  {   MIN_POINT_SIZE,  MAX_POINT_SIZE,  1,   0 }, // 10: track point size
513  {   MIN_ARROW_SIZE,  MAX_ARROW_SIZE,  1,   0 }, // 11: direction arrow size
514 };
515
516 static gchar* params_font_sizes[] = {
517   N_("Extra Extra Small"),
518   N_("Extra Small"),
519   N_("Small"),
520   N_("Medium"),
521   N_("Large"),
522   N_("Extra Large"),
523   N_("Extra Extra Large"),
524   NULL };
525
526 // Needs to align with vik_layer_sort_order_t
527 static gchar* params_sort_order[] = {
528   N_("None"),
529   N_("Name Ascending"),
530   N_("Name Descending"),
531   NULL
532 };
533
534 static VikLayerParamData black_color_default ( void ) {
535   VikLayerParamData data; gdk_color_parse ( "#000000", &data.c ); return data; // Black
536 }
537 static VikLayerParamData drawmode_default ( void ) { return VIK_LPD_UINT ( DRAWMODE_BY_TRACK ); }
538 static VikLayerParamData line_thickness_default ( void ) { return VIK_LPD_UINT ( 1 ); }
539 static VikLayerParamData trkpointsize_default ( void ) { return VIK_LPD_UINT ( MIN_POINT_SIZE ); }
540 static VikLayerParamData trkdirectionsize_default ( void ) { return VIK_LPD_UINT ( 5 ); }
541 static VikLayerParamData bg_line_thickness_default ( void ) { return VIK_LPD_UINT ( 0 ); }
542 static VikLayerParamData trackbgcolor_default ( void ) {
543   VikLayerParamData data; gdk_color_parse ( "#FFFFFF", &data.c ); return data; // White
544 }
545 static VikLayerParamData elevation_factor_default ( void ) { return VIK_LPD_UINT ( 30 ); }
546 static VikLayerParamData stop_length_default ( void ) { return VIK_LPD_UINT ( 60 ); }
547 static VikLayerParamData speed_factor_default ( void ) { return VIK_LPD_DOUBLE ( 30.0 ); }
548
549 static VikLayerParamData tnfontsize_default ( void ) { return VIK_LPD_UINT ( FS_MEDIUM ); }
550 static VikLayerParamData wpfontsize_default ( void ) { return VIK_LPD_UINT ( FS_MEDIUM ); }
551 static VikLayerParamData wptextcolor_default ( void ) {
552   VikLayerParamData data; gdk_color_parse ( "#FFFFFF", &data.c ); return data; // White
553 }
554 static VikLayerParamData wpbgcolor_default ( void ) {
555   VikLayerParamData data; gdk_color_parse ( "#8383C4", &data.c ); return data; // Kind of Blue
556 }
557 static VikLayerParamData wpsize_default ( void ) { return VIK_LPD_UINT ( 4 ); }
558 static VikLayerParamData wpsymbol_default ( void ) { return VIK_LPD_UINT ( WP_SYMBOL_FILLED_SQUARE ); }
559
560 static VikLayerParamData image_size_default ( void ) { return VIK_LPD_UINT ( 64 ); }
561 static VikLayerParamData image_alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
562 static VikLayerParamData image_cache_size_default ( void ) { return VIK_LPD_UINT ( 300 ); }
563
564 static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); }
565
566 static VikLayerParamData string_default ( void )
567 {
568   VikLayerParamData data;
569   data.s = "";
570   return data;
571 }
572
573 VikLayerParam trw_layer_params[] = {
574   { 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 },
575   { 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 },
576   { VIK_LAYER_TRW, "routes_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
577
578   { VIK_LAYER_TRW, "trackdrawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
579     N_("Note: the individual track controls what labels may be displayed"), vik_lpd_true_default, NULL, NULL },
580   { VIK_LAYER_TRW, "trackfontsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Labels Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, tnfontsize_default, NULL, NULL },
581   { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default, NULL, NULL },
582   { VIK_LAYER_TRW, "trackcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("All Tracks Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL,
583     N_("The color used when 'All Tracks Same Color' drawing mode is selected"), black_color_default, NULL, NULL },
584   { VIK_LAYER_TRW, "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
585   { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[0], NULL, NULL, line_thickness_default, NULL, NULL },
586   { VIK_LAYER_TRW, "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
587   { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL },
588   { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
589   { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL },
590   { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
591   { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL },
592   { VIK_LAYER_TRW, "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
593     N_("Whether to draw a marker when trackpoints are at the same position but over the minimum stop length apart in time"), vik_lpd_false_default, NULL, NULL },
594   { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[8], NULL, NULL, stop_length_default, NULL, NULL },
595
596   { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL },
597   { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS_ADV, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL },
598   { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS_ADV, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[1], NULL,
599     N_("The percentage factor away from the average speed determining the color used"), speed_factor_default, NULL, NULL },
600   { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL },
601
602   { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
603   { VIK_LAYER_TRW, "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, wpfontsize_default, NULL, NULL },
604   { VIK_LAYER_TRW, "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, black_color_default, NULL, NULL },
605   { VIK_LAYER_TRW, "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wptextcolor_default, NULL, NULL },
606   { VIK_LAYER_TRW, "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wpbgcolor_default, NULL, NULL },
607   { VIK_LAYER_TRW, "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
608   { VIK_LAYER_TRW, "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_COMBOBOX, params_wpsymbols, NULL, NULL, wpsymbol_default, NULL, NULL },
609   { VIK_LAYER_TRW, "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[7], NULL, NULL, wpsize_default, NULL, NULL },
610   { VIK_LAYER_TRW, "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
611   { VIK_LAYER_TRW, "wpsortorder", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL },
612
613   { VIK_LAYER_TRW, "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
614   { 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 },
615   { 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 },
616   { 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 },
617
618   { VIK_LAYER_TRW, "metadatadesc", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Description"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
619   { VIK_LAYER_TRW, "metadataauthor", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Author"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
620   { VIK_LAYER_TRW, "metadatatime", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Creation Time"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
621   { VIK_LAYER_TRW, "metadatakeywords", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Keywords"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
622 };
623
624 // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
625 enum {
626   // Sublayer visibilities
627   PARAM_TV,
628   PARAM_WV,
629   PARAM_RV,
630   // Tracks
631   PARAM_TDL,
632   PARAM_TLFONTSIZE,
633   PARAM_DM,
634   PARAM_TC,
635   PARAM_DL,
636   PARAM_LT,
637   PARAM_DD,
638   PARAM_DDS,
639   PARAM_DP,
640   PARAM_DPS,
641   PARAM_DE,
642   PARAM_EF,
643   PARAM_DS,
644   PARAM_SL,
645   PARAM_BLT,
646   PARAM_TBGC,
647   PARAM_TDSF,
648   PARAM_TSO,
649   // Waypoints
650   PARAM_DLA,
651   PARAM_WPFONTSIZE,
652   PARAM_WPC,
653   PARAM_WPTC,
654   PARAM_WPBC,
655   PARAM_WPBA,
656   PARAM_WPSYM,
657   PARAM_WPSIZE,
658   PARAM_WPSYMS,
659   PARAM_WPSO,
660   // WP images
661   PARAM_DI,
662   PARAM_IS,
663   PARAM_IA,
664   PARAM_ICS,
665   // Metadata
666   PARAM_MDDESC,
667   PARAM_MDAUTH,
668   PARAM_MDTIME,
669   PARAM_MDKEYS,
670   NUM_PARAMS
671 };
672
673 /*** TO ADD A PARAM:
674  *** 1) Add to trw_layer_params and enumeration
675  *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
676  ***/
677
678 /****** END PARAMETERS ******/
679
680 /* Layer Interface function definitions */
681 static VikTrwLayer* trw_layer_create ( VikViewport *vp );
682 static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter );
683 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file );
684 static void trw_layer_free ( VikTrwLayer *trwlayer );
685 static void trw_layer_draw ( VikTrwLayer *l, gpointer data );
686 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
687 static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 );
688 static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl );
689 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp );
690 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp );
691 static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter );
692 static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer );
693 static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
694 static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
695 static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp );
696 static void trw_layer_marshall ( VikTrwLayer *vtl, guint8 **data, gint *len );
697 static VikTrwLayer *trw_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp );
698 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
699 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
700 static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values );
701 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
702 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
703 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
704 static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
705 static void trw_layer_free_copied_item ( gint subtype, gpointer item );
706 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
707 static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
708 static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
709 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
710 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
711 /* End Layer Interface function definitions */
712
713 VikLayerInterface vik_trw_layer_interface = {
714   "TrackWaypoint",
715   N_("TrackWaypoint"),
716   "<control><shift>Y",
717   &viktrwlayer_pixbuf,
718
719   trw_layer_tools,
720   sizeof(trw_layer_tools) / sizeof(VikToolInterface),
721
722   trw_layer_params,
723   NUM_PARAMS,
724   params_groups, /* params_groups */
725   sizeof(params_groups)/sizeof(params_groups[0]),    /* number of groups */
726
727   VIK_MENU_ITEM_ALL,
728
729   (VikLayerFuncCreate)                  trw_layer_create,
730   (VikLayerFuncRealize)                 trw_layer_realize,
731   (VikLayerFuncPostRead)                trw_layer_post_read,
732   (VikLayerFuncFree)                    trw_layer_free,
733
734   (VikLayerFuncProperties)              NULL,
735   (VikLayerFuncDraw)                    trw_layer_draw,
736   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
737
738   (VikLayerFuncSetMenuItemsSelection)   trw_layer_set_menu_selection,
739   (VikLayerFuncGetMenuItemsSelection)   trw_layer_get_menu_selection,
740
741   (VikLayerFuncAddMenuItems)            trw_layer_add_menu_items,
742   (VikLayerFuncSublayerAddMenuItems)    trw_layer_sublayer_add_menu_items,
743
744   (VikLayerFuncSublayerRenameRequest)   trw_layer_sublayer_rename_request,
745   (VikLayerFuncSublayerToggleVisible)   trw_layer_sublayer_toggle_visible,
746   (VikLayerFuncSublayerTooltip)         trw_layer_sublayer_tooltip,
747   (VikLayerFuncLayerTooltip)            trw_layer_layer_tooltip,
748   (VikLayerFuncLayerSelected)           trw_layer_selected,
749
750   (VikLayerFuncMarshall)                trw_layer_marshall,
751   (VikLayerFuncUnmarshall)              trw_layer_unmarshall,
752
753   (VikLayerFuncSetParam)                trw_layer_set_param,
754   (VikLayerFuncGetParam)                trw_layer_get_param,
755   (VikLayerFuncChangeParam)             trw_layer_change_param,
756
757   (VikLayerFuncReadFileData)            a_gpspoint_read_file,
758   (VikLayerFuncWriteFileData)           a_gpspoint_write_file,
759
760   (VikLayerFuncDeleteItem)              trw_layer_del_item,
761   (VikLayerFuncCutItem)                 trw_layer_cut_item,
762   (VikLayerFuncCopyItem)                trw_layer_copy_item,
763   (VikLayerFuncPasteItem)               trw_layer_paste_item,
764   (VikLayerFuncFreeCopiedItem)          trw_layer_free_copied_item,
765   
766   (VikLayerFuncDragDropRequest)         trw_layer_drag_drop_request,
767
768   (VikLayerFuncSelectClick)             trw_layer_select_click,
769   (VikLayerFuncSelectMove)              trw_layer_select_move,
770   (VikLayerFuncSelectRelease)           trw_layer_select_release,
771   (VikLayerFuncSelectedViewportMenu)    trw_layer_show_selected_viewport_menu,
772 };
773
774 GType vik_trw_layer_get_type ()
775 {
776   static GType vtl_type = 0;
777
778   if (!vtl_type)
779   {
780     static const GTypeInfo vtl_info =
781     {
782       sizeof (VikTrwLayerClass),
783       NULL, /* base_init */
784       NULL, /* base_finalize */
785       NULL, /* class init */
786       NULL, /* class_finalize */
787       NULL, /* class_data */
788       sizeof (VikTrwLayer),
789       0,
790       NULL /* instance init */
791     };
792     vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 );
793   }
794
795   return vtl_type;
796 }
797
798 VikTRWMetadata *vik_trw_metadata_new()
799 {
800   return (VikTRWMetadata*)g_malloc0(sizeof(VikTRWMetadata));
801 }
802
803 void vik_trw_metadata_free ( VikTRWMetadata *metadata)
804 {
805   g_free (metadata);
806 }
807
808 VikTRWMetadata *vik_trw_layer_get_metadata ( VikTrwLayer *vtl )
809 {
810   return vtl->metadata;
811 }
812
813 void vik_trw_layer_set_metadata ( VikTrwLayer *vtl, VikTRWMetadata *metadata)
814 {
815   if ( vtl->metadata )
816     vik_trw_metadata_free ( vtl->metadata );
817   vtl->metadata = metadata;
818 }
819
820 typedef struct {
821   gboolean found;
822   const gchar *date_str;
823   const VikTrack *trk;
824   const VikWaypoint *wpt;
825   gpointer *trk_id;
826   gpointer *wpt_id;
827 } date_finder_type;
828
829 static gboolean trw_layer_find_date_track ( const gpointer id, const VikTrack *trk, date_finder_type *df )
830 {
831   gchar date_buf[20];
832   date_buf[0] = '\0';
833   // Might be an easier way to compare dates rather than converting the strings all the time...
834   if ( trk->trackpoints && VIK_TRACKPOINT(trk->trackpoints->data)->has_timestamp ) {
835     strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(VIK_TRACKPOINT(trk->trackpoints->data)->timestamp)));
836
837     if ( ! g_strcmp0 ( df->date_str, date_buf ) ) {
838       df->found = TRUE;
839       df->trk = trk;
840       df->trk_id = id;
841     }
842   }
843   return df->found;
844 }
845
846 static gboolean trw_layer_find_date_waypoint ( const gpointer id, const VikWaypoint *wpt, date_finder_type *df )
847 {
848   gchar date_buf[20];
849   date_buf[0] = '\0';
850   // Might be an easier way to compare dates rather than converting the strings all the time...
851   if ( wpt->has_timestamp ) {
852     strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(wpt->timestamp)));
853
854     if ( ! g_strcmp0 ( df->date_str, date_buf ) ) {
855       df->found = TRUE;
856       df->wpt = wpt;
857       df->wpt_id = id;
858     }
859   }
860   return df->found;
861 }
862
863 /**
864  * Find an item by date
865  */
866 gboolean vik_trw_layer_find_date ( VikTrwLayer *vtl, const gchar *date_str, VikCoord *position, VikViewport *vvp, gboolean do_tracks, gboolean select )
867 {
868   date_finder_type df;
869   df.found = FALSE;
870   df.date_str = date_str;
871   df.trk = NULL;
872   df.wpt = NULL;
873   // Only tracks ATM
874   if ( do_tracks )
875     g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_find_date_track, &df );
876   else
877     g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_find_date_waypoint, &df );
878
879   if ( select && df.found ) {
880     if ( do_tracks && df.trk ) {
881       struct LatLon maxmin[2] = { {0,0}, {0,0} };
882       trw_layer_find_maxmin_tracks ( NULL, df.trk, maxmin );
883       trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin );
884       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->tracks_iters, df.trk_id), TRUE );
885     }
886     else if ( df.wpt ) {
887       vik_viewport_set_center_coord ( vvp, &(df.wpt->coord) );
888       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->waypoints_iters, df.wpt_id), TRUE );
889     }
890     vik_layer_emit_update ( VIK_LAYER(vtl) );
891   }
892   return df.found;
893 }
894
895 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
896 {
897   static menu_array_sublayer values;
898   if (!sublayer) {
899     return;
900   }
901
902   gint ii;
903   for ( ii = MA_VTL; ii < MA_LAST; ii++ )
904     values[ii] = NULL;
905
906   values[MA_VTL]         = vtl;
907   values[MA_SUBTYPE]     = GINT_TO_POINTER (subtype);
908   values[MA_SUBLAYER_ID] = sublayer;
909   values[MA_CONFIRM]     = GINT_TO_POINTER (1); // Confirm delete request
910
911   trw_layer_delete_item ( values );
912 }
913
914 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
915 {
916   static menu_array_sublayer values;
917   if (!sublayer) {
918     return;
919   }
920
921   gint ii;
922   for ( ii = MA_VTL; ii < MA_LAST; ii++ )
923     values[ii] = NULL;
924
925   values[MA_VTL]         = vtl;
926   values[MA_SUBTYPE]     = GINT_TO_POINTER (subtype);
927   values[MA_SUBLAYER_ID] = sublayer;
928   values[MA_CONFIRM]     = GINT_TO_POINTER (1); // Confirm delete request
929
930   trw_layer_copy_item_cb(values);
931   trw_layer_cut_item_cb(values);
932 }
933
934 static void trw_layer_copy_item_cb ( menu_array_sublayer values)
935 {
936   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
937   gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]);
938   gpointer * sublayer = values[MA_SUBLAYER_ID];
939   guint8 *data = NULL;
940   guint len;
941
942   trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
943
944   if (data) {
945     const gchar* name;
946     if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
947       VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, sublayer);
948       if ( wp && wp->name )
949         name = wp->name;
950       else
951         name = NULL; // Broken :(
952     }
953     else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
954       VikTrack *trk = g_hash_table_lookup ( vtl->tracks, sublayer);
955       if ( trk && trk->name )
956         name = trk->name;
957       else
958         name = NULL; // Broken :(
959     }
960     else {
961       VikTrack *trk = g_hash_table_lookup ( vtl->routes, sublayer);
962       if ( trk && trk->name )
963         name = trk->name;
964       else
965         name = NULL; // Broken :(
966     }
967
968     a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
969                       subtype, len, name, data);
970   }
971 }
972
973 static void trw_layer_cut_item_cb ( menu_array_sublayer values)
974 {
975   trw_layer_copy_item_cb(values);
976   values[MA_CONFIRM] = GINT_TO_POINTER (0); // Never need to confirm automatic delete
977   trw_layer_delete_item(values);
978 }
979
980 static void trw_layer_paste_item_cb ( menu_array_sublayer values)
981 {
982   // Slightly cheating method, routing via the panels capability
983   a_clipboard_paste (VIK_LAYERS_PANEL(values[MA_VLP]));
984 }
985
986 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
987 {
988   guint8 *id;
989   guint il;
990
991   if (!sublayer) {
992     *item = NULL;
993     return;
994   }
995
996   GByteArray *ba = g_byte_array_new ();
997
998   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
999     vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
1000   } else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
1001     vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
1002   } else {
1003     vik_track_marshall ( g_hash_table_lookup ( vtl->routes, sublayer ), &id, &il );
1004   }
1005
1006   g_byte_array_append ( ba, id, il );
1007
1008   g_free(id);
1009
1010   *len = ba->len;
1011   *item = ba->data;
1012 }
1013
1014 static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len )
1015 {
1016   if ( !item )
1017     return FALSE;
1018
1019   gchar *name;
1020
1021   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
1022   {
1023     VikWaypoint *w;
1024
1025     w = vik_waypoint_unmarshall ( item, len );
1026     // When copying - we'll create a new name based on the original
1027     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, w->name);
1028     vik_trw_layer_add_waypoint ( vtl, name, w );
1029     waypoint_convert (NULL, w, &vtl->coord_mode);
1030     g_free ( name );
1031
1032     trw_layer_calculate_bounds_waypoints ( vtl );
1033
1034     // Consider if redraw necessary for the new item
1035     if ( vtl->vl.visible && vtl->waypoints_visible && w->visible )
1036       vik_layer_emit_update ( VIK_LAYER(vtl) );
1037     return TRUE;
1038   }
1039   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
1040   {
1041     VikTrack *t;
1042
1043     t = vik_track_unmarshall ( item, len );
1044     // When copying - we'll create a new name based on the original
1045     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name);
1046     vik_trw_layer_add_track ( vtl, name, t );
1047     vik_track_convert (t, vtl->coord_mode);
1048     g_free ( name );
1049
1050     // Consider if redraw necessary for the new item
1051     if ( vtl->vl.visible && vtl->tracks_visible && t->visible )
1052       vik_layer_emit_update ( VIK_LAYER(vtl) );
1053     return TRUE;
1054   }
1055   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
1056   {
1057     VikTrack *t;
1058
1059     t = vik_track_unmarshall ( item, len );
1060     // When copying - we'll create a new name based on the original
1061     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, t->name);
1062     vik_trw_layer_add_route ( vtl, name, t );
1063     vik_track_convert (t, vtl->coord_mode);
1064     g_free ( name );
1065
1066     // Consider if redraw necessary for the new item
1067     if ( vtl->vl.visible && vtl->routes_visible && t->visible )
1068       vik_layer_emit_update ( VIK_LAYER(vtl) );
1069     return TRUE;
1070   }
1071   return FALSE;
1072 }
1073
1074 static void trw_layer_free_copied_item ( gint subtype, gpointer item )
1075 {
1076   if (item) {
1077     g_free(item);
1078   }
1079 }
1080
1081 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
1082 {
1083   switch ( id )
1084   {
1085     case PARAM_TV: vtl->tracks_visible = data.b; break;
1086     case PARAM_WV: vtl->waypoints_visible = data.b; break;
1087     case PARAM_RV: vtl->routes_visible = data.b; break;
1088     case PARAM_TDL: vtl->track_draw_labels = data.b; break;
1089     case PARAM_TLFONTSIZE:
1090       if ( data.u < FS_NUM_SIZES ) {
1091         vtl->track_font_size = data.u;
1092         g_free ( vtl->track_fsize_str );
1093         switch ( vtl->track_font_size ) {
1094           case FS_XX_SMALL: vtl->track_fsize_str = g_strdup ( "xx-small" ); break;
1095           case FS_X_SMALL: vtl->track_fsize_str = g_strdup ( "x-small" ); break;
1096           case FS_SMALL: vtl->track_fsize_str = g_strdup ( "small" ); break;
1097           case FS_LARGE: vtl->track_fsize_str = g_strdup ( "large" ); break;
1098           case FS_X_LARGE: vtl->track_fsize_str = g_strdup ( "x-large" ); break;
1099           case FS_XX_LARGE: vtl->track_fsize_str = g_strdup ( "xx-large" ); break;
1100           default: vtl->track_fsize_str = g_strdup ( "medium" ); break;
1101         }
1102       }
1103       break;
1104     case PARAM_DM: vtl->drawmode = data.u; break;
1105     case PARAM_TC:
1106       vtl->track_color = data.c;
1107       if ( vp ) trw_layer_new_track_gcs ( vtl, vp );
1108       break;
1109     case PARAM_DP: vtl->drawpoints = data.b; break;
1110     case PARAM_DPS:
1111       if ( data.u >= MIN_POINT_SIZE && data.u <= MAX_POINT_SIZE )
1112         vtl->drawpoints_size = data.u;
1113       break;
1114     case PARAM_DE: vtl->drawelevation = data.b; break;
1115     case PARAM_DS: vtl->drawstops = data.b; break;
1116     case PARAM_DL: vtl->drawlines = data.b; break;
1117     case PARAM_DD: vtl->drawdirections = data.b; break;
1118     case PARAM_DDS:
1119       if ( data.u >= MIN_ARROW_SIZE && data.u <= MAX_ARROW_SIZE )
1120         vtl->drawdirections_size = data.u;
1121       break;
1122     case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
1123                      vtl->stop_length = data.u;
1124                    break;
1125     case PARAM_EF: if ( data.u >= 1 && data.u <= 100 )
1126                      vtl->elevation_factor = data.u;
1127                    break;
1128     case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness )
1129                    {
1130                      vtl->line_thickness = data.u;
1131                      if ( vp ) trw_layer_new_track_gcs ( vtl, vp );
1132                    }
1133                    break;
1134     case PARAM_BLT: if ( data.u <= 8 && data.u != vtl->bg_line_thickness )
1135                    {
1136                      vtl->bg_line_thickness = data.u;
1137                      if ( vp ) trw_layer_new_track_gcs ( vtl, vp );
1138                    }
1139                    break;
1140     case PARAM_TBGC:
1141       vtl->track_bg_color = data.c;
1142       if ( vtl->track_bg_gc )
1143         gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(vtl->track_bg_color));
1144       break;
1145     case PARAM_TDSF: vtl->track_draw_speed_factor = data.d; break;
1146     case PARAM_TSO: if ( data.u < VL_SO_LAST ) vtl->track_sort_order = data.u; break;
1147     case PARAM_DLA: vtl->drawlabels = data.b; break;
1148     case PARAM_DI: vtl->drawimages = data.b; break;
1149     case PARAM_IS: if ( data.u != vtl->image_size )
1150       {
1151         vtl->image_size = data.u;
1152         g_list_foreach ( vtl->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
1153         g_queue_free ( vtl->image_cache );
1154         vtl->image_cache = g_queue_new ();
1155       }
1156       break;
1157     case PARAM_IA: vtl->image_alpha = data.u; break;
1158     case PARAM_ICS: vtl->image_cache_size = data.u;
1159       while ( vtl->image_cache->length > vtl->image_cache_size ) /* if shrinking cache_size, free pixbuf ASAP */
1160           cached_pixbuf_free ( g_queue_pop_tail ( vtl->image_cache ) );
1161       break;
1162     case PARAM_WPC:
1163       vtl->waypoint_color = data.c;
1164       if ( vtl->waypoint_gc )
1165         gdk_gc_set_rgb_fg_color(vtl->waypoint_gc, &(vtl->waypoint_color));
1166       break;
1167     case PARAM_WPTC:
1168       vtl->waypoint_text_color = data.c;
1169       if ( vtl->waypoint_text_gc )
1170         gdk_gc_set_rgb_fg_color(vtl->waypoint_text_gc, &(vtl->waypoint_text_color));
1171       break;
1172     case PARAM_WPBC:
1173       vtl->waypoint_bg_color = data.c;
1174       if ( vtl->waypoint_bg_gc )
1175         gdk_gc_set_rgb_fg_color(vtl->waypoint_bg_gc, &(vtl->waypoint_bg_color));
1176       break;
1177     case PARAM_WPBA:
1178       vtl->wpbgand = data.b;
1179       if ( vtl->waypoint_bg_gc )
1180         gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY );
1181       break;
1182     case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
1183     case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
1184     case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
1185     case PARAM_WPFONTSIZE:
1186       if ( data.u < FS_NUM_SIZES ) {
1187         vtl->wp_font_size = data.u;
1188         g_free ( vtl->wp_fsize_str );
1189         switch ( vtl->wp_font_size ) {
1190           case FS_XX_SMALL: vtl->wp_fsize_str = g_strdup ( "xx-small" ); break;
1191           case FS_X_SMALL: vtl->wp_fsize_str = g_strdup ( "x-small" ); break;
1192           case FS_SMALL: vtl->wp_fsize_str = g_strdup ( "small" ); break;
1193           case FS_LARGE: vtl->wp_fsize_str = g_strdup ( "large" ); break;
1194           case FS_X_LARGE: vtl->wp_fsize_str = g_strdup ( "x-large" ); break;
1195           case FS_XX_LARGE: vtl->wp_fsize_str = g_strdup ( "xx-large" ); break;
1196           default: vtl->wp_fsize_str = g_strdup ( "medium" ); break;
1197         }
1198       }
1199       break;
1200     case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break;
1201     // Metadata
1202     case PARAM_MDDESC: if ( data.s && vtl->metadata ) vtl->metadata->description = g_strdup (data.s); break;
1203     case PARAM_MDAUTH: if ( data.s && vtl->metadata ) vtl->metadata->author = g_strdup (data.s); break;
1204     case PARAM_MDTIME: if ( data.s && vtl->metadata ) vtl->metadata->timestamp = g_strdup (data.s); break;
1205     case PARAM_MDKEYS: if ( data.s && vtl->metadata ) vtl->metadata->keywords = g_strdup (data.s); break;
1206     default: break;
1207   }
1208   return TRUE;
1209 }
1210
1211 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation )
1212 {
1213   VikLayerParamData rv;
1214   switch ( id )
1215   {
1216     case PARAM_TV: rv.b = vtl->tracks_visible; break;
1217     case PARAM_WV: rv.b = vtl->waypoints_visible; break;
1218     case PARAM_RV: rv.b = vtl->routes_visible; break;
1219     case PARAM_TDL: rv.b = vtl->track_draw_labels; break;
1220     case PARAM_TLFONTSIZE: rv.u = vtl->track_font_size; break;
1221     case PARAM_DM: rv.u = vtl->drawmode; break;
1222     case PARAM_TC: rv.c = vtl->track_color; break;
1223     case PARAM_DP: rv.b = vtl->drawpoints; break;
1224     case PARAM_DPS: rv.u = vtl->drawpoints_size; break;
1225     case PARAM_DE: rv.b = vtl->drawelevation; break;
1226     case PARAM_EF: rv.u = vtl->elevation_factor; break;
1227     case PARAM_DS: rv.b = vtl->drawstops; break;
1228     case PARAM_SL: rv.u = vtl->stop_length; break;
1229     case PARAM_DL: rv.b = vtl->drawlines; break;
1230     case PARAM_DD: rv.b = vtl->drawdirections; break;
1231     case PARAM_DDS: rv.u = vtl->drawdirections_size; break;
1232     case PARAM_LT: rv.u = vtl->line_thickness; break;
1233     case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
1234     case PARAM_DLA: rv.b = vtl->drawlabels; break;
1235     case PARAM_DI: rv.b = vtl->drawimages; break;
1236     case PARAM_TBGC: rv.c = vtl->track_bg_color; break;
1237     case PARAM_TDSF: rv.d = vtl->track_draw_speed_factor; break;
1238     case PARAM_TSO: rv.u = vtl->track_sort_order; break;
1239     case PARAM_IS: rv.u = vtl->image_size; break;
1240     case PARAM_IA: rv.u = vtl->image_alpha; break;
1241     case PARAM_ICS: rv.u = vtl->image_cache_size; break;
1242     case PARAM_WPC: rv.c = vtl->waypoint_color; break;
1243     case PARAM_WPTC: rv.c = vtl->waypoint_text_color; break;
1244     case PARAM_WPBC: rv.c = vtl->waypoint_bg_color; break;
1245     case PARAM_WPBA: rv.b = vtl->wpbgand; break;
1246     case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
1247     case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
1248     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
1249     case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
1250     case PARAM_WPSO: rv.u = vtl->wp_sort_order; break;
1251     // Metadata
1252     case PARAM_MDDESC: if (vtl->metadata) { rv.s = vtl->metadata->description; } break;
1253     case PARAM_MDAUTH: if (vtl->metadata) { rv.s = vtl->metadata->author; } break;
1254     case PARAM_MDTIME: if (vtl->metadata) { rv.s = vtl->metadata->timestamp; } break;
1255     case PARAM_MDKEYS: if (vtl->metadata) { rv.s = vtl->metadata->keywords; } break;
1256     default: break;
1257   }
1258   return rv;
1259 }
1260
1261 static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values )
1262 {
1263   // This '-3' is to account for the first few parameters not in the properties
1264   const gint OFFSET = -3;
1265
1266   switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
1267     // Alter sensitivity of waypoint draw image related widgets according to the draw image setting.
1268     case PARAM_DI: {
1269       // Get new value
1270       VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
1271       GtkWidget **ww1 = values[UI_CHG_WIDGETS];
1272       GtkWidget **ww2 = values[UI_CHG_LABELS];
1273       GtkWidget *w1 = ww1[OFFSET + PARAM_IS];
1274       GtkWidget *w2 = ww2[OFFSET + PARAM_IS];
1275       GtkWidget *w3 = ww1[OFFSET + PARAM_IA];
1276       GtkWidget *w4 = ww2[OFFSET + PARAM_IA];
1277       GtkWidget *w5 = ww1[OFFSET + PARAM_ICS];
1278       GtkWidget *w6 = ww2[OFFSET + PARAM_ICS];
1279       if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
1280       if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
1281       if ( w3 ) gtk_widget_set_sensitive ( w3, vlpd.b );
1282       if ( w4 ) gtk_widget_set_sensitive ( w4, vlpd.b );
1283       if ( w5 ) gtk_widget_set_sensitive ( w5, vlpd.b );
1284       if ( w6 ) gtk_widget_set_sensitive ( w6, vlpd.b );
1285       break;
1286     }
1287     // Alter sensitivity of waypoint label related widgets according to the draw label setting.
1288     case PARAM_DLA: {
1289       // Get new value
1290       VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
1291       GtkWidget **ww1 = values[UI_CHG_WIDGETS];
1292       GtkWidget **ww2 = values[UI_CHG_LABELS];
1293       GtkWidget *w1 = ww1[OFFSET + PARAM_WPTC];
1294       GtkWidget *w2 = ww2[OFFSET + PARAM_WPTC];
1295       GtkWidget *w3 = ww1[OFFSET + PARAM_WPBC];
1296       GtkWidget *w4 = ww2[OFFSET + PARAM_WPBC];
1297       GtkWidget *w5 = ww1[OFFSET + PARAM_WPBA];
1298       GtkWidget *w6 = ww2[OFFSET + PARAM_WPBA];
1299       GtkWidget *w7 = ww1[OFFSET + PARAM_WPFONTSIZE];
1300       GtkWidget *w8 = ww2[OFFSET + PARAM_WPFONTSIZE];
1301       if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
1302       if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
1303       if ( w3 ) gtk_widget_set_sensitive ( w3, vlpd.b );
1304       if ( w4 ) gtk_widget_set_sensitive ( w4, vlpd.b );
1305       if ( w5 ) gtk_widget_set_sensitive ( w5, vlpd.b );
1306       if ( w6 ) gtk_widget_set_sensitive ( w6, vlpd.b );
1307       if ( w7 ) gtk_widget_set_sensitive ( w7, vlpd.b );
1308       if ( w8 ) gtk_widget_set_sensitive ( w8, vlpd.b );
1309       break;
1310     }
1311     // Alter sensitivity of all track colours according to the draw track mode.
1312     case PARAM_DM: {
1313       // Get new value
1314       VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
1315       gboolean sensitive = ( vlpd.u == DRAWMODE_ALL_SAME_COLOR );
1316       GtkWidget **ww1 = values[UI_CHG_WIDGETS];
1317       GtkWidget **ww2 = values[UI_CHG_LABELS];
1318       GtkWidget *w1 = ww1[OFFSET + PARAM_TC];
1319       GtkWidget *w2 = ww2[OFFSET + PARAM_TC];
1320       if ( w1 ) gtk_widget_set_sensitive ( w1, sensitive );
1321       if ( w2 ) gtk_widget_set_sensitive ( w2, sensitive );
1322       break;
1323     }
1324     case PARAM_MDTIME: {
1325       // Force metadata->timestamp to be always read-only for now.
1326       GtkWidget **ww = values[UI_CHG_WIDGETS];
1327       GtkWidget *w1 = ww[OFFSET + PARAM_MDTIME];
1328       if ( w1 ) gtk_widget_set_sensitive ( w1, FALSE );
1329     }
1330     // NB Since other track settings have been split across tabs,
1331     // I don't think it's useful to set sensitivities on widgets you can't immediately see
1332     default: break;
1333   }
1334 }
1335
1336 static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
1337 {
1338   guint8 *pd;
1339   gint pl;
1340
1341   *data = NULL;
1342
1343   // Use byte arrays to store sublayer data
1344   // much like done elsewhere e.g. vik_layer_marshall_params()
1345   GByteArray *ba = g_byte_array_new ( );
1346
1347   guint8 *sl_data;
1348   guint sl_len;
1349
1350   guint object_length;
1351   guint subtype;
1352   // store:
1353   // the length of the item
1354   // the sublayer type of item
1355   // the the actual item
1356 #define tlm_append(object_pointer, size, type)  \
1357   subtype = (type); \
1358   object_length = (size); \
1359   g_byte_array_append ( ba, (guint8 *)&object_length, sizeof(object_length) ); \
1360   g_byte_array_append ( ba, (guint8 *)&subtype, sizeof(subtype) ); \
1361   g_byte_array_append ( ba, (object_pointer), object_length );
1362
1363   // Layer parameters first
1364   vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
1365   g_byte_array_append ( ba, (guint8 *)&pl, sizeof(pl) ); \
1366   g_byte_array_append ( ba, pd, pl );
1367   g_free ( pd );
1368
1369   // Now sublayer data
1370   GHashTableIter iter;
1371   gpointer key, value;
1372
1373   // Waypoints
1374   g_hash_table_iter_init ( &iter, vtl->waypoints );
1375   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
1376     vik_waypoint_marshall ( VIK_WAYPOINT(value), &sl_data, &sl_len );
1377     tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_WAYPOINT );
1378     g_free ( sl_data );
1379   }
1380
1381   // Tracks
1382   g_hash_table_iter_init ( &iter, vtl->tracks );
1383   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
1384     vik_track_marshall ( VIK_TRACK(value), &sl_data, &sl_len );
1385     tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_TRACK );
1386     g_free ( sl_data );
1387   }
1388
1389   // Routes
1390   g_hash_table_iter_init ( &iter, vtl->routes );
1391   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
1392     vik_track_marshall ( VIK_TRACK(value), &sl_data, &sl_len );
1393     tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_ROUTE );
1394     g_free ( sl_data );
1395   }
1396
1397 #undef tlm_append
1398
1399   *data = ba->data;
1400   *len = ba->len;
1401 }
1402
1403 static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
1404 {
1405   VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
1406   gint pl;
1407   gint consumed_length;
1408
1409   // First the overall layer parameters
1410   memcpy(&pl, data, sizeof(pl));
1411   data += sizeof(pl);
1412   vik_layer_unmarshall_params ( VIK_LAYER(vtl), data, pl, vvp );
1413   data += pl;
1414
1415   consumed_length = pl;
1416   const gint sizeof_len_and_subtype = sizeof(gint) + sizeof(gint);
1417
1418 #define tlm_size (*(gint *)data)
1419   // See marshalling above for order of how this is written
1420 #define tlm_next \
1421   data += sizeof_len_and_subtype + tlm_size;
1422
1423   // Now the individual sublayers:
1424
1425   while ( *data && consumed_length < len ) {
1426     // Normally four extra bytes at the end of the datastream
1427     //  (since it's a GByteArray and that's where it's length is stored)
1428     //  So only attempt read when there's an actual block of sublayer data
1429     if ( consumed_length + tlm_size < len ) {
1430
1431       // Reuse pl to read the subtype from the data stream
1432       memcpy(&pl, data+sizeof(gint), sizeof(pl));
1433
1434       if ( pl == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
1435         VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
1436         gchar *name = g_strdup ( trk->name );
1437         vik_trw_layer_add_track ( vtl, name, trk );
1438         g_free ( name );
1439       }
1440       if ( pl == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
1441         VikWaypoint *wp = vik_waypoint_unmarshall ( data + sizeof_len_and_subtype, 0 );
1442         gchar *name = g_strdup ( wp->name );
1443         vik_trw_layer_add_waypoint ( vtl, name, wp );
1444         g_free ( name );
1445       }
1446       if ( pl == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
1447         VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
1448         gchar *name = g_strdup ( trk->name );
1449         vik_trw_layer_add_route ( vtl, name, trk );
1450         g_free ( name );
1451       }
1452     }
1453     consumed_length += tlm_size + sizeof_len_and_subtype;
1454     tlm_next;
1455   }
1456   //g_debug ("consumed_length %d vs len %d", consumed_length, len);
1457
1458   // Not stored anywhere else so need to regenerate
1459   trw_layer_calculate_bounds_waypoints ( vtl );
1460
1461   return vtl;
1462 }
1463
1464 // Keep interesting hash function at least visible
1465 /*
1466 static guint strcase_hash(gconstpointer v)
1467 {
1468   // 31 bit hash function
1469   int i;
1470   const gchar *t = v;
1471   gchar s[128];   // malloc is too slow for reading big files
1472   gchar *p = s;
1473
1474   for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
1475       p[i] = toupper(t[i]);
1476   p[i] = '\0';
1477
1478   p = s;
1479   guint32 h = *p;
1480   if (h) {
1481     for (p += 1; *p != '\0'; p++)
1482       h = (h << 5) - h + *p;
1483   }
1484
1485   return h;  
1486 }
1487 */
1488
1489 // Stick a 1 at the end of the function name to make it more unique
1490 //  thus more easily searchable in a simple text editor
1491 static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp )
1492 {
1493   VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) );
1494   vik_layer_set_type ( VIK_LAYER(rv), VIK_LAYER_TRW );
1495
1496   // It's not entirely clear the benefits of hash tables usage here - possibly the simplicity of first implementation for unique names
1497   // Now with the name of the item stored as part of the item - these tables are effectively straightforward lists
1498
1499   // For this reworking I've choosen to keep the use of hash tables since for the expected data sizes
1500   // - even many hundreds of waypoints and tracks is quite small in the grand scheme of things,
1501   //  and with normal PC processing capabilities - it has negligibile performance impact
1502   // This also minimized the amount of rework - as the management of the hash tables already exists.
1503
1504   // The hash tables are indexed by simple integers acting as a UUID hash, which again shouldn't affect performance much
1505   //   we have to maintain a uniqueness (as before when multiple names where not allowed),
1506   //   this is to ensure it refers to the same item in the data structures used on the viewport and on the layers panel
1507
1508   rv->waypoints = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_waypoint_free );
1509   rv->waypoints_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
1510   rv->tracks = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free );
1511   rv->tracks_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
1512   rv->routes = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free );
1513   rv->routes_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
1514
1515   rv->image_cache = g_queue_new(); // Must be performed before set_params via set_defaults
1516
1517   vik_layer_set_defaults ( VIK_LAYER(rv), vvp );
1518
1519   // Param settings that are not available via the GUI
1520   // Force to on after processing params (which defaults them to off with a zero value)
1521   rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE;
1522
1523   rv->metadata = vik_trw_metadata_new ();
1524   rv->draw_sync_done = TRUE;
1525   rv->draw_sync_do = TRUE;
1526   // Everything else is 0, FALSE or NULL
1527
1528   return rv;
1529 }
1530
1531
1532 static void trw_layer_free ( VikTrwLayer *trwlayer )
1533 {
1534   g_hash_table_destroy(trwlayer->waypoints);
1535   g_hash_table_destroy(trwlayer->waypoints_iters);
1536   g_hash_table_destroy(trwlayer->tracks);
1537   g_hash_table_destroy(trwlayer->tracks_iters);
1538   g_hash_table_destroy(trwlayer->routes);
1539   g_hash_table_destroy(trwlayer->routes_iters);
1540
1541   /* ODC: replace with GArray */
1542   trw_layer_free_track_gcs ( trwlayer );
1543
1544   if ( trwlayer->wp_right_click_menu )
1545     g_object_ref_sink ( G_OBJECT(trwlayer->wp_right_click_menu) );
1546
1547   if ( trwlayer->track_right_click_menu )
1548     g_object_ref_sink ( G_OBJECT(trwlayer->track_right_click_menu) );
1549
1550   if ( trwlayer->tracklabellayout != NULL)
1551     g_object_unref ( G_OBJECT ( trwlayer->tracklabellayout ) );
1552
1553   if ( trwlayer->wplabellayout != NULL)
1554     g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) );
1555
1556   if ( trwlayer->waypoint_gc != NULL )
1557     g_object_unref ( G_OBJECT ( trwlayer->waypoint_gc ) );
1558
1559   if ( trwlayer->waypoint_text_gc != NULL )
1560     g_object_unref ( G_OBJECT ( trwlayer->waypoint_text_gc ) );
1561
1562   if ( trwlayer->waypoint_bg_gc != NULL )
1563     g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
1564
1565   g_free ( trwlayer->wp_fsize_str );
1566   g_free ( trwlayer->track_fsize_str );
1567
1568   if ( trwlayer->tpwin != NULL )
1569     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
1570
1571   if ( trwlayer->tracks_analysis_dialog != NULL )
1572     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tracks_analysis_dialog) );
1573
1574   g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
1575   g_queue_free ( trwlayer->image_cache );
1576 }
1577
1578 static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp )
1579 {
1580   dp->vtl = vtl;
1581   dp->vp = vp;
1582   dp->vw = (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl);
1583   dp->xmpp = vik_viewport_get_xmpp ( vp );
1584   dp->ympp = vik_viewport_get_ympp ( vp );
1585   dp->width = vik_viewport_get_width ( vp );
1586   dp->height = vik_viewport_get_height ( vp );
1587   dp->cc = vtl->drawdirections_size*cos(DEG2RAD(45)); // Calculate once per vtl update - even if not used
1588   dp->ss = vtl->drawdirections_size*sin(DEG2RAD(45)); // Calculate once per vtl update - even if not used
1589
1590   dp->center = vik_viewport_get_center ( vp );
1591   dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */
1592   dp->lat_lon = vik_viewport_get_coord_mode ( vp ) == VIK_COORD_LATLON;
1593
1594   if ( dp->one_zone )
1595   {
1596     gint w2, h2;
1597     w2 = dp->xmpp * (dp->width / 2) + 1600 / dp->xmpp; 
1598     h2 = dp->ympp * (dp->height / 2) + 1600 / dp->ympp;
1599     /* leniency -- for tracks. Obviously for waypoints this SHOULD be a lot smaller */
1600  
1601     dp->ce1 = dp->center->east_west-w2; 
1602     dp->ce2 = dp->center->east_west+w2;
1603     dp->cn1 = dp->center->north_south-h2;
1604     dp->cn2 = dp->center->north_south+h2;
1605   } else if ( dp->lat_lon ) {
1606     VikCoord upperleft, bottomright;
1607     /* quick & dirty calculation; really want to check all corners due to lat/lon smaller at top in northern hemisphere */
1608     /* this also DOESN'T WORK if you are crossing 180/-180 lon. I don't plan to in the near future...  */
1609     vik_viewport_screen_to_coord ( vp, -500, -500, &upperleft );
1610     vik_viewport_screen_to_coord ( vp, dp->width+500, dp->height+500, &bottomright );
1611     dp->ce1 = upperleft.east_west;
1612     dp->ce2 = bottomright.east_west;
1613     dp->cn1 = bottomright.north_south;
1614     dp->cn2 = upperleft.north_south;
1615   }
1616
1617   vik_viewport_get_min_max_lat_lon ( vp, &(dp->bbox.south), &(dp->bbox.north), &(dp->bbox.west), &(dp->bbox.east) );
1618 }
1619
1620 /*
1621  * Determine the colour of the trackpoint (and/or trackline) relative to the average speed
1622  * Here a simple traffic like light colour system is used:
1623  *  . slow points are red
1624  *  . average is yellow
1625  *  . fast points are green
1626  */
1627 static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2, gdouble average_speed, gdouble low_speed, gdouble high_speed )
1628 {
1629   gdouble rv = 0;
1630   if ( tp1->has_timestamp && tp2->has_timestamp ) {
1631     if ( average_speed > 0 ) {
1632       rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) ) / (tp1->timestamp - tp2->timestamp) );
1633       if ( rv < low_speed )
1634         return VIK_TRW_LAYER_TRACK_GC_SLOW;
1635       else if ( rv > high_speed )
1636         return VIK_TRW_LAYER_TRACK_GC_FAST;
1637       else
1638         return VIK_TRW_LAYER_TRACK_GC_AVER;
1639     }
1640   }
1641   return VIK_TRW_LAYER_TRACK_GC_BLACK;
1642 }
1643
1644 static void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
1645 {
1646   vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y );
1647   vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 );
1648   vik_viewport_draw_line ( vvp, gc, x+5, y+5, x-5, y-5 );
1649   vik_viewport_draw_line ( vvp, gc, x+5, y-5, x-5, y+5 );
1650 }
1651
1652
1653 static void trw_layer_draw_track_label ( gchar *name, gchar *fgcolour, gchar *bgcolour, struct DrawingParams *dp, VikCoord *coord )
1654 {
1655   gchar *label_markup = g_strdup_printf ( "<span foreground=\"%s\" background=\"%s\" size=\"%s\">%s</span>", fgcolour, bgcolour, dp->vtl->track_fsize_str, name );
1656
1657   if ( pango_parse_markup ( label_markup, -1, 0, NULL, NULL, NULL, NULL ) )
1658     pango_layout_set_markup ( dp->vtl->tracklabellayout, label_markup, -1 );
1659   else
1660     // Fallback if parse failure
1661     pango_layout_set_text ( dp->vtl->tracklabellayout, name, -1 );
1662
1663   g_free ( label_markup );
1664
1665   gint label_x, label_y;
1666   gint width, height;
1667   pango_layout_get_pixel_size ( dp->vtl->tracklabellayout, &width, &height );
1668
1669   vik_viewport_coord_to_screen ( dp->vp, coord, &label_x, &label_y );
1670   vik_viewport_draw_layout ( dp->vp, dp->vtl->track_bg_gc, label_x-width/2, label_y-height/2, dp->vtl->tracklabellayout );
1671 }
1672
1673 /**
1674  * distance_in_preferred_units:
1675  * @dist: The source distance in standard SI Units (i.e. metres)
1676  *
1677  * TODO: This is a generic function that could be moved into globals.c or utils.c
1678  *
1679  * Probably best used if you have a only few conversions to perform.
1680  * However if doing many points (such as on all points along a track) then this may be a bit slow,
1681  *  since it will be doing the preference check on each call
1682  *
1683  * Returns: The distance in the units as specified by the preferences
1684  */
1685 static gdouble distance_in_preferred_units ( gdouble dist )
1686 {
1687   gdouble mydist;
1688   vik_units_distance_t dist_units = a_vik_get_units_distance ();
1689   switch (dist_units) {
1690   case VIK_UNITS_DISTANCE_MILES:
1691     mydist = VIK_METERS_TO_MILES(dist);
1692     break;
1693   // VIK_UNITS_DISTANCE_KILOMETRES:
1694   default:
1695     mydist = dist/1000.0;
1696     break;
1697   }
1698   return mydist;
1699 }
1700
1701 /**
1702  * trw_layer_draw_dist_labels:
1703  *
1704  * Draw a few labels along a track at nicely seperated distances
1705  * This might slow things down if there's many tracks being displayed with this on.
1706  */
1707 static void trw_layer_draw_dist_labels ( struct DrawingParams *dp, VikTrack *trk, gboolean drawing_highlight )
1708 {
1709   static const gdouble chunksd[] = {0.25, 0.5, 1.0, 2.0, 5.0, 10.0, 15.0, 20.0,
1710                                     25.0, 40.0, 50.0, 75.0, 100.0,
1711                                     150.0, 200.0, 250.0, 500.0, 1000.0};
1712
1713   gdouble dist = vik_track_get_length_including_gaps ( trk ) / (trk->max_number_dist_labels+1);
1714
1715   // Convert to specified unit to find the friendly breakdown value
1716   dist = distance_in_preferred_units ( dist );
1717
1718   gint index = 0;
1719   gint i=0;
1720   for ( i = 0; i < G_N_ELEMENTS(chunksd); i++ ) {
1721     if ( chunksd[i] > dist ) {
1722       index = i;
1723       dist = chunksd[index];
1724       break;
1725     }
1726   }
1727
1728   vik_units_distance_t dist_units = a_vik_get_units_distance ();
1729
1730   for ( i = 1; i < trk->max_number_dist_labels+1; i++ ) {
1731     gdouble dist_i = dist * i;
1732
1733     // Convert distance back into metres for use in finding a trackpoint
1734     switch (dist_units) {
1735     case VIK_UNITS_DISTANCE_MILES:
1736       dist_i = VIK_MILES_TO_METERS(dist_i);
1737       break;
1738       // VIK_UNITS_DISTANCE_KILOMETRES:
1739     default:
1740       dist_i = dist_i*1000.0;
1741       break;
1742     }
1743
1744     gdouble dist_current = 0.0;
1745     VikTrackpoint *tp_current = vik_track_get_tp_by_dist ( trk, dist_i, FALSE, &dist_current );
1746     gdouble dist_next = 0.0;
1747     VikTrackpoint *tp_next = vik_track_get_tp_by_dist ( trk, dist_i, TRUE, &dist_next );
1748
1749     gdouble dist_between_tps = fabs (dist_next - dist_current);
1750     gdouble ratio = 0.0;
1751     // Prevent division by 0 errors
1752     if ( dist_between_tps > 0.0 )
1753       ratio = fabs(dist_i-dist_current)/dist_between_tps;
1754
1755     if ( tp_current && tp_next ) {
1756       // Construct the name based on the distance value
1757       gchar *name;
1758       gchar *units;
1759       switch (dist_units) {
1760       case VIK_UNITS_DISTANCE_MILES:
1761         units = g_strdup ( _("miles") );
1762         break;
1763         // VIK_UNITS_DISTANCE_KILOMETRES:
1764       default:
1765         units = g_strdup ( _("km") );
1766         break;
1767       }
1768
1769       // Convert for display
1770       dist_i = distance_in_preferred_units ( dist_i );
1771
1772       // Make the precision of the output related to the unit size.
1773       if ( index == 0 )
1774         name = g_strdup_printf ( "%.2f %s", dist_i, units);
1775       else if ( index == 1 )
1776         name = g_strdup_printf ( "%.1f %s", dist_i, units);
1777       else
1778         name = g_strdup_printf ( "%d %s", (gint)round(dist_i), units); // TODO single vs plurals
1779       g_free ( units );
1780
1781       struct LatLon ll_current, ll_next;
1782       vik_coord_to_latlon ( &tp_current->coord, &ll_current );
1783       vik_coord_to_latlon ( &tp_next->coord, &ll_next );
1784
1785       // positional interpolation
1786       // Using a simple ratio - may not be perfectly correct due to lat/long projections
1787       //  but should be good enough over the small scale that I anticipate usage on
1788       struct LatLon ll_new = { ll_current.lat + (ll_next.lat-ll_current.lat)*ratio,
1789                                ll_current.lon + (ll_next.lon-ll_current.lon)*ratio };
1790       VikCoord coord;
1791       vik_coord_load_from_latlon ( &coord, dp->vtl->coord_mode, &ll_new );
1792
1793       gchar *fgcolour;
1794       if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
1795         fgcolour = gdk_color_to_string ( &(trk->color) );
1796       else
1797         fgcolour = gdk_color_to_string ( &(dp->vtl->track_color) );
1798
1799       // if highlight mode on, then colour the background in the highlight colour
1800       gchar *bgcolour;
1801       if ( drawing_highlight )
1802         bgcolour = g_strdup ( vik_viewport_get_highlight_color ( dp->vp ) );
1803       else
1804         bgcolour = gdk_color_to_string ( &(dp->vtl->track_bg_color) );
1805
1806       trw_layer_draw_track_label ( name, fgcolour, bgcolour, dp, &coord );
1807
1808       g_free ( fgcolour );
1809       g_free ( bgcolour );
1810       g_free ( name );
1811     }
1812   }
1813 }
1814
1815 /**
1816  * trw_layer_draw_track_name_labels:
1817  *
1818  * Draw a label (or labels) for the track name somewhere depending on the track's properties
1819  */
1820 static void trw_layer_draw_track_name_labels ( struct DrawingParams *dp, VikTrack *trk, gboolean drawing_highlight )
1821 {
1822   gchar *fgcolour;
1823   if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
1824     fgcolour = gdk_color_to_string ( &(trk->color) );
1825   else
1826     fgcolour = gdk_color_to_string ( &(dp->vtl->track_color) );
1827
1828   // if highlight mode on, then colour the background in the highlight colour
1829   gchar *bgcolour;
1830   if ( drawing_highlight )
1831     bgcolour = g_strdup ( vik_viewport_get_highlight_color ( dp->vp ) );
1832   else
1833     bgcolour = gdk_color_to_string ( &(dp->vtl->track_bg_color) );
1834
1835   gchar *ename = g_markup_escape_text ( trk->name, -1 );
1836
1837   if ( trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ||
1838        trk->draw_name_mode == TRACK_DRAWNAME_CENTRE ) {
1839     struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
1840     trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
1841     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
1842     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
1843     VikCoord coord;
1844     vik_coord_load_from_latlon ( &coord, dp->vtl->coord_mode, &average );
1845
1846     trw_layer_draw_track_label ( ename, fgcolour, bgcolour, dp, &coord );
1847   }
1848
1849   if ( trk->draw_name_mode == TRACK_DRAWNAME_CENTRE )
1850     // No other labels to draw
1851     return;
1852
1853   VikTrackpoint *tp_end = vik_track_get_tp_last ( trk );
1854   if ( !tp_end )
1855     return;
1856   VikTrackpoint *tp_begin = vik_track_get_tp_first ( trk );
1857   if ( !tp_begin )
1858     return;
1859   VikCoord begin_coord = tp_begin->coord;
1860   VikCoord end_coord = tp_end->coord;
1861
1862   gboolean done_start_end = FALSE;
1863
1864   if ( trk->draw_name_mode == TRACK_DRAWNAME_START_END ||
1865        trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ) {
1866
1867     // This number can be configured via the settings if you really want to change it
1868     gdouble distance_diff;
1869     if ( ! a_settings_get_double ( "trackwaypoint_start_end_distance_diff", &distance_diff ) )
1870       distance_diff = 100.0; // Metres
1871
1872     if ( vik_coord_diff ( &begin_coord, &end_coord ) < distance_diff ) {
1873       // Start and end 'close' together so only draw one label at an average location
1874       gint x1, x2, y1, y2;
1875       vik_viewport_coord_to_screen ( dp->vp, &begin_coord, &x1, &y1);
1876       vik_viewport_coord_to_screen ( dp->vp, &end_coord, &x2, &y2);
1877       VikCoord av_coord;
1878       vik_viewport_screen_to_coord ( dp->vp, (x1 + x2) / 2, (y1 + y2) / 2, &av_coord );
1879
1880       gchar *name = g_strdup_printf ( "%s: %s", ename, _("start/end") );
1881       trw_layer_draw_track_label ( name, fgcolour, bgcolour, dp, &av_coord );
1882       g_free ( name );
1883
1884       done_start_end = TRUE;
1885     }
1886   }
1887
1888   if ( ! done_start_end ) {
1889     if ( trk->draw_name_mode == TRACK_DRAWNAME_START ||
1890          trk->draw_name_mode == TRACK_DRAWNAME_START_END ||
1891          trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ) {
1892       gchar *name_start = g_strdup_printf ( "%s: %s", ename, _("start") );
1893       trw_layer_draw_track_label ( name_start, fgcolour, bgcolour, dp, &begin_coord );
1894       g_free ( name_start );
1895     }
1896     // Don't draw end label if this is the one being created
1897     if ( trk != dp->vtl->current_track ) {
1898       if ( trk->draw_name_mode == TRACK_DRAWNAME_END ||
1899            trk->draw_name_mode == TRACK_DRAWNAME_START_END ||
1900            trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ) {
1901         gchar *name_end = g_strdup_printf ( "%s: %s", ename, _("end") );
1902         trw_layer_draw_track_label ( name_end, fgcolour, bgcolour, dp, &end_coord );
1903         g_free ( name_end );
1904       }
1905     }
1906   }
1907
1908   g_free ( fgcolour );
1909   g_free ( bgcolour );
1910   g_free ( ename );
1911 }
1912
1913 static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline )
1914 {
1915   if ( ! track->visible )
1916     return;
1917
1918   /* TODO: this function is a mess, get rid of any redundancy */
1919   GList *list = track->trackpoints;
1920   GdkGC *main_gc;
1921   gboolean useoldvals = TRUE;
1922
1923   gboolean drawpoints;
1924   gboolean drawstops;
1925   gboolean drawelevation;
1926   gdouble min_alt, max_alt, alt_diff = 0;
1927
1928   const guint8 tp_size_reg = dp->vtl->drawpoints_size;
1929   const guint8 tp_size_cur = dp->vtl->drawpoints_size*2;
1930   guint8 tp_size;
1931
1932   if ( dp->vtl->drawelevation )
1933   {
1934     /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
1935     if ( ( drawelevation = vik_track_get_minmax_alt ( track, &min_alt, &max_alt ) ) )
1936       alt_diff = max_alt - min_alt;
1937   }
1938
1939   /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
1940   if ( dp->vtl->bg_line_thickness && !draw_track_outline )
1941     trw_layer_draw_track ( id, track, dp, TRUE );
1942
1943   if ( draw_track_outline )
1944     drawpoints = drawstops = FALSE;
1945   else {
1946     drawpoints = dp->vtl->drawpoints;
1947     drawstops = dp->vtl->drawstops;
1948   }
1949
1950   gboolean drawing_highlight = FALSE;
1951   /* Current track - used for creation */
1952   if ( track == dp->vtl->current_track )
1953     main_gc = dp->vtl->current_track_gc;
1954   else {
1955     if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1956       /* Draw all tracks of the layer in special colour */
1957       /* if track is member of selected layer or is the current selected track
1958          then draw in the highlight colour.
1959          NB this supercedes the drawmode */
1960       if ( ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ) ||
1961            ( !track->is_route && ( dp->vtl->tracks == vik_window_get_selected_tracks ( dp->vw ) ) ) ||
1962            ( track->is_route && ( dp->vtl->routes == vik_window_get_selected_tracks ( dp->vw ) ) ) ||
1963            ( track == vik_window_get_selected_track ( dp->vw ) ) ) {
1964         main_gc = vik_viewport_get_gc_highlight (dp->vp);
1965         drawing_highlight = TRUE;
1966       }
1967     }
1968     if ( !drawing_highlight ) {
1969       // Still need to figure out the gc according to the drawing mode:
1970       switch ( dp->vtl->drawmode ) {
1971       case DRAWMODE_BY_TRACK:
1972         if ( dp->vtl->track_1color_gc )
1973           g_object_unref ( dp->vtl->track_1color_gc );
1974         dp->vtl->track_1color_gc = vik_viewport_new_gc_from_color ( dp->vp, &track->color, dp->vtl->line_thickness );
1975         main_gc = dp->vtl->track_1color_gc;
1976         break;
1977       default:
1978         // Mostly for DRAWMODE_ALL_SAME_COLOR
1979         // but includes DRAWMODE_BY_SPEED, main_gc is set later on as necessary
1980         main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_SINGLE);
1981         break;
1982       }
1983     }
1984   }
1985
1986   if (list) {
1987     int x, y, oldx, oldy;
1988     VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
1989   
1990     tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
1991
1992     vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1993
1994     // Draw the first point as something a bit different from the normal points
1995     // ATM it's slightly bigger and a triangle
1996     if ( drawpoints ) {
1997       GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} };
1998       vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 );
1999     }
2000
2001     oldx = x;
2002     oldy = y;
2003
2004     gdouble average_speed = 0.0;
2005     gdouble low_speed = 0.0;
2006     gdouble high_speed = 0.0;
2007     // If necessary calculate these values - which is done only once per track redraw
2008     if ( dp->vtl->drawmode == DRAWMODE_BY_SPEED ) {
2009       // the percentage factor away from the average speed determines transistions between the levels
2010       average_speed = vik_track_get_average_speed_moving(track, dp->vtl->stop_length);
2011       low_speed = average_speed - (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
2012       high_speed = average_speed + (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
2013     }
2014
2015     while ((list = g_list_next(list)))
2016     {
2017       tp = VIK_TRACKPOINT(list->data);
2018       tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
2019
2020       /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
2021       if ( (!dp->one_zone && !dp->lat_lon) ||     /* UTM & zones; do everything */
2022              ( ((!dp->one_zone) || tp->coord.utm_zone == dp->center->utm_zone) &&   /* only check zones if UTM & one_zone */
2023              tp->coord.east_west < dp->ce2 && tp->coord.east_west > dp->ce1 &&  /* both UTM and lat lon */
2024              tp->coord.north_south > dp->cn1 && tp->coord.north_south < dp->cn2 ) )
2025       {
2026         vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
2027
2028         /*
2029          * If points are the same in display coordinates, don't draw.
2030          */
2031         if ( useoldvals && x == oldx && y == oldy )
2032         {
2033           // Still need to process points to ensure 'stops' are drawn if required
2034           if ( drawstops && drawpoints && ! draw_track_outline && list->next &&
2035                (VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length) )
2036             vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
2037
2038           goto skip;
2039         }
2040
2041         VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
2042         if ( drawpoints || dp->vtl->drawlines ) {
2043           // setup main_gc for both point and line drawing
2044           if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
2045             main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ) );
2046           }
2047         }
2048
2049         if ( drawpoints && ! draw_track_outline )
2050         {
2051
2052           if ( list->next ) {
2053             /*
2054              * The concept of drawing stops is that a trackpoint
2055              * that is if the next trackpoint has a timestamp far into
2056              * the future, we draw a circle of 6x trackpoint size,
2057              * instead of a rectangle of 2x trackpoint size.
2058              * This is drawn first so the trackpoint will be drawn on top
2059              */
2060             /* stops */
2061             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
2062               /* Stop point.  Draw 6x circle. Always in redish colour */
2063               vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_STOP), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
2064
2065             /* Regular point - draw 2x square. */
2066             vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
2067           }
2068           else
2069             /* Final point - draw 4x circle. */
2070             vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
2071         }
2072
2073         if ((!tp->newsegment) && (dp->vtl->drawlines))
2074         {
2075
2076           /* UTM only: zone check */
2077           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
2078             draw_utm_skip_insignia (  dp->vp, main_gc, x, y);
2079
2080           if (!useoldvals)
2081             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
2082
2083           if ( draw_track_outline ) {
2084             vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
2085           }
2086           else {
2087
2088             vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
2089
2090             if ( dp->vtl->drawelevation && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
2091               GdkPoint tmp[4];
2092               #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
2093
2094               tmp[0].x = oldx;
2095               tmp[0].y = oldy;
2096               tmp[1].x = oldx;
2097               tmp[1].y = oldy-FIXALTITUDE(list->data);
2098               tmp[2].x = x;
2099               tmp[2].y = y-FIXALTITUDE(list->next->data);
2100               tmp[3].x = x;
2101               tmp[3].y = y;
2102
2103               GdkGC *tmp_gc;
2104               if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
2105                 tmp_gc = gtk_widget_get_style(GTK_WIDGET(dp->vp))->light_gc[3];
2106               else
2107                 tmp_gc = gtk_widget_get_style(GTK_WIDGET(dp->vp))->dark_gc[0];
2108               vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
2109
2110               vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
2111             }
2112           }
2113         }
2114
2115         if ( (!tp->newsegment) && dp->vtl->drawdirections ) {
2116           // Draw an arrow at the mid point to show the direction of the track
2117           // Code is a rework from vikwindow::draw_ruler()
2118           gint midx = (oldx + x) / 2;
2119           gint midy = (oldy + y) / 2;
2120
2121           gdouble len = sqrt ( ((midx-oldx) * (midx-oldx)) + ((midy-oldy) * (midy-oldy)) );
2122           // Avoid divide by zero and ensure at least 1 pixel big
2123           if ( len > 1 ) {
2124             gdouble dx = (oldx - midx) / len;
2125             gdouble dy = (oldy - midy) / len;
2126             vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc + dy * dp->ss), midy + (dy * dp->cc - dx * dp->ss) );
2127             vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc - dy * dp->ss), midy + (dy * dp->cc + dx * dp->ss) );
2128           }
2129         }
2130
2131       skip:
2132         oldx = x;
2133         oldy = y;
2134         useoldvals = TRUE;
2135       }
2136       else {
2137         if (useoldvals && dp->vtl->drawlines && (!tp->newsegment))
2138         {
2139           VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
2140           if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
2141           {
2142             vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
2143
2144             if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
2145               main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ));
2146             }
2147
2148             /*
2149              * If points are the same in display coordinates, don't draw.
2150              */
2151             if ( x != oldx || y != oldy )
2152               {
2153                 if ( draw_track_outline )
2154                   vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
2155                 else
2156                   vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
2157               }
2158           }
2159           else 
2160           {
2161             /*
2162              * If points are the same in display coordinates, don't draw.
2163              */
2164             if ( x != oldx && y != oldy )
2165               {
2166                 vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
2167                 draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
2168               }
2169           }
2170         }
2171         useoldvals = FALSE;
2172       }
2173     }
2174
2175     // Labels drawn after the trackpoints, so the labels are on top
2176     if ( dp->vtl->track_draw_labels ) {
2177       if ( track->max_number_dist_labels > 0 ) {
2178         trw_layer_draw_dist_labels ( dp, track, drawing_highlight );
2179       }
2180
2181       if ( track->draw_name_mode != TRACK_DRAWNAME_NO ) {
2182         trw_layer_draw_track_name_labels ( dp, track, drawing_highlight );
2183       }
2184     }
2185   }
2186 }
2187
2188 static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp )
2189 {
2190   if ( BBOX_INTERSECT ( track->bbox, dp->bbox ) ) {
2191     trw_layer_draw_track ( id, track, dp, FALSE );
2192   }
2193 }
2194
2195 static void cached_pixbuf_free ( CachedPixbuf *cp )
2196 {
2197   g_object_unref ( G_OBJECT(cp->pixbuf) );
2198   g_free ( cp->image );
2199 }
2200
2201 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name )
2202 {
2203   return strcmp ( cp->image, name );
2204 }
2205
2206 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp )
2207 {
2208   if ( wp->visible )
2209   if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) && 
2210              wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 && 
2211              wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
2212   {
2213     gint x, y;
2214     vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y );
2215
2216     /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
2217
2218     if ( wp->image && dp->vtl->drawimages )
2219     {
2220       GdkPixbuf *pixbuf = NULL;
2221       GList *l;
2222
2223       if ( dp->vtl->image_alpha == 0)
2224         return;
2225
2226       l = g_list_find_custom ( dp->vtl->image_cache->head, wp->image, (GCompareFunc) cached_pixbuf_cmp );
2227       if ( l )
2228         pixbuf = ((CachedPixbuf *) l->data)->pixbuf;
2229       else
2230       {
2231         gchar *image = wp->image;
2232         GdkPixbuf *regularthumb = a_thumbnails_get ( wp->image );
2233         if ( ! regularthumb )
2234         {
2235           regularthumb = a_thumbnails_get_default (); /* cache one 'not yet loaded' for all thumbs not loaded */
2236           image = "\x12\x00"; /* this shouldn't occur naturally. */
2237         }
2238         if ( regularthumb )
2239         {
2240           CachedPixbuf *cp = NULL;
2241           cp = g_malloc ( sizeof ( CachedPixbuf ) );
2242           if ( dp->vtl->image_size == 128 )
2243             cp->pixbuf = regularthumb;
2244           else
2245           {
2246             cp->pixbuf = a_thumbnails_scale_pixbuf(regularthumb, dp->vtl->image_size, dp->vtl->image_size);
2247             g_assert ( cp->pixbuf );
2248             g_object_unref ( G_OBJECT(regularthumb) );
2249           }
2250           cp->image = g_strdup ( image );
2251
2252           /* needed so 'click picture' tool knows how big the pic is; we don't
2253            * store it in cp because they may have been freed already. */
2254           wp->image_width = gdk_pixbuf_get_width ( cp->pixbuf );
2255           wp->image_height = gdk_pixbuf_get_height ( cp->pixbuf );
2256
2257           g_queue_push_head ( dp->vtl->image_cache, cp );
2258           if ( dp->vtl->image_cache->length > dp->vtl->image_cache_size )
2259             cached_pixbuf_free ( g_queue_pop_tail ( dp->vtl->image_cache ) );
2260
2261           pixbuf = cp->pixbuf;
2262         }
2263         else
2264         {
2265           pixbuf = a_thumbnails_get_default (); /* thumbnail not yet loaded */
2266         }
2267       }
2268       if ( pixbuf )
2269       {
2270         gint w, h;
2271         w = gdk_pixbuf_get_width ( pixbuf );
2272         h = gdk_pixbuf_get_height ( pixbuf );
2273
2274         if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
2275         {
2276           if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
2277             if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ||
2278                  dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) ||
2279                  wp == vik_window_get_selected_waypoint ( dp->vw ) ) {
2280               // Highlighted - so draw a little border around the chosen one
2281               // single line seems a little weak so draw 2 of them
2282               vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
2283                                            x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 );
2284               vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
2285                                            x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
2286             }
2287           }
2288           if ( dp->vtl->image_alpha == 255 )
2289             vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
2290           else
2291             vik_viewport_draw_pixbuf_with_alpha ( dp->vp, pixbuf, dp->vtl->image_alpha, 0, 0, x - (w/2), y - (h/2), w, h );
2292         }
2293         return; /* if failed to draw picture, default to drawing regular waypoint (below) */
2294       }
2295     }
2296
2297     // Draw appropriate symbol - either symbol image or simple types
2298     if ( dp->vtl->wp_draw_symbols && wp->symbol && wp->symbol_pixbuf ) {
2299       vik_viewport_draw_pixbuf ( dp->vp, wp->symbol_pixbuf, 0, 0, x - gdk_pixbuf_get_width(wp->symbol_pixbuf)/2, y - gdk_pixbuf_get_height(wp->symbol_pixbuf)/2, -1, -1 );
2300     } 
2301     else if ( wp == dp->vtl->current_wp ) {
2302       switch ( dp->vtl->wp_symbol ) {
2303         case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
2304         case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
2305         case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - dp->vtl->wp_size, y - dp->vtl->wp_size, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break;
2306         case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y - dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y + dp->vtl->wp_size*2 );
2307                           vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y + dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y - dp->vtl->wp_size*2 );
2308       }
2309     }
2310     else {
2311       switch ( dp->vtl->wp_symbol ) {
2312         case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - dp->vtl->wp_size/2, y - dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size ); break;
2313         case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - dp->vtl->wp_size/2, y - dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size ); break;
2314         case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x-dp->vtl->wp_size/2, y-dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break;
2315         case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y-dp->vtl->wp_size, x+dp->vtl->wp_size, y+dp->vtl->wp_size );
2316                           vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y+dp->vtl->wp_size, x+dp->vtl->wp_size, y-dp->vtl->wp_size ); break;
2317       }
2318     }
2319
2320     if ( dp->vtl->drawlabels )
2321     {
2322       /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
2323       gint label_x, label_y;
2324       gint width, height;
2325       // Hopefully name won't break the markup (may need to sanitize - g_markup_escape_text())
2326
2327       // Could this stored in the waypoint rather than recreating each pass?
2328       gchar *wp_label_markup = g_strdup_printf ( "<span size=\"%s\">%s</span>", dp->vtl->wp_fsize_str, wp->name );
2329
2330       if ( pango_parse_markup ( wp_label_markup, -1, 0, NULL, NULL, NULL, NULL ) )
2331         pango_layout_set_markup ( dp->vtl->wplabellayout, wp_label_markup, -1 );
2332       else
2333         // Fallback if parse failure
2334         pango_layout_set_text ( dp->vtl->wplabellayout, wp->name, -1 );
2335
2336       g_free ( wp_label_markup );
2337
2338       pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
2339       label_x = x - width/2;
2340       if ( wp->symbol_pixbuf )
2341         label_y = y - height - 2 - gdk_pixbuf_get_height(wp->symbol_pixbuf)/2;
2342       else
2343         label_y = y - dp->vtl->wp_size - height - 2;
2344
2345       /* if highlight mode on, then draw background text in highlight colour */
2346       if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
2347         if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ||
2348              dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) ||
2349              wp == vik_window_get_selected_waypoint ( dp->vw ) )
2350           vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2);
2351         else
2352           vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
2353       }
2354       else {
2355         vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
2356       }
2357       vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout );
2358     }
2359   }
2360 }
2361
2362 static void trw_layer_draw_waypoint_cb ( gpointer id, VikWaypoint *wp, struct DrawingParams *dp )
2363 {
2364   if ( BBOX_INTERSECT ( dp->vtl->waypoints_bbox, dp->bbox ) ) {
2365     trw_layer_draw_waypoint ( id, wp, dp );
2366   }
2367 }
2368
2369 static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
2370 {
2371   static struct DrawingParams dp;
2372   g_assert ( l != NULL );
2373
2374   init_drawing_params ( &dp, l, VIK_VIEWPORT(data) );
2375
2376   if ( l->tracks_visible )
2377     g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp );
2378
2379   if ( l->routes_visible )
2380     g_hash_table_foreach ( l->routes, (GHFunc) trw_layer_draw_track_cb, &dp );
2381
2382   if (l->waypoints_visible)
2383     g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint_cb, &dp );
2384 }
2385
2386 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
2387 {
2388   int i;
2389   if ( vtl->track_bg_gc ) 
2390   {
2391     g_object_unref ( vtl->track_bg_gc );
2392     vtl->track_bg_gc = NULL;
2393   }
2394   if ( vtl->track_1color_gc )
2395   {
2396     g_object_unref ( vtl->track_1color_gc );
2397     vtl->track_1color_gc = NULL;
2398   }
2399   if ( vtl->current_track_gc ) 
2400   {
2401     g_object_unref ( vtl->current_track_gc );
2402     vtl->current_track_gc = NULL;
2403   }
2404   if ( vtl->current_track_newpoint_gc )
2405   {
2406     g_object_unref ( vtl->current_track_newpoint_gc );
2407     vtl->current_track_newpoint_gc = NULL;
2408   }
2409
2410   if ( ! vtl->track_gc )
2411     return;
2412   for ( i = vtl->track_gc->len - 1; i >= 0; i-- )
2413     g_object_unref ( g_array_index ( vtl->track_gc, GObject *, i ) );
2414   g_array_free ( vtl->track_gc, TRUE );
2415   vtl->track_gc = NULL;
2416 }
2417
2418 static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
2419 {
2420   GdkGC *gc[ VIK_TRW_LAYER_TRACK_GC ];
2421   gint width = vtl->line_thickness;
2422
2423   if ( vtl->track_gc )
2424     trw_layer_free_track_gcs ( vtl );
2425
2426   if ( vtl->track_bg_gc )
2427     g_object_unref ( vtl->track_bg_gc );
2428   vtl->track_bg_gc = vik_viewport_new_gc_from_color ( vp, &(vtl->track_bg_color), width + vtl->bg_line_thickness );
2429
2430   // Ensure new track drawing heeds line thickness setting
2431   //  however always have a minium of 2, as 1 pixel is really narrow
2432   gint new_track_width = (vtl->line_thickness < 2) ? 2 : vtl->line_thickness;
2433   
2434   if ( vtl->current_track_gc )
2435     g_object_unref ( vtl->current_track_gc );
2436   vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
2437   gdk_gc_set_line_attributes ( vtl->current_track_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
2438
2439   // 'newpoint' gc is exactly the same as the current track gc
2440   if ( vtl->current_track_newpoint_gc )
2441     g_object_unref ( vtl->current_track_newpoint_gc );
2442   vtl->current_track_newpoint_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
2443   gdk_gc_set_line_attributes ( vtl->current_track_newpoint_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
2444
2445   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
2446
2447   gc[VIK_TRW_LAYER_TRACK_GC_STOP] = vik_viewport_new_gc ( vp, "#874200", width );
2448   gc[VIK_TRW_LAYER_TRACK_GC_BLACK] = vik_viewport_new_gc ( vp, "#000000", width ); // black
2449
2450   gc[VIK_TRW_LAYER_TRACK_GC_SLOW] = vik_viewport_new_gc ( vp, "#E6202E", width ); // red-ish
2451   gc[VIK_TRW_LAYER_TRACK_GC_AVER] = vik_viewport_new_gc ( vp, "#D2CD26", width ); // yellow-ish
2452   gc[VIK_TRW_LAYER_TRACK_GC_FAST] = vik_viewport_new_gc ( vp, "#2B8700", width ); // green-ish
2453
2454   gc[VIK_TRW_LAYER_TRACK_GC_SINGLE] = vik_viewport_new_gc_from_color ( vp, &(vtl->track_color), width );
2455
2456   g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
2457 }
2458
2459 static VikTrwLayer* trw_layer_create ( VikViewport *vp )
2460 {
2461   VikTrwLayer *rv = trw_layer_new1 ( vp );
2462   vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
2463
2464   if ( vp == NULL || gtk_widget_get_window(GTK_WIDGET(vp)) == NULL ) {
2465     /* early exit, as the rest is GUI related */
2466     return rv;
2467   }
2468
2469   rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
2470   pango_layout_set_font_description (rv->wplabellayout, gtk_widget_get_style(GTK_WIDGET(vp))->font_desc);
2471
2472   rv->tracklabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
2473   pango_layout_set_font_description (rv->tracklabellayout, gtk_widget_get_style(GTK_WIDGET(vp))->font_desc);
2474
2475   trw_layer_new_track_gcs ( rv, vp );
2476
2477   rv->waypoint_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_color), 2 );
2478   rv->waypoint_text_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_text_color), 1 );
2479   rv->waypoint_bg_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_bg_color), 1 );
2480   gdk_gc_set_function ( rv->waypoint_bg_gc, rv->wpbgand );
2481
2482   rv->coord_mode = vik_viewport_get_coord_mode ( vp );
2483
2484   rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection;
2485
2486   return rv;
2487 }
2488
2489 #define SMALL_ICON_SIZE 18
2490 /*
2491  * Can accept a null symbol, and may return null value
2492  */
2493 GdkPixbuf* get_wp_sym_small ( gchar *symbol )
2494 {
2495   GdkPixbuf* wp_icon = a_get_wp_sym (symbol);
2496   // ATM a_get_wp_sym returns a cached icon, with the size dependent on the preferences.
2497   //  So needing a small icon for the treeview may need some resizing:
2498   if ( wp_icon && gdk_pixbuf_get_width ( wp_icon ) != SMALL_ICON_SIZE )
2499     wp_icon = gdk_pixbuf_scale_simple ( wp_icon, SMALL_ICON_SIZE, SMALL_ICON_SIZE, GDK_INTERP_BILINEAR );
2500   return wp_icon;
2501 }
2502
2503 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] )
2504 {
2505   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
2506
2507   GdkPixbuf *pixbuf = NULL;
2508
2509   if ( track->has_color ) {
2510     pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, SMALL_ICON_SIZE, SMALL_ICON_SIZE );
2511     // Annoyingly the GdkColor.pixel does not give the correct color when passed to gdk_pixbuf_fill (even when alloc'ed)
2512     // Here is some magic found to do the conversion
2513     // http://www.cs.binghamton.edu/~sgreene/cs360-2011s/topics/gtk+-2.20.1/gtk/gtkcolorbutton.c
2514     guint32 pixel = ((track->color.red & 0xff00) << 16) |
2515       ((track->color.green & 0xff00) << 8) |
2516       (track->color.blue & 0xff00);
2517
2518     gdk_pixbuf_fill ( pixbuf, pixel );
2519   }
2520
2521   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE );
2522
2523   if ( pixbuf )
2524     g_object_unref (pixbuf);
2525
2526   *new_iter = *((GtkTreeIter *) pass_along[1]);
2527   if ( track->is_route )
2528     g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->routes_iters, id, new_iter );
2529   else
2530     g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, id, new_iter );
2531
2532   if ( ! track->visible )
2533     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
2534 }
2535
2536 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] )
2537 {
2538   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
2539
2540   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
2541
2542   *new_iter = *((GtkTreeIter *) pass_along[1]);
2543   g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter );
2544
2545   if ( ! wp->visible )
2546     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
2547 }
2548
2549 static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2550 {
2551   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
2552 }
2553
2554 static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2555 {
2556   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
2557 }
2558
2559 static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2560 {
2561   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE );
2562 }
2563
2564 static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2565 {
2566   GtkTreeIter iter2;
2567   gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACK) };
2568
2569   if ( g_hash_table_size (vtl->tracks) > 0 ) {
2570     trw_layer_add_sublayer_tracks ( vtl, vt , layer_iter );
2571
2572     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
2573
2574     vik_treeview_item_set_visible ( vt, &(vtl->tracks_iter), vtl->tracks_visible );
2575   }
2576
2577   if ( g_hash_table_size (vtl->routes) > 0 ) {
2578     trw_layer_add_sublayer_routes ( vtl, vt, layer_iter );
2579
2580     pass_along[0] = &(vtl->routes_iter);
2581     pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTE);
2582
2583     g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_realize_track, pass_along );
2584
2585     vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->routes_iter), vtl->routes_visible );
2586   }
2587
2588   if ( g_hash_table_size (vtl->waypoints) > 0 ) {
2589     trw_layer_add_sublayer_waypoints ( vtl, vt, layer_iter );
2590
2591     pass_along[0] = &(vtl->waypoints_iter);
2592     pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
2593
2594     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
2595
2596     vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), vtl->waypoints_visible );
2597   }
2598
2599 }
2600
2601 static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
2602 {
2603   switch ( subtype )
2604   {
2605     case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1);
2606     case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1);
2607     case VIK_TRW_LAYER_SUBLAYER_ROUTES: return (l->routes_visible ^= 1);
2608     case VIK_TRW_LAYER_SUBLAYER_TRACK:
2609     {
2610       VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer );
2611       if (t)
2612         return (t->visible ^= 1);
2613       else
2614         return TRUE;
2615     }
2616     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
2617     {
2618       VikWaypoint *t = g_hash_table_lookup ( l->waypoints, sublayer );
2619       if (t)
2620         return (t->visible ^= 1);
2621       else
2622         return TRUE;
2623     }
2624     case VIK_TRW_LAYER_SUBLAYER_ROUTE:
2625     {
2626       VikTrack *t = g_hash_table_lookup ( l->routes, sublayer );
2627       if (t)
2628         return (t->visible ^= 1);
2629       else
2630         return TRUE;
2631     }
2632   }
2633   return TRUE;
2634 }
2635
2636 /*
2637  * Return a property about tracks for this layer
2638  */
2639 gint vik_trw_layer_get_property_tracks_line_thickness ( VikTrwLayer *vtl )
2640 {
2641   return vtl->line_thickness;
2642 }
2643
2644 // Structure to hold multiple track information for a layer
2645 typedef struct {
2646   gdouble length;
2647   time_t  start_time;
2648   time_t  end_time;
2649   gint    duration;
2650 } tooltip_tracks;
2651
2652 /*
2653  * Build up layer multiple track information via updating the tooltip_tracks structure
2654  */
2655 static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_tracks *tt )
2656 {
2657   tt->length = tt->length + vik_track_get_length (tr);
2658
2659   // Ensure times are available
2660   if ( tr->trackpoints &&
2661        vik_track_get_tp_first(tr)->has_timestamp &&
2662        vik_track_get_tp_last(tr)->has_timestamp ) {
2663
2664     time_t t1, t2;
2665     t1 = vik_track_get_tp_first(tr)->timestamp;
2666     t2 = vik_track_get_tp_last(tr)->timestamp;
2667
2668     // Assume never actually have a track with a time of 0 (1st Jan 1970)
2669     // Hence initialize to the first 'proper' value
2670     if ( tt->start_time == 0 )
2671         tt->start_time = t1;
2672     if ( tt->end_time == 0 )
2673         tt->end_time = t2;
2674
2675     // Update find the earliest / last times
2676     if ( t1 < tt->start_time )
2677         tt->start_time = t1;
2678     if ( t2 > tt->end_time )
2679         tt->end_time = t2;
2680
2681     // Keep track of total time
2682     //  there maybe gaps within a track (eg segments)
2683     //  but this should be generally good enough for a simple indicator
2684     tt->duration = tt->duration + (int)(t2-t1);
2685   }
2686 }
2687
2688 /*
2689  * Generate tooltip text for the layer.
2690  * This is relatively complicated as it considers information for
2691  *   no tracks, a single track or multiple tracks
2692  *     (which may or may not have timing information)
2693  */
2694 static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
2695 {
2696   gchar tbuf1[32];
2697   gchar tbuf2[64];
2698   gchar tbuf3[64];
2699   gchar tbuf4[10];
2700   tbuf1[0] = '\0';
2701   tbuf2[0] = '\0';
2702   tbuf3[0] = '\0';
2703   tbuf4[0] = '\0';
2704
2705   static gchar tmp_buf[128];
2706   tmp_buf[0] = '\0';
2707
2708   // For compact date format I'm using '%x'     [The preferred date representation for the current locale without the time.]
2709
2710   // Safety check - I think these should always be valid
2711   if ( vtl->tracks && vtl->waypoints ) {
2712     tooltip_tracks tt = { 0.0, 0, 0 };
2713     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_tooltip, &tt );
2714
2715     GDate* gdate_start = g_date_new ();
2716     g_date_set_time_t (gdate_start, tt.start_time);
2717
2718     GDate* gdate_end = g_date_new ();
2719     g_date_set_time_t (gdate_end, tt.end_time);
2720
2721     if ( g_date_compare (gdate_start, gdate_end) ) {
2722       // Dates differ so print range on separate line
2723       g_date_strftime (tbuf1, sizeof(tbuf1), "%x", gdate_start);
2724       g_date_strftime (tbuf2, sizeof(tbuf2), "%x", gdate_end);
2725       g_snprintf (tbuf3, sizeof(tbuf3), "%s to %s\n", tbuf1, tbuf2);
2726     }
2727     else {
2728       // Same date so just show it and keep rest of text on the same line - provided it's a valid time!
2729       if ( tt.start_time != 0 )
2730         g_date_strftime (tbuf3, sizeof(tbuf3), "%x: ", gdate_start);
2731     }
2732
2733     tbuf2[0] = '\0';
2734     if ( tt.length > 0.0 ) {
2735       gdouble len_in_units;
2736
2737       // Setup info dependent on distance units
2738       if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) {
2739         g_snprintf (tbuf4, sizeof(tbuf4), "miles");
2740         len_in_units = VIK_METERS_TO_MILES(tt.length);
2741       }
2742       else {
2743         g_snprintf (tbuf4, sizeof(tbuf4), "kms");
2744         len_in_units = tt.length/1000.0;
2745       }
2746
2747       // Timing information if available
2748       tbuf1[0] = '\0';
2749       if ( tt.duration > 0 ) {
2750         g_snprintf (tbuf1, sizeof(tbuf1),
2751                     _(" in %d:%02d hrs:mins"),
2752                     (int)round(tt.duration/3600), (int)round((tt.duration/60)%60));
2753       }
2754       g_snprintf (tbuf2, sizeof(tbuf2),
2755                   _("\n%sTotal Length %.1f %s%s"),
2756                   tbuf3, len_in_units, tbuf4, tbuf1);
2757     }
2758
2759     // Put together all the elements to form compact tooltip text
2760     g_snprintf (tmp_buf, sizeof(tmp_buf),
2761                 _("Tracks: %d - Waypoints: %d - Routes: %d%s"),
2762                 g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2);
2763
2764     g_date_free (gdate_start);
2765     g_date_free (gdate_end);
2766
2767   }
2768
2769   return tmp_buf;
2770 }
2771
2772 static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer )
2773 {
2774   switch ( subtype )
2775   {
2776     case VIK_TRW_LAYER_SUBLAYER_TRACKS:
2777     {
2778       // Very simple tooltip - may expand detail in the future...
2779       static gchar tmp_buf[32];
2780       g_snprintf (tmp_buf, sizeof(tmp_buf),
2781                   _("Tracks: %d"),
2782                   g_hash_table_size (l->tracks));
2783       return tmp_buf;
2784     }
2785     break;
2786     case VIK_TRW_LAYER_SUBLAYER_ROUTES:
2787     {
2788       // Very simple tooltip - may expand detail in the future...
2789       static gchar tmp_buf[32];
2790       g_snprintf (tmp_buf, sizeof(tmp_buf),
2791                   _("Routes: %d"),
2792                   g_hash_table_size (l->routes));
2793       return tmp_buf;
2794     }
2795     break;
2796
2797     case VIK_TRW_LAYER_SUBLAYER_ROUTE:
2798       // Same tooltip for a route
2799     case VIK_TRW_LAYER_SUBLAYER_TRACK:
2800     {
2801       VikTrack *tr;
2802       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
2803         tr = g_hash_table_lookup ( l->tracks, sublayer );
2804       else
2805         tr = g_hash_table_lookup ( l->routes, sublayer );
2806
2807       if ( tr ) {
2808         // Could be a better way of handling strings - but this works...
2809         gchar time_buf1[20];
2810         gchar time_buf2[20];
2811         time_buf1[0] = '\0';
2812         time_buf2[0] = '\0';
2813         static gchar tmp_buf[100];
2814         // Compact info: Short date eg (11/20/99), duration and length
2815         // Hopefully these are the things that are most useful and so promoted into the tooltip
2816         if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) {
2817           // %x     The preferred date representation for the current locale without the time.
2818           strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(vik_track_get_tp_first(tr)->timestamp)));
2819           if ( vik_track_get_tp_last(tr)->has_timestamp ) {
2820             gint dur = ( (vik_track_get_tp_last(tr)->timestamp) - (vik_track_get_tp_first(tr)->timestamp) );
2821             if ( dur > 0 )
2822               g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
2823           }
2824         }
2825         // Get length and consider the appropriate distance units
2826         gdouble tr_len = vik_track_get_length(tr);
2827         vik_units_distance_t dist_units = a_vik_get_units_distance ();
2828         switch (dist_units) {
2829         case VIK_UNITS_DISTANCE_KILOMETRES:
2830           g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f km %s"), time_buf1, tr_len/1000.0, time_buf2);
2831           break;
2832         case VIK_UNITS_DISTANCE_MILES:
2833           g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, VIK_METERS_TO_MILES(tr_len), time_buf2);
2834           break;
2835         default:
2836           break;
2837         }
2838         return tmp_buf;
2839       }
2840     }
2841     break;
2842     case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
2843     {
2844       // Very simple tooltip - may expand detail in the future...
2845       static gchar tmp_buf[32];
2846       g_snprintf (tmp_buf, sizeof(tmp_buf),
2847                   _("Waypoints: %d"),
2848                   g_hash_table_size (l->waypoints));
2849       return tmp_buf;
2850     }
2851     break;
2852     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
2853     {
2854       VikWaypoint *w = g_hash_table_lookup ( l->waypoints, sublayer );
2855       // NB It's OK to return NULL
2856       if ( w ) {
2857         if ( w->comment )
2858           return w->comment;
2859         else
2860           return w->description;
2861       }
2862     }
2863     break;
2864     default: break;
2865   }
2866   return NULL;
2867 }
2868
2869 #define VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT "trkpt_selected_statusbar_format"
2870
2871 /**
2872  * set_statusbar_msg_info_trkpt:
2873  *
2874  * Function to show track point information on the statusbar
2875  *  Items displayed is controlled by the settings format code
2876  */
2877 static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt )
2878 {
2879   gchar *statusbar_format_code = NULL;
2880   gboolean need2free = FALSE;
2881   if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
2882     // Otherwise use default
2883     statusbar_format_code = g_strdup ( "KEATDN" );
2884     need2free = TRUE;
2885   }
2886
2887   gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, NULL, vtl->current_tp_track );
2888   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
2889   g_free ( msg );
2890
2891   if ( need2free )
2892     g_free ( statusbar_format_code );
2893 }
2894
2895 /*
2896  * Function to show basic waypoint information on the statusbar
2897  */
2898 static void set_statusbar_msg_info_wpt ( VikTrwLayer *vtl, VikWaypoint *wpt )
2899 {
2900   gchar tmp_buf1[64];
2901   switch (a_vik_get_units_height ()) {
2902   case VIK_UNITS_HEIGHT_FEET:
2903     g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(wpt->altitude)));
2904     break;
2905   default:
2906     //VIK_UNITS_HEIGHT_METRES:
2907     g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dm"), (int)round(wpt->altitude));
2908   }
2909   
2910   // Position part
2911   // Position is put last, as this bit is most likely not to be seen if the display is not big enough,
2912   //   one can easily use the current pointer position to see this if needed
2913   gchar *lat = NULL, *lon = NULL;
2914   static struct LatLon ll;
2915   vik_coord_to_latlon (&(wpt->coord), &ll);
2916   a_coords_latlon_to_string ( &ll, &lat, &lon );
2917
2918   // Combine parts to make overall message
2919   gchar *msg;
2920   if ( wpt->comment )
2921     // Add comment if available
2922     msg = g_strdup_printf ( _("%s | %s %s | Comment: %s"), tmp_buf1, lat, lon, wpt->comment );
2923   else
2924     msg = g_strdup_printf ( _("%s | %s %s"), tmp_buf1, lat, lon );
2925   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
2926   g_free ( lat );
2927   g_free ( lon );
2928   g_free ( msg );
2929 }
2930
2931 /**
2932  * General layer selection function, find out which bit is selected and take appropriate action
2933  */
2934 static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp )
2935 {
2936   // Reset
2937   l->current_wp    = NULL;
2938   l->current_wp_id = NULL;
2939   trw_layer_cancel_current_tp ( l, FALSE );
2940
2941   // Clear statusbar
2942   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l))), VIK_STATUSBAR_INFO, "" );
2943
2944   switch ( type )
2945     {
2946     case VIK_TREEVIEW_TYPE_LAYER:
2947       {
2948         vik_window_set_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l );
2949         /* Mark for redraw */
2950         return TRUE;
2951       }
2952       break;
2953
2954     case VIK_TREEVIEW_TYPE_SUBLAYER:
2955       {
2956         switch ( subtype )
2957           {
2958           case VIK_TRW_LAYER_SUBLAYER_TRACKS:
2959             {
2960               vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->tracks, l );
2961               /* Mark for redraw */
2962               return TRUE;
2963             }
2964             break;
2965           case VIK_TRW_LAYER_SUBLAYER_TRACK:
2966             {
2967               VikTrack *track = g_hash_table_lookup ( l->tracks, sublayer );
2968               vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l );
2969               /* Mark for redraw */
2970               return TRUE;
2971             }
2972             break;
2973           case VIK_TRW_LAYER_SUBLAYER_ROUTES:
2974             {
2975               vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->routes, l );
2976               /* Mark for redraw */
2977               return TRUE;
2978             }
2979             break;
2980           case VIK_TRW_LAYER_SUBLAYER_ROUTE:
2981             {
2982               VikTrack *track = g_hash_table_lookup ( l->routes, sublayer );
2983               vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l );
2984               /* Mark for redraw */
2985               return TRUE;
2986             }
2987             break;
2988           case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
2989             {
2990               vik_window_set_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->waypoints, l );
2991               /* Mark for redraw */
2992               return TRUE;
2993             }
2994             break;
2995           case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
2996             {
2997               VikWaypoint *wpt = g_hash_table_lookup ( l->waypoints, sublayer );
2998               if ( wpt ) {
2999                 vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)wpt, l );
3000                 // Show some waypoint info
3001                 set_statusbar_msg_info_wpt ( l, wpt );
3002                 /* Mark for redraw */
3003                 return TRUE;
3004               }
3005             }
3006             break;
3007           default:
3008             {
3009               return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
3010             }
3011             break;
3012           }
3013         return FALSE;
3014       }
3015       break;
3016
3017     default:
3018       return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
3019       break;
3020     }
3021 }
3022
3023 GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
3024 {
3025   return l->tracks;
3026 }
3027
3028 GHashTable *vik_trw_layer_get_routes ( VikTrwLayer *l )
3029 {
3030   return l->routes;
3031 }
3032
3033 GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l )
3034 {
3035   return l->waypoints;
3036 }
3037
3038 GHashTable *vik_trw_layer_get_tracks_iters ( VikTrwLayer *vtl )
3039 {
3040   return vtl->tracks_iters;
3041 }
3042
3043 GHashTable *vik_trw_layer_get_routes_iters ( VikTrwLayer *vtl )
3044 {
3045   return vtl->routes_iters;
3046 }
3047
3048 GHashTable *vik_trw_layer_get_waypoints_iters ( VikTrwLayer *vtl )
3049 {
3050   return vtl->waypoints;
3051 }
3052
3053 gboolean vik_trw_layer_is_empty ( VikTrwLayer *vtl )
3054 {
3055   return ! ( g_hash_table_size ( vtl->tracks ) ||
3056              g_hash_table_size ( vtl->routes ) ||
3057              g_hash_table_size ( vtl->waypoints ) );
3058 }
3059
3060 gboolean vik_trw_layer_get_tracks_visibility ( VikTrwLayer *vtl )
3061 {
3062   return vtl->tracks_visible;
3063 }
3064
3065 gboolean vik_trw_layer_get_routes_visibility ( VikTrwLayer *vtl )
3066 {
3067   return vtl->routes_visible;
3068 }
3069
3070 gboolean vik_trw_layer_get_waypoints_visibility ( VikTrwLayer *vtl )
3071 {
3072   return vtl->waypoints_visible;
3073 }
3074
3075 /*
3076  * ATM use a case sensitive find
3077  * Finds the first one
3078  */
3079 static gboolean trw_layer_waypoint_find ( const gpointer id, const VikWaypoint *wp, const gchar *name )
3080 {
3081   if ( wp && wp->name )
3082     if ( ! strcmp ( wp->name, name ) )
3083       return TRUE;
3084   return FALSE;
3085 }
3086
3087 /*
3088  * Get waypoint by name - not guaranteed to be unique
3089  * Finds the first one
3090  */
3091 VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, const gchar *name )
3092 {
3093   return g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find, (gpointer) name );
3094 }
3095
3096 /*
3097  * ATM use a case sensitive find
3098  * Finds the first one
3099  */
3100 static gboolean trw_layer_track_find ( const gpointer id, const VikTrack *trk, const gchar *name )
3101 {
3102   if ( trk && trk->name )
3103     if ( ! strcmp ( trk->name, name ) )
3104       return TRUE;
3105   return FALSE;
3106 }
3107
3108 /*
3109  * Get track by name - not guaranteed to be unique
3110  * Finds the first one
3111  */
3112 VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name )
3113 {
3114   return g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find, (gpointer) name );
3115 }
3116
3117 /*
3118  * Get route by name - not guaranteed to be unique
3119  * Finds the first one
3120  */
3121 VikTrack *vik_trw_layer_get_route ( VikTrwLayer *vtl, const gchar *name )
3122 {
3123   return g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find, (gpointer) name );
3124 }
3125
3126 static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] )
3127 {
3128   if ( trk->bbox.north > maxmin[0].lat || maxmin[0].lat == 0.0 )
3129     maxmin[0].lat = trk->bbox.north;
3130   if ( trk->bbox.south < maxmin[1].lat || maxmin[1].lat == 0.0 )
3131     maxmin[1].lat = trk->bbox.south;
3132   if ( trk->bbox.east > maxmin[0].lon || maxmin[0].lon == 0.0 )
3133     maxmin[0].lon = trk->bbox.east;
3134   if ( trk->bbox.west < maxmin[1].lon || maxmin[1].lon == 0.0 )
3135     maxmin[1].lon = trk->bbox.west;
3136 }
3137
3138 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2])
3139 {
3140   // Continually reuse maxmin to find the latest maximum and minimum values
3141   // First set to waypoints bounds
3142   maxmin[0].lat = vtl->waypoints_bbox.north;
3143   maxmin[1].lat = vtl->waypoints_bbox.south;
3144   maxmin[0].lon = vtl->waypoints_bbox.east;
3145   maxmin[1].lon = vtl->waypoints_bbox.west;
3146   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3147   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3148 }
3149
3150 gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
3151 {
3152   /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. like I don't have more important things to worry about... */
3153   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
3154   trw_layer_find_maxmin (vtl, maxmin);
3155   if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
3156     return FALSE;
3157   else
3158   {
3159     struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
3160     vik_coord_load_from_latlon ( dest, vtl->coord_mode, &average );
3161     return TRUE;
3162   }
3163 }
3164
3165 static void trw_layer_centerize ( menu_array_layer values )
3166 {
3167   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3168   VikCoord coord;
3169   if ( vik_trw_layer_find_center ( vtl, &coord ) )
3170     goto_coord ( values[MA_VLP], NULL, NULL, &coord );
3171   else
3172     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") );
3173 }
3174
3175 void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
3176 {
3177   /* First set the center [in case previously viewing from elsewhere] */
3178   /* Then loop through zoom levels until provided positions are in view */
3179   /* This method is not particularly fast - but should work well enough */
3180   struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
3181   VikCoord coord;
3182   vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
3183   vik_viewport_set_center_coord ( vvp, &coord );
3184
3185   /* Convert into definite 'smallest' and 'largest' positions */
3186   struct LatLon minmin;
3187   if ( maxmin[0].lat < maxmin[1].lat )
3188     minmin.lat = maxmin[0].lat;
3189   else
3190     minmin.lat = maxmin[1].lat;
3191
3192   struct LatLon maxmax;
3193   if ( maxmin[0].lon > maxmin[1].lon )
3194     maxmax.lon = maxmin[0].lon;
3195   else
3196     maxmax.lon = maxmin[1].lon;
3197
3198   /* Never zoom in too far - generally not that useful, as too close ! */
3199   /* Always recalculate the 'best' zoom level */
3200   gdouble zoom = 1.0;
3201   vik_viewport_set_zoom ( vvp, zoom );
3202
3203   gdouble min_lat, max_lat, min_lon, max_lon;
3204   /* Should only be a maximum of about 18 iterations from min to max zoom levels */
3205   while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
3206     vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
3207     /* NB I think the logic used in this test to determine if the bounds is within view
3208        fails if track goes across 180 degrees longitude.
3209        Hopefully that situation is not too common...
3210        Mind you viking doesn't really do edge locations to well anyway */
3211     if ( min_lat < minmin.lat &&
3212          max_lat > minmin.lat &&
3213          min_lon < maxmax.lon &&
3214          max_lon > maxmax.lon )
3215       /* Found within zoom level */
3216       break;
3217
3218     /* Try next */
3219     zoom = zoom * 2;
3220     vik_viewport_set_zoom ( vvp, zoom );
3221   }
3222 }
3223
3224 gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp )
3225 {
3226   /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. */
3227   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
3228   trw_layer_find_maxmin (vtl, maxmin);
3229   if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
3230     return FALSE;
3231   else {
3232     trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin );
3233     return TRUE;
3234   }
3235 }
3236
3237 static void trw_layer_auto_view ( menu_array_layer values )
3238 {
3239   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3240   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3241   if ( vik_trw_layer_auto_set_view ( vtl, vik_layers_panel_get_viewport (vlp) ) ) {
3242     vik_layers_panel_emit_update ( vlp );
3243   }
3244   else
3245     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") );
3246 }
3247
3248 static void trw_layer_export ( menu_array_layer values, const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type )
3249 {
3250   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3251   GtkWidget *file_selector;
3252   const gchar *fn;
3253   gboolean failed = FALSE;
3254   file_selector = gtk_file_chooser_dialog_new (title,
3255                                                NULL,
3256                                                GTK_FILE_CHOOSER_ACTION_SAVE,
3257                                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3258                                                GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
3259                                                NULL);
3260   gchar *cwd = g_get_current_dir();
3261   if ( cwd ) {
3262     gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(file_selector), cwd );
3263     g_free ( cwd );
3264   }
3265
3266   gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name);
3267
3268   while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT )
3269   {
3270     fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) );
3271     if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE ||
3272          a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
3273     {
3274       gtk_widget_hide ( file_selector );
3275       vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3276       failed = ! a_file_export ( vtl, fn, file_type, trk, TRUE );
3277       vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3278       break;
3279     }
3280   }
3281   gtk_widget_destroy ( file_selector );
3282   if ( failed )
3283     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("The filename you requested could not be opened for writing.") );
3284 }
3285
3286 static void trw_layer_export_gpspoint ( menu_array_layer values )
3287 {
3288   trw_layer_export ( values, _("Export Layer"), vik_layer_get_name(VIK_LAYER(values[MA_VTL])), NULL, FILE_TYPE_GPSPOINT );
3289 }
3290
3291 static void trw_layer_export_gpsmapper ( menu_array_layer values )
3292 {
3293   trw_layer_export ( values, _("Export Layer"), vik_layer_get_name(VIK_LAYER(values[MA_VTL])), NULL, FILE_TYPE_GPSMAPPER );
3294 }
3295
3296 static void trw_layer_export_gpx ( menu_array_layer values )
3297 {
3298   /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
3299   gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])) );
3300   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
3301     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
3302
3303   trw_layer_export ( values, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
3304
3305   g_free ( auto_save_name );
3306 }
3307
3308 static void trw_layer_export_kml ( menu_array_layer values )
3309 {
3310   /* Auto append '.kml' to the name (providing it's not already there) for the default filename */
3311   gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])) );
3312   if ( ! check_file_ext ( auto_save_name, ".kml" ) )
3313     auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL );
3314
3315   trw_layer_export ( values, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
3316
3317   g_free ( auto_save_name );
3318 }
3319
3320 /**
3321  * Convert the given TRW layer into a temporary GPX file and open it with the specified program
3322  *
3323  */
3324 static void trw_layer_export_external_gpx ( menu_array_layer values, const gchar* external_program )
3325 {
3326   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3327   gchar *name_used = NULL;
3328   int fd;
3329
3330   if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) {
3331     vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3332     gboolean failed = ! a_file_export ( vtl, name_used, FILE_TYPE_GPX, NULL, TRUE);
3333     vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3334     if (failed) {
3335       a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not create temporary file for export.") );
3336     }
3337     else {
3338       GError *err = NULL;
3339       gchar *quoted_file = g_shell_quote ( name_used );
3340       gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file );
3341       g_free ( quoted_file );
3342       if ( ! g_spawn_command_line_async ( cmd, &err ) )
3343       {
3344         a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s."), external_program );
3345         g_error_free ( err );
3346       }
3347       g_free ( cmd );
3348     }
3349     // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous
3350     //g_remove ( name_used );
3351     // Perhaps should be deleted when the program ends?
3352     // For now leave it to the user to delete it / use system temp cleanup methods.
3353     g_free ( name_used );
3354   }
3355 }
3356
3357 static void trw_layer_export_external_gpx_1 ( menu_array_layer values )
3358 {
3359   trw_layer_export_external_gpx ( values, a_vik_get_external_gpx_program_1() );
3360 }
3361
3362 static void trw_layer_export_external_gpx_2 ( menu_array_layer values )
3363 {
3364   trw_layer_export_external_gpx ( values, a_vik_get_external_gpx_program_2() );
3365 }
3366
3367 static void trw_layer_export_gpx_track ( menu_array_sublayer values )
3368 {
3369   menu_array_layer data;
3370   data[MA_VTL] = values[MA_VTL];
3371   data[MA_VLP] = values[MA_VLP];
3372
3373   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3374   VikTrack *trk;
3375   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
3376     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
3377   else
3378     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
3379
3380   if ( !trk || !trk->name )
3381     return;
3382
3383   /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
3384   gchar *auto_save_name = g_strdup ( trk->name );
3385   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
3386     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
3387
3388   gchar *label = NULL;
3389   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
3390     label = _("Export Route as GPX");
3391   else
3392     label = _("Export Track as GPX");
3393   trw_layer_export ( data, label, auto_save_name, trk, FILE_TYPE_GPX );
3394
3395   g_free ( auto_save_name );
3396 }
3397
3398 gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata )
3399 {
3400   wpu_udata *user_data = udata;
3401   if ( wp == user_data->wp ) {
3402     user_data->uuid = id;
3403     return TRUE;
3404   }
3405   return FALSE;
3406 }
3407
3408 static void trw_layer_goto_wp ( menu_array_layer values )
3409 {
3410   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3411   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3412   GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
3413                                                  VIK_GTK_WINDOW_FROM_LAYER(vtl),
3414                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3415                                                  GTK_STOCK_CANCEL,
3416                                                  GTK_RESPONSE_REJECT,
3417                                                  GTK_STOCK_OK,
3418                                                  GTK_RESPONSE_ACCEPT,
3419                                                  NULL);
3420
3421   GtkWidget *label, *entry;
3422   label = gtk_label_new(_("Waypoint Name:"));
3423   entry = gtk_entry_new();
3424
3425   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), label, FALSE, FALSE, 0);
3426   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), entry, FALSE, FALSE, 0);
3427   gtk_widget_show_all ( label );
3428   gtk_widget_show_all ( entry );
3429
3430   gtk_dialog_set_default_response ( GTK_DIALOG(dia), GTK_RESPONSE_ACCEPT );
3431
3432   while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
3433   {
3434     gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
3435     // Find *first* wp with the given name
3436     VikWaypoint *wp = vik_trw_layer_get_waypoint ( vtl, name );
3437
3438     if ( !wp )
3439       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Waypoint not found in this layer.") );
3440     else
3441     {
3442       vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), &(wp->coord) );
3443       vik_layers_panel_emit_update ( vlp );
3444
3445       // Find and select on the side panel
3446       wpu_udata udata;
3447       udata.wp   = wp;
3448       udata.uuid = NULL;
3449
3450       // Hmmm, want key of it
3451       gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
3452
3453       if ( wpf && udata.uuid ) {
3454         GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
3455         vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, it, TRUE );
3456       }
3457
3458       break;
3459     }
3460
3461     g_free ( name );
3462
3463   }
3464   gtk_widget_destroy ( dia );
3465 }
3466
3467 gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
3468 {
3469   gchar *default_name = highest_wp_number_get(vtl);
3470   VikWaypoint *wp = vik_waypoint_new();
3471   gchar *returned_name;
3472   gboolean updated;
3473   wp->coord = *def_coord;
3474   
3475   // Attempt to auto set height if DEM data is available
3476   vik_waypoint_apply_dem_data ( wp, TRUE );
3477
3478   returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated );
3479
3480   if ( returned_name )
3481   {
3482     wp->visible = TRUE;
3483     vik_trw_layer_add_waypoint ( vtl, returned_name, wp );
3484     g_free (default_name);
3485     g_free (returned_name);
3486     return TRUE;
3487   }
3488   g_free (default_name);
3489   vik_waypoint_free(wp);
3490   return FALSE;
3491 }
3492
3493 static void trw_layer_new_wikipedia_wp_viewport ( menu_array_layer values )
3494 {
3495   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
3496   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3497   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3498   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3499   VikViewport *vvp =  vik_window_viewport(vw);
3500
3501   // Note the order is max part first then min part - thus reverse order of use in min_max function:
3502   vik_viewport_get_min_max_lat_lon ( vvp, &maxmin[1].lat, &maxmin[0].lat, &maxmin[1].lon, &maxmin[0].lon );
3503   a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin);
3504   trw_layer_calculate_bounds_waypoints ( vtl );
3505   vik_layers_panel_emit_update ( vlp );
3506 }
3507
3508 static void trw_layer_new_wikipedia_wp_layer ( menu_array_layer values )
3509 {
3510   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3511   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3512   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
3513   
3514   trw_layer_find_maxmin (vtl, maxmin);
3515   a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin);
3516   trw_layer_calculate_bounds_waypoints ( vtl );
3517   vik_layers_panel_emit_update ( vlp );
3518 }
3519
3520 #ifdef VIK_CONFIG_GEOTAG
3521 static void trw_layer_geotagging_waypoint_mtime_keep ( menu_array_sublayer values )
3522 {
3523   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->waypoints, values[MA_SUBLAYER_ID] );
3524   if ( wp )
3525     // Update directly - not changing the mtime
3526     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE );
3527 }
3528
3529 static void trw_layer_geotagging_waypoint_mtime_update ( menu_array_sublayer values )
3530 {
3531   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->waypoints, values[MA_SUBLAYER_ID] );
3532   if ( wp )
3533     // Update directly
3534     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE );
3535 }
3536
3537 /*
3538  * Use code in separate file for this feature as reasonably complex
3539  */
3540 static void trw_layer_geotagging_track ( menu_array_sublayer values )
3541 {
3542   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3543   VikTrack *track = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
3544   // Unset so can be reverified later if necessary
3545   vtl->has_verified_thumbnails = FALSE;
3546
3547   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
3548                             vtl,
3549                             NULL,
3550                             track );
3551 }
3552
3553 static void trw_layer_geotagging_waypoint ( menu_array_sublayer values )
3554 {
3555   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3556   VikWaypoint *wpt = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
3557
3558   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
3559                             vtl,
3560                             wpt,
3561                             NULL );
3562 }
3563
3564 static void trw_layer_geotagging ( menu_array_layer values )
3565 {
3566   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3567   // Unset so can be reverified later if necessary
3568   vtl->has_verified_thumbnails = FALSE;
3569
3570   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
3571                             vtl,
3572                             NULL,
3573                             NULL );
3574 }
3575 #endif
3576
3577 // 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
3578
3579 static void trw_layer_acquire ( menu_array_layer values, VikDataSourceInterface *datasource )
3580 {
3581   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3582   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3583   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3584   VikViewport *vvp =  vik_window_viewport(vw);
3585
3586   a_acquire ( vw, vlp, vvp, datasource, NULL, NULL );
3587 }
3588
3589 /*
3590  * Acquire into this TRW Layer straight from GPS Device
3591  */
3592 static void trw_layer_acquire_gps_cb ( menu_array_layer values )
3593 {
3594   vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3595   trw_layer_acquire ( values, &vik_datasource_gps_interface );
3596 }
3597
3598 /*
3599  * Acquire into this TRW Layer from Directions
3600  */
3601 static void trw_layer_acquire_routing_cb ( menu_array_layer values )
3602 {
3603   trw_layer_acquire ( values, &vik_datasource_routing_interface );
3604 }
3605
3606 /*
3607  * Acquire into this TRW Layer from an entered URL
3608  */
3609 static void trw_layer_acquire_url_cb ( menu_array_layer values )
3610 {
3611   vik_datasource_url_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3612   trw_layer_acquire ( values, &vik_datasource_url_interface );
3613 }
3614
3615 #ifdef VIK_CONFIG_OPENSTREETMAP
3616 /*
3617  * Acquire into this TRW Layer from OSM
3618  */
3619 static void trw_layer_acquire_osm_cb ( menu_array_layer values )
3620 {
3621   trw_layer_acquire ( values, &vik_datasource_osm_interface );
3622 }
3623
3624 /**
3625  * Acquire into this TRW Layer from OSM for 'My' Traces
3626  */
3627 static void trw_layer_acquire_osm_my_traces_cb ( menu_array_layer values )
3628 {
3629   trw_layer_acquire ( values, &vik_datasource_osm_my_traces_interface );
3630 }
3631 #endif
3632
3633 #ifdef VIK_CONFIG_GEOCACHES
3634 /*
3635  * Acquire into this TRW Layer from Geocaching.com
3636  */
3637 static void trw_layer_acquire_geocache_cb ( menu_array_layer values )
3638 {
3639   trw_layer_acquire ( values, &vik_datasource_gc_interface );
3640 }
3641 #endif
3642
3643 #ifdef VIK_CONFIG_GEOTAG
3644 /*
3645  * Acquire into this TRW Layer from images
3646  */
3647 static void trw_layer_acquire_geotagged_cb ( menu_array_layer values )
3648 {
3649   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3650
3651   vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3652   trw_layer_acquire ( values, &vik_datasource_geotag_interface );
3653
3654   // Reverify thumbnails as they may have changed
3655   vtl->has_verified_thumbnails = FALSE;
3656   trw_layer_verify_thumbnails ( vtl, NULL );
3657 }
3658 #endif
3659
3660 static void trw_layer_gps_upload ( menu_array_layer values )
3661 {
3662   menu_array_sublayer data;
3663   gint ii;
3664   for ( ii = MA_VTL; ii < MA_LAST; ii++ )
3665     data[ii] = NULL;
3666   data[MA_VTL] = values[MA_VTL];
3667   data[MA_VLP] = values[MA_VLP];
3668
3669   trw_layer_gps_upload_any ( data );
3670 }
3671
3672 /**
3673  * If pass_along[3] is defined that this will upload just that track
3674  */
3675 static void trw_layer_gps_upload_any ( menu_array_sublayer values )
3676 {
3677   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3678   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3679
3680   // May not actually get a track here as values[2&3] can be null
3681   VikTrack *track = NULL;
3682   vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
3683   gboolean xfer_all = FALSE;
3684
3685   if ( values[MA_SUBTYPE] ) {
3686     xfer_all = FALSE;
3687     if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
3688       track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
3689       xfer_type = RTE;
3690     }
3691     else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
3692       track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
3693       xfer_type = TRK;
3694     }
3695     else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) {
3696       xfer_type = WPT;
3697     }
3698     else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
3699       xfer_type = RTE;
3700     }
3701   }
3702   else if ( !values[MA_CONFIRM] )
3703     xfer_all = TRUE; // i.e. whole layer
3704
3705   if (track && !track->visible) {
3706     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") );
3707     return;
3708   }
3709
3710   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
3711                                                     VIK_GTK_WINDOW_FROM_LAYER(vtl),
3712                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
3713                                                     GTK_STOCK_OK,
3714                                                     GTK_RESPONSE_ACCEPT,
3715                                                     GTK_STOCK_CANCEL,
3716                                                     GTK_RESPONSE_REJECT,
3717                                                     NULL );
3718
3719   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
3720   GtkWidget *response_w = NULL;
3721 #if GTK_CHECK_VERSION (2, 20, 0)
3722   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
3723 #endif
3724
3725   if ( response_w )
3726     gtk_widget_grab_focus ( response_w );
3727
3728   gpointer dgs = datasource_gps_setup ( dialog, xfer_type, xfer_all );
3729
3730   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
3731     datasource_gps_clean_up ( dgs );
3732     gtk_widget_destroy ( dialog );
3733     return;
3734   }
3735
3736   // Get info from reused datasource dialog widgets
3737   gchar* protocol = datasource_gps_get_protocol ( dgs );
3738   gchar* port = datasource_gps_get_descriptor ( dgs );
3739   // NB don't free the above strings as they're references to values held elsewhere
3740   gboolean do_tracks = datasource_gps_get_do_tracks ( dgs );
3741   gboolean do_routes = datasource_gps_get_do_routes ( dgs );
3742   gboolean do_waypoints = datasource_gps_get_do_waypoints ( dgs );
3743   gboolean turn_off = datasource_gps_get_off ( dgs );
3744
3745   gtk_widget_destroy ( dialog );
3746
3747   // When called from the viewport - work the corresponding layerspanel:
3748   if ( !vlp ) {
3749     vlp = vik_window_layers_panel ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3750   }
3751
3752   // Apply settings to transfer to the GPS device
3753   vik_gps_comm ( vtl,
3754                  track,
3755                  GPS_UP,
3756                  protocol,
3757                  port,
3758                  FALSE,
3759                  vik_layers_panel_get_viewport (vlp),
3760                  vlp,
3761                  do_tracks,
3762                  do_routes,
3763                  do_waypoints,
3764                  turn_off );
3765 }
3766
3767 /*
3768  * Acquire into this TRW Layer from any GPS Babel supported file
3769  */
3770 static void trw_layer_acquire_file_cb ( menu_array_layer values )
3771 {
3772   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3773   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3774   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3775   VikViewport *vvp =  vik_window_viewport(vw);
3776
3777   a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL );
3778 }
3779
3780 static void trw_layer_new_wp ( menu_array_layer values )
3781 {
3782   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3783   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3784   /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
3785      instead return true if you want to update. */
3786   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 ) {
3787     trw_layer_calculate_bounds_waypoints ( vtl );
3788     vik_layers_panel_emit_update ( vlp );
3789   }
3790 }
3791
3792 static void new_track_create_common ( VikTrwLayer *vtl, gchar *name )
3793 {
3794   vtl->current_track = vik_track_new();
3795   vik_track_set_defaults ( vtl->current_track );
3796   vtl->current_track->visible = TRUE;
3797   if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR )
3798     // Create track with the preferred colour from the layer properties
3799     vtl->current_track->color = vtl->track_color;
3800   else
3801     gdk_color_parse ( "#000000", &(vtl->current_track->color) );
3802   vtl->current_track->has_color = TRUE;
3803   vik_trw_layer_add_track ( vtl, name, vtl->current_track );
3804 }
3805
3806 static void trw_layer_new_track ( menu_array_layer values )
3807 {
3808   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3809
3810   if ( ! vtl->current_track ) {
3811     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ;
3812     new_track_create_common ( vtl, name );
3813     g_free ( name );
3814
3815     vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
3816   }
3817 }
3818
3819 static void new_route_create_common ( VikTrwLayer *vtl, gchar *name )
3820 {
3821   vtl->current_track = vik_track_new();
3822   vik_track_set_defaults ( vtl->current_track );
3823   vtl->current_track->visible = TRUE;
3824   vtl->current_track->is_route = TRUE;
3825   // By default make all routes red
3826   vtl->current_track->has_color = TRUE;
3827   gdk_color_parse ( "red", &vtl->current_track->color );
3828   vik_trw_layer_add_route ( vtl, name, vtl->current_track );
3829 }
3830
3831 static void trw_layer_new_route ( menu_array_layer values )
3832 {
3833   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3834
3835   if ( ! vtl->current_track ) {
3836     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ;
3837     new_route_create_common ( vtl, name );
3838     g_free ( name );
3839     vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_ROUTE );
3840   }
3841 }
3842
3843 static void trw_layer_auto_routes_view ( menu_array_layer values )
3844 {
3845   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3846   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3847
3848   if ( g_hash_table_size (vtl->routes) > 0 ) {
3849     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3850     g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3851     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3852     vik_layers_panel_emit_update ( vlp );
3853   }
3854 }
3855
3856
3857 static void trw_layer_finish_track ( menu_array_layer values )
3858 {
3859   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3860   vtl->current_track = NULL;
3861   vik_layer_emit_update ( VIK_LAYER(vtl) );
3862 }
3863
3864 static void trw_layer_auto_tracks_view ( menu_array_layer values )
3865 {
3866   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3867   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3868
3869   if ( g_hash_table_size (vtl->tracks) > 0 ) {
3870     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3871     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3872     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3873     vik_layers_panel_emit_update ( vlp );
3874   }
3875 }
3876
3877 static void trw_layer_single_waypoint_jump ( const gpointer id, const VikWaypoint *wp, gpointer vvp )
3878 {
3879   /* NB do not care if wp is visible or not */
3880   vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
3881 }
3882
3883 static void trw_layer_auto_waypoints_view ( menu_array_layer values )
3884 {
3885   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
3886   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
3887
3888   /* Only 1 waypoint - jump straight to it */
3889   if ( g_hash_table_size (vtl->waypoints) == 1 ) {
3890     VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
3891     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
3892   }
3893   /* If at least 2 waypoints - find center and then zoom to fit */
3894   else if ( g_hash_table_size (vtl->waypoints) > 1 )
3895   {
3896     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3897     maxmin[0].lat = vtl->waypoints_bbox.north;
3898     maxmin[1].lat = vtl->waypoints_bbox.south;
3899     maxmin[0].lon = vtl->waypoints_bbox.east;
3900     maxmin[1].lon = vtl->waypoints_bbox.west;
3901     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3902   }
3903
3904   vik_layers_panel_emit_update ( vlp );
3905 }
3906
3907 void trw_layer_osm_traces_upload_cb ( menu_array_layer values )
3908 {
3909   osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), NULL);
3910 }
3911
3912 void trw_layer_osm_traces_upload_track_cb ( menu_array_sublayer values )
3913 {
3914   if ( values[MA_MISC] ) {
3915     VikTrack *trk = VIK_TRACK(values[MA_MISC]);
3916     osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), trk);
3917   }
3918 }
3919
3920 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
3921 {
3922   static menu_array_layer pass_along;
3923   GtkWidget *item;
3924   GtkWidget *export_submenu;
3925   pass_along[MA_VTL] = vtl;
3926   pass_along[MA_VLP] = vlp;
3927
3928   item = gtk_menu_item_new();
3929   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3930   gtk_widget_show ( item );
3931
3932   if ( vtl->current_track ) {
3933     if ( vtl->current_track->is_route )
3934       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
3935     else
3936       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
3937     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
3938     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3939     gtk_widget_show ( item );
3940
3941     // Add separator
3942     item = gtk_menu_item_new ();
3943     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3944     gtk_widget_show ( item );
3945   }
3946
3947   /* Now with icons */
3948   item = gtk_image_menu_item_new_with_mnemonic ( _("_View Layer") );
3949   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
3950   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
3951   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3952   gtk_widget_show ( item );
3953
3954   GtkWidget *view_submenu = gtk_menu_new();
3955   item = gtk_image_menu_item_new_with_mnemonic ( _("V_iew") );
3956   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
3957   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3958   gtk_widget_show ( item );
3959   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), view_submenu );
3960
3961   item = gtk_menu_item_new_with_mnemonic ( _("View All _Tracks") );
3962   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
3963   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3964   gtk_widget_show ( item );
3965
3966   item = gtk_menu_item_new_with_mnemonic ( _("View All _Routes") );
3967   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
3968   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3969   gtk_widget_show ( item );
3970
3971   item = gtk_menu_item_new_with_mnemonic ( _("View All _Waypoints") );
3972   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
3973   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3974   gtk_widget_show ( item );
3975
3976   item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
3977   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
3978   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
3979   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3980   gtk_widget_show ( item );
3981
3982   item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
3983   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
3984   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3985   gtk_widget_show ( item );
3986
3987   export_submenu = gtk_menu_new ();
3988   item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Layer") );
3989   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
3990   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3991   gtk_widget_show ( item );
3992   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
3993   
3994   item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point...") );
3995   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
3996   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3997   gtk_widget_show ( item );
3998
3999   item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper...") );
4000   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
4001   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
4002   gtk_widget_show ( item );
4003
4004   item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX...") );
4005   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
4006   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
4007   gtk_widget_show ( item );
4008
4009   item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
4010   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
4011   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
4012   gtk_widget_show ( item );
4013
4014   gchar* external1 = g_strdup_printf ( _("Open with External Program_1: %s"), a_vik_get_external_gpx_program_1() );
4015   item = gtk_menu_item_new_with_mnemonic ( external1 );
4016   g_free ( external1 );
4017   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along );
4018   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
4019   gtk_widget_show ( item );
4020
4021   gchar* external2 = g_strdup_printf ( _("Open with External Program_2: %s"), a_vik_get_external_gpx_program_2() );
4022   item = gtk_menu_item_new_with_mnemonic ( external2 );
4023   g_free ( external2 );
4024   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along );
4025   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
4026   gtk_widget_show ( item );
4027
4028   GtkWidget *new_submenu = gtk_menu_new();
4029   item = gtk_image_menu_item_new_with_mnemonic ( _("_New") );
4030   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
4031   gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
4032   gtk_widget_show(item);
4033   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_submenu);
4034
4035   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Waypoint...") );
4036   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
4037   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
4038   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
4039   gtk_widget_show ( item );
4040
4041   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Track") );
4042   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
4043   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
4044   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
4045   gtk_widget_show ( item );
4046   // Make it available only when a new track *not* already in progress
4047   gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
4048
4049   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Route") );
4050   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
4051   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
4052   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
4053   gtk_widget_show ( item );
4054   // Make it available only when a new track *not* already in progress
4055   gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
4056
4057 #ifdef VIK_CONFIG_GEOTAG
4058   item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
4059   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging), pass_along );
4060   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4061   gtk_widget_show ( item );
4062 #endif
4063
4064   GtkWidget *acquire_submenu = gtk_menu_new ();
4065   item = gtk_image_menu_item_new_with_mnemonic ( _("_Acquire") );
4066   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU) );
4067   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4068   gtk_widget_show ( item );
4069   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), acquire_submenu );
4070   
4071   item = gtk_menu_item_new_with_mnemonic ( _("From _GPS...") );
4072   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_gps_cb), pass_along );
4073   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4074   gtk_widget_show ( item );
4075
4076   /* FIXME: only add menu when at least a routing engine has support for Directions */
4077   item = gtk_menu_item_new_with_mnemonic ( _("From _Directions...") );
4078   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_routing_cb), pass_along );
4079   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4080   gtk_widget_show ( item );
4081
4082 #ifdef VIK_CONFIG_OPENSTREETMAP
4083   item = gtk_menu_item_new_with_mnemonic ( _("From _OSM Traces...") );
4084   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_cb), pass_along );
4085   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4086   gtk_widget_show ( item );
4087
4088   item = gtk_menu_item_new_with_mnemonic ( _("From _My OSM Traces...") );
4089   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_my_traces_cb), pass_along );
4090   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4091   gtk_widget_show ( item );
4092 #endif
4093
4094   item = gtk_menu_item_new_with_mnemonic ( _("From _URL...") );
4095   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_url_cb), pass_along );
4096   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4097   gtk_widget_show ( item );
4098
4099 #ifdef VIK_CONFIG_GEONAMES
4100   GtkWidget *wikipedia_submenu = gtk_menu_new();
4101   item = gtk_image_menu_item_new_with_mnemonic ( _("From _Wikipedia Waypoints") );
4102   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
4103   gtk_menu_shell_append(GTK_MENU_SHELL (acquire_submenu), item);
4104   gtk_widget_show(item);
4105   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), wikipedia_submenu);
4106
4107   item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
4108   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
4109   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along );
4110   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
4111   gtk_widget_show ( item );
4112
4113   item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Current View") );
4114   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU) );
4115   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along );
4116   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
4117   gtk_widget_show ( item );
4118 #endif
4119
4120 #ifdef VIK_CONFIG_GEOCACHES
4121   item = gtk_menu_item_new_with_mnemonic ( _("From Geo_caching...") );
4122   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geocache_cb), pass_along );
4123   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4124   gtk_widget_show ( item );
4125 #endif
4126
4127 #ifdef VIK_CONFIG_GEOTAG
4128   item = gtk_menu_item_new_with_mnemonic ( _("From Geotagged _Images...") );
4129   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geotagged_cb), pass_along );
4130   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4131   gtk_widget_show ( item );
4132 #endif
4133
4134   item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
4135   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
4136   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
4137   gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
4138   gtk_widget_show ( item );
4139
4140   vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) );
4141
4142   GtkWidget *upload_submenu = gtk_menu_new ();
4143   item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
4144   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
4145   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4146   gtk_widget_show ( item );
4147   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
4148
4149   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") );
4150   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
4151   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along );
4152   gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
4153   gtk_widget_show ( item );
4154
4155 #ifdef VIK_CONFIG_OPENSTREETMAP 
4156   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
4157   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
4158   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_cb), pass_along );
4159   gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
4160   gtk_widget_show ( item );
4161 #endif
4162
4163   GtkWidget *delete_submenu = gtk_menu_new ();
4164   item = gtk_image_menu_item_new_with_mnemonic ( _("De_lete") );
4165   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4166   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4167   gtk_widget_show ( item );
4168   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
4169   
4170   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Tracks") );
4171   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4172   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
4173   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4174   gtk_widget_show ( item );
4175   
4176   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Tracks _From Selection...") );
4177   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4178   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
4179   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4180   gtk_widget_show ( item );
4181
4182   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
4183   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4184   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
4185   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4186   gtk_widget_show ( item );
4187
4188   item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
4189   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4190   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
4191   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4192   gtk_widget_show ( item );
4193   
4194   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") );
4195   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4196   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
4197   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4198   gtk_widget_show ( item );
4199   
4200   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Waypoints From _Selection...") );
4201   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4202   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
4203   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4204   gtk_widget_show ( item );
4205   
4206   item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
4207                                    vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
4208   if ( item ) {
4209     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4210     gtk_widget_show ( item );
4211   }  
4212
4213   item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
4214                                          vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
4215   if ( item ) {
4216     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4217     gtk_widget_show ( item );
4218   }
4219
4220   item = gtk_image_menu_item_new_with_mnemonic ( _("Track _List...") );
4221   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4222   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog), pass_along );
4223   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
4224   gtk_widget_show ( item );
4225   gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->tracks)+g_hash_table_size (vtl->routes)) );
4226
4227   item = gtk_image_menu_item_new_with_mnemonic ( _("_Waypoint List...") );
4228   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4229   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along );
4230   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
4231   gtk_widget_show ( item );
4232   gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->waypoints)) );
4233 }
4234
4235 // Fake Waypoint UUIDs vi simple increasing integer
4236 static guint wp_uuid = 0;
4237
4238 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
4239 {
4240   wp_uuid++;
4241
4242   vik_waypoint_set_name (wp, name);
4243
4244   if ( VIK_LAYER(vtl)->realized )
4245   {
4246     // Do we need to create the sublayer:
4247     if ( g_hash_table_size (vtl->waypoints) == 0 ) {
4248       trw_layer_add_sublayer_waypoints ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
4249     }
4250
4251     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
4252
4253     // Visibility column always needed for waypoints
4254     vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE );
4255
4256     // Actual setting of visibility dependent on the waypoint
4257     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
4258
4259     g_hash_table_insert ( vtl->waypoints_iters, GUINT_TO_POINTER(wp_uuid), iter );
4260
4261     // Sort now as post_read is not called on a realized waypoint
4262     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
4263   }
4264
4265   highest_wp_number_add_wp(vtl, name);
4266   g_hash_table_insert ( vtl->waypoints, GUINT_TO_POINTER(wp_uuid), wp );
4267  
4268 }
4269
4270 // Fake Track UUIDs vi simple increasing integer
4271 static guint tr_uuid = 0;
4272
4273 void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
4274 {
4275   tr_uuid++;
4276
4277   vik_track_set_name (t, name);
4278
4279   if ( VIK_LAYER(vtl)->realized )
4280   {
4281     // Do we need to create the sublayer:
4282     if ( g_hash_table_size (vtl->tracks) == 0 ) {
4283       trw_layer_add_sublayer_tracks ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
4284     }
4285
4286     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
4287     // Visibility column always needed for tracks
4288     vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
4289
4290     // Actual setting of visibility dependent on the track
4291     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
4292
4293     g_hash_table_insert ( vtl->tracks_iters, GUINT_TO_POINTER(tr_uuid), iter );
4294
4295     // Sort now as post_read is not called on a realized track
4296     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
4297   }
4298
4299   g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t );
4300
4301   trw_layer_update_treeview ( vtl, t );
4302 }
4303
4304 // Fake Route UUIDs vi simple increasing integer
4305 static guint rt_uuid = 0;
4306
4307 void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
4308 {
4309   rt_uuid++;
4310
4311   vik_track_set_name (t, name);
4312
4313   if ( VIK_LAYER(vtl)->realized )
4314   {
4315     // Do we need to create the sublayer:
4316     if ( g_hash_table_size (vtl->routes) == 0 ) {
4317       trw_layer_add_sublayer_routes ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
4318     }
4319
4320     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
4321     // Visibility column always needed for routes
4322     vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE );
4323     // Actual setting of visibility dependent on the route
4324     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
4325
4326     g_hash_table_insert ( vtl->routes_iters, GUINT_TO_POINTER(rt_uuid), iter );
4327
4328     // Sort now as post_read is not called on a realized route
4329     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
4330   }
4331
4332   g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t );
4333
4334   trw_layer_update_treeview ( vtl, t );
4335 }
4336
4337 /* to be called whenever a track has been deleted or may have been changed. */
4338 void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk )
4339 {
4340   if (vtl->current_tp_track == trk )
4341     trw_layer_cancel_current_tp ( vtl, FALSE );
4342 }
4343
4344 /**
4345  * Normally this is done to due the waypoint size preference having changed
4346  */
4347 void vik_trw_layer_reset_waypoints ( VikTrwLayer *vtl )
4348 {
4349   GHashTableIter iter;
4350   gpointer key, value;
4351
4352   // Foreach waypoint
4353   g_hash_table_iter_init ( &iter, vtl->waypoints );
4354   while ( g_hash_table_iter_next ( &iter, &key, &value ) ) {
4355     VikWaypoint *wp = VIK_WAYPOINT(value);
4356     if ( wp->symbol ) {
4357       // Reapply symbol setting to update the pixbuf
4358       gchar *tmp_symbol = g_strdup ( wp->symbol );
4359       vik_waypoint_set_symbol ( wp, tmp_symbol );
4360       g_free ( tmp_symbol );
4361     }
4362   }
4363 }
4364
4365 /**
4366  * trw_layer_new_unique_sublayer_name:
4367  *
4368  * Allocates a unique new name
4369  */
4370 gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
4371 {
4372   gint i = 2;
4373   gchar *newname = g_strdup(name);
4374
4375   gpointer id = NULL;
4376   do {
4377     id = NULL;
4378     switch ( sublayer_type ) {
4379     case VIK_TRW_LAYER_SUBLAYER_TRACK:
4380       id = (gpointer) vik_trw_layer_get_track ( vtl, newname );
4381       break;
4382     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
4383       id = (gpointer) vik_trw_layer_get_waypoint ( vtl, newname );
4384       break;
4385     default:
4386       id = (gpointer) vik_trw_layer_get_route ( vtl, newname );
4387       break;
4388     }
4389     // If found a name already in use try adding 1 to it and we try again
4390     if ( id ) {
4391       gchar *new_newname = g_strdup_printf("%s#%d", name, i);
4392       g_free(newname);
4393       newname = new_newname;
4394       i++;
4395     }
4396   } while ( id != NULL);
4397
4398   return newname;
4399 }
4400
4401 void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
4402 {
4403   // No more uniqueness of name forced when loading from a file
4404   // This now makes this function a little redunant as we just flow the parameters through
4405   vik_trw_layer_add_waypoint ( vtl, name, wp );
4406 }
4407
4408 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
4409 {
4410   if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
4411     vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
4412     vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
4413     vik_track_free ( tr );
4414     vtl->route_finder_append = FALSE; /* this means we have added it */
4415   } else {
4416
4417     // No more uniqueness of name forced when loading from a file
4418     if ( tr->is_route )
4419       vik_trw_layer_add_route ( vtl, name, tr );
4420     else
4421       vik_trw_layer_add_track ( vtl, name, tr );
4422
4423     if ( vtl->route_finder_check_added_track ) {
4424       vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
4425       vtl->route_finder_added_track = tr;
4426     }
4427   }
4428 }
4429
4430 static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l )
4431 {
4432   *l = g_list_append(*l, id);
4433 }
4434
4435 /*
4436  * Move an item from one TRW layer to another TRW layer
4437  */
4438 static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
4439 {
4440   // TODO reconsider strategy when moving within layer (if anything...)
4441   gboolean rename = ( vtl_src != vtl_dest );
4442   if ( ! rename )
4443     return;
4444
4445   if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
4446     VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
4447
4448     gchar *newname;
4449     if ( rename )
4450       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
4451     else
4452       newname = g_strdup ( trk->name );
4453
4454     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
4455     vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
4456     g_free ( newname );
4457     vik_trw_layer_delete_track ( vtl_src, trk );
4458   }
4459
4460   if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
4461     VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id );
4462
4463     gchar *newname;
4464     if ( rename )
4465       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
4466     else
4467       newname = g_strdup ( trk->name );
4468
4469     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
4470     vik_trw_layer_add_route ( vtl_dest, newname, trk2 );
4471     g_free ( newname );
4472     vik_trw_layer_delete_route ( vtl_src, trk );
4473   }
4474
4475   if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
4476     VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
4477
4478     gchar *newname;
4479     if ( rename )
4480       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
4481     else
4482       newname = g_strdup ( wp->name );
4483
4484     VikWaypoint *wp2 = vik_waypoint_copy ( wp );
4485     vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
4486     g_free ( newname );
4487     trw_layer_delete_waypoint ( vtl_src, wp );
4488
4489     // Recalculate bounds even if not renamed as maybe dragged between layers
4490     trw_layer_calculate_bounds_waypoints ( vtl_dest );
4491     trw_layer_calculate_bounds_waypoints ( vtl_src );
4492   }
4493 }
4494
4495 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
4496 {
4497   VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
4498   gint type = vik_treeview_item_get_data(vt, src_item_iter);
4499
4500   if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
4501     GList *items = NULL;
4502     GList *iter;
4503
4504     if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
4505       g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items);
4506     } 
4507     if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) {
4508       g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items);
4509     }    
4510     if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
4511       g_hash_table_foreach ( vtl_src->routes, (GHFunc)trw_layer_enum_item, &items);
4512     }
4513
4514     iter = items;
4515     while (iter) {
4516       if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
4517         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
4518       } else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
4519         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_ROUTE);
4520       } else {
4521         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
4522       }
4523       iter = iter->next;
4524     }
4525     if (items) 
4526       g_list_free(items);
4527   } else {
4528     gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
4529     trw_layer_move_item(vtl_src, vtl_dest, name, type);
4530   }
4531 }
4532
4533 gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata )
4534 {
4535   trku_udata *user_data = udata;
4536   if ( trk == user_data->trk ) {
4537     user_data->uuid = id;
4538     return TRUE;
4539   }
4540   return FALSE;
4541 }
4542
4543 gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
4544 {
4545   gboolean was_visible = FALSE;
4546
4547   if ( trk && trk->name ) {
4548
4549     if ( trk == vtl->current_track ) {
4550       vtl->current_track = NULL;
4551       vtl->current_tp_track = NULL;
4552       vtl->current_tp_id = NULL;
4553       vtl->moving_tp = FALSE;
4554     }
4555
4556     was_visible = trk->visible;
4557
4558     if ( trk == vtl->route_finder_current_track )
4559       vtl->route_finder_current_track = NULL;
4560
4561     if ( trk == vtl->route_finder_added_track )
4562       vtl->route_finder_added_track = NULL;
4563
4564     trku_udata udata;
4565     udata.trk  = trk;
4566     udata.uuid = NULL;
4567
4568     // Hmmm, want key of it
4569     gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
4570
4571     if ( trkf && udata.uuid ) {
4572       /* could be current_tp, so we have to check */
4573       trw_layer_cancel_tps_of_track ( vtl, trk );
4574
4575       GtkTreeIter *it = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid );
4576
4577       if ( it ) {
4578         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4579         g_hash_table_remove ( vtl->tracks_iters, udata.uuid );
4580         g_hash_table_remove ( vtl->tracks, udata.uuid );
4581
4582         // If last sublayer, then remove sublayer container
4583         if ( g_hash_table_size (vtl->tracks) == 0 ) {
4584           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
4585         }
4586       }
4587     }
4588   }
4589   return was_visible;
4590 }
4591
4592 gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
4593 {
4594   gboolean was_visible = FALSE;
4595
4596   if ( trk && trk->name ) {
4597
4598     if ( trk == vtl->current_track ) {
4599       vtl->current_track = NULL;
4600       vtl->current_tp_track = NULL;
4601       vtl->current_tp_id = NULL;
4602       vtl->moving_tp = FALSE;
4603     }
4604
4605     was_visible = trk->visible;
4606
4607     if ( trk == vtl->route_finder_current_track )
4608       vtl->route_finder_current_track = NULL;
4609
4610     if ( trk == vtl->route_finder_added_track )
4611       vtl->route_finder_added_track = NULL;
4612
4613     trku_udata udata;
4614     udata.trk  = trk;
4615     udata.uuid = NULL;
4616
4617     // Hmmm, want key of it
4618     gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
4619
4620     if ( trkf && udata.uuid ) {
4621       /* could be current_tp, so we have to check */
4622       trw_layer_cancel_tps_of_track ( vtl, trk );
4623
4624       GtkTreeIter *it = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
4625
4626       if ( it ) {
4627         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4628         g_hash_table_remove ( vtl->routes_iters, udata.uuid );
4629         g_hash_table_remove ( vtl->routes, udata.uuid );
4630
4631         // If last sublayer, then remove sublayer container
4632         if ( g_hash_table_size (vtl->routes) == 0 ) {
4633           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
4634         }
4635       }
4636     }
4637   }
4638   return was_visible;
4639 }
4640
4641 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
4642 {
4643   gboolean was_visible = FALSE;
4644
4645   if ( wp && wp->name ) {
4646
4647     if ( wp == vtl->current_wp ) {
4648       vtl->current_wp = NULL;
4649       vtl->current_wp_id = NULL;
4650       vtl->moving_wp = FALSE;
4651     }
4652
4653     was_visible = wp->visible;
4654     
4655     wpu_udata udata;
4656     udata.wp   = wp;
4657     udata.uuid = NULL;
4658
4659     // Hmmm, want key of it
4660     gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
4661
4662     if ( wpf && udata.uuid ) {
4663       GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
4664     
4665       if ( it ) {
4666         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4667         g_hash_table_remove ( vtl->waypoints_iters, udata.uuid );
4668
4669         highest_wp_number_remove_wp(vtl, wp->name);
4670         g_hash_table_remove ( vtl->waypoints, udata.uuid ); // last because this frees the name
4671
4672         // If last sublayer, then remove sublayer container
4673         if ( g_hash_table_size (vtl->waypoints) == 0 ) {
4674           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
4675         }
4676       }
4677     }
4678
4679   }
4680
4681   return was_visible;
4682 }
4683
4684 // Only for temporary use by trw_layer_delete_waypoint_by_name
4685 static gboolean trw_layer_waypoint_find_uuid_by_name ( const gpointer id, const VikWaypoint *wp, gpointer udata )
4686 {
4687   wpu_udata *user_data = udata;
4688   if ( ! strcmp ( wp->name, user_data->wp->name ) ) {
4689     user_data->uuid = id;
4690     return TRUE;
4691   }
4692   return FALSE;
4693 }
4694
4695 /*
4696  * Delete a waypoint by the given name
4697  * NOTE: ATM this will delete the first encountered Waypoint with the specified name
4698  *   as there be multiple waypoints with the same name
4699  */
4700 static gboolean trw_layer_delete_waypoint_by_name ( VikTrwLayer *vtl, const gchar *name )
4701 {
4702   wpu_udata udata;
4703   // Fake a waypoint with the given name
4704   udata.wp   = vik_waypoint_new ();
4705   vik_waypoint_set_name (udata.wp, name);
4706   // Currently only the name is used in this waypoint find function
4707   udata.uuid = NULL;
4708
4709   // Hmmm, want key of it
4710   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
4711
4712   vik_waypoint_free (udata.wp);
4713
4714   if ( wpf && udata.uuid )
4715     return trw_layer_delete_waypoint (vtl, g_hash_table_lookup ( vtl->waypoints, udata.uuid ));
4716   else
4717     return FALSE;
4718 }
4719
4720 typedef struct {
4721   VikTrack *trk; // input
4722   gpointer uuid; // output
4723 } tpu_udata;
4724
4725 // Only for temporary use by trw_layer_delete_track_by_name
4726 static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const VikTrack *trk, gpointer udata )
4727 {
4728   tpu_udata *user_data = udata;
4729   if ( ! strcmp ( trk->name, user_data->trk->name ) ) {
4730     user_data->uuid = id;
4731     return TRUE;
4732   }
4733   return FALSE;
4734 }
4735
4736 /*
4737  * Delete a track by the given name
4738  * NOTE: ATM this will delete the first encountered Track with the specified name
4739  *   as there may be multiple tracks with the same name within the specified hash table
4740  */
4741 static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name, GHashTable *ht_tracks )
4742 {
4743   tpu_udata udata;
4744   // Fake a track with the given name
4745   udata.trk   = vik_track_new ();
4746   vik_track_set_name (udata.trk, name);
4747   // Currently only the name is used in this waypoint find function
4748   udata.uuid = NULL;
4749
4750   // Hmmm, want key of it
4751   gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
4752
4753   vik_track_free (udata.trk);
4754
4755   if ( trkf && udata.uuid ) {
4756     // This could be a little better written...
4757     if ( vtl->tracks == ht_tracks )
4758       return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
4759     if ( vtl->routes == ht_tracks )
4760       return vik_trw_layer_delete_route (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
4761     return FALSE;
4762   }
4763   else
4764     return FALSE;
4765 }
4766
4767 static void remove_item_from_treeview ( const gpointer id, GtkTreeIter *it, VikTreeview * vt )
4768 {
4769     vik_treeview_item_delete (vt, it );
4770 }
4771
4772 void vik_trw_layer_delete_all_routes ( VikTrwLayer *vtl )
4773 {
4774
4775   vtl->current_track = NULL;
4776   vtl->route_finder_current_track = NULL;
4777   vtl->route_finder_added_track = NULL;
4778   if (vtl->current_tp_track)
4779     trw_layer_cancel_current_tp(vtl, FALSE);
4780
4781   g_hash_table_foreach(vtl->routes_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4782   g_hash_table_remove_all(vtl->routes_iters);
4783   g_hash_table_remove_all(vtl->routes);
4784
4785   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
4786
4787   vik_layer_emit_update ( VIK_LAYER(vtl) );
4788 }
4789
4790 void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
4791 {
4792
4793   vtl->current_track = NULL;
4794   vtl->route_finder_current_track = NULL;
4795   vtl->route_finder_added_track = NULL;
4796   if (vtl->current_tp_track)
4797     trw_layer_cancel_current_tp(vtl, FALSE);
4798
4799   g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4800   g_hash_table_remove_all(vtl->tracks_iters);
4801   g_hash_table_remove_all(vtl->tracks);
4802
4803   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
4804
4805   vik_layer_emit_update ( VIK_LAYER(vtl) );
4806 }
4807
4808 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
4809 {
4810   vtl->current_wp = NULL;
4811   vtl->current_wp_id = NULL;
4812   vtl->moving_wp = FALSE;
4813
4814   highest_wp_number_reset(vtl);
4815
4816   g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4817   g_hash_table_remove_all(vtl->waypoints_iters);
4818   g_hash_table_remove_all(vtl->waypoints);
4819
4820   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
4821
4822   vik_layer_emit_update ( VIK_LAYER(vtl) );
4823 }
4824
4825 static void trw_layer_delete_all_tracks ( menu_array_layer values )
4826 {
4827   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
4828   // Get confirmation from the user
4829   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4830                             _("Are you sure you want to delete all tracks in %s?"),
4831                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4832     vik_trw_layer_delete_all_tracks (vtl);
4833 }
4834
4835 static void trw_layer_delete_all_routes ( menu_array_layer values )
4836 {
4837   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
4838   // Get confirmation from the user
4839   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4840                             _("Are you sure you want to delete all routes in %s?"),
4841                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4842     vik_trw_layer_delete_all_routes (vtl);
4843 }
4844
4845 static void trw_layer_delete_all_waypoints ( menu_array_layer values )
4846 {
4847   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
4848   // Get confirmation from the user
4849   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4850                             _("Are you sure you want to delete all waypoints in %s?"),
4851                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4852     vik_trw_layer_delete_all_waypoints (vtl);
4853 }
4854
4855 static void trw_layer_delete_item ( menu_array_sublayer values )
4856 {
4857   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
4858   gboolean was_visible = FALSE;
4859   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
4860   {
4861     VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
4862     if ( wp && wp->name ) {
4863       if ( GPOINTER_TO_INT (values[MA_CONFIRM]) )
4864         // Get confirmation from the user
4865         // Maybe this Waypoint Delete should be optional as is it could get annoying...
4866         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4867             _("Are you sure you want to delete the waypoint \"%s\"?"),
4868             wp->name ) )
4869           return;
4870       was_visible = trw_layer_delete_waypoint ( vtl, wp );
4871     }
4872   }
4873   else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4874   {
4875     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
4876     if ( trk && trk->name ) {
4877       if ( GPOINTER_TO_INT (values[MA_CONFIRM]) )
4878         // Get confirmation from the user
4879         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4880                                   _("Are you sure you want to delete the track \"%s\"?"),
4881                                   trk->name ) )
4882           return;
4883       was_visible = vik_trw_layer_delete_track ( vtl, trk );
4884     }
4885   }
4886   else
4887   {
4888     VikTrack *trk = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
4889     if ( trk && trk->name ) {
4890       if ( GPOINTER_TO_INT (values[MA_CONFIRM]) )
4891         // Get confirmation from the user
4892         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4893                                     _("Are you sure you want to delete the route \"%s\"?"),
4894                                     trk->name ) )
4895           return;
4896       was_visible = vik_trw_layer_delete_route ( vtl, trk );
4897     }
4898   }
4899   if ( was_visible )
4900     vik_layer_emit_update ( VIK_LAYER(vtl) );
4901 }
4902
4903 /**
4904  *  Rename waypoint and maintain corresponding name of waypoint in the treeview
4905  */
4906 void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name )
4907 {
4908   vik_waypoint_set_name ( wp, new_name );
4909
4910   // Now update the treeview as well
4911   wpu_udata udataU;
4912   udataU.wp   = wp;
4913   udataU.uuid = NULL;
4914
4915   // Need key of it for treeview update
4916   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
4917
4918   if ( wpf && udataU.uuid ) {
4919     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
4920
4921     if ( it ) {
4922       vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, new_name );
4923       vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
4924     }
4925   }
4926 }
4927
4928 /**
4929  *  Maintain icon of waypoint in the treeview
4930  */
4931 void trw_layer_waypoint_reset_icon ( VikTrwLayer *vtl, VikWaypoint *wp )
4932 {
4933   // update the treeview
4934   wpu_udata udataU;
4935   udataU.wp   = wp;
4936   udataU.uuid = NULL;
4937
4938   // Need key of it for treeview update
4939   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
4940
4941   if ( wpf && udataU.uuid ) {
4942     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
4943
4944     if ( it ) {
4945       vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, it, get_wp_sym_small (wp->symbol) );
4946     }
4947   }
4948 }
4949
4950 static void trw_layer_properties_item ( menu_array_sublayer values )
4951 {
4952   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
4953   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
4954   {
4955     VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
4956
4957     if ( wp && wp->name )
4958     {
4959       gboolean updated = FALSE;
4960       gchar *new_name = a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, vtl, wp, vtl->coord_mode, FALSE, &updated );
4961       if ( new_name )
4962         trw_layer_waypoint_rename ( vtl, wp, new_name );
4963
4964       if ( updated && values[MA_TV_ITER] )
4965         vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, values[MA_TV_ITER], get_wp_sym_small (wp->symbol) );
4966
4967       if ( updated && VIK_LAYER(vtl)->visible )
4968         vik_layer_emit_update ( VIK_LAYER(vtl) );
4969     }
4970   }
4971   else
4972   {
4973     VikTrack *tr;
4974     if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4975       tr = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
4976     else
4977       tr = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
4978
4979     if ( tr && tr->name )
4980     {
4981       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4982                                   vtl,
4983                                   tr,
4984                                   values[MA_VLP],
4985                                   values[MA_VVP],
4986                                   FALSE );
4987     }
4988   }
4989 }
4990
4991 /**
4992  * trw_layer_track_statistics:
4993  *
4994  * Show track statistics.
4995  * ATM jump to the stats page in the properties
4996  * TODO: consider separating the stats into an individual dialog?
4997  */
4998 static void trw_layer_track_statistics ( menu_array_sublayer values )
4999 {
5000   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
5001   VikTrack *trk;
5002   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
5003     trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5004   else
5005     trk = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5006
5007   if ( trk && trk->name ) {
5008     vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5009                                 vtl,
5010                                 trk,
5011                                 values[MA_VLP],
5012                                 values[MA_VVP],
5013                                 TRUE );
5014   }
5015 }
5016
5017 /*
5018  * Update the treeview of the track id - primarily to update the icon
5019  */
5020 void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk )
5021 {
5022   trku_udata udata;
5023   udata.trk  = trk;
5024   udata.uuid = NULL;
5025
5026   gpointer *trkf = NULL;
5027   if ( trk->is_route )
5028     trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
5029   else
5030     trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
5031
5032   if ( trkf && udata.uuid ) {
5033
5034     GtkTreeIter *iter = NULL;
5035     if ( trk->is_route )
5036       iter = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
5037     else
5038       iter = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid );
5039
5040     if ( iter ) {
5041       // TODO: Make this a function
5042       GdkPixbuf *pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, 18, 18);
5043       guint32 pixel = ((trk->color.red & 0xff00) << 16) |
5044         ((trk->color.green & 0xff00) << 8) |
5045         (trk->color.blue & 0xff00);
5046       gdk_pixbuf_fill ( pixbuf, pixel );
5047       vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, iter, pixbuf );
5048       g_object_unref (pixbuf);
5049     }
5050
5051   }
5052 }
5053
5054 /*
5055    Parameter 1 -> VikLayersPanel
5056    Parameter 2 -> VikLayer
5057    Parameter 3 -> VikViewport
5058 */
5059 static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord )
5060 {
5061   if ( vlp ) {
5062     vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord );
5063     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
5064   }
5065   else {
5066     /* since vlp not set, vl & vvp should be valid instead! */
5067     if ( vl && vvp ) {
5068       vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord );
5069       vik_layer_emit_update ( VIK_LAYER(vl) );
5070     }
5071   }
5072 }
5073
5074 static void trw_layer_goto_track_startpoint ( menu_array_sublayer values )
5075 {
5076   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5077   VikTrack *track;
5078   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5079     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5080   else
5081     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5082
5083   if ( track && track->trackpoints )
5084     goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_first(track)->coord) );
5085 }
5086
5087 static void trw_layer_goto_track_center ( menu_array_sublayer values )
5088 {
5089   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5090   VikTrack *track;
5091   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5092     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5093   else
5094     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5095
5096   if ( track && track->trackpoints )
5097   {
5098     struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
5099     VikCoord coord;
5100     trw_layer_find_maxmin_tracks ( NULL, track, maxmin );
5101     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
5102     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
5103     vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
5104     goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &coord);
5105   }
5106 }
5107
5108 static void trw_layer_convert_track_route ( menu_array_sublayer values )
5109 {
5110   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5111   VikTrack *trk;
5112   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5113     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5114   else
5115     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5116
5117   if ( !trk )
5118     return;
5119
5120   // Converting a track to a route can be a bit more complicated,
5121   //  so give a chance to change our minds:
5122   if ( !trk->is_route &&
5123        ( ( vik_track_get_segment_count ( trk ) > 1 ) ||
5124          ( vik_track_get_average_speed ( trk ) > 0.0 ) ) ) {
5125
5126     if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5127                                 _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) )
5128       return;
5129 }
5130
5131   // Copy it
5132   VikTrack *trk_copy = vik_track_copy ( trk, TRUE );
5133
5134   // Convert
5135   trk_copy->is_route = !trk_copy->is_route;
5136
5137   // ATM can't set name to self - so must create temporary copy
5138   gchar *name = g_strdup ( trk_copy->name );
5139
5140   // Delete old one and then add new one
5141   if ( trk->is_route ) {
5142     vik_trw_layer_delete_route ( vtl, trk );
5143     vik_trw_layer_add_track ( vtl, name, trk_copy );
5144   }
5145   else {
5146     // Extra route conversion bits...
5147     vik_track_merge_segments ( trk_copy );
5148     vik_track_to_routepoints ( trk_copy );
5149
5150     vik_trw_layer_delete_track ( vtl, trk );
5151     vik_trw_layer_add_route ( vtl, name, trk_copy );
5152   }
5153   g_free ( name );
5154
5155   // Update in case color of track / route changes when moving between sublayers
5156   vik_layer_emit_update ( VIK_LAYER(vtl) );
5157 }
5158
5159 static void trw_layer_anonymize_times ( menu_array_sublayer values )
5160 {
5161   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5162   VikTrack *track;
5163   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5164     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5165   else
5166     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5167
5168   if ( track )
5169     vik_track_anonymize_times ( track );
5170 }
5171
5172 static void trw_layer_extend_track_end ( menu_array_sublayer values )
5173 {
5174   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
5175   VikTrack *track;
5176   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5177     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5178   else
5179     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5180
5181   if ( !track )
5182     return;
5183
5184   vtl->current_track = track;
5185   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);
5186
5187   if ( track->trackpoints )
5188     goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_last(track)->coord) );
5189 }
5190
5191 /**
5192  * extend a track using route finder
5193  */
5194 static void trw_layer_extend_track_end_route_finder ( menu_array_sublayer values )
5195 {
5196   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
5197   VikTrack *track = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5198   if ( !track )
5199     return;
5200   if ( !track->trackpoints )
5201     return;
5202
5203   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER );
5204   vtl->route_finder_coord = vik_track_get_tp_last(track)->coord;
5205   vtl->route_finder_current_track = track;
5206   vtl->route_finder_started = TRUE;
5207
5208   goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &vtl->route_finder_coord );
5209 }
5210
5211 /**
5212  *
5213  */
5214 static gboolean trw_layer_dem_test ( VikTrwLayer *vtl, VikLayersPanel *vlp )
5215 {
5216   // If have a vlp then perform a basic test to see if any DEM info available...
5217   if ( vlp ) {
5218     GList *dems = vik_layers_panel_get_all_layers_of_type (vlp, VIK_LAYER_DEM, TRUE); // Includes hidden DEM layer types
5219
5220     if ( !g_list_length(dems) ) {
5221       a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No DEM layers available, thus no DEM values can be applied.") );
5222       return FALSE;
5223     }
5224   }
5225   return TRUE;
5226 }
5227
5228 /**
5229  * apply_dem_data_common:
5230  *
5231  * A common function for applying the DEM values and reporting the results.
5232  */
5233 static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTrack *track, gboolean skip_existing_elevations )
5234 {
5235   if ( !trw_layer_dem_test ( vtl, vlp ) )
5236     return;
5237
5238   gulong changed = vik_track_apply_dem_data ( track, skip_existing_elevations );
5239   // Inform user how much was changed
5240   gchar str[64];
5241   const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
5242   g_snprintf(str, 64, tmp_str, changed);
5243   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5244 }
5245
5246 static void trw_layer_apply_dem_data_all ( menu_array_sublayer values )
5247 {
5248   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5249   VikTrack *track;
5250   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5251     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5252   else
5253     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5254
5255   if ( track )
5256     apply_dem_data_common ( vtl, values[MA_VLP], track, FALSE );
5257 }
5258
5259 static void trw_layer_apply_dem_data_only_missing ( menu_array_sublayer values )
5260 {
5261   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5262   VikTrack *track;
5263   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5264     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5265   else
5266     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5267
5268   if ( track )
5269     apply_dem_data_common ( vtl, values[MA_VLP], track, TRUE );
5270 }
5271
5272 /**
5273  * smooth_it:
5274  *
5275  * A common function for applying the elevation smoothing and reporting the results.
5276  */
5277 static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat )
5278 {
5279   gulong changed = vik_track_smooth_missing_elevation_data ( track, flat );
5280   // Inform user how much was changed
5281   gchar str[64];
5282   const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
5283   g_snprintf(str, 64, tmp_str, changed);
5284   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5285 }
5286
5287 /**
5288  *
5289  */
5290 static void trw_layer_missing_elevation_data_interp ( menu_array_sublayer values )
5291 {
5292   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5293   VikTrack *track;
5294   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5295     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5296   else
5297     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5298
5299   if ( !track )
5300     return;
5301
5302   smooth_it ( vtl, track, FALSE );
5303 }
5304
5305 static void trw_layer_missing_elevation_data_flat ( menu_array_sublayer values )
5306 {
5307   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5308   VikTrack *track;
5309   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5310     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5311   else
5312     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5313
5314   if ( !track )
5315     return;
5316
5317   smooth_it ( vtl, track, TRUE );
5318 }
5319
5320 /**
5321  * Commonal helper function
5322  */
5323 static void wp_changed_message ( VikTrwLayer *vtl, gint changed )
5324 {
5325   gchar str[64];
5326   const gchar *tmp_str = ngettext("%ld waypoint changed", "%ld waypoints changed", changed);
5327   g_snprintf(str, 64, tmp_str, changed);
5328   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5329 }
5330
5331 static void trw_layer_apply_dem_data_wpt_all ( menu_array_sublayer values )
5332 {
5333   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5334   VikLayersPanel *vlp = (VikLayersPanel *)values[MA_VLP];
5335
5336   if ( !trw_layer_dem_test ( vtl, vlp ) )
5337     return;
5338
5339   gint changed = 0;
5340   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
5341     // Single Waypoint
5342     VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
5343     if ( wp )
5344       changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
5345   }
5346   else {
5347     // All waypoints
5348     GHashTableIter iter;
5349     gpointer key, value;
5350
5351     g_hash_table_iter_init ( &iter, vtl->waypoints );
5352     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
5353       VikWaypoint *wp = VIK_WAYPOINT(value);
5354       changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
5355     }
5356   }
5357   wp_changed_message ( vtl, changed );
5358 }
5359
5360 static void trw_layer_apply_dem_data_wpt_only_missing ( menu_array_sublayer values )
5361 {
5362   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5363   VikLayersPanel *vlp = (VikLayersPanel *)values[MA_VLP];
5364
5365   if ( !trw_layer_dem_test ( vtl, vlp ) )
5366     return;
5367
5368   gint changed = 0;
5369   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
5370     // Single Waypoint
5371     VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
5372     if ( wp )
5373       changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
5374   }
5375   else {
5376     // All waypoints
5377     GHashTableIter iter;
5378     gpointer key, value;
5379
5380     g_hash_table_iter_init ( &iter, vtl->waypoints );
5381     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
5382       VikWaypoint *wp = VIK_WAYPOINT(value);
5383       changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
5384     }
5385   }
5386   wp_changed_message ( vtl, changed );
5387 }
5388
5389 static void trw_layer_goto_track_endpoint ( menu_array_sublayer values )
5390 {
5391   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5392   VikTrack *track;
5393   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5394     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5395   else
5396     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5397
5398   if ( !track )
5399     return;
5400   if ( !track->trackpoints )
5401     return;
5402   goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_last(track)->coord));
5403 }
5404
5405 static void trw_layer_goto_track_max_speed ( menu_array_sublayer values )
5406 {
5407   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5408   VikTrack *track;
5409   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5410     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5411   else
5412     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5413
5414   if ( !track )
5415     return;
5416
5417   VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track );
5418   if ( !vtp )
5419     return;
5420   goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord));
5421 }
5422
5423 static void trw_layer_goto_track_max_alt ( menu_array_sublayer values )
5424 {
5425   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5426   VikTrack *track;
5427   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5428     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5429   else
5430     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5431
5432   if ( !track )
5433     return;
5434
5435   VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track );
5436   if ( !vtp )
5437     return;
5438   goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord));
5439 }
5440
5441 static void trw_layer_goto_track_min_alt ( menu_array_sublayer values )
5442 {
5443   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5444   VikTrack *track;
5445   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5446     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5447   else
5448     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5449
5450   if ( !track )
5451     return;
5452
5453   VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track );
5454   if ( !vtp )
5455     return;
5456   goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord));
5457 }
5458
5459 /*
5460  * Automatically change the viewport to center on the track and zoom to see the extent of the track
5461  */
5462 static void trw_layer_auto_track_view ( menu_array_sublayer values )
5463 {
5464   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
5465   VikTrack *trk;
5466   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5467     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5468   else
5469     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5470
5471   if ( trk && trk->trackpoints )
5472   {
5473     struct LatLon maxmin[2] = { {0,0}, {0,0} };
5474     trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
5475     trw_layer_zoom_to_show_latlons ( vtl, values[MA_VVP], maxmin );
5476     if ( values[MA_VLP] )
5477       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(values[MA_VLP]) );
5478     else
5479       vik_layer_emit_update ( VIK_LAYER(vtl) );
5480   }
5481 }
5482
5483 /*
5484  * Refine the selected track/route with a routing engine.
5485  * The routing engine is selected by the user, when requestiong the job.
5486  */
5487 static void trw_layer_route_refine ( menu_array_sublayer values )
5488 {
5489   static gint last_engine = 0;
5490   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
5491   VikTrack *trk;
5492
5493   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5494     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
5495   else
5496     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5497
5498   if ( trk && trk->trackpoints )
5499   {
5500     /* Check size of the route */
5501     int nb = vik_track_get_tp_count(trk);
5502     if (nb > 100) {
5503       GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER (vtl),
5504                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
5505                                                   GTK_MESSAGE_WARNING,
5506                                                   GTK_BUTTONS_OK_CANCEL,
5507                                                   _("Refining a track with many points (%d) is unlikely to yield sensible results. Do you want to Continue?"),
5508                                                   nb);
5509       gint response = gtk_dialog_run ( GTK_DIALOG(dialog) );
5510       gtk_widget_destroy ( dialog );
5511       if (response != GTK_RESPONSE_OK )
5512         return;
5513     }
5514     /* Select engine from dialog */
5515     GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Refine Route with Routing Engine..."),
5516                                                   VIK_GTK_WINDOW_FROM_LAYER (vtl),
5517                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
5518                                                   GTK_STOCK_CANCEL,
5519                                                   GTK_RESPONSE_REJECT,
5520                                                   GTK_STOCK_OK,
5521                                                   GTK_RESPONSE_ACCEPT,
5522                                                   NULL);
5523     GtkWidget *label = gtk_label_new ( _("Select routing engine") );
5524     gtk_widget_show_all(label);
5525
5526     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 0 );
5527
5528     GtkWidget * combo = vik_routing_ui_selector_new ( (Predicate)vik_routing_engine_supports_refine, NULL );
5529     gtk_combo_box_set_active (GTK_COMBO_BOX (combo), last_engine);
5530     gtk_widget_show_all(combo);
5531
5532     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), combo, TRUE, TRUE, 0 );
5533
5534     gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
5535
5536     if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
5537     {
5538         /* Dialog validated: retrieve selected engine and do the job */
5539         last_engine = gtk_combo_box_get_active ( GTK_COMBO_BOX(combo) );
5540         VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine);
5541
5542         /* Change cursor */
5543         vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
5544
5545         /* Force saving track */
5546         /* FIXME: remove or rename this hack */
5547         vtl->route_finder_check_added_track = TRUE;
5548
5549         /* the job */
5550         vik_routing_engine_refine (routing, vtl, trk);
5551
5552         /* FIXME: remove or rename this hack */
5553         if ( vtl->route_finder_added_track )
5554           vik_track_calculate_bounds ( vtl->route_finder_added_track );
5555
5556         vtl->route_finder_added_track = NULL;
5557         vtl->route_finder_check_added_track = FALSE;
5558
5559         vik_layer_emit_update ( VIK_LAYER(vtl) );
5560
5561         /* Restore cursor */
5562         vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
5563     }
5564     gtk_widget_destroy ( dialog );
5565   }
5566 }
5567
5568 static void trw_layer_edit_trackpoint ( menu_array_sublayer values )
5569 {
5570   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
5571   trw_layer_tpwin_init ( vtl );
5572 }
5573
5574 /*************************************
5575  * merge/split by time routines 
5576  *************************************/
5577
5578 /* called for each key in track hash table.
5579  * If the current track has the same time stamp type, add it to the result,
5580  * except the one pointed by "exclude".
5581  * set exclude to NULL if there is no exclude to check.
5582  * Note that the result is in reverse (for performance reasons).
5583  */
5584 typedef struct {
5585   GList **result;
5586   GList  *exclude;
5587   gboolean with_timestamps;
5588 } twt_udata;
5589 static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata)
5590 {
5591   twt_udata *user_data = udata;
5592   VikTrackpoint *p1, *p2;
5593   VikTrack *trk = VIK_TRACK(value);
5594   if (trk == (VikTrack *)user_data->exclude) {
5595     return;
5596   }
5597
5598   if (trk->trackpoints) {
5599     p1 = vik_track_get_tp_first(trk);
5600     p2 = vik_track_get_tp_last(trk);
5601
5602     if ( user_data->with_timestamps ) {
5603       if (!p1->has_timestamp || !p2->has_timestamp) {
5604         return;
5605       }
5606     }
5607     else {
5608       // Don't add tracks with timestamps when getting non timestamp tracks
5609       if (p1->has_timestamp || p2->has_timestamp) {
5610         return;
5611       }
5612     }
5613   }
5614
5615   *(user_data->result) = g_list_prepend(*(user_data->result), key);
5616 }
5617
5618 /* called for each key in track hash table. if original track user_data[1] is close enough
5619  * to the passed one, add it to list in user_data[0] 
5620  */
5621 static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
5622 {
5623   time_t t1, t2;
5624   VikTrackpoint *p1, *p2;
5625   VikTrack *trk = VIK_TRACK(value);
5626
5627   GList **nearby_tracks = ((gpointer *)user_data)[0];
5628   GList *tpoints = ((gpointer *)user_data)[1];
5629
5630   /* outline: 
5631    * detect reasons for not merging, and return
5632    * if no reason is found not to merge, then do it.
5633    */
5634
5635   // Exclude the original track from the compiled list
5636   if (trk->trackpoints == tpoints) {
5637     return;
5638   }
5639
5640   t1 = vik_track_get_tp_first(trk)->timestamp;
5641   t2 = vik_track_get_tp_last(trk)->timestamp;
5642
5643   if (trk->trackpoints) {
5644     p1 = vik_track_get_tp_first(trk);
5645     p2 = vik_track_get_tp_last(trk);
5646
5647     if (!p1->has_timestamp || !p2->has_timestamp) {
5648       //g_print("no timestamp\n");
5649       return;
5650     }
5651
5652     guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
5653     //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
5654     if (! (abs(t1 - p2->timestamp) < threshold ||
5655         /*  p1 p2      t1 t2 */
5656            abs(p1->timestamp - t2) < threshold)
5657         /*  t1 t2      p1 p2 */
5658         ) {
5659       return;
5660     }
5661   }
5662
5663   *nearby_tracks = g_list_prepend(*nearby_tracks, value);
5664 }
5665
5666 /* comparison function used to sort tracks; a and b are hash table keys */
5667 /* Not actively used - can be restored if needed
5668 static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
5669 {
5670   GHashTable *tracks = user_data;
5671   time_t t1, t2;
5672
5673   t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
5674   t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
5675   
5676   if (t1 < t2) return -1;
5677   if (t1 > t2) return 1;
5678   return 0;
5679 }
5680 */
5681
5682 /* comparison function used to sort trackpoints */
5683 static gint trackpoint_compare(gconstpointer a, gconstpointer b)
5684 {
5685   time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
5686   
5687   if (t1 < t2) return -1;
5688   if (t1 > t2) return 1;
5689   return 0;
5690 }
5691
5692 /**
5693  * comparison function which can be used to sort tracks or waypoints by name
5694  */
5695 static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user_data)
5696 {
5697   const gchar* namea = (const gchar*) a;
5698   const gchar* nameb = (const gchar*) b;
5699   if ( namea == NULL || nameb == NULL)
5700     return 0;
5701   else
5702     // Same sort method as used in the vik_treeview_*_alphabetize functions
5703     return strcmp ( namea, nameb );
5704 }
5705
5706 /**
5707  * Attempt to merge selected track with other tracks specified by the user
5708  * Tracks to merge with must be of the same 'type' as the selected track -
5709  *  either all with timestamps, or all without timestamps
5710  */
5711 static void trw_layer_merge_with_other ( menu_array_sublayer values )
5712 {
5713   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5714   GList *other_tracks = NULL;
5715   GHashTable *ght_tracks;
5716   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5717     ght_tracks = vtl->routes;
5718   else
5719     ght_tracks = vtl->tracks;
5720
5721   VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, values[MA_SUBLAYER_ID] );
5722
5723   if ( !track )
5724     return;
5725
5726   if ( !track->trackpoints )
5727     return;
5728
5729   twt_udata udata;
5730   udata.result = &other_tracks;
5731   udata.exclude = track->trackpoints;
5732   // Allow merging with 'similar' time type time tracks
5733   // i.e. either those times, or those without
5734   udata.with_timestamps = vik_track_get_tp_first(track)->has_timestamp;
5735
5736   g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
5737   other_tracks = g_list_reverse(other_tracks);
5738
5739   if ( !other_tracks ) {
5740     if ( udata.with_timestamps )
5741       a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks with timestamps in this layer found"));
5742     else
5743       a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks without timestamps in this layer found"));
5744     return;
5745   }
5746
5747   // Sort alphabetically for user presentation
5748   // Convert into list of names for usage with dialog function
5749   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5750   GList *other_tracks_names = NULL;
5751   GList *iter = g_list_first ( other_tracks );
5752   while ( iter ) {
5753     other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (ght_tracks, iter->data))->name );
5754     iter = g_list_next ( iter );
5755   }
5756
5757   other_tracks_names = g_list_sort_with_data (other_tracks_names, sort_alphabetically, NULL);
5758
5759   GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5760                                                 other_tracks_names,
5761                                                 TRUE,
5762                                                 _("Merge with..."),
5763                                                 track->is_route ? _("Select route to merge with") : _("Select track to merge with"));
5764   g_list_free(other_tracks);
5765   g_list_free(other_tracks_names);
5766
5767   if (merge_list)
5768   {
5769     GList *l;
5770     for (l = merge_list; l != NULL; l = g_list_next(l)) {
5771       VikTrack *merge_track;
5772       if ( track->is_route )
5773         merge_track = vik_trw_layer_get_route ( vtl, l->data );
5774       else
5775         merge_track = vik_trw_layer_get_track ( vtl, l->data );
5776
5777       if (merge_track) {
5778         vik_track_steal_and_append_trackpoints ( track, merge_track );
5779         if ( track->is_route )
5780           vik_trw_layer_delete_route (vtl, merge_track);
5781         else
5782           vik_trw_layer_delete_track (vtl, merge_track);
5783         track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
5784       }
5785     }
5786     for (l = merge_list; l != NULL; l = g_list_next(l))
5787       g_free(l->data);
5788     g_list_free(merge_list);
5789
5790     vik_layer_emit_update( VIK_LAYER(vtl) );
5791   }
5792 }
5793
5794 // c.f. trw_layer_sorted_track_id_by_name_list
5795 //  but don't add the specified track to the list (normally current track)
5796 static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer id, const VikTrack *trk, gpointer udata)
5797 {
5798   twt_udata *user_data = udata;
5799
5800   // Skip self
5801   if (trk->trackpoints == user_data->exclude) {
5802     return;
5803   }
5804
5805   // Sort named list alphabetically
5806   *(user_data->result) = g_list_insert_sorted_with_data (*(user_data->result), trk->name, sort_alphabetically, NULL);
5807 }
5808
5809 /**
5810  * Join - this allows combining 'tracks' and 'track routes'
5811  *  i.e. doesn't care about whether tracks have consistent timestamps
5812  * ATM can only append one track at a time to the currently selected track
5813  */
5814 static void trw_layer_append_track ( menu_array_sublayer values )
5815 {
5816
5817   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5818   VikTrack *trk;
5819   GHashTable *ght_tracks;
5820   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5821     ght_tracks = vtl->routes;
5822   else
5823     ght_tracks = vtl->tracks;
5824
5825   trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, values[MA_SUBLAYER_ID] );
5826
5827   if ( !trk )
5828     return;
5829
5830   GList *other_tracks_names = NULL;
5831
5832   // Sort alphabetically for user presentation
5833   // Convert into list of names for usage with dialog function
5834   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5835   twt_udata udata;
5836   udata.result = &other_tracks_names;
5837   udata.exclude = trk->trackpoints;
5838
5839   g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
5840
5841   // Note the limit to selecting one track only
5842   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
5843   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
5844   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5845                                                  other_tracks_names,
5846                                                  FALSE,
5847                                                  trk->is_route ? _("Append Route"): _("Append Track"),
5848                                                  trk->is_route ? _("Select the route to append after the current route") :
5849                                                                  _("Select the track to append after the current track") );
5850
5851   g_list_free(other_tracks_names);
5852
5853   // It's a list, but shouldn't contain more than one other track!
5854   if ( append_list ) {
5855     GList *l;
5856     for (l = append_list; l != NULL; l = g_list_next(l)) {
5857       // TODO: at present this uses the first track found by name,
5858       //  which with potential multiple same named tracks may not be the one selected...
5859       VikTrack *append_track;
5860       if ( trk->is_route )
5861         append_track = vik_trw_layer_get_route ( vtl, l->data );
5862       else
5863         append_track = vik_trw_layer_get_track ( vtl, l->data );
5864
5865       if ( append_track ) {
5866         vik_track_steal_and_append_trackpoints ( trk, append_track );
5867         if ( trk->is_route )
5868           vik_trw_layer_delete_route (vtl, append_track);
5869         else
5870           vik_trw_layer_delete_track (vtl, append_track);
5871       }
5872     }
5873     for (l = append_list; l != NULL; l = g_list_next(l))
5874       g_free(l->data);
5875     g_list_free(append_list);
5876
5877     vik_layer_emit_update( VIK_LAYER(vtl) );
5878   }
5879 }
5880
5881 /**
5882  * Very similar to trw_layer_append_track for joining
5883  * but this allows selection from the 'other' list
5884  * If a track is selected, then is shows routes and joins the selected one
5885  * If a route is selected, then is shows tracks and joins the selected one
5886  */
5887 static void trw_layer_append_other ( menu_array_sublayer values )
5888 {
5889
5890   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5891   VikTrack *trk;
5892   GHashTable *ght_mykind, *ght_others;
5893   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
5894     ght_mykind = vtl->routes;
5895     ght_others = vtl->tracks;
5896   }
5897   else {
5898     ght_mykind = vtl->tracks;
5899     ght_others = vtl->routes;
5900   }
5901
5902   trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, values[MA_SUBLAYER_ID] );
5903
5904   if ( !trk )
5905     return;
5906
5907   GList *other_tracks_names = NULL;
5908
5909   // Sort alphabetically for user presentation
5910   // Convert into list of names for usage with dialog function
5911   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5912   twt_udata udata;
5913   udata.result = &other_tracks_names;
5914   udata.exclude = trk->trackpoints;
5915
5916   g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
5917
5918   // Note the limit to selecting one track only
5919   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
5920   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
5921   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5922                                                  other_tracks_names,
5923                                                  FALSE,
5924                                                  trk->is_route ? _("Append Track"): _("Append Route"),
5925                                                  trk->is_route ? _("Select the track to append after the current route") :
5926                                                                  _("Select the route to append after the current track") );
5927
5928   g_list_free(other_tracks_names);
5929
5930   // It's a list, but shouldn't contain more than one other track!
5931   if ( append_list ) {
5932     GList *l;
5933     for (l = append_list; l != NULL; l = g_list_next(l)) {
5934       // TODO: at present this uses the first track found by name,
5935       //  which with potential multiple same named tracks may not be the one selected...
5936
5937       // Get FROM THE OTHER TYPE list
5938       VikTrack *append_track;
5939       if ( trk->is_route )
5940         append_track = vik_trw_layer_get_track ( vtl, l->data );
5941       else
5942         append_track = vik_trw_layer_get_route ( vtl, l->data );
5943
5944       if ( append_track ) {
5945
5946         if ( !append_track->is_route &&
5947              ( ( vik_track_get_segment_count ( append_track ) > 1 ) ||
5948                ( vik_track_get_average_speed ( append_track ) > 0.0 ) ) ) {
5949
5950           if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5951                                       _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) ) {
5952             vik_track_merge_segments ( append_track );
5953             vik_track_to_routepoints ( append_track );
5954           }
5955           else {
5956             break;
5957           }
5958         }
5959
5960         vik_track_steal_and_append_trackpoints ( trk, append_track );
5961
5962         // Delete copied which is FROM THE OTHER TYPE list
5963         if ( trk->is_route )
5964           vik_trw_layer_delete_track (vtl, append_track);
5965         else
5966           vik_trw_layer_delete_route (vtl, append_track);
5967       }
5968     }
5969     for (l = append_list; l != NULL; l = g_list_next(l))
5970       g_free(l->data);
5971     g_list_free(append_list);
5972     vik_layer_emit_update( VIK_LAYER(vtl) );
5973   }
5974 }
5975
5976 /* merge by segments */
5977 static void trw_layer_merge_by_segment ( menu_array_sublayer values )
5978 {
5979   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5980   VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5981   guint segments = vik_track_merge_segments ( trk );
5982   // NB currently no need to redraw as segments not actually shown on the display
5983   // However inform the user of what happened:
5984   gchar str[64];
5985   const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
5986   g_snprintf(str, 64, tmp_str, segments);
5987   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
5988 }
5989
5990 /* merge by time routine */
5991 static void trw_layer_merge_by_timestamp ( menu_array_sublayer values )
5992 {
5993   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
5994
5995   //time_t t1, t2;
5996
5997   GList *tracks_with_timestamp = NULL;
5998   VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
5999   if (orig_trk->trackpoints &&
6000       !vik_track_get_tp_first(orig_trk)->has_timestamp) {
6001     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
6002     return;
6003   }
6004
6005   twt_udata udata;
6006   udata.result = &tracks_with_timestamp;
6007   udata.exclude = orig_trk->trackpoints;
6008   udata.with_timestamps = TRUE;
6009   g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
6010   tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
6011
6012   if (!tracks_with_timestamp) {
6013     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
6014     return;
6015   }
6016   g_list_free(tracks_with_timestamp);
6017
6018   static guint threshold_in_minutes = 1;
6019   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6020                                _("Merge Threshold..."),
6021                                _("Merge when time between tracks less than:"),
6022                                &threshold_in_minutes)) {
6023     return;
6024   }
6025
6026   // keep attempting to merge all tracks until no merges within the time specified is possible
6027   gboolean attempt_merge = TRUE;
6028   GList *nearby_tracks = NULL;
6029   GList *trps;
6030   static gpointer params[3];
6031
6032   while ( attempt_merge ) {
6033
6034     // Don't try again unless tracks have changed
6035     attempt_merge = FALSE;
6036
6037     trps = orig_trk->trackpoints;
6038     if ( !trps )
6039       return;
6040
6041     if (nearby_tracks) {
6042       g_list_free(nearby_tracks);
6043       nearby_tracks = NULL;
6044     }
6045
6046     params[0] = &nearby_tracks;
6047     params[1] = (gpointer)trps;
6048     params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
6049
6050     /* get a list of adjacent-in-time tracks */
6051     g_hash_table_foreach(vtl->tracks, find_nearby_tracks_by_time, params);
6052
6053     /* merge them */
6054     GList *l = nearby_tracks;
6055     while ( l ) {
6056       /* remove trackpoints from merged track, delete track */
6057       vik_track_steal_and_append_trackpoints ( orig_trk, VIK_TRACK(l->data) );
6058       vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
6059
6060       // Tracks have changed, therefore retry again against all the remaining tracks
6061       attempt_merge = TRUE;
6062
6063       l = g_list_next(l);
6064     }
6065
6066     orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
6067   }
6068
6069   g_list_free(nearby_tracks);
6070
6071   vik_layer_emit_update( VIK_LAYER(vtl) );
6072 }
6073
6074 /**
6075  * Split a track at the currently selected trackpoint
6076  */
6077 static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subtype )
6078 {
6079   if ( !vtl->current_tpl )
6080     return;
6081
6082   if ( vtl->current_tpl->next && vtl->current_tpl->prev ) {
6083     gchar *name = trw_layer_new_unique_sublayer_name(vtl, subtype, vtl->current_tp_track->name);
6084     if ( name ) {
6085       VikTrack *tr = vik_track_copy ( vtl->current_tp_track, FALSE );
6086       GList *newglist = g_list_alloc ();
6087       newglist->prev = NULL;
6088       newglist->next = vtl->current_tpl->next;
6089       newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
6090       tr->trackpoints = newglist;
6091
6092       vtl->current_tpl->next->prev = newglist; /* end old track here */
6093       vtl->current_tpl->next = NULL;
6094
6095       // Bounds of the selected track changed due to the split
6096       vik_track_calculate_bounds ( vtl->current_tp_track );
6097
6098       vtl->current_tpl = newglist; /* change tp to first of new track. */
6099       vtl->current_tp_track = tr;
6100
6101       if ( tr->is_route )
6102         vik_trw_layer_add_route ( vtl, name, tr );
6103       else
6104         vik_trw_layer_add_track ( vtl, name, tr );
6105
6106       // Bounds of the new track created by the split
6107       vik_track_calculate_bounds ( tr );
6108
6109       trku_udata udata;
6110       udata.trk  = tr;
6111       udata.uuid = NULL;
6112
6113       // Also need id of newly created track
6114       gpointer *trkf;
6115       if ( tr->is_route )
6116          trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
6117       else
6118          trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
6119
6120       if ( trkf && udata.uuid )
6121         vtl->current_tp_id = udata.uuid;
6122       else
6123         vtl->current_tp_id = NULL;
6124
6125       vik_layer_emit_update(VIK_LAYER(vtl));
6126     }
6127     g_free ( name );
6128   }
6129 }
6130
6131 /* split by time routine */
6132 static void trw_layer_split_by_timestamp ( menu_array_sublayer values )
6133 {
6134   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6135   VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6136   GList *trps = track->trackpoints;
6137   GList *iter;
6138   GList *newlists = NULL;
6139   GList *newtps = NULL;
6140   static guint thr = 1;
6141
6142   time_t ts, prev_ts;
6143
6144   if ( !trps )
6145     return;
6146
6147   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl), 
6148                                _("Split Threshold..."), 
6149                                _("Split when time between trackpoints exceeds:"), 
6150                                &thr)) {
6151     return;
6152   }
6153
6154   /* iterate through trackpoints, and copy them into new lists without touching original list */
6155   prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
6156   iter = trps;
6157
6158   while (iter) {
6159     ts = VIK_TRACKPOINT(iter->data)->timestamp;
6160
6161     // Check for unordered time points - this is quite a rare occurence - unless one has reversed a track.
6162     if (ts < prev_ts) {
6163       gchar tmp_str[64];
6164       strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&ts) );
6165       if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6166                                 _("Can not split track due to trackpoints not ordered in time - such as at %s.\n\nGoto this trackpoint?"),
6167                                 tmp_str ) ) {
6168         goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(VIK_TRACKPOINT(iter->data)->coord) );
6169       }
6170       return;
6171     }
6172
6173     if (ts - prev_ts > thr*60) {
6174       /* flush accumulated trackpoints into new list */
6175       newlists = g_list_append(newlists, g_list_reverse(newtps));
6176       newtps = NULL;
6177     }
6178
6179     /* accumulate trackpoint copies in newtps, in reverse order */
6180     newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
6181     prev_ts = ts;
6182     iter = g_list_next(iter);
6183   }
6184   if (newtps) {
6185       newlists = g_list_append(newlists, g_list_reverse(newtps));
6186   }
6187
6188   /* put lists of trackpoints into tracks */
6189   iter = newlists;
6190   // Only bother updating if the split results in new tracks
6191   if (g_list_length (newlists) > 1) {
6192     while (iter) {
6193       gchar *new_tr_name;
6194       VikTrack *tr;
6195
6196       tr = vik_track_copy ( track, FALSE );
6197       tr->trackpoints = (GList *)(iter->data);
6198
6199       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
6200       vik_trw_layer_add_track(vtl, new_tr_name, tr);
6201       g_free ( new_tr_name );
6202       vik_track_calculate_bounds ( tr );
6203       iter = g_list_next(iter);
6204     }
6205     // Remove original track and then update the display
6206     vik_trw_layer_delete_track (vtl, track);
6207     vik_layer_emit_update(VIK_LAYER(vtl));
6208   }
6209   g_list_free(newlists);
6210 }
6211
6212 /**
6213  * Split a track by the number of points as specified by the user
6214  */
6215 static void trw_layer_split_by_n_points ( menu_array_sublayer values )
6216 {
6217   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6218   VikTrack *track;
6219   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6220     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6221   else
6222     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6223
6224   if ( !track )
6225     return;
6226
6227   // Check valid track
6228   GList *trps = track->trackpoints;
6229   if ( !trps )
6230     return;
6231
6232   gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6233                                              _("Split Every Nth Point"),
6234                                              _("Split on every Nth point:"),
6235                                              250,   // Default value as per typical limited track capacity of various GPS devices
6236                                              2,     // Min
6237                                              65536, // Max
6238                                              5);    // Step
6239   // Was a valid number returned?
6240   if (!points)
6241     return;
6242
6243   // Now split...
6244   GList *iter;
6245   GList *newlists = NULL;
6246   GList *newtps = NULL;
6247   gint count = 0;
6248   iter = trps;
6249
6250   while (iter) {
6251     /* accumulate trackpoint copies in newtps, in reverse order */
6252     newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
6253     count++;
6254     if (count >= points) {
6255       /* flush accumulated trackpoints into new list */
6256       newlists = g_list_append(newlists, g_list_reverse(newtps));
6257       newtps = NULL;
6258       count = 0;
6259     }
6260     iter = g_list_next(iter);
6261   }
6262
6263   // If there is a remaining chunk put that into the new split list
6264   // This may well be the whole track if no split points were encountered
6265   if (newtps) {
6266       newlists = g_list_append(newlists, g_list_reverse(newtps));
6267   }
6268
6269   /* put lists of trackpoints into tracks */
6270   iter = newlists;
6271   // Only bother updating if the split results in new tracks
6272   if (g_list_length (newlists) > 1) {
6273     while (iter) {
6274       gchar *new_tr_name;
6275       VikTrack *tr;
6276
6277       tr = vik_track_copy ( track, FALSE );
6278       tr->trackpoints = (GList *)(iter->data);
6279
6280       if ( track->is_route ) {
6281         new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, track->name);
6282         vik_trw_layer_add_route(vtl, new_tr_name, tr);
6283       }
6284       else {
6285         new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
6286         vik_trw_layer_add_track(vtl, new_tr_name, tr);
6287       }
6288       g_free ( new_tr_name );
6289       vik_track_calculate_bounds ( tr );
6290
6291       iter = g_list_next(iter);
6292     }
6293     // Remove original track and then update the display
6294     if ( track->is_route )
6295       vik_trw_layer_delete_route (vtl, track);
6296     else
6297       vik_trw_layer_delete_track (vtl, track);
6298     vik_layer_emit_update(VIK_LAYER(vtl));
6299   }
6300   g_list_free(newlists);
6301 }
6302
6303 /**
6304  * Split a track at the currently selected trackpoint
6305  */
6306 static void trw_layer_split_at_trackpoint ( menu_array_sublayer values )
6307 {
6308   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6309   gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]);
6310   trw_layer_split_at_selected_trackpoint ( vtl, subtype );
6311 }
6312
6313 /**
6314  * Split a track by its segments
6315  * Routes do not have segments so don't call this for routes
6316  */
6317 static void trw_layer_split_segments ( menu_array_sublayer values )
6318 {
6319   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6320   VikTrack *trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6321
6322   if ( !trk )
6323     return;
6324
6325   guint ntracks;
6326
6327   VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
6328   gchar *new_tr_name;
6329   guint i;
6330   for ( i = 0; i < ntracks; i++ ) {
6331     if ( tracks[i] ) {
6332       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, trk->name);
6333       vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
6334       g_free ( new_tr_name );
6335     }
6336   }
6337   if ( tracks ) {
6338     g_free ( tracks );
6339     // Remove original track
6340     vik_trw_layer_delete_track ( vtl, trk );
6341     vik_layer_emit_update ( VIK_LAYER(vtl) );
6342   }
6343   else {
6344     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments"));
6345   }
6346 }
6347 /* end of split/merge routines */
6348
6349 static void trw_layer_trackpoint_selected_delete ( VikTrwLayer *vtl, VikTrack *trk )
6350 {
6351   GList *new_tpl;
6352
6353   // Find available adjacent trackpoint
6354   if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) ) {
6355     if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
6356       VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
6357
6358     // Delete current trackpoint
6359     vik_trackpoint_free ( vtl->current_tpl->data );
6360     trk->trackpoints = g_list_delete_link ( trk->trackpoints, vtl->current_tpl );
6361
6362     // Set to current to the available adjacent trackpoint
6363     vtl->current_tpl = new_tpl;
6364
6365     if ( vtl->current_tp_track ) {
6366       vik_track_calculate_bounds ( vtl->current_tp_track );
6367     }
6368   }
6369   else {
6370     // Delete current trackpoint
6371     vik_trackpoint_free ( vtl->current_tpl->data );
6372     trk->trackpoints = g_list_delete_link ( trk->trackpoints, vtl->current_tpl );
6373     trw_layer_cancel_current_tp ( vtl, FALSE );
6374   }
6375 }
6376
6377 /**
6378  * Delete the selected point
6379  */
6380 static void trw_layer_delete_point_selected ( menu_array_sublayer values )
6381 {
6382   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6383   VikTrack *trk;
6384   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6385     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6386   else
6387     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6388
6389   if ( !trk )
6390     return;
6391
6392   if ( !vtl->current_tpl )
6393     return;
6394
6395   trw_layer_trackpoint_selected_delete ( vtl, trk );
6396
6397   // Track has been updated so update tps:
6398   trw_layer_cancel_tps_of_track ( vtl, trk );
6399
6400   vik_layer_emit_update ( VIK_LAYER(vtl) );
6401 }
6402
6403 /**
6404  * Delete adjacent track points at the same position
6405  * AKA Delete Dulplicates on the Properties Window
6406  */
6407 static void trw_layer_delete_points_same_position ( menu_array_sublayer values )
6408 {
6409   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6410   VikTrack *trk;
6411   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6412     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6413   else
6414     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6415
6416   if ( !trk )
6417     return;
6418
6419   gulong removed = vik_track_remove_dup_points ( trk );
6420
6421   // Track has been updated so update tps:
6422   trw_layer_cancel_tps_of_track ( vtl, trk );
6423
6424   // Inform user how much was deleted as it's not obvious from the normal view
6425   gchar str[64];
6426   const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
6427   g_snprintf(str, 64, tmp_str, removed);
6428   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
6429
6430   vik_layer_emit_update ( VIK_LAYER(vtl) );
6431 }
6432
6433 /**
6434  * Delete adjacent track points with the same timestamp
6435  * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
6436  */
6437 static void trw_layer_delete_points_same_time ( menu_array_sublayer values )
6438 {
6439   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6440   VikTrack *trk;
6441   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6442     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6443   else
6444     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6445
6446   if ( !trk )
6447     return;
6448
6449   gulong removed = vik_track_remove_same_time_points ( trk );
6450
6451   // Track has been updated so update tps:
6452   trw_layer_cancel_tps_of_track ( vtl, trk );
6453
6454   // Inform user how much was deleted as it's not obvious from the normal view
6455   gchar str[64];
6456   const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
6457   g_snprintf(str, 64, tmp_str, removed);
6458   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
6459
6460   vik_layer_emit_update ( VIK_LAYER(vtl) );
6461 }
6462
6463 /**
6464  * Insert a point
6465  */
6466 static void trw_layer_insert_point_after ( menu_array_sublayer values )
6467 {
6468   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6469   VikTrack *track;
6470   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6471     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6472   else
6473     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6474
6475   if ( ! track )
6476     return;
6477
6478   trw_layer_insert_tp_beside_current_tp ( vtl, FALSE );
6479
6480   vik_layer_emit_update ( VIK_LAYER(vtl) );
6481 }
6482
6483 static void trw_layer_insert_point_before ( menu_array_sublayer values )
6484 {
6485   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6486   VikTrack *track;
6487   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6488     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6489   else
6490     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6491
6492   if ( ! track )
6493     return;
6494
6495   trw_layer_insert_tp_beside_current_tp ( vtl, TRUE );
6496
6497   vik_layer_emit_update ( VIK_LAYER(vtl) );
6498 }
6499
6500 /**
6501  * Reverse a track
6502  */
6503 static void trw_layer_reverse ( menu_array_sublayer values )
6504 {
6505   VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
6506   VikTrack *track;
6507   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6508     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
6509   else
6510     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
6511
6512   if ( ! track )
6513     return;
6514
6515   vik_track_reverse ( track );
6516  
6517   vik_layer_emit_update ( VIK_LAYER(vtl) );
6518 }
6519
6520 /**
6521  * Similar to trw_layer_enum_item, but this uses a sorted method
6522  */
6523 /* Currently unused
6524 static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata)
6525 {
6526   GList **list = (GList**)udata;
6527   // *list = g_list_prepend(*all, key); //unsorted method
6528   // Sort named list alphabetically
6529   *list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL);
6530 }
6531 */
6532
6533 /**
6534  * Now Waypoint specific sort
6535  */
6536 static void trw_layer_sorted_wp_id_by_name_list (const gpointer id, const VikWaypoint *wp, gpointer udata)
6537 {
6538   GList **list = (GList**)udata;
6539   // Sort named list alphabetically
6540   *list = g_list_insert_sorted_with_data (*list, wp->name, sort_alphabetically, NULL);
6541 }
6542
6543 /**
6544  * Track specific sort
6545  */
6546 static void trw_layer_sorted_track_id_by_name_list (const gpointer id, const VikTrack *trk, gpointer udata)
6547 {
6548   GList **list = (GList**)udata;
6549   // Sort named list alphabetically
6550   *list = g_list_insert_sorted_with_data (*list, trk->name, sort_alphabetically, NULL);
6551 }
6552
6553
6554 typedef struct {
6555   gboolean    has_same_track_name;
6556   const gchar *same_track_name;
6557 } same_track_name_udata;
6558
6559 static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
6560 {
6561   const gchar* namea = (const gchar*) aa;
6562   const gchar* nameb = (const gchar*) bb;
6563
6564   // the test
6565   gint result = strcmp ( namea, nameb );
6566
6567   if ( result == 0 ) {
6568     // Found two names the same
6569     same_track_name_udata *user_data = udata;
6570     user_data->has_same_track_name = TRUE;
6571     user_data->same_track_name = namea;
6572   }
6573
6574   // Leave ordering the same
6575   return 0;
6576 }
6577
6578 /**
6579  * Find out if any tracks have the same name in this hash table
6580  */
6581 static gboolean trw_layer_has_same_track_names ( GHashTable *ht_tracks )
6582 {
6583   // Sort items by name, then compare if any next to each other are the same
6584
6585   GList *track_names = NULL;
6586   g_hash_table_foreach ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6587
6588   // No tracks
6589   if ( ! track_names )
6590     return FALSE;
6591
6592   same_track_name_udata udata;
6593   udata.has_same_track_name = FALSE;
6594
6595   // Use sort routine to traverse list comparing items
6596   // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
6597   GList *dummy_list = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6598   // Still no tracks...
6599   if ( ! dummy_list )
6600     return FALSE;
6601
6602   return udata.has_same_track_name;
6603 }
6604
6605 /**
6606  * Force unqiue track names for the track table specified
6607  * Note the panel is a required parameter to enable the update of the names displayed
6608  * Specify if on tracks or else on routes
6609  */
6610 static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp, GHashTable *track_table, gboolean ontrack )
6611 {
6612   // . Search list for an instance of repeated name
6613   // . get track of this name
6614   // . create new name
6615   // . rename track & update equiv. treeview iter
6616   // . repeat until all different
6617
6618   same_track_name_udata udata;
6619
6620   GList *track_names = NULL;
6621   udata.has_same_track_name = FALSE;
6622   udata.same_track_name = NULL;
6623
6624   g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6625
6626   // No tracks
6627   if ( ! track_names )
6628     return;
6629
6630   GList *dummy_list1 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6631
6632   // Still no tracks...
6633   if ( ! dummy_list1 )
6634     return;
6635
6636   while ( udata.has_same_track_name ) {
6637
6638     // Find a track with the same name
6639     VikTrack *trk;
6640     if ( ontrack )
6641       trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name );
6642     else
6643       trk = vik_trw_layer_get_route ( vtl, (gpointer) udata.same_track_name );
6644
6645     if ( ! trk ) {
6646       // Broken :(
6647       g_critical("Houston, we've had a problem.");
6648       vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
6649                                   _("Internal Error in vik_trw_layer_uniquify_tracks") );
6650       return;
6651     }
6652
6653     // Rename it
6654     gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, udata.same_track_name );
6655     vik_track_set_name ( trk, newname );
6656
6657     trku_udata udataU;
6658     udataU.trk  = trk;
6659     udataU.uuid = NULL;
6660
6661     // Need want key of it for treeview update
6662     gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
6663
6664     if ( trkf && udataU.uuid ) {
6665
6666       GtkTreeIter *it;
6667       if ( ontrack )
6668         it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
6669       else
6670         it = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
6671
6672       if ( it ) {
6673         vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
6674         if ( ontrack )
6675           vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->wp_sort_order );
6676         else
6677           vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->wp_sort_order );
6678       }
6679     }
6680
6681     // Start trying to find same names again...
6682     track_names = NULL;
6683     g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6684     udata.has_same_track_name = FALSE;
6685     GList *dummy_list2 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6686
6687     // No tracks any more - give up searching
6688     if ( ! dummy_list2 )
6689       udata.has_same_track_name = FALSE;
6690   }
6691
6692   // Update
6693   vik_layers_panel_emit_update ( vlp );
6694 }
6695
6696 static void trw_layer_sort_order_a2z ( menu_array_sublayer values )
6697 {
6698   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
6699   GtkTreeIter *iter;
6700
6701   switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
6702   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
6703     iter = &(vtl->tracks_iter);
6704     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6705     break;
6706   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
6707     iter = &(vtl->routes_iter);
6708     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6709     break;
6710   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
6711     iter = &(vtl->waypoints_iter);
6712     vtl->wp_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6713     break;
6714   }
6715
6716   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
6717 }
6718
6719 static void trw_layer_sort_order_z2a ( menu_array_sublayer values )
6720 {
6721   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
6722   GtkTreeIter *iter;
6723
6724   switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
6725   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
6726     iter = &(vtl->tracks_iter);
6727     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6728     break;
6729   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
6730     iter = &(vtl->routes_iter);
6731     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6732     break;
6733   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
6734     iter = &(vtl->waypoints_iter);
6735     vtl->wp_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6736     break;
6737   }
6738
6739   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_DESCENDING );
6740 }
6741
6742 /**
6743  *
6744  */
6745 static void trw_layer_delete_tracks_from_selection ( menu_array_layer values )
6746 {
6747   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
6748   GList *all = NULL;
6749
6750   // Ensure list of track names offered is unique
6751   if ( trw_layer_has_same_track_names ( vtl->tracks ) ) {
6752     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6753                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6754       vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]), vtl->tracks, TRUE );
6755     }
6756     else
6757       return;
6758   }
6759
6760   // Sort list alphabetically for better presentation
6761   g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
6762
6763   if ( ! all ) {
6764     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No tracks found"));
6765     return;
6766   }
6767
6768   // Get list of items to delete from the user
6769   GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6770                                                  all,
6771                                                  TRUE,
6772                                                  _("Delete Selection"),
6773                                                  _("Select tracks to delete"));
6774   g_list_free(all);
6775
6776   // Delete requested tracks
6777   // since specificly requested, IMHO no need for extra confirmation
6778   if ( delete_list ) {
6779     GList *l;
6780     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6781       // This deletes first trk it finds of that name (but uniqueness is enforced above)
6782       trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
6783     }
6784     g_list_free(delete_list);
6785     vik_layer_emit_update( VIK_LAYER(vtl) );
6786   }
6787 }
6788
6789 /**
6790  *
6791  */
6792 static void trw_layer_delete_routes_from_selection ( menu_array_layer values )
6793 {
6794   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
6795   GList *all = NULL;
6796
6797   // Ensure list of track names offered is unique
6798   if ( trw_layer_has_same_track_names ( vtl->routes ) ) {
6799     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6800                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6801       vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]), vtl->routes, FALSE );
6802     }
6803     else
6804       return;
6805   }
6806
6807   // Sort list alphabetically for better presentation
6808   g_hash_table_foreach(vtl->routes, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
6809
6810   if ( ! all ) {
6811     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No routes found"));
6812     return;
6813   }
6814
6815   // Get list of items to delete from the user
6816   GList *delete_list = a_dialog_select_from_list ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6817                                                    all,
6818                                                    TRUE,
6819                                                    _("Delete Selection"),
6820                                                    _("Select routes to delete") );
6821   g_list_free(all);
6822
6823   // Delete requested routes
6824   // since specificly requested, IMHO no need for extra confirmation
6825   if ( delete_list ) {
6826     GList *l;
6827     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6828       // This deletes first route it finds of that name (but uniqueness is enforced above)
6829       trw_layer_delete_track_by_name (vtl, l->data, vtl->routes);
6830     }
6831     g_list_free(delete_list);
6832     vik_layer_emit_update( VIK_LAYER(vtl) );
6833   }
6834 }
6835
6836 typedef struct {
6837   gboolean    has_same_waypoint_name;
6838   const gchar *same_waypoint_name;
6839 } same_waypoint_name_udata;
6840
6841 static gint check_waypoints_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
6842 {
6843   const gchar* namea = (const gchar*) aa;
6844   const gchar* nameb = (const gchar*) bb;
6845
6846   // the test
6847   gint result = strcmp ( namea, nameb );
6848
6849   if ( result == 0 ) {
6850     // Found two names the same
6851     same_waypoint_name_udata *user_data = udata;
6852     user_data->has_same_waypoint_name = TRUE;
6853     user_data->same_waypoint_name = namea;
6854   }
6855
6856   // Leave ordering the same
6857   return 0;
6858 }
6859
6860 /**
6861  * Find out if any waypoints have the same name in this layer
6862  */
6863 gboolean trw_layer_has_same_waypoint_names ( VikTrwLayer *vtl )
6864 {
6865   // Sort items by name, then compare if any next to each other are the same
6866
6867   GList *waypoint_names = NULL;
6868   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6869
6870   // No waypoints
6871   if ( ! waypoint_names )
6872     return FALSE;
6873
6874   same_waypoint_name_udata udata;
6875   udata.has_same_waypoint_name = FALSE;
6876
6877   // Use sort routine to traverse list comparing items
6878   // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
6879   GList *dummy_list = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6880   // Still no waypoints...
6881   if ( ! dummy_list )
6882     return FALSE;
6883
6884   return udata.has_same_waypoint_name;
6885 }
6886
6887 /**
6888  * Force unqiue waypoint names for this layer
6889  * Note the panel is a required parameter to enable the update of the names displayed
6890  */
6891 static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel *vlp )
6892 {
6893   // . Search list for an instance of repeated name
6894   // . get waypoint of this name
6895   // . create new name
6896   // . rename waypoint & update equiv. treeview iter
6897   // . repeat until all different
6898
6899   same_waypoint_name_udata udata;
6900
6901   GList *waypoint_names = NULL;
6902   udata.has_same_waypoint_name = FALSE;
6903   udata.same_waypoint_name = NULL;
6904
6905   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6906
6907   // No waypoints
6908   if ( ! waypoint_names )
6909     return;
6910
6911   GList *dummy_list1 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6912
6913   // Still no waypoints...
6914   if ( ! dummy_list1 )
6915     return;
6916
6917   while ( udata.has_same_waypoint_name ) {
6918
6919     // Find a waypoint with the same name
6920     VikWaypoint *waypoint = vik_trw_layer_get_waypoint ( vtl, (gpointer) udata.same_waypoint_name );
6921
6922     if ( ! waypoint ) {
6923       // Broken :(
6924       g_critical("Houston, we've had a problem.");
6925       vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
6926                                   _("Internal Error in vik_trw_layer_uniquify_waypoints") );
6927       return;
6928     }
6929
6930     // Rename it
6931     gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, udata.same_waypoint_name );
6932
6933     trw_layer_waypoint_rename ( vtl, waypoint, newname );
6934
6935     // Start trying to find same names again...
6936     waypoint_names = NULL;
6937     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6938     udata.has_same_waypoint_name = FALSE;
6939     GList *dummy_list2 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6940
6941     // No waypoints any more - give up searching
6942     if ( ! dummy_list2 )
6943       udata.has_same_waypoint_name = FALSE;
6944   }
6945
6946   // Update
6947   vik_layers_panel_emit_update ( vlp );
6948 }
6949
6950 /**
6951  *
6952  */
6953 static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values )
6954 {
6955   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
6956   GList *all = NULL;
6957
6958   // Ensure list of waypoint names offered is unique
6959   if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
6960     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6961                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6962       vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]) );
6963     }
6964     else
6965       return;
6966   }
6967
6968   // Sort list alphabetically for better presentation
6969   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all);
6970   if ( ! all ) {
6971     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found"));
6972     return;
6973   }
6974
6975   all = g_list_sort_with_data(all, sort_alphabetically, NULL);
6976
6977   // Get list of items to delete from the user
6978   GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6979                                                  all,
6980                                                  TRUE,
6981                                                  _("Delete Selection"),
6982                                                  _("Select waypoints to delete"));
6983   g_list_free(all);
6984
6985   // Delete requested waypoints
6986   // since specificly requested, IMHO no need for extra confirmation
6987   if ( delete_list ) {
6988     GList *l;
6989     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6990       // This deletes first waypoint it finds of that name (but uniqueness is enforced above)
6991       trw_layer_delete_waypoint_by_name (vtl, l->data);
6992     }
6993     g_list_free(delete_list);
6994
6995     trw_layer_calculate_bounds_waypoints ( vtl );
6996     vik_layer_emit_update( VIK_LAYER(vtl) );
6997   }
6998
6999 }
7000
7001 /**
7002  *
7003  */
7004 static void trw_layer_iter_visibility_toggle ( gpointer id, GtkTreeIter *it, VikTreeview *vt )
7005 {
7006   vik_treeview_item_toggle_visible ( vt, it );
7007 }
7008
7009 /**
7010  *
7011  */
7012 static void trw_layer_iter_visibility ( gpointer id, GtkTreeIter *it, gpointer vis_data[2] )
7013 {
7014   vik_treeview_item_set_visible ( (VikTreeview*)vis_data[0], it, GPOINTER_TO_INT (vis_data[1]) );
7015 }
7016
7017 /**
7018  *
7019  */
7020 static void trw_layer_waypoints_visibility ( gpointer id, VikWaypoint *wp, gpointer on_off )
7021 {
7022   wp->visible = GPOINTER_TO_INT (on_off);
7023 }
7024
7025 /**
7026  *
7027  */
7028 static void trw_layer_waypoints_toggle_visibility ( gpointer id, VikWaypoint *wp )
7029 {
7030   wp->visible = !wp->visible;
7031 }
7032
7033 /**
7034  *
7035  */
7036 static void trw_layer_waypoints_visibility_off ( menu_array_layer values )
7037 {
7038   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7039   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
7040   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7041   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
7042   // Redraw
7043   vik_layer_emit_update ( VIK_LAYER(vtl) );
7044 }
7045
7046 /**
7047  *
7048  */
7049 static void trw_layer_waypoints_visibility_on ( menu_array_layer values )
7050 {
7051   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7052   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
7053   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7054   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
7055   // Redraw
7056   vik_layer_emit_update ( VIK_LAYER(vtl) );
7057 }
7058
7059 /**
7060  *
7061  */
7062 static void trw_layer_waypoints_visibility_toggle ( menu_array_layer values )
7063 {
7064   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7065   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
7066   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_toggle_visibility, NULL );
7067   // Redraw
7068   vik_layer_emit_update ( VIK_LAYER(vtl) );
7069 }
7070
7071 /**
7072  *
7073  */
7074 static void trw_layer_tracks_visibility ( gpointer id, VikTrack *trk, gpointer on_off )
7075 {
7076   trk->visible = GPOINTER_TO_INT (on_off);
7077 }
7078
7079 /**
7080  *
7081  */
7082 static void trw_layer_tracks_toggle_visibility ( gpointer id, VikTrack *trk )
7083 {
7084   trk->visible = !trk->visible;
7085 }
7086
7087 /**
7088  *
7089  */
7090 static void trw_layer_tracks_visibility_off ( menu_array_layer values )
7091 {
7092   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7093   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
7094   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7095   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
7096   // Redraw
7097   vik_layer_emit_update ( VIK_LAYER(vtl) );
7098 }
7099
7100 /**
7101  *
7102  */
7103 static void trw_layer_tracks_visibility_on ( menu_array_layer values )
7104 {
7105   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7106   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
7107   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7108   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
7109   // Redraw
7110   vik_layer_emit_update ( VIK_LAYER(vtl) );
7111 }
7112
7113 /**
7114  *
7115  */
7116 static void trw_layer_tracks_visibility_toggle ( menu_array_layer values )
7117 {
7118   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7119   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
7120   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
7121   // Redraw
7122   vik_layer_emit_update ( VIK_LAYER(vtl) );
7123 }
7124
7125 /**
7126  *
7127  */
7128 static void trw_layer_routes_visibility_off ( menu_array_layer values )
7129 {
7130   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7131   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
7132   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7133   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
7134   // Redraw
7135   vik_layer_emit_update ( VIK_LAYER(vtl) );
7136 }
7137
7138 /**
7139  *
7140  */
7141 static void trw_layer_routes_visibility_on ( menu_array_layer values )
7142 {
7143   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7144   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
7145   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7146   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
7147   // Redraw
7148   vik_layer_emit_update ( VIK_LAYER(vtl) );
7149 }
7150
7151 /**
7152  *
7153  */
7154 static void trw_layer_routes_visibility_toggle ( menu_array_layer values )
7155 {
7156   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7157   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
7158   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
7159   // Redraw
7160   vik_layer_emit_update ( VIK_LAYER(vtl) );
7161 }
7162
7163 /**
7164  * vik_trw_layer_build_waypoint_list_t:
7165  *
7166  * Helper function to construct a list of #vik_trw_waypoint_list_t
7167  */
7168 GList *vik_trw_layer_build_waypoint_list_t ( VikTrwLayer *vtl, GList *waypoints )
7169 {
7170   GList *waypoints_and_layers = NULL;
7171   // build waypoints_and_layers list
7172   while ( waypoints ) {
7173     vik_trw_waypoint_list_t *vtdl = g_malloc (sizeof(vik_trw_waypoint_list_t));
7174     vtdl->wpt = VIK_WAYPOINT(waypoints->data);
7175     vtdl->vtl = vtl;
7176     waypoints_and_layers = g_list_prepend ( waypoints_and_layers, vtdl );
7177     waypoints = g_list_next ( waypoints );
7178   }
7179   return waypoints_and_layers;
7180 }
7181
7182 /**
7183  * trw_layer_create_waypoint_list:
7184  *
7185  * Create the latest list of waypoints with the associated layer(s)
7186  *  Although this will always be from a single layer here
7187  */
7188 static GList* trw_layer_create_waypoint_list ( VikLayer *vl, gpointer user_data )
7189 {
7190   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
7191   GList *waypoints = g_hash_table_get_values ( vik_trw_layer_get_waypoints(vtl) );
7192
7193   return vik_trw_layer_build_waypoint_list_t ( vtl, waypoints );
7194 }
7195
7196 /**
7197  * trw_layer_analyse_close:
7198  *
7199  * Stuff to do on dialog closure
7200  */
7201 static void trw_layer_analyse_close ( GtkWidget *dialog, gint resp, VikLayer* vl )
7202 {
7203   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
7204   gtk_widget_destroy ( dialog );
7205   vtl->tracks_analysis_dialog = NULL;
7206 }
7207
7208 /**
7209  * vik_trw_layer_build_track_list_t:
7210  *
7211  * Helper function to construct a list of #vik_trw_track_list_t
7212  */
7213 GList *vik_trw_layer_build_track_list_t ( VikTrwLayer *vtl, GList *tracks )
7214 {
7215   GList *tracks_and_layers = NULL;
7216   // build tracks_and_layers list
7217   while ( tracks ) {
7218     vik_trw_track_list_t *vtdl = g_malloc (sizeof(vik_trw_track_list_t));
7219     vtdl->trk = VIK_TRACK(tracks->data);
7220     vtdl->vtl = vtl;
7221     tracks_and_layers = g_list_prepend ( tracks_and_layers, vtdl );
7222     tracks = g_list_next ( tracks );
7223   }
7224   return tracks_and_layers;
7225 }
7226
7227 /**
7228  * trw_layer_create_track_list:
7229  *
7230  * Create the latest list of tracks with the associated layer(s)
7231  *  Although this will always be from a single layer here
7232  */
7233 static GList* trw_layer_create_track_list ( VikLayer *vl, gpointer user_data )
7234 {
7235   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
7236   GList *tracks = NULL;
7237   if ( GPOINTER_TO_INT(user_data) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
7238     tracks = g_hash_table_get_values ( vik_trw_layer_get_tracks(vtl) );
7239   else
7240     tracks = g_hash_table_get_values ( vik_trw_layer_get_routes(vtl) );
7241
7242   return vik_trw_layer_build_track_list_t ( vtl, tracks );
7243 }
7244
7245 static void trw_layer_tracks_stats ( menu_array_layer values )
7246 {
7247   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7248   // There can only be one!
7249   if ( vtl->tracks_analysis_dialog )
7250     return;
7251
7252   vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
7253                                                              VIK_LAYER(vtl)->name,
7254                                                              VIK_LAYER(vtl),
7255                                                              GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACKS),
7256                                                              trw_layer_create_track_list,
7257                                                              trw_layer_analyse_close );
7258 }
7259
7260 /**
7261  *
7262  */
7263 static void trw_layer_routes_stats ( menu_array_layer values )
7264 {
7265   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7266   // There can only be one!
7267   if ( vtl->tracks_analysis_dialog )
7268     return;
7269
7270   vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
7271                                                              VIK_LAYER(vtl)->name,
7272                                                              VIK_LAYER(vtl),
7273                                                              GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTES),
7274                                                              trw_layer_create_track_list,
7275                                                              trw_layer_analyse_close );
7276 }
7277
7278 static void trw_layer_goto_waypoint ( menu_array_sublayer values )
7279 {
7280   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7281   VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
7282   if ( wp )
7283     goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(wp->coord) );
7284 }
7285
7286 static void trw_layer_waypoint_gc_webpage ( menu_array_sublayer values )
7287 {
7288   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7289   VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
7290   if ( !wp )
7291     return;
7292   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", wp->name );
7293   open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), webpage);
7294   g_free ( webpage );
7295 }
7296
7297 static void trw_layer_waypoint_webpage ( menu_array_sublayer values )
7298 {
7299   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
7300   VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
7301   if ( !wp )
7302     return;
7303   if ( !strncmp(wp->comment, "http", 4) ) {
7304     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->comment);
7305   } else if ( !strncmp(wp->description, "http", 4) ) {
7306     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->description);
7307   }
7308 }
7309
7310 static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
7311 {
7312   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
7313   {
7314     VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
7315
7316     // No actual change to the name supplied
7317     if ( wp->name )
7318       if (strcmp(newname, wp->name) == 0 )
7319        return NULL;
7320
7321     VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname );
7322
7323     if ( wpf ) {
7324       // An existing waypoint has been found with the requested name
7325       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
7326            _("A waypoint with the name \"%s\" already exists. Really rename to the same name?"),
7327            newname ) )
7328         return NULL;
7329     }
7330
7331     // Update WP name and refresh the treeview
7332     vik_waypoint_set_name (wp, newname);
7333
7334     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
7335     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->waypoints_iter), l->wp_sort_order );
7336
7337     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
7338
7339     return newname;
7340   }
7341
7342   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7343   {
7344     VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
7345
7346     // No actual change to the name supplied
7347     if ( trk->name )
7348       if (strcmp(newname, trk->name) == 0)
7349         return NULL;
7350
7351     VikTrack *trkf = vik_trw_layer_get_track ( l, (gpointer) newname );
7352
7353     if ( trkf ) {
7354       // An existing track has been found with the requested name
7355       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
7356           _("A track with the name \"%s\" already exists. Really rename to the same name?"),
7357           newname ) )
7358         return NULL;
7359     }
7360     // Update track name and refresh GUI parts
7361     vik_track_set_name (trk, newname);
7362
7363     // Update any subwindows that could be displaying this track which has changed name
7364     // Only one Track Edit Window
7365     if ( l->current_tp_track == trk && l->tpwin ) {
7366       vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
7367     }
7368     // Property Dialog of the track
7369     vik_trw_layer_propwin_update ( trk );
7370
7371     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
7372     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order );
7373
7374     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
7375
7376     return newname;
7377   }
7378
7379   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7380   {
7381     VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer );
7382
7383     // No actual change to the name supplied
7384     if ( trk->name )
7385       if (strcmp(newname, trk->name) == 0)
7386         return NULL;
7387
7388     VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname );
7389
7390     if ( trkf ) {
7391       // An existing track has been found with the requested name
7392       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
7393           _("A route with the name \"%s\" already exists. Really rename to the same name?"),
7394           newname ) )
7395         return NULL;
7396     }
7397     // Update track name and refresh GUI parts
7398     vik_track_set_name (trk, newname);
7399
7400     // Update any subwindows that could be displaying this track which has changed name
7401     // Only one Track Edit Window
7402     if ( l->current_tp_track == trk && l->tpwin ) {
7403       vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
7404     }
7405     // Property Dialog of the track
7406     vik_trw_layer_propwin_update ( trk );
7407
7408     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
7409     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order );
7410
7411     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
7412
7413     return newname;
7414   }
7415   return NULL;
7416 }
7417
7418 static gboolean is_valid_geocache_name ( gchar *str )
7419 {
7420   gint len = strlen ( str );
7421   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]));
7422 }
7423
7424 static void trw_layer_track_use_with_filter ( menu_array_sublayer values )
7425 {
7426   VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->tracks, values[MA_SUBLAYER_ID] );
7427   a_acquire_set_filter_track ( trk );
7428 }
7429
7430 #ifdef VIK_CONFIG_GOOGLE
7431 static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id )
7432 {
7433   VikTrack *tr = g_hash_table_lookup ( vtl->routes, track_id );
7434   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
7435 }
7436
7437 static void trw_layer_google_route_webpage ( menu_array_sublayer values )
7438 {
7439   VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->routes, values[MA_SUBLAYER_ID] );
7440   if ( tr ) {
7441     gchar *escaped = uri_escape ( tr->comment );
7442     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
7443     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(values[MA_VTL])), webpage);
7444     g_free ( escaped );
7445     g_free ( webpage );
7446   }
7447 }
7448 #endif
7449
7450 /* vlp can be NULL if necessary - i.e. right-click from a tool */
7451 /* viewpoint is now available instead */
7452 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
7453 {
7454   static menu_array_sublayer pass_along;
7455   GtkWidget *item;
7456   gboolean rv = FALSE;
7457
7458   pass_along[MA_VTL]         = l;
7459   pass_along[MA_VLP]         = vlp;
7460   pass_along[MA_SUBTYPE]     = GINT_TO_POINTER (subtype);
7461   pass_along[MA_SUBLAYER_ID] = sublayer;
7462   pass_along[MA_CONFIRM]     = GINT_TO_POINTER (1); // Confirm delete request
7463   pass_along[MA_VVP]         = vvp;
7464   pass_along[MA_TV_ITER]     = iter;
7465   pass_along[MA_MISC]        = NULL; // For misc purposes - maybe track or waypoint
7466
7467   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7468   {
7469     rv = TRUE;
7470
7471     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES, NULL );
7472     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_properties_item), pass_along );
7473     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7474     gtk_widget_show ( item );
7475
7476     if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
7477       VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer );
7478       if (tr && tr->property_dialog)
7479         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
7480     }
7481     if (subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
7482       VikTrack *tr = g_hash_table_lookup ( l->routes, sublayer );
7483       if (tr && tr->property_dialog)
7484         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
7485     }
7486
7487     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL );
7488     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along );
7489     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7490     gtk_widget_show ( item );
7491
7492     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL );
7493     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along );
7494     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7495     gtk_widget_show ( item );
7496
7497     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
7498     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
7499     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7500     gtk_widget_show ( item );
7501
7502     if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
7503     {
7504       // Always create separator as now there is always at least the transform menu option
7505       item = gtk_menu_item_new ();
7506       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7507       gtk_widget_show ( item );
7508
7509       /* could be a right-click using the tool */
7510       if ( vlp != NULL ) {
7511         item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
7512         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7513         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
7514         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7515         gtk_widget_show ( item );
7516       }
7517
7518       VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
7519
7520       if ( wp && wp->name ) {
7521         if ( is_valid_geocache_name ( wp->name ) ) {
7522           item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
7523           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
7524           gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7525           gtk_widget_show ( item );
7526         }
7527 #ifdef VIK_CONFIG_GEOTAG
7528         item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
7529         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint), pass_along );
7530         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7531         gtk_widget_set_tooltip_text (item, _("Geotag multiple images against this waypoint"));
7532         gtk_widget_show ( item );
7533 #endif
7534       }
7535
7536       if ( wp && wp->image )
7537       {
7538         // Set up image paramater
7539         pass_along[MA_MISC] = wp->image;
7540
7541         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
7542         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
7543         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along );
7544         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7545         gtk_widget_show ( item );
7546
7547 #ifdef VIK_CONFIG_GEOTAG
7548         GtkWidget *geotag_submenu = gtk_menu_new ();
7549         item = gtk_image_menu_item_new_with_mnemonic ( _("Update Geotag on _Image") );
7550         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7551         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7552         gtk_widget_show ( item );
7553         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), geotag_submenu );
7554   
7555         item = gtk_menu_item_new_with_mnemonic ( _("_Update") );
7556         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_update), pass_along );
7557         gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
7558         gtk_widget_show ( item );
7559
7560         item = gtk_menu_item_new_with_mnemonic ( _("Update and _Keep File Timestamp") );
7561         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_keep), pass_along );
7562         gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
7563         gtk_widget_show ( item );
7564 #endif
7565       }
7566
7567       if ( wp )
7568       {
7569         if ( ( wp->comment && !strncmp(wp->comment, "http", 4) ) ||
7570              ( wp->description && !strncmp(wp->description, "http", 4) )) {
7571           item = gtk_image_menu_item_new_with_mnemonic ( _("Visit _Webpage") );
7572           gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
7573           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_webpage), pass_along );
7574           gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7575           gtk_widget_show ( item );
7576         }
7577       }
7578     }
7579   }
7580
7581   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
7582     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PASTE, NULL );
7583     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_paste_item_cb), pass_along );
7584     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7585     gtk_widget_show ( item );
7586     // TODO: only enable if suitable item is in clipboard - want to determine *which* sublayer type
7587     if ( a_clipboard_type ( ) == VIK_CLIPBOARD_DATA_SUBLAYER )
7588       gtk_widget_set_sensitive ( item, TRUE );
7589     else
7590       gtk_widget_set_sensitive ( item, FALSE );
7591
7592     // Add separator
7593     item = gtk_menu_item_new ();
7594     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7595     gtk_widget_show ( item );
7596   }
7597
7598   if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
7599   {
7600     rv = TRUE;
7601     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
7602     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7603     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
7604     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7605     gtk_widget_show ( item );
7606   }
7607
7608   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS )
7609   {
7610     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
7611     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7612     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
7613     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7614     gtk_widget_show ( item );
7615
7616     item = gtk_image_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
7617     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7618     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
7619     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7620     gtk_widget_show ( item );
7621
7622     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") );
7623     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7624     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
7625     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7626     gtk_widget_show ( item );
7627
7628     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Waypoints From Selection...") );
7629     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7630     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
7631     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7632     gtk_widget_show ( item );
7633
7634     GtkWidget *vis_submenu = gtk_menu_new ();
7635     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7636     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7637     gtk_widget_show ( item );
7638     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7639
7640     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Waypoints") );
7641     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7642     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_on), pass_along );
7643     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7644     gtk_widget_show ( item );
7645
7646     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Waypoints") );
7647     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7648     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_off), pass_along );
7649     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7650     gtk_widget_show ( item );
7651
7652     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7653     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7654     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_toggle), pass_along );
7655     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7656     gtk_widget_show ( item );
7657
7658     item = gtk_image_menu_item_new_with_mnemonic ( _("_List Waypoints...") );
7659     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7660     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along );
7661     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7662   }
7663
7664   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS )
7665   {
7666     rv = TRUE;
7667
7668     if ( l->current_track && !l->current_track->is_route ) {
7669       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
7670       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7671       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7672       gtk_widget_show ( item );
7673       // Add separator
7674       item = gtk_menu_item_new ();
7675       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7676       gtk_widget_show ( item );
7677     }
7678
7679     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Tracks") );
7680     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7681     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
7682     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7683     gtk_widget_show ( item );
7684
7685     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Track") );
7686     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7687     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
7688     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7689     gtk_widget_show ( item );
7690     // Make it available only when a new track *not* already in progress
7691     gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
7692
7693     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Tracks") );
7694     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7695     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
7696     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7697     gtk_widget_show ( item );
7698
7699     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Tracks From Selection...") );
7700     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7701     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
7702     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7703     gtk_widget_show ( item );
7704
7705     GtkWidget *vis_submenu = gtk_menu_new ();
7706     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7707     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7708     gtk_widget_show ( item );
7709     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7710
7711     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Tracks") );
7712     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7713     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_on), pass_along );
7714     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7715     gtk_widget_show ( item );
7716
7717     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Tracks") );
7718     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7719     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_off), pass_along );
7720     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7721     gtk_widget_show ( item );
7722
7723     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7724     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7725     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_toggle), pass_along );
7726     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7727
7728     item = gtk_image_menu_item_new_with_mnemonic ( _("_List Tracks...") );
7729     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7730     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along );
7731     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7732     gtk_widget_show ( item );
7733
7734     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7735     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_stats), pass_along );
7736     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7737     gtk_widget_show ( item );
7738   }
7739
7740   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES )
7741   {
7742     rv = TRUE;
7743
7744     if ( l->current_track && l->current_track->is_route ) {
7745       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
7746       // Reuse finish track method
7747       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7748       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7749       gtk_widget_show ( item );
7750       // Add separator
7751       item = gtk_menu_item_new ();
7752       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7753       gtk_widget_show ( item );
7754     }
7755
7756     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Routes") );
7757     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7758     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
7759     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7760     gtk_widget_show ( item );
7761
7762     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Route") );
7763     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7764     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
7765     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7766     gtk_widget_show ( item );
7767     // Make it available only when a new track *not* already in progress
7768     gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
7769
7770     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
7771     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7772     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
7773     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7774     gtk_widget_show ( item );
7775
7776     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
7777     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7778     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
7779     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7780     gtk_widget_show ( item );
7781
7782     GtkWidget *vis_submenu = gtk_menu_new ();
7783     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7784     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7785     gtk_widget_show ( item );
7786     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7787
7788     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Routes") );
7789     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7790     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_on), pass_along );
7791     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7792     gtk_widget_show ( item );
7793
7794     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Routes") );
7795     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7796     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_off), pass_along );
7797     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7798     gtk_widget_show ( item );
7799
7800     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7801     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7802     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_toggle), pass_along );
7803     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7804
7805     item = gtk_image_menu_item_new_with_mnemonic ( _("_List Routes...") );
7806     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7807     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along );
7808     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7809
7810     gtk_widget_show ( item );
7811
7812     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7813     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_stats), pass_along );
7814     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7815     gtk_widget_show ( item );
7816   }
7817
7818
7819   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
7820     GtkWidget *submenu_sort = gtk_menu_new ();
7821     item = gtk_image_menu_item_new_with_mnemonic ( _("_Sort") );
7822     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7823     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7824     gtk_widget_show ( item );
7825     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_sort );
7826
7827     item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Ascending") );
7828     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU) );
7829     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_a2z), pass_along );
7830     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
7831     gtk_widget_show ( item );
7832
7833     item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Descending") );
7834     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_DESCENDING, GTK_ICON_SIZE_MENU) );
7835     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_z2a), pass_along );
7836     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
7837     gtk_widget_show ( item );
7838   }
7839
7840   GtkWidget *upload_submenu = gtk_menu_new ();
7841
7842   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7843   {
7844     item = gtk_menu_item_new ();
7845     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7846     gtk_widget_show ( item );
7847
7848     if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && !l->current_track->is_route )
7849       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
7850     if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && l->current_track->is_route )
7851       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
7852     if ( l->current_track ) {
7853       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7854       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7855       gtk_widget_show ( item );
7856
7857       // Add separator
7858       item = gtk_menu_item_new ();
7859       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7860       gtk_widget_show ( item );
7861     }
7862
7863     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7864       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
7865     else
7866       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Route") );
7867     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7868     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
7869     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7870     gtk_widget_show ( item );
7871
7872     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7873     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_statistics), pass_along );
7874     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7875     gtk_widget_show ( item );
7876
7877     GtkWidget *goto_submenu;
7878     goto_submenu = gtk_menu_new ();
7879     item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
7880     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7881     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7882     gtk_widget_show ( item );
7883     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), goto_submenu );
7884
7885     item = gtk_image_menu_item_new_with_mnemonic ( _("_Startpoint") );
7886     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_MENU) );
7887     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
7888     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7889     gtk_widget_show ( item );
7890
7891     item = gtk_image_menu_item_new_with_mnemonic ( _("\"_Center\"") );
7892     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7893     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
7894     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7895     gtk_widget_show ( item );
7896
7897     item = gtk_image_menu_item_new_with_mnemonic ( _("_Endpoint") );
7898     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_MENU) );
7899     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
7900     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7901     gtk_widget_show ( item );
7902
7903     item = gtk_image_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
7904     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_MENU) );
7905     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
7906     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7907     gtk_widget_show ( item );
7908
7909     item = gtk_image_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
7910     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU) );
7911     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
7912     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7913     gtk_widget_show ( item );
7914
7915     // Routes don't have speeds
7916     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7917       item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
7918       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) );
7919       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along );
7920       gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7921       gtk_widget_show ( item );
7922     }
7923
7924     GtkWidget *combine_submenu;
7925     combine_submenu = gtk_menu_new ();
7926     item = gtk_image_menu_item_new_with_mnemonic ( _("Co_mbine") );
7927     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU) );
7928     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7929     gtk_widget_show ( item );
7930     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), combine_submenu );
7931
7932     // Routes don't have times or segments...
7933     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7934       item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
7935       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
7936       gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7937       gtk_widget_show ( item );
7938
7939       item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
7940       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
7941       gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7942       gtk_widget_show ( item );
7943     }
7944
7945     item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") );
7946     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along );
7947     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7948     gtk_widget_show ( item );
7949
7950     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7951       item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
7952     else
7953       item = gtk_menu_item_new_with_mnemonic ( _("_Append Route...") );
7954     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
7955     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7956     gtk_widget_show ( item );
7957
7958     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7959       item = gtk_menu_item_new_with_mnemonic ( _("Append _Route...") );
7960     else
7961       item = gtk_menu_item_new_with_mnemonic ( _("Append _Track...") );
7962     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_other), pass_along );
7963     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7964     gtk_widget_show ( item );
7965
7966     GtkWidget *split_submenu;
7967     split_submenu = gtk_menu_new ();
7968     item = gtk_image_menu_item_new_with_mnemonic ( _("_Split") );
7969     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU) );
7970     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7971     gtk_widget_show ( item );
7972     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), split_submenu );
7973
7974     // Routes don't have times or segments...
7975     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7976       item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
7977       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
7978       gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7979       gtk_widget_show ( item );
7980
7981       // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy
7982       item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") );
7983       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along );
7984       gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7985       gtk_widget_show ( item );
7986     }
7987
7988     item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") );
7989     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along );
7990     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7991     gtk_widget_show ( item );
7992
7993     item = gtk_menu_item_new_with_mnemonic ( _("Split at _Trackpoint") );
7994     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_at_trackpoint), pass_along );
7995     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7996     gtk_widget_show ( item );
7997     // Make it available only when a trackpoint is selected.
7998     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
7999
8000     GtkWidget *insert_submenu = gtk_menu_new ();
8001     item = gtk_image_menu_item_new_with_mnemonic ( _("_Insert Points") );
8002     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
8003     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8004     gtk_widget_show ( item );
8005     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), insert_submenu );
8006
8007     item = gtk_menu_item_new_with_mnemonic ( _("Insert Point _Before Selected Point") );
8008     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_insert_point_before), pass_along );
8009     gtk_menu_shell_append ( GTK_MENU_SHELL(insert_submenu), item );
8010     gtk_widget_show ( item );
8011     // Make it available only when a point is selected
8012     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
8013
8014     item = gtk_menu_item_new_with_mnemonic ( _("Insert Point _After Selected Point") );
8015     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_insert_point_after), pass_along );
8016     gtk_menu_shell_append ( GTK_MENU_SHELL(insert_submenu), item );
8017     gtk_widget_show ( item );
8018     // Make it available only when a point is selected
8019     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
8020
8021     GtkWidget *delete_submenu;
8022     delete_submenu = gtk_menu_new ();
8023     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") );
8024     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) );
8025     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8026     gtk_widget_show ( item );
8027     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
8028
8029     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _Selected Point") );
8030     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) );
8031     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_point_selected), pass_along );
8032     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
8033     gtk_widget_show ( item );
8034     // Make it available only when a point is selected
8035     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
8036
8037     item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") );
8038     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along );
8039     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
8040     gtk_widget_show ( item );
8041
8042     item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Time") );
8043     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_time), pass_along );
8044     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
8045     gtk_widget_show ( item );
8046
8047     GtkWidget *transform_submenu;
8048     transform_submenu = gtk_menu_new ();
8049     item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
8050     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
8051     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8052     gtk_widget_show ( item );
8053     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
8054
8055     GtkWidget *dem_submenu;
8056     dem_submenu = gtk_menu_new ();
8057     item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
8058     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
8059     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
8060     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
8061
8062     item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
8063     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_all), pass_along );
8064     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
8065     gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
8066     gtk_widget_show ( item );
8067
8068     item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
8069     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_only_missing), pass_along );
8070     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
8071     gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
8072     gtk_widget_show ( item );
8073
8074     GtkWidget *smooth_submenu;
8075     smooth_submenu = gtk_menu_new ();
8076     item = gtk_menu_item_new_with_mnemonic ( _("_Smooth Missing Elevation Data") );
8077     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
8078     gtk_widget_show ( item );
8079     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smooth_submenu );
8080
8081     item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolated") );
8082     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_interp), pass_along );
8083     gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
8084     gtk_widget_set_tooltip_text (item, _("Interpolate between known elevation values to derive values for the missing elevations"));
8085     gtk_widget_show ( item );
8086
8087     item = gtk_image_menu_item_new_with_mnemonic ( _("_Flat") );
8088     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_flat), pass_along );
8089     gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
8090     gtk_widget_set_tooltip_text (item, _("Set unknown elevation values to the last known value"));
8091     gtk_widget_show ( item );
8092
8093     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
8094       item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") );
8095     else
8096       item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") );
8097     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
8098     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along );
8099     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
8100     gtk_widget_show ( item );
8101
8102     // Routes don't have timestamps - so this is only available for tracks
8103     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
8104       item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") );
8105       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along );
8106       gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
8107       gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01"));
8108       gtk_widget_show ( item );
8109     }
8110
8111     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
8112       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
8113     else
8114       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Route") );
8115     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU) );
8116     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_reverse), pass_along );
8117     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8118     gtk_widget_show ( item );
8119
8120     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
8121       item = gtk_image_menu_item_new_with_mnemonic ( _("Refine Route...") );
8122       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
8123       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_route_refine), pass_along );
8124       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8125       gtk_widget_show ( item );
8126     }
8127
8128     /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
8129     if ( vlp ) {
8130       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
8131         item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
8132       else
8133         item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Route...") );
8134       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Maps Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
8135       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
8136       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8137       gtk_widget_show ( item );
8138     }
8139
8140     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
8141       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") );
8142     else
8143       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Route as GPX...") );
8144     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
8145     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along );
8146     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8147     gtk_widget_show ( item );
8148
8149     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
8150       item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") );
8151     else
8152       item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Route End") );
8153     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
8154     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
8155     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8156     gtk_widget_show ( item );
8157
8158     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
8159       item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
8160       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
8161       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
8162       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8163       gtk_widget_show ( item );
8164     }
8165
8166     // ATM can't upload a single waypoint but can do waypoints to a GPS
8167     if ( subtype != VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
8168       item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
8169       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
8170       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8171       gtk_widget_show ( item );
8172       gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
8173
8174       item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS...") );
8175       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
8176       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload_any), pass_along );
8177       gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
8178       gtk_widget_show ( item );
8179     }
8180   }
8181
8182 #ifdef VIK_CONFIG_GOOGLE
8183   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) )
8184   {
8185     item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") );
8186     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
8187     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_google_route_webpage), pass_along );
8188     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8189     gtk_widget_show ( item );
8190   }
8191 #endif
8192
8193   // Some things aren't usable with routes
8194   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
8195 #ifdef VIK_CONFIG_OPENSTREETMAP
8196     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
8197     // Convert internal pointer into track
8198     pass_along[MA_MISC] = g_hash_table_lookup ( l->tracks, sublayer);
8199     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
8200     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_track_cb), pass_along );
8201     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
8202     gtk_widget_show ( item );
8203 #endif
8204
8205     item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") );
8206     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
8207     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
8208     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8209     gtk_widget_show ( item );
8210
8211     /* ATM This function is only available via the layers panel, due to needing a vlp */
8212     if ( vlp ) {
8213       item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp,
8214                                     vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
8215                                     g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
8216       if ( item ) {
8217         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8218         gtk_widget_show ( item );
8219       }
8220     }
8221
8222 #ifdef VIK_CONFIG_GEOTAG
8223     item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
8224     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_track), pass_along );
8225     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8226     gtk_widget_show ( item );
8227 #endif
8228   }
8229
8230   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
8231     // Only show on viewport popmenu when a trackpoint is selected
8232     if ( ! vlp && l->current_tpl ) {
8233       // Add separator
8234       item = gtk_menu_item_new ();
8235       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8236       gtk_widget_show ( item );
8237
8238       item = gtk_image_menu_item_new_with_mnemonic ( _("_Edit Trackpoint") );
8239       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU) );
8240       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_edit_trackpoint), pass_along );
8241       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8242       gtk_widget_show ( item );
8243     }
8244   }
8245
8246   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
8247     GtkWidget *transform_submenu;
8248     transform_submenu = gtk_menu_new ();
8249     item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
8250     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
8251     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8252     gtk_widget_show ( item );
8253     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
8254
8255     GtkWidget *dem_submenu;
8256     dem_submenu = gtk_menu_new ();
8257     item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
8258     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
8259     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
8260     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
8261
8262     item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
8263     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_all), pass_along );
8264     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
8265     gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
8266     gtk_widget_show ( item );
8267
8268     item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
8269     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_only_missing), pass_along );
8270     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
8271     gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
8272     gtk_widget_show ( item );
8273   }
8274
8275   gtk_widget_show_all ( GTK_WIDGET(menu) );
8276
8277   return rv;
8278 }
8279
8280 // TODO: Probably better to rework this track manipulation in viktrack.c
8281 static void trw_layer_insert_tp_beside_current_tp ( VikTrwLayer *vtl, gboolean before )
8282 {
8283   // sanity check
8284   if (!vtl->current_tpl)
8285     return;
8286
8287   VikTrackpoint *tp_current = VIK_TRACKPOINT(vtl->current_tpl->data);
8288   VikTrackpoint *tp_other = NULL;
8289
8290   if ( before ) {
8291     if (!vtl->current_tpl->prev)
8292       return;
8293     tp_other = VIK_TRACKPOINT(vtl->current_tpl->prev->data);
8294   } else {
8295     if (!vtl->current_tpl->next)
8296       return;
8297     tp_other = VIK_TRACKPOINT(vtl->current_tpl->next->data);
8298   }
8299
8300   // Use current and other trackpoints to form a new track point which is inserted into the tracklist
8301   if ( tp_other ) {
8302
8303     VikTrackpoint *tp_new = vik_trackpoint_new();
8304     struct LatLon ll_current, ll_other;
8305     vik_coord_to_latlon ( &tp_current->coord, &ll_current );
8306     vik_coord_to_latlon ( &tp_other->coord, &ll_other );
8307
8308     /* main positional interpolation */
8309     struct LatLon ll_new = { (ll_current.lat+ll_other.lat)/2, (ll_current.lon+ll_other.lon)/2 };
8310     vik_coord_load_from_latlon ( &(tp_new->coord), vtl->coord_mode, &ll_new );
8311
8312     /* Now other properties that can be interpolated */
8313     tp_new->altitude = (tp_current->altitude + tp_other->altitude) / 2;
8314
8315     if (tp_current->has_timestamp && tp_other->has_timestamp) {
8316       /* Note here the division is applied to each part, then added
8317          This is to avoid potential overflow issues with a 32 time_t for dates after midpoint of this Unix time on 2004/01/04 */
8318       tp_new->timestamp = (tp_current->timestamp/2) + (tp_other->timestamp/2);
8319       tp_new->has_timestamp = TRUE;
8320     }
8321
8322     if (tp_current->speed != NAN && tp_other->speed != NAN)
8323       tp_new->speed = (tp_current->speed + tp_other->speed)/2;
8324
8325     /* TODO - improve interpolation of course, as it may not be correct.
8326        if courses in degrees are 350 + 020, the mid course more likely to be 005 (not 185)
8327        [similar applies if value is in radians] */
8328     if (tp_current->course != NAN && tp_other->course != NAN)
8329       tp_new->course = (tp_current->course + tp_other->course)/2;
8330
8331     /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */
8332
8333     // Insert new point into the appropriate trackpoint list, either before or after the current trackpoint as directed
8334     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
8335     if ( !trk )
8336       // Otherwise try routes
8337       trk = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
8338     if ( !trk )
8339       return;
8340
8341     gint index =  g_list_index ( trk->trackpoints, tp_current );
8342     if ( index > -1 ) {
8343       if ( !before )
8344         index = index + 1;
8345       // NB no recalculation of bounds since it is inserted between points
8346       trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index );
8347     }
8348   }
8349 }
8350
8351 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
8352 {
8353   if ( vtl->tpwin )
8354   {
8355     if ( destroy)
8356     {
8357       gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
8358       vtl->tpwin = NULL;
8359     }
8360     else
8361       vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
8362   }
8363   if ( vtl->current_tpl )
8364   {
8365     vtl->current_tpl = NULL;
8366     vtl->current_tp_track = NULL;
8367     vtl->current_tp_id = NULL;
8368     vik_layer_emit_update(VIK_LAYER(vtl));
8369   }
8370 }
8371
8372 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
8373 {
8374   g_assert ( vtl->tpwin != NULL );
8375   if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
8376     trw_layer_cancel_current_tp ( vtl, TRUE );
8377
8378   if ( vtl->current_tpl == NULL )
8379     return;
8380
8381   if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
8382   {
8383     trw_layer_split_at_selected_trackpoint ( vtl, vtl->current_tp_track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK );
8384     vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8385   }
8386   else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
8387   {
8388     VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
8389     if ( tr == NULL )
8390       tr = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
8391     if ( tr == NULL )
8392       return;
8393
8394     trw_layer_trackpoint_selected_delete ( vtl, tr );
8395
8396     if ( vtl->current_tpl )
8397       // Reset dialog with the available adjacent trackpoint
8398       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8399
8400     vik_layer_emit_update(VIK_LAYER(vtl));
8401   }
8402   else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
8403   {
8404     if ( vtl->current_tp_track )
8405       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name );
8406     vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
8407   }
8408   else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
8409   {
8410     if ( vtl->current_tp_track )
8411       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name );
8412     vik_layer_emit_update(VIK_LAYER(vtl));
8413   }
8414   else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
8415   {
8416     trw_layer_insert_tp_beside_current_tp ( vtl, FALSE );
8417     vik_layer_emit_update(VIK_LAYER(vtl));
8418   }
8419   else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
8420     vik_layer_emit_update(VIK_LAYER(vtl));
8421 }
8422
8423 /**
8424  * trw_layer_dialog_shift:
8425  * @vertical: The reposition strategy. If Vertical moves dialog vertically, otherwise moves it horizontally
8426  *
8427  * Try to reposition a dialog if it's over the specified coord
8428  *  so to not obscure the item of interest
8429  */
8430 void trw_layer_dialog_shift ( VikTrwLayer *vtl, GtkWindow *dialog, VikCoord *coord, gboolean vertical )
8431 {
8432   GtkWindow *parent = VIK_GTK_WINDOW_FROM_LAYER(vtl); //i.e. the main window
8433
8434   // Attempt force dialog to be shown so we can find out where it is more reliably...
8435   while ( gtk_events_pending() )
8436     gtk_main_iteration ();
8437
8438   // get parent window position & size
8439   gint win_pos_x, win_pos_y;
8440   gtk_window_get_position ( parent, &win_pos_x, &win_pos_y );
8441
8442   gint win_size_x, win_size_y;
8443   gtk_window_get_size ( parent, &win_size_x, &win_size_y );
8444
8445   // get own dialog size
8446   gint dia_size_x, dia_size_y;
8447   gtk_window_get_size ( dialog, &dia_size_x, &dia_size_y );
8448
8449   // get own dialog position
8450   gint dia_pos_x, dia_pos_y;
8451   gtk_window_get_position ( dialog, &dia_pos_x, &dia_pos_y );
8452
8453   // Dialog not 'realized'/positioned - so can't really do any repositioning logic
8454   if ( dia_pos_x > 2 && dia_pos_y > 2 ) {
8455
8456     VikViewport *vvp = vik_window_viewport ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
8457
8458     gint vp_xx, vp_yy; // In viewport pixels
8459     vik_viewport_coord_to_screen ( vvp, coord, &vp_xx, &vp_yy );
8460
8461     // Work out the 'bounding box' in pixel terms of the dialog and only move it when over the position
8462
8463     gint dest_x = 0;
8464     gint dest_y = 0;
8465     if ( gtk_widget_translate_coordinates ( GTK_WIDGET(vvp), GTK_WIDGET(parent), 0, 0, &dest_x, &dest_y ) ) {
8466
8467       // Transform Viewport pixels into absolute pixels
8468       gint tmp_xx = vp_xx + dest_x + win_pos_x - 10;
8469       gint tmp_yy = vp_yy + dest_y + win_pos_y - 10;
8470
8471       // Is dialog over the point (to within an  ^^ edge value)
8472       if ( (tmp_xx > dia_pos_x) && (tmp_xx < (dia_pos_x + dia_size_x)) &&
8473            (tmp_yy > dia_pos_y) && (tmp_yy < (dia_pos_y + dia_size_y)) ) {
8474
8475         if ( vertical ) {
8476           // Shift up<->down
8477           gint hh = vik_viewport_get_height ( vvp );
8478
8479           // Consider the difference in viewport to the full window
8480           gint offset_y = dest_y;
8481           // Add difference between dialog and window sizes
8482           offset_y += win_pos_y + (hh/2 - dia_size_y)/2;
8483
8484           if ( vp_yy > hh/2 ) {
8485             // Point in bottom half, move window to top half
8486             gtk_window_move ( dialog, dia_pos_x, offset_y );
8487           }
8488           else {
8489             // Point in top half, move dialog down
8490             gtk_window_move ( dialog, dia_pos_x, hh/2 + offset_y );
8491           }
8492         }
8493         else {
8494           // Shift left<->right
8495           gint ww = vik_viewport_get_width ( vvp );
8496
8497           // Consider the difference in viewport to the full window
8498           gint offset_x = dest_x;
8499           // Add difference between dialog and window sizes
8500           offset_x += win_pos_x + (ww/2 - dia_size_x)/2;
8501
8502           if ( vp_xx > ww/2 ) {
8503             // Point on right, move window to left
8504             gtk_window_move ( dialog, offset_x, dia_pos_y );
8505           }
8506           else {
8507             // Point on left, move right
8508             gtk_window_move ( dialog, ww/2 + offset_x, dia_pos_y );
8509           }
8510         }
8511       }
8512     }
8513   }
8514 }
8515
8516 static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
8517 {
8518   if ( ! vtl->tpwin )
8519   {
8520     vtl->tpwin = vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8521     g_signal_connect_swapped ( GTK_DIALOG(vtl->tpwin), "response", G_CALLBACK(trw_layer_tpwin_response), vtl );
8522     /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
8523     g_signal_connect_swapped ( vtl->tpwin, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp), vtl );
8524
8525     gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
8526
8527     if ( vtl->current_tpl ) {
8528       // get tp pixel position
8529       VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
8530
8531       // Shift up<->down to try not to obscure the trackpoint.
8532       trw_layer_dialog_shift ( vtl, GTK_WINDOW(vtl->tpwin), &(tp->coord), TRUE );
8533     }
8534   }
8535
8536   if ( vtl->current_tpl )
8537     if ( vtl->current_tp_track )
8538       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8539   /* set layer name and TP data */
8540 }
8541
8542 /***************************************************************************
8543  ** Tool code
8544  ***************************************************************************/
8545
8546 /*** Utility data structures and functions ****/
8547
8548 typedef struct {
8549   gint x, y;
8550   gint closest_x, closest_y;
8551   gboolean draw_images;
8552   gpointer *closest_wp_id;
8553   VikWaypoint *closest_wp;
8554   VikViewport *vvp;
8555 } WPSearchParams;
8556
8557 typedef struct {
8558   gint x, y;
8559   gint closest_x, closest_y;
8560   gpointer closest_track_id;
8561   VikTrackpoint *closest_tp;
8562   VikViewport *vvp;
8563   GList *closest_tpl;
8564   LatLonBBox bbox;
8565 } TPSearchParams;
8566
8567 static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchParams *params )
8568 {
8569   gint x, y;
8570   if ( !wp->visible )
8571     return;
8572
8573   vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
8574
8575   // If waypoint has an image then use the image size to select
8576   if ( params->draw_images && wp->image ) {
8577     gint slackx, slacky;
8578     slackx = wp->image_width / 2;
8579     slacky = wp->image_height / 2;
8580
8581     if (    x <= params->x + slackx && x >= params->x - slackx
8582          && y <= params->y + slacky && y >= params->y - slacky ) {
8583       params->closest_wp_id = id;
8584       params->closest_wp = wp;
8585       params->closest_x = x;
8586       params->closest_y = y;
8587     }
8588   }
8589   else if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
8590             ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
8591              abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
8592     {
8593       params->closest_wp_id = id;
8594       params->closest_wp = wp;
8595       params->closest_x = x;
8596       params->closest_y = y;
8597     }
8598 }
8599
8600 static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams *params )
8601 {
8602   GList *tpl = t->trackpoints;
8603   VikTrackpoint *tp;
8604
8605   if ( !t->visible )
8606     return;
8607
8608   if ( ! BBOX_INTERSECT ( t->bbox, params->bbox ) )
8609     return;
8610
8611   while (tpl)
8612   {
8613     gint x, y;
8614     tp = VIK_TRACKPOINT(tpl->data);
8615
8616     vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
8617  
8618     if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
8619         ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
8620           abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
8621     {
8622       params->closest_track_id = id;
8623       params->closest_tp = tp;
8624       params->closest_tpl = tpl;
8625       params->closest_x = x;
8626       params->closest_y = y;
8627     }
8628     tpl = tpl->next;
8629   }
8630 }
8631
8632 // ATM: Leave this as 'Track' only.
8633 //  Not overly bothered about having a snap to route trackpoint capability
8634 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
8635 {
8636   TPSearchParams params;
8637   params.x = x;
8638   params.y = y;
8639   params.vvp = vvp;
8640   params.closest_track_id = NULL;
8641   params.closest_tp = NULL;
8642   vik_viewport_get_min_max_lat_lon ( params.vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
8643   g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
8644   return params.closest_tp;
8645 }
8646
8647 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
8648 {
8649   WPSearchParams params;
8650   params.x = x;
8651   params.y = y;
8652   params.vvp = vvp;
8653   params.draw_images = vtl->drawimages;
8654   params.closest_wp = NULL;
8655   params.closest_wp_id = NULL;
8656   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
8657   return params.closest_wp;
8658 }
8659
8660
8661 // Some forward declarations
8662 static void marker_begin_move ( tool_ed_t *t, gint x, gint y );
8663 static void marker_moveto ( tool_ed_t *t, gint x, gint y );
8664 static void marker_end_move ( tool_ed_t *t );
8665 //
8666
8667 static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
8668 {
8669   if ( t->holding ) {
8670     VikCoord new_coord;
8671     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8672
8673     // Here always allow snapping back to the original location
8674     //  this is useful when one decides not to move the thing afterall
8675     // If one wants to move the item only a little bit then don't hold down the 'snap' key!
8676  
8677     // snap to TP
8678     if ( event->state & GDK_CONTROL_MASK )
8679     {
8680       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8681       if ( tp )
8682         new_coord = tp->coord;
8683     }
8684
8685     // snap to WP
8686     if ( event->state & GDK_SHIFT_MASK )
8687     {
8688       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8689       if ( wp )
8690         new_coord = wp->coord;
8691     }
8692     
8693     gint x, y;
8694     vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
8695
8696     marker_moveto ( t, x, y );
8697
8698     return TRUE;
8699   }
8700   return FALSE;
8701 }
8702
8703 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
8704 {
8705   if ( t->holding && event->button == 1 )
8706   {
8707     VikCoord new_coord;
8708     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8709
8710     // snap to TP
8711     if ( event->state & GDK_CONTROL_MASK )
8712     {
8713       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8714       if ( tp )
8715         new_coord = tp->coord;
8716     }
8717
8718     // snap to WP
8719     if ( event->state & GDK_SHIFT_MASK )
8720     {
8721       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8722       if ( wp )
8723         new_coord = wp->coord;
8724     }
8725
8726     marker_end_move ( t );
8727
8728     // Determine if working on a waypoint or a trackpoint
8729     if ( t->is_waypoint ) {
8730       // Update waypoint position
8731       vtl->current_wp->coord = new_coord;
8732       trw_layer_calculate_bounds_waypoints ( vtl );
8733       // Reset waypoint pointer
8734       vtl->current_wp    = NULL;
8735       vtl->current_wp_id = NULL;
8736     }
8737     else {
8738       if ( vtl->current_tpl ) {
8739         VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
8740
8741         if ( vtl->current_tp_track )
8742           vik_track_calculate_bounds ( vtl->current_tp_track );
8743
8744         if ( vtl->tpwin )
8745           if ( vtl->current_tp_track )
8746             vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8747         // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin
8748       }
8749     }
8750
8751     vik_layer_emit_update ( VIK_LAYER(vtl) );
8752     return TRUE;
8753   }
8754   return FALSE;
8755 }
8756
8757 /*
8758   Returns true if a waypoint or track is found near the requested event position for this particular layer
8759   The item found is automatically selected
8760   This is a tool like feature but routed via the layer interface, since it's instigated by a 'global' layer tool in vikwindow.c
8761  */
8762 static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* tet )
8763 {
8764   if ( event->button != 1 )
8765     return FALSE;
8766
8767   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8768     return FALSE;
8769
8770   if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
8771     return FALSE;
8772
8773   LatLonBBox bbox;
8774   vik_viewport_get_min_max_lat_lon ( vvp, &(bbox.south), &(bbox.north), &(bbox.west), &(bbox.east) );
8775
8776   // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track
8777
8778   if ( vtl->waypoints_visible && BBOX_INTERSECT (vtl->waypoints_bbox, bbox ) ) {
8779     WPSearchParams wp_params;
8780     wp_params.vvp = vvp;
8781     wp_params.x = event->x;
8782     wp_params.y = event->y;
8783     wp_params.draw_images = vtl->drawimages;
8784     wp_params.closest_wp_id = NULL;
8785     wp_params.closest_wp = NULL;
8786
8787     g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params);
8788
8789     if ( wp_params.closest_wp )  {
8790
8791       // Select
8792       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_id ), TRUE );
8793
8794       // Too easy to move it so must be holding shift to start immediately moving it
8795       //   or otherwise be previously selected but not have an image (otherwise clicking within image bounds (again) moves it)
8796       if ( event->state & GDK_SHIFT_MASK ||
8797            ( vtl->current_wp == wp_params.closest_wp && !vtl->current_wp->image ) ) {
8798         // Put into 'move buffer'
8799         // NB vvp & vw already set in tet
8800         tet->vtl = (gpointer)vtl;
8801         tet->is_waypoint = TRUE;
8802       
8803         marker_begin_move (tet, event->x, event->y);
8804       }
8805
8806       vtl->current_wp =    wp_params.closest_wp;
8807       vtl->current_wp_id = wp_params.closest_wp_id;
8808
8809       if ( event->type == GDK_2BUTTON_PRESS ) {
8810         if ( vtl->current_wp->image ) {
8811           menu_array_sublayer values;
8812           values[MA_VTL] = vtl;
8813           values[MA_MISC] = vtl->current_wp->image;
8814           trw_layer_show_picture ( values );
8815         }
8816       }
8817
8818       vik_layer_emit_update ( VIK_LAYER(vtl) );
8819
8820       return TRUE;
8821     }
8822   }
8823
8824   // Used for both track and route lists
8825   TPSearchParams tp_params;
8826   tp_params.vvp = vvp;
8827   tp_params.x = event->x;
8828   tp_params.y = event->y;
8829   tp_params.closest_track_id = NULL;
8830   tp_params.closest_tp = NULL;
8831   tp_params.closest_tpl = NULL;
8832   tp_params.bbox = bbox;
8833
8834   if (vtl->tracks_visible) {
8835     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params);
8836
8837     if ( tp_params.closest_tp )  {
8838
8839       // Always select + highlight the track
8840       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, tp_params.closest_track_id ), TRUE );
8841
8842       tet->is_waypoint = FALSE;
8843
8844       // Select the Trackpoint
8845       // Can move it immediately when control held or it's the previously selected tp
8846       if ( event->state & GDK_CONTROL_MASK ||
8847            vtl->current_tpl == tp_params.closest_tpl ) {
8848         // Put into 'move buffer'
8849         // NB vvp & vw already set in tet
8850         tet->vtl = (gpointer)vtl;
8851         marker_begin_move (tet, event->x, event->y);
8852       }
8853
8854       vtl->current_tpl = tp_params.closest_tpl;
8855       vtl->current_tp_id = tp_params.closest_track_id;
8856       vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, tp_params.closest_track_id );
8857
8858       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
8859
8860       if ( vtl->tpwin )
8861         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8862
8863       vik_layer_emit_update ( VIK_LAYER(vtl) );
8864       return TRUE;
8865     }
8866   }
8867
8868   // Try again for routes
8869   if (vtl->routes_visible) {
8870     g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &tp_params);
8871
8872     if ( tp_params.closest_tp )  {
8873
8874       // Always select + highlight the track
8875       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, tp_params.closest_track_id ), TRUE );
8876
8877       tet->is_waypoint = FALSE;
8878
8879       // Select the Trackpoint
8880       // Can move it immediately when control held or it's the previously selected tp
8881       if ( event->state & GDK_CONTROL_MASK ||
8882            vtl->current_tpl == tp_params.closest_tpl ) {
8883         // Put into 'move buffer'
8884         // NB vvp & vw already set in tet
8885         tet->vtl = (gpointer)vtl;
8886         marker_begin_move (tet, event->x, event->y);
8887       }
8888
8889       vtl->current_tpl = tp_params.closest_tpl;
8890       vtl->current_tp_id = tp_params.closest_track_id;
8891       vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, tp_params.closest_track_id );
8892
8893       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
8894
8895       if ( vtl->tpwin )
8896         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8897
8898       vik_layer_emit_update ( VIK_LAYER(vtl) );
8899       return TRUE;
8900     }
8901   }
8902
8903   /* these aren't the droids you're looking for */
8904   vtl->current_wp    = NULL;
8905   vtl->current_wp_id = NULL;
8906   trw_layer_cancel_current_tp ( vtl, FALSE );
8907
8908   // Blank info
8909   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, "" );
8910
8911   return FALSE;
8912 }
8913
8914 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8915 {
8916   if ( event->button != 3 )
8917     return FALSE;
8918
8919   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8920     return FALSE;
8921
8922   if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
8923     return FALSE;
8924
8925   /* Post menu for the currently selected item */
8926
8927   /* See if a track is selected */
8928   VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8929   if ( track && track->visible ) {
8930
8931     if ( track->name ) {
8932
8933       if ( vtl->track_right_click_menu )
8934         g_object_ref_sink ( G_OBJECT(vtl->track_right_click_menu) );
8935
8936       vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
8937       
8938       trku_udata udataU;
8939       udataU.trk  = track;
8940       udataU.uuid = NULL;
8941
8942       gpointer *trkf;
8943       if ( track->is_route )
8944         trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU );
8945       else
8946         trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
8947
8948       if ( trkf && udataU.uuid ) {
8949
8950         GtkTreeIter *iter;
8951         if ( track->is_route )
8952           iter = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
8953         else
8954           iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
8955
8956         trw_layer_sublayer_add_menu_items ( vtl,
8957                                             vtl->track_right_click_menu,
8958                                             NULL,
8959                                             track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK,
8960                                             udataU.uuid,
8961                                             iter,
8962                                             vvp );
8963       }
8964
8965       gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8966         
8967       return TRUE;
8968     }
8969   }
8970
8971   /* See if a waypoint is selected */
8972   VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8973   if ( waypoint && waypoint->visible ) {
8974     if ( waypoint->name ) {
8975
8976       if ( vtl->wp_right_click_menu )
8977         g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
8978
8979       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
8980
8981       wpu_udata udata;
8982       udata.wp   = waypoint;
8983       udata.uuid = NULL;
8984
8985       gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
8986
8987       if ( wpf && udata.uuid ) {
8988         GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
8989
8990         trw_layer_sublayer_add_menu_items ( vtl,
8991                                             vtl->wp_right_click_menu,
8992                                             NULL,
8993                                             VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
8994                                             udata.uuid,
8995                                             iter,
8996                                             vvp );
8997       }
8998       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8999
9000       return TRUE;
9001     }
9002   }
9003
9004   return FALSE;
9005 }
9006
9007 /* background drawing hook, to be passed the viewport */
9008 static gboolean tool_sync_done = TRUE;
9009
9010 static gboolean tool_sync(gpointer data)
9011 {
9012   VikViewport *vvp = data;
9013   gdk_threads_enter();
9014   vik_viewport_sync(vvp);
9015   tool_sync_done = TRUE;
9016   gdk_threads_leave();
9017   return FALSE;
9018 }
9019
9020 static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
9021 {
9022   t->holding = TRUE;
9023   t->gc = vik_viewport_new_gc (t->vvp, "black", 2);
9024   gdk_gc_set_function ( t->gc, GDK_INVERT );
9025   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
9026   vik_viewport_sync(t->vvp);
9027   t->oldx = x;
9028   t->oldy = y;
9029 }
9030
9031 static void marker_moveto ( tool_ed_t *t, gint x, gint y )
9032 {
9033   VikViewport *vvp =  t->vvp;
9034   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
9035   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
9036   t->oldx = x;
9037   t->oldy = y;
9038
9039   if (tool_sync_done) {
9040     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
9041     tool_sync_done = FALSE;
9042   }
9043 }
9044
9045 static void marker_end_move ( tool_ed_t *t )
9046 {
9047   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
9048   g_object_unref ( t->gc );
9049   t->holding = FALSE;
9050 }
9051
9052 /*** Edit waypoint ****/
9053
9054 static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp)
9055 {
9056   tool_ed_t *t = g_new(tool_ed_t, 1);
9057   t->vvp = vvp;
9058   t->holding = FALSE;
9059   return t;
9060 }
9061
9062 static void tool_edit_waypoint_destroy ( tool_ed_t *t )
9063 {
9064   g_free ( t );
9065 }
9066
9067 static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9068 {
9069   WPSearchParams params;
9070   tool_ed_t *t = data;
9071   VikViewport *vvp = t->vvp;
9072
9073   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9074     return FALSE;
9075
9076   if ( t->holding ) {
9077     return TRUE;
9078   }
9079
9080   if ( !vtl->vl.visible || !vtl->waypoints_visible )
9081     return FALSE;
9082
9083   if ( vtl->current_wp && vtl->current_wp->visible )
9084   {
9085     /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
9086     gint x, y;
9087     vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
9088
9089     if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
9090          abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
9091     {
9092       if ( event->button == 3 )
9093         vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
9094       else {
9095         marker_begin_move(t, event->x, event->y);
9096       }
9097       return TRUE;
9098     }
9099   }
9100
9101   params.vvp = vvp;
9102   params.x = event->x;
9103   params.y = event->y;
9104   params.draw_images = vtl->drawimages;
9105   params.closest_wp_id = NULL;
9106   params.closest_wp = NULL;
9107   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
9108   if ( vtl->current_wp && (vtl->current_wp == params.closest_wp) )
9109   {
9110     marker_begin_move(t, event->x, event->y);
9111     return FALSE;
9112   }
9113   else if ( params.closest_wp )
9114   {
9115     if ( event->button == 3 )
9116       vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
9117     else
9118       vtl->waypoint_rightclick = FALSE;
9119
9120     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, params.closest_wp_id ), TRUE );
9121
9122     vtl->current_wp = params.closest_wp;
9123     vtl->current_wp_id = params.closest_wp_id;
9124
9125     /* could make it so don't update if old WP is off screen and new is null but oh well */
9126     vik_layer_emit_update ( VIK_LAYER(vtl) );
9127     return TRUE;
9128   }
9129
9130   vtl->current_wp = NULL;
9131   vtl->current_wp_id = NULL;
9132   vtl->waypoint_rightclick = FALSE;
9133   vik_layer_emit_update ( VIK_LAYER(vtl) );
9134   return FALSE;
9135 }
9136
9137 static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
9138 {
9139   tool_ed_t *t = data;
9140   VikViewport *vvp = t->vvp;
9141
9142   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9143     return FALSE;
9144
9145   if ( t->holding ) {
9146     VikCoord new_coord;
9147     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9148
9149     /* snap to TP */
9150     if ( event->state & GDK_CONTROL_MASK )
9151     {
9152       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9153       if ( tp )
9154         new_coord = tp->coord;
9155     }
9156
9157     /* snap to WP */
9158     if ( event->state & GDK_SHIFT_MASK )
9159     {
9160       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9161       if ( wp && wp != vtl->current_wp )
9162         new_coord = wp->coord;
9163     }
9164     
9165     { 
9166       gint x, y;
9167       vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
9168
9169       marker_moveto ( t, x, y );
9170     } 
9171     return TRUE;
9172   }
9173   return FALSE;
9174 }
9175
9176 static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9177 {
9178   tool_ed_t *t = data;
9179   VikViewport *vvp = t->vvp;
9180
9181   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9182     return FALSE;
9183   
9184   if ( t->holding && event->button == 1 )
9185   {
9186     VikCoord new_coord;
9187     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9188
9189     /* snap to TP */
9190     if ( event->state & GDK_CONTROL_MASK )
9191     {
9192       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9193       if ( tp )
9194         new_coord = tp->coord;
9195     }
9196
9197     /* snap to WP */
9198     if ( event->state & GDK_SHIFT_MASK )
9199     {
9200       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9201       if ( wp && wp != vtl->current_wp )
9202         new_coord = wp->coord;
9203     }
9204
9205     marker_end_move ( t );
9206
9207     vtl->current_wp->coord = new_coord;
9208
9209     trw_layer_calculate_bounds_waypoints ( vtl );
9210     vik_layer_emit_update ( VIK_LAYER(vtl) );
9211     return TRUE;
9212   }
9213   /* PUT IN RIGHT PLACE!!! */
9214   if ( event->button == 3 && vtl->waypoint_rightclick )
9215   {
9216     if ( vtl->wp_right_click_menu )
9217       g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
9218     if ( vtl->current_wp ) {
9219       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
9220       trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_id, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_id ), vvp );
9221       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
9222     }
9223     vtl->waypoint_rightclick = FALSE;
9224   }
9225   return FALSE;
9226 }
9227
9228 /*** New track ****/
9229
9230 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
9231 {
9232   return vvp;
9233 }
9234
9235 typedef struct {
9236   VikTrwLayer *vtl;
9237   GdkDrawable *drawable;
9238   GdkGC *gc;
9239   GdkPixmap *pixmap;
9240 } draw_sync_t;
9241
9242 /*
9243  * Draw specified pixmap
9244  */
9245 static gboolean draw_sync ( gpointer data )
9246 {
9247   draw_sync_t *ds = (draw_sync_t*) data;
9248   // Sometimes don't want to draw
9249   //  normally because another update has taken precedent such as panning the display
9250   //   which means this pixmap is no longer valid
9251   if ( ds->vtl->draw_sync_do ) {
9252     gdk_threads_enter();
9253     gdk_draw_drawable (ds->drawable,
9254                        ds->gc,
9255                        ds->pixmap,
9256                        0, 0, 0, 0, -1, -1);
9257     ds->vtl->draw_sync_done = TRUE;
9258     gdk_threads_leave();
9259   }
9260   g_free ( ds );
9261   return FALSE;
9262 }
9263
9264 static gchar* distance_string (gdouble distance)
9265 {
9266   gchar str[128];
9267
9268   /* draw label with distance */
9269   vik_units_distance_t dist_units = a_vik_get_units_distance ();
9270   switch (dist_units) {
9271   case VIK_UNITS_DISTANCE_MILES:
9272     if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
9273       g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
9274     } else if (distance < 1609.4) {
9275       g_sprintf(str, "%d yards", (int)(distance*1.0936133));
9276     } else {
9277       g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
9278     }
9279     break;
9280   default:
9281     // VIK_UNITS_DISTANCE_KILOMETRES
9282     if (distance >= 1000 && distance < 100000) {
9283       g_sprintf(str, "%3.2f km", distance/1000.0);
9284     } else if (distance < 1000) {
9285       g_sprintf(str, "%d m", (int)distance);
9286     } else {
9287       g_sprintf(str, "%d km", (int)distance/1000);
9288     }
9289     break;
9290   }
9291   return g_strdup (str);
9292 }
9293
9294 /*
9295  * Actually set the message in statusbar
9296  */
9297 static void statusbar_write (gdouble distance, gdouble elev_gain, gdouble elev_loss, gdouble last_step, gdouble angle, VikTrwLayer *vtl )
9298 {
9299   // Only show elevation data when track has some elevation properties
9300   gchar str_gain_loss[64];
9301   str_gain_loss[0] = '\0';
9302   gchar str_last_step[64];
9303   str_last_step[0] = '\0';
9304   gchar *str_total = distance_string (distance);
9305   
9306   if ( (elev_gain > 0.1) || (elev_loss > 0.1) ) {
9307     if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
9308       g_sprintf(str_gain_loss, _(" - Gain %dm:Loss %dm"), (int)elev_gain, (int)elev_loss);
9309     else
9310       g_sprintf(str_gain_loss, _(" - Gain %dft:Loss %dft"), (int)VIK_METERS_TO_FEET(elev_gain), (int)VIK_METERS_TO_FEET(elev_loss));
9311   }
9312   
9313   if ( last_step > 0 ) {
9314       gchar *tmp = distance_string (last_step);
9315       g_sprintf(str_last_step, _(" - Bearing %3.1f° - Step %s"), RAD2DEG(angle), tmp);
9316       g_free ( tmp );
9317   }
9318   
9319   VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl));
9320
9321   // Write with full gain/loss information
9322   gchar *msg = g_strdup_printf ( "Total %s%s%s", str_total, str_last_step, str_gain_loss);
9323   vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg );
9324   g_free ( msg );
9325   g_free ( str_total );
9326 }
9327
9328 /*
9329  * Figure out what information should be set in the statusbar and then write it
9330  */
9331 static void update_statusbar ( VikTrwLayer *vtl )
9332 {
9333   // Get elevation data
9334   gdouble elev_gain, elev_loss;
9335   vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
9336
9337   /* Find out actual distance of current track */
9338   gdouble distance = vik_track_get_length (vtl->current_track);
9339
9340   statusbar_write (distance, elev_gain, elev_loss, 0, 0, vtl);
9341 }
9342
9343
9344 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
9345 {
9346   /* if we haven't sync'ed yet, we don't have time to do more. */
9347   if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
9348     VikTrackpoint *last_tpt = vik_track_get_tp_last(vtl->current_track);
9349
9350     static GdkPixmap *pixmap = NULL;
9351     int w1, h1, w2, h2;
9352     // Need to check in case window has been resized
9353     w1 = vik_viewport_get_width(vvp);
9354     h1 = vik_viewport_get_height(vvp);
9355     if (!pixmap) {
9356       pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
9357     }
9358     gdk_drawable_get_size (pixmap, &w2, &h2);
9359     if (w1 != w2 || h1 != h2) {
9360       g_object_unref ( G_OBJECT ( pixmap ) );
9361       pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
9362     }
9363
9364     // Reset to background
9365     gdk_draw_drawable (pixmap,
9366                        vtl->current_track_newpoint_gc,
9367                        vik_viewport_get_pixmap(vvp),
9368                        0, 0, 0, 0, -1, -1);
9369
9370     draw_sync_t *passalong;
9371     gint x1, y1;
9372
9373     vik_viewport_coord_to_screen ( vvp, &(last_tpt->coord), &x1, &y1 );
9374
9375     // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method)
9376     //  otherwise using vik_viewport_draw_* functions puts the data into the base pixmap,
9377     //  thus when we come to reset to the background it would include what we have already drawn!!
9378     gdk_draw_line ( pixmap,
9379                     vtl->current_track_newpoint_gc,
9380                     x1, y1, event->x, event->y );
9381     // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
9382
9383     /* Find out actual distance of current track */
9384     gdouble distance = vik_track_get_length (vtl->current_track);
9385
9386     // Now add distance to where the pointer is //
9387     VikCoord coord;
9388     struct LatLon ll;
9389     vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
9390     vik_coord_to_latlon ( &coord, &ll );
9391     gdouble last_step = vik_coord_diff( &coord, &(last_tpt->coord));
9392     distance = distance + last_step;
9393
9394     // Get elevation data
9395     gdouble elev_gain, elev_loss;
9396     vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
9397
9398     // Adjust elevation data (if available) for the current pointer position
9399     gdouble elev_new;
9400     elev_new = (gdouble) a_dems_get_elev_by_coord ( &coord, VIK_DEM_INTERPOL_BEST );
9401     if ( elev_new != VIK_DEM_INVALID_ELEVATION ) {
9402       if ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) {
9403         // Adjust elevation of last track point
9404         if ( elev_new > last_tpt->altitude )
9405           // Going up
9406           elev_gain += elev_new - last_tpt->altitude;
9407         else
9408           // Going down
9409           elev_loss += last_tpt->altitude - elev_new;
9410       }
9411     }
9412
9413     //
9414     // Display of the distance 'tooltip' during track creation is controlled by a preference
9415     //
9416     if ( a_vik_get_create_track_tooltip() ) {
9417
9418       gchar *str = distance_string (distance);
9419
9420       PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
9421       pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc);
9422       pango_layout_set_text (pl, str, -1);
9423       gint wd, hd;
9424       pango_layout_get_pixel_size ( pl, &wd, &hd );
9425
9426       gint xd,yd;
9427       // offset from cursor a bit depending on font size
9428       xd = event->x + 10;
9429       yd = event->y - hd;
9430
9431       // Create a background block to make the text easier to read over the background map
9432       GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
9433       gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
9434       gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
9435
9436       g_object_unref ( G_OBJECT ( pl ) );
9437       g_object_unref ( G_OBJECT ( background_block_gc ) );
9438       g_free (str);
9439     }
9440
9441     passalong = g_new(draw_sync_t,1); // freed by draw_sync()
9442     passalong->vtl = vtl;
9443     passalong->pixmap = pixmap;
9444     passalong->drawable = gtk_widget_get_window(GTK_WIDGET(vvp));
9445     passalong->gc = vtl->current_track_newpoint_gc;
9446
9447     gdouble angle;
9448     gdouble baseangle;
9449     vik_viewport_compute_bearing ( vvp, x1, y1, event->x, event->y, &angle, &baseangle );
9450
9451     // Update statusbar with full gain/loss information
9452     statusbar_write (distance, elev_gain, elev_loss, last_step, angle, vtl);
9453
9454     // draw pixmap when we have time to
9455     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
9456     vtl->draw_sync_done = FALSE;
9457     return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
9458   }
9459   return VIK_LAYER_TOOL_ACK;
9460 }
9461
9462 // NB vtl->current_track must be valid
9463 static void undo_trackpoint_add ( VikTrwLayer *vtl )
9464 {
9465   // 'undo'
9466   if ( vtl->current_track->trackpoints ) {
9467     // TODO rework this...
9468     //vik_trackpoint_free ( vik_track_get_tp_last (vtl->current_track) );
9469     GList *last = g_list_last(vtl->current_track->trackpoints);
9470     g_free ( last->data );
9471     vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
9472
9473     vik_track_calculate_bounds ( vtl->current_track );
9474   }
9475 }
9476
9477 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
9478 {
9479   if ( vtl->current_track && event->keyval == GDK_Escape ) {
9480     vtl->current_track = NULL;
9481     vik_layer_emit_update ( VIK_LAYER(vtl) );
9482     return TRUE;
9483   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
9484     undo_trackpoint_add ( vtl );
9485     update_statusbar ( vtl );
9486     vik_layer_emit_update ( VIK_LAYER(vtl) );
9487     return TRUE;
9488   }
9489   return FALSE;
9490 }
9491
9492 /*
9493  * Common function to handle trackpoint button requests on either a route or a track
9494  *  . enables adding a point via normal click
9495  *  . enables removal of last point via right click
9496  *  . finishing of the track or route via double clicking
9497  */
9498 static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9499 {
9500   VikTrackpoint *tp;
9501
9502   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9503     return FALSE;
9504
9505   if ( event->button == 2 ) {
9506     // As the display is panning, the new track pixmap is now invalid so don't draw it
9507     //  otherwise this drawing done results in flickering back to an old image
9508     vtl->draw_sync_do = FALSE;
9509     return FALSE;
9510   }
9511
9512   if ( event->button == 3 )
9513   {
9514     if ( !vtl->current_track )
9515       return FALSE;
9516     undo_trackpoint_add ( vtl );
9517     update_statusbar ( vtl );
9518     vik_layer_emit_update ( VIK_LAYER(vtl) );
9519     return TRUE;
9520   }
9521
9522   if ( event->type == GDK_2BUTTON_PRESS )
9523   {
9524     /* subtract last (duplicate from double click) tp then end */
9525     if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
9526     {
9527       /* undo last, then end */
9528       undo_trackpoint_add ( vtl );
9529       vtl->current_track = NULL;
9530     }
9531     vik_layer_emit_update ( VIK_LAYER(vtl) );
9532     return TRUE;
9533   }
9534
9535   tp = vik_trackpoint_new();
9536   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
9537
9538   /* snap to other TP */
9539   if ( event->state & GDK_CONTROL_MASK )
9540   {
9541     VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9542     if ( other_tp )
9543       tp->coord = other_tp->coord;
9544   }
9545
9546   tp->newsegment = FALSE;
9547   tp->has_timestamp = FALSE;
9548   tp->timestamp = 0;
9549
9550   if ( vtl->current_track ) {
9551     vik_track_add_trackpoint ( vtl->current_track, tp, TRUE ); // Ensure bounds is updated
9552     /* Auto attempt to get elevation from DEM data (if it's available) */
9553     vik_track_apply_dem_data_last_trackpoint ( vtl->current_track );
9554   }
9555
9556   vtl->ct_x1 = vtl->ct_x2;
9557   vtl->ct_y1 = vtl->ct_y2;
9558   vtl->ct_x2 = event->x;
9559   vtl->ct_y2 = event->y;
9560
9561   vik_layer_emit_update ( VIK_LAYER(vtl) );
9562   return TRUE;
9563 }
9564
9565 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9566 {
9567   // ----------------------------------------------------- if current is a route - switch to new track
9568   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
9569   {
9570     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
9571     if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ) ) )
9572     {
9573       new_track_create_common ( vtl, name );
9574       g_free ( name );
9575     }
9576     else
9577       return TRUE;
9578   }
9579   return tool_new_track_or_route_click ( vtl, event, vvp );
9580 }
9581
9582 static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9583 {
9584   if ( event->button == 2 ) {
9585     // Pan moving ended - enable potential point drawing again
9586     vtl->draw_sync_do = TRUE;
9587     vtl->draw_sync_done = TRUE;
9588   }
9589 }
9590
9591 /*** New route ****/
9592
9593 static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp)
9594 {
9595   return vvp;
9596 }
9597
9598 static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9599 {
9600   // -------------------------- if current is a track - switch to new route
9601   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
9602   {
9603     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
9604     if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ) ) ) {
9605       new_route_create_common ( vtl, name );
9606       g_free ( name );
9607     }
9608     else
9609       return TRUE;
9610   }
9611   return tool_new_track_or_route_click ( vtl, event, vvp );
9612 }
9613
9614 /*** New waypoint ****/
9615
9616 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
9617 {
9618   return vvp;
9619 }
9620
9621 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9622 {
9623   VikCoord coord;
9624   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9625     return FALSE;
9626   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
9627   if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) {
9628     trw_layer_calculate_bounds_waypoints ( vtl );
9629     vik_layer_emit_update ( VIK_LAYER(vtl) );
9630   }
9631   return TRUE;
9632 }
9633
9634
9635 /*** Edit trackpoint ****/
9636
9637 static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp)
9638 {
9639   tool_ed_t *t = g_new(tool_ed_t, 1);
9640   t->vvp = vvp;
9641   t->holding = FALSE;
9642   return t;
9643 }
9644
9645 static void tool_edit_trackpoint_destroy ( tool_ed_t *t )
9646 {
9647   g_free ( t );
9648 }
9649
9650 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9651 {
9652   tool_ed_t *t = data;
9653   VikViewport *vvp = t->vvp;
9654   TPSearchParams params;
9655   /* OUTDATED DOCUMENTATION:
9656    find 5 pixel range on each side. then put these UTM, and a pointer
9657    to the winning track name (and maybe the winning track itself), and a
9658    pointer to the winning trackpoint, inside an array or struct. pass 
9659    this along, do a foreach on the tracks which will do a foreach on the 
9660    trackpoints. */
9661   params.vvp = vvp;
9662   params.x = event->x;
9663   params.y = event->y;
9664   params.closest_track_id = NULL;
9665   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
9666   params.closest_tp = NULL;
9667   params.closest_tpl = NULL;
9668   vik_viewport_get_min_max_lat_lon ( vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
9669
9670   if ( event->button != 1 ) 
9671     return FALSE;
9672
9673   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9674     return FALSE;
9675
9676   if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible )
9677     return FALSE;
9678
9679   if ( vtl->current_tpl )
9680   {
9681     /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
9682     VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
9683     VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
9684     if ( !current_tr )
9685       return FALSE;
9686
9687     gint x, y;
9688     vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
9689
9690     if ( current_tr->visible && 
9691          abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
9692          abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
9693       marker_begin_move ( t, event->x, event->y );
9694       return TRUE;
9695     }
9696
9697   }
9698
9699   if ( vtl->tracks_visible )
9700     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
9701
9702   if ( params.closest_tp )
9703   {
9704     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, params.closest_track_id ), TRUE );
9705     vtl->current_tpl = params.closest_tpl;
9706     vtl->current_tp_id = params.closest_track_id;
9707     vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, params.closest_track_id );
9708     trw_layer_tpwin_init ( vtl );
9709     set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
9710     vik_layer_emit_update ( VIK_LAYER(vtl) );
9711     return TRUE;
9712   }
9713
9714   if ( vtl->routes_visible )
9715     g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &params);
9716
9717   if ( params.closest_tp )
9718   {
9719     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, params.closest_track_id ), TRUE );
9720     vtl->current_tpl = params.closest_tpl;
9721     vtl->current_tp_id = params.closest_track_id;
9722     vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, params.closest_track_id );
9723     trw_layer_tpwin_init ( vtl );
9724     set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
9725     vik_layer_emit_update ( VIK_LAYER(vtl) );
9726     return TRUE;
9727   }
9728
9729   /* these aren't the droids you're looking for */
9730   return FALSE;
9731 }
9732
9733 static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
9734 {
9735   tool_ed_t *t = data;
9736   VikViewport *vvp = t->vvp;
9737
9738   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9739     return FALSE;
9740
9741   if ( t->holding )
9742   {
9743     VikCoord new_coord;
9744     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9745
9746     /* snap to TP */
9747     if ( event->state & GDK_CONTROL_MASK )
9748     {
9749       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9750       if ( tp && tp != vtl->current_tpl->data )
9751         new_coord = tp->coord;
9752     }
9753     //    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
9754     { 
9755       gint x, y;
9756       vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
9757       marker_moveto ( t, x, y );
9758     } 
9759
9760     return TRUE;
9761   }
9762   return FALSE;
9763 }
9764
9765 static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9766 {
9767   tool_ed_t *t = data;
9768   VikViewport *vvp = t->vvp;
9769
9770   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9771     return FALSE;
9772   if ( event->button != 1) 
9773     return FALSE;
9774
9775   if ( t->holding ) {
9776     VikCoord new_coord;
9777     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9778
9779     /* snap to TP */
9780     if ( event->state & GDK_CONTROL_MASK )
9781     {
9782       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9783       if ( tp && tp != vtl->current_tpl->data )
9784         new_coord = tp->coord;
9785     }
9786
9787     VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
9788     if ( vtl->current_tp_track )
9789       vik_track_calculate_bounds ( vtl->current_tp_track );
9790
9791     marker_end_move ( t );
9792
9793     /* diff dist is diff from orig */
9794     if ( vtl->tpwin )
9795       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
9796
9797     vik_layer_emit_update ( VIK_LAYER(vtl) );
9798     return TRUE;
9799   }
9800   return FALSE;
9801 }
9802
9803
9804 /*** Route Finder ***/
9805 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
9806 {
9807   return vvp;
9808 }
9809
9810 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9811 {
9812   VikCoord tmp;
9813   if ( !vtl ) return FALSE;
9814   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
9815   if ( event->button == 3 && vtl->route_finder_current_track ) {
9816     VikCoord *new_end;
9817     new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
9818     if ( new_end ) {
9819       vtl->route_finder_coord = *new_end;
9820       g_free ( new_end );
9821       vik_layer_emit_update ( VIK_LAYER(vtl) );
9822       /* remove last ' to:...' */
9823       if ( vtl->route_finder_current_track->comment ) {
9824         gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
9825         if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
9826           gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
9827                                            last_to - vtl->route_finder_current_track->comment - 1);
9828           vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
9829         }
9830       }
9831     }
9832   }
9833   else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
9834     struct LatLon start, end;
9835
9836     vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
9837     vik_coord_to_latlon ( &(tmp), &end );
9838     vtl->route_finder_coord = tmp; /* for continuations */
9839
9840     /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
9841     if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
9842       vtl->route_finder_append = TRUE;  // merge tracks. keep started true.
9843     } else {
9844       vtl->route_finder_check_added_track = TRUE;
9845       vtl->route_finder_started = FALSE;
9846     }
9847
9848     vik_routing_default_find ( vtl, start, end);
9849
9850     /* see if anything was done -- a track was added or appended to */
9851     if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) {
9852       vik_track_set_comment_no_copy ( vtl->route_finder_added_track, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
9853     } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
9854       /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
9855       gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
9856       vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
9857     }
9858
9859     if ( vtl->route_finder_added_track )
9860       vik_track_calculate_bounds ( vtl->route_finder_added_track );
9861
9862     vtl->route_finder_added_track = NULL;
9863     vtl->route_finder_check_added_track = FALSE;
9864     vtl->route_finder_append = FALSE;
9865
9866     vik_layer_emit_update ( VIK_LAYER(vtl) );
9867   } else {
9868     vtl->route_finder_started = TRUE;
9869     vtl->route_finder_coord = tmp;
9870     vtl->route_finder_current_track = NULL;
9871   }
9872   return TRUE;
9873 }
9874
9875 /*** Show picture ****/
9876
9877 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
9878 {
9879   return vvp;
9880 }
9881
9882 /* Params are: vvp, event, last match found or NULL */
9883 static void tool_show_picture_wp ( const gpointer id, VikWaypoint *wp, gpointer params[3] )
9884 {
9885   if ( wp->image && wp->visible )
9886   {
9887     gint x, y, slackx, slacky;
9888     GdkEventButton *event = (GdkEventButton *) params[1];
9889
9890     vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
9891     slackx = wp->image_width / 2;
9892     slacky = wp->image_height / 2;
9893     if (    x <= event->x + slackx && x >= event->x - slackx
9894          && y <= event->y + slacky && y >= event->y - slacky )
9895     {
9896       params[2] = wp->image; /* we've found a match. however continue searching
9897                               * since we want to find the last match -- that
9898                               * is, the match that was drawn last. */
9899     }
9900   }
9901 }
9902
9903 static void trw_layer_show_picture ( menu_array_sublayer values )
9904 {
9905   /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
9906 #ifdef WINDOWS
9907   ShellExecute(NULL, "open", (char *) values[MA_MISC], NULL, NULL, SW_SHOWNORMAL);
9908 #else /* WINDOWS */
9909   GError *err = NULL;
9910   gchar *quoted_file = g_shell_quote ( (gchar *) values[MA_MISC] );
9911   gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
9912   g_free ( quoted_file );
9913   if ( ! g_spawn_command_line_async ( cmd, &err ) )
9914     {
9915       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() );
9916       g_error_free ( err );
9917     }
9918   g_free ( cmd );
9919 #endif /* WINDOWS */
9920 }
9921
9922 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9923 {
9924   gpointer params[3] = { vvp, event, NULL };
9925   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9926     return FALSE;
9927   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
9928   if ( params[2] )
9929   {
9930     static menu_array_sublayer values;
9931     values[MA_VTL] = vtl;
9932     values[MA_MISC] = params[2];
9933     trw_layer_show_picture ( values );
9934     return TRUE; /* found a match */
9935   }
9936   else
9937     return FALSE; /* go through other layers, searching for a match */
9938 }
9939
9940 /***************************************************************************
9941  ** End tool code 
9942  ***************************************************************************/
9943
9944
9945 static void image_wp_make_list ( const gpointer id, VikWaypoint *wp, GSList **pics )
9946 {
9947   if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
9948     *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
9949 }
9950
9951 /* Structure for thumbnail creating data used in the background thread */
9952 typedef struct {
9953   VikTrwLayer *vtl; // Layer needed for redrawing
9954   GSList *pics;     // Image list
9955 } thumbnail_create_thread_data;
9956
9957 static int create_thumbnails_thread ( thumbnail_create_thread_data *tctd, gpointer threaddata )
9958 {
9959   guint total = g_slist_length(tctd->pics), done = 0;
9960   while ( tctd->pics )
9961   {
9962     a_thumbnails_create ( (gchar *) tctd->pics->data );
9963     int result = a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
9964     if ( result != 0 )
9965       return -1; /* Abort thread */
9966
9967     tctd->pics = tctd->pics->next;
9968   }
9969
9970   // Redraw to show the thumbnails as they are now created
9971   if ( IS_VIK_LAYER(tctd->vtl) )
9972     vik_layer_emit_update ( VIK_LAYER(tctd->vtl) ); // NB update from background thread
9973
9974   return 0;
9975 }
9976
9977 static void thumbnail_create_thread_free ( thumbnail_create_thread_data *tctd )
9978 {
9979   while ( tctd->pics )
9980   {
9981     g_free ( tctd->pics->data );
9982     tctd->pics = g_slist_delete_link ( tctd->pics, tctd->pics );
9983   }
9984   g_free ( tctd );
9985 }
9986
9987 void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
9988 {
9989   if ( ! vtl->has_verified_thumbnails )
9990   {
9991     GSList *pics = NULL;
9992     g_hash_table_foreach ( vtl->waypoints, (GHFunc) image_wp_make_list, &pics );
9993     if ( pics )
9994     {
9995       gint len = g_slist_length ( pics );
9996       gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
9997       thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
9998       tctd->vtl = vtl;
9999       tctd->pics = pics;
10000       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
10001                             tmp,
10002                             (vik_thr_func) create_thumbnails_thread,
10003                             tctd,
10004                             (vik_thr_free_func) thumbnail_create_thread_free,
10005                             NULL,
10006                             len );
10007       g_free ( tmp );
10008     }
10009   }
10010 }
10011
10012 static const gchar* my_track_colors ( gint ii )
10013 {
10014   static const gchar* colors[VIK_TRW_LAYER_TRACK_GCS] = {
10015     "#2d870a",
10016     "#135D34",
10017     "#0a8783",
10018     "#0e4d87",
10019     "#05469f",
10020     "#695CBB",
10021     "#2d059f",
10022     "#4a059f",
10023     "#5A171A",
10024     "#96059f"
10025   };
10026   // Fast and reliable way of returning a colour
10027   return colors[(ii % VIK_TRW_LAYER_TRACK_GCS)];
10028 }
10029
10030 static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl )
10031 {
10032   GHashTableIter iter;
10033   gpointer key, value;
10034
10035   gint ii = 0;
10036   // Tracks
10037   g_hash_table_iter_init ( &iter, vtl->tracks );
10038
10039   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
10040
10041     // Tracks get a random spread of colours if not already assigned
10042     if ( ! VIK_TRACK(value)->has_color ) {
10043       if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR )
10044         VIK_TRACK(value)->color = vtl->track_color;
10045       else {
10046         gdk_color_parse ( my_track_colors (ii), &(VIK_TRACK(value)->color) );
10047       }
10048       VIK_TRACK(value)->has_color = TRUE;
10049     }
10050
10051     trw_layer_update_treeview ( vtl, VIK_TRACK(value) );
10052
10053     ii++;
10054     if (ii > VIK_TRW_LAYER_TRACK_GCS)
10055       ii = 0;
10056   }
10057
10058   // Routes
10059   ii = 0;
10060   g_hash_table_iter_init ( &iter, vtl->routes );
10061
10062   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
10063
10064     // Routes get an intermix of reds
10065     if ( ! VIK_TRACK(value)->has_color ) {
10066       if ( ii )
10067         gdk_color_parse ( "#FF0000" , &(VIK_TRACK(value)->color) ); // Red
10068       else
10069         gdk_color_parse ( "#B40916" , &(VIK_TRACK(value)->color) ); // Dark Red
10070       VIK_TRACK(value)->has_color = TRUE;
10071     }
10072
10073     trw_layer_update_treeview ( vtl, VIK_TRACK(value) );
10074
10075     ii = !ii;
10076   }
10077 }
10078
10079 /*
10080  * (Re)Calculate the bounds of the waypoints in this layer,
10081  * This should be called whenever waypoints are changed
10082  */
10083 void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl )
10084 {
10085   struct LatLon topleft = { 0.0, 0.0 };
10086   struct LatLon bottomright = { 0.0, 0.0 };
10087   struct LatLon ll;
10088
10089   GHashTableIter iter;
10090   gpointer key, value;
10091
10092   g_hash_table_iter_init ( &iter, vtl->waypoints );
10093
10094   // Set bounds to first point
10095   if ( g_hash_table_iter_next (&iter, &key, &value) ) {
10096     vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &topleft );
10097     vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &bottomright );
10098   }
10099
10100   // Ensure there is another point...
10101   if ( g_hash_table_size ( vtl->waypoints ) > 1 ) {
10102
10103     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
10104
10105       // See if this point increases the bounds.
10106       vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &ll );
10107
10108       if ( ll.lat > topleft.lat) topleft.lat = ll.lat;
10109       if ( ll.lon < topleft.lon) topleft.lon = ll.lon;
10110       if ( ll.lat < bottomright.lat) bottomright.lat = ll.lat;
10111       if ( ll.lon > bottomright.lon) bottomright.lon = ll.lon;
10112     }
10113   }
10114
10115   vtl->waypoints_bbox.north = topleft.lat;
10116   vtl->waypoints_bbox.east = bottomright.lon;
10117   vtl->waypoints_bbox.south = bottomright.lat;
10118   vtl->waypoints_bbox.west = topleft.lon;
10119 }
10120
10121 static void trw_layer_calculate_bounds_track ( gpointer id, VikTrack *trk )
10122 {
10123   vik_track_calculate_bounds ( trk );
10124 }
10125
10126 static void trw_layer_calculate_bounds_tracks ( VikTrwLayer *vtl )
10127 {
10128   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_calculate_bounds_track, NULL );
10129   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_calculate_bounds_track, NULL );
10130 }
10131
10132 static void trw_layer_sort_all ( VikTrwLayer *vtl )
10133 {
10134   if ( ! VIK_LAYER(vtl)->vt )
10135     return;
10136
10137   // Obviously need 2 to tango - sorting with only 1 (or less) is a lonely activity!
10138   if ( g_hash_table_size (vtl->tracks) > 1 )
10139     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
10140
10141   if ( g_hash_table_size (vtl->routes) > 1 )
10142     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
10143
10144   if ( g_hash_table_size (vtl->waypoints) > 1 )
10145     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
10146 }
10147
10148 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
10149 {
10150   if ( VIK_LAYER(vtl)->realized )
10151     trw_layer_verify_thumbnails ( vtl, vvp );
10152   trw_layer_track_alloc_colors ( vtl );
10153
10154   trw_layer_calculate_bounds_waypoints ( vtl );
10155   trw_layer_calculate_bounds_tracks ( vtl );
10156
10157   // Apply treeview sort after loading all the tracks for this layer
10158   //  (rather than sorted insert on each individual track additional)
10159   //  and after subsequent changes to the properties as the specified order may have changed.
10160   //  since the sorting of a treeview section is now very quick
10161   // NB sorting is also performed after every name change as well to maintain the list order
10162   trw_layer_sort_all ( vtl );
10163
10164   // Setting metadata time if not otherwise set
10165   if ( vtl->metadata ) {
10166
10167     gboolean need_to_set_time = TRUE;
10168     if ( vtl->metadata->timestamp ) {
10169       need_to_set_time = FALSE;
10170       if ( !g_strcmp0(vtl->metadata->timestamp, "" ) )
10171         need_to_set_time = TRUE;
10172     }
10173
10174     if ( need_to_set_time ) {
10175       // Could rewrite this as a general get first time of a TRW Layer function
10176       GTimeVal timestamp;
10177       timestamp.tv_usec = 0;
10178       gboolean has_timestamp = FALSE;
10179
10180       GList *gl = NULL;
10181       gl = g_hash_table_get_values ( vtl->tracks );
10182       gl = g_list_sort ( gl, vik_track_compare_timestamp );
10183       gl = g_list_first ( gl );
10184
10185       // Check times of tracks
10186       if ( gl ) {
10187         // Only need to check the first track as they have been sorted by time
10188         VikTrack *trk = (VikTrack*)gl->data;
10189         // Assume trackpoints already sorted by time
10190         VikTrackpoint *tpt = vik_track_get_tp_first(trk);
10191         if ( tpt && tpt->has_timestamp ) {
10192           timestamp.tv_sec = tpt->timestamp;
10193           has_timestamp = TRUE;
10194         }
10195         g_list_free ( gl );
10196       }
10197
10198       if ( !has_timestamp ) {
10199         // 'Last' resort - current time
10200         // Get before waypoint tests - so that if a waypoint time value (in the past) is found it should be used
10201         g_get_current_time ( &timestamp );
10202
10203         // Check times of waypoints
10204         gl = g_hash_table_get_values ( vtl->waypoints );
10205         GList *iter;
10206         for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) {
10207           VikWaypoint *wpt = (VikWaypoint*)iter->data;
10208           if ( wpt->has_timestamp ) {
10209             if ( timestamp.tv_sec > wpt->timestamp ) {
10210               timestamp.tv_sec = wpt->timestamp;
10211               has_timestamp = TRUE;
10212             }
10213           }
10214         }
10215         g_list_free ( gl );
10216       }
10217
10218       vtl->metadata->timestamp = g_time_val_to_iso8601 ( &timestamp );
10219     }
10220   }
10221 }
10222
10223 VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
10224 {
10225   return vtl->coord_mode;
10226 }
10227
10228 /**
10229  * Uniquify the whole layer
10230  * Also requires the layers panel as the names shown there need updating too
10231  * Returns whether the operation was successful or not
10232  */
10233 gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
10234 {
10235   if ( vtl && vlp ) {
10236     vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->tracks, TRUE );
10237     vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->routes, FALSE );
10238     vik_trw_layer_uniquify_waypoints ( vtl, vlp );
10239     return TRUE;
10240   }
10241   return FALSE;
10242 }
10243
10244 static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode )
10245 {
10246   vik_coord_convert ( &(wp->coord), *dest_mode );
10247 }
10248
10249 static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode )
10250 {
10251   vik_track_convert ( tr, *dest_mode );
10252 }
10253
10254 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode )
10255 {
10256   if ( vtl->coord_mode != dest_mode )
10257   {
10258     vtl->coord_mode = dest_mode;
10259     g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_convert, &dest_mode );
10260     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
10261     g_hash_table_foreach ( vtl->routes, (GHFunc) track_convert, &dest_mode );
10262   }
10263 }
10264
10265 static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 selection )
10266 {
10267   vtl->menu_selection = selection;
10268 }
10269
10270 static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl )
10271 {
10272   return (vtl->menu_selection);
10273 }
10274
10275 /* ----------- Downloading maps along tracks --------------- */
10276
10277 static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
10278 {
10279   /* TODO: calculating based on current size of viewport */
10280   const gdouble w_at_zoom_0_125 = 0.0013;
10281   const gdouble h_at_zoom_0_125 = 0.0011;
10282   gdouble zoom_factor = zoom_level/0.125;
10283
10284   wh->lat = h_at_zoom_0_125 * zoom_factor;
10285   wh->lon = w_at_zoom_0_125 * zoom_factor;
10286
10287   return 0;   /* all OK */
10288 }
10289
10290 static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
10291 {
10292   if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
10293       (dist->lat >= ABS(to->north_south - from->north_south)))
10294     return NULL;
10295
10296   VikCoord *coord = g_malloc(sizeof(VikCoord));
10297   coord->mode = VIK_COORD_LATLON;
10298
10299   if (ABS(gradient) < 1) {
10300     if (from->east_west > to->east_west)
10301       coord->east_west = from->east_west - dist->lon;
10302     else
10303       coord->east_west = from->east_west + dist->lon;
10304     coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
10305   } else {
10306     if (from->north_south > to->north_south)
10307       coord->north_south = from->north_south - dist->lat;
10308     else
10309       coord->north_south = from->north_south + dist->lat;
10310     coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
10311   }
10312
10313   return coord;
10314 }
10315
10316 static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
10317 {
10318   /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
10319   gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
10320
10321   VikCoord *next = from;
10322   while (TRUE) {
10323     if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
10324         break;
10325     list = g_list_prepend(list, next);
10326   }
10327
10328   return list;
10329 }
10330
10331 void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
10332 {
10333   typedef struct _Rect {
10334     VikCoord tl;
10335     VikCoord br;
10336     VikCoord center;
10337   } Rect;
10338 #define GLRECT(iter) ((Rect *)((iter)->data))
10339
10340   struct LatLon wh;
10341   GList *rects_to_download = NULL;
10342   GList *rect_iter;
10343
10344   if (get_download_area_width(vvp, zoom_level, &wh))
10345     return;
10346
10347   GList *iter = tr->trackpoints;
10348   if (!iter)
10349     return;
10350
10351   gboolean new_map = TRUE;
10352   VikCoord *cur_coord, tl, br;
10353   Rect *rect;
10354   while (iter) {
10355     cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
10356     if (new_map) {
10357       vik_coord_set_area(cur_coord, &wh, &tl, &br);
10358       rect = g_malloc(sizeof(Rect));
10359       rect->tl = tl;
10360       rect->br = br;
10361       rect->center = *cur_coord;
10362       rects_to_download = g_list_prepend(rects_to_download, rect);
10363       new_map = FALSE;
10364       iter = iter->next;
10365       continue;
10366     }
10367     gboolean found = FALSE;
10368     for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
10369       if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
10370         found = TRUE;
10371         break;
10372       }
10373     }
10374     if (found)
10375         iter = iter->next;
10376     else
10377       new_map = TRUE;
10378   }
10379
10380   GList *fillins = NULL;
10381   /* 'fillin' doesn't work in UTM mode - potentially ending up in massive loop continually allocating memory - hence don't do it */
10382   /* seems that ATM the function get_next_coord works only for LATLON */
10383   if ( cur_coord->mode == VIK_COORD_LATLON ) {
10384     /* fill-ins for far apart points */
10385     GList *cur_rect, *next_rect;
10386     for (cur_rect = rects_to_download;
10387          (next_rect = cur_rect->next) != NULL;
10388          cur_rect = cur_rect->next) {
10389       if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
10390           (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
10391         fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
10392       }
10393     }
10394   } else
10395     g_message("%s: this feature works only in Mercator mode", __FUNCTION__);
10396
10397   if (fillins) {
10398     GList *iter = fillins;
10399     while (iter) {
10400       cur_coord = (VikCoord *)(iter->data);
10401       vik_coord_set_area(cur_coord, &wh, &tl, &br);
10402       rect = g_malloc(sizeof(Rect));
10403       rect->tl = tl;
10404       rect->br = br;
10405       rect->center = *cur_coord;
10406       rects_to_download = g_list_prepend(rects_to_download, rect);
10407       iter = iter->next;
10408     }
10409   }
10410
10411   for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
10412     vik_maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
10413   }
10414
10415   if (fillins) {
10416     for (iter = fillins; iter; iter = iter->next)
10417       g_free(iter->data);
10418     g_list_free(fillins);
10419   }
10420   if (rects_to_download) {
10421     for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
10422       g_free(rect_iter->data);
10423     g_list_free(rects_to_download);
10424   }
10425 }
10426
10427 static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values )
10428 {
10429   VikMapsLayer *vml;
10430   gint selected_map;
10431   gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
10432   gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
10433   gint selected_zoom, default_zoom;
10434
10435   VikTrwLayer *vtl = values[MA_VTL];
10436   VikLayersPanel *vlp = values[MA_VLP];
10437   VikTrack *trk;
10438   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
10439     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
10440   else
10441     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
10442   if ( !trk )
10443     return;
10444
10445   VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
10446
10447   GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types
10448   int num_maps = g_list_length(vmls);
10449
10450   if (!num_maps) {
10451     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No map layer in use. Create one first") );
10452     return;
10453   }
10454
10455   // Convert from list of vmls to list of names. Allowing the user to select one of them
10456   gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
10457   VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
10458
10459   gchar **np = map_names;
10460   VikMapsLayer **lp = map_layers;
10461   int i;
10462   for (i = 0; i < num_maps; i++) {
10463     vml = (VikMapsLayer *)(vmls->data);
10464     *lp++ = vml;
10465     *np++ = vik_maps_layer_get_map_label(vml);
10466     vmls = vmls->next;
10467   }
10468   // Mark end of the array lists
10469   *lp = NULL;
10470   *np = NULL;
10471
10472   gdouble cur_zoom = vik_viewport_get_zoom(vvp);
10473   for (default_zoom = 0; default_zoom < G_N_ELEMENTS(zoom_vals); default_zoom++) {
10474     if (cur_zoom == zoom_vals[default_zoom])
10475       break;
10476   }
10477   default_zoom = (default_zoom == G_N_ELEMENTS(zoom_vals)) ? G_N_ELEMENTS(zoom_vals) - 1 : default_zoom;
10478
10479   if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, 0, zoomlist, default_zoom, &selected_map, &selected_zoom))
10480     goto done;
10481
10482   vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
10483
10484 done:
10485   for (i = 0; i < num_maps; i++)
10486     g_free(map_names[i]);
10487   g_free(map_names);
10488   g_free(map_layers);
10489
10490   g_list_free(vmls);
10491
10492 }
10493
10494 /**** lowest waypoint number calculation ***/
10495 static gint highest_wp_number_name_to_number(const gchar *name) {
10496   if ( strlen(name) == 3 ) {
10497     int n = atoi(name);
10498     if ( n < 100 && name[0] != '0' )
10499       return -1;
10500     if ( n < 10 && name[0] != '0' )
10501       return -1;
10502     return n;
10503   }
10504   return -1;
10505 }
10506
10507
10508 static void highest_wp_number_reset(VikTrwLayer *vtl)
10509 {
10510   vtl->highest_wp_number = -1;
10511 }
10512
10513 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name)
10514 {
10515   /* if is bigger that top, add it */
10516   gint new_wp_num = highest_wp_number_name_to_number(new_wp_name);
10517   if ( new_wp_num > vtl->highest_wp_number )
10518     vtl->highest_wp_number = new_wp_num;
10519 }
10520
10521 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name)
10522 {
10523   /* if wasn't top, do nothing. if was top, count backwards until we find one used */
10524   gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
10525   if ( vtl->highest_wp_number == old_wp_num ) {
10526     gchar buf[4];
10527     vtl->highest_wp_number--;
10528
10529     g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
10530     /* search down until we find something that *does* exist */
10531
10532     while ( vtl->highest_wp_number > 0 && ! vik_trw_layer_get_waypoint ( vtl, buf )) {
10533       vtl->highest_wp_number--;
10534       g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
10535     }
10536   }
10537 }
10538
10539 /* get lowest unused number */
10540 static gchar *highest_wp_number_get(VikTrwLayer *vtl)
10541 {
10542   gchar buf[4];
10543   if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 )
10544     return NULL;
10545   g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 );
10546   return g_strdup(buf);
10547 }
10548
10549 /**
10550  * trw_layer_create_track_list_both:
10551  *
10552  * Create the latest list of tracks and routes
10553  */
10554 static GList* trw_layer_create_track_list_both ( VikLayer *vl, gpointer user_data )
10555 {
10556   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
10557   GList *tracks = NULL;
10558   tracks = g_list_concat ( tracks, g_hash_table_get_values ( vik_trw_layer_get_tracks ( vtl ) ) );
10559   tracks = g_list_concat ( tracks, g_hash_table_get_values ( vik_trw_layer_get_routes ( vtl ) ) );
10560
10561   return vik_trw_layer_build_track_list_t ( vtl, tracks );
10562 }
10563
10564 static void trw_layer_track_list_dialog_single ( menu_array_sublayer values )
10565 {
10566   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
10567
10568   gchar *title = NULL;
10569   if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
10570     title = g_strdup_printf ( _("%s: Track List"), VIK_LAYER(vtl)->name );
10571   else
10572     title = g_strdup_printf ( _("%s: Route List"), VIK_LAYER(vtl)->name );
10573
10574   vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), values[MA_SUBTYPE], trw_layer_create_track_list, FALSE );
10575   g_free ( title );
10576 }
10577
10578 static void trw_layer_track_list_dialog ( menu_array_layer values )
10579 {
10580   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
10581
10582   gchar *title = g_strdup_printf ( _("%s: Track and Route List"), VIK_LAYER(vtl)->name );
10583   vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_track_list_both, FALSE );
10584   g_free ( title );
10585 }
10586
10587 static void trw_layer_waypoint_list_dialog ( menu_array_layer values )
10588 {
10589   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
10590
10591   gchar *title = g_strdup_printf ( _("%s: Waypoint List"), VIK_LAYER(vtl)->name );
10592   vik_trw_layer_waypoint_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_waypoint_list, FALSE );
10593   g_free ( title );
10594 }