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