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