]> git.street.me.uk Git - andy/viking.git/blame - src/viktrwlayer.c
On creating a new waypoint always attempt to auto set the altitude if DEM data is...
[andy/viking.git] / src / viktrwlayer.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
a482007a
GB
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>
50a14534
EB
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#define WAYPOINT_FONT "Sans 8"
26
27/* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
28/* viktrwlayer.c -- 2200 lines can make a difference in the state of things */
29
3e7553ae
GB
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
50a14534 34#include "viking.h"
7114e879 35#include "vikmapslayer.h"
50a14534
EB
36#include "viktrwlayer_tpwin.h"
37#include "viktrwlayer_propwin.h"
acaf7113 38#include "garminsymbols.h"
50a14534
EB
39#include "thumbnails.h"
40#include "background.h"
911400b5 41#include "gpx.h"
e0b0b9c1 42#include "babel.h"
ad0a8c2d
EB
43#include "dem.h"
44#include "dems.h"
165a4fa9 45#include "geonamessearch.h"
3e7553ae
GB
46#ifdef VIK_CONFIG_OPENSTREETMAP
47#include "osm-traces.h"
48#endif
28c82d8b 49#include "acquire.h"
7d02a0b0 50#include "util.h"
50a14534 51
bce3a7b0
EB
52#include "icons/icons.h"
53
8c00358d 54#ifdef HAVE_MATH_H
50a14534 55#include <math.h>
8c00358d
GB
56#endif
57#ifdef HAVE_STRING_H
50a14534 58#include <string.h>
8c00358d
GB
59#endif
60#ifdef HAVE_STDLIB_H
50a14534 61#include <stdlib.h>
8c00358d 62#endif
8c060406 63#include <stdio.h>
50a14534
EB
64#include <ctype.h>
65
777e2d4d 66#include <gdk/gdkkeysyms.h>
8c060406
MA
67#include <glib.h>
68#include <glib/gstdio.h>
4c77d5e0 69#include <glib/gi18n.h>
777e2d4d 70
090cae39
GB
71/* Relax some dependencies */
72#if ! GLIB_CHECK_VERSION(2,12,0)
73static gboolean return_true (gpointer a, gpointer b, gpointer c) { return TRUE; }
74static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
75#endif
76
ae941b4c 77#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml"
480fb7e1 78#define VIK_TRW_LAYER_TRACK_GC 13
50a14534
EB
79#define VIK_TRW_LAYER_TRACK_GC_RATES 10
80#define VIK_TRW_LAYER_TRACK_GC_MIN 0
81#define VIK_TRW_LAYER_TRACK_GC_MAX 11
82#define VIK_TRW_LAYER_TRACK_GC_BLACK 12
83
84#define DRAWMODE_BY_TRACK 0
85#define DRAWMODE_BY_VELOCITY 1
86#define DRAWMODE_ALL_BLACK 2
87
88#define POINTS 1
89#define LINES 2
90
91/* this is how it knows when you click if you are clicking close to a trackpoint. */
92#define TRACKPOINT_SIZE_APPROX 5
93#define WAYPOINT_SIZE_APPROX 5
94
b42a25ba
EB
95#define MIN_STOP_LENGTH 15
96#define MAX_STOP_LENGTH 86400
97#define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
98 /* this is multiplied by user-inputted value from 1-100. */
50a14534
EB
99enum {
100VIK_TRW_LAYER_SUBLAYER_TRACKS,
101VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
102VIK_TRW_LAYER_SUBLAYER_TRACK,
103VIK_TRW_LAYER_SUBLAYER_WAYPOINT
104};
105
106enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
107
108struct _VikTrwLayer {
109 VikLayer vl;
110 GHashTable *tracks;
111 GHashTable *tracks_iters;
112 GHashTable *waypoints_iters;
113 GHashTable *waypoints;
114 GtkTreeIter waypoints_iter, tracks_iter;
115 gboolean tracks_visible, waypoints_visible;
116 guint8 drawmode;
117 guint8 drawpoints;
b42a25ba
EB
118 guint8 drawelevation;
119 guint8 elevation_factor;
120 guint8 drawstops;
121 guint32 stop_length;
50a14534
EB
122 guint8 drawlines;
123 guint8 line_thickness;
124 guint8 bg_line_thickness;
125
126 guint8 wp_symbol;
127 guint8 wp_size;
ea3933fc 128 gboolean wp_draw_symbols;
50a14534
EB
129
130 gdouble velocity_min, velocity_max;
131 GArray *track_gc;
132 guint16 track_gc_iter;
8e9c992d 133 GdkGC *current_track_gc;
50a14534
EB
134 GdkGC *track_bg_gc;
135 GdkGC *waypoint_gc;
136 GdkGC *waypoint_text_gc;
137 GdkGC *waypoint_bg_gc;
138 GdkFont *waypoint_font;
139 VikTrack *current_track;
140 guint16 ct_x1, ct_y1, ct_x2, ct_y2;
7b203521
EB
141 gboolean ct_sync_done;
142
50a14534
EB
143
144 VikCoordMode coord_mode;
145
146 /* wp editing tool */
147 VikWaypoint *current_wp;
148 gchar *current_wp_name;
149 gboolean moving_wp;
150 gboolean waypoint_rightclick;
151
152 /* track editing tool */
153 GList *current_tpl;
154 gchar *current_tp_track_name;
155 VikTrwLayerTpwin *tpwin;
156
157 /* weird hack for joining tracks */
158 GList *last_tpl;
159 gchar *last_tp_track_name;
160
161 /* track editing tool -- more specifically, moving tps */
162 gboolean moving_tp;
163
7ff7d728
RN
164 /* route finder tool */
165 gboolean route_finder_started;
166 VikCoord route_finder_coord;
167 gboolean route_finder_check_added_track;
168 gchar *route_finder_added_track_name;
169 VikTrack *route_finder_current_track;
170 gboolean route_finder_append;
1eef1bde 171
50a14534
EB
172 gboolean drawlabels;
173 gboolean drawimages;
174 guint8 image_alpha;
175 GQueue *image_cache;
176 guint8 image_size;
177 guint16 image_cache_size;
178
179 /* for waypoint text */
180 PangoLayout *wplabellayout;
181
182 gboolean has_verified_thumbnails;
183
184 GtkMenu *wp_right_click_menu;
8bd81489 185 GtkMenu *track_right_click_menu;
50a14534 186
20c7a3a0
QT
187 /* menu */
188 VikStdLayerMenuItem menu_selection;
189
a8fe53f8 190 gint highest_wp_number;
50a14534
EB
191};
192
193/* A caached waypoint image. */
194typedef struct {
195 GdkPixbuf *pixbuf;
196 gchar *image; /* filename */
197} CachedPixbuf;
198
199struct DrawingParams {
200 VikViewport *vp;
201 VikTrwLayer *vtl;
202 gdouble xmpp, ympp;
203 guint16 width, height;
204 const VikCoord *center;
205 gint track_gc_iter;
206 gboolean one_zone, lat_lon;
207 gdouble ce1, ce2, cn1, cn2;
208};
209
2cebc318 210static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16);
20c7a3a0
QT
211static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl);
212
6bb72350
RN
213static void trw_layer_delete_item ( gpointer pass_along[6] );
214static void trw_layer_copy_item_cb ( gpointer pass_along[6] );
215static void trw_layer_cut_item_cb ( gpointer pass_along[6] );
33534cd8 216
50a14534
EB
217static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] );
218static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] );
165a4fa9 219static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
50a14534
EB
220
221static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
222static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
223
224static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 );
225static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp );
226static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp );
227
cb89c5a5 228static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
c7060c4e
RN
229static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
230
6bb72350
RN
231static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
232static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] );
50a14534 233static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
6bb72350
RN
234static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] );
235static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
236static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
237static void trw_layer_goto_track_center ( gpointer pass_along[6] );
111fa174 238static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
6bb72350 239static void trw_layer_merge_with_other ( gpointer pass_along[6] );
111fa174 240static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
af2341f3 241static void trw_layer_split_by_n_points ( gpointer pass_along[6] );
c95d6b00
RN
242static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] );
243static void trw_layer_edit_trackpoint ( gpointer pass_along[6] );
a412f3f5 244static void trw_layer_show_picture ( gpointer pass_along[6] );
c95d6b00 245
50a14534 246static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
5a10c240 247static void trw_layer_auto_view ( gpointer layer_and_vlp[2] );
f7f8a0a6 248static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, const gchar* trackname, guint file_type );
50a14534
EB
249static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
250static void trw_layer_new_wp ( gpointer lav[2] );
fc59e8c7 251static void trw_layer_auto_waypoints_view ( gpointer lav[2] );
535ed1ae 252static void trw_layer_auto_tracks_view ( gpointer lav[2] );
c9a5cbf9 253static void trw_layer_delete_all_tracks ( gpointer lav[2] );
20b671c3 254static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] );
c9a5cbf9 255static void trw_layer_delete_all_waypoints ( gpointer lav[2] );
20b671c3 256static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] );
165a4fa9
HR
257static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] );
258static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] );
50a14534
EB
259
260/* pop-up items */
6bb72350
RN
261static void trw_layer_properties_item ( gpointer pass_along[6] );
262static void trw_layer_goto_waypoint ( gpointer pass_along[6] );
263static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] );
50a14534 264
6bb72350
RN
265static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[5] );
266static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[5] );
50a14534
EB
267static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
268
50a14534 269
911400b5 270static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len );
28612684 271static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
911400b5 272
158b3642
RN
273static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
274static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
50a14534 275
33534cd8 276static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
d5874ef9
RN
277static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
278
ddc47a46
AF
279static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
280static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
50a14534 281static void trw_layer_free_copied_item ( gint subtype, gpointer item );
70a23263 282static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
50a14534 283
08f14055
RN
284static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
285static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
286static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
e46f259a 287static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
77ad64fa 288
db79f75f 289static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
50a14534
EB
290static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl );
291static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
292static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
293static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
50a14534 294
941aa6e9 295static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
33534cd8 296static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
dc2c040e 297static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
33534cd8 298static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
941aa6e9
AF
299static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp);
300static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
301static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp);
7432fddf 302static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
dc2c040e 303static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
7432fddf 304static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
98f5364d
EB
305static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp);
306static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
941aa6e9
AF
307static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
308static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
dc2c040e 309static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp );
777e2d4d 310static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp );
941aa6e9
AF
311static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
312static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
7ff7d728
RN
313static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
314static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
1eef1bde 315
50a14534 316
50a14534
EB
317static void cached_pixbuf_free ( CachedPixbuf *cp );
318static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
319static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp );
320
321static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
322static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
323
324static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
325
e890a6e6 326static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name);
ddc47a46
AF
327static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode );
328static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode );
e890a6e6 329
a8fe53f8
EB
330static gchar *highest_wp_number_get(VikTrwLayer *vtl);
331static void highest_wp_number_reset(VikTrwLayer *vtl);
332static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
333static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
334
335
50a14534 336static VikToolInterface trw_layer_tools[] = {
4c77d5e0 337 { N_("Create Waypoint"), (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL,
5bfafde9 338 (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
941aa6e9 339
4c77d5e0 340 { N_("Create Track"), (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL,
dc2c040e 341 (VikToolMouseFunc) tool_new_track_click, (VikToolMouseMoveFunc) tool_new_track_move, NULL,
5bfafde9 342 (VikToolKeyFunc) tool_new_track_key_press, GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
50a14534 343
4c77d5e0 344 { N_("Begin Track"), (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL,
5bfafde9 345 (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
98f5364d 346
4c77d5e0 347 { N_("Edit Waypoint"), (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL,
7432fddf 348 (VikToolMouseFunc) tool_edit_waypoint_click,
dc2c040e 349 (VikToolMouseMoveFunc) tool_edit_waypoint_move,
5bfafde9 350 (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
941aa6e9 351
4c77d5e0 352 { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
33534cd8 353 (VikToolMouseFunc) tool_edit_trackpoint_click,
dc2c040e 354 (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
5bfafde9 355 (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
941aa6e9 356
4c77d5e0 357 { N_("Show Picture"), (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL,
5bfafde9 358 (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
1eef1bde 359
7ff7d728
RN
360 { N_("Route Finder"), (VikToolConstructorFunc) tool_route_finder_create, NULL, NULL, NULL,
361 (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
941aa6e9 362};
8e9c992d 363enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
50a14534
EB
364
365/****** PARAMETERS ******/
366
4c77d5e0 367static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
55906514 368enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
50a14534 369
4c77d5e0
GB
370static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 };
371static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
50a14534 372
b42a25ba 373
50a14534
EB
374static VikLayerParamScale params_scales[] = {
375 /* min max step digits */
376 { 1, 10, 1, 0 }, /* line_thickness */
377 { 0.0, 99.0, 1, 2 }, /* velocity_min */
378 { 1.0, 100.0, 1.0, 2 }, /* velocity_max */
379 /* 5 * step == how much to turn */
380 { 16, 128, 3.2, 0 }, /* image_size */
381 { 0, 255, 5, 0 }, /* image alpha */
382 { 5, 500, 5, 0 }, /* image cache_size */
383 { 0, 8, 1, 0 }, /* image cache_size */
384 { 1, 64, 1, 0 }, /* wpsize */
b42a25ba
EB
385 { MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1, 0 }, /* stop_length */
386 { 1, 100, 1, 0 }, /* stop_length */
50a14534
EB
387};
388
389VikLayerParam trw_layer_params[] = {
390 { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
391 { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
392
4c77d5e0
GB
393 { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL },
394 { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON },
395 { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON },
396 { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON },
397 { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 9 },
398
399 { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON },
400 { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 },
401
402 { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
403 { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 },
404 { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, 0 },
405 { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Min Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
406 { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Max Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 },
407
408 { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON },
409 { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
410 { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, 0 },
411 { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, 0 },
412 { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, 0 },
413 { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL },
414 { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 },
415 { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON },
416
417 { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON },
418 { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 3 },
419 { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 4 },
420 { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
50a14534
EB
421};
422
55906514 423enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS };
ad0a8c2d
EB
424
425/*** TO ADD A PARAM:
426 *** 1) Add to trw_layer_params and enumeration
427 *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
ad0a8c2d 428 ***/
50a14534
EB
429
430/****** END PARAMETERS ******/
431
432VikLayerInterface vik_trw_layer_interface = {
433 "TrackWaypoint",
5bfafde9 434 &viktrwlayer_pixbuf,
50a14534
EB
435
436 trw_layer_tools,
437 sizeof(trw_layer_tools) / sizeof(VikToolInterface),
438
439 trw_layer_params,
440 NUM_PARAMS,
441 params_groups, /* params_groups */
442 sizeof(params_groups)/sizeof(params_groups[0]), /* number of groups */
443
5a4a28bf
QT
444 VIK_MENU_ITEM_ALL,
445
50a14534
EB
446 (VikLayerFuncCreate) vik_trw_layer_create,
447 (VikLayerFuncRealize) vik_trw_layer_realize,
448 (VikLayerFuncPostRead) trw_layer_verify_thumbnails,
449 (VikLayerFuncFree) vik_trw_layer_free,
450
451 (VikLayerFuncProperties) NULL,
452 (VikLayerFuncDraw) vik_trw_layer_draw,
453 (VikLayerFuncChangeCoordMode) trw_layer_change_coord_mode,
454
20c7a3a0
QT
455 (VikLayerFuncSetMenuItemsSelection) vik_trw_layer_set_menu_selection,
456 (VikLayerFuncGetMenuItemsSelection) vik_trw_layer_get_menu_selection,
457
50a14534
EB
458 (VikLayerFuncAddMenuItems) vik_trw_layer_add_menu_items,
459 (VikLayerFuncSublayerAddMenuItems) vik_trw_layer_sublayer_add_menu_items,
460
461 (VikLayerFuncSublayerRenameRequest) vik_trw_layer_sublayer_rename_request,
462 (VikLayerFuncSublayerToggleVisible) vik_trw_layer_sublayer_toggle_visible,
c7060c4e 463 (VikLayerFuncSublayerTooltip) trw_layer_sublayer_tooltip,
cb89c5a5 464 (VikLayerFuncLayerTooltip) trw_layer_layer_tooltip,
a5dcfdb7 465 (VikLayerFuncLayerSelected) vik_trw_layer_selected,
50a14534 466
911400b5
AF
467 (VikLayerFuncMarshall) trw_layer_marshall,
468 (VikLayerFuncUnmarshall) trw_layer_unmarshall,
50a14534
EB
469
470 (VikLayerFuncSetParam) trw_layer_set_param,
471 (VikLayerFuncGetParam) trw_layer_get_param,
472
473 (VikLayerFuncReadFileData) a_gpspoint_read_file,
474 (VikLayerFuncWriteFileData) a_gpspoint_write_file,
475
33534cd8 476 (VikLayerFuncDeleteItem) trw_layer_del_item,
d5874ef9 477 (VikLayerFuncCutItem) trw_layer_cut_item,
50a14534
EB
478 (VikLayerFuncCopyItem) trw_layer_copy_item,
479 (VikLayerFuncPasteItem) trw_layer_paste_item,
480 (VikLayerFuncFreeCopiedItem) trw_layer_free_copied_item,
70a23263
AF
481
482 (VikLayerFuncDragDropRequest) trw_layer_drag_drop_request,
77ad64fa
RN
483
484 (VikLayerFuncSelectClick) trw_layer_select_click,
08f14055
RN
485 (VikLayerFuncSelectMove) trw_layer_select_move,
486 (VikLayerFuncSelectRelease) trw_layer_select_release,
e46f259a 487 (VikLayerFuncSelectedViewportMenu) trw_layer_show_selected_viewport_menu,
50a14534
EB
488};
489
490/* for copy & paste (I think?) */
491typedef struct {
ddc47a46
AF
492 guint len;
493 guint8 data[0];
494 // gchar *name;
495 // VikWaypoint *wp;
496} FlatItem;
50a14534
EB
497
498GType vik_trw_layer_get_type ()
499{
500 static GType vtl_type = 0;
501
502 if (!vtl_type)
503 {
504 static const GTypeInfo vtl_info =
505 {
506 sizeof (VikTrwLayerClass),
507 NULL, /* base_init */
508 NULL, /* base_finalize */
509 NULL, /* class init */
510 NULL, /* class_finalize */
511 NULL, /* class_data */
512 sizeof (VikTrwLayer),
513 0,
514 NULL /* instance init */
515 };
516 vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 );
517 }
518
519 return vtl_type;
520}
521
33534cd8
AF
522static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
523{
6bb72350 524 static gpointer pass_along[6];
33534cd8
AF
525 if (!sublayer) {
526 return;
527 }
528
529 pass_along[0] = vtl;
530 pass_along[1] = NULL;
dc2c040e 531 pass_along[2] = GINT_TO_POINTER (subtype);
33534cd8 532 pass_along[3] = sublayer;
169acf64 533 pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
6bb72350 534 pass_along[5] = NULL;
33534cd8
AF
535
536 trw_layer_delete_item ( pass_along );
537}
50a14534 538
d5874ef9
RN
539static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
540{
6bb72350 541 static gpointer pass_along[6];
d5874ef9
RN
542 if (!sublayer) {
543 return;
544 }
545
546 pass_along[0] = vtl;
547 pass_along[1] = NULL;
548 pass_along[2] = GINT_TO_POINTER (subtype);
549 pass_along[3] = sublayer;
169acf64 550 pass_along[4] = GINT_TO_POINTER (0); // No delete confirmation needed for auto delete
6bb72350 551 pass_along[5] = NULL;
d5874ef9
RN
552
553 trw_layer_copy_item_cb(pass_along);
554 trw_layer_cut_item_cb(pass_along);
555}
556
6bb72350 557static void trw_layer_copy_item_cb ( gpointer pass_along[6])
2cebc318
QT
558{
559 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
dc2c040e 560 gint subtype = GPOINTER_TO_INT (pass_along[2]);
2cebc318
QT
561 gpointer * sublayer = pass_along[3];
562 guint8 *data = NULL;
563 guint len;
564
565 trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
566
567 if (data) {
568 a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
569 subtype, len, data);
570 }
571}
572
6bb72350 573static void trw_layer_cut_item_cb ( gpointer pass_along[6])
2cebc318
QT
574{
575 trw_layer_copy_item_cb(pass_along);
169acf64 576 pass_along[4] = GINT_TO_POINTER (0); // Never need to confirm automatic delete
2cebc318
QT
577 trw_layer_delete_item(pass_along);
578}
579
ddc47a46 580static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
50a14534 581{
ddc47a46
AF
582 FlatItem *fi;
583 guint8 *id;
584 guint il;
585
586 if (!sublayer) {
587 *item = NULL;
588 return;
50a14534 589 }
ddc47a46
AF
590
591 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
50a14534 592 {
ddc47a46
AF
593 vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
594 } else {
595 vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
50a14534 596 }
ddc47a46
AF
597
598 *len = sizeof(FlatItem) + strlen(sublayer) + 1 + il;
599 fi = g_malloc ( *len );
600 fi->len = strlen(sublayer) + 1;
601 memcpy(fi->data, sublayer, fi->len);
602 memcpy(fi->data + fi->len, id, il);
603 g_free(id);
604 *item = (guint8 *)fi;
50a14534
EB
605}
606
ddc47a46 607static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len )
50a14534 608{
ddc47a46
AF
609 FlatItem *fi = (FlatItem *) item;
610
611 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && fi )
50a14534 612 {
ddc47a46
AF
613 VikWaypoint *w;
614 gchar *name;
615
616 name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, (gchar *)fi->data);
617 w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
618 vik_trw_layer_add_waypoint ( vtl, name, w );
619 waypoint_convert(name, w, &vtl->coord_mode);
58cd1c43
RN
620 // Consider if redraw necessary for the new item
621 if ( vtl->vl.visible && vtl->waypoints_visible && w->visible )
622 vik_layer_emit_update ( VIK_LAYER(vtl) );
50a14534
EB
623 return TRUE;
624 }
ddc47a46 625 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi )
50a14534 626 {
ddc47a46
AF
627 VikTrack *t;
628 gchar *name;
629 name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, (gchar *)fi->data);
630 t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
631 vik_trw_layer_add_track ( vtl, name, t );
632 track_convert(name, t, &vtl->coord_mode);
58cd1c43
RN
633 // Consider if redraw necessary for the new item
634 if ( vtl->vl.visible && vtl->tracks_visible && t->visible )
635 vik_layer_emit_update ( VIK_LAYER(vtl) );
50a14534
EB
636 return TRUE;
637 }
638 return FALSE;
639}
640
641static void trw_layer_free_copied_item ( gint subtype, gpointer item )
642{
ddc47a46
AF
643 if (item) {
644 g_free(item);
50a14534
EB
645 }
646}
647
158b3642 648static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
649{
650 switch ( id )
651 {
652 case PARAM_TV: vtl->tracks_visible = data.b; break;
653 case PARAM_WV: vtl->waypoints_visible = data.b; break;
654 case PARAM_DM: vtl->drawmode = data.u; break;
655 case PARAM_DP: vtl->drawpoints = data.b; break;
b42a25ba
EB
656 case PARAM_DE: vtl->drawelevation = data.b; break;
657 case PARAM_DS: vtl->drawstops = data.b; break;
50a14534 658 case PARAM_DL: vtl->drawlines = data.b; break;
b42a25ba
EB
659 case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
660 vtl->stop_length = data.u;
661 break;
662 case PARAM_EF: if ( data.u >= 1 && data.u <= 100 )
663 vtl->elevation_factor = data.u;
664 break;
50a14534
EB
665 case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness )
666 {
667 vtl->line_thickness = data.u;
668 trw_layer_new_track_gcs ( vtl, vp );
669 }
670 break;
f53c5b13 671 case PARAM_BLT: if ( data.u >= 0 && data.u <= 8 && data.u != vtl->bg_line_thickness )
50a14534
EB
672 {
673 vtl->bg_line_thickness = data.u;
674 trw_layer_new_track_gcs ( vtl, vp );
675 }
676 break;
72ff842f
RN
677 case PARAM_VMIN:
678 {
679 /* Convert to store internally
680 NB file operation always in internal units (metres per second) */
681 vik_units_speed_t speed_units = a_vik_get_units_speed ();
682 if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
683 vtl->velocity_min = data.d;
684 else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
685 vtl->velocity_min = VIK_KPH_TO_MPS(data.d);
686 else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
687 vtl->velocity_min = VIK_MPH_TO_MPS(data.d);
688 else
689 /* Knots */
690 vtl->velocity_min = VIK_KNOTS_TO_MPS(data.d);
691 break;
692 }
693 case PARAM_VMAX:
694 {
695 /* Convert to store internally
696 NB file operation always in internal units (metres per second) */
697 vik_units_speed_t speed_units = a_vik_get_units_speed ();
698 if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
699 vtl->velocity_max = data.d;
700 else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
701 vtl->velocity_max = VIK_KPH_TO_MPS(data.d);
702 else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
703 vtl->velocity_max = VIK_MPH_TO_MPS(data.d);
704 else
705 /* Knots */
706 vtl->velocity_max = VIK_KNOTS_TO_MPS(data.d);
707 break;
708 }
50a14534
EB
709 case PARAM_TBGC: gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(data.c)); break;
710 case PARAM_DLA: vtl->drawlabels = data.b; break;
711 case PARAM_DI: vtl->drawimages = data.b; break;
712 case PARAM_IS: if ( data.u != vtl->image_size )
713 {
714 vtl->image_size = data.u;
715 g_list_foreach ( vtl->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
716 g_queue_free ( vtl->image_cache );
717 vtl->image_cache = g_queue_new ();
718 }
719 break;
720 case PARAM_IA: vtl->image_alpha = data.u; break;
721 case PARAM_ICS: vtl->image_cache_size = data.u;
722 while ( vtl->image_cache->length > vtl->image_cache_size ) /* if shrinking cache_size, free pixbuf ASAP */
723 cached_pixbuf_free ( g_queue_pop_tail ( vtl->image_cache ) );
724 break;
725 case PARAM_WPC: gdk_gc_set_rgb_fg_color(vtl->waypoint_gc, &(data.c)); break;
726 case PARAM_WPTC: gdk_gc_set_rgb_fg_color(vtl->waypoint_text_gc, &(data.c)); break;
727 case PARAM_WPBC: gdk_gc_set_rgb_fg_color(vtl->waypoint_bg_gc, &(data.c)); break;
728 case PARAM_WPBA: gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY ); break;
729 case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
730 case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
ea3933fc 731 case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
50a14534
EB
732 }
733 return TRUE;
734}
735
158b3642 736static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation )
50a14534
EB
737{
738 VikLayerParamData rv;
739 switch ( id )
740 {
741 case PARAM_TV: rv.b = vtl->tracks_visible; break;
742 case PARAM_WV: rv.b = vtl->waypoints_visible; break;
743 case PARAM_DM: rv.u = vtl->drawmode; break;
744 case PARAM_DP: rv.b = vtl->drawpoints; break;
b42a25ba
EB
745 case PARAM_DE: rv.b = vtl->drawelevation; break;
746 case PARAM_EF: rv.u = vtl->elevation_factor; break;
747 case PARAM_DS: rv.b = vtl->drawstops; break;
748 case PARAM_SL: rv.u = vtl->stop_length; break;
50a14534
EB
749 case PARAM_DL: rv.b = vtl->drawlines; break;
750 case PARAM_LT: rv.u = vtl->line_thickness; break;
751 case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
72ff842f
RN
752 case PARAM_VMIN:
753 {
754 /* Convert to store internally
755 NB file operation always in internal units (metres per second) */
756 vik_units_speed_t speed_units = a_vik_get_units_speed ();
757 if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
758 rv.d = vtl->velocity_min;
759 else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
760 rv.d = VIK_MPS_TO_KPH(vtl->velocity_min);
761 else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
762 rv.d = VIK_MPS_TO_MPH(vtl->velocity_min);
763 else
764 /* Knots */
765 rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_min);
766 break;
767 }
768 case PARAM_VMAX:
769 {
770 /* Convert to store internally
771 NB file operation always in internal units (metres per second) */
772 vik_units_speed_t speed_units = a_vik_get_units_speed ();
773 if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
774 rv.d = vtl->velocity_max;
775 else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
776 rv.d = VIK_MPS_TO_KPH(vtl->velocity_max);
777 else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
778 rv.d = VIK_MPS_TO_MPH(vtl->velocity_max);
779 else
780 /* Knots */
781 rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_max);
782 break;
783 }
50a14534
EB
784 case PARAM_DLA: rv.b = vtl->drawlabels; break;
785 case PARAM_DI: rv.b = vtl->drawimages; break;
786 case PARAM_TBGC: vik_gc_get_fg_color(vtl->track_bg_gc, &(rv.c)); break;
787 case PARAM_IS: rv.u = vtl->image_size; break;
788 case PARAM_IA: rv.u = vtl->image_alpha; break;
789 case PARAM_ICS: rv.u = vtl->image_cache_size; break;
790 case PARAM_WPC: vik_gc_get_fg_color(vtl->waypoint_gc, &(rv.c)); break;
791 case PARAM_WPTC: vik_gc_get_fg_color(vtl->waypoint_text_gc, &(rv.c)); break;
792 case PARAM_WPBC: vik_gc_get_fg_color(vtl->waypoint_bg_gc, &(rv.c)); break;
793 case PARAM_WPBA: rv.b = (vik_gc_get_function(vtl->waypoint_bg_gc)==GDK_AND); break;
794 case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
795 case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
ea3933fc 796 case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
50a14534
EB
797 }
798 return rv;
799}
800
911400b5
AF
801static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
802{
4efcd55c
RN
803 guint8 *pd;
804 gchar *dd;
805 gsize dl;
806 gint pl;
911400b5
AF
807 gchar *tmpname;
808 FILE *f;
809
810 *data = NULL;
811
812 if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
813 a_gpx_write_file(vtl, f);
814 vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
815 fclose(f);
8c060406 816 f = NULL;
4efcd55c 817 g_file_get_contents(tmpname, &dd, &dl, NULL);
911400b5
AF
818 *len = sizeof(pl) + pl + dl;
819 *data = g_malloc(*len);
820 memcpy(*data, &pl, sizeof(pl));
821 memcpy(*data + sizeof(pl), pd, pl);
822 memcpy(*data + sizeof(pl) + pl, dd, dl);
823
824 g_free(pd);
825 g_free(dd);
8c060406 826 g_remove(tmpname);
911400b5
AF
827 g_free(tmpname);
828 }
829}
830
28612684 831static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
911400b5
AF
832{
833 VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
28612684 834 gint pl;
911400b5
AF
835 gchar *tmpname;
836 FILE *f;
837
838
839 memcpy(&pl, data, sizeof(pl));
840 data += sizeof(pl);
841 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, pl, vvp );
842 data += pl;
843
844 if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
4258f4e2 845 g_critical("couldn't open temp file");
911400b5
AF
846 exit(1);
847 }
848 fwrite(data, len - pl - sizeof(pl), 1, f);
849 rewind(f);
850 a_gpx_read_file(rv, f);
851 fclose(f);
8c060406
MA
852 f = NULL;
853 g_remove(tmpname);
911400b5
AF
854 g_free(tmpname);
855 return rv;
856}
857
753ec753 858static GList * str_array_to_glist(gchar* data[])
267b6db5
QT
859{
860 GList *gl = NULL;
861 gpointer * p;
0654760a 862 for (p = (gpointer)data; *p; p++)
267b6db5
QT
863 gl = g_list_prepend(gl, *p);
864 return(g_list_reverse(gl));
865}
866
8499a412
QT
867static gboolean strcase_equal(gconstpointer s1, gconstpointer s2)
868{
869 return (strcasecmp(s1, s2) == 0);
870}
871
872static guint strcase_hash(gconstpointer v)
873{
874 /* 31 bit hash function */
875 int i;
876 const gchar *t = v;
877 gchar s[128]; /* malloc is too slow for reading big files */
878 gchar *p = s;
879
880 for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
881 p[i] = toupper(t[i]);
882 p[i] = '\0';
883
884 p = s;
885 guint32 h = *p;
886 if (h) {
887 for (p += 1; *p != '\0'; p++)
888 h = (h << 5) - h + *p;
889 }
890
891 return h;
892}
893
50a14534
EB
894VikTrwLayer *vik_trw_layer_new ( gint drawmode )
895{
267b6db5 896 if (trw_layer_params[PARAM_DM].widget_data == NULL)
753ec753 897 trw_layer_params[PARAM_DM].widget_data = str_array_to_glist(params_drawmodes);
267b6db5 898 if (trw_layer_params[PARAM_WPSYM].widget_data == NULL)
753ec753 899 trw_layer_params[PARAM_WPSYM].widget_data = str_array_to_glist(params_wpsymbols);
267b6db5 900
50a14534
EB
901 VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) );
902 vik_layer_init ( VIK_LAYER(rv), VIK_LAYER_TRW );
903
8499a412 904 rv->waypoints = g_hash_table_new_full ( strcase_hash, strcase_equal, g_free, (GDestroyNotify) vik_waypoint_free );
50a14534
EB
905 rv->tracks = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_track_free );
906 rv->tracks_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
8499a412 907 rv->waypoints_iters = g_hash_table_new_full ( strcase_hash, strcase_equal, NULL, g_free );
50a14534
EB
908
909 /* TODO: constants at top */
910 rv->waypoints_visible = rv->tracks_visible = TRUE;
911 rv->drawmode = drawmode;
912 rv->drawpoints = TRUE;
b42a25ba
EB
913 rv->drawstops = FALSE;
914 rv->drawelevation = FALSE;
915 rv->elevation_factor = 30;
916 rv->stop_length = 60;
50a14534
EB
917 rv->drawlines = TRUE;
918 rv->wplabellayout = NULL;
919 rv->wp_right_click_menu = NULL;
8bd81489 920 rv->track_right_click_menu = NULL;
50a14534
EB
921 rv->waypoint_gc = NULL;
922 rv->waypoint_text_gc = NULL;
923 rv->waypoint_bg_gc = NULL;
924 rv->track_gc = NULL;
925 rv->velocity_max = 5.0;
926 rv->velocity_min = 0.0;
927 rv->line_thickness = 1;
b42a25ba 928 rv->bg_line_thickness = 0;
50a14534
EB
929 rv->current_wp = NULL;
930 rv->current_wp_name = NULL;
931 rv->current_track = NULL;
932 rv->current_tpl = NULL;
933 rv->current_tp_track_name = NULL;
934 rv->moving_tp = FALSE;
935 rv->moving_wp = FALSE;
1eef1bde 936
7b203521
EB
937 rv->ct_sync_done = TRUE;
938
7ff7d728
RN
939 rv->route_finder_started = FALSE;
940 rv->route_finder_check_added_track = FALSE;
941 rv->route_finder_added_track_name = NULL;
942 rv->route_finder_current_track = NULL;
943 rv->route_finder_append = FALSE;
1eef1bde 944
50a14534
EB
945 rv->waypoint_rightclick = FALSE;
946 rv->last_tpl = NULL;
947 rv->last_tp_track_name = NULL;
948 rv->tpwin = NULL;
949 rv->image_cache = g_queue_new();
950 rv->image_size = 64;
951 rv->image_alpha = 255;
952 rv->image_cache_size = 300;
953 rv->drawimages = TRUE;
954 rv->drawlabels = TRUE;
955 return rv;
956}
957
958
959void vik_trw_layer_free ( VikTrwLayer *trwlayer )
960{
961 g_hash_table_destroy(trwlayer->waypoints);
962 g_hash_table_destroy(trwlayer->tracks);
963
964 /* ODC: replace with GArray */
965 trw_layer_free_track_gcs ( trwlayer );
966
967 if ( trwlayer->wp_right_click_menu )
4f14a010 968 g_object_ref_sink ( G_OBJECT(trwlayer->wp_right_click_menu) );
50a14534 969
8bd81489
RN
970 if ( trwlayer->track_right_click_menu )
971 gtk_object_sink ( GTK_OBJECT(trwlayer->track_right_click_menu) );
972
50a14534
EB
973 if ( trwlayer->wplabellayout != NULL)
974 g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) );
975
976 if ( trwlayer->waypoint_gc != NULL )
977 g_object_unref ( G_OBJECT ( trwlayer->waypoint_gc ) );
978
979 if ( trwlayer->waypoint_text_gc != NULL )
980 g_object_unref ( G_OBJECT ( trwlayer->waypoint_text_gc ) );
981
982 if ( trwlayer->waypoint_bg_gc != NULL )
983 g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
984
985 if ( trwlayer->waypoint_font != NULL )
986 gdk_font_unref ( trwlayer->waypoint_font );
987
988 if ( trwlayer->tpwin != NULL )
989 gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
990
991 g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
992 g_queue_free ( trwlayer->image_cache );
993}
994
995static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp )
996{
997 dp->vp = vp;
998 dp->xmpp = vik_viewport_get_xmpp ( vp );
999 dp->ympp = vik_viewport_get_ympp ( vp );
1000 dp->width = vik_viewport_get_width ( vp );
1001 dp->height = vik_viewport_get_height ( vp );
1002 dp->center = vik_viewport_get_center ( vp );
1003 dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */
1004 dp->lat_lon = vik_viewport_get_coord_mode ( vp ) == VIK_COORD_LATLON;
1005
1006 if ( dp->one_zone )
1007 {
1008 gint w2, h2;
1009 w2 = dp->xmpp * (dp->width / 2) + 1600 / dp->xmpp;
1010 h2 = dp->ympp * (dp->height / 2) + 1600 / dp->ympp;
1011 /* leniency -- for tracks. Obviously for waypoints this SHOULD be a lot smaller */
1012
1013 dp->ce1 = dp->center->east_west-w2;
1014 dp->ce2 = dp->center->east_west+w2;
1015 dp->cn1 = dp->center->north_south-h2;
1016 dp->cn2 = dp->center->north_south+h2;
1017 } else if ( dp->lat_lon ) {
1018 VikCoord upperleft, bottomright;
1019 /* quick & dirty calculation; really want to check all corners due to lat/lon smaller at top in northern hemisphere */
1020 /* this also DOESN'T WORK if you are crossing 180/-180 lon. I don't plan to in the near future... */
1021 vik_viewport_screen_to_coord ( vp, -500, -500, &upperleft );
1022 vik_viewport_screen_to_coord ( vp, dp->width+500, dp->height+500, &bottomright );
1023 dp->ce1 = upperleft.east_west;
1024 dp->ce2 = bottomright.east_west;
1025 dp->cn1 = bottomright.north_south;
1026 dp->cn2 = upperleft.north_south;
1027 }
1028
1029 dp->track_gc_iter = 0;
1030}
1031
1032static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 )
1033{
1034 static gdouble rv = 0;
1035 if ( tp1->has_timestamp && tp2->has_timestamp )
1036 {
1037 rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) )
1038 / (tp1->timestamp - tp2->timestamp) ) - vtl->velocity_min;
1039
1040 if ( rv < 0 )
1041 return VIK_TRW_LAYER_TRACK_GC_MIN;
1042 else if ( vtl->velocity_min >= vtl->velocity_max )
1043 return VIK_TRW_LAYER_TRACK_GC_MAX;
1044
1045 rv *= (VIK_TRW_LAYER_TRACK_GC_RATES / (vtl->velocity_max - vtl->velocity_min));
1046
1047 if ( rv >= VIK_TRW_LAYER_TRACK_GC_MAX )
1048 return VIK_TRW_LAYER_TRACK_GC_MAX;
1049 return (gint) rv;
1050 }
1051 else
1052 return VIK_TRW_LAYER_TRACK_GC_BLACK;
1053}
1054
1055void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
1056{
1057 vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y );
1058 vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 );
1059 vik_viewport_draw_line ( vvp, gc, x+5, y+5, x-5, y-5 );
1060 vik_viewport_draw_line ( vvp, gc, x+5, y-5, x-5, y+5 );
1061}
1062
1063static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct DrawingParams *dp, gboolean drawing_white_background )
1064{
1065 /* TODO: this function is a mess, get rid of any redundancy */
1066 GList *list = track->trackpoints;
8e9c992d 1067 GdkGC *main_gc;
50a14534
EB
1068 gboolean useoldvals = TRUE;
1069
1070 gboolean drawpoints;
b42a25ba
EB
1071 gboolean drawstops;
1072 gboolean drawelevation;
941aa6e9 1073 gdouble min_alt, max_alt, alt_diff = 0;
50a14534
EB
1074
1075 const guint8 tp_size_reg = 2;
1076 const guint8 tp_size_cur = 4;
1077 guint8 tp_size;
1078
b42a25ba
EB
1079 if ( dp->vtl->drawelevation )
1080 {
1081 /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
1082 if ( ( drawelevation = vik_track_get_minmax_alt ( track, &min_alt, &max_alt ) ) )
1083 alt_diff = max_alt - min_alt;
1084 }
1085
50a14534
EB
1086 if ( ! track->visible )
1087 return;
1088
1089 /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
1090 if ( dp->vtl->bg_line_thickness && !drawing_white_background )
1091 trw_layer_draw_track ( name, track, dp, TRUE );
1092
1093 if ( drawing_white_background )
b42a25ba
EB
1094 drawpoints = drawstops = FALSE;
1095 else {
50a14534 1096 drawpoints = dp->vtl->drawpoints;
b42a25ba
EB
1097 drawstops = dp->vtl->drawstops;
1098 }
50a14534 1099
a5dcfdb7 1100 /* Current track - used for creation */
8e9c992d
EB
1101 if ( track == dp->vtl->current_track )
1102 main_gc = dp->vtl->current_track_gc;
a5dcfdb7
RN
1103 else {
1104 if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1105 /* Draw all tracks of the layer in special colour */
1106 /* if track is member of selected layer or is the current selected track
1107 then draw in the highlight colour.
1108 NB this supercedes the drawmode */
1109 if ( dp->vtl && ( ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ||
1110 ( dp->vtl->tracks == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ||
1111 track == vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) {
480fb7e1 1112 main_gc = vik_viewport_get_gc_highlight (dp->vp);
a5dcfdb7
RN
1113 }
1114 else {
1115 if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
1116 dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK;
1117
1118 main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
1119 }
1120 }
1121 else {
1122 if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
1123 dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK;
1124
1125 main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
1126 }
1127 }
8e9c992d 1128
50a14534
EB
1129 if (list) {
1130 int x, y, oldx, oldy;
1131 VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
1132
1133 tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
1134
1135 vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1136
1137 if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC )
1138 {
1139 GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} };
8e9c992d 1140 vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 );
50a14534
EB
1141 }
1142
1143 oldx = x;
1144 oldy = y;
1145
50a14534
EB
1146 while ((list = g_list_next(list)))
1147 {
1148 tp = VIK_TRACKPOINT(list->data);
1149 tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
1150
1151 /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
1152 if ( (!dp->one_zone && !dp->lat_lon) || /* UTM & zones; do everything */
1153 ( ((!dp->one_zone) || tp->coord.utm_zone == dp->center->utm_zone) && /* only check zones if UTM & one_zone */
1154 tp->coord.east_west < dp->ce2 && tp->coord.east_west > dp->ce1 && /* both UTM and lat lon */
1155 tp->coord.north_south > dp->cn1 && tp->coord.north_south < dp->cn2 ) )
1156 {
1157 vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1158
1159 if ( drawpoints && ! drawing_white_background )
1160 {
1161 if ( list->next ) {
8e9c992d 1162 vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
50a14534
EB
1163
1164 /* stops */
b42a25ba 1165 if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
50a14534
EB
1166 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 );
1167 }
1168 else
8e9c992d 1169 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 );
50a14534
EB
1170 }
1171
1172 if ((!tp->newsegment) && (dp->vtl->drawlines))
1173 {
1174 VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
1175
1176 /* UTM only: zone check */
1177 if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
8e9c992d 1178 draw_utm_skip_insignia ( dp->vp, main_gc, x, y);
50a14534 1179
f66c1d0c 1180 if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
50a14534 1181 dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
f66c1d0c
RN
1182 main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
1183 }
50a14534
EB
1184
1185 if (!useoldvals)
1186 vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
1187
8c4f1350 1188 if ( drawing_white_background ) {
50a14534 1189 vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
8c4f1350
EB
1190 }
1191 else {
8c4f1350 1192
8e9c992d 1193 vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
b42a25ba
EB
1194 if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
1195 GdkPoint tmp[4];
1196 #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
1197 if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
1198 tmp[0].x = oldx;
1199 tmp[0].y = oldy;
1200 tmp[1].x = oldx;
1201 tmp[1].y = oldy-FIXALTITUDE(list->data);
1202 tmp[2].x = x;
1203 tmp[2].y = y-FIXALTITUDE(list->next->data);
1204 tmp[3].x = x;
1205 tmp[3].y = y;
1206
1207 GdkGC *tmp_gc;
1208 if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
1209 tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
1210 else
1211 tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
1212 vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
1213 }
8e9c992d 1214 vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
8c4f1350
EB
1215 }
1216 }
50a14534
EB
1217 }
1218
1219 oldx = x;
1220 oldy = y;
1221 useoldvals = TRUE;
1222 }
1223 else {
1224 if (useoldvals && dp->vtl->drawlines && (!tp->newsegment))
1225 {
1226 VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
1227 if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
1228 {
1229 vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
f66c1d0c 1230 if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
50a14534 1231 dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
f66c1d0c
RN
1232 main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
1233 }
50a14534
EB
1234
1235 if ( drawing_white_background )
1236 vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
1237 else
8e9c992d 1238 vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
50a14534
EB
1239 }
1240 else
1241 {
1242 vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
8e9c992d 1243 draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
50a14534
EB
1244 }
1245 }
1246 useoldvals = FALSE;
1247 }
1248 }
1249 }
1250 if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
480fb7e1 1251 if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC )
50a14534
EB
1252 dp->track_gc_iter = 0;
1253}
1254
1255/* the only reason this exists is so that trw_layer_draw_track can first call itself to draw the white track background */
1256static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp )
1257{
1258 trw_layer_draw_track ( name, track, dp, FALSE );
1259}
1260
1261static void cached_pixbuf_free ( CachedPixbuf *cp )
1262{
1263 g_object_unref ( G_OBJECT(cp->pixbuf) );
1264 g_free ( cp->image );
1265}
1266
1267static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name )
1268{
1269 return strcmp ( cp->image, name );
1270}
1271
1272static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp )
1273{
1274 if ( wp->visible )
51f0884d 1275 if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) &&
50a14534
EB
1276 wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 &&
1277 wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
1278 {
1279 gint x, y;
a7f9c01e 1280 GdkPixbuf *sym = NULL;
50a14534
EB
1281 vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y );
1282
1283 /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
1284
1285 if ( wp->image && dp->vtl->drawimages )
1286 {
1287 GdkPixbuf *pixbuf = NULL;
1288 GList *l;
1289
1290 if ( dp->vtl->image_alpha == 0)
1291 return;
1292
1293 l = g_list_find_custom ( dp->vtl->image_cache->head, wp->image, (GCompareFunc) cached_pixbuf_cmp );
1294 if ( l )
1295 pixbuf = ((CachedPixbuf *) l->data)->pixbuf;
1296 else
1297 {
1298 gchar *image = wp->image;
1299 GdkPixbuf *regularthumb = a_thumbnails_get ( wp->image );
1300 if ( ! regularthumb )
1301 {
1302 regularthumb = a_thumbnails_get_default (); /* cache one 'not yet loaded' for all thumbs not loaded */
1303 image = "\x12\x00"; /* this shouldn't occur naturally. */
1304 }
1305 if ( regularthumb )
1306 {
1307 CachedPixbuf *cp = NULL;
1308 cp = g_malloc ( sizeof ( CachedPixbuf ) );
1309 if ( dp->vtl->image_size == 128 )
1310 cp->pixbuf = regularthumb;
1311 else
1312 {
1313 cp->pixbuf = a_thumbnails_scale_pixbuf(regularthumb, dp->vtl->image_size, dp->vtl->image_size);
1314 g_assert ( cp->pixbuf );
1315 g_object_unref ( G_OBJECT(regularthumb) );
1316 }
1317 cp->image = g_strdup ( image );
1318
1319 /* needed so 'click picture' tool knows how big the pic is; we don't
1320 * store it in cp because they may have been freed already. */
1321 wp->image_width = gdk_pixbuf_get_width ( cp->pixbuf );
1322 wp->image_height = gdk_pixbuf_get_height ( cp->pixbuf );
1323
1324 g_queue_push_head ( dp->vtl->image_cache, cp );
1325 if ( dp->vtl->image_cache->length > dp->vtl->image_cache_size )
1326 cached_pixbuf_free ( g_queue_pop_tail ( dp->vtl->image_cache ) );
1327
1328 pixbuf = cp->pixbuf;
1329 }
1330 else
1331 {
1332 pixbuf = a_thumbnails_get_default (); /* thumbnail not yet loaded */
1333 }
1334 }
1335 if ( pixbuf )
1336 {
1337 gint w, h;
1338 w = gdk_pixbuf_get_width ( pixbuf );
1339 h = gdk_pixbuf_get_height ( pixbuf );
1340
1341 if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
1342 {
a5dcfdb7
RN
1343 if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1344 if ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
1345 dp->vtl->waypoints == vik_window_get_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
1346 wp == vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) {
1347 // Highlighted - so draw a little border around the chosen one
1348 // single line seems a little weak so draw 2 of them
480fb7e1 1349 vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
a5dcfdb7 1350 x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 );
480fb7e1 1351 vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
a5dcfdb7
RN
1352 x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
1353 }
1354 }
50a14534
EB
1355 if ( dp->vtl->image_alpha == 255 )
1356 vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
1357 else
1358 vik_viewport_draw_pixbuf_with_alpha ( dp->vp, pixbuf, dp->vtl->image_alpha, 0, 0, x - (w/2), y - (h/2), w, h );
1359 }
1360 return; /* if failed to draw picture, default to drawing regular waypoint (below) */
1361 }
1362 }
1363
1364 /* DRAW ACTUAL DOT */
ea3933fc 1365 if ( dp->vtl->wp_draw_symbols && wp->symbol && (sym = a_get_wp_sym(wp->symbol)) ) {
acaf7113
AF
1366 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 );
1367 }
1368 else if ( wp == dp->vtl->current_wp ) {
50a14534
EB
1369 switch ( dp->vtl->wp_symbol ) {
1370 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;
1371 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;
1372 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;
1373 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 );
1374 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 );
1375 }
1376 }
1377 else {
1378 switch ( dp->vtl->wp_symbol ) {
1379 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;
1380 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;
1381 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;
1382 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 );
1383 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;
1384 }
1385 }
1386
1387 if ( dp->vtl->drawlabels )
1388 {
1389 /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
a7f9c01e 1390 gint label_x, label_y;
50a14534
EB
1391 gint width, height;
1392 pango_layout_set_text ( dp->vtl->wplabellayout, name, -1 );
1393 pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
a7f9c01e
QT
1394 label_x = x - width/2;
1395 if (sym)
1396 label_y = y - height - 2 - gdk_pixbuf_get_height(sym)/2;
1397 else
1398 label_y = y - dp->vtl->wp_size - height - 2;
1399
480fb7e1 1400 /* if highlight mode on, then draw background text in highlight colour */
a5dcfdb7
RN
1401 if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1402 if ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
1403 dp->vtl->waypoints == vik_window_get_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ||
1404 wp == vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) )
480fb7e1 1405 vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2);
a5dcfdb7
RN
1406 else
1407 vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
1408 }
1409 else {
1410 vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
1411 }
a7f9c01e 1412 vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout );
50a14534
EB
1413 }
1414 }
1415}
1416
1417void vik_trw_layer_draw ( VikTrwLayer *l, gpointer data )
1418{
1419 static struct DrawingParams dp;
1420 g_assert ( l != NULL );
1421
1422 init_drawing_params ( &dp, VIK_VIEWPORT(data) );
1423 dp.vtl = l;
1424
1425 if ( l->tracks_visible )
1426 g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp );
1427
1428 if (l->waypoints_visible)
1429 g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint, &dp );
1430}
1431
1432static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
1433{
1434 int i;
1435 if ( vtl->track_bg_gc )
1436 {
1437 g_object_unref ( vtl->track_bg_gc );
1438 vtl->track_bg_gc = NULL;
1439 }
8e9c992d
EB
1440 if ( vtl->current_track_gc )
1441 {
1442 g_object_unref ( vtl->current_track_gc );
1443 vtl->current_track_gc = NULL;
1444 }
50a14534
EB
1445
1446 if ( ! vtl->track_gc )
1447 return;
1448 for ( i = vtl->track_gc->len - 1; i >= 0; i-- )
1449 g_object_unref ( g_array_index ( vtl->track_gc, GObject *, i ) );
1450 g_array_free ( vtl->track_gc, TRUE );
1451 vtl->track_gc = NULL;
1452}
1453
1454static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
1455{
1456 GdkGC *gc[ VIK_TRW_LAYER_TRACK_GC ];
1457 gint width = vtl->line_thickness;
1458
1459 if ( vtl->track_gc )
1460 trw_layer_free_track_gcs ( vtl );
1461
1462 if ( vtl->track_bg_gc )
1463 g_object_unref ( vtl->track_bg_gc );
1464 vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
1465
8e9c992d
EB
1466 if ( vtl->current_track_gc )
1467 g_object_unref ( vtl->current_track_gc );
1468 vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
1469 gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
1470
50a14534
EB
1471 vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
1472
1473 gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
1474
1475 gc[1] = vik_viewport_new_gc ( vp, "#0a8742", width );
1476 gc[2] = vik_viewport_new_gc ( vp, "#0a8783", width );
1477 gc[3] = vik_viewport_new_gc ( vp, "#0a4d87", width );
1478 gc[4] = vik_viewport_new_gc ( vp, "#05469f", width );
1479 gc[5] = vik_viewport_new_gc ( vp, "#1b059f", width );
1480 gc[6] = vik_viewport_new_gc ( vp, "#2d059f", width );
1481 gc[7] = vik_viewport_new_gc ( vp, "#4a059f", width );
1482 gc[8] = vik_viewport_new_gc ( vp, "#84059f", width );
1483 gc[9] = vik_viewport_new_gc ( vp, "#96059f", width );
1484 gc[10] = vik_viewport_new_gc ( vp, "#f22ef2", width );
1485
16b01243 1486 gc[11] = vik_viewport_new_gc ( vp, "#874200", width ); /* above range */
50a14534
EB
1487
1488 gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */
1489
1490 g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
1491}
1492
1493VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
1494{
1495 VikTrwLayer *rv = vik_trw_layer_new ( 0 );
1496 PangoFontDescription *pfd;
1497 rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
1498 pfd = pango_font_description_from_string (WAYPOINT_FONT);
1499 pango_layout_set_font_description (rv->wplabellayout, pfd);
1500 /* freeing PangoFontDescription, cause it has been copied by prev. call */
1501 pango_font_description_free (pfd);
1502
1503 vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
1504
1505 trw_layer_new_track_gcs ( rv, vp );
1506
1507 rv->waypoint_gc = vik_viewport_new_gc ( vp, "#000000", 2 );
1508 rv->waypoint_text_gc = vik_viewport_new_gc ( vp, "#FFFFFF", 1 );
1509 rv->waypoint_bg_gc = vik_viewport_new_gc ( vp, "#8383C4", 1 );
1510 gdk_gc_set_function ( rv->waypoint_bg_gc, GDK_AND );
1511
1512 rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
1513
1514 rv->has_verified_thumbnails = FALSE;
1515 rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
1516 rv->wp_size = 4;
ea3933fc 1517 rv->wp_draw_symbols = TRUE;
50a14534
EB
1518
1519 rv->coord_mode = vik_viewport_get_coord_mode ( vp );
1520
20c7a3a0
QT
1521 rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection;
1522
50a14534
EB
1523 return rv;
1524}
1525
6bb72350 1526static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[5] )
50a14534
EB
1527{
1528 GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
1529
1530#ifdef VIK_CONFIG_ALPHABETIZED_TRW
dc2c040e 1531 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
50a14534 1532#else
1d45914c 1533 vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
50a14534
EB
1534#endif
1535
1536 *new_iter = *((GtkTreeIter *) pass_along[1]);
1537 g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, name, new_iter );
1538
1539 if ( ! track->visible )
1540 vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
1541}
1542
6bb72350 1543static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[5] )
50a14534
EB
1544{
1545 GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
1546#ifdef VIK_CONFIG_ALPHABETIZED_TRW
dc2c040e 1547 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
50a14534 1548#else
1d45914c 1549 vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE );
50a14534
EB
1550#endif
1551
1552 *new_iter = *((GtkTreeIter *) pass_along[1]);
1553 g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, name, new_iter );
1554
1555 if ( ! wp->visible )
1556 vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
1557}
1558
1559
1560void vik_trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
1561{
1562 GtkTreeIter iter2;
1563 gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, (gpointer) VIK_TRW_LAYER_SUBLAYER_TRACK };
1564
1565#ifdef VIK_CONFIG_ALPHABETIZED_TRW
4c77d5e0 1566 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
50a14534 1567#else
4c77d5e0 1568 vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
50a14534
EB
1569#endif
1570 if ( ! vtl->tracks_visible )
1571 vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), FALSE );
1572
1573 g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
1574
1575#ifdef VIK_CONFIG_ALPHABETIZED_TRW
4c77d5e0 1576 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
50a14534 1577#else
4c77d5e0 1578 vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
50a14534
EB
1579#endif
1580
1581 if ( ! vtl->waypoints_visible )
1582 vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), FALSE );
1583
1584 pass_along[0] = &(vtl->waypoints_iter);
1585 pass_along[4] = (gpointer) VIK_TRW_LAYER_SUBLAYER_WAYPOINT;
1586
1587 g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
1588
1589}
1590
1591gboolean vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
1592{
1593 switch ( subtype )
1594 {
1595 case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1);
1596 case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1);
1597 case VIK_TRW_LAYER_SUBLAYER_TRACK:
1598 {
1599 VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer );
1600 if (t)
1601 return (t->visible ^= 1);
1602 else
1603 return TRUE;
1604 }
1605 case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
1606 {
1607 VikWaypoint *t = g_hash_table_lookup ( l->waypoints, sublayer );
1608 if (t)
1609 return (t->visible ^= 1);
1610 else
1611 return TRUE;
1612 }
1613 }
1614 return TRUE;
1615}
1616
cb89c5a5
RN
1617// Structure to hold multiple track information for a layer
1618typedef struct {
1619 gdouble length;
1620 time_t start_time;
1621 time_t end_time;
1622 gint duration;
1623} tooltip_tracks;
1624
1625/*
1626 * Build up layer multiple track information via updating the tooltip_tracks structure
1627 */
1628static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_tracks *tt )
1629{
1630 tt->length = tt->length + vik_track_get_length (tr);
1631
1632 // Ensure times are available
1633 if ( tr->trackpoints &&
1634 VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp &&
1635 VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) {
1636
1637 time_t t1, t2;
1638 t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
1639 t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
1640
1641 // Assume never actually have a track with a time of 0 (1st Jan 1970)
1642 // Hence initialize to the first 'proper' value
1643 if ( tt->start_time == 0 )
1644 tt->start_time = t1;
1645 if ( tt->end_time == 0 )
1646 tt->end_time = t2;
1647
1648 // Update find the earliest / last times
1649 if ( t1 < tt->start_time )
1650 tt->start_time = t1;
1651 if ( t2 > tt->end_time )
1652 tt->end_time = t2;
1653
1654 // Keep track of total time
1655 // there maybe gaps within a track (eg segments)
1656 // but this should be generally good enough for a simple indicator
1657 tt->duration = tt->duration + (int)(t2-t1);
1658 }
1659}
1660
1661/*
1662 * Generate tooltip text for the layer.
1663 * This is relatively complicated as it considers information for
1664 * no tracks, a single track or multiple tracks
1665 * (which may or may not have timing information)
1666 */
1667static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
1668{
1669 gchar tbuf1[32];
1670 gchar tbuf2[64];
1671 gchar tbuf3[64];
1672 gchar tbuf4[10];
1673 tbuf1[0] = '\0';
1674 tbuf2[0] = '\0';
1675 tbuf3[0] = '\0';
1676 tbuf4[0] = '\0';
1677
1678 static gchar tmp_buf[128];
1679 tmp_buf[0] = '\0';
1680
1681 // For compact date format I'm using '%x' [The preferred date representation for the current locale without the time.]
1682
1683 // Safety check - I think these should always be valid
1684 if ( vtl->tracks && vtl->waypoints ) {
1685 tooltip_tracks tt = { 0.0, 0, 0 };
1686 g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_tooltip, &tt );
1687
1688 GDate* gdate_start = g_date_new ();
1689 g_date_set_time_t (gdate_start, tt.start_time);
1690
1691 GDate* gdate_end = g_date_new ();
1692 g_date_set_time_t (gdate_end, tt.end_time);
1693
1694 if ( g_date_compare (gdate_start, gdate_end) ) {
1695 // Dates differ so print range on separate line
1696 g_date_strftime (tbuf1, sizeof(tbuf1), "%x", gdate_start);
1697 g_date_strftime (tbuf2, sizeof(tbuf2), "%x", gdate_end);
1698 g_snprintf (tbuf3, sizeof(tbuf3), "%s to %s\n", tbuf1, tbuf2);
1699 }
1700 else {
1701 // Same date so just show it and keep rest of text on the same line - provided it's a valid time!
1702 if ( tt.start_time != 0 )
1703 g_date_strftime (tbuf3, sizeof(tbuf3), "%x: ", gdate_start);
1704 }
1705
1706 tbuf2[0] = '\0';
1707 if ( tt.length > 0.0 ) {
1708 gdouble len_in_units;
1709
1710 // Setup info dependent on distance units
1711 if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) {
1712 g_snprintf (tbuf4, sizeof(tbuf4), "miles");
a492ff13 1713 len_in_units = VIK_METERS_TO_MILES(tt.length);
cb89c5a5
RN
1714 }
1715 else {
1716 g_snprintf (tbuf4, sizeof(tbuf4), "kms");
1717 len_in_units = tt.length/1000.0;
1718 }
1719
1720 // Timing information if available
1721 tbuf1[0] = '\0';
1722 if ( tt.duration > 0 ) {
1723 g_snprintf (tbuf1, sizeof(tbuf1),
1724 _(" in %d:%02d hrs:mins"),
1725 (int)round(tt.duration/3600), (int)round((tt.duration/60)%60));
1726 }
1727 g_snprintf (tbuf2, sizeof(tbuf2),
1728 _("\n%sTotal Length %.1f %s%s"),
1729 tbuf3, len_in_units, tbuf4, tbuf1);
1730 }
1731
1732 // Put together all the elements to form compact tooltip text
1733 g_snprintf (tmp_buf, sizeof(tmp_buf),
1734 _("Tracks: %d - Waypoints: %d%s"),
1735 g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), tbuf2);
1736
1737 g_date_free (gdate_start);
1738 g_date_free (gdate_end);
1739
1740 }
1741
1742 return tmp_buf;
1743}
1744
c7060c4e
RN
1745static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer )
1746{
1747 switch ( subtype )
1748 {
1749 case VIK_TRW_LAYER_SUBLAYER_TRACKS: return NULL;
1750 case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return NULL;
1751 case VIK_TRW_LAYER_SUBLAYER_TRACK:
1752 {
1753 VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer );
1754 if ( tr ) {
1755 // Could be a better way of handling strings - but this works...
1756 gchar time_buf1[20];
1757 gchar time_buf2[20];
1758 time_buf1[0] = '\0';
1759 time_buf2[0] = '\0';
1760 static gchar tmp_buf[100];
1761 // Compact info: Short date eg (11/20/99), duration and length
1762 // Hopefully these are the things that are most useful and so promoted into the tooltip
1763 if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp ) {
1764 // %x The preferred date representation for the current locale without the time.
1765 strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(VIK_TRACKPOINT(tr->trackpoints->data)->timestamp)));
1766 if ( VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) {
1767 gint dur = ( (VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp) - (VIK_TRACKPOINT(tr->trackpoints->data)->timestamp) );
1768 if ( dur > 0 )
cb89c5a5 1769 g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
c7060c4e
RN
1770 }
1771 }
1772 // Get length and consider the appropriate distance units
1773 gdouble tr_len = vik_track_get_length(tr);
1774 vik_units_distance_t dist_units = a_vik_get_units_distance ();
1775 switch (dist_units) {
1776 case VIK_UNITS_DISTANCE_KILOMETRES:
1777 g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f km %s"), time_buf1, tr_len/1000.0, time_buf2);
1778 break;
1779 case VIK_UNITS_DISTANCE_MILES:
a492ff13 1780 g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, VIK_METERS_TO_MILES(tr_len), time_buf2);
c7060c4e
RN
1781 break;
1782 default:
1783 break;
1784 }
1785 return tmp_buf;
1786 }
1787 }
1788 break;
1789 case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
1790 {
1791 VikWaypoint *w = g_hash_table_lookup ( l->waypoints, sublayer );
1792 // NB It's OK to return NULL
1793 return w->comment;
1794 }
1795 break;
1796 default: break;
1797 }
1798 return NULL;
1799}
1800
a5dcfdb7
RN
1801/**
1802 * General layer selection function, find out which bit is selected and take appropriate action
1803 */
1804gboolean vik_trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp )
1805{
c95d6b00
RN
1806 // Reset
1807 l->current_wp = NULL;
1808 l->current_wp_name = NULL;
1809 trw_layer_cancel_current_tp ( l, FALSE );
1810
a5dcfdb7
RN
1811 switch ( type )
1812 {
1813 case VIK_TREEVIEW_TYPE_LAYER:
1814 {
1815 vik_window_set_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l );
1816 /* Mark for redraw */
1817 return TRUE;
1818 }
1819 break;
1820
1821 case VIK_TREEVIEW_TYPE_SUBLAYER:
1822 {
1823 switch ( subtype )
1824 {
1825 case VIK_TRW_LAYER_SUBLAYER_TRACKS:
1826 {
113c74f6 1827 vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->tracks, l );
a5dcfdb7
RN
1828 /* Mark for redraw */
1829 return TRUE;
1830 }
1831 break;
1832 case VIK_TRW_LAYER_SUBLAYER_TRACK:
1833 {
43f2e1da 1834 vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), g_hash_table_lookup ( l->tracks, sublayer ), l, sublayer );
a5dcfdb7
RN
1835 /* Mark for redraw */
1836 return TRUE;
1837 }
1838 break;
1839 case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
1840 {
113c74f6 1841 vik_window_set_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->waypoints, l );
a5dcfdb7
RN
1842 /* Mark for redraw */
1843 return TRUE;
1844 }
1845 break;
1846 case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
1847 {
43f2e1da 1848 vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), g_hash_table_lookup ( l->waypoints, sublayer ), l, sublayer );
a5dcfdb7
RN
1849 /* Mark for redraw */
1850 return TRUE;
1851 }
1852 break;
1853 default:
1854 {
1855 return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
1856 }
1857 break;
1858 }
1859 return FALSE;
1860 }
1861 break;
1862
1863 default:
1864 return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
1865 break;
1866 }
1867}
c7060c4e 1868
50a14534
EB
1869GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
1870{
1871 return l->tracks;
1872}
1873
1874GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l )
1875{
1876 return l->waypoints;
1877}
1878
1879static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] )
1880{
1881 static VikCoord fixme;
1882 vik_coord_copy_convert ( &(w->coord), VIK_COORD_LATLON, &fixme );
1883 if ( VIK_LATLON(&fixme)->lat > maxmin[0].lat || maxmin[0].lat == 0.0 )
1884 maxmin[0].lat = VIK_LATLON(&fixme)->lat;
1885 if ( VIK_LATLON(&fixme)->lat < maxmin[1].lat || maxmin[1].lat == 0.0 )
1886 maxmin[1].lat = VIK_LATLON(&fixme)->lat;
1887 if ( VIK_LATLON(&fixme)->lon > maxmin[0].lon || maxmin[0].lon == 0.0 )
1888 maxmin[0].lon = VIK_LATLON(&fixme)->lon;
1889 if ( VIK_LATLON(&fixme)->lon < maxmin[1].lon || maxmin[1].lon == 0.0 )
1890 maxmin[1].lon = VIK_LATLON(&fixme)->lon;
1891}
1892
1893static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] )
1894{
1895 GList *tr = *t;
1896 static VikCoord fixme;
1897
1898 while ( tr )
1899 {
1900 vik_coord_copy_convert ( &(VIK_TRACKPOINT(tr->data)->coord), VIK_COORD_LATLON, &fixme );
1901 if ( VIK_LATLON(&fixme)->lat > maxmin[0].lat || maxmin[0].lat == 0.0 )
1902 maxmin[0].lat = VIK_LATLON(&fixme)->lat;
1903 if ( VIK_LATLON(&fixme)->lat < maxmin[1].lat || maxmin[1].lat == 0.0 )
1904 maxmin[1].lat = VIK_LATLON(&fixme)->lat;
1905 if ( VIK_LATLON(&fixme)->lon > maxmin[0].lon || maxmin[0].lon == 0.0 )
1906 maxmin[0].lon = VIK_LATLON(&fixme)->lon;
1907 if ( VIK_LATLON(&fixme)->lon < maxmin[1].lon || maxmin[1].lon == 0.0 )
1908 maxmin[1].lon = VIK_LATLON(&fixme)->lon;
1909 tr = tr->next;
1910 }
1911}
1912
165a4fa9
HR
1913static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2])
1914{
1915 struct LatLon wpt_maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
1916 struct LatLon trk_maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
1917
1918 g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, wpt_maxmin );
1919 g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, trk_maxmin );
1920 if ((wpt_maxmin[0].lat != 0.0 && wpt_maxmin[0].lat > trk_maxmin[0].lat) || trk_maxmin[0].lat == 0.0) {
1921 maxmin[0].lat = wpt_maxmin[0].lat;
1922 }
1923 else {
1924 maxmin[0].lat = trk_maxmin[0].lat;
1925 }
1926 if ((wpt_maxmin[0].lon != 0.0 && wpt_maxmin[0].lon > trk_maxmin[0].lon) || trk_maxmin[0].lon == 0.0) {
1927 maxmin[0].lon = wpt_maxmin[0].lon;
1928 }
1929 else {
1930 maxmin[0].lon = trk_maxmin[0].lon;
1931 }
1932 if ((wpt_maxmin[1].lat != 0.0 && wpt_maxmin[1].lat < trk_maxmin[1].lat) || trk_maxmin[1].lat == 0.0) {
1933 maxmin[1].lat = wpt_maxmin[1].lat;
1934 }
1935 else {
1936 maxmin[1].lat = trk_maxmin[1].lat;
1937 }
1938 if ((wpt_maxmin[1].lon != 0.0 && wpt_maxmin[1].lon < trk_maxmin[1].lon) || trk_maxmin[1].lon == 0.0) {
1939 maxmin[1].lon = wpt_maxmin[1].lon;
1940 }
1941 else {
1942 maxmin[1].lon = trk_maxmin[1].lon;
1943 }
1944}
50a14534
EB
1945
1946gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
1947{
1948 /* 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... */
1949 struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
165a4fa9 1950 trw_layer_find_maxmin (vtl, maxmin);
50a14534
EB
1951 if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
1952 return FALSE;
1953 else
1954 {
1955 struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
1956 vik_coord_load_from_latlon ( dest, vtl->coord_mode, &average );
1957 return TRUE;
1958 }
1959}
1960
1961static void trw_layer_centerize ( gpointer layer_and_vlp[2] )
1962{
1963 VikCoord coord;
1964 if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
6bb72350 1965 goto_coord ( layer_and_vlp[1], NULL, NULL, &coord );
50a14534 1966 else
4c77d5e0 1967 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
50a14534
EB
1968}
1969
c5638216
RN
1970static void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
1971{
1972 /* First set the center [in case previously viewing from elsewhere] */
1973 /* Then loop through zoom levels until provided positions are in view */
1974 /* This method is not particularly fast - but should work well enough */
1975 struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
1976 VikCoord coord;
1977 vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
1978 vik_viewport_set_center_coord ( vvp, &coord );
1979
1980 /* Convert into definite 'smallest' and 'largest' positions */
1981 struct LatLon minmin;
1982 if ( maxmin[0].lat < maxmin[1].lat )
1983 minmin.lat = maxmin[0].lat;
1984 else
1985 minmin.lat = maxmin[1].lat;
1986
1987 struct LatLon maxmax;
1988 if ( maxmin[0].lon > maxmin[1].lon )
1989 maxmax.lon = maxmin[0].lon;
1990 else
1991 maxmax.lon = maxmin[1].lon;
1992
1993 /* Never zoom in too far - generally not that useful, as too close ! */
1994 /* Always recalculate the 'best' zoom level */
1995 gdouble zoom = 1.0;
1996 vik_viewport_set_zoom ( vvp, zoom );
1997
1998 gdouble min_lat, max_lat, min_lon, max_lon;
1999 /* Should only be a maximum of about 18 iterations from min to max zoom levels */
2000 while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
2001 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2002 /* NB I think the logic used in this test to determine if the bounds is within view
2003 fails if track goes across 180 degrees longitude.
2004 Hopefully that situation is not too common...
2005 Mind you viking doesn't really do edge locations to well anyway */
2006 if ( min_lat < minmin.lat &&
2007 max_lat > minmin.lat &&
2008 min_lon < maxmax.lon &&
2009 max_lon > maxmax.lon )
2010 /* Found within zoom level */
2011 break;
2012
2013 /* Try next */
2014 zoom = zoom * 2;
2015 vik_viewport_set_zoom ( vvp, zoom );
2016 }
2017}
2018
2019gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp )
2020{
2021 /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. */
2022 struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2023 trw_layer_find_maxmin (vtl, maxmin);
2024 if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
2025 return FALSE;
2026 else {
2027 trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin );
2028 return TRUE;
2029 }
2030}
2031
5a10c240
RN
2032static void trw_layer_auto_view ( gpointer layer_and_vlp[2] )
2033{
2034 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])) ) ) {
2035 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
2036 }
2037 else
2038 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
2039}
2040
f7f8a0a6 2041static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, const gchar* trackname, guint file_type )
50a14534
EB
2042{
2043 GtkWidget *file_selector;
2044 const gchar *fn;
2045 gboolean failed = FALSE;
7f6757c4
RN
2046 file_selector = gtk_file_chooser_dialog_new (title,
2047 NULL,
2048 GTK_FILE_CHOOSER_ACTION_SAVE,
2049 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2050 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2051 NULL);
2052 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name);
6e4a49aa
MA
2053
2054 while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT )
50a14534 2055 {
6e4a49aa 2056 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) );
45acf79e 2057 if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
2058 {
2059 gtk_widget_hide ( file_selector );
f7f8a0a6 2060 failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname);
50a14534
EB
2061 break;
2062 }
2063 else
2064 {
d91e5f2b 2065 if ( a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
50a14534
EB
2066 {
2067 gtk_widget_hide ( file_selector );
f7f8a0a6 2068 failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname);
50a14534
EB
2069 break;
2070 }
2071 }
2072 }
2073 gtk_widget_destroy ( file_selector );
2074 if ( failed )
4c77d5e0 2075 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The filename you requested could not be opened for writing.") );
50a14534
EB
2076}
2077
2078static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] )
2079{
f7f8a0a6 2080 trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSPOINT );
50a14534
EB
2081}
2082
2083static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] )
2084{
f7f8a0a6 2085 trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSMAPPER );
50a14534
EB
2086}
2087
561e6ad0
EB
2088static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
2089{
f7f8a0a6 2090 trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPX );
7f6757c4
RN
2091}
2092
ba9d0a00
RN
2093static void trw_layer_export_kml ( gpointer layer_and_vlp[2] )
2094{
2095 /* Auto append '.kml' to the name (providing it's not already there) for the default filename */
2096 gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
2097 if ( ! check_file_ext ( auto_save_name, ".kml" ) )
2098 auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL );
2099
2100 trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
2101
2102 g_free ( auto_save_name );
2103}
2104
7f6757c4
RN
2105static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
2106{
7f6757c4
RN
2107 gpointer layer_and_vlp[2];
2108 layer_and_vlp[0] = pass_along[0];
2109 layer_and_vlp[1] = pass_along[1];
2110
2111 /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
2112 gchar *auto_save_name = g_strdup ( pass_along[3] );
2113 if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
2114 auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
2115
f7f8a0a6 2116 trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, pass_along[3], FILE_TYPE_GPX );
7f6757c4
RN
2117
2118 g_free ( auto_save_name );
561e6ad0
EB
2119}
2120
50a14534
EB
2121static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
2122{
2123 GHashTable *wps = vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp[0]) );
a77d62d8 2124 GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
50a14534
EB
2125 VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
2126 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2127 GTK_STOCK_CANCEL,
2128 GTK_RESPONSE_REJECT,
2129 GTK_STOCK_OK,
2130 GTK_RESPONSE_ACCEPT,
2131 NULL);
2132
2133 GtkWidget *label, *entry;
4c77d5e0 2134 label = gtk_label_new(_("Waypoint Name:"));
50a14534
EB
2135 entry = gtk_entry_new();
2136
2137 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), label, FALSE, FALSE, 0);
2138 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), entry, FALSE, FALSE, 0);
2139 gtk_widget_show_all ( label );
2140 gtk_widget_show_all ( entry );
2141
7ea3cb11
RN
2142 gtk_dialog_set_default_response ( GTK_DIALOG(dia), GTK_RESPONSE_ACCEPT );
2143
50a14534
EB
2144 while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
2145 {
2146 VikWaypoint *wp;
2147 gchar *upname = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
2148 int i;
2149
2150 for ( i = strlen(upname)-1; i >= 0; i-- )
2151 upname[i] = toupper(upname[i]);
2152
2153 wp = g_hash_table_lookup ( wps, upname );
2154
2155 if (!wp)
4c77d5e0 2156 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
50a14534
EB
2157 else
2158 {
2159 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
2160 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
bdd1c412 2161 vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, upname ), TRUE );
50a14534
EB
2162 break;
2163 }
2164
2165 g_free ( upname );
2166
2167 }
2168 gtk_widget_destroy ( dia );
2169}
2170
2171gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
2172{
ac1bde8b 2173 gchar *default_name = highest_wp_number_get(vtl);
acaf7113 2174 VikWaypoint *wp = vik_waypoint_new();
ac1bde8b
RN
2175 gchar *returned_name;
2176 gboolean updated;
acaf7113 2177 wp->coord = *def_coord;
d60a672e
RN
2178
2179 // Attempt to auto set height if DEM data is available
2180 gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST );
2181 if ( elev != VIK_DEM_INVALID_ELEVATION )
2182 wp->altitude = (gdouble)elev;
50a14534 2183
ac1bde8b 2184 if ( ( returned_name = a_dialog_waypoint ( w, default_name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode, TRUE, &updated ) ) )
50a14534 2185 {
805d282e 2186 wp->visible = TRUE;
ac1bde8b
RN
2187 vik_trw_layer_add_waypoint ( vtl, returned_name, wp );
2188 g_free (default_name);
50a14534
EB
2189 return TRUE;
2190 }
ac1bde8b 2191 g_free (default_name);
acaf7113 2192 vik_waypoint_free(wp);
50a14534
EB
2193 return FALSE;
2194}
2195
165a4fa9
HR
2196static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] )
2197{
2198 VikCoord one, two;
2199 struct LatLon one_ll, two_ll;
2200 struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2201
2202 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2203 VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2204 VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
2205 VikViewport *vvp = vik_window_viewport(vw);
2206 vik_viewport_screen_to_coord ( vvp, 0, 0, &one);
2207 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &two);
2208 vik_coord_to_latlon(&one, &one_ll);
2209 vik_coord_to_latlon(&two, &two_ll);
2210 if (one_ll.lat > two_ll.lat) {
2211 maxmin[0].lat = one_ll.lat;
2212 maxmin[1].lat = two_ll.lat;
2213 }
2214 else {
2215 maxmin[0].lat = two_ll.lat;
2216 maxmin[1].lat = one_ll.lat;
2217 }
2218 if (one_ll.lon > two_ll.lon) {
2219 maxmin[0].lon = one_ll.lon;
2220 maxmin[1].lon = two_ll.lon;
2221 }
2222 else {
2223 maxmin[0].lon = two_ll.lon;
2224 maxmin[1].lon = one_ll.lon;
2225 }
2226 a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin);
2227}
2228
2229static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] )
2230{
2231 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2232 VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2233 struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2234
2235 trw_layer_find_maxmin (vtl, maxmin);
2236 a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin);
2237}
2238
50a14534
EB
2239static void trw_layer_new_wp ( gpointer lav[2] )
2240{
2241 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2242 VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2243 /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
2244 instead return true if you want to update. */
2245 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 )
2246 vik_layers_panel_emit_update ( vlp );
2247}
2248
535ed1ae
RN
2249static void trw_layer_auto_tracks_view ( gpointer lav[2] )
2250{
2251 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2252 VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2253
2254 if ( g_hash_table_size (vtl->tracks) > 0 ) {
2255 struct LatLon maxmin[2] = { {0,0}, {0,0} };
2256 g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
2257 trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
2258 vik_layers_panel_emit_update ( vlp );
2259 }
2260}
2261
fc59e8c7
RN
2262static void trw_layer_single_waypoint_jump ( const gchar *name, const VikWaypoint *wp, gpointer vvp )
2263{
2264 /* NB do not care if wp is visible or not */
2265 vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
2266}
2267
2268static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
2269{
2270 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2271 VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2272
2273 /* Only 1 waypoint - jump straight to it */
2274 if ( g_hash_table_size (vtl->waypoints) == 1 ) {
2275 VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
2276 g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
2277 }
2278 /* If at least 2 waypoints - find center and then zoom to fit */
2279 else if ( g_hash_table_size (vtl->waypoints) > 1 )
2280 {
2281 struct LatLon maxmin[2] = { {0,0}, {0,0} };
2282 g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin );
2283 trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
2284 }
2285
2286 vik_layers_panel_emit_update ( vlp );
2287}
2288
50a14534
EB
2289void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
2290{
2291 static gpointer pass_along[2];
2292 GtkWidget *item;
98fcbbdb 2293 GtkWidget *export_submenu;
165a4fa9 2294 GtkWidget *wikipedia_submenu;
50a14534
EB
2295 pass_along[0] = vtl;
2296 pass_along[1] = vlp;
2297
2298 item = gtk_menu_item_new();
2299 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2300 gtk_widget_show ( item );
2301
5a10c240
RN
2302 item = gtk_menu_item_new_with_mnemonic ( _("_View Layer") );
2303 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
2304 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2305 gtk_widget_show ( item );
2306
535ed1ae
RN
2307 item = gtk_menu_item_new_with_mnemonic ( _("View All Trac_ks") );
2308 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
2309 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2310 gtk_widget_show ( item );
2311
fc59e8c7
RN
2312 item = gtk_menu_item_new_with_mnemonic ( _("V_iew All Waypoints") );
2313 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
2314 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2315 gtk_widget_show ( item );
2316
d65659e7 2317 item = gtk_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
50a14534
EB
2318 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
2319 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2320 gtk_widget_show ( item );
2321
7306a492 2322 item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
50a14534
EB
2323 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
2324 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2325 gtk_widget_show ( item );
2326
1bd88e66 2327 export_submenu = gtk_menu_new ();
d65659e7 2328 item = gtk_menu_item_new_with_mnemonic ( _("_Export Layer") );
50a14534
EB
2329 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2330 gtk_widget_show ( item );
98fcbbdb 2331 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
1bd88e66 2332
7306a492 2333 item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point...") );
1bd88e66
GB
2334 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
2335 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
2336 gtk_widget_show ( item );
50a14534 2337
7306a492 2338 item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper...") );
50a14534 2339 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
1bd88e66 2340 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
50a14534
EB
2341 gtk_widget_show ( item );
2342
7306a492 2343 item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX...") );
561e6ad0 2344 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
1bd88e66 2345 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
561e6ad0
EB
2346 gtk_widget_show ( item );
2347
ba9d0a00
RN
2348 item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
2349 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
2350 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
2351 gtk_widget_show ( item );
2352
7306a492 2353 item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
50a14534
EB
2354 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
2355 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2356 gtk_widget_show ( item );
3e7553ae 2357
da03b29d 2358#ifdef VIK_CONFIG_GEONAMES
165a4fa9 2359 wikipedia_submenu = gtk_menu_new();
d65659e7 2360 item = gtk_menu_item_new_with_mnemonic ( _("_Add Wikipedia Waypoints") );
165a4fa9
HR
2361 gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
2362 gtk_widget_show(item);
2363 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), wikipedia_submenu);
2364
d65659e7 2365 item = gtk_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
165a4fa9
HR
2366 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along );
2367 gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
2368 gtk_widget_show ( item );
2369
d65659e7 2370 item = gtk_menu_item_new_with_mnemonic ( _("Within _Current View") );
165a4fa9
HR
2371 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along );
2372 gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
2373 gtk_widget_show ( item );
da03b29d 2374#endif
165a4fa9 2375
3e7553ae 2376#ifdef VIK_CONFIG_OPENSTREETMAP
7306a492 2377 item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
3e7553ae
GB
2378 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
2379 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2380 gtk_widget_show ( item );
2381#endif
28c82d8b 2382
c9a5cbf9
RN
2383 GtkWidget *delete_submenu = gtk_menu_new ();
2384 item = gtk_menu_item_new_with_mnemonic ( _("De_lete") );
2385 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2386 gtk_widget_show ( item );
2387 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
2388
2389 item = gtk_menu_item_new_with_mnemonic ( _("Delete All _Tracks") );
2390 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
2391 gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
2392 gtk_widget_show ( item );
2393
20b671c3
RN
2394 item = gtk_menu_item_new_with_mnemonic ( _("Delete Tracks _From Selection...") );
2395 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
2396 gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
2397 gtk_widget_show ( item );
2398
c9a5cbf9
RN
2399 item = gtk_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") );
2400 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
2401 gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
2402 gtk_widget_show ( item );
2403
20b671c3
RN
2404 item = gtk_menu_item_new_with_mnemonic ( _("Delete Waypoints From _Selection...") );
2405 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
2406 gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
2407 gtk_widget_show ( item );
2408
28c82d8b 2409 item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
d65659e7 2410 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
28c82d8b
EB
2411 if ( item ) {
2412 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2413 gtk_widget_show ( item );
2414 }
2415
2416 item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
d65659e7 2417 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
28c82d8b
EB
2418 if ( item ) {
2419 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2420 gtk_widget_show ( item );
2421 }
50a14534
EB
2422}
2423
2424void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
2425{
2426 if ( VIK_LAYER(vtl)->realized )
2427 {
2428 VikWaypoint *oldwp = VIK_WAYPOINT ( g_hash_table_lookup ( vtl->waypoints, name ) );
2429 if ( oldwp )
2430 wp->visible = oldwp->visible; /* same visibility so we don't have to update viktreeview */
2431 else
2432 {
2433 GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
58cd1c43 2434 // Visibility column always needed for waypoints
50a14534
EB
2435#ifdef VIK_CONFIG_ALPHABETIZED_TRW
2436 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE );
2437#else
2438 vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE );
2439#endif
58cd1c43
RN
2440 // Actual setting of visibility dependent on the waypoint
2441 vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
50a14534 2442 g_hash_table_insert ( vtl->waypoints_iters, name, iter );
50a14534
EB
2443 }
2444 }
50a14534 2445
a8fe53f8 2446 highest_wp_number_add_wp(vtl, name);
50a14534
EB
2447 g_hash_table_insert ( vtl->waypoints, name, wp );
2448
2449}
2450
2451void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
2452{
2453 if ( VIK_LAYER(vtl)->realized )
2454 {
2455 VikTrack *oldt = VIK_TRACK ( g_hash_table_lookup ( vtl->tracks, name ) );
2456 if ( oldt )
2457 t->visible = oldt->visible; /* same visibility so we don't have to update viktreeview */
2458 else
2459 {
2460 GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
58cd1c43 2461 // Visibility column always needed for tracks
50a14534 2462#ifdef VIK_CONFIG_ALPHABETIZED_TRW
58cd1c43 2463 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
50a14534 2464#else
58cd1c43 2465 vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
50a14534 2466#endif
58cd1c43
RN
2467 // Actual setting of visibility dependent on the track
2468 vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
50a14534 2469 g_hash_table_insert ( vtl->tracks_iters, name, iter );
50a14534
EB
2470 }
2471 }
50a14534
EB
2472
2473 g_hash_table_insert ( vtl->tracks, name, t );
2474
2475}
2476
50a14534 2477/* to be called whenever a track has been deleted or may have been changed. */
21700912 2478void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name )
50a14534
EB
2479{
2480 if (vtl->current_tp_track_name && g_strcasecmp(trk_name, vtl->current_tp_track_name) == 0)
2481 trw_layer_cancel_current_tp ( vtl, FALSE );
2482 else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0)
2483 trw_layer_cancel_last_tp ( vtl );
2484}
e890a6e6
EB
2485
2486static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
2487{
2488 gint i = 2;
2489 gchar *newname = g_strdup(name);
2490 while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ?
941aa6e9 2491 (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) {
e890a6e6
EB
2492 gchar *new_newname = g_strdup_printf("%s#%d", name, i);
2493 g_free(newname);
2494 newname = new_newname;
2495 i++;
2496 }
2497 return newname;
2498}
50a14534 2499
805d282e
EB
2500void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
2501{
2502 vik_trw_layer_add_waypoint ( vtl,
2503 get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name),
2504 wp );
2505}
2506void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
2507{
7ff7d728 2508 if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
c3deba01 2509 vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
7ff7d728 2510 vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
bddd2056 2511 vik_track_free ( tr );
7ff7d728 2512 vtl->route_finder_append = FALSE; /* this means we have added it */
bddd2056
EB
2513 } else {
2514 gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
2515 vik_trw_layer_add_track ( vtl, new_name, tr );
2516
7ff7d728 2517 if ( vtl->route_finder_check_added_track ) {
c3deba01 2518 vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
7ff7d728
RN
2519 if ( vtl->route_finder_added_track_name ) /* for google routes */
2520 g_free ( vtl->route_finder_added_track_name );
2521 vtl->route_finder_added_track_name = g_strdup(new_name);
bddd2056
EB
2522 }
2523 }
805d282e
EB
2524}
2525
c48517ad
AF
2526static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l )
2527{
2528 *l = g_list_append(*l, (gpointer)name);
2529}
2530
2531static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type )
2532{
2533 gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name);
2534 if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
2535 VikTrack *t;
2536 t = vik_track_copy(vik_trw_layer_get_track(vtl_src, name));
2537 vik_trw_layer_delete_track(vtl_src, name);
2538 vik_trw_layer_add_track(vtl_dest, newname, t);
2539 }
2540 if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
2541 VikWaypoint *w;
2542 w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, name));
2543 vik_trw_layer_delete_waypoint(vtl_src, name);
2544 vik_trw_layer_add_waypoint(vtl_dest, newname, w);
2545 }
2546}
2547
70a23263 2548static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
e4afc73a
EB
2549{
2550 VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
c48517ad
AF
2551 gint type = vik_treeview_item_get_data(vt, src_item_iter);
2552
e4afc73a 2553 if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
b637058e
EB
2554 GList *items = NULL;
2555 GList *iter;
e4afc73a 2556
c48517ad
AF
2557 if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
2558 g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items);
2559 }
2560 if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) {
2561 g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items);
2562 }
2563
2564 iter = items;
2565 while (iter) {
2566 if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
2567 trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
2568 } else {
2569 trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
2570 }
2571 iter = iter->next;
e4afc73a 2572 }
c48517ad 2573 if (items)
b637058e 2574 g_list_free(items);
c48517ad
AF
2575 } else {
2576 gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
2577 trw_layer_move_item(vtl_src, vtl_dest, name, type);
e4afc73a
EB
2578 }
2579}
2580
e4afc73a 2581gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
50a14534
EB
2582{
2583 VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name );
2584 gboolean was_visible = FALSE;
2585 if ( t )
2586 {
2587 GtkTreeIter *it;
2588 was_visible = t->visible;
77ad64fa 2589 if ( t == vtl->current_track ) {
50a14534 2590 vtl->current_track = NULL;
77ad64fa 2591 }
7ff7d728
RN
2592 if ( t == vtl->route_finder_current_track )
2593 vtl->route_finder_current_track = NULL;
2594
50a14534
EB
2595 /* could be current_tp, so we have to check */
2596 trw_layer_cancel_tps_of_track ( vtl, trk_name );
2597
2598 g_assert ( ( it = g_hash_table_lookup ( vtl->tracks_iters, trk_name ) ) );
2599 vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
2600 g_hash_table_remove ( vtl->tracks_iters, trk_name );
2601
2602 /* do this last because trk_name may be pointing to actual orig key */
2603 g_hash_table_remove ( vtl->tracks, trk_name );
2604 }
2605 return was_visible;
2606}
2607
e4afc73a
EB
2608gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name )
2609{
2610 gboolean was_visible = FALSE;
2611 VikWaypoint *wp;
2612
2613 wp = g_hash_table_lookup ( vtl->waypoints, wp_name );
2614 if ( wp ) {
2615 GtkTreeIter *it;
2616
2617 if ( wp == vtl->current_wp ) {
2618 vtl->current_wp = NULL;
2619 vtl->current_wp_name = NULL;
2620 vtl->moving_wp = FALSE;
2621 }
2622
2623 was_visible = wp->visible;
2624 g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) wp_name ) ) );
2625 vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
2626 g_hash_table_remove ( vtl->waypoints_iters, (gchar *) wp_name );
a8fe53f8
EB
2627
2628 highest_wp_number_remove_wp(vtl, wp_name);
e4afc73a
EB
2629 g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */
2630 }
2631
2632 return was_visible;
2633}
2634
700b0908
QT
2635static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt)
2636{
2637 vik_treeview_item_delete (vt, it );
2638}
2639
2640void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
2641{
2642
2643 vtl->current_track = NULL;
7ff7d728 2644 vtl->route_finder_current_track = NULL;
700b0908
QT
2645 if (vtl->current_tp_track_name)
2646 trw_layer_cancel_current_tp(vtl, FALSE);
2647 if (vtl->last_tp_track_name)
2648 trw_layer_cancel_last_tp ( vtl );
2649
2650 g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
2651 g_hash_table_remove_all(vtl->tracks_iters);
2652 g_hash_table_remove_all(vtl->tracks);
2653
2654 /* TODO: only update if the layer is visible (ticked) */
2655 vik_layer_emit_update ( VIK_LAYER(vtl) );
2656}
2657
2658void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
2659{
2660 vtl->current_wp = NULL;
2661 vtl->current_wp_name = NULL;
2662 vtl->moving_wp = FALSE;
2663
a8fe53f8
EB
2664 highest_wp_number_reset(vtl);
2665
700b0908
QT
2666 g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
2667 g_hash_table_remove_all(vtl->waypoints_iters);
2668 g_hash_table_remove_all(vtl->waypoints);
2669
2670 /* TODO: only update if the layer is visible (ticked) */
2671 vik_layer_emit_update ( VIK_LAYER(vtl) );
2672}
2673
c9a5cbf9
RN
2674static void trw_layer_delete_all_tracks ( gpointer lav[2] )
2675{
2676 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2677 // Get confirmation from the user
2678 if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
2679 _("Are you sure you want to delete all tracks in %s?"),
2680 vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
2681 vik_trw_layer_delete_all_tracks (vtl);
2682}
2683
2684static void trw_layer_delete_all_waypoints ( gpointer lav[2] )
2685{
2686 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2687 // Get confirmation from the user
2688 if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
2689 _("Are you sure you want to delete all waypoints in %s?"),
2690 vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
2691 vik_trw_layer_delete_all_waypoints (vtl);
2692}
2693
6bb72350 2694static void trw_layer_delete_item ( gpointer pass_along[6] )
50a14534
EB
2695{
2696 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
2697 gboolean was_visible = FALSE;
dc2c040e 2698 if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
50a14534 2699 {
169acf64
RN
2700 if ( GPOINTER_TO_INT ( pass_along[4]) )
2701 // Get confirmation from the user
2702 // Maybe this Waypoint Delete should be optional as is it could get annoying...
2703 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
2704 _("Are you sure you want to delete the waypoint \"%s\""),
2705 pass_along[3] ) )
2706 return;
e4afc73a 2707 was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
50a14534
EB
2708 }
2709 else
2710 {
169acf64
RN
2711 if ( GPOINTER_TO_INT ( pass_along[4]) )
2712 // Get confirmation from the user
2713 if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
2714 _("Are you sure you want to delete the track \"%s\""),
2715 pass_along[3] ) )
2716 return;
e4afc73a 2717 was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
50a14534 2718 }
50a14534
EB
2719 if ( was_visible )
2720 vik_layer_emit_update ( VIK_LAYER(vtl) );
2721}
2722
2723
6bb72350 2724static void trw_layer_properties_item ( gpointer pass_along[6] )
50a14534
EB
2725{
2726 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
dc2c040e 2727 if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
50a14534
EB
2728 {
2729 VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
2730 if ( wp )
2731 {
ac1bde8b
RN
2732 gboolean updated = FALSE;
2733 a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), pass_along[3], wp, NULL, vtl->coord_mode, FALSE, &updated );
50a14534 2734
ac1bde8b
RN
2735 if ( updated && VIK_LAYER(vtl)->visible )
2736 vik_layer_emit_update ( VIK_LAYER(vtl) );
50a14534
EB
2737 }
2738 }
2739 else
2740 {
2741 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
2742 if ( tr )
2743 {
21700912 2744 vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6bb72350
RN
2745 vtl, tr,
2746 pass_along[1], /* vlp */
2747 pass_along[3], /* track name */
2748 pass_along[5] ); /* vvp */
50a14534
EB
2749 }
2750 }
2751}
2752
6bb72350
RN
2753/*
2754 Parameter 1 -> VikLayersPanel
2755 Parameter 2 -> VikLayer
2756 Parameter 3 -> VikViewport
2757*/
2758static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord )
2759{
2760 if ( vlp ) {
2761 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord );
2762 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
2763 }
2764 else {
2765 /* since vlp not set, vl & vvp should be valid instead! */
2766 if ( vl && vvp ) {
2767 vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord );
2768 vik_layer_emit_update ( VIK_LAYER(vl) );
2769 }
2770 }
50a14534
EB
2771}
2772
6bb72350 2773static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] )
50a14534
EB
2774{
2775 GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
2776 if ( trps && trps->data )
6bb72350 2777 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
50a14534
EB
2778}
2779
6bb72350 2780static void trw_layer_goto_track_center ( gpointer pass_along[6] )
50a14534 2781{
8fb71d6c 2782 /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
50a14534
EB
2783 GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2784 if ( trps && *trps )
2785 {
2786 struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
2787 VikCoord coord;
2788 trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
2789 average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
2790 average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
2791 vik_coord_load_from_latlon ( &coord, VIK_TRW_LAYER(pass_along[0])->coord_mode, &average );
6bb72350 2792 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord);
50a14534
EB
2793 }
2794}
2795
8fb71d6c
EB
2796static void trw_layer_extend_track_end ( gpointer pass_along[6] )
2797{
2798 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
2799 VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2800
2801 vtl->current_track = track;
a7955c1d 2802 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK);
8fb71d6c
EB
2803
2804 if ( track->trackpoints )
6bb72350 2805 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
8fb71d6c
EB
2806}
2807
e3154bef 2808/**
7ff7d728 2809 * extend a track using route finder
e3154bef 2810 */
7ff7d728 2811static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
a7955c1d
AM
2812{
2813 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
2814 VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2815 VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord);
2816
2817 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, NUM_TOOLS );
7ff7d728
RN
2818 vtl->route_finder_coord = last_coord;
2819 vtl->route_finder_current_track = track;
2820 vtl->route_finder_started = TRUE;
a7955c1d
AM
2821
2822 if ( track->trackpoints )
6bb72350 2823 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
a7955c1d
AM
2824
2825}
a7955c1d 2826
ad0a8c2d
EB
2827static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
2828{
2829 /* TODO: check & warn if no DEM data, or no applicable DEM data. */
2830 /* Also warn if overwrite old elevation data */
2831 VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2832
55906514 2833 vik_track_apply_dem_data ( track );
ad0a8c2d
EB
2834}
2835
50a14534
EB
2836static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
2837{
2838 GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
2839 if ( !trps )
2840 return;
111fa174 2841 trps = g_list_last(trps);
6bb72350 2842 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
50a14534
EB
2843}
2844
6bb72350 2845static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
03e7da75
RN
2846{
2847 VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
2848 if ( !vtp )
2849 return;
6bb72350 2850 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
03e7da75
RN
2851}
2852
6bb72350 2853static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
c28faca8
RN
2854{
2855 VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
2856 if ( !vtp )
2857 return;
6bb72350 2858 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
c28faca8
RN
2859}
2860
6bb72350 2861static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
c28faca8
RN
2862{
2863 VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) );
2864 if ( !vtp )
2865 return;
6bb72350 2866 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
c28faca8 2867}
111fa174 2868
469113fb
RN
2869/*
2870 * Automatically change the viewport to center on the track and zoom to see the extent of the track
2871 */
2872static void trw_layer_auto_track_view ( gpointer pass_along[5] )
2873{
2874 GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2875 if ( trps && *trps )
2876 {
2877 struct LatLon maxmin[2] = { {0,0}, {0,0} };
2878 trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
6bb72350
RN
2879 trw_layer_zoom_to_show_latlons ( VIK_TRW_LAYER(pass_along[0]), pass_along[5], maxmin );
2880 if ( pass_along[1] )
2881 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
2882 else
2883 vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
469113fb
RN
2884 }
2885}
2886
c95d6b00
RN
2887static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
2888{
2889 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
2890 trw_layer_tpwin_init ( vtl );
2891}
2892
111fa174
AF
2893/*************************************
2894 * merge/split by time routines
2895 *************************************/
2896
15f45edc
QT
2897/* called for each key in track hash table.
2898 * If the current track has time stamp, add it to the result,
2899 * except the one pointed by "exclude".
2900 * set exclude to NULL if there is no exclude to check.
2901 * Not that result is in reverse (for performance reason).
2902 */
2903typedef struct {
2904 GList **result;
2905 GList *exclude;
2906} twt_udata;
2907static void find_tracks_with_timestamp(gpointer key, gpointer value, gpointer udata)
2908{
2909 twt_udata *user_data = udata;
2910 VikTrackpoint *p1, *p2;
2911
2912 if (VIK_TRACK(value)->trackpoints == user_data->exclude) {
2913 return;
2914 }
2915
2916 if (VIK_TRACK(value)->trackpoints) {
2917 p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
2918 p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
2919
2920 if (!p1->has_timestamp || !p2->has_timestamp) {
2921 g_print("no timestamp\n");
2922 return;
2923 }
2924
2925 }
2926
2927 *(user_data->result) = g_list_prepend(*(user_data->result), key);
2928}
2929
111fa174
AF
2930/* called for each key in track hash table. if original track user_data[1] is close enough
2931 * to the passed one, add it to list in user_data[0]
2932 */
2933static void find_nearby_track(gpointer key, gpointer value, gpointer user_data)
2934{
2935 time_t t1, t2;
2936 VikTrackpoint *p1, *p2;
2937
2938 GList **nearby_tracks = ((gpointer *)user_data)[0];
2939 GList *orig_track = ((gpointer *)user_data)[1];
dc2c040e 2940 guint thr = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
111fa174 2941
a61b2619
AF
2942 /* outline:
2943 * detect reasons for not merging, and return
2944 * if no reason is found not to merge, then do it.
2945 */
111fa174
AF
2946
2947 if (VIK_TRACK(value)->trackpoints == orig_track) {
2948 return;
2949 }
2950
a61b2619
AF
2951 t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
2952 t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
111fa174 2953
a61b2619
AF
2954 if (VIK_TRACK(value)->trackpoints) {
2955 p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
2956 p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
2957
2958 if (!p1->has_timestamp || !p2->has_timestamp) {
2959 g_print("no timestamp\n");
2960 return;
2961 }
111fa174 2962
a61b2619
AF
2963 /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
2964 if (! (abs(t1 - p2->timestamp) < thr*60 ||
2965 /* p1 p2 t1 t2 */
2966 abs(p1->timestamp - t2) < thr*60)
2967 /* t1 t2 p1 p2 */
2968 ) {
2969 return;
2970 }
111fa174 2971 }
a61b2619
AF
2972
2973 *nearby_tracks = g_list_prepend(*nearby_tracks, key);
111fa174
AF
2974}
2975
2976/* comparison function used to sort tracks; a and b are hash table keys */
02b5d347 2977/* Not actively used - can be restored if needed
111fa174
AF
2978static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
2979{
2980 GHashTable *tracks = user_data;
2981 time_t t1, t2;
2982
2983 t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
2984 t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
2985
2986 if (t1 < t2) return -1;
2987 if (t1 > t2) return 1;
2988 return 0;
2989}
02b5d347 2990*/
111fa174
AF
2991
2992/* comparison function used to sort trackpoints */
2993static gint trackpoint_compare(gconstpointer a, gconstpointer b)
2994{
2995 time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
2996
2997 if (t1 < t2) return -1;
2998 if (t1 > t2) return 1;
2999 return 0;
3000}
3001
fb2306f7
RN
3002#ifdef VIK_CONFIG_ALPHABETIZED_TRW
3003/**
3004 * comparison function which can be used to sort tracks or waypoints by name
3005 */
3006static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user_data)
3007{
3008 const gchar* namea = (const gchar*) a;
3009 const gchar* nameb = (const gchar*) b;
3010 if ( namea == NULL || nameb == NULL)
3011 return 0;
3012 else
3013 // Same sort method as used in the vik_treeview_*_alphabetize functions
3014 return strcmp ( namea, nameb );
3015}
3016#endif
3017
291edcab
HR
3018static void trw_layer_merge_with_other ( gpointer pass_along[6] )
3019{
3020 VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
15f45edc 3021 gchar *orig_track_name = pass_along[3];
15f45edc
QT
3022 GList *tracks_with_timestamp = NULL;
3023 VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
3024
3025 if (track->trackpoints &&
3026 !VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp) {
3027 a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
3028 return;
3029 }
3030
3031 if (1) {
3032
3033 twt_udata udata;
3034 udata.result = &tracks_with_timestamp;
3035 udata.exclude = track->trackpoints;
3036 g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp, (gpointer)&udata);
3037 tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
3038 }
291edcab 3039
15f45edc
QT
3040 if (!tracks_with_timestamp) {
3041 a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
3042 return;
3043 }
3044
8352326e
RN
3045#ifdef VIK_CONFIG_ALPHABETIZED_TRW
3046 // Sort alphabetically for user presentation
3047 tracks_with_timestamp = g_list_sort_with_data (tracks_with_timestamp, sort_alphabetically, NULL);
3048#endif
3049
7767aa02 3050 GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
02bba540 3051 tracks_with_timestamp, TRUE,
7767aa02 3052 _("Merge with..."), _("Select track to merge with"));
15f45edc 3053 g_list_free(tracks_with_timestamp);
291edcab 3054
7767aa02 3055 if (merge_list)
291edcab 3056 {
7767aa02
QT
3057 GList *l;
3058 for (l = merge_list; l != NULL; l = g_list_next(l)) {
3059 VikTrack *merge_track = (VikTrack *) g_hash_table_lookup (vtl->tracks, l->data );
3060 if (merge_track) {
3061 track->trackpoints = g_list_concat(track->trackpoints, merge_track->trackpoints);
3062 merge_track->trackpoints = NULL;
3063 vik_trw_layer_delete_track(vtl, l->data);
3064 track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
3065 }
291edcab 3066 }
7767aa02
QT
3067 /* TODO: free data before free merge_list */
3068 for (l = merge_list; l != NULL; l = g_list_next(l))
3069 g_free(l->data);
3070 g_list_free(merge_list);
15f45edc 3071 vik_layer_emit_update( VIK_LAYER(vtl) );
291edcab 3072 }
291edcab
HR
3073}
3074
111fa174
AF
3075/* merge by time routine */
3076static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
3077{
a61b2619
AF
3078 VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
3079 gchar *orig_track_name = strdup(pass_along[3]);
3080
02b5d347 3081 //time_t t1, t2;
a61b2619 3082 GList *nearby_tracks;
111fa174
AF
3083 VikTrack *track;
3084 GList *trps;
3085 static guint thr = 1;
3086 guint track_count = 0;
111fa174 3087
a61b2619 3088 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
4c77d5e0 3089 _("Merge Threshold..."),
a61b2619 3090 _("Merge when time between tracks less than:"),
111fa174 3091 &thr)) {
3b36279c 3092 free(orig_track_name);
111fa174
AF
3093 return;
3094 }
3095
3096 /* merge tracks until we can't */
a61b2619 3097 nearby_tracks = NULL;
111fa174
AF
3098 do {
3099 gpointer params[3];
3100
a61b2619 3101 track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
111fa174
AF
3102 trps = track->trackpoints;
3103 if ( !trps )
3104 return;
3105
3106
3107 if (nearby_tracks) {
3108 g_list_free(nearby_tracks);
3109 nearby_tracks = NULL;
3110 }
3111
02b5d347
RN
3112 //t1 = ((VikTrackpoint *)trps->data)->timestamp;
3113 //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
111fa174 3114
70a23263 3115 /* g_print("Original track times: %d and %d\n", t1, t2); */
111fa174
AF
3116 params[0] = &nearby_tracks;
3117 params[1] = trps;
dc2c040e 3118 params[2] = GUINT_TO_POINTER (thr);
111fa174
AF
3119
3120 /* get a list of adjacent-in-time tracks */
a61b2619 3121 g_hash_table_foreach(vtl->tracks, find_nearby_track, (gpointer)params);
111fa174
AF
3122
3123 /* add original track */
3124 nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name);
3125
111fa174
AF
3126 /* merge them */
3127 {
a61b2619 3128#define get_track(x) VIK_TRACK(g_hash_table_lookup(vtl->tracks, (gchar *)((x)->data)))
111fa174
AF
3129#define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
3130#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
3131 GList *l = nearby_tracks;
3132 VikTrack *tr = vik_track_new();
3133 tr->visible = track->visible;
3134 track_count = 0;
3135 while (l) {
3136 /*
3137 time_t t1, t2;
3138 t1 = get_first_trackpoint(l)->timestamp;
3139 t2 = get_last_trackpoint(l)->timestamp;
70a23263 3140 g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
111fa174
AF
3141 */
3142
3143
3144 /* remove trackpoints from merged track, delete track */
3145 tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints);
3146 get_track(l)->trackpoints = NULL;
a61b2619 3147 vik_trw_layer_delete_track(vtl, l->data);
111fa174
AF
3148
3149 track_count ++;
3150 l = g_list_next(l);
3151 }
3152 tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare);
a61b2619 3153 vik_trw_layer_add_track(vtl, strdup(orig_track_name), tr);
111fa174
AF
3154
3155#undef get_first_trackpoint
3156#undef get_last_trackpoint
3157#undef get_track
3158 }
3159 } while (track_count > 1);
3160 g_list_free(nearby_tracks);
3161 free(orig_track_name);
0654760a 3162 vik_layer_emit_update( VIK_LAYER(vtl) );
111fa174
AF
3163}
3164
3165/* split by time routine */
3166static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
3167{
3168 VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
3169 GList *trps = track->trackpoints;
3170 GList *iter;
3171 GList *newlists = NULL;
3172 GList *newtps = NULL;
3173 guint i;
3174 static guint thr = 1;
3175
3176 time_t ts, prev_ts;
3177
3178 if ( !trps )
3179 return;
3180
3181 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
4c77d5e0
GB
3182 _("Split Threshold..."),
3183 _("Split when time between trackpoints exceeds:"),
111fa174
AF
3184 &thr)) {
3185 return;
3186 }
3187
3188 /* iterate through trackpoints, and copy them into new lists without touching original list */
3189 prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
3190 iter = trps;
3191
3192 while (iter) {
3193 ts = VIK_TRACKPOINT(iter->data)->timestamp;
3194 if (ts < prev_ts) {
70a23263 3195 g_print("panic: ts < prev_ts: this should never happen!\n");
111fa174
AF
3196 return;
3197 }
3198 if (ts - prev_ts > thr*60) {
3199 /* flush accumulated trackpoints into new list */
aa9887a1 3200 newlists = g_list_append(newlists, g_list_reverse(newtps));
111fa174
AF
3201 newtps = NULL;
3202 }
3203
3204 /* accumulate trackpoint copies in newtps, in reverse order */
3205 newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
3206 prev_ts = ts;
3207 iter = g_list_next(iter);
3208 }
3209 if (newtps) {
aa9887a1 3210 newlists = g_list_append(newlists, g_list_reverse(newtps));
111fa174
AF
3211 }
3212
3213 /* put lists of trackpoints into tracks */
3214 iter = newlists;
3215 i = 1;
c9d8f273
RN
3216 // Only bother updating if the split results in new tracks
3217 if (g_list_length (newlists) > 1) {
3218 while (iter) {
3219 gchar *new_tr_name;
3220 VikTrack *tr;
111fa174 3221
c9d8f273
RN
3222 tr = vik_track_new();
3223 tr->visible = track->visible;
3224 tr->trackpoints = (GList *)(iter->data);
111fa174 3225
c9d8f273
RN
3226 new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
3227 vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
3228 /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
111fa174
AF
3229 VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
3230
c9d8f273
RN
3231 iter = g_list_next(iter);
3232 }
3233 vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
3234 vik_layer_emit_update(VIK_LAYER(pass_along[0]));
111fa174
AF
3235 }
3236 g_list_free(newlists);
111fa174
AF
3237}
3238
af2341f3
RN
3239/**
3240 * Split a track by the number of points as specified by the user
3241 */
3242static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
3243{
3244 VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
3245 VikTrack *track = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
3246
3247 // Check valid track
3248 GList *trps = track->trackpoints;
3249 if ( !trps )
3250 return;
3251
3252 gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
3253 _("Split Every Nth Point"),
3254 _("Split on every Nth point:"),
3255 250, // Default value as per typical limited track capacity of various GPS devices
3256 2, // Min
3257 65536, // Max
3258 5); // Step
3259 // Was a valid number returned?
3260 if (!points)
3261 return;
3262
3263 // Now split...
3264 GList *iter;
3265 GList *newlists = NULL;
3266 GList *newtps = NULL;
3267 gint count = 0;
3268 iter = trps;
3269
3270 while (iter) {
3271 /* accumulate trackpoint copies in newtps, in reverse order */
3272 newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
3273 count++;
3274 if (count >= points) {
3275 /* flush accumulated trackpoints into new list */
3276 newlists = g_list_append(newlists, g_list_reverse(newtps));
3277 newtps = NULL;
3278 count = 0;
3279 }
3280 iter = g_list_next(iter);
3281 }
3282
3283 // If there is a remaining chunk put that into the new split list
3284 // This may well be the whole track if no split points were encountered
3285 if (newtps) {
3286 newlists = g_list_append(newlists, g_list_reverse(newtps));
3287 }
3288
3289 /* put lists of trackpoints into tracks */
3290 iter = newlists;
3291 guint i = 1;
3292 // Only bother updating if the split results in new tracks
3293 if (g_list_length (newlists) > 1) {
3294 while (iter) {
3295 gchar *new_tr_name;
3296 VikTrack *tr;
3297
3298 tr = vik_track_new();
3299 tr->visible = track->visible;
3300 tr->trackpoints = (GList *)(iter->data);
3301
3302 new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
3303 vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
3304
3305 iter = g_list_next(iter);
3306 }
3307 // Remove original track and then update the display
3308 vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
3309 vik_layer_emit_update(VIK_LAYER(pass_along[0]));
3310 }
3311 g_list_free(newlists);
3312}
3313
111fa174
AF
3314/* end of split/merge routines */
3315
20b671c3
RN
3316/**
3317 * Similar to trw_layer_enum_item, but this uses a sorted method
3318 */
3319static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata)
3320{
3321 GList **list = (GList**)udata;
3322 //*list = g_list_prepend(*all, key); //unsorted method
3323 // Sort named list alphabetically
3324 *list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL);
3325}
3326
3327/**
3328 *
3329 */
3330static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
3331{
3332 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3333 GList *all = NULL;
3334 // Sort list alphabetically for better presentation
3335 g_hash_table_foreach(vtl->tracks, trw_layer_sorted_name_list, &all);
3336
3337 if ( ! all ) {
3338 a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No tracks found"));
3339 return;
3340 }
3341
3342 // Get list of items to delete from the user
3343 GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
3344 all,
3345 TRUE,
3346 _("Delete Selection"),
3347 _("Select tracks to delete"));
3348 g_list_free(all);
3349
3350 // Delete requested tracks
3351 // since specificly requested, IMHO no need for extra confirmation
3352 if ( delete_list ) {
3353 GList *l;
3354 for (l = delete_list; l != NULL; l = g_list_next(l)) {
3355 vik_trw_layer_delete_track(vtl, l->data);
3356 }
3357 g_list_free(delete_list);
3358 vik_layer_emit_update( VIK_LAYER(vtl) );
3359 }
3360}
3361
3362/**
3363 *
3364 */
3365static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] )
3366{
3367 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3368 GList *all = NULL;
3369
3370 // Sort list alphabetically for better presentation
3371 g_hash_table_foreach ( vtl->waypoints, trw_layer_sorted_name_list, &all);
3372 if ( ! all ) {
3373 a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found"));
3374 return;
3375 }
3376
3377 all = g_list_sort_with_data(all, sort_alphabetically, NULL);
3378
3379 // Get list of items to delete from the user
3380 GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
3381 all,
3382 TRUE,
3383 _("Delete Selection"),
3384 _("Select waypoints to delete"));
3385 g_list_free(all);
3386
3387 // Delete requested waypoints
3388 // since specificly requested, IMHO no need for extra confirmation
3389 if ( delete_list ) {
3390 GList *l;
3391 for (l = delete_list; l != NULL; l = g_list_next(l)) {
3392 vik_trw_layer_delete_waypoint(vtl, l->data);
3393 }
3394 g_list_free(delete_list);
3395 vik_layer_emit_update( VIK_LAYER(vtl) );
3396 }
3397
3398}
111fa174 3399
6bb72350 3400static void trw_layer_goto_waypoint ( gpointer pass_along[6] )
50a14534
EB
3401{
3402 VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
3403 if ( wp )
6bb72350 3404 goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(wp->coord) );
50a14534
EB
3405}
3406
6bb72350 3407static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] )
50a14534
EB
3408{
3409 gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] );
7d02a0b0 3410 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
50a14534
EB
3411 g_free ( webpage );
3412}
3413
3414const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
3415{
3416 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
3417 {
50a14534
EB
3418 gchar *rv;
3419 VikWaypoint *wp;
3420
8499a412 3421 if (strcmp(newname, sublayer) == 0 )
50a14534
EB
3422 return NULL;
3423
8499a412
QT
3424 if (strcasecmp(newname, sublayer)) { /* Not just changing case */
3425 if (g_hash_table_lookup( l->waypoints, newname))
3426 {
3427 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Waypoint Already Exists") );
3428 return NULL;
3429 }
50a14534
EB
3430 }
3431
50a14534
EB
3432 iter = g_hash_table_lookup ( l->waypoints_iters, sublayer );
3433 g_hash_table_steal ( l->waypoints_iters, sublayer );
3434
e4afc73a 3435 wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) );
a8fe53f8 3436 highest_wp_number_remove_wp(l, sublayer);
e4afc73a
EB
3437 g_hash_table_remove ( l->waypoints, sublayer );
3438
50a14534 3439 rv = g_strdup(newname);
50a14534
EB
3440
3441 vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
3442
a8fe53f8 3443 highest_wp_number_add_wp(l, rv);
50a14534
EB
3444 g_hash_table_insert ( l->waypoints, rv, wp );
3445 g_hash_table_insert ( l->waypoints_iters, rv, iter );
3446
3447 /* it hasn't been updated yet so we pass new name */
3448#ifdef VIK_CONFIG_ALPHABETIZED_TRW
3449 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
3450#endif
3451
3452 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
3453 return rv;
3454 }
3455 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
3456 {
50a14534
EB
3457 gchar *rv;
3458 VikTrack *tr;
3459 GtkTreeIter *iter;
3460 gchar *orig_key;
3461
8499a412 3462 if (strcmp(newname, sublayer) == 0)
50a14534
EB
3463 return NULL;
3464
8499a412 3465 if (strcasecmp(newname, sublayer)) { /* Not just changing case */
c8de7dd7 3466 if (g_hash_table_lookup( l->tracks, newname))
8499a412
QT
3467 {
3468 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Track Already Exists") );
3469 return NULL;
3470 }
50a14534
EB
3471 }
3472
886031df 3473 g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
50a14534
EB
3474 g_hash_table_steal ( l->tracks, sublayer );
3475
3476 iter = g_hash_table_lookup ( l->tracks_iters, sublayer );
3477 g_hash_table_steal ( l->tracks_iters, sublayer );
3478
3479 rv = g_strdup(newname);
50a14534
EB
3480
3481 vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
3482
3483 g_hash_table_insert ( l->tracks, rv, tr );
3484 g_hash_table_insert ( l->tracks_iters, rv, iter );
3485
3486 /* don't forget about current_tp_track_name, update that too */
3487 if ( l->current_tp_track_name && g_strcasecmp(orig_key,l->current_tp_track_name) == 0 )
3488 {
3489 l->current_tp_track_name = rv;
3490 if ( l->tpwin )
3491 vik_trw_layer_tpwin_set_track_name ( l->tpwin, rv );
3492 }
3493 else if ( l->last_tp_track_name && g_strcasecmp(orig_key,l->last_tp_track_name) == 0 )
3494 l->last_tp_track_name = rv;
3495
3496 g_free ( orig_key );
3497
3498#ifdef VIK_CONFIG_ALPHABETIZED_TRW
3499 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
3500#endif
3501
3502 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
3503 return rv;
3504 }
3505 return NULL;
3506}
3507
3508static gboolean is_valid_geocache_name ( gchar *str )
3509{
3510 gint len = strlen ( str );
0c1044e9 3511 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]));
50a14534
EB
3512}
3513
6bb72350 3514static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
28c82d8b
EB
3515{
3516 gchar *track_name = (gchar *) pass_along[3];
3517 VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
3518 a_acquire_set_filter_track ( tr, track_name );
3519}
3520
bddd2056
EB
3521static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name )
3522{
3523 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_name );
3524 return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
3525}
3526
6bb72350 3527static void trw_layer_track_google_route_webpage ( gpointer pass_along[6] )
bddd2056
EB
3528{
3529 gchar *track_name = (gchar *) pass_along[3];
3530 VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
3531 if ( tr ) {
3532 gchar *escaped = uri_escape ( tr->comment );
3533 gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
7d02a0b0 3534 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
bddd2056 3535 g_free ( escaped );
bddd2056
EB
3536 g_free ( webpage );
3537 }
3538}
3539
50eadc64
RN
3540/* vlp can be NULL if necessary - i.e. right-click from a tool */
3541/* viewpoint is now available instead */
3542gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
50a14534 3543{
6bb72350 3544 static gpointer pass_along[6];
50a14534
EB
3545 GtkWidget *item;
3546 gboolean rv = FALSE;
3547
3548 pass_along[0] = l;
3549 pass_along[1] = vlp;
dc2c040e 3550 pass_along[2] = GINT_TO_POINTER (subtype);
50a14534 3551 pass_along[3] = sublayer;
169acf64 3552 pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
6bb72350 3553 pass_along[5] = vvp;
50a14534
EB
3554
3555 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
3556 {
3557 rv = TRUE;
3558
3559 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES, NULL );
3560 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_properties_item), pass_along );
3561 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3562 gtk_widget_show ( item );
3563
21700912
QT
3564 if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
3565 VikTrwLayer *vtl = l;
3566 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, sublayer );
3567 if (tr && tr->property_dialog)
3568 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
3569 }
3570
2cebc318
QT
3571 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL );
3572 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along );
3573 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3574 gtk_widget_show ( item );
3575
3576 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL );
3577 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along );
3578 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3579 gtk_widget_show ( item );
3580
50a14534
EB
3581 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
3582 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
3583 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3584 gtk_widget_show ( item );
3585
3586 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
3587 {
5ede6aa6
RN
3588 gboolean separator_created = FALSE;
3589
50a14534
EB
3590 /* could be a right-click using the tool */
3591 if ( vlp != NULL ) {
5ede6aa6
RN
3592 item = gtk_menu_item_new ();
3593 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3594 gtk_widget_show ( item );
3595
3596 separator_created = TRUE;
3597
92dce2ef 3598 item = gtk_menu_item_new_with_mnemonic ( _("_Goto") );
50a14534
EB
3599 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
3600 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3601 gtk_widget_show ( item );
3602 }
3603
3604 if ( is_valid_geocache_name ( (gchar *) sublayer ) )
3605 {
5ede6aa6
RN
3606 if ( !separator_created ) {
3607 item = gtk_menu_item_new ();
3608 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3609 gtk_widget_show ( item );
a412f3f5 3610 separator_created = TRUE;
5ede6aa6
RN
3611 }
3612
92dce2ef 3613 item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
50a14534
EB
3614 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
3615 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3616 gtk_widget_show ( item );
3617 }
3618
a412f3f5
RN
3619 VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
3620
3621 if ( wp && wp->image )
3622 {
3623 if ( !separator_created ) {
3624 item = gtk_menu_item_new ();
3625 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3626 gtk_widget_show ( item );
3627 separator_created = TRUE;
3628 }
3629
3630 // Set up image paramater
3631 pass_along[5] = wp->image;
3632
3633 item = gtk_menu_item_new_with_mnemonic ( _("_Show Picture...") );
3634 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along );
3635 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3636 gtk_widget_show ( item );
3637 }
3638
50a14534
EB
3639 }
3640 }
3641
5ede6aa6
RN
3642 if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
3643 {
b66bb4ab 3644 rv = TRUE;
7306a492 3645 item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
5ede6aa6
RN
3646 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
3647 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3648 gtk_widget_show ( item );
3649 }
3650
539ba038
RN
3651 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS )
3652 {
3653 item = gtk_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
3654 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
3655 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3656 gtk_widget_show ( item );
3657
3658 item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
3659 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
3660 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3661 gtk_widget_show ( item );
c9a5cbf9
RN
3662
3663 item = gtk_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") );
3664 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
3665 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3666 gtk_widget_show ( item );
20b671c3
RN
3667
3668 item = gtk_menu_item_new_with_mnemonic ( _("_Delete Waypoints From Selection...") );
3669 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
3670 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3671 gtk_widget_show ( item );
539ba038
RN
3672 }
3673
f1e68516
RN
3674 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS )
3675 {
3676 rv = TRUE;
3677
3678 item = gtk_menu_item_new_with_mnemonic ( _("_View All Tracks") );
3679 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
3680 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3681 gtk_widget_show ( item );
c9a5cbf9
RN
3682
3683 item = gtk_menu_item_new_with_mnemonic ( _("Delete _All Tracks") );
3684 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
3685 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3686 gtk_widget_show ( item );
20b671c3
RN
3687
3688 item = gtk_menu_item_new_with_mnemonic ( _("_Delete Tracks From Selection...") );
3689 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
3690 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3691 gtk_widget_show ( item );
f1e68516
RN
3692 }
3693
50a14534
EB
3694 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
3695 {
937b36ed 3696 GtkWidget *goto_submenu;
50a14534
EB
3697 item = gtk_menu_item_new ();
3698 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3699 gtk_widget_show ( item );
3700
937b36ed
RN
3701 goto_submenu = gtk_menu_new ();
3702 item = gtk_menu_item_new_with_mnemonic ( _("_Goto") );
3703 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3704 gtk_widget_show ( item );
3705 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), goto_submenu );
3706
3707 item = gtk_menu_item_new_with_mnemonic ( _("_Startpoint") );
50a14534 3708 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
937b36ed 3709 gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
50a14534
EB
3710 gtk_widget_show ( item );
3711
937b36ed 3712 item = gtk_menu_item_new_with_mnemonic ( _("\"_Center\"") );
50a14534 3713 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
937b36ed 3714 gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
50a14534
EB
3715 gtk_widget_show ( item );
3716
937b36ed 3717 item = gtk_menu_item_new_with_mnemonic ( _("_Endpoint") );
50a14534 3718 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
937b36ed 3719 gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
50a14534 3720 gtk_widget_show ( item );
111fa174 3721
c28faca8
RN
3722 item = gtk_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
3723 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
3724 gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
3725 gtk_widget_show ( item );
3726
3727 item = gtk_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
3728 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
3729 gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
3730 gtk_widget_show ( item );
3731
03e7da75
RN
3732 item = gtk_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
3733 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along );
3734 gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
3735 gtk_widget_show ( item );
3736
469113fb
RN
3737 item = gtk_menu_item_new_with_mnemonic ( _("_View Track") );
3738 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
3739 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3740 gtk_widget_show ( item );
3741
7306a492 3742 item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
111fa174
AF
3743 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
3744 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3745 gtk_widget_show ( item );
3746
40a68e7c 3747 item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") );
291edcab
HR
3748 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along );
3749 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3750 gtk_widget_show ( item );
3751
7306a492 3752 item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
111fa174
AF
3753 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
3754 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3755 gtk_widget_show ( item );
7114e879 3756
7306a492 3757 item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") );
af2341f3
RN
3758 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along );
3759 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3760 gtk_widget_show ( item );
3761
6bb72350
RN
3762 /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
3763 if ( vlp ) {
3764 item = gtk_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
3765 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
3766 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3767 gtk_widget_show ( item );
3768 }
ad0a8c2d 3769
40a68e7c 3770 item = gtk_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
ad0a8c2d
EB
3771 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
3772 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8fb71d6c
EB
3773 gtk_widget_show ( item );
3774
7306a492 3775 item = gtk_menu_item_new_with_mnemonic ( _("Export Trac_k as GPX...") );
7f6757c4
RN
3776 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along );
3777 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3778 gtk_widget_show ( item );
3779
40a68e7c 3780 item = gtk_menu_item_new_with_mnemonic ( _("E_xtend Track End") );
8fb71d6c
EB
3781 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
3782 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
ad0a8c2d 3783 gtk_widget_show ( item );
5092de80 3784
0db79fc5 3785 item = gtk_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
7ff7d728 3786 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
a7955c1d
AM
3787 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3788 gtk_widget_show ( item );
3789
5092de80 3790#ifdef VIK_CONFIG_OPENSTREETMAP
7306a492 3791 item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
5092de80
GB
3792 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
3793 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3794 gtk_widget_show ( item );
3795#endif
bddd2056
EB
3796
3797 if ( is_valid_google_route ( l, (gchar *) sublayer ) )
3798 {
40a68e7c 3799 item = gtk_menu_item_new_with_mnemonic ( _("_View Google Directions") );
bddd2056
EB
3800 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along );
3801 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3802 gtk_widget_show ( item );
3803 }
3804
40a68e7c 3805 item = gtk_menu_item_new_with_mnemonic ( _("Use with _Filter") );
28c82d8b
EB
3806 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
3807 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3808 gtk_widget_show ( item );
3809
6bb72350
RN
3810 /* ATM This function is only available via the layers panel, due to needing a vlp */
3811 if ( vlp ) {
3812 item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp,
3813 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
3814 g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
3815 if ( item ) {
3816 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3817 gtk_widget_show ( item );
3818 }
3819 }
c95d6b00
RN
3820
3821 // Only show on viewport popmenu when a trackpoint is selected
3822 if ( ! vlp && l->current_tpl ) {
3823 // Add separator
3824 item = gtk_menu_item_new ();
3825 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3826 gtk_widget_show ( item );
3827
3828 item = gtk_image_menu_item_new_with_mnemonic ( _("_Edit Trackpoint") );
3829 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU) );
3830 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_edit_trackpoint), pass_along );
3831 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3832 gtk_widget_show ( item );
3833 }
3834
50a14534
EB
3835 }
3836
50a14534
EB
3837 return rv;
3838}
3839
db79f75f
RN
3840static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl )
3841{
3842 /* sanity checks */
3843 if (!vtl->current_tpl)
3844 return;
3845 if (!vtl->current_tpl->next)
3846 return;
3847
3848 VikTrackpoint *tp_current = VIK_TRACKPOINT(vtl->current_tpl->data);
3849 VikTrackpoint *tp_next = VIK_TRACKPOINT(vtl->current_tpl->next->data);
3850
3851 /* Use current and next trackpoints to form a new track point which is inserted into the tracklist */
3852 if ( tp_next ) {
3853
3854 VikTrackpoint *tp_new = vik_trackpoint_new();
3855 struct LatLon ll_current, ll_next;
3856 vik_coord_to_latlon ( &tp_current->coord, &ll_current );
3857 vik_coord_to_latlon ( &tp_next->coord, &ll_next );
3858
3859 /* main positional interpolation */
3860 struct LatLon ll_new = { (ll_current.lat+ll_next.lat)/2, (ll_current.lon+ll_next.lon)/2 };
3861 vik_coord_load_from_latlon ( &(tp_new->coord), vtl->coord_mode, &ll_new );
3862
3863 /* Now other properties that can be interpolated */
3864 tp_new->altitude = (tp_current->altitude + tp_next->altitude) / 2;
3865
3866 if (tp_current->has_timestamp && tp_next->has_timestamp) {
3867 /* Note here the division is applied to each part, then added
3868 This is to avoid potential overflow issues with a 32 time_t for dates after midpoint of this Unix time on 2004/01/04 */
3869 tp_new->timestamp = (tp_current->timestamp/2) + (tp_next->timestamp/2);
3870 tp_new->has_timestamp = TRUE;
3871 }
3872
3873 if (tp_current->speed != NAN && tp_next->speed != NAN)
3874 tp_new->speed = (tp_current->speed + tp_next->speed)/2;
3875
3876 /* TODO - improve interpolation of course, as it may not be correct.
3877 if courses in degrees are 350 + 020, the mid course more likely to be 005 (not 185)
3878 [similar applies if value is in radians] */
3879 if (tp_current->course != NAN && tp_next->course != NAN)
3880 tp_new->speed = (tp_current->course + tp_next->course)/2;
3881
3882 /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */
3883
3884 /* Insert new point into the trackpoints list after the current TP */
3885 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
3886 gint index = g_list_index ( tr->trackpoints, tp_current );
3887 if ( index > -1 ) {
3888 tr->trackpoints = g_list_insert (tr->trackpoints, tp_new, index+1 );
3889 }
3890 }
3891}
50a14534
EB
3892
3893/* to be called when last_tpl no long exists. */
3894static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
3895{
3896 if ( vtl->tpwin ) /* can't join with a non-existant TP. */
3897 vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
3898 vtl->last_tpl = NULL;
3899 vtl->last_tp_track_name = NULL;
3900}
3901
3902static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
3903{
3904 if ( vtl->tpwin )
3905 {
3906 if ( destroy)
3907 {
3908 gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
3909 vtl->tpwin = NULL;
3910 }
3911 else
3912 vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
3913 }
3914 if ( vtl->current_tpl )
3915 {
3916 vtl->current_tpl = NULL;
3917 vtl->current_tp_track_name = NULL;
3918 vik_layer_emit_update(VIK_LAYER(vtl));
3919 }
3920}
3921
3922static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
3923{
3924 g_assert ( vtl->tpwin != NULL );
3925 if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
3926 trw_layer_cancel_current_tp ( vtl, TRUE );
0d601fd4
RN
3927
3928 if ( vtl->current_tpl == NULL )
3929 return;
3930
3931 if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
50a14534 3932 {
b3538521
RN
3933 gchar *name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track_name);
3934 if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks, name ) ) )
50a14534
EB
3935 {
3936 VikTrack *tr = vik_track_new ();
3937 GList *newglist = g_list_alloc ();
3938 newglist->prev = NULL;
3939 newglist->next = vtl->current_tpl->next;
3940 newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
3941 tr->trackpoints = newglist;
3942
3943 vtl->current_tpl->next->prev = newglist; /* end old track here */
3944 vtl->current_tpl->next = NULL;
3945
3946 vtl->current_tpl = newglist; /* change tp to first of new track. */
3947 vtl->current_tp_track_name = name;
3948
3949 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
3950
e632ab42
GB
3951 tr->visible = TRUE;
3952
50a14534
EB
3953 vik_trw_layer_add_track ( vtl, name, tr );
3954 vik_layer_emit_update(VIK_LAYER(vtl));
3955 }
3956 }
3957 else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
3958 {
3959 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
3960 GList *new_tpl;
3961 g_assert(tr != NULL);
3962
3963 /* can't join with a non-existent trackpoint */
3964 vtl->last_tpl = NULL;
3965 vtl->last_tp_track_name = NULL;
3966
3967 if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
3968 {
3969 if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
3970 VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
3971
3972 tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl ); /* this nulls current_tpl->prev and next */
3973
3974 /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
3975 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track_name );
3976
3977 trw_layer_cancel_last_tp ( vtl );
3978
3979 g_free ( vtl->current_tpl->data ); /* TODO: vik_trackpoint_free() */
3980 g_list_free_1 ( vtl->current_tpl );
3981 vtl->current_tpl = new_tpl;
3982 vik_layer_emit_update(VIK_LAYER(vtl));
3983 }
3984 else
3985 {
3986 tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl );
3987 g_free ( vtl->current_tpl->data ); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
3988 g_list_free_1 ( vtl->current_tpl );
3989 trw_layer_cancel_current_tp ( vtl, FALSE );
3990 }
3991 }
3992 else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
3993 {
3994 vtl->last_tpl = vtl->current_tpl;
3995 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track_name );
3996 vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
3997 }
3998 else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
3999 {
4000 vtl->last_tpl = vtl->current_tpl;
4001 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track_name );
4002 vik_layer_emit_update(VIK_LAYER(vtl));
4003 }
4004 else if ( response == VIK_TRW_LAYER_TPWIN_JOIN )
4005 {
4006 VikTrack *tr1 = g_hash_table_lookup ( vtl->tracks, vtl->last_tp_track_name );
4007 VikTrack *tr2 = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
4008
4009 VikTrack *tr_first = tr1, *tr_last = tr2;
4010
4011 gchar *tmp;
4012
4013 if ( (!vtl->last_tpl->next) && (!vtl->current_tpl->next) ) /* both endpoints */
4014 vik_track_reverse ( tr2 ); /* reverse the second, that way second track clicked will be later. */
4015 else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->prev) )
4016 vik_track_reverse ( tr1 );
4017 else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->next) ) /* clicked startpoint, then endpoint -- concat end to start */
4018 {
4019 tr_first = tr2;
4020 tr_last = tr1;
4021 }
4022 /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
4023
4024 if ( tr_last->trackpoints ) /* deleting this part here joins them into 1 segmented track. useful but there's no place in the UI for this feature. segments should be deprecated anyway. */
4025 VIK_TRACKPOINT(tr_last->trackpoints->data)->newsegment = FALSE;
4026 tr1->trackpoints = g_list_concat ( tr_first->trackpoints, tr_last->trackpoints );
4027 tr2->trackpoints = NULL;
4028
4029 tmp = vtl->current_tp_track_name;
4030
4031 vtl->current_tp_track_name = vtl->last_tp_track_name; /* current_tp stays the same (believe it or not!) */
4032 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
4033
4034 /* if we did this before, trw_layer_delete_track would have canceled the current tp because
4035 * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
e4afc73a 4036 vik_trw_layer_delete_track ( vtl, tmp );
50a14534
EB
4037
4038 trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
4039 vik_layer_emit_update(VIK_LAYER(vtl));
4040 }
2880a1de
RN
4041 else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
4042 {
4043 trw_layer_insert_tp_after_current_tp ( vtl );
4044 vik_layer_emit_update(VIK_LAYER(vtl));
4045 }
50a14534
EB
4046 else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
4047 vik_layer_emit_update (VIK_LAYER(vtl));
4048}
4049
4050static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
4051{
4052 if ( ! vtl->tpwin )
4053 {
4054 vtl->tpwin = vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl) );
4055 g_signal_connect_swapped ( GTK_DIALOG(vtl->tpwin), "response", G_CALLBACK(trw_layer_tpwin_response), vtl );
4056 /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
4057 g_signal_connect_swapped ( vtl->tpwin, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp), vtl );
4058 gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
4059 }
4060 if ( vtl->current_tpl )
4061 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
4062 /* set layer name and TP data */
4063}
4064
941aa6e9
AF
4065/***************************************************************************
4066 ** Tool code
4067 ***************************************************************************/
50a14534 4068
941aa6e9 4069/*** Utility data structures and functions ****/
50a14534
EB
4070
4071typedef struct {
4072 gint x, y;
4073 gint closest_x, closest_y;
4074 gchar *closest_wp_name;
4075 VikWaypoint *closest_wp;
4076 VikViewport *vvp;
4077} WPSearchParams;
4078
941aa6e9
AF
4079typedef struct {
4080 gint x, y;
4081 gint closest_x, closest_y;
4082 gchar *closest_track_name;
4083 VikTrackpoint *closest_tp;
4084 VikViewport *vvp;
4085 GList *closest_tpl;
4086} TPSearchParams;
4087
50a14534
EB
4088static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
4089{
4090 gint x, y;
4091 if ( !wp->visible )
4092 return;
4093
4094 vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
59b0a97a
RN
4095
4096 // If waypoint has an image then use the image size to select
4097 if ( wp->image ) {
4098 gint slackx, slacky;
4099 slackx = wp->image_width / 2;
4100 slacky = wp->image_height / 2;
4101
4102 if ( x <= params->x + slackx && x >= params->x - slackx
4103 && y <= params->y + slacky && y >= params->y - slacky ) {
4104 params->closest_wp_name = name;
4105 params->closest_wp = wp;
4106 params->closest_x = x;
4107 params->closest_y = y;
4108 }
50a14534 4109 }
59b0a97a
RN
4110 else if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
4111 ((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */
4112 abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
4113 {
4114 params->closest_wp_name = name;
4115 params->closest_wp = wp;
4116 params->closest_x = x;
4117 params->closest_y = y;
4118 }
50a14534
EB
4119}
4120
941aa6e9 4121static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
50a14534 4122{
941aa6e9
AF
4123 GList *tpl = t->trackpoints;
4124 VikTrackpoint *tp;
50a14534 4125
941aa6e9
AF
4126 if ( !t->visible )
4127 return;
50a14534 4128
941aa6e9
AF
4129 while (tpl)
4130 {
4131 gint x, y;
4132 tp = VIK_TRACKPOINT(tpl->data);
4133
4134 vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
4135
4136 if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
4137 ((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */
4138 abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
50a14534 4139 {
941aa6e9
AF
4140 params->closest_track_name = name;
4141 params->closest_tp = tp;
4142 params->closest_tpl = tpl;
4143 params->closest_x = x;
4144 params->closest_y = y;
50a14534 4145 }
941aa6e9 4146 tpl = tpl->next;
50a14534 4147 }
941aa6e9
AF
4148}
4149
4150static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
4151{
4152 TPSearchParams params;
4153 params.x = x;
4154 params.y = y;
4155 params.vvp = vvp;
4156 params.closest_track_name = NULL;
4157 params.closest_tp = NULL;
4158 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
4159 return params.closest_tp;
50a14534
EB
4160}
4161
4162static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
4163{
4164 WPSearchParams params;
4165 params.x = x;
4166 params.y = y;
4167 params.vvp = vvp;
4168 params.closest_wp = NULL;
4169 params.closest_wp_name = NULL;
4170 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
4171 return params.closest_wp;
4172}
4173
08f14055
RN
4174// Some forward declarations
4175static void marker_begin_move ( tool_ed_t *t, gint x, gint y );
4176static void marker_moveto ( tool_ed_t *t, gint x, gint y );
4177static void marker_end_move ( tool_ed_t *t );
4178//
4179
4180static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
4181{
4182 if ( t->holding ) {
4183 VikCoord new_coord;
4184 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
4185
4186 // Here always allow snapping back to the original location
4187 // this is useful when one decides not to move the thing afterall
4188 // If one wants to move the item only a little bit then don't hold down the 'snap' key!
4189
4190 // snap to TP
4191 if ( event->state & GDK_CONTROL_MASK )
4192 {
4193 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4194 if ( tp )
4195 new_coord = tp->coord;
4196 }
4197
4198 // snap to WP
4199 if ( event->state & GDK_SHIFT_MASK )
4200 {
4201 VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4202 if ( wp )
4203 new_coord = wp->coord;
4204 }
4205
4206 gint x, y;
4207 vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
4208
4209 marker_moveto ( t, x, y );
4210
4211 return TRUE;
4212 }
4213 return FALSE;
4214}
4215
4216static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
4217{
4218 if ( t->holding && event->button == 1 )
4219 {
4220 VikCoord new_coord;
4221 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
4222
4223 // snap to TP
4224 if ( event->state & GDK_CONTROL_MASK )
4225 {
4226 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4227 if ( tp )
4228 new_coord = tp->coord;
4229 }
4230
4231 // snap to WP
4232 if ( event->state & GDK_SHIFT_MASK )
4233 {
4234 VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4235 if ( wp )
4236 new_coord = wp->coord;
4237 }
4238
4239 marker_end_move ( t );
4240
4241 // Determine if working on a waypoint or a trackpoint
4242 if ( t->is_waypoint )
4243 vtl->current_wp->coord = new_coord;
4244 else {
4245 if ( vtl->current_tpl ) {
4246 VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
4247
4248 if ( vtl->tpwin )
4249 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
4250
4251 // Don't really know what this is for but seems like it might be handy...
4252 /* can't join with itself! */
4253 trw_layer_cancel_last_tp ( vtl );
4254 }
4255 }
4256
4257 // Reset
4258 vtl->current_wp = NULL;
4259 vtl->current_wp_name = NULL;
4260 trw_layer_cancel_current_tp ( vtl, FALSE );
4261
4262 vik_layer_emit_update ( VIK_LAYER(vtl) );
4263 return TRUE;
4264 }
4265 return FALSE;
4266}
4267
77ad64fa
RN
4268/*
4269 Returns true if a waypoint or track is found near the requested event position for this particular layer
4270 The item found is automatically selected
4271 This is a tool like feature but routed via the layer interface, since it's instigated by a 'global' layer tool in vikwindow.c
4272 */
08f14055 4273static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* tet )
77ad64fa
RN
4274{
4275 if ( event->button != 1 )
4276 return FALSE;
4277
4278 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4279 return FALSE;
4280
4281 if ( !vtl->tracks_visible && !vtl->waypoints_visible )
4282 return FALSE;
4283
08f14055 4284 // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track
77ad64fa
RN
4285
4286 if (vtl->waypoints_visible) {
4287 WPSearchParams wp_params;
4288 wp_params.vvp = vvp;
4289 wp_params.x = event->x;
4290 wp_params.y = event->y;
4291 wp_params.closest_wp_name = NULL;
4292 wp_params.closest_wp = NULL;
4293
4294 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params);
4295
4296 if ( wp_params.closest_wp ) {
08f14055
RN
4297
4298 // Select
77ad64fa 4299 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_name ), TRUE );
08f14055
RN
4300
4301 // Too easy to move it so must be holding shift to start immediately moving it
4302 // or otherwise be previously selected
4303 if ( event->state & GDK_SHIFT_MASK ||
4304 vtl->current_wp == wp_params.closest_wp ) {
4305 // Put into 'move buffer'
4306 // NB vvp & vw already set in tet
4307 tet->vtl = (gpointer)vtl;
4308 tet->is_waypoint = TRUE;
4309
4310 marker_begin_move (tet, event->x, event->y);
4311 }
4312
4313 vtl->current_wp = wp_params.closest_wp;
4314 vtl->current_wp_name = wp_params.closest_wp_name;
4315
77ad64fa 4316 vik_layer_emit_update ( VIK_LAYER(vtl) );
08f14055 4317
77ad64fa
RN
4318 return TRUE;
4319 }
4320 }
4321
4322 if (vtl->tracks_visible) {
4323 TPSearchParams tp_params;
4324 tp_params.vvp = vvp;
4325 tp_params.x = event->x;
4326 tp_params.y = event->y;
4327 tp_params.closest_track_name = NULL;
4328 tp_params.closest_tp = NULL;
4329
4330 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params);
4331
4332 if ( tp_params.closest_tp ) {
08f14055
RN
4333
4334 // Always select + highlight the track
77ad64fa 4335 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, tp_params.closest_track_name ), TRUE );
08f14055
RN
4336
4337 tet->is_waypoint = FALSE;
4338
4339 // Select the Trackpoint
4340 // Can move it immediately when control held or it's the previously selected tp
4341 if ( event->state & GDK_CONTROL_MASK ||
4342 vtl->current_tpl == tp_params.closest_tpl ) {
4343 // Put into 'move buffer'
4344 // NB vvp & vw already set in tet
4345 tet->vtl = (gpointer)vtl;
4346 marker_begin_move (tet, event->x, event->y);
4347 }
4348
4349 vtl->current_tpl = tp_params.closest_tpl;
4350 vtl->current_tp_track_name = tp_params.closest_track_name;
4351
4352 if ( vtl->tpwin )
4353 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
4354
77ad64fa
RN
4355 vik_layer_emit_update ( VIK_LAYER(vtl) );
4356 return TRUE;
4357 }
4358 }
4359
4360 /* these aren't the droids you're looking for */
08f14055
RN
4361 vtl->current_wp = NULL;
4362 vtl->current_wp_name = NULL;
4363 trw_layer_cancel_current_tp ( vtl, FALSE );
4364
77ad64fa
RN
4365 return FALSE;
4366}
4367
e46f259a
RN
4368static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
4369{
4370 if ( event->button != 3 )
4371 return FALSE;
4372
4373 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4374 return FALSE;
4375
4376 if ( !vtl->tracks_visible && !vtl->waypoints_visible )
4377 return FALSE;
4378
4379 /* Post menu for the currently selected item */
4380
4381 /* See if a track is selected */
4382 VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
4383 if ( track && track->visible ) {
4384
4385 if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
4386
4387 if ( vtl->track_right_click_menu )
4388 gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
4389
4390 vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
4391
4392 vik_trw_layer_sublayer_add_menu_items ( vtl,
4393 vtl->track_right_click_menu,
4394 NULL,
4395 VIK_TRW_LAYER_SUBLAYER_TRACK,
4396 vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
4397 g_hash_table_lookup ( vtl->tracks_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
4398 vvp);
4399
4400 gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
4401
4402 return TRUE;
4403 }
4404 }
4405
4406 /* See if a waypoint is selected */
4407 VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
4408 if ( waypoint && waypoint->visible ) {
4409 if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
4410
4411 if ( vtl->wp_right_click_menu )
4412 gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
4413
4414 vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
4415 vik_trw_layer_sublayer_add_menu_items ( vtl,
4416 vtl->wp_right_click_menu,
4417 NULL,
4418 VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
4419 vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
4420 g_hash_table_lookup ( vtl->waypoints_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
4421 vvp);
4422 gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
4423
4424 return TRUE;
4425 }
4426 }
4427
4428 return FALSE;
4429}
4430
7432fddf
AF
4431/* background drawing hook, to be passed the viewport */
4432static gboolean tool_sync_done = TRUE;
4433
4434static gboolean tool_sync(gpointer data)
4435{
4436 VikViewport *vvp = data;
4437 gdk_threads_enter();
4438 vik_viewport_sync(vvp);
4439 tool_sync_done = TRUE;
4440 gdk_threads_leave();
4441 return FALSE;
4442}
4443
7432fddf
AF
4444static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
4445{
4446 t->holding = TRUE;
4447 t->gc = vik_viewport_new_gc (t->vvp, "black", 2);
4448 gdk_gc_set_function ( t->gc, GDK_INVERT );
4449 vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
4450 vik_viewport_sync(t->vvp);
4451 t->oldx = x;
4452 t->oldy = y;
4453}
4454
4455static void marker_moveto ( tool_ed_t *t, gint x, gint y )
4456{
4457 VikViewport *vvp = t->vvp;
4458 vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
4459 vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
4460 t->oldx = x;
4461 t->oldy = y;
7b203521 4462
7432fddf
AF
4463 if (tool_sync_done) {
4464 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
4465 tool_sync_done = FALSE;
4466 }
4467}
4468
4469static void marker_end_move ( tool_ed_t *t )
4470{
4471 vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
4472 g_object_unref ( t->gc );
4473 t->holding = FALSE;
4474}
4475
941aa6e9
AF
4476/*** Edit waypoint ****/
4477
4478static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp)
4479{
7432fddf
AF
4480 tool_ed_t *t = g_new(tool_ed_t, 1);
4481 t->vvp = vvp;
4482 t->holding = FALSE;
4483 return t;
941aa6e9
AF
4484}
4485
7432fddf 4486static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
50a14534
EB
4487{
4488 WPSearchParams params;
7432fddf
AF
4489 tool_ed_t *t = data;
4490 VikViewport *vvp = t->vvp;
50a14534 4491
941aa6e9
AF
4492 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4493 return FALSE;
7432fddf
AF
4494
4495 if ( t->holding ) {
4496 return TRUE;
4497 }
4498
87741170
RN
4499 if ( !vtl->vl.visible || !vtl->waypoints_visible )
4500 return FALSE;
4501
50a14534
EB
4502 if ( vtl->current_wp && vtl->current_wp->visible )
4503 {
4504 /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
4505 gint x, y;
4506 vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
4507
c75d78d7
AF
4508 if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
4509 abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
50a14534
EB
4510 {
4511 if ( event->button == 3 )
4512 vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
7432fddf
AF
4513 else {
4514 marker_begin_move(t, event->x, event->y);
4515 }
50a14534
EB
4516 return TRUE;
4517 }
4518 }
4519
4520 params.vvp = vvp;
4521 params.x = event->x;
4522 params.y = event->y;
4523 params.closest_wp_name = NULL;
4524 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
4525 params.closest_wp = NULL;
4526 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
4527 if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
4528 {
7432fddf
AF
4529 /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
4530 marker_begin_move(t, event->x, event->y);
7742da66 4531 g_critical("shouldn't be here");
7432fddf 4532 exit(1);
50a14534
EB
4533 }
4534 else if ( params.closest_wp )
4535 {
4536 if ( event->button == 3 )
4537 vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
4538 else
4539 vtl->waypoint_rightclick = FALSE;
4540
4541 vtl->current_wp = params.closest_wp;
4542 vtl->current_wp_name = params.closest_wp_name;
50a14534
EB
4543
4544 if ( params.closest_wp )
bdd1c412 4545 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ), TRUE );
50a14534
EB
4546
4547 /* could make it so don't update if old WP is off screen and new is null but oh well */
4548 vik_layer_emit_update ( VIK_LAYER(vtl) );
4549 return TRUE;
4550 }
4551
4552 vtl->current_wp = NULL;
4553 vtl->current_wp_name = NULL;
50a14534 4554 vtl->waypoint_rightclick = FALSE;
7432fddf
AF
4555 vik_layer_emit_update ( VIK_LAYER(vtl) );
4556 return FALSE;
4557}
4558
dc2c040e 4559static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
7432fddf
AF
4560{
4561 tool_ed_t *t = data;
4562 VikViewport *vvp = t->vvp;
4563
4564 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4565 return FALSE;
4566
4567 if ( t->holding ) {
4568 VikCoord new_coord;
4569 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
4570
4571 /* snap to TP */
4572 if ( event->state & GDK_CONTROL_MASK )
4573 {
4574 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4575 if ( tp )
4576 new_coord = tp->coord;
4577 }
4578
4579 /* snap to WP */
4580 if ( event->state & GDK_SHIFT_MASK )
4581 {
4582 VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4583 if ( wp && wp != vtl->current_wp )
4584 new_coord = wp->coord;
4585 }
4586
4587 {
4588 gint x, y;
4589 vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
7b203521 4590
7432fddf
AF
4591 marker_moveto ( t, x, y );
4592 }
4593 return TRUE;
4594 }
50a14534
EB
4595 return FALSE;
4596}
4597
7432fddf 4598static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
941aa6e9 4599{
7432fddf
AF
4600 tool_ed_t *t = data;
4601 VikViewport *vvp = t->vvp;
4602
941aa6e9
AF
4603 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4604 return FALSE;
7432fddf
AF
4605
4606 if ( t->holding && event->button == 1 )
941aa6e9
AF
4607 {
4608 VikCoord new_coord;
941aa6e9
AF
4609 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
4610
4611 /* snap to TP */
4612 if ( event->state & GDK_CONTROL_MASK )
4613 {
4614 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4615 if ( tp )
4616 new_coord = tp->coord;
4617 }
4618
4619 /* snap to WP */
4620 if ( event->state & GDK_SHIFT_MASK )
4621 {
4622 VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4623 if ( wp && wp != vtl->current_wp )
4624 new_coord = wp->coord;
4625 }
4626
7432fddf
AF
4627 marker_end_move ( t );
4628
941aa6e9
AF
4629 vtl->current_wp->coord = new_coord;
4630 vik_layer_emit_update ( VIK_LAYER(vtl) );
4631 return TRUE;
4632 }
4633 /* PUT IN RIGHT PLACE!!! */
7432fddf 4634 if ( event->button == 3 && vtl->waypoint_rightclick )
941aa6e9
AF
4635 {
4636 if ( vtl->wp_right_click_menu )
4f14a010 4637 g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
941aa6e9 4638 vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
50eadc64 4639 vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ), vvp );
941aa6e9
AF
4640 gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
4641 vtl->waypoint_rightclick = FALSE;
4642 }
4643 return FALSE;
4644}
4645
98f5364d
EB
4646/**** Begin track ***/
4647static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp)
4648{
4649 return vvp;
4650}
4651
4652static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
4653{
4654 vtl->current_track = NULL;
4655 return tool_new_track_click ( vtl, event, vvp );
4656}
4657
941aa6e9
AF
4658/*** New track ****/
4659
4660static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
4661{
4662 return vvp;
4663}
4664
7b203521
EB
4665typedef struct {
4666 VikTrwLayer *vtl;
4667 VikViewport *vvp;
4668 gint x1,y1,x2,y2;
4669} new_track_move_passalong_t;
4670
4671/* sync and undraw, but only when we have time */
4672static gboolean ct_sync ( gpointer passalong )
4673{
4674 new_track_move_passalong_t *p = (new_track_move_passalong_t *) passalong;
4675 vik_viewport_sync ( p->vvp );
4676 gdk_gc_set_function ( p->vtl->current_track_gc, GDK_INVERT );
4677 vik_viewport_draw_line ( p->vvp, p->vtl->current_track_gc, p->x1, p->y1, p->x2, p->y2 );
4678 gdk_gc_set_function ( p->vtl->current_track_gc, GDK_COPY );
4679 p->vtl->ct_sync_done = TRUE;
4680 g_free ( p );
4681 return FALSE;
4682}
4683
dc2c040e 4684static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
7b203521
EB
4685{
4686 /* if we haven't sync'ed yet, we don't have time to do more. */
4687 if ( vtl->ct_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
4688 GList *iter = vtl->current_track->trackpoints;
4689 new_track_move_passalong_t *passalong;
4690 gint x1, y1;
4691
4692 while ( iter->next )
4693 iter = iter->next;
4694 gdk_gc_set_function ( vtl->current_track_gc, GDK_INVERT );
4695 vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
4696 vik_viewport_draw_line ( vvp, vtl->current_track_gc, x1, y1, event->x, event->y );
4697 gdk_gc_set_function ( vtl->current_track_gc, GDK_COPY );
4698
4699 passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
4700 passalong->vtl = vtl;
4701 passalong->vvp = vvp;
4702 passalong->x1 = x1;
4703 passalong->y1 = y1;
4704 passalong->x2 = event->x;
4705 passalong->y2 = event->y;
4706
4707 /* this will sync and undraw when we have time to */
4708 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, ct_sync, passalong, NULL);
4709 vtl->ct_sync_done = FALSE;
165d30aa 4710 return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
7b203521 4711 }
165d30aa 4712 return VIK_LAYER_TOOL_ACK;
7b203521
EB
4713}
4714
777e2d4d
EB
4715static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
4716{
4717 if ( vtl->current_track && event->keyval == GDK_Escape ) {
4718 vtl->current_track = NULL;
4719 vik_layer_emit_update ( VIK_LAYER(vtl) );
4720 return TRUE;
4721 } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
4722 /* undo */
4723 if ( vtl->current_track->trackpoints )
4724 {
4725 GList *last = g_list_last(vtl->current_track->trackpoints);
4726 g_free ( last->data );
4727 vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
4728 }
4729 vik_layer_emit_update ( VIK_LAYER(vtl) );
4730 return TRUE;
4731 }
4732 return FALSE;
4733}
4734
941aa6e9 4735static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
50a14534
EB
4736{
4737 VikTrackpoint *tp;
4738
941aa6e9
AF
4739 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4740 return FALSE;
4741
50a14534
EB
4742 if ( event->button == 3 && vtl->current_track )
4743 {
4744 /* undo */
4745 if ( vtl->current_track->trackpoints )
4746 {
4747 GList *last = g_list_last(vtl->current_track->trackpoints);
4748 g_free ( last->data );
4749 vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
4750 }
4751 vik_layer_emit_update ( VIK_LAYER(vtl) );
4752 return TRUE;
4753 }
4754
4755 if ( event->type == GDK_2BUTTON_PRESS )
4756 {
4757 /* subtract last (duplicate from double click) tp then end */
4758 if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
4759 {
4760 GList *last = g_list_last(vtl->current_track->trackpoints);
4761 g_free ( last->data );
4762 vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
4763 /* undo last, then end */
4764 vtl->current_track = NULL;
4765 }
8e9c992d 4766 vik_layer_emit_update ( VIK_LAYER(vtl) );
50a14534
EB
4767 return TRUE;
4768 }
4769
4770 if ( ! vtl->current_track )
4771 {
e13ab673
RN
4772 gchar *name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
4773 if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name ) ) )
50a14534
EB
4774 {
4775 vtl->current_track = vik_track_new();
4776 vtl->current_track->visible = TRUE;
4777 vik_trw_layer_add_track ( vtl, name, vtl->current_track );
98f5364d
EB
4778
4779 /* incase it was created by begin track */
4780 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
50a14534
EB
4781 }
4782 else
4783 return TRUE;
4784 }
4785 tp = vik_trackpoint_new();
4786 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
4787
4788 /* snap to other TP */
4789 if ( event->state & GDK_CONTROL_MASK )
4790 {
4791 VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4792 if ( other_tp )
4793 tp->coord = other_tp->coord;
4794 }
4795
4796 tp->newsegment = FALSE;
4797 tp->has_timestamp = FALSE;
4798 tp->timestamp = 0;
50a14534
EB
4799 vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
4800
4801 vtl->ct_x1 = vtl->ct_x2;
4802 vtl->ct_y1 = vtl->ct_y2;
4803 vtl->ct_x2 = event->x;
4804 vtl->ct_y2 = event->y;
4805
4806 vik_layer_emit_update ( VIK_LAYER(vtl) );
4807 return TRUE;
4808}
4809
941aa6e9
AF
4810/*** New waypoint ****/
4811
4812static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
4813{
4814 return vvp;
4815}
4816
4817static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
4818{
4819 VikCoord coord;
4820 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4821 return FALSE;
4822 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
4823 if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible)
4824 vik_layer_emit_update ( VIK_LAYER(vtl) );
4825 return TRUE;
4826}
4827
4828
4829/*** Edit trackpoint ****/
4830
4831static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp)
4832{
7432fddf 4833 tool_ed_t *t = g_new(tool_ed_t, 1);
33534cd8
AF
4834 t->vvp = vvp;
4835 t->holding = FALSE;
4836 return t;
941aa6e9
AF
4837}
4838
33534cd8 4839static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
941aa6e9 4840{
7432fddf 4841 tool_ed_t *t = data;
33534cd8
AF
4842 VikViewport *vvp = t->vvp;
4843 TPSearchParams params;
941aa6e9
AF
4844 /* OUTDATED DOCUMENTATION:
4845 find 5 pixel range on each side. then put these UTM, and a pointer
4846 to the winning track name (and maybe the winning track itself), and a
4847 pointer to the winning trackpoint, inside an array or struct. pass
4848 this along, do a foreach on the tracks which will do a foreach on the
4849 trackpoints. */
4850 params.vvp = vvp;
4851 params.x = event->x;
4852 params.y = event->y;
4853 params.closest_track_name = NULL;
4854 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
4855 params.closest_tp = NULL;
4856
7432fddf
AF
4857 if ( event->button != 1 )
4858 return FALSE;
4859
941aa6e9
AF
4860 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4861 return FALSE;
4862
87741170
RN
4863 if ( !vtl->vl.visible || !vtl->tracks_visible )
4864 return FALSE;
4865
941aa6e9
AF
4866 if ( vtl->current_tpl )
4867 {
4868 /* 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.) */
4869 VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
4870 VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name));
4871 gint x, y;
4872 g_assert ( current_tr );
4873
4874 vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
4875
4876 if ( current_tr->visible &&
4877 abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
7432fddf
AF
4878 abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
4879 marker_begin_move ( t, event->x, event->y );
941aa6e9
AF
4880 return TRUE;
4881 }
4882
4883 vtl->last_tpl = vtl->current_tpl;
4884 vtl->last_tp_track_name = vtl->current_tp_track_name;
4885 }
4886
4887 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
4888
4889 if ( params.closest_tp )
4890 {
4891 vtl->current_tpl = params.closest_tpl;
4892 vtl->current_tp_track_name = params.closest_track_name;
bdd1c412 4893 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ), TRUE );
941aa6e9
AF
4894 trw_layer_tpwin_init ( vtl );
4895 vik_layer_emit_update ( VIK_LAYER(vtl) );
4896 return TRUE;
4897 }
4898
4899 /* these aren't the droids you're looking for */
4900 return FALSE;
4901}
4902
dc2c040e 4903static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
33534cd8 4904{
7432fddf 4905 tool_ed_t *t = data;
33534cd8
AF
4906 VikViewport *vvp = t->vvp;
4907
4908 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4909 return FALSE;
4910
4911 if ( t->holding )
4912 {
4913 VikCoord new_coord;
33534cd8
AF
4914 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
4915
4916 /* snap to TP */
4917 if ( event->state & GDK_CONTROL_MASK )
4918 {
4919 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4920 if ( tp && tp != vtl->current_tpl->data )
4921 new_coord = tp->coord;
4922 }
4923 // VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
7432fddf
AF
4924 {
4925 gint x, y;
4926 vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
4927 marker_moveto ( t, x, y );
4928 }
33534cd8
AF
4929
4930 return TRUE;
4931 }
4932 return FALSE;
4933}
4934
33534cd8 4935static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
941aa6e9 4936{
7432fddf 4937 tool_ed_t *t = data;
33534cd8
AF
4938 VikViewport *vvp = t->vvp;
4939
941aa6e9
AF
4940 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
4941 return FALSE;
7432fddf
AF
4942 if ( event->button != 1)
4943 return FALSE;
33534cd8 4944
7432fddf 4945 if ( t->holding ) {
941aa6e9 4946 VikCoord new_coord;
941aa6e9
AF
4947 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
4948
4949 /* snap to TP */
4950 if ( event->state & GDK_CONTROL_MASK )
4951 {
4952 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
4953 if ( tp && tp != vtl->current_tpl->data )
4954 new_coord = tp->coord;
4955 }
4956
4957 VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
4958
7432fddf 4959 marker_end_move ( t );
33534cd8 4960
941aa6e9
AF
4961 /* diff dist is diff from orig */
4962 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
4963 /* can't join with itself! */
4964 trw_layer_cancel_last_tp ( vtl );
4965
4966 vik_layer_emit_update ( VIK_LAYER(vtl) );
4967 return TRUE;
4968 }
4969 return FALSE;
4970}
4971
4972
7ff7d728
RN
4973/*** Route Finder ***/
4974static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
1eef1bde
QT
4975{
4976 return vvp;
4977}
4978
7ff7d728 4979static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
1eef1bde
QT
4980{
4981 VikCoord tmp;
0c1044e9 4982 if ( !vtl ) return FALSE;
1eef1bde 4983 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
7ff7d728 4984 if ( event->button == 3 && vtl->route_finder_current_track ) {
c3deba01 4985 VikCoord *new_end;
7ff7d728 4986 new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
c3deba01 4987 if ( new_end ) {
7ff7d728 4988 vtl->route_finder_coord = *new_end;
c3deba01
EB
4989 g_free ( new_end );
4990 vik_layer_emit_update ( VIK_LAYER(vtl) );
4991 /* remove last ' to:...' */
7ff7d728
RN
4992 if ( vtl->route_finder_current_track->comment ) {
4993 gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
4994 if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
4995 gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
4996 last_to - vtl->route_finder_current_track->comment - 1);
4997 vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
c3deba01
EB
4998 }
4999 }
5000 }
5001 }
7ff7d728 5002 else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
1eef1bde 5003 struct LatLon start, end;
533bbf34
MA
5004 gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE];
5005 gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE];
5006 gchar *url;
bddd2056 5007
7ff7d728 5008 vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
1eef1bde 5009 vik_coord_to_latlon ( &(tmp), &end );
7ff7d728 5010 vtl->route_finder_coord = tmp; /* for continuations */
bddd2056
EB
5011
5012 /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
7ff7d728
RN
5013 if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
5014 vtl->route_finder_append = TRUE; // merge tracks. keep started true.
bddd2056 5015 } else {
7ff7d728
RN
5016 vtl->route_finder_check_added_track = TRUE;
5017 vtl->route_finder_started = FALSE;
bddd2056
EB
5018 }
5019
533bbf34
MA
5020 url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING,
5021 g_ascii_dtostr (startlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lat),
5022 g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon),
5023 g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat),
5024 g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon));
ae941b4c 5025 a_babel_convert_from_url ( vtl, url, "kml", NULL, NULL );
533bbf34 5026 g_free ( url );
bddd2056
EB
5027
5028 /* see if anything was done -- a track was added or appended to */
7ff7d728 5029 if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track_name ) {
bddd2056
EB
5030 VikTrack *tr;
5031
7ff7d728 5032 tr = g_hash_table_lookup ( vtl->tracks, vtl->route_finder_added_track_name );
bddd2056
EB
5033
5034 if ( tr )
265bffa9 5035 vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
bddd2056 5036
7ff7d728
RN
5037 vtl->route_finder_current_track = tr;
5038
5039 g_free ( vtl->route_finder_added_track_name );
5040 vtl->route_finder_added_track_name = NULL;
5041 } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
5042 /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
5043 gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
5044 vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
bddd2056 5045 }
7ff7d728
RN
5046 vtl->route_finder_check_added_track = FALSE;
5047 vtl->route_finder_append = FALSE;
bddd2056 5048
1eef1bde
QT
5049 vik_layer_emit_update ( VIK_LAYER(vtl) );
5050 } else {
7ff7d728
RN
5051 vtl->route_finder_started = TRUE;
5052 vtl->route_finder_coord = tmp;
5053 vtl->route_finder_current_track = NULL;
1eef1bde 5054 }
1eef1bde
QT
5055 return TRUE;
5056}
5057
941aa6e9
AF
5058/*** Show picture ****/
5059
5060static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
5061{
5062 return vvp;
5063}
5064
5065/* Params are: vvp, event, last match found or NULL */
5066static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] )
5067{
5068 if ( wp->image && wp->visible )
5069 {
5070 gint x, y, slackx, slacky;
5071 GdkEventButton *event = (GdkEventButton *) params[1];
5072
5073 vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
5074 slackx = wp->image_width / 2;
5075 slacky = wp->image_height / 2;
5076 if ( x <= event->x + slackx && x >= event->x - slackx
5077 && y <= event->y + slacky && y >= event->y - slacky )
5078 {
5079 params[2] = wp->image; /* we've found a match. however continue searching
5080 * since we want to find the last match -- that
5081 * is, the match that was drawn last. */
5082 }
5083 }
5084}
5085
a412f3f5
RN
5086static void trw_layer_show_picture ( gpointer pass_along[6] )
5087{
5088 /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
5089#ifdef WINDOWS
5090 ShellExecute(NULL, NULL, (char *) pass_along[2], NULL, ".\\", 0);
5091#else /* WINDOWS */
5092 GError *err = NULL;
5093 gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
5094 gchar *cmd = g_strdup_printf ( "eog %s", quoted_file );
5095 g_free ( quoted_file );
5096 if ( ! g_spawn_command_line_async ( cmd, &err ) )
5097 {
5098 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch eog to open file.") );
5099 g_error_free ( err );
5100 }
5101 g_free ( cmd );
5102#endif /* WINDOWS */
5103}
5104
941aa6e9
AF
5105static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
5106{
5107 gpointer params[3] = { vvp, event, NULL };
5108 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
5109 return FALSE;
5110 g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
5111 if ( params[2] )
5112 {
a412f3f5
RN
5113 static gpointer pass_along[6];
5114 pass_along[0] = vtl;
5115 pass_along[5] = params[2];
5116 trw_layer_show_picture ( pass_along );
941aa6e9
AF
5117 return TRUE; /* found a match */
5118 }
5119 else
5120 return FALSE; /* go through other layers, searching for a match */
5121}
5122
5123/***************************************************************************
5124 ** End tool code
5125 ***************************************************************************/
5126
5127
5128
5129
5130
50a14534
EB
5131static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
5132{
5133 if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
5134 *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
5135}
5136
91822ddd
RN
5137/* Structure for thumbnail creating data used in the background thread */
5138typedef struct {
5139 VikTrwLayer *vtl; // Layer needed for redrawing
5140 GSList *pics; // Image list
5141} thumbnail_create_thread_data;
5142
5143static int create_thumbnails_thread ( thumbnail_create_thread_data *tctd, gpointer threaddata )
50a14534 5144{
91822ddd
RN
5145 guint total = g_slist_length(tctd->pics), done = 0;
5146 while ( tctd->pics )
50a14534 5147 {
91822ddd 5148 a_thumbnails_create ( (gchar *) tctd->pics->data );
54861848
GB
5149 int result = a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
5150 if ( result != 0 )
5151 return -1; /* Abort thread */
5152
91822ddd 5153 tctd->pics = tctd->pics->next;
50a14534 5154 }
91822ddd
RN
5155
5156 // Redraw to show the thumbnails as they are now created
5157 gdk_threads_enter();
5158 if ( IS_VIK_LAYER(tctd->vtl) )
5159 vik_layer_emit_update ( VIK_LAYER(tctd->vtl) );
5160 gdk_threads_leave();
5161
17c8aefa 5162 return 0;
50a14534
EB
5163}
5164
91822ddd 5165static void thumbnail_create_thread_free ( thumbnail_create_thread_data *tctd )
50a14534 5166{
91822ddd 5167 while ( tctd->pics )
50a14534 5168 {
91822ddd
RN
5169 g_free ( tctd->pics->data );
5170 tctd->pics = g_slist_delete_link ( tctd->pics, tctd->pics );
50a14534 5171 }
91822ddd 5172 g_free ( tctd );
50a14534
EB
5173}
5174
5175static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
5176{
5177 if ( ! vtl->has_verified_thumbnails )
5178 {
5179 GSList *pics = NULL;
5180 g_hash_table_foreach ( vtl->waypoints, (GHFunc) image_wp_make_list, &pics );
5181 if ( pics )
5182 {
5183 gint len = g_slist_length ( pics );
4c77d5e0 5184 gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
91822ddd
RN
5185 thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
5186 tctd->vtl = vtl;
5187 tctd->pics = pics;
5188 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5189 tmp,
5190 (vik_thr_func) create_thumbnails_thread,
5191 tctd,
5192 (vik_thr_free_func) thumbnail_create_thread_free,
5193 NULL,
5194 len );
50a14534
EB
5195 g_free ( tmp );
5196 }
5197 }
5198}
5199
5200VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
5201{
5202 return vtl->coord_mode;
5203}
5204
5205
5206
5207static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode )
5208{
5209 vik_coord_convert ( &(wp->coord), *dest_mode );
5210}
5211
5212static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode )
5213{
5214 vik_track_convert ( tr, *dest_mode );
5215}
5216
5217static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode )
5218{
5219 if ( vtl->coord_mode != dest_mode )
5220 {
5221 vtl->coord_mode = dest_mode;
5222 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_convert, &dest_mode );
5223 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
5224 }
5225}
e4afc73a
EB
5226
5227VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, gchar *name )
5228{
5229 return g_hash_table_lookup ( vtl->waypoints, name );
5230}
5231
f7f8a0a6 5232VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name )
e4afc73a
EB
5233{
5234 return g_hash_table_lookup ( vtl->tracks, name );
5235}
20c7a3a0 5236
2cebc318 5237static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection)
20c7a3a0
QT
5238{
5239 vtl->menu_selection = selection;
5240}
5241
5242static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl)
5243{
5244 return(vtl->menu_selection);
5245}
5246
7114e879
QT
5247/* ----------- Downloading maps along tracks --------------- */
5248
5249static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
5250{
5251 /* TODO: calculating based on current size of viewport */
5252 const gdouble w_at_zoom_0_125 = 0.0013;
5253 const gdouble h_at_zoom_0_125 = 0.0011;
5254 gdouble zoom_factor = zoom_level/0.125;
5255
5256 wh->lat = h_at_zoom_0_125 * zoom_factor;
5257 wh->lon = w_at_zoom_0_125 * zoom_factor;
5258
5259 return 0; /* all OK */
5260}
5261
35e22ed8
QT
5262static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
5263{
5264 if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
5265 (dist->lat >= ABS(to->north_south - from->north_south)))
5266 return NULL;
5267
5268 VikCoord *coord = g_malloc(sizeof(VikCoord));
5269 coord->mode = VIK_COORD_LATLON;
5270
5271 if (ABS(gradient) < 1) {
5272 if (from->east_west > to->east_west)
5273 coord->east_west = from->east_west - dist->lon;
5274 else
5275 coord->east_west = from->east_west + dist->lon;
5276 coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
5277 } else {
5278 if (from->north_south > to->north_south)
5279 coord->north_south = from->north_south - dist->lat;
5280 else
5281 coord->north_south = from->north_south + dist->lat;
5282 coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
5283 }
5284
5285 return coord;
5286}
5287
5288static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
5289{
5290 /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
5291 gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
5292
5293 VikCoord *next = from;
5294 while (TRUE) {
5295 if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
5296 break;
5297 list = g_list_prepend(list, next);
5298 }
5299
5300 return list;
5301}
5302
7114e879
QT
5303void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
5304{
5305 typedef struct _Rect {
5306 VikCoord tl;
5307 VikCoord br;
35e22ed8 5308 VikCoord center;
7114e879 5309 } Rect;
35e22ed8 5310#define GLRECT(iter) ((Rect *)((iter)->data))
7114e879
QT
5311
5312 struct LatLon wh;
35e22ed8 5313 GList *rects_to_download = NULL;
7114e879
QT
5314 GList *rect_iter;
5315
5316 if (get_download_area_width(vvp, zoom_level, &wh))
5317 return;
5318
5319 GList *iter = tr->trackpoints;
35e22ed8
QT
5320 if (!iter)
5321 return;
7114e879
QT
5322
5323 gboolean new_map = TRUE;
5324 VikCoord *cur_coord, tl, br;
5325 Rect *rect;
7114e879
QT
5326 while (iter) {
5327 cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
5328 if (new_map) {
5329 vik_coord_set_area(cur_coord, &wh, &tl, &br);
5330 rect = g_malloc(sizeof(Rect));
5331 rect->tl = tl;
5332 rect->br = br;
35e22ed8
QT
5333 rect->center = *cur_coord;
5334 rects_to_download = g_list_prepend(rects_to_download, rect);
7114e879
QT
5335 new_map = FALSE;
5336 iter = iter->next;
5337 continue;
5338 }
5339 gboolean found = FALSE;
35e22ed8
QT
5340 for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
5341 if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
7114e879
QT
5342 found = TRUE;
5343 break;
5344 }
5345 }
5346 if (found)
5347 iter = iter->next;
5348 else
5349 new_map = TRUE;
5350 }
35e22ed8 5351
35e22ed8 5352 GList *fillins = NULL;
b1e57d16
RN
5353 /* 'fillin' doesn't work in UTM mode - potentially ending up in massive loop continually allocating memory - hence don't do it */
5354 /* seems that ATM the function get_next_coord works only for LATLON */
5355 if ( cur_coord->mode == VIK_COORD_LATLON ) {
5356 /* fill-ins for far apart points */
5357 GList *cur_rect, *next_rect;
5358 for (cur_rect = rects_to_download;
5359 (next_rect = cur_rect->next) != NULL;
5360 cur_rect = cur_rect->next) {
5361 if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
5362 (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
5363 fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
5364 }
35e22ed8 5365 }
3cbbb49e
GB
5366 } else
5367 g_message("%s: this feature works only in Mercator mode", __FUNCTION__);
35e22ed8
QT
5368
5369 if (fillins) {
5370 GList *iter = fillins;
5371 while (iter) {
5372 cur_coord = (VikCoord *)(iter->data);
5373 vik_coord_set_area(cur_coord, &wh, &tl, &br);
5374 rect = g_malloc(sizeof(Rect));
5375 rect->tl = tl;
5376 rect->br = br;
5377 rect->center = *cur_coord;
5378 rects_to_download = g_list_prepend(rects_to_download, rect);
5379 iter = iter->next;
5380 }
5381 }
5382
5383 for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
7114e879
QT
5384 maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
5385 }
5386
35e22ed8
QT
5387 if (fillins) {
5388 for (iter = fillins; iter; iter = iter->next)
5389 g_free(iter->data);
5390 g_list_free(fillins);
5391 }
5392 if (rects_to_download) {
5393 for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
5394 g_free(rect_iter->data);
5395 g_list_free(rects_to_download);
5396 }
7114e879
QT
5397}
5398
6bb72350 5399static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
7114e879
QT
5400{
5401 VikMapsLayer *vml;
5402 gint selected_map, default_map;
5403 gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
5404 gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
5405 gint selected_zoom, default_zoom;
5406 int i,j;
5407
5408
5409 VikTrwLayer *vtl = pass_along[0];
5410 VikLayersPanel *vlp = pass_along[1];
5411 VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
5412 VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
5413
aa7ed888 5414 GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types
7114e879
QT
5415 int num_maps = g_list_length(vmls);
5416
5417 if (!num_maps) {
4c77d5e0 5418 a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR, _("No map layer in use. Create one first"), NULL);
7114e879
QT
5419 return;
5420 }
5421
5422 gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
5423 VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
5424
5425 gchar **np = map_names;
5426 VikMapsLayer **lp = map_layers;
5427 for (i = 0; i < num_maps; i++) {
5428 gboolean dup = FALSE;
5429 vml = (VikMapsLayer *)(vmls->data);
5430 for (j = 0; j < i; j++) { /* no duplicate allowed */
5431 if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) {
5432 dup = TRUE;
5433 break;
5434 }
5435 }
5436 if (!dup) {
5437 *lp++ = vml;
5438 *np++ = vik_maps_layer_get_map_label(vml);
5439 }
5440 vmls = vmls->next;
5441 }
5442 *lp = NULL;
5443 *np = NULL;
5444 num_maps = lp - map_layers;
5445
5446 for (default_map = 0; default_map < num_maps; default_map++) {
5447 /* TODO: check for parent layer's visibility */
5448 if (VIK_LAYER(map_layers[default_map])->visible)
5449 break;
5450 }
5451 default_map = (default_map == num_maps) ? 0 : default_map;
5452
5453 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
5454 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
5455 if (cur_zoom == zoom_vals[default_zoom])
5456 break;
5457 }
5458 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
5459
5460 if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom))
5461 goto done;
5462
5463 vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
5464
5465done:
5466 for (i = 0; i < num_maps; i++)
5467 g_free(map_names[i]);
5468 g_free(map_names);
5469 g_free(map_layers);
5470
5471 g_list_free(vmls);
5472
5473}
0c1044e9 5474
a8fe53f8
EB
5475/**** lowest waypoint number calculation ***/
5476static gint highest_wp_number_name_to_number(const gchar *name) {
5477 if ( strlen(name) == 3 ) {
5478 int n = atoi(name);
5479 if ( n < 100 && name[0] != '0' )
5480 return -1;
5481 if ( n < 10 && name[0] != '0' )
5482 return -1;
5483 return n;
5484 }
5485 return -1;
5486}
5487
5488
5489static void highest_wp_number_reset(VikTrwLayer *vtl)
5490{
5491 vtl->highest_wp_number = -1;
5492}
5493
5494static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name)
5495{
5496 /* if is bigger that top, add it */
5497 gint new_wp_num = highest_wp_number_name_to_number(new_wp_name);
5498 if ( new_wp_num > vtl->highest_wp_number )
5499 vtl->highest_wp_number = new_wp_num;
5500}
5501
5502static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name)
5503{
5504 /* if wasn't top, do nothing. if was top, count backwards until we find one used */
5505 gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
5506 if ( vtl->highest_wp_number == old_wp_num ) {
5507 gchar buf[4];
5508 vtl->highest_wp_number --;
5509
5510 g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
5511 /* search down until we find something that *does* exist */
5512
3ce17b61 5513 while ( vtl->highest_wp_number > 0 && ! g_hash_table_lookup ( vtl->waypoints, buf ) ) {
a8fe53f8
EB
5514 vtl->highest_wp_number --;
5515 g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
5516 }
5517 }
5518}
5519
5520/* get lowest unused number */
5521static gchar *highest_wp_number_get(VikTrwLayer *vtl)
5522{
5523 gchar buf[4];
5524 if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 )
3ce17b61 5525 return NULL;
a8fe53f8
EB
5526 g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 );
5527 return g_strdup(buf);
5528}