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