]> git.street.me.uk Git - andy/viking.git/blame - src/viktrwlayer.c
Sort waypoints in GPX output
[andy/viking.git] / src / viktrwlayer.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#define WAYPOINT_FONT "Sans 8"
23
24/* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
25/* viktrwlayer.c -- 2200 lines can make a difference in the state of things */
26
3e7553ae
GB
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
50a14534 31#include "viking.h"
7114e879 32#include "vikmapslayer.h"
50a14534
EB
33#include "viktrwlayer_pixmap.h"
34#include "viktrwlayer_tpwin.h"
35#include "viktrwlayer_propwin.h"
acaf7113 36#include "garminsymbols.h"
50a14534
EB
37#include "thumbnails.h"
38#include "background.h"
911400b5 39#include "gpx.h"
e0b0b9c1 40#include "babel.h"
ad0a8c2d
EB
41#include "dem.h"
42#include "dems.h"
7567b54c 43#include "googlesearch.h"
3e7553ae
GB
44#ifdef VIK_CONFIG_OPENSTREETMAP
45#include "osm-traces.h"
46#endif
28c82d8b 47#include "acquire.h"
7d02a0b0 48#include "util.h"
50a14534 49
bce3a7b0
EB
50#include "icons/icons.h"
51
50a14534
EB
52#include <math.h>
53#include <string.h>
54#include <stdlib.h>
55#include <ctype.h>
56
777e2d4d 57#include <gdk/gdkkeysyms.h>
4c77d5e0 58#include <glib/gi18n.h>
777e2d4d 59
090cae39
GB
60/* Relax some dependencies */
61#if ! GLIB_CHECK_VERSION(2,12,0)
62static gboolean return_true (gpointer a, gpointer b, gpointer c) { return TRUE; }
63static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
64#endif
65
1eef1bde 66#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%f,%f to %f,%f&output=js\" 2>/dev/null)"
50a14534
EB
67#define VIK_TRW_LAYER_TRACK_GC 13
68#define VIK_TRW_LAYER_TRACK_GC_RATES 10
69#define VIK_TRW_LAYER_TRACK_GC_MIN 0
70#define VIK_TRW_LAYER_TRACK_GC_MAX 11
71#define VIK_TRW_LAYER_TRACK_GC_BLACK 12
72
73#define DRAWMODE_BY_TRACK 0
74#define DRAWMODE_BY_VELOCITY 1
75#define DRAWMODE_ALL_BLACK 2
76
77#define POINTS 1
78#define LINES 2
79
80/* this is how it knows when you click if you are clicking close to a trackpoint. */
81#define TRACKPOINT_SIZE_APPROX 5
82#define WAYPOINT_SIZE_APPROX 5
83
b42a25ba
EB
84#define MIN_STOP_LENGTH 15
85#define MAX_STOP_LENGTH 86400
86#define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
87 /* this is multiplied by user-inputted value from 1-100. */
50a14534
EB
88enum {
89VIK_TRW_LAYER_SUBLAYER_TRACKS,
90VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
91VIK_TRW_LAYER_SUBLAYER_TRACK,
92VIK_TRW_LAYER_SUBLAYER_WAYPOINT
93};
94
95enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
96
97struct _VikTrwLayer {
98 VikLayer vl;
99 GHashTable *tracks;
100 GHashTable *tracks_iters;
101 GHashTable *waypoints_iters;
102 GHashTable *waypoints;
103 GtkTreeIter waypoints_iter, tracks_iter;
104 gboolean tracks_visible, waypoints_visible;
105 guint8 drawmode;
106 guint8 drawpoints;
b42a25ba
EB
107 guint8 drawelevation;
108 guint8 elevation_factor;
109 guint8 drawstops;
110 guint32 stop_length;
50a14534
EB
111 guint8 drawlines;
112 guint8 line_thickness;
113 guint8 bg_line_thickness;
114
115 guint8 wp_symbol;
116 guint8 wp_size;
ea3933fc 117 gboolean wp_draw_symbols;
50a14534
EB
118
119 gdouble velocity_min, velocity_max;
120 GArray *track_gc;
121 guint16 track_gc_iter;
8e9c992d 122 GdkGC *current_track_gc;
50a14534
EB
123 GdkGC *track_bg_gc;
124 GdkGC *waypoint_gc;
125 GdkGC *waypoint_text_gc;
126 GdkGC *waypoint_bg_gc;
127 GdkFont *waypoint_font;
128 VikTrack *current_track;
129 guint16 ct_x1, ct_y1, ct_x2, ct_y2;
7b203521
EB
130 gboolean ct_sync_done;
131
50a14534
EB
132
133 VikCoordMode coord_mode;
134
135 /* wp editing tool */
136 VikWaypoint *current_wp;
137 gchar *current_wp_name;
138 gboolean moving_wp;
139 gboolean waypoint_rightclick;
140
141 /* track editing tool */
142 GList *current_tpl;
143 gchar *current_tp_track_name;
144 VikTrwLayerTpwin *tpwin;
145
146 /* weird hack for joining tracks */
147 GList *last_tpl;
148 gchar *last_tp_track_name;
149
150 /* track editing tool -- more specifically, moving tps */
151 gboolean moving_tp;
152
1eef1bde
QT
153 /* magic scissors tool */
154 gboolean magic_scissors_started;
155 VikCoord magic_scissors_coord;
bddd2056
EB
156 gboolean magic_scissors_check_added_track;
157 gchar *magic_scissors_added_track_name;
158 VikTrack *magic_scissors_current_track;
159 gboolean magic_scissors_append;
1eef1bde 160
50a14534
EB
161 gboolean drawlabels;
162 gboolean drawimages;
163 guint8 image_alpha;
164 GQueue *image_cache;
165 guint8 image_size;
166 guint16 image_cache_size;
167
168 /* for waypoint text */
169 PangoLayout *wplabellayout;
170
171 gboolean has_verified_thumbnails;
172
173 GtkMenu *wp_right_click_menu;
174
20c7a3a0
QT
175 /* menu */
176 VikStdLayerMenuItem menu_selection;
177
50a14534
EB
178};
179
180/* A caached waypoint image. */
181typedef struct {
182 GdkPixbuf *pixbuf;
183 gchar *image; /* filename */
184} CachedPixbuf;
185
186struct DrawingParams {
187 VikViewport *vp;
188 VikTrwLayer *vtl;
189 gdouble xmpp, ympp;
190 guint16 width, height;
191 const VikCoord *center;
192 gint track_gc_iter;
193 gboolean one_zone, lat_lon;
194 gdouble ce1, ce2, cn1, cn2;
195};
196
2cebc318 197static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16);
20c7a3a0
QT
198static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl);
199
33534cd8 200static void trw_layer_delete_item ( gpointer *pass_along );
2cebc318
QT
201static void trw_layer_copy_item_cb( gpointer *pass_along);
202static void trw_layer_cut_item_cb( gpointer *pass_along);
33534cd8 203
50a14534
EB
204static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] );
205static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] );
206
207static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
208static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
209
210static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 );
211static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp );
212static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp );
213
214static void goto_coord ( VikLayersPanel *vlp, const VikCoord *coord );
215static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] );
216static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
111fa174
AF
217static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
218static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
7114e879 219static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]);
50a14534
EB
220static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
221static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type );
222static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
223static void trw_layer_new_wp ( gpointer lav[2] );
224
225/* pop-up items */
226static void trw_layer_properties_item ( gpointer pass_along[5] );
227static void trw_layer_goto_waypoint ( gpointer pass_along[5] );
228static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] );
229
230static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[4] );
231static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] );
232static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
233
50a14534 234
911400b5
AF
235static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len );
236static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp );
237
50a14534
EB
238static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp );
239static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id );
240
33534cd8 241static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
ddc47a46
AF
242static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
243static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
50a14534 244static void trw_layer_free_copied_item ( gint subtype, gpointer item );
70a23263 245static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
50a14534 246
50a14534
EB
247static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl );
248static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
249static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
250static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
50a14534 251
941aa6e9 252static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
33534cd8
AF
253static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
254static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
255static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
941aa6e9
AF
256static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp);
257static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
258static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp);
7432fddf
AF
259static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
260static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
261static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
98f5364d
EB
262static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp);
263static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
941aa6e9
AF
264static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
265static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
165d30aa 266static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
777e2d4d 267static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp );
941aa6e9
AF
268static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
269static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
1eef1bde
QT
270static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp);
271static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
272
50a14534
EB
273
274static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str );
275
276static void cached_pixbuf_free ( CachedPixbuf *cp );
277static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
278static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp );
279
280static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
281static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
282
283static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
284
e890a6e6 285static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name);
ddc47a46
AF
286static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode );
287static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode );
e890a6e6 288
50a14534 289static VikToolInterface trw_layer_tools[] = {
4c77d5e0 290 { N_("Create Waypoint"), (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL,
777e2d4d 291 (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL, &cursor_addwp },
941aa6e9 292
4c77d5e0 293 { N_("Create Track"), (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL,
777e2d4d
EB
294 (VikToolMouseFunc) tool_new_track_click, (VikToolMouseFunc) tool_new_track_move, NULL,
295 (VikToolKeyFunc) tool_new_track_key_press, &cursor_addtr },
50a14534 296
4c77d5e0 297 { N_("Begin Track"), (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL,
777e2d4d 298 (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL, &cursor_begintr },
98f5364d 299
4c77d5e0 300 { N_("Edit Waypoint"), (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL,
7432fddf
AF
301 (VikToolMouseFunc) tool_edit_waypoint_click,
302 (VikToolMouseFunc) tool_edit_waypoint_move,
777e2d4d 303 (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, &cursor_edwp },
941aa6e9 304
4c77d5e0 305 { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
33534cd8
AF
306 (VikToolMouseFunc) tool_edit_trackpoint_click,
307 (VikToolMouseFunc) tool_edit_trackpoint_move,
777e2d4d 308 (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, &cursor_edtr },
941aa6e9 309
4c77d5e0 310 { N_("Show Picture"), (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL,
777e2d4d 311 (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL, &cursor_showpic },
1eef1bde 312
4c77d5e0 313 { N_("Magic Scissors"), (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL,
777e2d4d 314 (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, (VikToolKeyFunc) NULL, &cursor_iscissors },
941aa6e9 315};
8e9c992d 316enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
50a14534
EB
317
318/****** PARAMETERS ******/
319
4c77d5e0 320static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
55906514 321enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
50a14534 322
4c77d5e0
GB
323static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 };
324static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
50a14534 325
b42a25ba 326
50a14534
EB
327static VikLayerParamScale params_scales[] = {
328 /* min max step digits */
329 { 1, 10, 1, 0 }, /* line_thickness */
330 { 0.0, 99.0, 1, 2 }, /* velocity_min */
331 { 1.0, 100.0, 1.0, 2 }, /* velocity_max */
332 /* 5 * step == how much to turn */
333 { 16, 128, 3.2, 0 }, /* image_size */
334 { 0, 255, 5, 0 }, /* image alpha */
335 { 5, 500, 5, 0 }, /* image cache_size */
336 { 0, 8, 1, 0 }, /* image cache_size */
337 { 1, 64, 1, 0 }, /* wpsize */
b42a25ba
EB
338 { MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1, 0 }, /* stop_length */
339 { 1, 100, 1, 0 }, /* stop_length */
50a14534
EB
340};
341
342VikLayerParam trw_layer_params[] = {
343 { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
344 { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES },
345
4c77d5e0
GB
346 { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL },
347 { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON },
348 { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON },
349 { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON },
350 { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 9 },
351
352 { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON },
353 { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 },
354
355 { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
356 { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 },
357 { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, 0 },
358 { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Min Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
359 { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Max Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 },
360
361 { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON },
362 { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
363 { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, 0 },
364 { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, 0 },
365 { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, 0 },
366 { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL },
367 { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 },
368 { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON },
369
370 { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON },
371 { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 3 },
372 { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 4 },
373 { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
50a14534
EB
374};
375
55906514 376enum { 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
377
378/*** TO ADD A PARAM:
379 *** 1) Add to trw_layer_params and enumeration
380 *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
ad0a8c2d 381 ***/
50a14534
EB
382
383/****** END PARAMETERS ******/
384
385VikLayerInterface vik_trw_layer_interface = {
386 "TrackWaypoint",
387 &trwlayer_pixbuf,
388
389 trw_layer_tools,
390 sizeof(trw_layer_tools) / sizeof(VikToolInterface),
391
392 trw_layer_params,
393 NUM_PARAMS,
394 params_groups, /* params_groups */
395 sizeof(params_groups)/sizeof(params_groups[0]), /* number of groups */
396
5a4a28bf
QT
397 VIK_MENU_ITEM_ALL,
398
50a14534
EB
399 (VikLayerFuncCreate) vik_trw_layer_create,
400 (VikLayerFuncRealize) vik_trw_layer_realize,
401 (VikLayerFuncPostRead) trw_layer_verify_thumbnails,
402 (VikLayerFuncFree) vik_trw_layer_free,
403
404 (VikLayerFuncProperties) NULL,
405 (VikLayerFuncDraw) vik_trw_layer_draw,
406 (VikLayerFuncChangeCoordMode) trw_layer_change_coord_mode,
407
20c7a3a0
QT
408 (VikLayerFuncSetMenuItemsSelection) vik_trw_layer_set_menu_selection,
409 (VikLayerFuncGetMenuItemsSelection) vik_trw_layer_get_menu_selection,
410
50a14534
EB
411 (VikLayerFuncAddMenuItems) vik_trw_layer_add_menu_items,
412 (VikLayerFuncSublayerAddMenuItems) vik_trw_layer_sublayer_add_menu_items,
413
414 (VikLayerFuncSublayerRenameRequest) vik_trw_layer_sublayer_rename_request,
415 (VikLayerFuncSublayerToggleVisible) vik_trw_layer_sublayer_toggle_visible,
416
911400b5
AF
417 (VikLayerFuncMarshall) trw_layer_marshall,
418 (VikLayerFuncUnmarshall) trw_layer_unmarshall,
50a14534
EB
419
420 (VikLayerFuncSetParam) trw_layer_set_param,
421 (VikLayerFuncGetParam) trw_layer_get_param,
422
423 (VikLayerFuncReadFileData) a_gpspoint_read_file,
424 (VikLayerFuncWriteFileData) a_gpspoint_write_file,
425
33534cd8 426 (VikLayerFuncDeleteItem) trw_layer_del_item,
50a14534
EB
427 (VikLayerFuncCopyItem) trw_layer_copy_item,
428 (VikLayerFuncPasteItem) trw_layer_paste_item,
429 (VikLayerFuncFreeCopiedItem) trw_layer_free_copied_item,
70a23263
AF
430
431 (VikLayerFuncDragDropRequest) trw_layer_drag_drop_request,
50a14534
EB
432};
433
434/* for copy & paste (I think?) */
435typedef struct {
ddc47a46
AF
436 guint len;
437 guint8 data[0];
438 // gchar *name;
439 // VikWaypoint *wp;
440} FlatItem;
50a14534
EB
441
442GType vik_trw_layer_get_type ()
443{
444 static GType vtl_type = 0;
445
446 if (!vtl_type)
447 {
448 static const GTypeInfo vtl_info =
449 {
450 sizeof (VikTrwLayerClass),
451 NULL, /* base_init */
452 NULL, /* base_finalize */
453 NULL, /* class init */
454 NULL, /* class_finalize */
455 NULL, /* class_data */
456 sizeof (VikTrwLayer),
457 0,
458 NULL /* instance init */
459 };
460 vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 );
461 }
462
463 return vtl_type;
464}
465
33534cd8
AF
466static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
467{
468 static gpointer pass_along[5];
469 if (!sublayer) {
470 return;
471 }
472
473 pass_along[0] = vtl;
474 pass_along[1] = NULL;
475 pass_along[2] = (gpointer) subtype;
476 pass_along[3] = sublayer;
477 pass_along[4] = NULL;
478
479 trw_layer_delete_item ( pass_along );
480}
50a14534 481
2cebc318
QT
482static void trw_layer_copy_item_cb( gpointer pass_along[5])
483{
484 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
485 gint subtype = (gint)pass_along[2];
486 gpointer * sublayer = pass_along[3];
487 guint8 *data = NULL;
488 guint len;
489
490 trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
491
492 if (data) {
493 a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
494 subtype, len, data);
495 }
496}
497
498static void trw_layer_cut_item_cb( gpointer pass_along[5])
499{
500 trw_layer_copy_item_cb(pass_along);
501 trw_layer_delete_item(pass_along);
502}
503
ddc47a46 504static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
50a14534 505{
ddc47a46
AF
506 FlatItem *fi;
507 guint8 *id;
508 guint il;
509
510 if (!sublayer) {
511 *item = NULL;
512 return;
50a14534 513 }
ddc47a46
AF
514
515 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
50a14534 516 {
ddc47a46
AF
517 vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
518 } else {
519 vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
50a14534 520 }
ddc47a46
AF
521
522 *len = sizeof(FlatItem) + strlen(sublayer) + 1 + il;
523 fi = g_malloc ( *len );
524 fi->len = strlen(sublayer) + 1;
525 memcpy(fi->data, sublayer, fi->len);
526 memcpy(fi->data + fi->len, id, il);
527 g_free(id);
528 *item = (guint8 *)fi;
50a14534
EB
529}
530
ddc47a46 531static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len )
50a14534 532{
ddc47a46
AF
533 FlatItem *fi = (FlatItem *) item;
534
535 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && fi )
50a14534 536 {
ddc47a46
AF
537 VikWaypoint *w;
538 gchar *name;
539
540 name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, (gchar *)fi->data);
541 w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
542 vik_trw_layer_add_waypoint ( vtl, name, w );
543 waypoint_convert(name, w, &vtl->coord_mode);
50a14534
EB
544 return TRUE;
545 }
ddc47a46 546 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi )
50a14534 547 {
ddc47a46
AF
548 VikTrack *t;
549 gchar *name;
550 name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, (gchar *)fi->data);
551 t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
552 vik_trw_layer_add_track ( vtl, name, t );
553 track_convert(name, t, &vtl->coord_mode);
50a14534
EB
554 return TRUE;
555 }
556 return FALSE;
557}
558
559static void trw_layer_free_copied_item ( gint subtype, gpointer item )
560{
ddc47a46
AF
561 if (item) {
562 g_free(item);
50a14534
EB
563 }
564}
565
50a14534
EB
566static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp )
567{
568 switch ( id )
569 {
570 case PARAM_TV: vtl->tracks_visible = data.b; break;
571 case PARAM_WV: vtl->waypoints_visible = data.b; break;
572 case PARAM_DM: vtl->drawmode = data.u; break;
573 case PARAM_DP: vtl->drawpoints = data.b; break;
b42a25ba
EB
574 case PARAM_DE: vtl->drawelevation = data.b; break;
575 case PARAM_DS: vtl->drawstops = data.b; break;
50a14534 576 case PARAM_DL: vtl->drawlines = data.b; break;
b42a25ba
EB
577 case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
578 vtl->stop_length = data.u;
579 break;
580 case PARAM_EF: if ( data.u >= 1 && data.u <= 100 )
581 vtl->elevation_factor = data.u;
582 break;
50a14534
EB
583 case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness )
584 {
585 vtl->line_thickness = data.u;
586 trw_layer_new_track_gcs ( vtl, vp );
587 }
588 break;
589 case PARAM_BLT: if ( data.u > 0 && data.u <= 8 && data.u != vtl->bg_line_thickness )
590 {
591 vtl->bg_line_thickness = data.u;
592 trw_layer_new_track_gcs ( vtl, vp );
593 }
594 break;
595 case PARAM_VMIN: vtl->velocity_min = data.d; break;
596 case PARAM_VMAX: vtl->velocity_max = data.d; break;
597 case PARAM_TBGC: gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(data.c)); break;
598 case PARAM_DLA: vtl->drawlabels = data.b; break;
599 case PARAM_DI: vtl->drawimages = data.b; break;
600 case PARAM_IS: if ( data.u != vtl->image_size )
601 {
602 vtl->image_size = data.u;
603 g_list_foreach ( vtl->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
604 g_queue_free ( vtl->image_cache );
605 vtl->image_cache = g_queue_new ();
606 }
607 break;
608 case PARAM_IA: vtl->image_alpha = data.u; break;
609 case PARAM_ICS: vtl->image_cache_size = data.u;
610 while ( vtl->image_cache->length > vtl->image_cache_size ) /* if shrinking cache_size, free pixbuf ASAP */
611 cached_pixbuf_free ( g_queue_pop_tail ( vtl->image_cache ) );
612 break;
613 case PARAM_WPC: gdk_gc_set_rgb_fg_color(vtl->waypoint_gc, &(data.c)); break;
614 case PARAM_WPTC: gdk_gc_set_rgb_fg_color(vtl->waypoint_text_gc, &(data.c)); break;
615 case PARAM_WPBC: gdk_gc_set_rgb_fg_color(vtl->waypoint_bg_gc, &(data.c)); break;
616 case PARAM_WPBA: gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY ); break;
617 case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
618 case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
ea3933fc 619 case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
50a14534
EB
620 }
621 return TRUE;
622}
623
624static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id )
625{
626 VikLayerParamData rv;
627 switch ( id )
628 {
629 case PARAM_TV: rv.b = vtl->tracks_visible; break;
630 case PARAM_WV: rv.b = vtl->waypoints_visible; break;
631 case PARAM_DM: rv.u = vtl->drawmode; break;
632 case PARAM_DP: rv.b = vtl->drawpoints; break;
b42a25ba
EB
633 case PARAM_DE: rv.b = vtl->drawelevation; break;
634 case PARAM_EF: rv.u = vtl->elevation_factor; break;
635 case PARAM_DS: rv.b = vtl->drawstops; break;
636 case PARAM_SL: rv.u = vtl->stop_length; break;
50a14534
EB
637 case PARAM_DL: rv.b = vtl->drawlines; break;
638 case PARAM_LT: rv.u = vtl->line_thickness; break;
639 case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
640 case PARAM_VMIN: rv.d = vtl->velocity_min; break;
641 case PARAM_VMAX: rv.d = vtl->velocity_max; break;
642 case PARAM_DLA: rv.b = vtl->drawlabels; break;
643 case PARAM_DI: rv.b = vtl->drawimages; break;
644 case PARAM_TBGC: vik_gc_get_fg_color(vtl->track_bg_gc, &(rv.c)); break;
645 case PARAM_IS: rv.u = vtl->image_size; break;
646 case PARAM_IA: rv.u = vtl->image_alpha; break;
647 case PARAM_ICS: rv.u = vtl->image_cache_size; break;
648 case PARAM_WPC: vik_gc_get_fg_color(vtl->waypoint_gc, &(rv.c)); break;
649 case PARAM_WPTC: vik_gc_get_fg_color(vtl->waypoint_text_gc, &(rv.c)); break;
650 case PARAM_WPBC: vik_gc_get_fg_color(vtl->waypoint_bg_gc, &(rv.c)); break;
651 case PARAM_WPBA: rv.b = (vik_gc_get_function(vtl->waypoint_bg_gc)==GDK_AND); break;
652 case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
653 case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
ea3933fc 654 case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
50a14534
EB
655 }
656 return rv;
657}
658
911400b5
AF
659static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
660{
661 guint8 *pd, *dd;
662 gint pl, dl;
663 gchar *tmpname;
664 FILE *f;
665
666 *data = NULL;
667
668 if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
669 a_gpx_write_file(vtl, f);
670 vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
671 fclose(f);
941aa6e9 672 g_file_get_contents(tmpname, (void *)&dd, (void *)&dl, NULL);
911400b5
AF
673 *len = sizeof(pl) + pl + dl;
674 *data = g_malloc(*len);
675 memcpy(*data, &pl, sizeof(pl));
676 memcpy(*data + sizeof(pl), pd, pl);
677 memcpy(*data + sizeof(pl) + pl, dd, dl);
678
679 g_free(pd);
680 g_free(dd);
681 remove(tmpname);
682 g_free(tmpname);
683 }
684}
685
686static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp )
687{
688 VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
689 guint pl;
690 gchar *tmpname;
691 FILE *f;
692
693
694 memcpy(&pl, data, sizeof(pl));
695 data += sizeof(pl);
696 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, pl, vvp );
697 data += pl;
698
699 if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
700 g_critical("couldn't open temp file\n");
701 exit(1);
702 }
703 fwrite(data, len - pl - sizeof(pl), 1, f);
704 rewind(f);
705 a_gpx_read_file(rv, f);
706 fclose(f);
707 remove(tmpname);
708 g_free(tmpname);
709 return rv;
710}
711
267b6db5
QT
712static GList * a_array_to_glist(gpointer data[])
713{
714 GList *gl = NULL;
715 gpointer * p;
716 for (p = data; *p; p++)
717 gl = g_list_prepend(gl, *p);
718 return(g_list_reverse(gl));
719}
720
50a14534
EB
721VikTrwLayer *vik_trw_layer_new ( gint drawmode )
722{
267b6db5
QT
723 if (trw_layer_params[PARAM_DM].widget_data == NULL)
724 trw_layer_params[PARAM_DM].widget_data = a_array_to_glist(params_drawmodes);
725 if (trw_layer_params[PARAM_WPSYM].widget_data == NULL)
726 trw_layer_params[PARAM_WPSYM].widget_data = a_array_to_glist(params_wpsymbols);
727
50a14534
EB
728 VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) );
729 vik_layer_init ( VIK_LAYER(rv), VIK_LAYER_TRW );
730
731 rv->waypoints = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_waypoint_free );
732 rv->tracks = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_track_free );
733 rv->tracks_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
734 rv->waypoints_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
735
736 /* TODO: constants at top */
737 rv->waypoints_visible = rv->tracks_visible = TRUE;
738 rv->drawmode = drawmode;
739 rv->drawpoints = TRUE;
b42a25ba
EB
740 rv->drawstops = FALSE;
741 rv->drawelevation = FALSE;
742 rv->elevation_factor = 30;
743 rv->stop_length = 60;
50a14534
EB
744 rv->drawlines = TRUE;
745 rv->wplabellayout = NULL;
746 rv->wp_right_click_menu = NULL;
747 rv->waypoint_gc = NULL;
748 rv->waypoint_text_gc = NULL;
749 rv->waypoint_bg_gc = NULL;
750 rv->track_gc = NULL;
751 rv->velocity_max = 5.0;
752 rv->velocity_min = 0.0;
753 rv->line_thickness = 1;
b42a25ba 754 rv->bg_line_thickness = 0;
50a14534
EB
755 rv->current_wp = NULL;
756 rv->current_wp_name = NULL;
757 rv->current_track = NULL;
758 rv->current_tpl = NULL;
759 rv->current_tp_track_name = NULL;
760 rv->moving_tp = FALSE;
761 rv->moving_wp = FALSE;
1eef1bde 762
7b203521
EB
763 rv->ct_sync_done = TRUE;
764
1eef1bde 765 rv->magic_scissors_started = FALSE;
bddd2056
EB
766 rv->magic_scissors_check_added_track = FALSE;
767 rv->magic_scissors_added_track_name = NULL;
768 rv->magic_scissors_current_track = NULL;
769 rv->magic_scissors_append = FALSE;
1eef1bde 770
50a14534
EB
771 rv->waypoint_rightclick = FALSE;
772 rv->last_tpl = NULL;
773 rv->last_tp_track_name = NULL;
774 rv->tpwin = NULL;
775 rv->image_cache = g_queue_new();
776 rv->image_size = 64;
777 rv->image_alpha = 255;
778 rv->image_cache_size = 300;
779 rv->drawimages = TRUE;
780 rv->drawlabels = TRUE;
781 return rv;
782}
783
784
785void vik_trw_layer_free ( VikTrwLayer *trwlayer )
786{
787 g_hash_table_destroy(trwlayer->waypoints);
788 g_hash_table_destroy(trwlayer->tracks);
789
790 /* ODC: replace with GArray */
791 trw_layer_free_track_gcs ( trwlayer );
792
793 if ( trwlayer->wp_right_click_menu )
794 gtk_object_sink ( GTK_OBJECT(trwlayer->wp_right_click_menu) );
795
796 if ( trwlayer->wplabellayout != NULL)
797 g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) );
798
799 if ( trwlayer->waypoint_gc != NULL )
800 g_object_unref ( G_OBJECT ( trwlayer->waypoint_gc ) );
801
802 if ( trwlayer->waypoint_text_gc != NULL )
803 g_object_unref ( G_OBJECT ( trwlayer->waypoint_text_gc ) );
804
805 if ( trwlayer->waypoint_bg_gc != NULL )
806 g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
807
808 if ( trwlayer->waypoint_font != NULL )
809 gdk_font_unref ( trwlayer->waypoint_font );
810
811 if ( trwlayer->tpwin != NULL )
812 gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
813
814 g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
815 g_queue_free ( trwlayer->image_cache );
816}
817
818static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp )
819{
820 dp->vp = vp;
821 dp->xmpp = vik_viewport_get_xmpp ( vp );
822 dp->ympp = vik_viewport_get_ympp ( vp );
823 dp->width = vik_viewport_get_width ( vp );
824 dp->height = vik_viewport_get_height ( vp );
825 dp->center = vik_viewport_get_center ( vp );
826 dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */
827 dp->lat_lon = vik_viewport_get_coord_mode ( vp ) == VIK_COORD_LATLON;
828
829 if ( dp->one_zone )
830 {
831 gint w2, h2;
832 w2 = dp->xmpp * (dp->width / 2) + 1600 / dp->xmpp;
833 h2 = dp->ympp * (dp->height / 2) + 1600 / dp->ympp;
834 /* leniency -- for tracks. Obviously for waypoints this SHOULD be a lot smaller */
835
836 dp->ce1 = dp->center->east_west-w2;
837 dp->ce2 = dp->center->east_west+w2;
838 dp->cn1 = dp->center->north_south-h2;
839 dp->cn2 = dp->center->north_south+h2;
840 } else if ( dp->lat_lon ) {
841 VikCoord upperleft, bottomright;
842 /* quick & dirty calculation; really want to check all corners due to lat/lon smaller at top in northern hemisphere */
843 /* this also DOESN'T WORK if you are crossing 180/-180 lon. I don't plan to in the near future... */
844 vik_viewport_screen_to_coord ( vp, -500, -500, &upperleft );
845 vik_viewport_screen_to_coord ( vp, dp->width+500, dp->height+500, &bottomright );
846 dp->ce1 = upperleft.east_west;
847 dp->ce2 = bottomright.east_west;
848 dp->cn1 = bottomright.north_south;
849 dp->cn2 = upperleft.north_south;
850 }
851
852 dp->track_gc_iter = 0;
853}
854
855static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 )
856{
857 static gdouble rv = 0;
858 if ( tp1->has_timestamp && tp2->has_timestamp )
859 {
860 rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) )
861 / (tp1->timestamp - tp2->timestamp) ) - vtl->velocity_min;
862
863 if ( rv < 0 )
864 return VIK_TRW_LAYER_TRACK_GC_MIN;
865 else if ( vtl->velocity_min >= vtl->velocity_max )
866 return VIK_TRW_LAYER_TRACK_GC_MAX;
867
868 rv *= (VIK_TRW_LAYER_TRACK_GC_RATES / (vtl->velocity_max - vtl->velocity_min));
869
870 if ( rv >= VIK_TRW_LAYER_TRACK_GC_MAX )
871 return VIK_TRW_LAYER_TRACK_GC_MAX;
872 return (gint) rv;
873 }
874 else
875 return VIK_TRW_LAYER_TRACK_GC_BLACK;
876}
877
878void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
879{
880 vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y );
881 vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 );
882 vik_viewport_draw_line ( vvp, gc, x+5, y+5, x-5, y-5 );
883 vik_viewport_draw_line ( vvp, gc, x+5, y-5, x-5, y+5 );
884}
885
886static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct DrawingParams *dp, gboolean drawing_white_background )
887{
888 /* TODO: this function is a mess, get rid of any redundancy */
889 GList *list = track->trackpoints;
8e9c992d 890 GdkGC *main_gc;
50a14534
EB
891 gboolean useoldvals = TRUE;
892
893 gboolean drawpoints;
b42a25ba
EB
894 gboolean drawstops;
895 gboolean drawelevation;
941aa6e9 896 gdouble min_alt, max_alt, alt_diff = 0;
50a14534
EB
897
898 const guint8 tp_size_reg = 2;
899 const guint8 tp_size_cur = 4;
900 guint8 tp_size;
901
b42a25ba
EB
902 if ( dp->vtl->drawelevation )
903 {
904 /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
905 if ( ( drawelevation = vik_track_get_minmax_alt ( track, &min_alt, &max_alt ) ) )
906 alt_diff = max_alt - min_alt;
907 }
908
50a14534
EB
909 if ( ! track->visible )
910 return;
911
912 /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
913 if ( dp->vtl->bg_line_thickness && !drawing_white_background )
914 trw_layer_draw_track ( name, track, dp, TRUE );
915
916 if ( drawing_white_background )
b42a25ba
EB
917 drawpoints = drawstops = FALSE;
918 else {
50a14534 919 drawpoints = dp->vtl->drawpoints;
b42a25ba
EB
920 drawstops = dp->vtl->drawstops;
921 }
50a14534 922
8e9c992d
EB
923 if ( track == dp->vtl->current_track )
924 main_gc = dp->vtl->current_track_gc;
925 else
926 main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
927
50a14534
EB
928 if (list) {
929 int x, y, oldx, oldy;
930 VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
931
932 tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
933
934 vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
935
936 if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC )
937 {
938 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 939 vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 );
50a14534
EB
940 }
941
942 oldx = x;
943 oldy = y;
944
945 if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
946 dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_MAX + 1;
947
948 while ((list = g_list_next(list)))
949 {
950 tp = VIK_TRACKPOINT(list->data);
951 tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
952
953 /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
954 if ( (!dp->one_zone && !dp->lat_lon) || /* UTM & zones; do everything */
955 ( ((!dp->one_zone) || tp->coord.utm_zone == dp->center->utm_zone) && /* only check zones if UTM & one_zone */
956 tp->coord.east_west < dp->ce2 && tp->coord.east_west > dp->ce1 && /* both UTM and lat lon */
957 tp->coord.north_south > dp->cn1 && tp->coord.north_south < dp->cn2 ) )
958 {
959 vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
960
961 if ( drawpoints && ! drawing_white_background )
962 {
963 if ( list->next ) {
8e9c992d 964 vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
50a14534 965
8e9c992d 966 vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
734652bf 967
50a14534 968 /* stops */
b42a25ba 969 if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
50a14534
EB
970 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 );
971 }
972 else
8e9c992d 973 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
974 }
975
976 if ((!tp->newsegment) && (dp->vtl->drawlines))
977 {
978 VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
979
980 /* UTM only: zone check */
981 if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
8e9c992d 982 draw_utm_skip_insignia ( dp->vp, main_gc, x, y);
50a14534
EB
983
984 if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY )
985 dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
986
987 if (!useoldvals)
988 vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
989
8c4f1350 990 if ( drawing_white_background ) {
50a14534 991 vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
8c4f1350
EB
992 }
993 else {
8c4f1350 994
8e9c992d 995 vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
b42a25ba
EB
996 if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
997 GdkPoint tmp[4];
998 #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
999 if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
1000 tmp[0].x = oldx;
1001 tmp[0].y = oldy;
1002 tmp[1].x = oldx;
1003 tmp[1].y = oldy-FIXALTITUDE(list->data);
1004 tmp[2].x = x;
1005 tmp[2].y = y-FIXALTITUDE(list->next->data);
1006 tmp[3].x = x;
1007 tmp[3].y = y;
1008
1009 GdkGC *tmp_gc;
1010 if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
1011 tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
1012 else
1013 tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
1014 vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
1015 }
8e9c992d 1016 vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
8c4f1350
EB
1017 }
1018 }
50a14534
EB
1019 }
1020
1021 oldx = x;
1022 oldy = y;
1023 useoldvals = TRUE;
1024 }
1025 else {
1026 if (useoldvals && dp->vtl->drawlines && (!tp->newsegment))
1027 {
1028 VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
1029 if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
1030 {
1031 vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1032 if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY )
1033 dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
1034
1035 if ( drawing_white_background )
1036 vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
1037 else
8e9c992d 1038 vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
50a14534
EB
1039 }
1040 else
1041 {
1042 vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
8e9c992d 1043 draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
50a14534
EB
1044 }
1045 }
1046 useoldvals = FALSE;
1047 }
1048 }
1049 }
1050 if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
1051 if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC )
1052 dp->track_gc_iter = 0;
1053}
1054
1055/* the only reason this exists is so that trw_layer_draw_track can first call itself to draw the white track background */
1056static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp )
1057{
1058 trw_layer_draw_track ( name, track, dp, FALSE );
1059}
1060
1061static void cached_pixbuf_free ( CachedPixbuf *cp )
1062{
1063 g_object_unref ( G_OBJECT(cp->pixbuf) );
1064 g_free ( cp->image );
1065}
1066
1067static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name )
1068{
1069 return strcmp ( cp->image, name );
1070}
1071
1072static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp )
1073{
1074 if ( wp->visible )
51f0884d 1075 if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) &&
50a14534
EB
1076 wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 &&
1077 wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
1078 {
1079 gint x, y;
acaf7113 1080 GdkPixbuf *sym;
50a14534
EB
1081 vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y );
1082
1083 /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
1084
1085 if ( wp->image && dp->vtl->drawimages )
1086 {
1087 GdkPixbuf *pixbuf = NULL;
1088 GList *l;
1089
1090 if ( dp->vtl->image_alpha == 0)
1091 return;
1092
1093 l = g_list_find_custom ( dp->vtl->image_cache->head, wp->image, (GCompareFunc) cached_pixbuf_cmp );
1094 if ( l )
1095 pixbuf = ((CachedPixbuf *) l->data)->pixbuf;
1096 else
1097 {
1098 gchar *image = wp->image;
1099 GdkPixbuf *regularthumb = a_thumbnails_get ( wp->image );
1100 if ( ! regularthumb )
1101 {
1102 regularthumb = a_thumbnails_get_default (); /* cache one 'not yet loaded' for all thumbs not loaded */
1103 image = "\x12\x00"; /* this shouldn't occur naturally. */
1104 }
1105 if ( regularthumb )
1106 {
1107 CachedPixbuf *cp = NULL;
1108 cp = g_malloc ( sizeof ( CachedPixbuf ) );
1109 if ( dp->vtl->image_size == 128 )
1110 cp->pixbuf = regularthumb;
1111 else
1112 {
1113 cp->pixbuf = a_thumbnails_scale_pixbuf(regularthumb, dp->vtl->image_size, dp->vtl->image_size);
1114 g_assert ( cp->pixbuf );
1115 g_object_unref ( G_OBJECT(regularthumb) );
1116 }
1117 cp->image = g_strdup ( image );
1118
1119 /* needed so 'click picture' tool knows how big the pic is; we don't
1120 * store it in cp because they may have been freed already. */
1121 wp->image_width = gdk_pixbuf_get_width ( cp->pixbuf );
1122 wp->image_height = gdk_pixbuf_get_height ( cp->pixbuf );
1123
1124 g_queue_push_head ( dp->vtl->image_cache, cp );
1125 if ( dp->vtl->image_cache->length > dp->vtl->image_cache_size )
1126 cached_pixbuf_free ( g_queue_pop_tail ( dp->vtl->image_cache ) );
1127
1128 pixbuf = cp->pixbuf;
1129 }
1130 else
1131 {
1132 pixbuf = a_thumbnails_get_default (); /* thumbnail not yet loaded */
1133 }
1134 }
1135 if ( pixbuf )
1136 {
1137 gint w, h;
1138 w = gdk_pixbuf_get_width ( pixbuf );
1139 h = gdk_pixbuf_get_height ( pixbuf );
1140
1141 if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
1142 {
1143 if ( dp->vtl->image_alpha == 255 )
1144 vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
1145 else
1146 vik_viewport_draw_pixbuf_with_alpha ( dp->vp, pixbuf, dp->vtl->image_alpha, 0, 0, x - (w/2), y - (h/2), w, h );
1147 }
1148 return; /* if failed to draw picture, default to drawing regular waypoint (below) */
1149 }
1150 }
1151
1152 /* DRAW ACTUAL DOT */
ea3933fc 1153 if ( dp->vtl->wp_draw_symbols && wp->symbol && (sym = a_get_wp_sym(wp->symbol)) ) {
acaf7113
AF
1154 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 );
1155 }
1156 else if ( wp == dp->vtl->current_wp ) {
50a14534
EB
1157 switch ( dp->vtl->wp_symbol ) {
1158 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;
1159 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;
1160 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;
1161 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 );
1162 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 );
1163 }
1164 }
1165 else {
1166 switch ( dp->vtl->wp_symbol ) {
1167 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;
1168 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;
1169 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;
1170 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 );
1171 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;
1172 }
1173 }
1174
1175 if ( dp->vtl->drawlabels )
1176 {
1177 /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
1178 gint width, height;
1179 pango_layout_set_text ( dp->vtl->wplabellayout, name, -1 );
1180 pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
1181 vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, x + dp->vtl->wp_size - 1, y-1,width+1,height-1);
1182 vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, x + dp->vtl->wp_size, y, dp->vtl->wplabellayout );
1183 }
1184 }
1185}
1186
1187void vik_trw_layer_draw ( VikTrwLayer *l, gpointer data )
1188{
1189 static struct DrawingParams dp;
1190 g_assert ( l != NULL );
1191
1192 init_drawing_params ( &dp, VIK_VIEWPORT(data) );
1193 dp.vtl = l;
1194
1195 if ( l->tracks_visible )
1196 g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp );
1197
1198 if (l->waypoints_visible)
1199 g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint, &dp );
1200}
1201
1202static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
1203{
1204 int i;
1205 if ( vtl->track_bg_gc )
1206 {
1207 g_object_unref ( vtl->track_bg_gc );
1208 vtl->track_bg_gc = NULL;
1209 }
8e9c992d
EB
1210 if ( vtl->current_track_gc )
1211 {
1212 g_object_unref ( vtl->current_track_gc );
1213 vtl->current_track_gc = NULL;
1214 }
50a14534
EB
1215
1216 if ( ! vtl->track_gc )
1217 return;
1218 for ( i = vtl->track_gc->len - 1; i >= 0; i-- )
1219 g_object_unref ( g_array_index ( vtl->track_gc, GObject *, i ) );
1220 g_array_free ( vtl->track_gc, TRUE );
1221 vtl->track_gc = NULL;
1222}
1223
1224static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
1225{
1226 GdkGC *gc[ VIK_TRW_LAYER_TRACK_GC ];
1227 gint width = vtl->line_thickness;
1228
1229 if ( vtl->track_gc )
1230 trw_layer_free_track_gcs ( vtl );
1231
1232 if ( vtl->track_bg_gc )
1233 g_object_unref ( vtl->track_bg_gc );
1234 vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
1235
8e9c992d
EB
1236 if ( vtl->current_track_gc )
1237 g_object_unref ( vtl->current_track_gc );
1238 vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
1239 gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
1240
50a14534
EB
1241 vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
1242
1243 gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
1244
1245 gc[1] = vik_viewport_new_gc ( vp, "#0a8742", width );
1246 gc[2] = vik_viewport_new_gc ( vp, "#0a8783", width );
1247 gc[3] = vik_viewport_new_gc ( vp, "#0a4d87", width );
1248 gc[4] = vik_viewport_new_gc ( vp, "#05469f", width );
1249 gc[5] = vik_viewport_new_gc ( vp, "#1b059f", width );
1250 gc[6] = vik_viewport_new_gc ( vp, "#2d059f", width );
1251 gc[7] = vik_viewport_new_gc ( vp, "#4a059f", width );
1252 gc[8] = vik_viewport_new_gc ( vp, "#84059f", width );
1253 gc[9] = vik_viewport_new_gc ( vp, "#96059f", width );
1254 gc[10] = vik_viewport_new_gc ( vp, "#f22ef2", width );
1255
1256 gc[11] = vik_viewport_new_gc ( vp, "#ff0000", width ); /* above range */
1257
1258 gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */
1259
1260 g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
1261}
1262
1263VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
1264{
1265 VikTrwLayer *rv = vik_trw_layer_new ( 0 );
1266 PangoFontDescription *pfd;
1267 rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
1268 pfd = pango_font_description_from_string (WAYPOINT_FONT);
1269 pango_layout_set_font_description (rv->wplabellayout, pfd);
1270 /* freeing PangoFontDescription, cause it has been copied by prev. call */
1271 pango_font_description_free (pfd);
1272
1273 vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
1274
1275 trw_layer_new_track_gcs ( rv, vp );
1276
1277 rv->waypoint_gc = vik_viewport_new_gc ( vp, "#000000", 2 );
1278 rv->waypoint_text_gc = vik_viewport_new_gc ( vp, "#FFFFFF", 1 );
1279 rv->waypoint_bg_gc = vik_viewport_new_gc ( vp, "#8383C4", 1 );
1280 gdk_gc_set_function ( rv->waypoint_bg_gc, GDK_AND );
1281
1282 rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
1283
1284 rv->has_verified_thumbnails = FALSE;
1285 rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
1286 rv->wp_size = 4;
ea3933fc 1287 rv->wp_draw_symbols = TRUE;
50a14534
EB
1288
1289 rv->coord_mode = vik_viewport_get_coord_mode ( vp );
1290
20c7a3a0
QT
1291 rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection;
1292
50a14534
EB
1293 return rv;
1294}
1295
1296static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] )
1297{
1298 GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
1299
1300#ifdef VIK_CONFIG_ALPHABETIZED_TRW
1301 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
1302#else
1303 vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
1304#endif
1305
1306 *new_iter = *((GtkTreeIter *) pass_along[1]);
1307 g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, name, new_iter );
1308
1309 if ( ! track->visible )
1310 vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
1311}
1312
1313static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[4] )
1314{
1315 GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
1316#ifdef VIK_CONFIG_ALPHABETIZED_TRW
1317 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
1318#else
1319 vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE );
1320#endif
1321
1322 *new_iter = *((GtkTreeIter *) pass_along[1]);
1323 g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, name, new_iter );
1324
1325 if ( ! wp->visible )
1326 vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
1327}
1328
1329
1330void vik_trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
1331{
1332 GtkTreeIter iter2;
1333 gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, (gpointer) VIK_TRW_LAYER_SUBLAYER_TRACK };
1334
1335#ifdef VIK_CONFIG_ALPHABETIZED_TRW
4c77d5e0 1336 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
50a14534 1337#else
4c77d5e0 1338 vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
50a14534
EB
1339#endif
1340 if ( ! vtl->tracks_visible )
1341 vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), FALSE );
1342
1343 g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
1344
1345#ifdef VIK_CONFIG_ALPHABETIZED_TRW
4c77d5e0 1346 vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
50a14534 1347#else
4c77d5e0 1348 vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
50a14534
EB
1349#endif
1350
1351 if ( ! vtl->waypoints_visible )
1352 vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), FALSE );
1353
1354 pass_along[0] = &(vtl->waypoints_iter);
1355 pass_along[4] = (gpointer) VIK_TRW_LAYER_SUBLAYER_WAYPOINT;
1356
1357 g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
1358
1359}
1360
1361gboolean vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
1362{
1363 switch ( subtype )
1364 {
1365 case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1);
1366 case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1);
1367 case VIK_TRW_LAYER_SUBLAYER_TRACK:
1368 {
1369 VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer );
1370 if (t)
1371 return (t->visible ^= 1);
1372 else
1373 return TRUE;
1374 }
1375 case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
1376 {
1377 VikWaypoint *t = g_hash_table_lookup ( l->waypoints, sublayer );
1378 if (t)
1379 return (t->visible ^= 1);
1380 else
1381 return TRUE;
1382 }
1383 }
1384 return TRUE;
1385}
1386
1387GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
1388{
1389 return l->tracks;
1390}
1391
1392GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l )
1393{
1394 return l->waypoints;
1395}
1396
1397static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] )
1398{
1399 static VikCoord fixme;
1400 vik_coord_copy_convert ( &(w->coord), VIK_COORD_LATLON, &fixme );
1401 if ( VIK_LATLON(&fixme)->lat > maxmin[0].lat || maxmin[0].lat == 0.0 )
1402 maxmin[0].lat = VIK_LATLON(&fixme)->lat;
1403 if ( VIK_LATLON(&fixme)->lat < maxmin[1].lat || maxmin[1].lat == 0.0 )
1404 maxmin[1].lat = VIK_LATLON(&fixme)->lat;
1405 if ( VIK_LATLON(&fixme)->lon > maxmin[0].lon || maxmin[0].lon == 0.0 )
1406 maxmin[0].lon = VIK_LATLON(&fixme)->lon;
1407 if ( VIK_LATLON(&fixme)->lon < maxmin[1].lon || maxmin[1].lon == 0.0 )
1408 maxmin[1].lon = VIK_LATLON(&fixme)->lon;
1409}
1410
1411static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] )
1412{
1413 GList *tr = *t;
1414 static VikCoord fixme;
1415
1416 while ( tr )
1417 {
1418 vik_coord_copy_convert ( &(VIK_TRACKPOINT(tr->data)->coord), VIK_COORD_LATLON, &fixme );
1419 if ( VIK_LATLON(&fixme)->lat > maxmin[0].lat || maxmin[0].lat == 0.0 )
1420 maxmin[0].lat = VIK_LATLON(&fixme)->lat;
1421 if ( VIK_LATLON(&fixme)->lat < maxmin[1].lat || maxmin[1].lat == 0.0 )
1422 maxmin[1].lat = VIK_LATLON(&fixme)->lat;
1423 if ( VIK_LATLON(&fixme)->lon > maxmin[0].lon || maxmin[0].lon == 0.0 )
1424 maxmin[0].lon = VIK_LATLON(&fixme)->lon;
1425 if ( VIK_LATLON(&fixme)->lon < maxmin[1].lon || maxmin[1].lon == 0.0 )
1426 maxmin[1].lon = VIK_LATLON(&fixme)->lon;
1427 tr = tr->next;
1428 }
1429}
1430
1431
1432gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
1433{
1434 /* 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... */
1435 struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
1436 g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin );
1437 g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
1438 if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
1439 return FALSE;
1440 else
1441 {
1442 struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
1443 vik_coord_load_from_latlon ( dest, vtl->coord_mode, &average );
1444 return TRUE;
1445 }
1446}
1447
1448static void trw_layer_centerize ( gpointer layer_and_vlp[2] )
1449{
1450 VikCoord coord;
1451 if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
1452 goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp[1]), &coord );
1453 else
4c77d5e0 1454 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
50a14534
EB
1455}
1456
1457static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type )
1458{
1459 GtkWidget *file_selector;
1460 const gchar *fn;
1461 gboolean failed = FALSE;
4c77d5e0 1462 file_selector = gtk_file_selection_new (_("Export Layer"));
63726881 1463 gtk_file_selection_set_filename (GTK_FILE_SELECTION(file_selector), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])));
50a14534
EB
1464
1465 while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_OK )
1466 {
1467 fn = gtk_file_selection_get_filename (GTK_FILE_SELECTION(file_selector) );
1468 if ( access ( fn, F_OK ) != 0 )
1469 {
1470 gtk_widget_hide ( file_selector );
1471 failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type );
1472 break;
1473 }
1474 else
1475 {
4c77d5e0 1476 if ( a_dialog_overwrite ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
50a14534
EB
1477 {
1478 gtk_widget_hide ( file_selector );
1479 failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type );
1480 break;
1481 }
1482 }
1483 }
1484 gtk_widget_destroy ( file_selector );
1485 if ( failed )
4c77d5e0 1486 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
1487}
1488
1489static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] )
1490{
1491 trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSPOINT );
1492}
1493
1494static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] )
1495{
1496 trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSMAPPER );
1497}
1498
561e6ad0
EB
1499static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
1500{
1501 trw_layer_export ( layer_and_vlp, FILE_TYPE_GPX );
1502}
1503
50a14534
EB
1504static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
1505{
1506 GHashTable *wps = vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp[0]) );
4c77d5e0 1507 GtkWidget *dia = gtk_dialog_new_with_buttons (_("Create"),
50a14534
EB
1508 VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
1509 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1510 GTK_STOCK_CANCEL,
1511 GTK_RESPONSE_REJECT,
1512 GTK_STOCK_OK,
1513 GTK_RESPONSE_ACCEPT,
1514 NULL);
1515
1516 GtkWidget *label, *entry;
4c77d5e0 1517 label = gtk_label_new(_("Waypoint Name:"));
50a14534
EB
1518 entry = gtk_entry_new();
1519
1520 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), label, FALSE, FALSE, 0);
1521 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), entry, FALSE, FALSE, 0);
1522 gtk_widget_show_all ( label );
1523 gtk_widget_show_all ( entry );
1524
1525 while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
1526 {
1527 VikWaypoint *wp;
1528 gchar *upname = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1529 int i;
1530
1531 for ( i = strlen(upname)-1; i >= 0; i-- )
1532 upname[i] = toupper(upname[i]);
1533
1534 wp = g_hash_table_lookup ( wps, upname );
1535
1536 if (!wp)
4c77d5e0 1537 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
50a14534
EB
1538 else
1539 {
1540 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
1541 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
1542 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 ) );
1543 break;
1544 }
1545
1546 g_free ( upname );
1547
1548 }
1549 gtk_widget_destroy ( dia );
1550}
1551
1552gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
1553{
1554 gchar *name;
acaf7113
AF
1555 VikWaypoint *wp = vik_waypoint_new();
1556 wp->coord = *def_coord;
1557 wp->altitude = VIK_DEFAULT_ALTITUDE;
50a14534 1558
acaf7113 1559 if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) )
50a14534 1560 {
805d282e 1561 wp->visible = TRUE;
50a14534
EB
1562 vik_trw_layer_add_waypoint ( vtl, name, wp );
1563 return TRUE;
1564 }
acaf7113 1565 vik_waypoint_free(wp);
50a14534
EB
1566 return FALSE;
1567}
1568
1569static void trw_layer_new_wp ( gpointer lav[2] )
1570{
1571 VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
1572 VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
1573 /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
1574 instead return true if you want to update. */
1575 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 )
1576 vik_layers_panel_emit_update ( vlp );
1577}
1578
1579void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
1580{
1581 static gpointer pass_along[2];
1582 GtkWidget *item;
98fcbbdb 1583 GtkWidget *export_submenu;
50a14534
EB
1584 pass_along[0] = vtl;
1585 pass_along[1] = vlp;
1586
1587 item = gtk_menu_item_new();
1588 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1589 gtk_widget_show ( item );
1590
4c77d5e0 1591 item = gtk_menu_item_new_with_label ( _("Goto Center of Layer") );
50a14534
EB
1592 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
1593 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1594 gtk_widget_show ( item );
1595
4c77d5e0 1596 item = gtk_menu_item_new_with_label ( _("Goto Waypoint") );
50a14534
EB
1597 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
1598 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1599 gtk_widget_show ( item );
1600
1bd88e66 1601 export_submenu = gtk_menu_new ();
4c77d5e0 1602 item = gtk_menu_item_new_with_label ( _("Export layer") );
50a14534
EB
1603 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1604 gtk_widget_show ( item );
98fcbbdb 1605 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
1bd88e66 1606
4c77d5e0 1607 item = gtk_menu_item_new_with_label ( _("Export as GPSPoint") );
1bd88e66
GB
1608 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
1609 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
1610 gtk_widget_show ( item );
50a14534 1611
4c77d5e0 1612 item = gtk_menu_item_new_with_label ( _("Export as GPSMapper") );
50a14534 1613 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
1bd88e66 1614 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
50a14534
EB
1615 gtk_widget_show ( item );
1616
4c77d5e0 1617 item = gtk_menu_item_new_with_label ( _("Export as GPX") );
561e6ad0 1618 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
1bd88e66 1619 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
561e6ad0
EB
1620 gtk_widget_show ( item );
1621
4c77d5e0 1622 item = gtk_menu_item_new_with_label ( _("New Waypoint") );
50a14534
EB
1623 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
1624 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1625 gtk_widget_show ( item );
3e7553ae
GB
1626
1627#ifdef VIK_CONFIG_OPENSTREETMAP
4c77d5e0 1628 item = gtk_menu_item_new_with_label ( _("Upload to OSM") );
3e7553ae
GB
1629 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
1630 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1631 gtk_widget_show ( item );
1632#endif
28c82d8b
EB
1633
1634 item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
1635 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
1636 if ( item ) {
1637 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1638 gtk_widget_show ( item );
1639 }
1640
1641 item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
1642 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
1643 if ( item ) {
1644 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1645 gtk_widget_show ( item );
1646 }
50a14534
EB
1647}
1648
1649void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
1650{
1651 if ( VIK_LAYER(vtl)->realized )
1652 {
1653 VikWaypoint *oldwp = VIK_WAYPOINT ( g_hash_table_lookup ( vtl->waypoints, name ) );
1654 if ( oldwp )
1655 wp->visible = oldwp->visible; /* same visibility so we don't have to update viktreeview */
1656 else
1657 {
1658 GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
1659#ifdef VIK_CONFIG_ALPHABETIZED_TRW
1660 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE );
1661#else
1662 vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE );
1663#endif
1664 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter );
1665 g_hash_table_insert ( vtl->waypoints_iters, name, iter );
1666 wp->visible = TRUE;
1667 }
1668 }
1669 else
1670 wp->visible = TRUE;
1671
1672 g_hash_table_insert ( vtl->waypoints, name, wp );
1673
1674}
1675
1676void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
1677{
1678 if ( VIK_LAYER(vtl)->realized )
1679 {
1680 VikTrack *oldt = VIK_TRACK ( g_hash_table_lookup ( vtl->tracks, name ) );
1681 if ( oldt )
1682 t->visible = oldt->visible; /* same visibility so we don't have to update viktreeview */
1683 else
1684 {
1685 GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
1686#ifdef VIK_CONFIG_ALPHABETIZED_TRW
1687 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
1688#else
1689 vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
1690#endif
1691 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter );
1692 g_hash_table_insert ( vtl->tracks_iters, name, iter );
805d282e 1693 /* t->visible = TRUE; */
50a14534
EB
1694 }
1695 }
1696 else
805d282e 1697 ; /* t->visible = TRUE; // this is now used by file input functions */
50a14534
EB
1698
1699 g_hash_table_insert ( vtl->tracks, name, t );
1700
1701}
1702
1703static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str )
1704{
1705 gchar *upp = g_strdup ( str );
1706 gboolean rv;
1707 char *tmp = upp;
1708 while ( *tmp )
1709 {
1710 *tmp = toupper(*tmp);
1711 tmp++;
1712 }
1713 rv = g_hash_table_lookup ( hash, upp ) ? TRUE : FALSE;
1714 g_free (upp);
1715 return rv;
1716}
1717
1718/* to be called whenever a track has been deleted or may have been changed. */
21700912 1719void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name )
50a14534
EB
1720{
1721 if (vtl->current_tp_track_name && g_strcasecmp(trk_name, vtl->current_tp_track_name) == 0)
1722 trw_layer_cancel_current_tp ( vtl, FALSE );
1723 else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0)
1724 trw_layer_cancel_last_tp ( vtl );
1725}
e890a6e6
EB
1726
1727static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
1728{
1729 gint i = 2;
1730 gchar *newname = g_strdup(name);
1731 while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ?
941aa6e9 1732 (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) {
e890a6e6
EB
1733 gchar *new_newname = g_strdup_printf("%s#%d", name, i);
1734 g_free(newname);
1735 newname = new_newname;
1736 i++;
1737 }
1738 return newname;
1739}
50a14534 1740
805d282e
EB
1741void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
1742{
1743 vik_trw_layer_add_waypoint ( vtl,
1744 get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name),
1745 wp );
1746}
1747void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
1748{
bddd2056 1749 if ( vtl->magic_scissors_append && vtl->magic_scissors_current_track ) {
c3deba01 1750 vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
bddd2056
EB
1751 vik_track_steal_and_append_trackpoints ( vtl->magic_scissors_current_track, tr );
1752 vik_track_free ( tr );
1753 vtl->magic_scissors_append = FALSE; /* this means we have added it */
1754 } else {
1755 gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
1756 vik_trw_layer_add_track ( vtl, new_name, tr );
1757
1758 if ( vtl->magic_scissors_check_added_track ) {
c3deba01 1759 vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
bddd2056
EB
1760 if ( vtl->magic_scissors_added_track_name ) /* for google routes */
1761 g_free ( vtl->magic_scissors_added_track_name );
1762 vtl->magic_scissors_added_track_name = g_strdup(new_name);
1763 }
1764 }
805d282e
EB
1765}
1766
c48517ad
AF
1767static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l )
1768{
1769 *l = g_list_append(*l, (gpointer)name);
1770}
1771
1772static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type )
1773{
1774 gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name);
1775 if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
1776 VikTrack *t;
1777 t = vik_track_copy(vik_trw_layer_get_track(vtl_src, name));
1778 vik_trw_layer_delete_track(vtl_src, name);
1779 vik_trw_layer_add_track(vtl_dest, newname, t);
1780 }
1781 if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
1782 VikWaypoint *w;
1783 w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, name));
1784 vik_trw_layer_delete_waypoint(vtl_src, name);
1785 vik_trw_layer_add_waypoint(vtl_dest, newname, w);
1786 }
1787}
1788
70a23263 1789static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
e4afc73a
EB
1790{
1791 VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
c48517ad
AF
1792 gint type = vik_treeview_item_get_data(vt, src_item_iter);
1793
e4afc73a 1794 if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
b637058e
EB
1795 GList *items = NULL;
1796 GList *iter;
e4afc73a 1797
c48517ad
AF
1798 if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
1799 g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items);
1800 }
1801 if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) {
1802 g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items);
1803 }
1804
1805 iter = items;
1806 while (iter) {
1807 if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
1808 trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
1809 } else {
1810 trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
1811 }
1812 iter = iter->next;
e4afc73a 1813 }
c48517ad 1814 if (items)
b637058e 1815 g_list_free(items);
c48517ad
AF
1816 } else {
1817 gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
1818 trw_layer_move_item(vtl_src, vtl_dest, name, type);
e4afc73a
EB
1819 }
1820}
1821
1822
1823gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
50a14534
EB
1824{
1825 VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name );
1826 gboolean was_visible = FALSE;
1827 if ( t )
1828 {
1829 GtkTreeIter *it;
1830 was_visible = t->visible;
1831 if ( t == vtl->current_track )
1832 vtl->current_track = NULL;
bddd2056
EB
1833 if ( t == vtl->magic_scissors_current_track )
1834 vtl->magic_scissors_current_track = NULL;
50a14534
EB
1835
1836 /* could be current_tp, so we have to check */
1837 trw_layer_cancel_tps_of_track ( vtl, trk_name );
1838
1839 g_assert ( ( it = g_hash_table_lookup ( vtl->tracks_iters, trk_name ) ) );
1840 vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
1841 g_hash_table_remove ( vtl->tracks_iters, trk_name );
1842
1843 /* do this last because trk_name may be pointing to actual orig key */
1844 g_hash_table_remove ( vtl->tracks, trk_name );
1845 }
1846 return was_visible;
1847}
1848
e4afc73a
EB
1849gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name )
1850{
1851 gboolean was_visible = FALSE;
1852 VikWaypoint *wp;
1853
1854 wp = g_hash_table_lookup ( vtl->waypoints, wp_name );
1855 if ( wp ) {
1856 GtkTreeIter *it;
1857
1858 if ( wp == vtl->current_wp ) {
1859 vtl->current_wp = NULL;
1860 vtl->current_wp_name = NULL;
1861 vtl->moving_wp = FALSE;
1862 }
1863
1864 was_visible = wp->visible;
1865 g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) wp_name ) ) );
1866 vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
1867 g_hash_table_remove ( vtl->waypoints_iters, (gchar *) wp_name );
1868 g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */
1869 }
1870
1871 return was_visible;
1872}
1873
700b0908
QT
1874static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt)
1875{
1876 vik_treeview_item_delete (vt, it );
1877}
1878
1879void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
1880{
1881
1882 vtl->current_track = NULL;
bddd2056 1883 vtl->magic_scissors_current_track = NULL;
700b0908
QT
1884 if (vtl->current_tp_track_name)
1885 trw_layer_cancel_current_tp(vtl, FALSE);
1886 if (vtl->last_tp_track_name)
1887 trw_layer_cancel_last_tp ( vtl );
1888
1889 g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
1890 g_hash_table_remove_all(vtl->tracks_iters);
1891 g_hash_table_remove_all(vtl->tracks);
1892
1893 /* TODO: only update if the layer is visible (ticked) */
1894 vik_layer_emit_update ( VIK_LAYER(vtl) );
1895}
1896
1897void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
1898{
1899 vtl->current_wp = NULL;
1900 vtl->current_wp_name = NULL;
1901 vtl->moving_wp = FALSE;
1902
1903 g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
1904 g_hash_table_remove_all(vtl->waypoints_iters);
1905 g_hash_table_remove_all(vtl->waypoints);
1906
1907 /* TODO: only update if the layer is visible (ticked) */
1908 vik_layer_emit_update ( VIK_LAYER(vtl) );
1909}
1910
50a14534
EB
1911static void trw_layer_delete_item ( gpointer pass_along[5] )
1912{
1913 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
1914 gboolean was_visible = FALSE;
1915 if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
1916 {
e4afc73a 1917 was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
50a14534
EB
1918 }
1919 else
1920 {
e4afc73a 1921 was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
50a14534 1922 }
50a14534
EB
1923 if ( was_visible )
1924 vik_layer_emit_update ( VIK_LAYER(vtl) );
1925}
1926
1927
1928static void trw_layer_properties_item ( gpointer pass_along[5] )
1929{
1930 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
1931 if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
1932 {
1933 VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
1934 if ( wp )
1935 {
1936 if ( a_dialog_new_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), NULL, wp, NULL, vtl->coord_mode ) )
1937
1938 if ( VIK_LAYER(vtl)->visible )
1939 vik_layer_emit_update ( VIK_LAYER(vtl) );
1940 }
1941 }
1942 else
1943 {
1944 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
1945 if ( tr )
1946 {
21700912
QT
1947 vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
1948 vtl, tr,
1949 pass_along[1], /* vlp */
1950 pass_along[3] /* track name */);
50a14534
EB
1951 }
1952 }
1953}
1954
1955static void goto_coord ( VikLayersPanel *vlp, const VikCoord *coord )
1956{
1957 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), coord );
1958 vik_layers_panel_emit_update ( vlp );
1959}
1960
1961static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] )
1962{
1963 GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
1964 if ( trps && trps->data )
1965 goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *) trps->data)->coord));
1966}
1967
1968static void trw_layer_goto_track_center ( gpointer pass_along[5] )
1969{
8fb71d6c 1970 /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
50a14534
EB
1971 GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
1972 if ( trps && *trps )
1973 {
1974 struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
1975 VikCoord coord;
1976 trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
1977 average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
1978 average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
1979 vik_coord_load_from_latlon ( &coord, VIK_TRW_LAYER(pass_along[0])->coord_mode, &average );
1980 goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &coord);
1981 }
1982}
1983
8fb71d6c
EB
1984static void trw_layer_extend_track_end ( gpointer pass_along[6] )
1985{
1986 VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
1987 VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
1988
1989 vtl->current_track = track;
1990 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
1991
1992 if ( track->trackpoints )
1993 goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
1994}
1995
ad0a8c2d
EB
1996static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
1997{
1998 /* TODO: check & warn if no DEM data, or no applicable DEM data. */
1999 /* Also warn if overwrite old elevation data */
2000 VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2001
55906514 2002 vik_track_apply_dem_data ( track );
ad0a8c2d
EB
2003}
2004
50a14534
EB
2005static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
2006{
2007 GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
2008 if ( !trps )
2009 return;
111fa174 2010 trps = g_list_last(trps);
50a14534
EB
2011 goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *) trps->data)->coord));
2012}
2013
111fa174
AF
2014
2015/*************************************
2016 * merge/split by time routines
2017 *************************************/
2018
2019/* called for each key in track hash table. if original track user_data[1] is close enough
2020 * to the passed one, add it to list in user_data[0]
2021 */
2022static void find_nearby_track(gpointer key, gpointer value, gpointer user_data)
2023{
2024 time_t t1, t2;
2025 VikTrackpoint *p1, *p2;
2026
2027 GList **nearby_tracks = ((gpointer *)user_data)[0];
2028 GList *orig_track = ((gpointer *)user_data)[1];
2029 guint thr = (guint)((gpointer *)user_data)[2];
2030
2031 t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
2032 t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
2033
2034 if (VIK_TRACK(value)->trackpoints == orig_track) {
2035 return;
2036 }
2037
2038 p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
2039 p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
2040
2041 if (!p1->has_timestamp || !p2->has_timestamp) {
70a23263 2042 g_print("no timestamp\n");
111fa174
AF
2043 return;
2044 }
2045
70a23263 2046 /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
111fa174
AF
2047 if (abs(t1 - p2->timestamp) < thr*60 ||
2048 /* p1 p2 t1 t2 */
2049 abs(p1->timestamp - t2) < thr*60
2050 /* t1 t2 p1 p2 */
2051 ) {
2052 *nearby_tracks = g_list_prepend(*nearby_tracks, key);
2053 }
2054}
2055
2056/* comparison function used to sort tracks; a and b are hash table keys */
2057static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
2058{
2059 GHashTable *tracks = user_data;
2060 time_t t1, t2;
2061
2062 t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
2063 t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
2064
2065 if (t1 < t2) return -1;
2066 if (t1 > t2) return 1;
2067 return 0;
2068}
2069
2070/* comparison function used to sort trackpoints */
2071static gint trackpoint_compare(gconstpointer a, gconstpointer b)
2072{
2073 time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
2074
2075 if (t1 < t2) return -1;
2076 if (t1 > t2) return 1;
2077 return 0;
2078}
2079
2080/* merge by time routine */
2081static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
2082{
2083 time_t t1, t2;
2084 GList *nearby_tracks = NULL;
2085 VikTrack *track;
2086 GList *trps;
2087 static guint thr = 1;
2088 guint track_count = 0;
2089 gchar *orig_track_name = strdup(pass_along[3]);
2090
2091 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
4c77d5e0
GB
2092 _("Merge Threshold..."),
2093 _("Merge when time between trackpoints less than:"),
111fa174
AF
2094 &thr)) {
2095 return;
2096 }
2097
2098 /* merge tracks until we can't */
2099 do {
2100 gpointer params[3];
2101
2102 track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, orig_track_name );
2103 trps = track->trackpoints;
2104 if ( !trps )
2105 return;
2106
2107
2108 if (nearby_tracks) {
2109 g_list_free(nearby_tracks);
2110 nearby_tracks = NULL;
2111 }
2112
2113 t1 = ((VikTrackpoint *)trps->data)->timestamp;
2114 t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
2115
70a23263 2116 /* g_print("Original track times: %d and %d\n", t1, t2); */
111fa174
AF
2117 params[0] = &nearby_tracks;
2118 params[1] = trps;
2119 params[2] = (gpointer)thr;
2120
2121 /* get a list of adjacent-in-time tracks */
2122 g_hash_table_foreach(VIK_TRW_LAYER(pass_along[0])->tracks, find_nearby_track, (gpointer)params);
2123
2124 /* add original track */
2125 nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name);
2126
2127 /* sort by first trackpoint; assumes they don't overlap */
2128 nearby_tracks = g_list_sort_with_data(nearby_tracks, track_compare, VIK_TRW_LAYER(pass_along[0])->tracks);
2129
2130 /* merge them */
2131 {
2132#define get_track(x) VIK_TRACK(g_hash_table_lookup(VIK_TRW_LAYER(pass_along[0])->tracks, (gchar *)((x)->data)))
2133#define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
2134#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
2135 GList *l = nearby_tracks;
2136 VikTrack *tr = vik_track_new();
2137 tr->visible = track->visible;
2138 track_count = 0;
2139 while (l) {
2140 /*
2141 time_t t1, t2;
2142 t1 = get_first_trackpoint(l)->timestamp;
2143 t2 = get_last_trackpoint(l)->timestamp;
70a23263 2144 g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
111fa174
AF
2145 */
2146
2147
2148 /* remove trackpoints from merged track, delete track */
2149 tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints);
2150 get_track(l)->trackpoints = NULL;
e4afc73a 2151 vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), l->data);
111fa174
AF
2152
2153 track_count ++;
2154 l = g_list_next(l);
2155 }
2156 tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare);
2157 vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), strdup(orig_track_name), tr);
2158
2159#undef get_first_trackpoint
2160#undef get_last_trackpoint
2161#undef get_track
2162 }
2163 } while (track_count > 1);
2164 g_list_free(nearby_tracks);
2165 free(orig_track_name);
2166 vik_layer_emit_update(VIK_LAYER(pass_along[0]));
2167}
2168
2169/* split by time routine */
2170static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
2171{
2172 VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
2173 GList *trps = track->trackpoints;
2174 GList *iter;
2175 GList *newlists = NULL;
2176 GList *newtps = NULL;
2177 guint i;
2178 static guint thr = 1;
2179
2180 time_t ts, prev_ts;
2181
2182 if ( !trps )
2183 return;
2184
2185 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
4c77d5e0
GB
2186 _("Split Threshold..."),
2187 _("Split when time between trackpoints exceeds:"),
111fa174
AF
2188 &thr)) {
2189 return;
2190 }
2191
2192 /* iterate through trackpoints, and copy them into new lists without touching original list */
2193 prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
2194 iter = trps;
2195
2196 while (iter) {
2197 ts = VIK_TRACKPOINT(iter->data)->timestamp;
2198 if (ts < prev_ts) {
70a23263 2199 g_print("panic: ts < prev_ts: this should never happen!\n");
111fa174
AF
2200 return;
2201 }
2202 if (ts - prev_ts > thr*60) {
2203 /* flush accumulated trackpoints into new list */
2204 newlists = g_list_prepend(newlists, g_list_reverse(newtps));
2205 newtps = NULL;
2206 }
2207
2208 /* accumulate trackpoint copies in newtps, in reverse order */
2209 newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
2210 prev_ts = ts;
2211 iter = g_list_next(iter);
2212 }
2213 if (newtps) {
2214 newlists = g_list_prepend(newlists, g_list_reverse(newtps));
2215 }
2216
2217 /* put lists of trackpoints into tracks */
2218 iter = newlists;
2219 i = 1;
2220 while (iter) {
2221 gchar *new_tr_name;
2222 VikTrack *tr;
2223
2224 tr = vik_track_new();
2225 tr->visible = track->visible;
2226 tr->trackpoints = (GList *)(iter->data);
2227
2228 new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
2229 vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
70a23263 2230 /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
111fa174
AF
2231 VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
2232
2233 iter = g_list_next(iter);
2234 }
2235 g_list_free(newlists);
e4afc73a 2236 vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
111fa174
AF
2237 vik_layer_emit_update(VIK_LAYER(pass_along[0]));
2238}
2239
2240/* end of split/merge routines */
2241
2242
50a14534
EB
2243static void trw_layer_goto_waypoint ( gpointer pass_along[5] )
2244{
2245 VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
2246 if ( wp )
2247 goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(wp->coord) );
2248}
2249
2250static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] )
2251{
2252 gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] );
7d02a0b0 2253 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
50a14534
EB
2254 g_free ( webpage );
2255}
2256
2257const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
2258{
2259 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
2260 {
2261 int i;
2262 gchar *rv;
2263 VikWaypoint *wp;
2264
2265 if ( strcasecmp ( newname, sublayer ) == 0 )
2266 return NULL;
2267
2268 if ( uppercase_exists_in_hash ( l->waypoints, newname ) )
2269 {
4c77d5e0 2270 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Waypoint Already Exists") );
50a14534
EB
2271 return NULL;
2272 }
2273
50a14534
EB
2274 iter = g_hash_table_lookup ( l->waypoints_iters, sublayer );
2275 g_hash_table_steal ( l->waypoints_iters, sublayer );
2276
e4afc73a
EB
2277 wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) );
2278 g_hash_table_remove ( l->waypoints, sublayer );
2279
50a14534
EB
2280 rv = g_strdup(newname);
2281 for ( i = strlen(rv) - 1; i >= 0; i-- )
2282 rv[i] = toupper(rv[i]);
2283
2284 vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
2285
2286 g_hash_table_insert ( l->waypoints, rv, wp );
2287 g_hash_table_insert ( l->waypoints_iters, rv, iter );
2288
2289 /* it hasn't been updated yet so we pass new name */
2290#ifdef VIK_CONFIG_ALPHABETIZED_TRW
2291 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
2292#endif
2293
2294 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
2295 return rv;
2296 }
2297 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
2298 {
2299 int i;
2300 gchar *rv;
2301 VikTrack *tr;
2302 GtkTreeIter *iter;
2303 gchar *orig_key;
2304
2305 if ( strcasecmp ( newname, sublayer ) == 0 )
2306 return NULL;
2307
2308 if ( uppercase_exists_in_hash ( l->tracks, newname ) )
2309 {
4c77d5e0 2310 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Track Already Exists") );
50a14534
EB
2311 return NULL;
2312 }
2313
886031df 2314 g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
50a14534
EB
2315 g_hash_table_steal ( l->tracks, sublayer );
2316
2317 iter = g_hash_table_lookup ( l->tracks_iters, sublayer );
2318 g_hash_table_steal ( l->tracks_iters, sublayer );
2319
2320 rv = g_strdup(newname);
2321 for ( i = strlen(rv) - 1; i >= 0; i-- )
2322 rv[i] = toupper(rv[i]);
2323
2324 vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
2325
2326 g_hash_table_insert ( l->tracks, rv, tr );
2327 g_hash_table_insert ( l->tracks_iters, rv, iter );
2328
2329 /* don't forget about current_tp_track_name, update that too */
2330 if ( l->current_tp_track_name && g_strcasecmp(orig_key,l->current_tp_track_name) == 0 )
2331 {
2332 l->current_tp_track_name = rv;
2333 if ( l->tpwin )
2334 vik_trw_layer_tpwin_set_track_name ( l->tpwin, rv );
2335 }
2336 else if ( l->last_tp_track_name && g_strcasecmp(orig_key,l->last_tp_track_name) == 0 )
2337 l->last_tp_track_name = rv;
2338
2339 g_free ( orig_key );
2340
2341#ifdef VIK_CONFIG_ALPHABETIZED_TRW
2342 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
2343#endif
2344
2345 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
2346 return rv;
2347 }
2348 return NULL;
2349}
2350
2351static gboolean is_valid_geocache_name ( gchar *str )
2352{
2353 gint len = strlen ( str );
0c1044e9 2354 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
2355}
2356
28c82d8b
EB
2357static void trw_layer_track_use_with_filter ( gpointer *pass_along )
2358{
2359 gchar *track_name = (gchar *) pass_along[3];
2360 VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
2361 a_acquire_set_filter_track ( tr, track_name );
2362}
2363
bddd2056
EB
2364static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name )
2365{
2366 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_name );
2367 return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
2368}
2369
2370static void trw_layer_track_google_route_webpage( gpointer *pass_along )
2371{
2372 gchar *track_name = (gchar *) pass_along[3];
2373 VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
2374 if ( tr ) {
2375 gchar *escaped = uri_escape ( tr->comment );
2376 gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
7d02a0b0 2377 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
bddd2056 2378 g_free ( escaped );
bddd2056
EB
2379 g_free ( webpage );
2380 }
2381}
2382
50a14534
EB
2383/* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
2384gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
2385{
2386 static GtkTreeIter staticiter;
2387 static gpointer pass_along[5];
2388 GtkWidget *item;
2389 gboolean rv = FALSE;
2390
2391 pass_along[0] = l;
2392 pass_along[1] = vlp;
2393 pass_along[2] = (gpointer) subtype;
2394 pass_along[3] = sublayer;
2395 staticiter = *iter; /* will exist after function has ended */
2396 pass_along[4] = &staticiter;
2397
2398 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
2399 {
2400 rv = TRUE;
2401
2402 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES, NULL );
2403 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_properties_item), pass_along );
2404 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2405 gtk_widget_show ( item );
2406
21700912
QT
2407 if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
2408 VikTrwLayer *vtl = l;
2409 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, sublayer );
2410 if (tr && tr->property_dialog)
2411 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
2412 }
2413
2cebc318
QT
2414 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL );
2415 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along );
2416 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2417 gtk_widget_show ( item );
2418
2419 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL );
2420 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along );
2421 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2422 gtk_widget_show ( item );
2423
50a14534
EB
2424 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
2425 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
2426 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2427 gtk_widget_show ( item );
2428
2429 if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
2430 {
2431 /* could be a right-click using the tool */
2432 if ( vlp != NULL ) {
4c77d5e0 2433 item = gtk_menu_item_new_with_label ( _("Goto") );
50a14534
EB
2434 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
2435 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2436 gtk_widget_show ( item );
2437 }
2438
2439 if ( is_valid_geocache_name ( (gchar *) sublayer ) )
2440 {
4c77d5e0 2441 item = gtk_menu_item_new_with_label ( _("Visit Geocache Webpage") );
50a14534
EB
2442 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
2443 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2444 gtk_widget_show ( item );
2445 }
2446
2447 }
2448 }
2449
2450 if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
2451 {
2452 item = gtk_menu_item_new ();
2453 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2454 gtk_widget_show ( item );
2455
4c77d5e0 2456 item = gtk_menu_item_new_with_label ( _("Goto Startpoint") );
50a14534
EB
2457 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
2458 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2459 gtk_widget_show ( item );
2460
4c77d5e0 2461 item = gtk_menu_item_new_with_label ( _("Goto \"Center\"") );
50a14534
EB
2462 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
2463 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2464 gtk_widget_show ( item );
2465
4c77d5e0 2466 item = gtk_menu_item_new_with_label ( _("Goto Endpoint") );
50a14534
EB
2467 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
2468 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2469 gtk_widget_show ( item );
111fa174 2470
4c77d5e0 2471 item = gtk_menu_item_new_with_label ( _("Merge By Time") );
111fa174
AF
2472 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
2473 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2474 gtk_widget_show ( item );
2475
4c77d5e0 2476 item = gtk_menu_item_new_with_label ( _("Split By Time") );
111fa174
AF
2477 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
2478 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2479 gtk_widget_show ( item );
7114e879 2480
4c77d5e0 2481 item = gtk_menu_item_new_with_label ( _("Download maps along track...") );
7114e879
QT
2482 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
2483 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2484 gtk_widget_show ( item );
ad0a8c2d 2485
4c77d5e0 2486 item = gtk_menu_item_new_with_label ( _("Apply DEM Data") );
ad0a8c2d
EB
2487 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
2488 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8fb71d6c
EB
2489 gtk_widget_show ( item );
2490
2491 item = gtk_menu_item_new_with_label ( "Extend track end" );
2492 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
2493 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
ad0a8c2d 2494 gtk_widget_show ( item );
5092de80
GB
2495
2496#ifdef VIK_CONFIG_OPENSTREETMAP
4c77d5e0 2497 item = gtk_menu_item_new_with_label ( _("Upload to OSM") );
5092de80
GB
2498 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
2499 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2500 gtk_widget_show ( item );
2501#endif
bddd2056
EB
2502
2503 if ( is_valid_google_route ( l, (gchar *) sublayer ) )
2504 {
2505 item = gtk_menu_item_new_with_label ( "View Google Directions" );
2506 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along );
2507 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2508 gtk_widget_show ( item );
2509 }
2510
28c82d8b
EB
2511 item = gtk_menu_item_new_with_label ( "Use with filter" );
2512 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
2513 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2514 gtk_widget_show ( item );
2515
2516 item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp,
2517 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
2518 g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
2519 if ( item ) {
2520 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2521 gtk_widget_show ( item );
2522 }
50a14534
EB
2523 }
2524
2525 if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
2526 {
2527 item = gtk_menu_item_new ();
2528 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2529 gtk_widget_show ( item );
2530
4c77d5e0 2531 item = gtk_menu_item_new_with_label ( _("New Waypoint") );
50a14534
EB
2532 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
2533 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2534 gtk_widget_show ( item );
2535 }
2536
2537 return rv;
2538}
2539
50a14534
EB
2540
2541/* to be called when last_tpl no long exists. */
2542static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
2543{
2544 if ( vtl->tpwin ) /* can't join with a non-existant TP. */
2545 vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
2546 vtl->last_tpl = NULL;
2547 vtl->last_tp_track_name = NULL;
2548}
2549
2550static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
2551{
2552 if ( vtl->tpwin )
2553 {
2554 if ( destroy)
2555 {
2556 gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
2557 vtl->tpwin = NULL;
2558 }
2559 else
2560 vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
2561 }
2562 if ( vtl->current_tpl )
2563 {
2564 vtl->current_tpl = NULL;
2565 vtl->current_tp_track_name = NULL;
2566 vik_layer_emit_update(VIK_LAYER(vtl));
2567 }
2568}
2569
2570static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
2571{
2572 g_assert ( vtl->tpwin != NULL );
2573 if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
2574 trw_layer_cancel_current_tp ( vtl, TRUE );
2575 else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
2576 {
2577 gchar *name;
2578 if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks ) ) )
2579 {
2580 VikTrack *tr = vik_track_new ();
2581 GList *newglist = g_list_alloc ();
2582 newglist->prev = NULL;
2583 newglist->next = vtl->current_tpl->next;
2584 newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
2585 tr->trackpoints = newglist;
2586
2587 vtl->current_tpl->next->prev = newglist; /* end old track here */
2588 vtl->current_tpl->next = NULL;
2589
2590 vtl->current_tpl = newglist; /* change tp to first of new track. */
2591 vtl->current_tp_track_name = name;
2592
2593 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
2594
2595 vik_trw_layer_add_track ( vtl, name, tr );
2596 vik_layer_emit_update(VIK_LAYER(vtl));
2597 }
2598 }
2599 else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
2600 {
2601 VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
2602 GList *new_tpl;
2603 g_assert(tr != NULL);
2604
2605 /* can't join with a non-existent trackpoint */
2606 vtl->last_tpl = NULL;
2607 vtl->last_tp_track_name = NULL;
2608
2609 if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
2610 {
2611 if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
2612 VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
2613
2614 tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl ); /* this nulls current_tpl->prev and next */
2615
2616 /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
2617 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track_name );
2618
2619 trw_layer_cancel_last_tp ( vtl );
2620
2621 g_free ( vtl->current_tpl->data ); /* TODO: vik_trackpoint_free() */
2622 g_list_free_1 ( vtl->current_tpl );
2623 vtl->current_tpl = new_tpl;
2624 vik_layer_emit_update(VIK_LAYER(vtl));
2625 }
2626 else
2627 {
2628 tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl );
2629 g_free ( vtl->current_tpl->data ); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
2630 g_list_free_1 ( vtl->current_tpl );
2631 trw_layer_cancel_current_tp ( vtl, FALSE );
2632 }
2633 }
2634 else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
2635 {
2636 vtl->last_tpl = vtl->current_tpl;
2637 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track_name );
2638 vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
2639 }
2640 else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
2641 {
2642 vtl->last_tpl = vtl->current_tpl;
2643 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track_name );
2644 vik_layer_emit_update(VIK_LAYER(vtl));
2645 }
2646 else if ( response == VIK_TRW_LAYER_TPWIN_JOIN )
2647 {
2648 VikTrack *tr1 = g_hash_table_lookup ( vtl->tracks, vtl->last_tp_track_name );
2649 VikTrack *tr2 = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
2650
2651 VikTrack *tr_first = tr1, *tr_last = tr2;
2652
2653 gchar *tmp;
2654
2655 if ( (!vtl->last_tpl->next) && (!vtl->current_tpl->next) ) /* both endpoints */
2656 vik_track_reverse ( tr2 ); /* reverse the second, that way second track clicked will be later. */
2657 else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->prev) )
2658 vik_track_reverse ( tr1 );
2659 else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->next) ) /* clicked startpoint, then endpoint -- concat end to start */
2660 {
2661 tr_first = tr2;
2662 tr_last = tr1;
2663 }
2664 /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
2665
2666 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. */
2667 VIK_TRACKPOINT(tr_last->trackpoints->data)->newsegment = FALSE;
2668 tr1->trackpoints = g_list_concat ( tr_first->trackpoints, tr_last->trackpoints );
2669 tr2->trackpoints = NULL;
2670
2671 tmp = vtl->current_tp_track_name;
2672
2673 vtl->current_tp_track_name = vtl->last_tp_track_name; /* current_tp stays the same (believe it or not!) */
2674 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
2675
2676 /* if we did this before, trw_layer_delete_track would have canceled the current tp because
2677 * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
e4afc73a 2678 vik_trw_layer_delete_track ( vtl, tmp );
50a14534
EB
2679
2680 trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
2681 vik_layer_emit_update(VIK_LAYER(vtl));
2682 }
2683 else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
2684 vik_layer_emit_update (VIK_LAYER(vtl));
2685}
2686
2687static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
2688{
2689 if ( ! vtl->tpwin )
2690 {
2691 vtl->tpwin = vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl) );
2692 g_signal_connect_swapped ( GTK_DIALOG(vtl->tpwin), "response", G_CALLBACK(trw_layer_tpwin_response), vtl );
2693 /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
2694 g_signal_connect_swapped ( vtl->tpwin, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp), vtl );
2695 gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
2696 }
2697 if ( vtl->current_tpl )
2698 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
2699 /* set layer name and TP data */
2700}
2701
941aa6e9
AF
2702/***************************************************************************
2703 ** Tool code
2704 ***************************************************************************/
50a14534 2705
941aa6e9 2706/*** Utility data structures and functions ****/
50a14534
EB
2707
2708typedef struct {
2709 gint x, y;
2710 gint closest_x, closest_y;
2711 gchar *closest_wp_name;
2712 VikWaypoint *closest_wp;
2713 VikViewport *vvp;
2714} WPSearchParams;
2715
941aa6e9
AF
2716typedef struct {
2717 gint x, y;
2718 gint closest_x, closest_y;
2719 gchar *closest_track_name;
2720 VikTrackpoint *closest_tp;
2721 VikViewport *vvp;
2722 GList *closest_tpl;
2723} TPSearchParams;
2724
50a14534
EB
2725static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
2726{
2727 gint x, y;
2728 if ( !wp->visible )
2729 return;
2730
2731 vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
2732
2733 if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
2734 ((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */
2735 abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
2736 {
2737 params->closest_wp_name = name;
2738 params->closest_wp = wp;
2739 params->closest_x = x;
2740 params->closest_y = y;
2741 }
2742}
2743
941aa6e9 2744static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
50a14534 2745{
941aa6e9
AF
2746 GList *tpl = t->trackpoints;
2747 VikTrackpoint *tp;
50a14534 2748
941aa6e9
AF
2749 if ( !t->visible )
2750 return;
50a14534 2751
941aa6e9
AF
2752 while (tpl)
2753 {
2754 gint x, y;
2755 tp = VIK_TRACKPOINT(tpl->data);
2756
2757 vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
2758
2759 if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
2760 ((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */
2761 abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
50a14534 2762 {
941aa6e9
AF
2763 params->closest_track_name = name;
2764 params->closest_tp = tp;
2765 params->closest_tpl = tpl;
2766 params->closest_x = x;
2767 params->closest_y = y;
50a14534 2768 }
941aa6e9 2769 tpl = tpl->next;
50a14534 2770 }
941aa6e9
AF
2771}
2772
2773static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
2774{
2775 TPSearchParams params;
2776 params.x = x;
2777 params.y = y;
2778 params.vvp = vvp;
2779 params.closest_track_name = NULL;
2780 params.closest_tp = NULL;
2781 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
2782 return params.closest_tp;
50a14534
EB
2783}
2784
2785static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
2786{
2787 WPSearchParams params;
2788 params.x = x;
2789 params.y = y;
2790 params.vvp = vvp;
2791 params.closest_wp = NULL;
2792 params.closest_wp_name = NULL;
2793 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
2794 return params.closest_wp;
2795}
2796
7432fddf
AF
2797/* background drawing hook, to be passed the viewport */
2798static gboolean tool_sync_done = TRUE;
2799
2800static gboolean tool_sync(gpointer data)
2801{
2802 VikViewport *vvp = data;
2803 gdk_threads_enter();
2804 vik_viewport_sync(vvp);
2805 tool_sync_done = TRUE;
2806 gdk_threads_leave();
2807 return FALSE;
2808}
2809
2810typedef struct {
2811 VikViewport *vvp;
2812 gboolean holding;
2813 GdkGC *gc;
2814 int oldx, oldy;
2815} tool_ed_t;
2816
2817static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
2818{
2819 t->holding = TRUE;
2820 t->gc = vik_viewport_new_gc (t->vvp, "black", 2);
2821 gdk_gc_set_function ( t->gc, GDK_INVERT );
2822 vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
2823 vik_viewport_sync(t->vvp);
2824 t->oldx = x;
2825 t->oldy = y;
2826}
2827
2828static void marker_moveto ( tool_ed_t *t, gint x, gint y )
2829{
2830 VikViewport *vvp = t->vvp;
2831 vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
2832 vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
2833 t->oldx = x;
2834 t->oldy = y;
7b203521 2835
7432fddf
AF
2836 if (tool_sync_done) {
2837 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
2838 tool_sync_done = FALSE;
2839 }
2840}
2841
2842static void marker_end_move ( tool_ed_t *t )
2843{
2844 vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
2845 g_object_unref ( t->gc );
2846 t->holding = FALSE;
2847}
2848
941aa6e9
AF
2849/*** Edit waypoint ****/
2850
2851static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp)
2852{
7432fddf
AF
2853 tool_ed_t *t = g_new(tool_ed_t, 1);
2854 t->vvp = vvp;
2855 t->holding = FALSE;
2856 return t;
941aa6e9
AF
2857}
2858
7432fddf 2859static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
50a14534
EB
2860{
2861 WPSearchParams params;
7432fddf
AF
2862 tool_ed_t *t = data;
2863 VikViewport *vvp = t->vvp;
50a14534 2864
941aa6e9
AF
2865 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
2866 return FALSE;
7432fddf
AF
2867
2868 if ( t->holding ) {
2869 return TRUE;
2870 }
2871
50a14534
EB
2872 if ( vtl->current_wp && vtl->current_wp->visible )
2873 {
2874 /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
2875 gint x, y;
2876 vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
2877
c75d78d7
AF
2878 if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
2879 abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
50a14534
EB
2880 {
2881 if ( event->button == 3 )
2882 vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
7432fddf
AF
2883 else {
2884 marker_begin_move(t, event->x, event->y);
2885 }
50a14534
EB
2886 return TRUE;
2887 }
2888 }
2889
2890 params.vvp = vvp;
2891 params.x = event->x;
2892 params.y = event->y;
2893 params.closest_wp_name = NULL;
2894 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
2895 params.closest_wp = NULL;
2896 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
2897 if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
2898 {
7432fddf
AF
2899 /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
2900 marker_begin_move(t, event->x, event->y);
7742da66 2901 g_critical("shouldn't be here");
7432fddf 2902 exit(1);
50a14534
EB
2903 }
2904 else if ( params.closest_wp )
2905 {
2906 if ( event->button == 3 )
2907 vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
2908 else
2909 vtl->waypoint_rightclick = FALSE;
2910
2911 vtl->current_wp = params.closest_wp;
2912 vtl->current_wp_name = params.closest_wp_name;
50a14534
EB
2913
2914 if ( params.closest_wp )
2915 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) );
2916
2917 /* could make it so don't update if old WP is off screen and new is null but oh well */
2918 vik_layer_emit_update ( VIK_LAYER(vtl) );
2919 return TRUE;
2920 }
2921
2922 vtl->current_wp = NULL;
2923 vtl->current_wp_name = NULL;
50a14534 2924 vtl->waypoint_rightclick = FALSE;
7432fddf
AF
2925 vik_layer_emit_update ( VIK_LAYER(vtl) );
2926 return FALSE;
2927}
2928
2929static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
2930{
2931 tool_ed_t *t = data;
2932 VikViewport *vvp = t->vvp;
2933
2934 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
2935 return FALSE;
2936
2937 if ( t->holding ) {
2938 VikCoord new_coord;
2939 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
2940
2941 /* snap to TP */
2942 if ( event->state & GDK_CONTROL_MASK )
2943 {
2944 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
2945 if ( tp )
2946 new_coord = tp->coord;
2947 }
2948
2949 /* snap to WP */
2950 if ( event->state & GDK_SHIFT_MASK )
2951 {
2952 VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
2953 if ( wp && wp != vtl->current_wp )
2954 new_coord = wp->coord;
2955 }
2956
2957 {
2958 gint x, y;
2959 vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
7b203521 2960
7432fddf
AF
2961 marker_moveto ( t, x, y );
2962 }
2963 return TRUE;
2964 }
50a14534
EB
2965 return FALSE;
2966}
2967
7432fddf 2968static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
941aa6e9 2969{
7432fddf
AF
2970 tool_ed_t *t = data;
2971 VikViewport *vvp = t->vvp;
2972
941aa6e9
AF
2973 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
2974 return FALSE;
7432fddf
AF
2975
2976 if ( t->holding && event->button == 1 )
941aa6e9
AF
2977 {
2978 VikCoord new_coord;
941aa6e9
AF
2979 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
2980
2981 /* snap to TP */
2982 if ( event->state & GDK_CONTROL_MASK )
2983 {
2984 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
2985 if ( tp )
2986 new_coord = tp->coord;
2987 }
2988
2989 /* snap to WP */
2990 if ( event->state & GDK_SHIFT_MASK )
2991 {
2992 VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
2993 if ( wp && wp != vtl->current_wp )
2994 new_coord = wp->coord;
2995 }
2996
7432fddf
AF
2997 marker_end_move ( t );
2998
941aa6e9
AF
2999 vtl->current_wp->coord = new_coord;
3000 vik_layer_emit_update ( VIK_LAYER(vtl) );
3001 return TRUE;
3002 }
3003 /* PUT IN RIGHT PLACE!!! */
7432fddf 3004 if ( event->button == 3 && vtl->waypoint_rightclick )
941aa6e9
AF
3005 {
3006 if ( vtl->wp_right_click_menu )
3007 gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
3008 vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
3009 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 ) );
3010 gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
3011 vtl->waypoint_rightclick = FALSE;
3012 }
3013 return FALSE;
3014}
3015
98f5364d
EB
3016/**** Begin track ***/
3017static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp)
3018{
3019 return vvp;
3020}
3021
3022static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
3023{
3024 vtl->current_track = NULL;
3025 return tool_new_track_click ( vtl, event, vvp );
3026}
3027
941aa6e9
AF
3028/*** New track ****/
3029
3030static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
3031{
3032 return vvp;
3033}
3034
7b203521
EB
3035typedef struct {
3036 VikTrwLayer *vtl;
3037 VikViewport *vvp;
3038 gint x1,y1,x2,y2;
3039} new_track_move_passalong_t;
3040
3041/* sync and undraw, but only when we have time */
3042static gboolean ct_sync ( gpointer passalong )
3043{
3044 new_track_move_passalong_t *p = (new_track_move_passalong_t *) passalong;
3045 vik_viewport_sync ( p->vvp );
3046 gdk_gc_set_function ( p->vtl->current_track_gc, GDK_INVERT );
3047 vik_viewport_draw_line ( p->vvp, p->vtl->current_track_gc, p->x1, p->y1, p->x2, p->y2 );
3048 gdk_gc_set_function ( p->vtl->current_track_gc, GDK_COPY );
3049 p->vtl->ct_sync_done = TRUE;
3050 g_free ( p );
3051 return FALSE;
3052}
3053
165d30aa 3054static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
7b203521
EB
3055{
3056 /* if we haven't sync'ed yet, we don't have time to do more. */
3057 if ( vtl->ct_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
3058 GList *iter = vtl->current_track->trackpoints;
3059 new_track_move_passalong_t *passalong;
3060 gint x1, y1;
3061
3062 while ( iter->next )
3063 iter = iter->next;
3064 gdk_gc_set_function ( vtl->current_track_gc, GDK_INVERT );
3065 vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
3066 vik_viewport_draw_line ( vvp, vtl->current_track_gc, x1, y1, event->x, event->y );
3067 gdk_gc_set_function ( vtl->current_track_gc, GDK_COPY );
3068
3069 passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
3070 passalong->vtl = vtl;
3071 passalong->vvp = vvp;
3072 passalong->x1 = x1;
3073 passalong->y1 = y1;
3074 passalong->x2 = event->x;
3075 passalong->y2 = event->y;
3076
3077 /* this will sync and undraw when we have time to */
3078 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, ct_sync, passalong, NULL);
3079 vtl->ct_sync_done = FALSE;
165d30aa 3080 return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
7b203521 3081 }
165d30aa 3082 return VIK_LAYER_TOOL_ACK;
7b203521
EB
3083}
3084
777e2d4d
EB
3085static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
3086{
3087 if ( vtl->current_track && event->keyval == GDK_Escape ) {
3088 vtl->current_track = NULL;
3089 vik_layer_emit_update ( VIK_LAYER(vtl) );
3090 return TRUE;
3091 } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
3092 /* undo */
3093 if ( vtl->current_track->trackpoints )
3094 {
3095 GList *last = g_list_last(vtl->current_track->trackpoints);
3096 g_free ( last->data );
3097 vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
3098 }
3099 vik_layer_emit_update ( VIK_LAYER(vtl) );
3100 return TRUE;
3101 }
3102 return FALSE;
3103}
3104
941aa6e9 3105static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
50a14534
EB
3106{
3107 VikTrackpoint *tp;
3108
941aa6e9
AF
3109 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
3110 return FALSE;
3111
50a14534
EB
3112 if ( event->button == 3 && vtl->current_track )
3113 {
3114 /* undo */
3115 if ( vtl->current_track->trackpoints )
3116 {
3117 GList *last = g_list_last(vtl->current_track->trackpoints);
3118 g_free ( last->data );
3119 vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
3120 }
3121 vik_layer_emit_update ( VIK_LAYER(vtl) );
3122 return TRUE;
3123 }
3124
3125 if ( event->type == GDK_2BUTTON_PRESS )
3126 {
3127 /* subtract last (duplicate from double click) tp then end */
3128 if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
3129 {
3130 GList *last = g_list_last(vtl->current_track->trackpoints);
3131 g_free ( last->data );
3132 vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
3133 /* undo last, then end */
3134 vtl->current_track = NULL;
3135 }
8e9c992d 3136 vik_layer_emit_update ( VIK_LAYER(vtl) );
50a14534
EB
3137 return TRUE;
3138 }
3139
3140 if ( ! vtl->current_track )
3141 {
3142 gchar *name;
3143 if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ) ) )
3144 {
3145 vtl->current_track = vik_track_new();
3146 vtl->current_track->visible = TRUE;
3147 vik_trw_layer_add_track ( vtl, name, vtl->current_track );
98f5364d
EB
3148
3149 /* incase it was created by begin track */
3150 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
50a14534
EB
3151 }
3152 else
3153 return TRUE;
3154 }
3155 tp = vik_trackpoint_new();
3156 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
3157
3158 /* snap to other TP */
3159 if ( event->state & GDK_CONTROL_MASK )
3160 {
3161 VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
3162 if ( other_tp )
3163 tp->coord = other_tp->coord;
3164 }
3165
3166 tp->newsegment = FALSE;
3167 tp->has_timestamp = FALSE;
3168 tp->timestamp = 0;
3169 tp->altitude = VIK_DEFAULT_ALTITUDE;
3170 vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
3171
3172 vtl->ct_x1 = vtl->ct_x2;
3173 vtl->ct_y1 = vtl->ct_y2;
3174 vtl->ct_x2 = event->x;
3175 vtl->ct_y2 = event->y;
3176
3177 vik_layer_emit_update ( VIK_LAYER(vtl) );
3178 return TRUE;
3179}
3180
941aa6e9
AF
3181
3182/*** New waypoint ****/
3183
3184static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
3185{
3186 return vvp;
3187}
3188
3189static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
3190{
3191 VikCoord coord;
3192 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
3193 return FALSE;
3194 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
3195 if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible)
3196 vik_layer_emit_update ( VIK_LAYER(vtl) );
3197 return TRUE;
3198}
3199
3200
3201/*** Edit trackpoint ****/
3202
3203static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp)
3204{
7432fddf 3205 tool_ed_t *t = g_new(tool_ed_t, 1);
33534cd8
AF
3206 t->vvp = vvp;
3207 t->holding = FALSE;
3208 return t;
941aa6e9
AF
3209}
3210
33534cd8 3211static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
941aa6e9 3212{
7432fddf 3213 tool_ed_t *t = data;
33534cd8
AF
3214 VikViewport *vvp = t->vvp;
3215 TPSearchParams params;
941aa6e9
AF
3216 /* OUTDATED DOCUMENTATION:
3217 find 5 pixel range on each side. then put these UTM, and a pointer
3218 to the winning track name (and maybe the winning track itself), and a
3219 pointer to the winning trackpoint, inside an array or struct. pass
3220 this along, do a foreach on the tracks which will do a foreach on the
3221 trackpoints. */
3222 params.vvp = vvp;
3223 params.x = event->x;
3224 params.y = event->y;
3225 params.closest_track_name = NULL;
3226 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
3227 params.closest_tp = NULL;
3228
7432fddf
AF
3229 if ( event->button != 1 )
3230 return FALSE;
3231
941aa6e9
AF
3232 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
3233 return FALSE;
3234
3235 if ( vtl->current_tpl )
3236 {
3237 /* 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.) */
3238 VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
3239 VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name));
3240 gint x, y;
3241 g_assert ( current_tr );
3242
3243 vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
3244
3245 if ( current_tr->visible &&
3246 abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
7432fddf
AF
3247 abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
3248 marker_begin_move ( t, event->x, event->y );
941aa6e9
AF
3249 return TRUE;
3250 }
3251
3252 vtl->last_tpl = vtl->current_tpl;
3253 vtl->last_tp_track_name = vtl->current_tp_track_name;
3254 }
3255
3256 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
3257
3258 if ( params.closest_tp )
3259 {
3260 vtl->current_tpl = params.closest_tpl;
3261 vtl->current_tp_track_name = params.closest_track_name;
3262 vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ) );
3263 trw_layer_tpwin_init ( vtl );
3264 vik_layer_emit_update ( VIK_LAYER(vtl) );
3265 return TRUE;
3266 }
3267
3268 /* these aren't the droids you're looking for */
3269 return FALSE;
3270}
3271
33534cd8
AF
3272static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
3273{
7432fddf 3274 tool_ed_t *t = data;
33534cd8
AF
3275 VikViewport *vvp = t->vvp;
3276
3277 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
3278 return FALSE;
3279
3280 if ( t->holding )
3281 {
3282 VikCoord new_coord;
33534cd8
AF
3283 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
3284
3285 /* snap to TP */
3286 if ( event->state & GDK_CONTROL_MASK )
3287 {
3288 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
3289 if ( tp && tp != vtl->current_tpl->data )
3290 new_coord = tp->coord;
3291 }
3292 // VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
7432fddf
AF
3293 {
3294 gint x, y;
3295 vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
3296 marker_moveto ( t, x, y );
3297 }
33534cd8
AF
3298
3299 return TRUE;
3300 }
3301 return FALSE;
3302}
3303
33534cd8 3304static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
941aa6e9 3305{
7432fddf 3306 tool_ed_t *t = data;
33534cd8
AF
3307 VikViewport *vvp = t->vvp;
3308
941aa6e9
AF
3309 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
3310 return FALSE;
7432fddf
AF
3311 if ( event->button != 1)
3312 return FALSE;
33534cd8 3313
7432fddf 3314 if ( t->holding ) {
941aa6e9 3315 VikCoord new_coord;
941aa6e9
AF
3316 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
3317
3318 /* snap to TP */
3319 if ( event->state & GDK_CONTROL_MASK )
3320 {
3321 VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
3322 if ( tp && tp != vtl->current_tpl->data )
3323 new_coord = tp->coord;
3324 }
3325
3326 VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
3327
7432fddf 3328 marker_end_move ( t );
33534cd8 3329
941aa6e9
AF
3330 /* diff dist is diff from orig */
3331 vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
3332 /* can't join with itself! */
3333 trw_layer_cancel_last_tp ( vtl );
3334
3335 vik_layer_emit_update ( VIK_LAYER(vtl) );
3336 return TRUE;
3337 }
3338 return FALSE;
3339}
3340
3341
1eef1bde
QT
3342/*** Magic Scissors ***/
3343static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
3344{
3345 return vvp;
3346}
3347
3348static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
3349{
3350 VikCoord tmp;
0c1044e9 3351 if ( !vtl ) return FALSE;
1eef1bde 3352 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
c3deba01
EB
3353 if ( event->button == 3 && vtl->magic_scissors_current_track ) {
3354 VikCoord *new_end;
3355 new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track );
3356 if ( new_end ) {
3357 vtl->magic_scissors_coord = *new_end;
3358 g_free ( new_end );
3359 vik_layer_emit_update ( VIK_LAYER(vtl) );
3360 /* remove last ' to:...' */
3361 if ( vtl->magic_scissors_current_track->comment ) {
3362 gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' );
3363 if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) {
3364 gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment,
3365 last_to - vtl->magic_scissors_current_track->comment - 1);
3366 vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
3367 }
3368 }
3369 }
3370 }
3371 else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) {
1eef1bde
QT
3372 struct LatLon start, end;
3373 gchar *cmd;
bddd2056 3374
1eef1bde
QT
3375 vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start );
3376 vik_coord_to_latlon ( &(tmp), &end );
3377 cmd = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, start.lat, start.lon, end.lat, end.lon );
bddd2056
EB
3378 vtl->magic_scissors_coord = tmp; /* for continuations */
3379
3380 /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
3381 if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) {
3382 vtl->magic_scissors_append = TRUE; // merge tracks. keep started true.
3383 } else {
3384 vtl->magic_scissors_check_added_track = TRUE;
3385 vtl->magic_scissors_started = FALSE;
3386 }
3387
1eef1bde
QT
3388 a_babel_convert_from_shellcommand ( vtl, cmd, "google", NULL, NULL );
3389 g_free ( cmd );
bddd2056
EB
3390
3391 /* see if anything was done -- a track was added or appended to */
3392 if ( vtl->magic_scissors_check_added_track && vtl->magic_scissors_added_track_name ) {
3393 VikTrack *tr;
3394
3395 tr = g_hash_table_lookup ( vtl->tracks, vtl->magic_scissors_added_track_name );
3396
3397 if ( tr )
3398 vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f%f", start.lat, start.lon, end.lat, end.lon ) );
3399
3400 vtl->magic_scissors_current_track = tr;
3401
3402 g_free ( vtl->magic_scissors_added_track_name );
3403 vtl->magic_scissors_added_track_name = NULL;
3404 } else if ( vtl->magic_scissors_append == FALSE && vtl->magic_scissors_current_track ) {
3405 /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
3406 gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->magic_scissors_current_track->comment, end.lat, end.lon );
3407 vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
3408 }
3409 vtl->magic_scissors_check_added_track = FALSE;
3410 vtl->magic_scissors_append = FALSE;
3411
1eef1bde
QT
3412 vik_layer_emit_update ( VIK_LAYER(vtl) );
3413 } else {
bddd2056 3414 vtl->magic_scissors_started = TRUE;
1eef1bde 3415 vtl->magic_scissors_coord = tmp;
bddd2056 3416 vtl->magic_scissors_current_track = NULL;
1eef1bde 3417 }
1eef1bde
QT
3418 return TRUE;
3419}
3420
941aa6e9
AF
3421/*** Show picture ****/
3422
3423static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
3424{
3425 return vvp;
3426}
3427
3428/* Params are: vvp, event, last match found or NULL */
3429static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] )
3430{
3431 if ( wp->image && wp->visible )
3432 {
3433 gint x, y, slackx, slacky;
3434 GdkEventButton *event = (GdkEventButton *) params[1];
3435
3436 vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
3437 slackx = wp->image_width / 2;
3438 slacky = wp->image_height / 2;
3439 if ( x <= event->x + slackx && x >= event->x - slackx
3440 && y <= event->y + slacky && y >= event->y - slacky )
3441 {
3442 params[2] = wp->image; /* we've found a match. however continue searching
3443 * since we want to find the last match -- that
3444 * is, the match that was drawn last. */
3445 }
3446 }
3447}
3448
3449static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
3450{
3451 gpointer params[3] = { vvp, event, NULL };
3452 if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
3453 return FALSE;
3454 g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
3455 if ( params[2] )
3456 {
3457 /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
3458#ifdef WINDOWS
3459 ShellExecute(NULL, NULL, (char *) params[2], NULL, ".\\", 0);
3460#else /* WINDOWS */
3461 GError *err = NULL;
3462 gchar *quoted_file = g_shell_quote ( (gchar *) params[2] );
3463 gchar *cmd = g_strdup_printf ( "eog %s", quoted_file );
3464 g_free ( quoted_file );
3465 if ( ! g_spawn_command_line_async ( cmd, &err ) )
3466 {
4c77d5e0 3467 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch eog to open file.") );
941aa6e9
AF
3468 g_error_free ( err );
3469 }
3470 g_free ( cmd );
3471#endif /* WINDOWS */
3472 return TRUE; /* found a match */
3473 }
3474 else
3475 return FALSE; /* go through other layers, searching for a match */
3476}
3477
3478/***************************************************************************
3479 ** End tool code
3480 ***************************************************************************/
3481
3482
3483
3484
3485
50a14534
EB
3486static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
3487{
3488 if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
3489 *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
3490}
3491
3492static void create_thumbnails_thread ( GSList *pics, gpointer threaddata )
3493{
3494 guint total = g_slist_length(pics), done = 0;
3495 while ( pics )
3496 {
3497 a_thumbnails_create ( (gchar *) pics->data );
3498 a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
3499 pics = pics->next;
3500 }
3501}
3502
3503static void free_pics_slist ( GSList *pics )
3504{
3505 while ( pics )
3506 {
3507 g_free ( pics->data );
3508 pics = g_slist_delete_link ( pics, pics );
3509 }
3510}
3511
3512static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
3513{
3514 if ( ! vtl->has_verified_thumbnails )
3515 {
3516 GSList *pics = NULL;
3517 g_hash_table_foreach ( vtl->waypoints, (GHFunc) image_wp_make_list, &pics );
3518 if ( pics )
3519 {
3520 gint len = g_slist_length ( pics );
4c77d5e0 3521 gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
50a14534
EB
3522 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 );
3523 g_free ( tmp );
3524 }
3525 }
3526}
3527
3528VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
3529{
3530 return vtl->coord_mode;
3531}
3532
3533
3534
3535static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode )
3536{
3537 vik_coord_convert ( &(wp->coord), *dest_mode );
3538}
3539
3540static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode )
3541{
3542 vik_track_convert ( tr, *dest_mode );
3543}
3544
3545static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode )
3546{
3547 if ( vtl->coord_mode != dest_mode )
3548 {
3549 vtl->coord_mode = dest_mode;
3550 g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_convert, &dest_mode );
3551 g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
3552 }
3553}
e4afc73a
EB
3554
3555VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, gchar *name )
3556{
3557 return g_hash_table_lookup ( vtl->waypoints, name );
3558}
3559
3560VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, gchar *name )
3561{
3562 return g_hash_table_lookup ( vtl->tracks, name );
3563}
20c7a3a0 3564
2cebc318 3565static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection)
20c7a3a0
QT
3566{
3567 vtl->menu_selection = selection;
3568}
3569
3570static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl)
3571{
3572 return(vtl->menu_selection);
3573}
3574
7114e879
QT
3575/* ----------- Downloading maps along tracks --------------- */
3576
3577static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
3578{
3579 /* TODO: calculating based on current size of viewport */
3580 const gdouble w_at_zoom_0_125 = 0.0013;
3581 const gdouble h_at_zoom_0_125 = 0.0011;
3582 gdouble zoom_factor = zoom_level/0.125;
3583
3584 wh->lat = h_at_zoom_0_125 * zoom_factor;
3585 wh->lon = w_at_zoom_0_125 * zoom_factor;
3586
3587 return 0; /* all OK */
3588}
3589
35e22ed8
QT
3590static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
3591{
3592 if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
3593 (dist->lat >= ABS(to->north_south - from->north_south)))
3594 return NULL;
3595
3596 VikCoord *coord = g_malloc(sizeof(VikCoord));
3597 coord->mode = VIK_COORD_LATLON;
3598
3599 if (ABS(gradient) < 1) {
3600 if (from->east_west > to->east_west)
3601 coord->east_west = from->east_west - dist->lon;
3602 else
3603 coord->east_west = from->east_west + dist->lon;
3604 coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
3605 } else {
3606 if (from->north_south > to->north_south)
3607 coord->north_south = from->north_south - dist->lat;
3608 else
3609 coord->north_south = from->north_south + dist->lat;
3610 coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
3611 }
3612
3613 return coord;
3614}
3615
3616static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
3617{
3618 /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
3619 gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
3620
3621 VikCoord *next = from;
3622 while (TRUE) {
3623 if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
3624 break;
3625 list = g_list_prepend(list, next);
3626 }
3627
3628 return list;
3629}
3630
7114e879
QT
3631void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
3632{
3633 typedef struct _Rect {
3634 VikCoord tl;
3635 VikCoord br;
35e22ed8 3636 VikCoord center;
7114e879 3637 } Rect;
35e22ed8 3638#define GLRECT(iter) ((Rect *)((iter)->data))
7114e879
QT
3639
3640 struct LatLon wh;
35e22ed8 3641 GList *rects_to_download = NULL;
7114e879
QT
3642 GList *rect_iter;
3643
3644 if (get_download_area_width(vvp, zoom_level, &wh))
3645 return;
3646
3647 GList *iter = tr->trackpoints;
35e22ed8
QT
3648 if (!iter)
3649 return;
7114e879
QT
3650
3651 gboolean new_map = TRUE;
3652 VikCoord *cur_coord, tl, br;
3653 Rect *rect;
7114e879
QT
3654 while (iter) {
3655 cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
3656 if (new_map) {
3657 vik_coord_set_area(cur_coord, &wh, &tl, &br);
3658 rect = g_malloc(sizeof(Rect));
3659 rect->tl = tl;
3660 rect->br = br;
35e22ed8
QT
3661 rect->center = *cur_coord;
3662 rects_to_download = g_list_prepend(rects_to_download, rect);
7114e879
QT
3663 new_map = FALSE;
3664 iter = iter->next;
3665 continue;
3666 }
3667 gboolean found = FALSE;
35e22ed8
QT
3668 for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
3669 if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
7114e879
QT
3670 found = TRUE;
3671 break;
3672 }
3673 }
3674 if (found)
3675 iter = iter->next;
3676 else
3677 new_map = TRUE;
3678 }
35e22ed8
QT
3679
3680 /* fill-ins for far apart points */
3681 GList *cur_rect, *next_rect;
3682 GList *fillins = NULL;
3683 for (cur_rect = rects_to_download;
3684 (next_rect = cur_rect->next) != NULL;
3685 cur_rect = cur_rect->next) {
3686 if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
3687 (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
3688 fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
3689 }
3690 }
3691
3692 if (fillins) {
3693 GList *iter = fillins;
3694 while (iter) {
3695 cur_coord = (VikCoord *)(iter->data);
3696 vik_coord_set_area(cur_coord, &wh, &tl, &br);
3697 rect = g_malloc(sizeof(Rect));
3698 rect->tl = tl;
3699 rect->br = br;
3700 rect->center = *cur_coord;
3701 rects_to_download = g_list_prepend(rects_to_download, rect);
3702 iter = iter->next;
3703 }
3704 }
3705
3706 for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
7114e879
QT
3707 maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
3708 }
3709
35e22ed8
QT
3710 if (fillins) {
3711 for (iter = fillins; iter; iter = iter->next)
3712 g_free(iter->data);
3713 g_list_free(fillins);
3714 }
3715 if (rects_to_download) {
3716 for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
3717 g_free(rect_iter->data);
3718 g_list_free(rects_to_download);
3719 }
7114e879
QT
3720}
3721
7114e879
QT
3722static void trw_layer_download_map_along_track_cb(gpointer pass_along[6])
3723{
3724 VikMapsLayer *vml;
3725 gint selected_map, default_map;
3726 gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
3727 gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
3728 gint selected_zoom, default_zoom;
3729 int i,j;
3730
3731
3732 VikTrwLayer *vtl = pass_along[0];
3733 VikLayersPanel *vlp = pass_along[1];
3734 VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
3735 VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
3736
3737 GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS);
3738 int num_maps = g_list_length(vmls);
3739
3740 if (!num_maps) {
4c77d5e0 3741 a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR, _("No map layer in use. Create one first"), NULL);
7114e879
QT
3742 return;
3743 }
3744
3745 gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
3746 VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
3747
3748 gchar **np = map_names;
3749 VikMapsLayer **lp = map_layers;
3750 for (i = 0; i < num_maps; i++) {
3751 gboolean dup = FALSE;
3752 vml = (VikMapsLayer *)(vmls->data);
3753 for (j = 0; j < i; j++) { /* no duplicate allowed */
3754 if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) {
3755 dup = TRUE;
3756 break;
3757 }
3758 }
3759 if (!dup) {
3760 *lp++ = vml;
3761 *np++ = vik_maps_layer_get_map_label(vml);
3762 }
3763 vmls = vmls->next;
3764 }
3765 *lp = NULL;
3766 *np = NULL;
3767 num_maps = lp - map_layers;
3768
3769 for (default_map = 0; default_map < num_maps; default_map++) {
3770 /* TODO: check for parent layer's visibility */
3771 if (VIK_LAYER(map_layers[default_map])->visible)
3772 break;
3773 }
3774 default_map = (default_map == num_maps) ? 0 : default_map;
3775
3776 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
3777 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
3778 if (cur_zoom == zoom_vals[default_zoom])
3779 break;
3780 }
3781 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
3782
3783 if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom))
3784 goto done;
3785
3786 vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
3787
3788done:
3789 for (i = 0; i < num_maps; i++)
3790 g_free(map_names[i]);
3791 g_free(map_names);
3792 g_free(map_layers);
3793
3794 g_list_free(vmls);
3795
3796}
0c1044e9 3797