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