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