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