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