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