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