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