2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
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.
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.
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
22 #define WAYPOINT_FONT "Sans 8"
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 */
32 #include "vikmapslayer.h"
33 #include "viktrwlayer_tpwin.h"
34 #include "viktrwlayer_propwin.h"
35 #include "garminsymbols.h"
36 #include "thumbnails.h"
37 #include "background.h"
42 #include "geonamessearch.h"
43 #ifdef VIK_CONFIG_OPENSTREETMAP
44 #include "osm-traces.h"
49 #include "icons/icons.h"
63 #include <gdk/gdkkeysyms.h>
65 #include <glib/gstdio.h>
66 #include <glib/gi18n.h>
68 /* Relax some dependencies */
69 #if ! GLIB_CHECK_VERSION(2,12,0)
70 static gboolean
return_true (gpointer a
, gpointer b
, gpointer c
) { return TRUE
; }
71 static g_hash_table_remove_all (GHashTable
*ght
) { g_hash_table_foreach_remove ( ght
, (GHRFunc
) return_true
, FALSE
); }
74 #define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js"
75 #define VIK_TRW_LAYER_TRACK_GC 13
76 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
77 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
78 #define VIK_TRW_LAYER_TRACK_GC_MAX 11
79 #define VIK_TRW_LAYER_TRACK_GC_BLACK 12
81 #define DRAWMODE_BY_TRACK 0
82 #define DRAWMODE_BY_VELOCITY 1
83 #define DRAWMODE_ALL_BLACK 2
88 /* this is how it knows when you click if you are clicking close to a trackpoint. */
89 #define TRACKPOINT_SIZE_APPROX 5
90 #define WAYPOINT_SIZE_APPROX 5
92 #define MIN_STOP_LENGTH 15
93 #define MAX_STOP_LENGTH 86400
94 #define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
95 /* this is multiplied by user-inputted value from 1-100. */
97 VIK_TRW_LAYER_SUBLAYER_TRACKS
,
98 VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
,
99 VIK_TRW_LAYER_SUBLAYER_TRACK
,
100 VIK_TRW_LAYER_SUBLAYER_WAYPOINT
103 enum { WP_SYMBOL_FILLED_SQUARE
, WP_SYMBOL_SQUARE
, WP_SYMBOL_CIRCLE
, WP_SYMBOL_X
, WP_NUM_SYMBOLS
};
105 struct _VikTrwLayer
{
108 GHashTable
*tracks_iters
;
109 GHashTable
*waypoints_iters
;
110 GHashTable
*waypoints
;
111 GtkTreeIter waypoints_iter
, tracks_iter
;
112 gboolean tracks_visible
, waypoints_visible
;
115 guint8 drawelevation
;
116 guint8 elevation_factor
;
120 guint8 line_thickness
;
121 guint8 bg_line_thickness
;
125 gboolean wp_draw_symbols
;
127 gdouble velocity_min
, velocity_max
;
129 guint16 track_gc_iter
;
130 GdkGC
*current_track_gc
;
133 GdkGC
*waypoint_text_gc
;
134 GdkGC
*waypoint_bg_gc
;
135 GdkFont
*waypoint_font
;
136 VikTrack
*current_track
;
137 guint16 ct_x1
, ct_y1
, ct_x2
, ct_y2
;
138 gboolean ct_sync_done
;
141 VikCoordMode coord_mode
;
143 /* wp editing tool */
144 VikWaypoint
*current_wp
;
145 gchar
*current_wp_name
;
147 gboolean waypoint_rightclick
;
149 /* track editing tool */
151 gchar
*current_tp_track_name
;
152 VikTrwLayerTpwin
*tpwin
;
154 /* weird hack for joining tracks */
156 gchar
*last_tp_track_name
;
158 /* track editing tool -- more specifically, moving tps */
161 /* magic scissors tool */
162 gboolean magic_scissors_started
;
163 VikCoord magic_scissors_coord
;
164 gboolean magic_scissors_check_added_track
;
165 gchar
*magic_scissors_added_track_name
;
166 VikTrack
*magic_scissors_current_track
;
167 gboolean magic_scissors_append
;
174 guint16 image_cache_size
;
176 /* for waypoint text */
177 PangoLayout
*wplabellayout
;
179 gboolean has_verified_thumbnails
;
181 GtkMenu
*wp_right_click_menu
;
184 VikStdLayerMenuItem menu_selection
;
186 gint highest_wp_number
;
189 /* A caached waypoint image. */
192 gchar
*image
; /* filename */
195 struct DrawingParams
{
199 guint16 width
, height
;
200 const VikCoord
*center
;
202 gboolean one_zone
, lat_lon
;
203 gdouble ce1
, ce2
, cn1
, cn2
;
206 static void vik_trw_layer_set_menu_selection(VikTrwLayer
*vtl
, guint16
);
207 static guint16
vik_trw_layer_get_menu_selection(VikTrwLayer
*vtl
);
209 static void trw_layer_delete_item ( gpointer
*pass_along
);
210 static void trw_layer_copy_item_cb( gpointer
*pass_along
);
211 static void trw_layer_cut_item_cb( gpointer
*pass_along
);
213 static void trw_layer_find_maxmin_waypoints ( const gchar
*name
, const VikWaypoint
*w
, struct LatLon maxmin
[2] );
214 static void trw_layer_find_maxmin_tracks ( const gchar
*name
, GList
**t
, struct LatLon maxmin
[2] );
215 static void trw_layer_find_maxmin (VikTrwLayer
*vtl
, struct LatLon maxmin
[2]);
217 static void trw_layer_new_track_gcs ( VikTrwLayer
*vtl
, VikViewport
*vp
);
218 static void trw_layer_free_track_gcs ( VikTrwLayer
*vtl
);
220 static gint
calculate_velocity ( VikTrwLayer
*vtl
, VikTrackpoint
*tp1
, VikTrackpoint
*tp2
);
221 static void trw_layer_draw_track_cb ( const gchar
*name
, VikTrack
*track
, struct DrawingParams
*dp
);
222 static void trw_layer_draw_waypoint ( const gchar
*name
, VikWaypoint
*wp
, struct DrawingParams
*dp
);
224 static void goto_coord ( VikLayersPanel
*vlp
, const VikCoord
*coord
);
225 static void trw_layer_goto_track_startpoint ( gpointer pass_along
[5] );
226 static void trw_layer_goto_track_endpoint ( gpointer pass_along
[6] );
227 static void trw_layer_merge_by_timestamp ( gpointer pass_along
[6] );
228 static void trw_layer_split_by_timestamp ( gpointer pass_along
[6] );
229 static void trw_layer_download_map_along_track_cb(gpointer pass_along
[6]);
230 static void trw_layer_centerize ( gpointer layer_and_vlp
[2] );
231 static void trw_layer_export ( gpointer layer_and_vlp
[2], guint file_type
);
232 static void trw_layer_goto_wp ( gpointer layer_and_vlp
[2] );
233 static void trw_layer_new_wp ( gpointer lav
[2] );
234 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav
[2] );
235 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav
[2] );
236 static void trw_layer_merge_with_other ( gpointer pass_along
[6] );
239 static void trw_layer_properties_item ( gpointer pass_along
[5] );
240 static void trw_layer_goto_waypoint ( gpointer pass_along
[5] );
241 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along
[5] );
243 static void trw_layer_realize_waypoint ( gchar
*name
, VikWaypoint
*wp
, gpointer pass_along
[4] );
244 static void trw_layer_realize_track ( gchar
*name
, VikTrack
*track
, gpointer pass_along
[4] );
245 static void init_drawing_params ( struct DrawingParams
*dp
, VikViewport
*vp
);
248 static void trw_layer_marshall( VikTrwLayer
*vtl
, guint8
**data
, gint
*len
);
249 static VikTrwLayer
*trw_layer_unmarshall( gpointer data
, gint len
, VikViewport
*vvp
);
251 static gboolean
trw_layer_set_param ( VikTrwLayer
*vtl
, guint16 id
, VikLayerParamData data
, VikViewport
*vp
);
252 static VikLayerParamData
trw_layer_get_param ( VikTrwLayer
*vtl
, guint16 id
);
254 static void trw_layer_del_item ( VikTrwLayer
*vtl
, gint subtype
, gpointer sublayer
);
255 static void trw_layer_copy_item ( VikTrwLayer
*vtl
, gint subtype
, gpointer sublayer
, guint8
**item
, guint
*len
);
256 static gboolean
trw_layer_paste_item ( VikTrwLayer
*vtl
, gint subtype
, guint8
*item
, guint len
);
257 static void trw_layer_free_copied_item ( gint subtype
, gpointer item
);
258 static void trw_layer_drag_drop_request ( VikTrwLayer
*vtl_src
, VikTrwLayer
*vtl_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
);
260 static void trw_layer_cancel_last_tp ( VikTrwLayer
*vtl
);
261 static void trw_layer_cancel_current_tp ( VikTrwLayer
*vtl
, gboolean destroy
);
262 static void trw_layer_tpwin_response ( VikTrwLayer
*vtl
, gint response
);
263 static void trw_layer_tpwin_init ( VikTrwLayer
*vtl
);
265 static gpointer
tool_edit_trackpoint_create ( VikWindow
*vw
, VikViewport
*vvp
);
266 static gboolean
tool_edit_trackpoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
);
267 static gboolean
tool_edit_trackpoint_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, gpointer data
);
268 static gboolean
tool_edit_trackpoint_release ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
);
269 static gpointer
tool_show_picture_create ( VikWindow
*vw
, VikViewport
*vvp
);
270 static gboolean
tool_show_picture_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
);
271 static gpointer
tool_edit_waypoint_create ( VikWindow
*vw
, VikViewport
*vvp
);
272 static gboolean
tool_edit_waypoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
);
273 static gboolean
tool_edit_waypoint_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, gpointer data
);
274 static gboolean
tool_edit_waypoint_release ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
);
275 static gpointer
tool_begin_track_create ( VikWindow
*vw
, VikViewport
*vvp
);
276 static gboolean
tool_begin_track_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
);
277 static gpointer
tool_new_track_create ( VikWindow
*vw
, VikViewport
*vvp
);
278 static gboolean
tool_new_track_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
);
279 static VikLayerToolFuncStatus
tool_new_track_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, VikViewport
*vvp
);
280 static gboolean
tool_new_track_key_press ( VikTrwLayer
*vtl
, GdkEventKey
*event
, VikViewport
*vvp
);
281 static gpointer
tool_new_waypoint_create ( VikWindow
*vw
, VikViewport
*vvp
);
282 static gboolean
tool_new_waypoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
);
283 static gpointer
tool_magic_scissors_create ( VikWindow
*vw
, VikViewport
*vvp
);
284 static gboolean
tool_magic_scissors_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
);
287 static void cached_pixbuf_free ( CachedPixbuf
*cp
);
288 static gint
cached_pixbuf_cmp ( CachedPixbuf
*cp
, const gchar
*name
);
289 static void trw_layer_verify_thumbnails ( VikTrwLayer
*vtl
, GtkWidget
*vp
);
291 static VikTrackpoint
*closest_tp_in_five_pixel_interval ( VikTrwLayer
*vtl
, VikViewport
*vvp
, gint x
, gint y
);
292 static VikWaypoint
*closest_wp_in_five_pixel_interval ( VikTrwLayer
*vtl
, VikViewport
*vvp
, gint x
, gint y
);
294 static void trw_layer_change_coord_mode ( VikTrwLayer
*vtl
, VikCoordMode dest_mode
);
296 static gchar
*get_new_unique_sublayer_name (VikTrwLayer
*vtl
, gint sublayer_type
, const gchar
*name
);
297 static void waypoint_convert ( const gchar
*name
, VikWaypoint
*wp
, VikCoordMode
*dest_mode
);
298 static void track_convert ( const gchar
*name
, VikTrack
*tr
, VikCoordMode
*dest_mode
);
300 static gchar
*highest_wp_number_get(VikTrwLayer
*vtl
);
301 static void highest_wp_number_reset(VikTrwLayer
*vtl
);
302 static void highest_wp_number_add_wp(VikTrwLayer
*vtl
, const gchar
*new_wp_name
);
303 static void highest_wp_number_remove_wp(VikTrwLayer
*vtl
, const gchar
*old_wp_name
);
306 static VikToolInterface trw_layer_tools
[] = {
307 { N_("Create Waypoint"), (VikToolConstructorFunc
) tool_new_waypoint_create
, NULL
, NULL
, NULL
,
308 (VikToolMouseFunc
) tool_new_waypoint_click
, NULL
, NULL
, (VikToolKeyFunc
) NULL
, GDK_CURSOR_IS_PIXMAP
, &cursor_addwp_pixbuf
},
310 { N_("Create Track"), (VikToolConstructorFunc
) tool_new_track_create
, NULL
, NULL
, NULL
,
311 (VikToolMouseFunc
) tool_new_track_click
, (VikToolMouseMoveFunc
) tool_new_track_move
, NULL
,
312 (VikToolKeyFunc
) tool_new_track_key_press
, GDK_CURSOR_IS_PIXMAP
, &cursor_addtr_pixbuf
},
314 { N_("Begin Track"), (VikToolConstructorFunc
) tool_begin_track_create
, NULL
, NULL
, NULL
,
315 (VikToolMouseFunc
) tool_begin_track_click
, NULL
, NULL
, (VikToolKeyFunc
) NULL
, GDK_CURSOR_IS_PIXMAP
, &cursor_begintr_pixbuf
},
317 { N_("Edit Waypoint"), (VikToolConstructorFunc
) tool_edit_waypoint_create
, NULL
, NULL
, NULL
,
318 (VikToolMouseFunc
) tool_edit_waypoint_click
,
319 (VikToolMouseMoveFunc
) tool_edit_waypoint_move
,
320 (VikToolMouseFunc
) tool_edit_waypoint_release
, (VikToolKeyFunc
) NULL
, GDK_CURSOR_IS_PIXMAP
, &cursor_edwp_pixbuf
},
322 { N_("Edit Trackpoint"), (VikToolConstructorFunc
) tool_edit_trackpoint_create
, NULL
, NULL
, NULL
,
323 (VikToolMouseFunc
) tool_edit_trackpoint_click
,
324 (VikToolMouseMoveFunc
) tool_edit_trackpoint_move
,
325 (VikToolMouseFunc
) tool_edit_trackpoint_release
, (VikToolKeyFunc
) NULL
, GDK_CURSOR_IS_PIXMAP
, &cursor_edtr_pixbuf
},
327 { N_("Show Picture"), (VikToolConstructorFunc
) tool_show_picture_create
, NULL
, NULL
, NULL
,
328 (VikToolMouseFunc
) tool_show_picture_click
, NULL
, NULL
, (VikToolKeyFunc
) NULL
, GDK_CURSOR_IS_PIXMAP
, &cursor_showpic_pixbuf
},
330 { N_("Magic Scissors"), (VikToolConstructorFunc
) tool_magic_scissors_create
, NULL
, NULL
, NULL
,
331 (VikToolMouseFunc
) tool_magic_scissors_click
, NULL
, NULL
, (VikToolKeyFunc
) NULL
, GDK_CURSOR_IS_PIXMAP
, &cursor_iscissors_pixbuf
},
333 enum { TOOL_CREATE_WAYPOINT
=0, TOOL_CREATE_TRACK
, TOOL_BEGIN_TRACK
, TOOL_EDIT_WAYPOINT
, TOOL_EDIT_TRACKPOINT
, TOOL_SHOW_PICTURE
, NUM_TOOLS
};
335 /****** PARAMETERS ******/
337 static gchar
*params_groups
[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
338 enum { GROUP_WAYPOINTS
, GROUP_TRACKS
, GROUP_IMAGES
};
340 static gchar
*params_drawmodes
[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 };
341 static gchar
*params_wpsymbols
[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
344 static VikLayerParamScale params_scales
[] = {
345 /* min max step digits */
346 { 1, 10, 1, 0 }, /* line_thickness */
347 { 0.0, 99.0, 1, 2 }, /* velocity_min */
348 { 1.0, 100.0, 1.0, 2 }, /* velocity_max */
349 /* 5 * step == how much to turn */
350 { 16, 128, 3.2, 0 }, /* image_size */
351 { 0, 255, 5, 0 }, /* image alpha */
352 { 5, 500, 5, 0 }, /* image cache_size */
353 { 0, 8, 1, 0 }, /* image cache_size */
354 { 1, 64, 1, 0 }, /* wpsize */
355 { MIN_STOP_LENGTH
, MAX_STOP_LENGTH
, 1, 0 }, /* stop_length */
356 { 1, 100, 1, 0 }, /* stop_length */
359 VikLayerParam trw_layer_params
[] = {
360 { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN
, VIK_LAYER_NOT_IN_PROPERTIES
},
361 { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN
, VIK_LAYER_NOT_IN_PROPERTIES
},
363 { "drawmode", VIK_LAYER_PARAM_UINT
, GROUP_TRACKS
, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_RADIOGROUP
, NULL
},
364 { "drawlines", VIK_LAYER_PARAM_BOOLEAN
, GROUP_TRACKS
, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON
},
365 { "drawpoints", VIK_LAYER_PARAM_BOOLEAN
, GROUP_TRACKS
, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON
},
366 { "drawelevation", VIK_LAYER_PARAM_BOOLEAN
, GROUP_TRACKS
, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON
},
367 { "elevation_factor", VIK_LAYER_PARAM_UINT
, GROUP_TRACKS
, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE
, params_scales
+ 9 },
369 { "drawstops", VIK_LAYER_PARAM_BOOLEAN
, GROUP_TRACKS
, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON
},
370 { "stop_length", VIK_LAYER_PARAM_UINT
, GROUP_TRACKS
, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON
, params_scales
+ 8 },
372 { "line_thickness", VIK_LAYER_PARAM_UINT
, GROUP_TRACKS
, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON
, params_scales
+ 0 },
373 { "bg_line_thickness", VIK_LAYER_PARAM_UINT
, GROUP_TRACKS
, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON
, params_scales
+ 6 },
374 { "trackbgcolor", VIK_LAYER_PARAM_COLOR
, GROUP_TRACKS
, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR
, 0 },
375 { "velocity_min", VIK_LAYER_PARAM_DOUBLE
, GROUP_TRACKS
, N_("Min Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON
, params_scales
+ 1 },
376 { "velocity_max", VIK_LAYER_PARAM_DOUBLE
, GROUP_TRACKS
, N_("Max Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON
, params_scales
+ 2 },
378 { "drawlabels", VIK_LAYER_PARAM_BOOLEAN
, GROUP_WAYPOINTS
, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON
},
379 { "wpcolor", VIK_LAYER_PARAM_COLOR
, GROUP_WAYPOINTS
, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR
, 0 },
380 { "wptextcolor", VIK_LAYER_PARAM_COLOR
, GROUP_WAYPOINTS
, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR
, 0 },
381 { "wpbgcolor", VIK_LAYER_PARAM_COLOR
, GROUP_WAYPOINTS
, N_("Background:"), VIK_LAYER_WIDGET_COLOR
, 0 },
382 { "wpbgand", VIK_LAYER_PARAM_BOOLEAN
, GROUP_WAYPOINTS
, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON
, 0 },
383 { "wpsymbol", VIK_LAYER_PARAM_UINT
, GROUP_WAYPOINTS
, N_("Waypoint marker:"), VIK_LAYER_WIDGET_RADIOGROUP
, NULL
},
384 { "wpsize", VIK_LAYER_PARAM_UINT
, GROUP_WAYPOINTS
, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON
, params_scales
+ 7 },
385 { "wpsyms", VIK_LAYER_PARAM_BOOLEAN
, GROUP_WAYPOINTS
, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON
},
387 { "drawimages", VIK_LAYER_PARAM_BOOLEAN
, GROUP_IMAGES
, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON
},
388 { "image_size", VIK_LAYER_PARAM_UINT
, GROUP_IMAGES
, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE
, params_scales
+ 3 },
389 { "image_alpha", VIK_LAYER_PARAM_UINT
, GROUP_IMAGES
, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE
, params_scales
+ 4 },
390 { "image_cache_size", VIK_LAYER_PARAM_UINT
, GROUP_IMAGES
, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE
, params_scales
+ 5 },
393 enum { 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
};
396 *** 1) Add to trw_layer_params and enumeration
397 *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
400 /****** END PARAMETERS ******/
402 VikLayerInterface vik_trw_layer_interface
= {
407 sizeof(trw_layer_tools
) / sizeof(VikToolInterface
),
411 params_groups
, /* params_groups */
412 sizeof(params_groups
)/sizeof(params_groups
[0]), /* number of groups */
416 (VikLayerFuncCreate
) vik_trw_layer_create
,
417 (VikLayerFuncRealize
) vik_trw_layer_realize
,
418 (VikLayerFuncPostRead
) trw_layer_verify_thumbnails
,
419 (VikLayerFuncFree
) vik_trw_layer_free
,
421 (VikLayerFuncProperties
) NULL
,
422 (VikLayerFuncDraw
) vik_trw_layer_draw
,
423 (VikLayerFuncChangeCoordMode
) trw_layer_change_coord_mode
,
425 (VikLayerFuncSetMenuItemsSelection
) vik_trw_layer_set_menu_selection
,
426 (VikLayerFuncGetMenuItemsSelection
) vik_trw_layer_get_menu_selection
,
428 (VikLayerFuncAddMenuItems
) vik_trw_layer_add_menu_items
,
429 (VikLayerFuncSublayerAddMenuItems
) vik_trw_layer_sublayer_add_menu_items
,
431 (VikLayerFuncSublayerRenameRequest
) vik_trw_layer_sublayer_rename_request
,
432 (VikLayerFuncSublayerToggleVisible
) vik_trw_layer_sublayer_toggle_visible
,
434 (VikLayerFuncMarshall
) trw_layer_marshall
,
435 (VikLayerFuncUnmarshall
) trw_layer_unmarshall
,
437 (VikLayerFuncSetParam
) trw_layer_set_param
,
438 (VikLayerFuncGetParam
) trw_layer_get_param
,
440 (VikLayerFuncReadFileData
) a_gpspoint_read_file
,
441 (VikLayerFuncWriteFileData
) a_gpspoint_write_file
,
443 (VikLayerFuncDeleteItem
) trw_layer_del_item
,
444 (VikLayerFuncCopyItem
) trw_layer_copy_item
,
445 (VikLayerFuncPasteItem
) trw_layer_paste_item
,
446 (VikLayerFuncFreeCopiedItem
) trw_layer_free_copied_item
,
448 (VikLayerFuncDragDropRequest
) trw_layer_drag_drop_request
,
451 /* for copy & paste (I think?) */
459 GType
vik_trw_layer_get_type ()
461 static GType vtl_type
= 0;
465 static const GTypeInfo vtl_info
=
467 sizeof (VikTrwLayerClass
),
468 NULL
, /* base_init */
469 NULL
, /* base_finalize */
470 NULL
, /* class init */
471 NULL
, /* class_finalize */
472 NULL
, /* class_data */
473 sizeof (VikTrwLayer
),
475 NULL
/* instance init */
477 vtl_type
= g_type_register_static ( VIK_LAYER_TYPE
, "VikTrwLayer", &vtl_info
, 0 );
483 static void trw_layer_del_item ( VikTrwLayer
*vtl
, gint subtype
, gpointer sublayer
)
485 static gpointer pass_along
[5];
491 pass_along
[1] = NULL
;
492 pass_along
[2] = GINT_TO_POINTER (subtype
);
493 pass_along
[3] = sublayer
;
494 pass_along
[4] = NULL
;
496 trw_layer_delete_item ( pass_along
);
499 static void trw_layer_copy_item_cb( gpointer pass_along
[5])
501 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
502 gint subtype
= GPOINTER_TO_INT (pass_along
[2]);
503 gpointer
* sublayer
= pass_along
[3];
507 trw_layer_copy_item( vtl
, subtype
, sublayer
, &data
, &len
);
510 a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER
, VIK_LAYER_TRW
,
515 static void trw_layer_cut_item_cb( gpointer pass_along
[5])
517 trw_layer_copy_item_cb(pass_along
);
518 trw_layer_delete_item(pass_along
);
521 static void trw_layer_copy_item ( VikTrwLayer
*vtl
, gint subtype
, gpointer sublayer
, guint8
**item
, guint
*len
)
532 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
534 vik_waypoint_marshall ( g_hash_table_lookup ( vtl
->waypoints
, sublayer
), &id
, &il
);
536 vik_track_marshall ( g_hash_table_lookup ( vtl
->tracks
, sublayer
), &id
, &il
);
539 *len
= sizeof(FlatItem
) + strlen(sublayer
) + 1 + il
;
540 fi
= g_malloc ( *len
);
541 fi
->len
= strlen(sublayer
) + 1;
542 memcpy(fi
->data
, sublayer
, fi
->len
);
543 memcpy(fi
->data
+ fi
->len
, id
, il
);
545 *item
= (guint8
*)fi
;
548 static gboolean
trw_layer_paste_item ( VikTrwLayer
*vtl
, gint subtype
, guint8
*item
, guint len
)
550 FlatItem
*fi
= (FlatItem
*) item
;
552 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
&& fi
)
557 name
= get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, (gchar
*)fi
->data
);
558 w
= vik_waypoint_unmarshall(fi
->data
+ fi
->len
, len
- sizeof(*fi
) - fi
->len
);
559 vik_trw_layer_add_waypoint ( vtl
, name
, w
);
560 waypoint_convert(name
, w
, &vtl
->coord_mode
);
563 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
&& fi
)
567 name
= get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_TRACK
, (gchar
*)fi
->data
);
568 t
= vik_track_unmarshall(fi
->data
+ fi
->len
, len
- sizeof(*fi
) - fi
->len
);
569 vik_trw_layer_add_track ( vtl
, name
, t
);
570 track_convert(name
, t
, &vtl
->coord_mode
);
576 static void trw_layer_free_copied_item ( gint subtype
, gpointer item
)
583 static gboolean
trw_layer_set_param ( VikTrwLayer
*vtl
, guint16 id
, VikLayerParamData data
, VikViewport
*vp
)
587 case PARAM_TV
: vtl
->tracks_visible
= data
.b
; break;
588 case PARAM_WV
: vtl
->waypoints_visible
= data
.b
; break;
589 case PARAM_DM
: vtl
->drawmode
= data
.u
; break;
590 case PARAM_DP
: vtl
->drawpoints
= data
.b
; break;
591 case PARAM_DE
: vtl
->drawelevation
= data
.b
; break;
592 case PARAM_DS
: vtl
->drawstops
= data
.b
; break;
593 case PARAM_DL
: vtl
->drawlines
= data
.b
; break;
594 case PARAM_SL
: if ( data
.u
>= MIN_STOP_LENGTH
&& data
.u
<= MAX_STOP_LENGTH
)
595 vtl
->stop_length
= data
.u
;
597 case PARAM_EF
: if ( data
.u
>= 1 && data
.u
<= 100 )
598 vtl
->elevation_factor
= data
.u
;
600 case PARAM_LT
: if ( data
.u
> 0 && data
.u
< 15 && data
.u
!= vtl
->line_thickness
)
602 vtl
->line_thickness
= data
.u
;
603 trw_layer_new_track_gcs ( vtl
, vp
);
606 case PARAM_BLT
: if ( data
.u
> 0 && data
.u
<= 8 && data
.u
!= vtl
->bg_line_thickness
)
608 vtl
->bg_line_thickness
= data
.u
;
609 trw_layer_new_track_gcs ( vtl
, vp
);
612 case PARAM_VMIN
: vtl
->velocity_min
= data
.d
; break;
613 case PARAM_VMAX
: vtl
->velocity_max
= data
.d
; break;
614 case PARAM_TBGC
: gdk_gc_set_rgb_fg_color(vtl
->track_bg_gc
, &(data
.c
)); break;
615 case PARAM_DLA
: vtl
->drawlabels
= data
.b
; break;
616 case PARAM_DI
: vtl
->drawimages
= data
.b
; break;
617 case PARAM_IS
: if ( data
.u
!= vtl
->image_size
)
619 vtl
->image_size
= data
.u
;
620 g_list_foreach ( vtl
->image_cache
->head
, (GFunc
) cached_pixbuf_free
, NULL
);
621 g_queue_free ( vtl
->image_cache
);
622 vtl
->image_cache
= g_queue_new ();
625 case PARAM_IA
: vtl
->image_alpha
= data
.u
; break;
626 case PARAM_ICS
: vtl
->image_cache_size
= data
.u
;
627 while ( vtl
->image_cache
->length
> vtl
->image_cache_size
) /* if shrinking cache_size, free pixbuf ASAP */
628 cached_pixbuf_free ( g_queue_pop_tail ( vtl
->image_cache
) );
630 case PARAM_WPC
: gdk_gc_set_rgb_fg_color(vtl
->waypoint_gc
, &(data
.c
)); break;
631 case PARAM_WPTC
: gdk_gc_set_rgb_fg_color(vtl
->waypoint_text_gc
, &(data
.c
)); break;
632 case PARAM_WPBC
: gdk_gc_set_rgb_fg_color(vtl
->waypoint_bg_gc
, &(data
.c
)); break;
633 case PARAM_WPBA
: gdk_gc_set_function(vtl
->waypoint_bg_gc
, data
.b
? GDK_AND
: GDK_COPY
); break;
634 case PARAM_WPSYM
: if ( data
.u
< WP_NUM_SYMBOLS
) vtl
->wp_symbol
= data
.u
; break;
635 case PARAM_WPSIZE
: if ( data
.u
> 0 && data
.u
<= 64 ) vtl
->wp_size
= data
.u
; break;
636 case PARAM_WPSYMS
: vtl
->wp_draw_symbols
= data
.b
; break;
641 static VikLayerParamData
trw_layer_get_param ( VikTrwLayer
*vtl
, guint16 id
)
643 VikLayerParamData rv
;
646 case PARAM_TV
: rv
.b
= vtl
->tracks_visible
; break;
647 case PARAM_WV
: rv
.b
= vtl
->waypoints_visible
; break;
648 case PARAM_DM
: rv
.u
= vtl
->drawmode
; break;
649 case PARAM_DP
: rv
.b
= vtl
->drawpoints
; break;
650 case PARAM_DE
: rv
.b
= vtl
->drawelevation
; break;
651 case PARAM_EF
: rv
.u
= vtl
->elevation_factor
; break;
652 case PARAM_DS
: rv
.b
= vtl
->drawstops
; break;
653 case PARAM_SL
: rv
.u
= vtl
->stop_length
; break;
654 case PARAM_DL
: rv
.b
= vtl
->drawlines
; break;
655 case PARAM_LT
: rv
.u
= vtl
->line_thickness
; break;
656 case PARAM_BLT
: rv
.u
= vtl
->bg_line_thickness
; break;
657 case PARAM_VMIN
: rv
.d
= vtl
->velocity_min
; break;
658 case PARAM_VMAX
: rv
.d
= vtl
->velocity_max
; break;
659 case PARAM_DLA
: rv
.b
= vtl
->drawlabels
; break;
660 case PARAM_DI
: rv
.b
= vtl
->drawimages
; break;
661 case PARAM_TBGC
: vik_gc_get_fg_color(vtl
->track_bg_gc
, &(rv
.c
)); break;
662 case PARAM_IS
: rv
.u
= vtl
->image_size
; break;
663 case PARAM_IA
: rv
.u
= vtl
->image_alpha
; break;
664 case PARAM_ICS
: rv
.u
= vtl
->image_cache_size
; break;
665 case PARAM_WPC
: vik_gc_get_fg_color(vtl
->waypoint_gc
, &(rv
.c
)); break;
666 case PARAM_WPTC
: vik_gc_get_fg_color(vtl
->waypoint_text_gc
, &(rv
.c
)); break;
667 case PARAM_WPBC
: vik_gc_get_fg_color(vtl
->waypoint_bg_gc
, &(rv
.c
)); break;
668 case PARAM_WPBA
: rv
.b
= (vik_gc_get_function(vtl
->waypoint_bg_gc
)==GDK_AND
); break;
669 case PARAM_WPSYM
: rv
.u
= vtl
->wp_symbol
; break;
670 case PARAM_WPSIZE
: rv
.u
= vtl
->wp_size
; break;
671 case PARAM_WPSYMS
: rv
.b
= vtl
->wp_draw_symbols
; break;
676 static void trw_layer_marshall( VikTrwLayer
*vtl
, guint8
**data
, gint
*len
)
685 if ((f
= fdopen(g_file_open_tmp (NULL
, &tmpname
, NULL
), "r+"))) {
686 a_gpx_write_file(vtl
, f
);
687 vik_layer_marshall_params(VIK_LAYER(vtl
), &pd
, &pl
);
690 g_file_get_contents(tmpname
, (void *)&dd
, (void *)&dl
, NULL
);
691 *len
= sizeof(pl
) + pl
+ dl
;
692 *data
= g_malloc(*len
);
693 memcpy(*data
, &pl
, sizeof(pl
));
694 memcpy(*data
+ sizeof(pl
), pd
, pl
);
695 memcpy(*data
+ sizeof(pl
) + pl
, dd
, dl
);
704 static VikTrwLayer
*trw_layer_unmarshall( gpointer data
, gint len
, VikViewport
*vvp
)
706 VikTrwLayer
*rv
= VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW
, vvp
, NULL
, FALSE
));
712 memcpy(&pl
, data
, sizeof(pl
));
714 vik_layer_unmarshall_params ( VIK_LAYER(rv
), data
, pl
, vvp
);
717 if (!(f
= fdopen(g_file_open_tmp (NULL
, &tmpname
, NULL
), "r+"))) {
718 g_critical("couldn't open temp file");
721 fwrite(data
, len
- pl
- sizeof(pl
), 1, f
);
723 a_gpx_read_file(rv
, f
);
731 static GList
* str_array_to_glist(gchar
* data
[])
735 for (p
= (gpointer
)data
; *p
; p
++)
736 gl
= g_list_prepend(gl
, *p
);
737 return(g_list_reverse(gl
));
740 static gboolean
strcase_equal(gconstpointer s1
, gconstpointer s2
)
742 return (strcasecmp(s1
, s2
) == 0);
745 static guint
strcase_hash(gconstpointer v
)
747 /* 31 bit hash function */
750 gchar s
[128]; /* malloc is too slow for reading big files */
753 for (i
= 0; (i
< (sizeof(s
)- 1)) && t
[i
]; i
++)
754 p
[i
] = toupper(t
[i
]);
760 for (p
+= 1; *p
!= '\0'; p
++)
761 h
= (h
<< 5) - h
+ *p
;
767 VikTrwLayer
*vik_trw_layer_new ( gint drawmode
)
769 if (trw_layer_params
[PARAM_DM
].widget_data
== NULL
)
770 trw_layer_params
[PARAM_DM
].widget_data
= str_array_to_glist(params_drawmodes
);
771 if (trw_layer_params
[PARAM_WPSYM
].widget_data
== NULL
)
772 trw_layer_params
[PARAM_WPSYM
].widget_data
= str_array_to_glist(params_wpsymbols
);
774 VikTrwLayer
*rv
= VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE
, NULL
) );
775 vik_layer_init ( VIK_LAYER(rv
), VIK_LAYER_TRW
);
777 rv
->waypoints
= g_hash_table_new_full ( strcase_hash
, strcase_equal
, g_free
, (GDestroyNotify
) vik_waypoint_free
);
778 rv
->tracks
= g_hash_table_new_full ( g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) vik_track_free
);
779 rv
->tracks_iters
= g_hash_table_new_full ( g_str_hash
, g_str_equal
, NULL
, g_free
);
780 rv
->waypoints_iters
= g_hash_table_new_full ( strcase_hash
, strcase_equal
, NULL
, g_free
);
782 /* TODO: constants at top */
783 rv
->waypoints_visible
= rv
->tracks_visible
= TRUE
;
784 rv
->drawmode
= drawmode
;
785 rv
->drawpoints
= TRUE
;
786 rv
->drawstops
= FALSE
;
787 rv
->drawelevation
= FALSE
;
788 rv
->elevation_factor
= 30;
789 rv
->stop_length
= 60;
790 rv
->drawlines
= TRUE
;
791 rv
->wplabellayout
= NULL
;
792 rv
->wp_right_click_menu
= NULL
;
793 rv
->waypoint_gc
= NULL
;
794 rv
->waypoint_text_gc
= NULL
;
795 rv
->waypoint_bg_gc
= NULL
;
797 rv
->velocity_max
= 5.0;
798 rv
->velocity_min
= 0.0;
799 rv
->line_thickness
= 1;
800 rv
->bg_line_thickness
= 0;
801 rv
->current_wp
= NULL
;
802 rv
->current_wp_name
= NULL
;
803 rv
->current_track
= NULL
;
804 rv
->current_tpl
= NULL
;
805 rv
->current_tp_track_name
= NULL
;
806 rv
->moving_tp
= FALSE
;
807 rv
->moving_wp
= FALSE
;
809 rv
->ct_sync_done
= TRUE
;
811 rv
->magic_scissors_started
= FALSE
;
812 rv
->magic_scissors_check_added_track
= FALSE
;
813 rv
->magic_scissors_added_track_name
= NULL
;
814 rv
->magic_scissors_current_track
= NULL
;
815 rv
->magic_scissors_append
= FALSE
;
817 rv
->waypoint_rightclick
= FALSE
;
819 rv
->last_tp_track_name
= NULL
;
821 rv
->image_cache
= g_queue_new();
823 rv
->image_alpha
= 255;
824 rv
->image_cache_size
= 300;
825 rv
->drawimages
= TRUE
;
826 rv
->drawlabels
= TRUE
;
831 void vik_trw_layer_free ( VikTrwLayer
*trwlayer
)
833 g_hash_table_destroy(trwlayer
->waypoints
);
834 g_hash_table_destroy(trwlayer
->tracks
);
836 /* ODC: replace with GArray */
837 trw_layer_free_track_gcs ( trwlayer
);
839 if ( trwlayer
->wp_right_click_menu
)
840 gtk_object_sink ( GTK_OBJECT(trwlayer
->wp_right_click_menu
) );
842 if ( trwlayer
->wplabellayout
!= NULL
)
843 g_object_unref ( G_OBJECT ( trwlayer
->wplabellayout
) );
845 if ( trwlayer
->waypoint_gc
!= NULL
)
846 g_object_unref ( G_OBJECT ( trwlayer
->waypoint_gc
) );
848 if ( trwlayer
->waypoint_text_gc
!= NULL
)
849 g_object_unref ( G_OBJECT ( trwlayer
->waypoint_text_gc
) );
851 if ( trwlayer
->waypoint_bg_gc
!= NULL
)
852 g_object_unref ( G_OBJECT ( trwlayer
->waypoint_bg_gc
) );
854 if ( trwlayer
->waypoint_font
!= NULL
)
855 gdk_font_unref ( trwlayer
->waypoint_font
);
857 if ( trwlayer
->tpwin
!= NULL
)
858 gtk_widget_destroy ( GTK_WIDGET(trwlayer
->tpwin
) );
860 g_list_foreach ( trwlayer
->image_cache
->head
, (GFunc
) cached_pixbuf_free
, NULL
);
861 g_queue_free ( trwlayer
->image_cache
);
864 static void init_drawing_params ( struct DrawingParams
*dp
, VikViewport
*vp
)
867 dp
->xmpp
= vik_viewport_get_xmpp ( vp
);
868 dp
->ympp
= vik_viewport_get_ympp ( vp
);
869 dp
->width
= vik_viewport_get_width ( vp
);
870 dp
->height
= vik_viewport_get_height ( vp
);
871 dp
->center
= vik_viewport_get_center ( vp
);
872 dp
->one_zone
= vik_viewport_is_one_zone ( vp
); /* false if some other projection besides UTM */
873 dp
->lat_lon
= vik_viewport_get_coord_mode ( vp
) == VIK_COORD_LATLON
;
878 w2
= dp
->xmpp
* (dp
->width
/ 2) + 1600 / dp
->xmpp
;
879 h2
= dp
->ympp
* (dp
->height
/ 2) + 1600 / dp
->ympp
;
880 /* leniency -- for tracks. Obviously for waypoints this SHOULD be a lot smaller */
882 dp
->ce1
= dp
->center
->east_west
-w2
;
883 dp
->ce2
= dp
->center
->east_west
+w2
;
884 dp
->cn1
= dp
->center
->north_south
-h2
;
885 dp
->cn2
= dp
->center
->north_south
+h2
;
886 } else if ( dp
->lat_lon
) {
887 VikCoord upperleft
, bottomright
;
888 /* quick & dirty calculation; really want to check all corners due to lat/lon smaller at top in northern hemisphere */
889 /* this also DOESN'T WORK if you are crossing 180/-180 lon. I don't plan to in the near future... */
890 vik_viewport_screen_to_coord ( vp
, -500, -500, &upperleft
);
891 vik_viewport_screen_to_coord ( vp
, dp
->width
+500, dp
->height
+500, &bottomright
);
892 dp
->ce1
= upperleft
.east_west
;
893 dp
->ce2
= bottomright
.east_west
;
894 dp
->cn1
= bottomright
.north_south
;
895 dp
->cn2
= upperleft
.north_south
;
898 dp
->track_gc_iter
= 0;
901 static gint
calculate_velocity ( VikTrwLayer
*vtl
, VikTrackpoint
*tp1
, VikTrackpoint
*tp2
)
903 static gdouble rv
= 0;
904 if ( tp1
->has_timestamp
&& tp2
->has_timestamp
)
906 rv
= ( vik_coord_diff ( &(tp1
->coord
), &(tp2
->coord
) )
907 / (tp1
->timestamp
- tp2
->timestamp
) ) - vtl
->velocity_min
;
910 return VIK_TRW_LAYER_TRACK_GC_MIN
;
911 else if ( vtl
->velocity_min
>= vtl
->velocity_max
)
912 return VIK_TRW_LAYER_TRACK_GC_MAX
;
914 rv
*= (VIK_TRW_LAYER_TRACK_GC_RATES
/ (vtl
->velocity_max
- vtl
->velocity_min
));
916 if ( rv
>= VIK_TRW_LAYER_TRACK_GC_MAX
)
917 return VIK_TRW_LAYER_TRACK_GC_MAX
;
921 return VIK_TRW_LAYER_TRACK_GC_BLACK
;
924 void draw_utm_skip_insignia ( VikViewport
*vvp
, GdkGC
*gc
, gint x
, gint y
)
926 vik_viewport_draw_line ( vvp
, gc
, x
+5, y
, x
-5, y
);
927 vik_viewport_draw_line ( vvp
, gc
, x
, y
+5, x
, y
-5 );
928 vik_viewport_draw_line ( vvp
, gc
, x
+5, y
+5, x
-5, y
-5 );
929 vik_viewport_draw_line ( vvp
, gc
, x
+5, y
-5, x
-5, y
+5 );
932 static void trw_layer_draw_track ( const gchar
*name
, VikTrack
*track
, struct DrawingParams
*dp
, gboolean drawing_white_background
)
934 /* TODO: this function is a mess, get rid of any redundancy */
935 GList
*list
= track
->trackpoints
;
937 gboolean useoldvals
= TRUE
;
941 gboolean drawelevation
;
942 gdouble min_alt
, max_alt
, alt_diff
= 0;
944 const guint8 tp_size_reg
= 2;
945 const guint8 tp_size_cur
= 4;
948 if ( dp
->vtl
->drawelevation
)
950 /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
951 if ( ( drawelevation
= vik_track_get_minmax_alt ( track
, &min_alt
, &max_alt
) ) )
952 alt_diff
= max_alt
- min_alt
;
955 if ( ! track
->visible
)
958 /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
959 if ( dp
->vtl
->bg_line_thickness
&& !drawing_white_background
)
960 trw_layer_draw_track ( name
, track
, dp
, TRUE
);
962 if ( drawing_white_background
)
963 drawpoints
= drawstops
= FALSE
;
965 drawpoints
= dp
->vtl
->drawpoints
;
966 drawstops
= dp
->vtl
->drawstops
;
969 if ( track
== dp
->vtl
->current_track
)
970 main_gc
= dp
->vtl
->current_track_gc
;
972 main_gc
= g_array_index(dp
->vtl
->track_gc
, GdkGC
*, dp
->track_gc_iter
);
975 int x
, y
, oldx
, oldy
;
976 VikTrackpoint
*tp
= VIK_TRACKPOINT(list
->data
);
978 tp_size
= (list
== dp
->vtl
->current_tpl
) ? tp_size_cur
: tp_size_reg
;
980 vik_viewport_coord_to_screen ( dp
->vp
, &(tp
->coord
), &x
, &y
);
982 if ( (drawpoints
) && dp
->track_gc_iter
< VIK_TRW_LAYER_TRACK_GC
)
984 GdkPoint trian
[3] = { { x
, y
-(3*tp_size
) }, { x
-(2*tp_size
), y
+(2*tp_size
) }, {x
+(2*tp_size
), y
+(2*tp_size
)} };
985 vik_viewport_draw_polygon ( dp
->vp
, main_gc
, TRUE
, trian
, 3 );
991 if ( dp
->vtl
->drawmode
== DRAWMODE_ALL_BLACK
)
992 dp
->track_gc_iter
= VIK_TRW_LAYER_TRACK_GC_MAX
+ 1;
994 while ((list
= g_list_next(list
)))
996 tp
= VIK_TRACKPOINT(list
->data
);
997 tp_size
= (list
== dp
->vtl
->current_tpl
) ? tp_size_cur
: tp_size_reg
;
999 /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
1000 if ( (!dp
->one_zone
&& !dp
->lat_lon
) || /* UTM & zones; do everything */
1001 ( ((!dp
->one_zone
) || tp
->coord
.utm_zone
== dp
->center
->utm_zone
) && /* only check zones if UTM & one_zone */
1002 tp
->coord
.east_west
< dp
->ce2
&& tp
->coord
.east_west
> dp
->ce1
&& /* both UTM and lat lon */
1003 tp
->coord
.north_south
> dp
->cn1
&& tp
->coord
.north_south
< dp
->cn2
) )
1005 vik_viewport_coord_to_screen ( dp
->vp
, &(tp
->coord
), &x
, &y
);
1007 if ( drawpoints
&& ! drawing_white_background
)
1010 vik_viewport_draw_rectangle ( dp
->vp
, main_gc
, TRUE
, x
-tp_size
, y
-tp_size
, 2*tp_size
, 2*tp_size
);
1012 vik_viewport_draw_rectangle ( dp
->vp
, main_gc
, TRUE
, x
-tp_size
, y
-tp_size
, 2*tp_size
, 2*tp_size
);
1015 if ( drawstops
&& VIK_TRACKPOINT(list
->next
->data
)->timestamp
- VIK_TRACKPOINT(list
->data
)->timestamp
> dp
->vtl
->stop_length
)
1016 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 );
1019 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 );
1022 if ((!tp
->newsegment
) && (dp
->vtl
->drawlines
))
1024 VikTrackpoint
*tp2
= VIK_TRACKPOINT(list
->prev
->data
);
1026 /* UTM only: zone check */
1027 if ( drawpoints
&& dp
->vtl
->coord_mode
== VIK_COORD_UTM
&& tp
->coord
.utm_zone
!= dp
->center
->utm_zone
)
1028 draw_utm_skip_insignia ( dp
->vp
, main_gc
, x
, y
);
1030 if ( dp
->vtl
->drawmode
== DRAWMODE_BY_VELOCITY
)
1031 dp
->track_gc_iter
= calculate_velocity ( dp
->vtl
, tp
, tp2
);
1034 vik_viewport_coord_to_screen ( dp
->vp
, &(tp2
->coord
), &oldx
, &oldy
);
1036 if ( drawing_white_background
) {
1037 vik_viewport_draw_line ( dp
->vp
, dp
->vtl
->track_bg_gc
, oldx
, oldy
, x
, y
);
1041 vik_viewport_draw_line ( dp
->vp
, main_gc
, oldx
, oldy
, x
, y
);
1042 if ( dp
->vtl
->drawelevation
&& list
&& list
->next
&& VIK_TRACKPOINT(list
->next
->data
)->altitude
!= VIK_DEFAULT_ALTITUDE
) {
1044 #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
1045 if ( list
&& list
->next
&& VIK_TRACKPOINT(list
->next
->data
)->altitude
!= VIK_DEFAULT_ALTITUDE
) {
1049 tmp
[1].y
= oldy
-FIXALTITUDE(list
->data
);
1051 tmp
[2].y
= y
-FIXALTITUDE(list
->next
->data
);
1056 if ( ((oldx
- x
) > 0 && (oldy
- y
) > 0) || ((oldx
- x
) < 0 && (oldy
- y
) < 0))
1057 tmp_gc
= GTK_WIDGET(dp
->vp
)->style
->light_gc
[3];
1059 tmp_gc
= GTK_WIDGET(dp
->vp
)->style
->dark_gc
[0];
1060 vik_viewport_draw_polygon ( dp
->vp
, tmp_gc
, TRUE
, tmp
, 4);
1062 vik_viewport_draw_line ( dp
->vp
, main_gc
, oldx
, oldy
-FIXALTITUDE(list
->data
), x
, y
-FIXALTITUDE(list
->next
->data
));
1072 if (useoldvals
&& dp
->vtl
->drawlines
&& (!tp
->newsegment
))
1074 VikTrackpoint
*tp2
= VIK_TRACKPOINT(list
->prev
->data
);
1075 if ( dp
->vtl
->coord_mode
!= VIK_COORD_UTM
|| tp
->coord
.utm_zone
== dp
->center
->utm_zone
)
1077 vik_viewport_coord_to_screen ( dp
->vp
, &(tp
->coord
), &x
, &y
);
1078 if ( dp
->vtl
->drawmode
== DRAWMODE_BY_VELOCITY
)
1079 dp
->track_gc_iter
= calculate_velocity ( dp
->vtl
, tp
, tp2
);
1081 if ( drawing_white_background
)
1082 vik_viewport_draw_line ( dp
->vp
, dp
->vtl
->track_bg_gc
, oldx
, oldy
, x
, y
);
1084 vik_viewport_draw_line ( dp
->vp
, main_gc
, oldx
, oldy
, x
, y
);
1088 vik_viewport_coord_to_screen ( dp
->vp
, &(tp2
->coord
), &x
, &y
);
1089 draw_utm_skip_insignia ( dp
->vp
, main_gc
, x
, y
);
1096 if ( dp
->vtl
->drawmode
== DRAWMODE_BY_TRACK
)
1097 if ( ++(dp
->track_gc_iter
) >= VIK_TRW_LAYER_TRACK_GC
)
1098 dp
->track_gc_iter
= 0;
1101 /* the only reason this exists is so that trw_layer_draw_track can first call itself to draw the white track background */
1102 static void trw_layer_draw_track_cb ( const gchar
*name
, VikTrack
*track
, struct DrawingParams
*dp
)
1104 trw_layer_draw_track ( name
, track
, dp
, FALSE
);
1107 static void cached_pixbuf_free ( CachedPixbuf
*cp
)
1109 g_object_unref ( G_OBJECT(cp
->pixbuf
) );
1110 g_free ( cp
->image
);
1113 static gint
cached_pixbuf_cmp ( CachedPixbuf
*cp
, const gchar
*name
)
1115 return strcmp ( cp
->image
, name
);
1118 static void trw_layer_draw_waypoint ( const gchar
*name
, VikWaypoint
*wp
, struct DrawingParams
*dp
)
1121 if ( (!dp
->one_zone
&& !dp
->lat_lon
) || ( ( dp
->lat_lon
|| wp
->coord
.utm_zone
== dp
->center
->utm_zone
) &&
1122 wp
->coord
.east_west
< dp
->ce2
&& wp
->coord
.east_west
> dp
->ce1
&&
1123 wp
->coord
.north_south
> dp
->cn1
&& wp
->coord
.north_south
< dp
->cn2
) )
1126 GdkPixbuf
*sym
= NULL
;
1127 vik_viewport_coord_to_screen ( dp
->vp
, &(wp
->coord
), &x
, &y
);
1129 /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
1131 if ( wp
->image
&& dp
->vtl
->drawimages
)
1133 GdkPixbuf
*pixbuf
= NULL
;
1136 if ( dp
->vtl
->image_alpha
== 0)
1139 l
= g_list_find_custom ( dp
->vtl
->image_cache
->head
, wp
->image
, (GCompareFunc
) cached_pixbuf_cmp
);
1141 pixbuf
= ((CachedPixbuf
*) l
->data
)->pixbuf
;
1144 gchar
*image
= wp
->image
;
1145 GdkPixbuf
*regularthumb
= a_thumbnails_get ( wp
->image
);
1146 if ( ! regularthumb
)
1148 regularthumb
= a_thumbnails_get_default (); /* cache one 'not yet loaded' for all thumbs not loaded */
1149 image
= "\x12\x00"; /* this shouldn't occur naturally. */
1153 CachedPixbuf
*cp
= NULL
;
1154 cp
= g_malloc ( sizeof ( CachedPixbuf
) );
1155 if ( dp
->vtl
->image_size
== 128 )
1156 cp
->pixbuf
= regularthumb
;
1159 cp
->pixbuf
= a_thumbnails_scale_pixbuf(regularthumb
, dp
->vtl
->image_size
, dp
->vtl
->image_size
);
1160 g_assert ( cp
->pixbuf
);
1161 g_object_unref ( G_OBJECT(regularthumb
) );
1163 cp
->image
= g_strdup ( image
);
1165 /* needed so 'click picture' tool knows how big the pic is; we don't
1166 * store it in cp because they may have been freed already. */
1167 wp
->image_width
= gdk_pixbuf_get_width ( cp
->pixbuf
);
1168 wp
->image_height
= gdk_pixbuf_get_height ( cp
->pixbuf
);
1170 g_queue_push_head ( dp
->vtl
->image_cache
, cp
);
1171 if ( dp
->vtl
->image_cache
->length
> dp
->vtl
->image_cache_size
)
1172 cached_pixbuf_free ( g_queue_pop_tail ( dp
->vtl
->image_cache
) );
1174 pixbuf
= cp
->pixbuf
;
1178 pixbuf
= a_thumbnails_get_default (); /* thumbnail not yet loaded */
1184 w
= gdk_pixbuf_get_width ( pixbuf
);
1185 h
= gdk_pixbuf_get_height ( pixbuf
);
1187 if ( x
+(w
/2) > 0 && y
+(h
/2) > 0 && x
-(w
/2) < dp
->width
&& y
-(h
/2) < dp
->height
) /* always draw within boundaries */
1189 if ( dp
->vtl
->image_alpha
== 255 )
1190 vik_viewport_draw_pixbuf ( dp
->vp
, pixbuf
, 0, 0, x
- (w
/2), y
- (h
/2), w
, h
);
1192 vik_viewport_draw_pixbuf_with_alpha ( dp
->vp
, pixbuf
, dp
->vtl
->image_alpha
, 0, 0, x
- (w
/2), y
- (h
/2), w
, h
);
1194 return; /* if failed to draw picture, default to drawing regular waypoint (below) */
1198 /* DRAW ACTUAL DOT */
1199 if ( dp
->vtl
->wp_draw_symbols
&& wp
->symbol
&& (sym
= a_get_wp_sym(wp
->symbol
)) ) {
1200 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 );
1202 else if ( wp
== dp
->vtl
->current_wp
) {
1203 switch ( dp
->vtl
->wp_symbol
) {
1204 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;
1205 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;
1206 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;
1207 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 );
1208 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 );
1212 switch ( dp
->vtl
->wp_symbol
) {
1213 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;
1214 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;
1215 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;
1216 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
);
1217 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;
1221 if ( dp
->vtl
->drawlabels
)
1223 /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
1224 gint label_x
, label_y
;
1226 pango_layout_set_text ( dp
->vtl
->wplabellayout
, name
, -1 );
1227 pango_layout_get_pixel_size ( dp
->vtl
->wplabellayout
, &width
, &height
);
1228 label_x
= x
- width
/2;
1230 label_y
= y
- height
- 2 - gdk_pixbuf_get_height(sym
)/2;
1232 label_y
= y
- dp
->vtl
->wp_size
- height
- 2;
1234 vik_viewport_draw_rectangle ( dp
->vp
, dp
->vtl
->waypoint_bg_gc
, TRUE
, label_x
- 1, label_y
-1,width
+2,height
+2);
1235 vik_viewport_draw_layout ( dp
->vp
, dp
->vtl
->waypoint_text_gc
, label_x
, label_y
, dp
->vtl
->wplabellayout
);
1240 void vik_trw_layer_draw ( VikTrwLayer
*l
, gpointer data
)
1242 static struct DrawingParams dp
;
1243 g_assert ( l
!= NULL
);
1245 init_drawing_params ( &dp
, VIK_VIEWPORT(data
) );
1248 if ( l
->tracks_visible
)
1249 g_hash_table_foreach ( l
->tracks
, (GHFunc
) trw_layer_draw_track_cb
, &dp
);
1251 if (l
->waypoints_visible
)
1252 g_hash_table_foreach ( l
->waypoints
, (GHFunc
) trw_layer_draw_waypoint
, &dp
);
1255 static void trw_layer_free_track_gcs ( VikTrwLayer
*vtl
)
1258 if ( vtl
->track_bg_gc
)
1260 g_object_unref ( vtl
->track_bg_gc
);
1261 vtl
->track_bg_gc
= NULL
;
1263 if ( vtl
->current_track_gc
)
1265 g_object_unref ( vtl
->current_track_gc
);
1266 vtl
->current_track_gc
= NULL
;
1269 if ( ! vtl
->track_gc
)
1271 for ( i
= vtl
->track_gc
->len
- 1; i
>= 0; i
-- )
1272 g_object_unref ( g_array_index ( vtl
->track_gc
, GObject
*, i
) );
1273 g_array_free ( vtl
->track_gc
, TRUE
);
1274 vtl
->track_gc
= NULL
;
1277 static void trw_layer_new_track_gcs ( VikTrwLayer
*vtl
, VikViewport
*vp
)
1279 GdkGC
*gc
[ VIK_TRW_LAYER_TRACK_GC
];
1280 gint width
= vtl
->line_thickness
;
1282 if ( vtl
->track_gc
)
1283 trw_layer_free_track_gcs ( vtl
);
1285 if ( vtl
->track_bg_gc
)
1286 g_object_unref ( vtl
->track_bg_gc
);
1287 vtl
->track_bg_gc
= vik_viewport_new_gc ( vp
, "#FFFFFF", width
+ vtl
->bg_line_thickness
);
1289 if ( vtl
->current_track_gc
)
1290 g_object_unref ( vtl
->current_track_gc
);
1291 vtl
->current_track_gc
= vik_viewport_new_gc ( vp
, "#FF0000", 2 );
1292 gdk_gc_set_line_attributes ( vtl
->current_track_gc
, 2, GDK_LINE_ON_OFF_DASH
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1294 vtl
->track_gc
= g_array_sized_new ( FALSE
, FALSE
, sizeof ( GdkGC
* ), VIK_TRW_LAYER_TRACK_GC
);
1296 gc
[0] = vik_viewport_new_gc ( vp
, "#2d870a", width
); /* below range */
1298 gc
[1] = vik_viewport_new_gc ( vp
, "#0a8742", width
);
1299 gc
[2] = vik_viewport_new_gc ( vp
, "#0a8783", width
);
1300 gc
[3] = vik_viewport_new_gc ( vp
, "#0a4d87", width
);
1301 gc
[4] = vik_viewport_new_gc ( vp
, "#05469f", width
);
1302 gc
[5] = vik_viewport_new_gc ( vp
, "#1b059f", width
);
1303 gc
[6] = vik_viewport_new_gc ( vp
, "#2d059f", width
);
1304 gc
[7] = vik_viewport_new_gc ( vp
, "#4a059f", width
);
1305 gc
[8] = vik_viewport_new_gc ( vp
, "#84059f", width
);
1306 gc
[9] = vik_viewport_new_gc ( vp
, "#96059f", width
);
1307 gc
[10] = vik_viewport_new_gc ( vp
, "#f22ef2", width
);
1309 gc
[11] = vik_viewport_new_gc ( vp
, "#ff0000", width
); /* above range */
1311 gc
[12] = vik_viewport_new_gc ( vp
, "#000000", width
); /* black / no speed data */
1313 g_array_append_vals ( vtl
->track_gc
, gc
, VIK_TRW_LAYER_TRACK_GC
);
1316 VikTrwLayer
*vik_trw_layer_create ( VikViewport
*vp
)
1318 VikTrwLayer
*rv
= vik_trw_layer_new ( 0 );
1319 PangoFontDescription
*pfd
;
1320 rv
->wplabellayout
= gtk_widget_create_pango_layout (GTK_WIDGET(vp
), NULL
);
1321 pfd
= pango_font_description_from_string (WAYPOINT_FONT
);
1322 pango_layout_set_font_description (rv
->wplabellayout
, pfd
);
1323 /* freeing PangoFontDescription, cause it has been copied by prev. call */
1324 pango_font_description_free (pfd
);
1326 vik_layer_rename ( VIK_LAYER(rv
), vik_trw_layer_interface
.name
);
1328 trw_layer_new_track_gcs ( rv
, vp
);
1330 rv
->waypoint_gc
= vik_viewport_new_gc ( vp
, "#000000", 2 );
1331 rv
->waypoint_text_gc
= vik_viewport_new_gc ( vp
, "#FFFFFF", 1 );
1332 rv
->waypoint_bg_gc
= vik_viewport_new_gc ( vp
, "#8383C4", 1 );
1333 gdk_gc_set_function ( rv
->waypoint_bg_gc
, GDK_AND
);
1335 rv
->waypoint_font
= gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
1337 rv
->has_verified_thumbnails
= FALSE
;
1338 rv
->wp_symbol
= WP_SYMBOL_FILLED_SQUARE
;
1340 rv
->wp_draw_symbols
= TRUE
;
1342 rv
->coord_mode
= vik_viewport_get_coord_mode ( vp
);
1344 rv
->menu_selection
= vik_layer_get_interface(VIK_LAYER(rv
)->type
)->menu_items_selection
;
1349 static void trw_layer_realize_track ( gchar
*name
, VikTrack
*track
, gpointer pass_along
[4] )
1351 GtkTreeIter
*new_iter
= g_malloc(sizeof(GtkTreeIter
));
1353 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1354 vik_treeview_add_sublayer_alphabetized ( (VikTreeview
*) pass_along
[3], (GtkTreeIter
*) pass_along
[0], (GtkTreeIter
*) pass_along
[1], name
, pass_along
[2], name
, GPOINTER_TO_INT (pass_along
[4]), NULL
, TRUE
, TRUE
);
1356 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
);
1359 *new_iter
= *((GtkTreeIter
*) pass_along
[1]);
1360 g_hash_table_insert ( VIK_TRW_LAYER(pass_along
[2])->tracks_iters
, name
, new_iter
);
1362 if ( ! track
->visible
)
1363 vik_treeview_item_set_visible ( (VikTreeview
*) pass_along
[3], (GtkTreeIter
*) pass_along
[1], FALSE
);
1366 static void trw_layer_realize_waypoint ( gchar
*name
, VikWaypoint
*wp
, gpointer pass_along
[4] )
1368 GtkTreeIter
*new_iter
= g_malloc(sizeof(GtkTreeIter
));
1369 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1370 vik_treeview_add_sublayer_alphabetized ( (VikTreeview
*) pass_along
[3], (GtkTreeIter
*) pass_along
[0], (GtkTreeIter
*) pass_along
[1], name
, pass_along
[2], name
, GPOINTER_TO_INT (pass_along
[4]), NULL
, TRUE
, TRUE
);
1372 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
);
1375 *new_iter
= *((GtkTreeIter
*) pass_along
[1]);
1376 g_hash_table_insert ( VIK_TRW_LAYER(pass_along
[2])->waypoints_iters
, name
, new_iter
);
1378 if ( ! wp
->visible
)
1379 vik_treeview_item_set_visible ( (VikTreeview
*) pass_along
[3], (GtkTreeIter
*) pass_along
[1], FALSE
);
1383 void vik_trw_layer_realize ( VikTrwLayer
*vtl
, VikTreeview
*vt
, GtkTreeIter
*layer_iter
)
1386 gpointer pass_along
[5] = { &(vtl
->tracks_iter
), &iter2
, vtl
, vt
, (gpointer
) VIK_TRW_LAYER_SUBLAYER_TRACK
};
1388 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1389 vik_treeview_add_sublayer_alphabetized ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->tracks_iter
), _("Tracks"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_TRACKS
, NULL
, TRUE
, FALSE
);
1391 vik_treeview_add_sublayer ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->tracks_iter
), _("Tracks"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_TRACKS
, NULL
, TRUE
, FALSE
);
1393 if ( ! vtl
->tracks_visible
)
1394 vik_treeview_item_set_visible ( (VikTreeview
*) vt
, &(vtl
->tracks_iter
), FALSE
);
1396 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) trw_layer_realize_track
, pass_along
);
1398 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1399 vik_treeview_add_sublayer_alphabetized ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->waypoints_iter
), _("Waypoints"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
, NULL
, TRUE
, FALSE
);
1401 vik_treeview_add_sublayer ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->waypoints_iter
), _("Waypoints"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
, NULL
, TRUE
, FALSE
);
1404 if ( ! vtl
->waypoints_visible
)
1405 vik_treeview_item_set_visible ( (VikTreeview
*) vt
, &(vtl
->waypoints_iter
), FALSE
);
1407 pass_along
[0] = &(vtl
->waypoints_iter
);
1408 pass_along
[4] = (gpointer
) VIK_TRW_LAYER_SUBLAYER_WAYPOINT
;
1410 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) trw_layer_realize_waypoint
, pass_along
);
1414 gboolean
vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer
*l
, gint subtype
, gpointer sublayer
)
1418 case VIK_TRW_LAYER_SUBLAYER_TRACKS
: return (l
->tracks_visible
^= 1);
1419 case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
: return (l
->waypoints_visible
^= 1);
1420 case VIK_TRW_LAYER_SUBLAYER_TRACK
:
1422 VikTrack
*t
= g_hash_table_lookup ( l
->tracks
, sublayer
);
1424 return (t
->visible
^= 1);
1428 case VIK_TRW_LAYER_SUBLAYER_WAYPOINT
:
1430 VikWaypoint
*t
= g_hash_table_lookup ( l
->waypoints
, sublayer
);
1432 return (t
->visible
^= 1);
1440 GHashTable
*vik_trw_layer_get_tracks ( VikTrwLayer
*l
)
1445 GHashTable
*vik_trw_layer_get_waypoints ( VikTrwLayer
*l
)
1447 return l
->waypoints
;
1450 static void trw_layer_find_maxmin_waypoints ( const gchar
*name
, const VikWaypoint
*w
, struct LatLon maxmin
[2] )
1452 static VikCoord fixme
;
1453 vik_coord_copy_convert ( &(w
->coord
), VIK_COORD_LATLON
, &fixme
);
1454 if ( VIK_LATLON(&fixme
)->lat
> maxmin
[0].lat
|| maxmin
[0].lat
== 0.0 )
1455 maxmin
[0].lat
= VIK_LATLON(&fixme
)->lat
;
1456 if ( VIK_LATLON(&fixme
)->lat
< maxmin
[1].lat
|| maxmin
[1].lat
== 0.0 )
1457 maxmin
[1].lat
= VIK_LATLON(&fixme
)->lat
;
1458 if ( VIK_LATLON(&fixme
)->lon
> maxmin
[0].lon
|| maxmin
[0].lon
== 0.0 )
1459 maxmin
[0].lon
= VIK_LATLON(&fixme
)->lon
;
1460 if ( VIK_LATLON(&fixme
)->lon
< maxmin
[1].lon
|| maxmin
[1].lon
== 0.0 )
1461 maxmin
[1].lon
= VIK_LATLON(&fixme
)->lon
;
1464 static void trw_layer_find_maxmin_tracks ( const gchar
*name
, GList
**t
, struct LatLon maxmin
[2] )
1467 static VikCoord fixme
;
1471 vik_coord_copy_convert ( &(VIK_TRACKPOINT(tr
->data
)->coord
), VIK_COORD_LATLON
, &fixme
);
1472 if ( VIK_LATLON(&fixme
)->lat
> maxmin
[0].lat
|| maxmin
[0].lat
== 0.0 )
1473 maxmin
[0].lat
= VIK_LATLON(&fixme
)->lat
;
1474 if ( VIK_LATLON(&fixme
)->lat
< maxmin
[1].lat
|| maxmin
[1].lat
== 0.0 )
1475 maxmin
[1].lat
= VIK_LATLON(&fixme
)->lat
;
1476 if ( VIK_LATLON(&fixme
)->lon
> maxmin
[0].lon
|| maxmin
[0].lon
== 0.0 )
1477 maxmin
[0].lon
= VIK_LATLON(&fixme
)->lon
;
1478 if ( VIK_LATLON(&fixme
)->lon
< maxmin
[1].lon
|| maxmin
[1].lon
== 0.0 )
1479 maxmin
[1].lon
= VIK_LATLON(&fixme
)->lon
;
1484 static void trw_layer_find_maxmin (VikTrwLayer
*vtl
, struct LatLon maxmin
[2])
1486 struct LatLon wpt_maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1487 struct LatLon trk_maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1489 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) trw_layer_find_maxmin_waypoints
, wpt_maxmin
);
1490 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) trw_layer_find_maxmin_tracks
, trk_maxmin
);
1491 if ((wpt_maxmin
[0].lat
!= 0.0 && wpt_maxmin
[0].lat
> trk_maxmin
[0].lat
) || trk_maxmin
[0].lat
== 0.0) {
1492 maxmin
[0].lat
= wpt_maxmin
[0].lat
;
1495 maxmin
[0].lat
= trk_maxmin
[0].lat
;
1497 if ((wpt_maxmin
[0].lon
!= 0.0 && wpt_maxmin
[0].lon
> trk_maxmin
[0].lon
) || trk_maxmin
[0].lon
== 0.0) {
1498 maxmin
[0].lon
= wpt_maxmin
[0].lon
;
1501 maxmin
[0].lon
= trk_maxmin
[0].lon
;
1503 if ((wpt_maxmin
[1].lat
!= 0.0 && wpt_maxmin
[1].lat
< trk_maxmin
[1].lat
) || trk_maxmin
[1].lat
== 0.0) {
1504 maxmin
[1].lat
= wpt_maxmin
[1].lat
;
1507 maxmin
[1].lat
= trk_maxmin
[1].lat
;
1509 if ((wpt_maxmin
[1].lon
!= 0.0 && wpt_maxmin
[1].lon
< trk_maxmin
[1].lon
) || trk_maxmin
[1].lon
== 0.0) {
1510 maxmin
[1].lon
= wpt_maxmin
[1].lon
;
1513 maxmin
[1].lon
= trk_maxmin
[1].lon
;
1517 gboolean
vik_trw_layer_find_center ( VikTrwLayer
*vtl
, VikCoord
*dest
)
1519 /* 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... */
1520 struct LatLon maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1521 trw_layer_find_maxmin (vtl
, maxmin
);
1522 if (maxmin
[0].lat
== 0.0 && maxmin
[0].lon
== 0.0 && maxmin
[1].lat
== 0.0 && maxmin
[1].lon
== 0.0)
1526 struct LatLon average
= { (maxmin
[0].lat
+maxmin
[1].lat
)/2, (maxmin
[0].lon
+maxmin
[1].lon
)/2 };
1527 vik_coord_load_from_latlon ( dest
, vtl
->coord_mode
, &average
);
1532 static void trw_layer_centerize ( gpointer layer_and_vlp
[2] )
1535 if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp
[0]), &coord
) )
1536 goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp
[1]), &coord
);
1538 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]), _("This layer has no waypoints or trackpoints.") );
1541 static void trw_layer_export ( gpointer layer_and_vlp
[2], guint file_type
)
1543 GtkWidget
*file_selector
;
1545 gboolean failed
= FALSE
;
1546 file_selector
= gtk_file_chooser_dialog_new (_("Export Layer"),
1548 GTK_FILE_CHOOSER_ACTION_SAVE
,
1549 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1550 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
1552 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(file_selector
), vik_layer_get_name(VIK_LAYER(layer_and_vlp
[0])));
1554 while ( gtk_dialog_run ( GTK_DIALOG(file_selector
) ) == GTK_RESPONSE_ACCEPT
)
1556 fn
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector
) );
1557 if ( g_file_test ( fn
, G_FILE_TEST_EXISTS
) == FALSE
)
1559 gtk_widget_hide ( file_selector
);
1560 failed
= ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp
[0]), fn
, file_type
);
1565 if ( a_dialog_overwrite ( GTK_WINDOW(file_selector
), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn
) ) )
1567 gtk_widget_hide ( file_selector
);
1568 failed
= ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp
[0]), fn
, file_type
);
1573 gtk_widget_destroy ( file_selector
);
1575 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]), _("The filename you requested could not be opened for writing.") );
1578 static void trw_layer_export_gpspoint ( gpointer layer_and_vlp
[2] )
1580 trw_layer_export ( layer_and_vlp
, FILE_TYPE_GPSPOINT
);
1583 static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp
[2] )
1585 trw_layer_export ( layer_and_vlp
, FILE_TYPE_GPSMAPPER
);
1588 static void trw_layer_export_gpx ( gpointer layer_and_vlp
[2] )
1590 trw_layer_export ( layer_and_vlp
, FILE_TYPE_GPX
);
1593 static void trw_layer_goto_wp ( gpointer layer_and_vlp
[2] )
1595 GHashTable
*wps
= vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp
[0]) );
1596 GtkWidget
*dia
= gtk_dialog_new_with_buttons (_("Create"),
1597 VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]),
1598 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
,
1600 GTK_RESPONSE_REJECT
,
1602 GTK_RESPONSE_ACCEPT
,
1605 GtkWidget
*label
, *entry
;
1606 label
= gtk_label_new(_("Waypoint Name:"));
1607 entry
= gtk_entry_new();
1609 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), label
, FALSE
, FALSE
, 0);
1610 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), entry
, FALSE
, FALSE
, 0);
1611 gtk_widget_show_all ( label
);
1612 gtk_widget_show_all ( entry
);
1614 while ( gtk_dialog_run ( GTK_DIALOG(dia
) ) == GTK_RESPONSE_ACCEPT
)
1617 gchar
*upname
= g_strdup(gtk_entry_get_text(GTK_ENTRY(entry
)));
1620 for ( i
= strlen(upname
)-1; i
>= 0; i
-- )
1621 upname
[i
] = toupper(upname
[i
]);
1623 wp
= g_hash_table_lookup ( wps
, upname
);
1626 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]), _("Waypoint not found in this layer.") );
1629 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp
[1])), &(wp
->coord
) );
1630 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp
[1]) );
1631 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
) );
1638 gtk_widget_destroy ( dia
);
1641 gboolean
vik_trw_layer_new_waypoint ( VikTrwLayer
*vtl
, GtkWindow
*w
, const VikCoord
*def_coord
)
1643 gchar
*name
= highest_wp_number_get(vtl
);
1644 VikWaypoint
*wp
= vik_waypoint_new();
1645 wp
->coord
= *def_coord
;
1647 if ( a_dialog_new_waypoint ( w
, &name
, wp
, vik_trw_layer_get_waypoints ( vtl
), vtl
->coord_mode
) )
1650 vik_trw_layer_add_waypoint ( vtl
, name
, wp
);
1653 vik_waypoint_free(wp
);
1657 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav
[2] )
1660 struct LatLon one_ll
, two_ll
;
1661 struct LatLon maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1663 VikTrwLayer
*vtl
= VIK_TRW_LAYER(lav
[0]);
1664 VikLayersPanel
*vlp
= VIK_LAYERS_PANEL(lav
[1]);
1665 VikWindow
*vw
= (VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
));
1666 VikViewport
*vvp
= vik_window_viewport(vw
);
1667 vik_viewport_screen_to_coord ( vvp
, 0, 0, &one
);
1668 vik_viewport_screen_to_coord ( vvp
, vik_viewport_get_width(vvp
), vik_viewport_get_height(vvp
), &two
);
1669 vik_coord_to_latlon(&one
, &one_ll
);
1670 vik_coord_to_latlon(&two
, &two_ll
);
1671 if (one_ll
.lat
> two_ll
.lat
) {
1672 maxmin
[0].lat
= one_ll
.lat
;
1673 maxmin
[1].lat
= two_ll
.lat
;
1676 maxmin
[0].lat
= two_ll
.lat
;
1677 maxmin
[1].lat
= one_ll
.lat
;
1679 if (one_ll
.lon
> two_ll
.lon
) {
1680 maxmin
[0].lon
= one_ll
.lon
;
1681 maxmin
[1].lon
= two_ll
.lon
;
1684 maxmin
[0].lon
= two_ll
.lon
;
1685 maxmin
[1].lon
= one_ll
.lon
;
1687 a_geonames_wikipedia_box((VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vtl
, vlp
, maxmin
);
1690 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav
[2] )
1692 VikTrwLayer
*vtl
= VIK_TRW_LAYER(lav
[0]);
1693 VikLayersPanel
*vlp
= VIK_LAYERS_PANEL(lav
[1]);
1694 struct LatLon maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1696 trw_layer_find_maxmin (vtl
, maxmin
);
1697 a_geonames_wikipedia_box((VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vtl
, vlp
, maxmin
);
1700 static void trw_layer_new_wp ( gpointer lav
[2] )
1702 VikTrwLayer
*vtl
= VIK_TRW_LAYER(lav
[0]);
1703 VikLayersPanel
*vlp
= VIK_LAYERS_PANEL(lav
[1]);
1704 /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
1705 instead return true if you want to update. */
1706 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
)
1707 vik_layers_panel_emit_update ( vlp
);
1710 void vik_trw_layer_add_menu_items ( VikTrwLayer
*vtl
, GtkMenu
*menu
, gpointer vlp
)
1712 static gpointer pass_along
[2];
1714 GtkWidget
*export_submenu
;
1715 GtkWidget
*wikipedia_submenu
;
1716 pass_along
[0] = vtl
;
1717 pass_along
[1] = vlp
;
1719 item
= gtk_menu_item_new();
1720 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
1721 gtk_widget_show ( item
);
1723 item
= gtk_menu_item_new_with_label ( _("Goto Center of Layer") );
1724 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_centerize
), pass_along
);
1725 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1726 gtk_widget_show ( item
);
1728 item
= gtk_menu_item_new_with_label ( _("Goto Waypoint") );
1729 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_wp
), pass_along
);
1730 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1731 gtk_widget_show ( item
);
1733 export_submenu
= gtk_menu_new ();
1734 item
= gtk_menu_item_new_with_label ( _("Export layer") );
1735 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1736 gtk_widget_show ( item
);
1737 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item
), export_submenu
);
1739 item
= gtk_menu_item_new_with_label ( _("Export as GPSPoint") );
1740 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_export_gpspoint
), pass_along
);
1741 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu
), item
);
1742 gtk_widget_show ( item
);
1744 item
= gtk_menu_item_new_with_label ( _("Export as GPSMapper") );
1745 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_export_gpsmapper
), pass_along
);
1746 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu
), item
);
1747 gtk_widget_show ( item
);
1749 item
= gtk_menu_item_new_with_label ( _("Export as GPX") );
1750 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_export_gpx
), pass_along
);
1751 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu
), item
);
1752 gtk_widget_show ( item
);
1754 item
= gtk_menu_item_new_with_label ( _("New Waypoint") );
1755 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wp
), pass_along
);
1756 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1757 gtk_widget_show ( item
);
1759 #ifdef VIK_CONFIG_GEONAMES
1760 wikipedia_submenu
= gtk_menu_new();
1761 item
= gtk_menu_item_new_with_label ( _("Add Wikipedia Waypoints") );
1762 gtk_menu_shell_append(GTK_MENU_SHELL (menu
), item
);
1763 gtk_widget_show(item
);
1764 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), wikipedia_submenu
);
1766 item
= gtk_menu_item_new_with_label ( _("Within layer bounds") );
1767 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer
), pass_along
);
1768 gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu
), item
);
1769 gtk_widget_show ( item
);
1771 item
= gtk_menu_item_new_with_label ( _("Within current view") );
1772 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport
), pass_along
);
1773 gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu
), item
);
1774 gtk_widget_show ( item
);
1777 #ifdef VIK_CONFIG_OPENSTREETMAP
1778 item
= gtk_menu_item_new_with_label ( _("Upload to OSM") );
1779 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(osm_traces_upload_cb
), pass_along
);
1780 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1781 gtk_widget_show ( item
);
1784 item
= a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vlp
,
1785 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp
)), vtl
);
1787 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1788 gtk_widget_show ( item
);
1791 item
= a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vlp
,
1792 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp
)), vtl
);
1794 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1795 gtk_widget_show ( item
);
1799 void vik_trw_layer_add_waypoint ( VikTrwLayer
*vtl
, gchar
*name
, VikWaypoint
*wp
)
1801 if ( VIK_LAYER(vtl
)->realized
)
1803 VikWaypoint
*oldwp
= VIK_WAYPOINT ( g_hash_table_lookup ( vtl
->waypoints
, name
) );
1805 wp
->visible
= oldwp
->visible
; /* same visibility so we don't have to update viktreeview */
1808 GtkTreeIter
*iter
= g_malloc(sizeof(GtkTreeIter
));
1809 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1810 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl
)->vt
, &(vtl
->waypoints_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, NULL
, TRUE
, TRUE
);
1812 vik_treeview_add_sublayer ( VIK_LAYER(vtl
)->vt
, &(vtl
->waypoints_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, NULL
, TRUE
, TRUE
);
1814 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, iter
);
1815 g_hash_table_insert ( vtl
->waypoints_iters
, name
, iter
);
1822 highest_wp_number_add_wp(vtl
, name
);
1823 g_hash_table_insert ( vtl
->waypoints
, name
, wp
);
1827 void vik_trw_layer_add_track ( VikTrwLayer
*vtl
, gchar
*name
, VikTrack
*t
)
1829 if ( VIK_LAYER(vtl
)->realized
)
1831 VikTrack
*oldt
= VIK_TRACK ( g_hash_table_lookup ( vtl
->tracks
, name
) );
1833 t
->visible
= oldt
->visible
; /* same visibility so we don't have to update viktreeview */
1836 GtkTreeIter
*iter
= g_malloc(sizeof(GtkTreeIter
));
1837 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1838 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl
)->vt
, &(vtl
->tracks_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_TRACK
, NULL
, TRUE
, TRUE
);
1840 vik_treeview_add_sublayer ( VIK_LAYER(vtl
)->vt
, &(vtl
->tracks_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_TRACK
, NULL
, TRUE
, TRUE
);
1842 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, iter
);
1843 g_hash_table_insert ( vtl
->tracks_iters
, name
, iter
);
1844 /* t->visible = TRUE; */
1848 ; /* t->visible = TRUE; // this is now used by file input functions */
1850 g_hash_table_insert ( vtl
->tracks
, name
, t
);
1854 /* to be called whenever a track has been deleted or may have been changed. */
1855 void trw_layer_cancel_tps_of_track ( VikTrwLayer
*vtl
, const gchar
*trk_name
)
1857 if (vtl
->current_tp_track_name
&& g_strcasecmp(trk_name
, vtl
->current_tp_track_name
) == 0)
1858 trw_layer_cancel_current_tp ( vtl
, FALSE
);
1859 else if (vtl
->last_tp_track_name
&& g_strcasecmp(trk_name
, vtl
->last_tp_track_name
) == 0)
1860 trw_layer_cancel_last_tp ( vtl
);
1863 static gchar
*get_new_unique_sublayer_name (VikTrwLayer
*vtl
, gint sublayer_type
, const gchar
*name
)
1866 gchar
*newname
= g_strdup(name
);
1867 while ((sublayer_type
== VIK_TRW_LAYER_SUBLAYER_TRACK
) ?
1868 (void *)vik_trw_layer_get_track(vtl
, newname
) : (void *)vik_trw_layer_get_waypoint(vtl
, newname
)) {
1869 gchar
*new_newname
= g_strdup_printf("%s#%d", name
, i
);
1871 newname
= new_newname
;
1877 void vik_trw_layer_filein_add_waypoint ( VikTrwLayer
*vtl
, gchar
*name
, VikWaypoint
*wp
)
1879 vik_trw_layer_add_waypoint ( vtl
,
1880 get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, name
),
1883 void vik_trw_layer_filein_add_track ( VikTrwLayer
*vtl
, gchar
*name
, VikTrack
*tr
)
1885 if ( vtl
->magic_scissors_append
&& vtl
->magic_scissors_current_track
) {
1886 vik_track_remove_dup_points ( tr
); /* make "double point" track work to undo */
1887 vik_track_steal_and_append_trackpoints ( vtl
->magic_scissors_current_track
, tr
);
1888 vik_track_free ( tr
);
1889 vtl
->magic_scissors_append
= FALSE
; /* this means we have added it */
1891 gchar
*new_name
= get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_TRACK
, name
);
1892 vik_trw_layer_add_track ( vtl
, new_name
, tr
);
1894 if ( vtl
->magic_scissors_check_added_track
) {
1895 vik_track_remove_dup_points ( tr
); /* make "double point" track work to undo */
1896 if ( vtl
->magic_scissors_added_track_name
) /* for google routes */
1897 g_free ( vtl
->magic_scissors_added_track_name
);
1898 vtl
->magic_scissors_added_track_name
= g_strdup(new_name
);
1903 static void trw_layer_enum_item ( const gchar
*name
, GList
**tr
, GList
**l
)
1905 *l
= g_list_append(*l
, (gpointer
)name
);
1908 static void trw_layer_move_item ( VikTrwLayer
*vtl_src
, VikTrwLayer
*vtl_dest
, gchar
*name
, gint type
)
1910 gchar
*newname
= get_new_unique_sublayer_name(vtl_dest
, type
, name
);
1911 if (type
== VIK_TRW_LAYER_SUBLAYER_TRACK
) {
1913 t
= vik_track_copy(vik_trw_layer_get_track(vtl_src
, name
));
1914 vik_trw_layer_delete_track(vtl_src
, name
);
1915 vik_trw_layer_add_track(vtl_dest
, newname
, t
);
1917 if (type
==VIK_TRW_LAYER_SUBLAYER_WAYPOINT
) {
1919 w
= vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src
, name
));
1920 vik_trw_layer_delete_waypoint(vtl_src
, name
);
1921 vik_trw_layer_add_waypoint(vtl_dest
, newname
, w
);
1925 static void trw_layer_drag_drop_request ( VikTrwLayer
*vtl_src
, VikTrwLayer
*vtl_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
)
1927 VikTreeview
*vt
= VIK_LAYER(vtl_src
)->vt
;
1928 gint type
= vik_treeview_item_get_data(vt
, src_item_iter
);
1930 if (!vik_treeview_item_get_pointer(vt
, src_item_iter
)) {
1931 GList
*items
= NULL
;
1934 if (type
==VIK_TRW_LAYER_SUBLAYER_TRACKS
) {
1935 g_hash_table_foreach ( vtl_src
->tracks
, (GHFunc
)trw_layer_enum_item
, &items
);
1937 if (type
==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
) {
1938 g_hash_table_foreach ( vtl_src
->waypoints
, (GHFunc
)trw_layer_enum_item
, &items
);
1943 if (type
==VIK_TRW_LAYER_SUBLAYER_TRACKS
) {
1944 trw_layer_move_item ( vtl_src
, vtl_dest
, iter
->data
, VIK_TRW_LAYER_SUBLAYER_TRACK
);
1946 trw_layer_move_item ( vtl_src
, vtl_dest
, iter
->data
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
);
1953 gchar
*name
= vik_treeview_item_get_pointer(vt
, src_item_iter
);
1954 trw_layer_move_item(vtl_src
, vtl_dest
, name
, type
);
1959 gboolean
vik_trw_layer_delete_track ( VikTrwLayer
*vtl
, const gchar
*trk_name
)
1961 VikTrack
*t
= g_hash_table_lookup ( vtl
->tracks
, trk_name
);
1962 gboolean was_visible
= FALSE
;
1966 was_visible
= t
->visible
;
1967 if ( t
== vtl
->current_track
)
1968 vtl
->current_track
= NULL
;
1969 if ( t
== vtl
->magic_scissors_current_track
)
1970 vtl
->magic_scissors_current_track
= NULL
;
1972 /* could be current_tp, so we have to check */
1973 trw_layer_cancel_tps_of_track ( vtl
, trk_name
);
1975 g_assert ( ( it
= g_hash_table_lookup ( vtl
->tracks_iters
, trk_name
) ) );
1976 vik_treeview_item_delete ( VIK_LAYER(vtl
)->vt
, it
);
1977 g_hash_table_remove ( vtl
->tracks_iters
, trk_name
);
1979 /* do this last because trk_name may be pointing to actual orig key */
1980 g_hash_table_remove ( vtl
->tracks
, trk_name
);
1985 gboolean
vik_trw_layer_delete_waypoint ( VikTrwLayer
*vtl
, const gchar
*wp_name
)
1987 gboolean was_visible
= FALSE
;
1990 wp
= g_hash_table_lookup ( vtl
->waypoints
, wp_name
);
1994 if ( wp
== vtl
->current_wp
) {
1995 vtl
->current_wp
= NULL
;
1996 vtl
->current_wp_name
= NULL
;
1997 vtl
->moving_wp
= FALSE
;
2000 was_visible
= wp
->visible
;
2001 g_assert ( ( it
= g_hash_table_lookup ( vtl
->waypoints_iters
, (gchar
*) wp_name
) ) );
2002 vik_treeview_item_delete ( VIK_LAYER(vtl
)->vt
, it
);
2003 g_hash_table_remove ( vtl
->waypoints_iters
, (gchar
*) wp_name
);
2005 highest_wp_number_remove_wp(vtl
, wp_name
);
2006 g_hash_table_remove ( vtl
->waypoints
, wp_name
); /* last because this frees name */
2012 static void remove_item_from_treeview(const gchar
*name
, GtkTreeIter
*it
, VikTreeview
* vt
)
2014 vik_treeview_item_delete (vt
, it
);
2017 void vik_trw_layer_delete_all_tracks ( VikTrwLayer
*vtl
)
2020 vtl
->current_track
= NULL
;
2021 vtl
->magic_scissors_current_track
= NULL
;
2022 if (vtl
->current_tp_track_name
)
2023 trw_layer_cancel_current_tp(vtl
, FALSE
);
2024 if (vtl
->last_tp_track_name
)
2025 trw_layer_cancel_last_tp ( vtl
);
2027 g_hash_table_foreach(vtl
->tracks_iters
, (GHFunc
) remove_item_from_treeview
, VIK_LAYER(vtl
)->vt
);
2028 g_hash_table_remove_all(vtl
->tracks_iters
);
2029 g_hash_table_remove_all(vtl
->tracks
);
2031 /* TODO: only update if the layer is visible (ticked) */
2032 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2035 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer
*vtl
)
2037 vtl
->current_wp
= NULL
;
2038 vtl
->current_wp_name
= NULL
;
2039 vtl
->moving_wp
= FALSE
;
2041 highest_wp_number_reset(vtl
);
2043 g_hash_table_foreach(vtl
->waypoints_iters
, (GHFunc
) remove_item_from_treeview
, VIK_LAYER(vtl
)->vt
);
2044 g_hash_table_remove_all(vtl
->waypoints_iters
);
2045 g_hash_table_remove_all(vtl
->waypoints
);
2047 /* TODO: only update if the layer is visible (ticked) */
2048 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2051 static void trw_layer_delete_item ( gpointer pass_along
[5] )
2053 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2054 gboolean was_visible
= FALSE
;
2055 if ( GPOINTER_TO_INT (pass_along
[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2057 was_visible
= vik_trw_layer_delete_waypoint ( vtl
, (gchar
*) pass_along
[3] );
2061 was_visible
= vik_trw_layer_delete_track ( vtl
, (gchar
*) pass_along
[3] );
2064 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2068 static void trw_layer_properties_item ( gpointer pass_along
[5] )
2070 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2071 if ( GPOINTER_TO_INT (pass_along
[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2073 VikWaypoint
*wp
= g_hash_table_lookup ( vtl
->waypoints
, pass_along
[3] );
2076 if ( a_dialog_new_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), NULL
, wp
, NULL
, vtl
->coord_mode
) )
2078 if ( VIK_LAYER(vtl
)->visible
)
2079 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2084 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, pass_along
[3] );
2087 vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl
),
2089 pass_along
[1], /* vlp */
2090 pass_along
[3] /* track name */);
2095 static void goto_coord ( VikLayersPanel
*vlp
, const VikCoord
*coord
)
2097 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp
), coord
);
2098 vik_layers_panel_emit_update ( vlp
);
2101 static void trw_layer_goto_track_startpoint ( gpointer pass_along
[5] )
2103 GList
*trps
= ((VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] ))->trackpoints
;
2104 if ( trps
&& trps
->data
)
2105 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(((VikTrackpoint
*) trps
->data
)->coord
));
2108 static void trw_layer_goto_track_center ( gpointer pass_along
[5] )
2110 /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
2111 GList
**trps
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2112 if ( trps
&& *trps
)
2114 struct LatLon average
, maxmin
[2] = { {0,0}, {0,0} };
2116 trw_layer_find_maxmin_tracks ( NULL
, trps
, maxmin
);
2117 average
.lat
= (maxmin
[0].lat
+maxmin
[1].lat
)/2;
2118 average
.lon
= (maxmin
[0].lon
+maxmin
[1].lon
)/2;
2119 vik_coord_load_from_latlon ( &coord
, VIK_TRW_LAYER(pass_along
[0])->coord_mode
, &average
);
2120 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &coord
);
2124 static void trw_layer_extend_track_end ( gpointer pass_along
[6] )
2126 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2127 VikTrack
*track
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2129 vtl
->current_track
= track
;
2130 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), VIK_LAYER_TRW
, TOOL_CREATE_TRACK
);
2132 if ( track
->trackpoints
)
2133 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(((VikTrackpoint
*)g_list_last(track
->trackpoints
)->data
)->coord
) );
2137 * extend a track using magic scissors
2139 static void trw_layer_extend_track_end_ms ( gpointer pass_along
[6] )
2141 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2142 VikTrack
*track
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2143 VikCoord last_coord
= (((VikTrackpoint
*)g_list_last(track
->trackpoints
)->data
)->coord
);
2145 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), VIK_LAYER_TRW
, NUM_TOOLS
);
2146 vtl
->magic_scissors_coord
= last_coord
;
2147 vtl
->magic_scissors_current_track
= track
;
2149 if ( track
->trackpoints
)
2150 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &last_coord
) ;
2154 static void trw_layer_apply_dem_data ( gpointer pass_along
[6] )
2156 /* TODO: check & warn if no DEM data, or no applicable DEM data. */
2157 /* Also warn if overwrite old elevation data */
2158 VikTrack
*track
= (VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2160 vik_track_apply_dem_data ( track
);
2163 static void trw_layer_goto_track_endpoint ( gpointer pass_along
[6] )
2165 GList
*trps
= ((VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] ))->trackpoints
;
2168 trps
= g_list_last(trps
);
2169 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(((VikTrackpoint
*) trps
->data
)->coord
));
2173 /*************************************
2174 * merge/split by time routines
2175 *************************************/
2177 /* called for each key in track hash table.
2178 * If the current track has time stamp, add it to the result,
2179 * except the one pointed by "exclude".
2180 * set exclude to NULL if there is no exclude to check.
2181 * Not that result is in reverse (for performance reason).
2187 static void find_tracks_with_timestamp(gpointer key
, gpointer value
, gpointer udata
)
2189 twt_udata
*user_data
= udata
;
2190 VikTrackpoint
*p1
, *p2
;
2192 if (VIK_TRACK(value
)->trackpoints
== user_data
->exclude
) {
2196 if (VIK_TRACK(value
)->trackpoints
) {
2197 p1
= VIK_TRACKPOINT(VIK_TRACK(value
)->trackpoints
->data
);
2198 p2
= VIK_TRACKPOINT(g_list_last(VIK_TRACK(value
)->trackpoints
)->data
);
2200 if (!p1
->has_timestamp
|| !p2
->has_timestamp
) {
2201 g_print("no timestamp\n");
2207 *(user_data
->result
) = g_list_prepend(*(user_data
->result
), key
);
2210 /* called for each key in track hash table. if original track user_data[1] is close enough
2211 * to the passed one, add it to list in user_data[0]
2213 static void find_nearby_track(gpointer key
, gpointer value
, gpointer user_data
)
2216 VikTrackpoint
*p1
, *p2
;
2218 GList
**nearby_tracks
= ((gpointer
*)user_data
)[0];
2219 GList
*orig_track
= ((gpointer
*)user_data
)[1];
2220 guint thr
= GPOINTER_TO_UINT (((gpointer
*)user_data
)[2]);
2223 * detect reasons for not merging, and return
2224 * if no reason is found not to merge, then do it.
2227 if (VIK_TRACK(value
)->trackpoints
== orig_track
) {
2231 t1
= VIK_TRACKPOINT(orig_track
->data
)->timestamp
;
2232 t2
= VIK_TRACKPOINT(g_list_last(orig_track
)->data
)->timestamp
;
2234 if (VIK_TRACK(value
)->trackpoints
) {
2235 p1
= VIK_TRACKPOINT(VIK_TRACK(value
)->trackpoints
->data
);
2236 p2
= VIK_TRACKPOINT(g_list_last(VIK_TRACK(value
)->trackpoints
)->data
);
2238 if (!p1
->has_timestamp
|| !p2
->has_timestamp
) {
2239 g_print("no timestamp\n");
2243 /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
2244 if (! (abs(t1
- p2
->timestamp
) < thr
*60 ||
2246 abs(p1
->timestamp
- t2
) < thr
*60)
2253 *nearby_tracks
= g_list_prepend(*nearby_tracks
, key
);
2256 /* comparison function used to sort tracks; a and b are hash table keys */
2257 static gint
track_compare(gconstpointer a
, gconstpointer b
, gpointer user_data
)
2259 GHashTable
*tracks
= user_data
;
2262 t1
= VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks
, a
))->trackpoints
->data
)->timestamp
;
2263 t2
= VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks
, b
))->trackpoints
->data
)->timestamp
;
2265 if (t1
< t2
) return -1;
2266 if (t1
> t2
) return 1;
2270 /* comparison function used to sort trackpoints */
2271 static gint
trackpoint_compare(gconstpointer a
, gconstpointer b
)
2273 time_t t1
= VIK_TRACKPOINT(a
)->timestamp
, t2
= VIK_TRACKPOINT(b
)->timestamp
;
2275 if (t1
< t2
) return -1;
2276 if (t1
> t2
) return 1;
2280 static void trw_layer_merge_with_other ( gpointer pass_along
[6] )
2282 VikTrwLayer
*vtl
= (VikTrwLayer
*)pass_along
[0];
2283 gchar
*orig_track_name
= pass_along
[3];
2284 GList
*tracks_with_timestamp
= NULL
;
2285 VikTrack
*track
= (VikTrack
*) g_hash_table_lookup ( vtl
->tracks
, orig_track_name
);
2287 if (track
->trackpoints
&&
2288 !VIK_TRACKPOINT(track
->trackpoints
->data
)->has_timestamp
) {
2289 a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl
), _("Failed. This track does not have timestamp"));
2296 udata
.result
= &tracks_with_timestamp
;
2297 udata
.exclude
= track
->trackpoints
;
2298 g_hash_table_foreach(vtl
->tracks
, find_tracks_with_timestamp
, (gpointer
)&udata
);
2299 tracks_with_timestamp
= g_list_reverse(tracks_with_timestamp
);
2302 if (!tracks_with_timestamp
) {
2303 a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl
), _("Failed. No other track in this layer has timestamp"));
2307 GList
*merge_list
= a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl
),
2308 vtl
->tracks
, tracks_with_timestamp
, TRUE
,
2309 _("Merge with..."), _("Select track to merge with"));
2310 g_list_free(tracks_with_timestamp
);
2315 for (l
= merge_list
; l
!= NULL
; l
= g_list_next(l
)) {
2316 VikTrack
*merge_track
= (VikTrack
*) g_hash_table_lookup (vtl
->tracks
, l
->data
);
2318 track
->trackpoints
= g_list_concat(track
->trackpoints
, merge_track
->trackpoints
);
2319 merge_track
->trackpoints
= NULL
;
2320 vik_trw_layer_delete_track(vtl
, l
->data
);
2321 track
->trackpoints
= g_list_sort(track
->trackpoints
, trackpoint_compare
);
2324 /* TODO: free data before free merge_list */
2325 for (l
= merge_list
; l
!= NULL
; l
= g_list_next(l
))
2327 g_list_free(merge_list
);
2328 vik_layer_emit_update( VIK_LAYER(vtl
) );
2332 /* merge by time routine */
2333 static void trw_layer_merge_by_timestamp ( gpointer pass_along
[6] )
2335 VikTrwLayer
*vtl
= (VikTrwLayer
*)pass_along
[0];
2336 gchar
*orig_track_name
= strdup(pass_along
[3]);
2339 GList
*nearby_tracks
;
2342 static guint thr
= 1;
2343 guint track_count
= 0;
2345 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl
),
2346 _("Merge Threshold..."),
2347 _("Merge when time between tracks less than:"),
2349 free(orig_track_name
);
2353 /* merge tracks until we can't */
2354 nearby_tracks
= NULL
;
2358 track
= (VikTrack
*) g_hash_table_lookup ( vtl
->tracks
, orig_track_name
);
2359 trps
= track
->trackpoints
;
2364 if (nearby_tracks
) {
2365 g_list_free(nearby_tracks
);
2366 nearby_tracks
= NULL
;
2369 t1
= ((VikTrackpoint
*)trps
->data
)->timestamp
;
2370 t2
= ((VikTrackpoint
*)g_list_last(trps
)->data
)->timestamp
;
2372 /* g_print("Original track times: %d and %d\n", t1, t2); */
2373 params
[0] = &nearby_tracks
;
2375 params
[2] = GUINT_TO_POINTER (thr
);
2377 /* get a list of adjacent-in-time tracks */
2378 g_hash_table_foreach(vtl
->tracks
, find_nearby_track
, (gpointer
)params
);
2380 /* add original track */
2381 nearby_tracks
= g_list_prepend(nearby_tracks
, orig_track_name
);
2385 #define get_track(x) VIK_TRACK(g_hash_table_lookup(vtl->tracks, (gchar *)((x)->data)))
2386 #define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
2387 #define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
2388 GList
*l
= nearby_tracks
;
2389 VikTrack
*tr
= vik_track_new();
2390 tr
->visible
= track
->visible
;
2395 t1 = get_first_trackpoint(l)->timestamp;
2396 t2 = get_last_trackpoint(l)->timestamp;
2397 g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
2401 /* remove trackpoints from merged track, delete track */
2402 tr
->trackpoints
= g_list_concat(tr
->trackpoints
, get_track(l
)->trackpoints
);
2403 get_track(l
)->trackpoints
= NULL
;
2404 vik_trw_layer_delete_track(vtl
, l
->data
);
2409 tr
->trackpoints
= g_list_sort(tr
->trackpoints
, trackpoint_compare
);
2410 vik_trw_layer_add_track(vtl
, strdup(orig_track_name
), tr
);
2412 #undef get_first_trackpoint
2413 #undef get_last_trackpoint
2416 } while (track_count
> 1);
2417 g_list_free(nearby_tracks
);
2418 free(orig_track_name
);
2419 vik_layer_emit_update( VIK_LAYER(vtl
) );
2422 /* split by time routine */
2423 static void trw_layer_split_by_timestamp ( gpointer pass_along
[6] )
2425 VikTrack
*track
= (VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2426 GList
*trps
= track
->trackpoints
;
2428 GList
*newlists
= NULL
;
2429 GList
*newtps
= NULL
;
2431 static guint thr
= 1;
2438 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along
[0]),
2439 _("Split Threshold..."),
2440 _("Split when time between trackpoints exceeds:"),
2445 /* iterate through trackpoints, and copy them into new lists without touching original list */
2446 prev_ts
= VIK_TRACKPOINT(trps
->data
)->timestamp
;
2450 ts
= VIK_TRACKPOINT(iter
->data
)->timestamp
;
2452 g_print("panic: ts < prev_ts: this should never happen!\n");
2455 if (ts
- prev_ts
> thr
*60) {
2456 /* flush accumulated trackpoints into new list */
2457 newlists
= g_list_prepend(newlists
, g_list_reverse(newtps
));
2461 /* accumulate trackpoint copies in newtps, in reverse order */
2462 newtps
= g_list_prepend(newtps
, vik_trackpoint_copy(VIK_TRACKPOINT(iter
->data
)));
2464 iter
= g_list_next(iter
);
2467 newlists
= g_list_prepend(newlists
, g_list_reverse(newtps
));
2470 /* put lists of trackpoints into tracks */
2477 tr
= vik_track_new();
2478 tr
->visible
= track
->visible
;
2479 tr
->trackpoints
= (GList
*)(iter
->data
);
2481 new_tr_name
= g_strdup_printf("%s #%d", (gchar
*) pass_along
[3], i
++);
2482 vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along
[0]), new_tr_name
, tr
);
2483 /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
2484 VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
2486 iter
= g_list_next(iter
);
2488 g_list_free(newlists
);
2489 vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along
[0]), (gchar
*)pass_along
[3]);
2490 vik_layer_emit_update(VIK_LAYER(pass_along
[0]));
2493 /* end of split/merge routines */
2496 static void trw_layer_goto_waypoint ( gpointer pass_along
[5] )
2498 VikWaypoint
*wp
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->waypoints
, pass_along
[3] );
2500 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(wp
->coord
) );
2503 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along
[5] )
2505 gchar
*webpage
= g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar
*) pass_along
[3] );
2506 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along
[0])), webpage
);
2510 const gchar
*vik_trw_layer_sublayer_rename_request ( VikTrwLayer
*l
, const gchar
*newname
, gpointer vlp
, gint subtype
, gpointer sublayer
, GtkTreeIter
*iter
)
2512 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2517 if (strcmp(newname
, sublayer
) == 0 )
2520 if (strcasecmp(newname
, sublayer
)) { /* Not just changing case */
2521 if (g_hash_table_lookup( l
->waypoints
, newname
))
2523 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l
), _("Waypoint Already Exists") );
2528 iter
= g_hash_table_lookup ( l
->waypoints_iters
, sublayer
);
2529 g_hash_table_steal ( l
->waypoints_iters
, sublayer
);
2531 wp
= vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l
->waypoints
, sublayer
)) );
2532 highest_wp_number_remove_wp(l
, sublayer
);
2533 g_hash_table_remove ( l
->waypoints
, sublayer
);
2535 rv
= g_strdup(newname
);
2537 vik_treeview_item_set_pointer ( VIK_LAYER(l
)->vt
, iter
, rv
);
2539 highest_wp_number_add_wp(l
, rv
);
2540 g_hash_table_insert ( l
->waypoints
, rv
, wp
);
2541 g_hash_table_insert ( l
->waypoints_iters
, rv
, iter
);
2543 /* it hasn't been updated yet so we pass new name */
2544 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
2545 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l
)->vt
, iter
, rv
);
2548 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp
) );
2551 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
)
2558 if (strcmp(newname
, sublayer
) == 0)
2561 if (strcasecmp(newname
, sublayer
)) { /* Not just changing case */
2562 if (g_hash_table_lookup( l
->waypoints
, newname
))
2564 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l
), _("Track Already Exists") );
2569 g_hash_table_lookup_extended ( l
->tracks
, sublayer
, (void *)&orig_key
, (void *)&tr
);
2570 g_hash_table_steal ( l
->tracks
, sublayer
);
2572 iter
= g_hash_table_lookup ( l
->tracks_iters
, sublayer
);
2573 g_hash_table_steal ( l
->tracks_iters
, sublayer
);
2575 rv
= g_strdup(newname
);
2577 vik_treeview_item_set_pointer ( VIK_LAYER(l
)->vt
, iter
, rv
);
2579 g_hash_table_insert ( l
->tracks
, rv
, tr
);
2580 g_hash_table_insert ( l
->tracks_iters
, rv
, iter
);
2582 /* don't forget about current_tp_track_name, update that too */
2583 if ( l
->current_tp_track_name
&& g_strcasecmp(orig_key
,l
->current_tp_track_name
) == 0 )
2585 l
->current_tp_track_name
= rv
;
2587 vik_trw_layer_tpwin_set_track_name ( l
->tpwin
, rv
);
2589 else if ( l
->last_tp_track_name
&& g_strcasecmp(orig_key
,l
->last_tp_track_name
) == 0 )
2590 l
->last_tp_track_name
= rv
;
2592 g_free ( orig_key
);
2594 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
2595 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l
)->vt
, iter
, rv
);
2598 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp
) );
2604 static gboolean
is_valid_geocache_name ( gchar
*str
)
2606 gint len
= strlen ( str
);
2607 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]));
2610 static void trw_layer_track_use_with_filter ( gpointer
*pass_along
)
2612 gchar
*track_name
= (gchar
*) pass_along
[3];
2613 VikTrack
*tr
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, track_name
);
2614 a_acquire_set_filter_track ( tr
, track_name
);
2617 static gboolean
is_valid_google_route ( VikTrwLayer
*vtl
, const gchar
*track_name
)
2619 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, track_name
);
2620 return ( tr
&& tr
->comment
&& strlen(tr
->comment
) > 7 && !strncmp(tr
->comment
, "from:", 5) );
2623 static void trw_layer_track_google_route_webpage( gpointer
*pass_along
)
2625 gchar
*track_name
= (gchar
*) pass_along
[3];
2626 VikTrack
*tr
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, track_name
);
2628 gchar
*escaped
= uri_escape ( tr
->comment
);
2629 gchar
*webpage
= g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped
);
2630 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along
[0])), webpage
);
2636 /* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
2637 gboolean
vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer
*l
, GtkMenu
*menu
, gpointer vlp
, gint subtype
, gpointer sublayer
, GtkTreeIter
*iter
)
2639 static GtkTreeIter staticiter
;
2640 static gpointer pass_along
[5];
2642 gboolean rv
= FALSE
;
2645 pass_along
[1] = vlp
;
2646 pass_along
[2] = GINT_TO_POINTER (subtype
);
2647 pass_along
[3] = sublayer
;
2648 staticiter
= *iter
; /* will exist after function has ended */
2649 pass_along
[4] = &staticiter
;
2651 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
|| subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
)
2655 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES
, NULL
);
2656 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_properties_item
), pass_along
);
2657 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2658 gtk_widget_show ( item
);
2660 if (subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
) {
2661 VikTrwLayer
*vtl
= l
;
2662 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, sublayer
);
2663 if (tr
&& tr
->property_dialog
)
2664 gtk_widget_set_sensitive(GTK_WIDGET(item
), FALSE
);
2667 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT
, NULL
);
2668 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_cut_item_cb
), pass_along
);
2669 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2670 gtk_widget_show ( item
);
2672 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY
, NULL
);
2673 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_copy_item_cb
), pass_along
);
2674 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2675 gtk_widget_show ( item
);
2677 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE
, NULL
);
2678 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_delete_item
), pass_along
);
2679 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2680 gtk_widget_show ( item
);
2682 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2684 /* could be a right-click using the tool */
2685 if ( vlp
!= NULL
) {
2686 item
= gtk_menu_item_new_with_label ( _("Goto") );
2687 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_waypoint
), pass_along
);
2688 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2689 gtk_widget_show ( item
);
2692 if ( is_valid_geocache_name ( (gchar
*) sublayer
) )
2694 item
= gtk_menu_item_new_with_label ( _("Visit Geocache Webpage") );
2695 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage
), pass_along
);
2696 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2697 gtk_widget_show ( item
);
2703 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
)
2705 item
= gtk_menu_item_new ();
2706 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2707 gtk_widget_show ( item
);
2709 item
= gtk_menu_item_new_with_label ( _("Goto Startpoint") );
2710 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_track_startpoint
), pass_along
);
2711 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2712 gtk_widget_show ( item
);
2714 item
= gtk_menu_item_new_with_label ( _("Goto \"Center\"") );
2715 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_track_center
), pass_along
);
2716 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2717 gtk_widget_show ( item
);
2719 item
= gtk_menu_item_new_with_label ( _("Goto Endpoint") );
2720 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_track_endpoint
), pass_along
);
2721 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2722 gtk_widget_show ( item
);
2724 item
= gtk_menu_item_new_with_label ( _("Merge By Time") );
2725 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_merge_by_timestamp
), pass_along
);
2726 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2727 gtk_widget_show ( item
);
2729 item
= gtk_menu_item_new_with_label ( _("Merge With Other Tracks...") );
2730 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_merge_with_other
), pass_along
);
2731 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2732 gtk_widget_show ( item
);
2734 item
= gtk_menu_item_new_with_label ( _("Split By Time") );
2735 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_split_by_timestamp
), pass_along
);
2736 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2737 gtk_widget_show ( item
);
2739 item
= gtk_menu_item_new_with_label ( _("Download maps along track...") );
2740 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb
), pass_along
);
2741 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2742 gtk_widget_show ( item
);
2744 item
= gtk_menu_item_new_with_label ( _("Apply DEM Data") );
2745 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_apply_dem_data
), pass_along
);
2746 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2747 gtk_widget_show ( item
);
2749 item
= gtk_menu_item_new_with_label ( _("Extend track end") );
2750 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_extend_track_end
), pass_along
);
2751 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2752 gtk_widget_show ( item
);
2754 item
= gtk_menu_item_new_with_label ( _("Extend using magic scissors") );
2755 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_extend_track_end_ms
), pass_along
);
2756 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2757 gtk_widget_show ( item
);
2759 #ifdef VIK_CONFIG_OPENSTREETMAP
2760 item
= gtk_menu_item_new_with_label ( _("Upload to OSM") );
2761 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(osm_traces_upload_track_cb
), pass_along
);
2762 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2763 gtk_widget_show ( item
);
2766 if ( is_valid_google_route ( l
, (gchar
*) sublayer
) )
2768 item
= gtk_menu_item_new_with_label ( _("View Google Directions") );
2769 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_track_google_route_webpage
), pass_along
);
2770 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2771 gtk_widget_show ( item
);
2774 item
= gtk_menu_item_new_with_label ( _("Use with filter") );
2775 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_track_use_with_filter
), pass_along
);
2776 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2777 gtk_widget_show ( item
);
2779 item
= a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l
)), vlp
,
2780 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp
)),
2781 g_hash_table_lookup ( l
->tracks
, (gchar
*) sublayer
) );
2783 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
2784 gtk_widget_show ( item
);
2788 if ( vlp
&& (subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
|| subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
) )
2790 item
= gtk_menu_item_new ();
2791 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2792 gtk_widget_show ( item
);
2794 item
= gtk_menu_item_new_with_label ( _("New Waypoint") );
2795 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wp
), pass_along
);
2796 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
2797 gtk_widget_show ( item
);
2804 /* to be called when last_tpl no long exists. */
2805 static void trw_layer_cancel_last_tp ( VikTrwLayer
*vtl
)
2807 if ( vtl
->tpwin
) /* can't join with a non-existant TP. */
2808 vik_trw_layer_tpwin_disable_join ( vtl
->tpwin
);
2809 vtl
->last_tpl
= NULL
;
2810 vtl
->last_tp_track_name
= NULL
;
2813 static void trw_layer_cancel_current_tp ( VikTrwLayer
*vtl
, gboolean destroy
)
2819 gtk_widget_destroy ( GTK_WIDGET(vtl
->tpwin
) );
2823 vik_trw_layer_tpwin_set_empty ( vtl
->tpwin
);
2825 if ( vtl
->current_tpl
)
2827 vtl
->current_tpl
= NULL
;
2828 vtl
->current_tp_track_name
= NULL
;
2829 vik_layer_emit_update(VIK_LAYER(vtl
));
2833 static void trw_layer_tpwin_response ( VikTrwLayer
*vtl
, gint response
)
2835 g_assert ( vtl
->tpwin
!= NULL
);
2836 if ( response
== VIK_TRW_LAYER_TPWIN_CLOSE
)
2837 trw_layer_cancel_current_tp ( vtl
, TRUE
);
2838 else if ( response
== VIK_TRW_LAYER_TPWIN_SPLIT
&& vtl
->current_tpl
->next
&& vtl
->current_tpl
->prev
)
2841 if ( ( name
= a_dialog_new_track ( GTK_WINDOW(vtl
->tpwin
), vtl
->tracks
) ) )
2843 VikTrack
*tr
= vik_track_new ();
2844 GList
*newglist
= g_list_alloc ();
2845 newglist
->prev
= NULL
;
2846 newglist
->next
= vtl
->current_tpl
->next
;
2847 newglist
->data
= vik_trackpoint_copy(VIK_TRACKPOINT(vtl
->current_tpl
->data
));
2848 tr
->trackpoints
= newglist
;
2850 vtl
->current_tpl
->next
->prev
= newglist
; /* end old track here */
2851 vtl
->current_tpl
->next
= NULL
;
2853 vtl
->current_tpl
= newglist
; /* change tp to first of new track. */
2854 vtl
->current_tp_track_name
= name
;
2856 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
2858 vik_trw_layer_add_track ( vtl
, name
, tr
);
2859 vik_layer_emit_update(VIK_LAYER(vtl
));
2862 else if ( response
== VIK_TRW_LAYER_TPWIN_DELETE
)
2864 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, vtl
->current_tp_track_name
);
2866 g_assert(tr
!= NULL
);
2868 /* can't join with a non-existent trackpoint */
2869 vtl
->last_tpl
= NULL
;
2870 vtl
->last_tp_track_name
= NULL
;
2872 if ( (new_tpl
= vtl
->current_tpl
->next
) || (new_tpl
= vtl
->current_tpl
->prev
) )
2874 if ( VIK_TRACKPOINT(vtl
->current_tpl
->data
)->newsegment
&& vtl
->current_tpl
->next
)
2875 VIK_TRACKPOINT(vtl
->current_tpl
->next
->data
)->newsegment
= TRUE
; /* don't concat segments on del */
2877 tr
->trackpoints
= g_list_remove_link ( tr
->trackpoints
, vtl
->current_tpl
); /* this nulls current_tpl->prev and next */
2879 /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
2880 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, new_tpl
, vtl
->current_tp_track_name
);
2882 trw_layer_cancel_last_tp ( vtl
);
2884 g_free ( vtl
->current_tpl
->data
); /* TODO: vik_trackpoint_free() */
2885 g_list_free_1 ( vtl
->current_tpl
);
2886 vtl
->current_tpl
= new_tpl
;
2887 vik_layer_emit_update(VIK_LAYER(vtl
));
2891 tr
->trackpoints
= g_list_remove_link ( tr
->trackpoints
, vtl
->current_tpl
);
2892 g_free ( vtl
->current_tpl
->data
); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
2893 g_list_free_1 ( vtl
->current_tpl
);
2894 trw_layer_cancel_current_tp ( vtl
, FALSE
);
2897 else if ( response
== VIK_TRW_LAYER_TPWIN_FORWARD
&& vtl
->current_tpl
->next
)
2899 vtl
->last_tpl
= vtl
->current_tpl
;
2900 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
= vtl
->current_tpl
->next
, vtl
->current_tp_track_name
);
2901 vik_layer_emit_update(VIK_LAYER(vtl
)); /* TODO longone: either move or only update if tp is inside drawing window */
2903 else if ( response
== VIK_TRW_LAYER_TPWIN_BACK
&& vtl
->current_tpl
->prev
)
2905 vtl
->last_tpl
= vtl
->current_tpl
;
2906 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
= vtl
->current_tpl
->prev
, vtl
->current_tp_track_name
);
2907 vik_layer_emit_update(VIK_LAYER(vtl
));
2909 else if ( response
== VIK_TRW_LAYER_TPWIN_JOIN
)
2911 VikTrack
*tr1
= g_hash_table_lookup ( vtl
->tracks
, vtl
->last_tp_track_name
);
2912 VikTrack
*tr2
= g_hash_table_lookup ( vtl
->tracks
, vtl
->current_tp_track_name
);
2914 VikTrack
*tr_first
= tr1
, *tr_last
= tr2
;
2918 if ( (!vtl
->last_tpl
->next
) && (!vtl
->current_tpl
->next
) ) /* both endpoints */
2919 vik_track_reverse ( tr2
); /* reverse the second, that way second track clicked will be later. */
2920 else if ( (!vtl
->last_tpl
->prev
) && (!vtl
->current_tpl
->prev
) )
2921 vik_track_reverse ( tr1
);
2922 else if ( (!vtl
->last_tpl
->prev
) && (!vtl
->current_tpl
->next
) ) /* clicked startpoint, then endpoint -- concat end to start */
2927 /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
2929 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. */
2930 VIK_TRACKPOINT(tr_last
->trackpoints
->data
)->newsegment
= FALSE
;
2931 tr1
->trackpoints
= g_list_concat ( tr_first
->trackpoints
, tr_last
->trackpoints
);
2932 tr2
->trackpoints
= NULL
;
2934 tmp
= vtl
->current_tp_track_name
;
2936 vtl
->current_tp_track_name
= vtl
->last_tp_track_name
; /* current_tp stays the same (believe it or not!) */
2937 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
2939 /* if we did this before, trw_layer_delete_track would have canceled the current tp because
2940 * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
2941 vik_trw_layer_delete_track ( vtl
, tmp
);
2943 trw_layer_cancel_last_tp ( vtl
); /* same TP, can't join. */
2944 vik_layer_emit_update(VIK_LAYER(vtl
));
2946 else if ( response
== VIK_TRW_LAYER_TPWIN_DATA_CHANGED
)
2947 vik_layer_emit_update (VIK_LAYER(vtl
));
2950 static void trw_layer_tpwin_init ( VikTrwLayer
*vtl
)
2954 vtl
->tpwin
= vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl
) );
2955 g_signal_connect_swapped ( GTK_DIALOG(vtl
->tpwin
), "response", G_CALLBACK(trw_layer_tpwin_response
), vtl
);
2956 /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
2957 g_signal_connect_swapped ( vtl
->tpwin
, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp
), vtl
);
2958 gtk_widget_show_all ( GTK_WIDGET(vtl
->tpwin
) );
2960 if ( vtl
->current_tpl
)
2961 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
2962 /* set layer name and TP data */
2965 /***************************************************************************
2967 ***************************************************************************/
2969 /*** Utility data structures and functions ****/
2973 gint closest_x
, closest_y
;
2974 gchar
*closest_wp_name
;
2975 VikWaypoint
*closest_wp
;
2981 gint closest_x
, closest_y
;
2982 gchar
*closest_track_name
;
2983 VikTrackpoint
*closest_tp
;
2988 static void waypoint_search_closest_tp ( gchar
*name
, VikWaypoint
*wp
, WPSearchParams
*params
)
2994 vik_viewport_coord_to_screen ( params
->vvp
, &(wp
->coord
), &x
, &y
);
2996 if ( abs (x
- params
->x
) <= WAYPOINT_SIZE_APPROX
&& abs (y
- params
->y
) <= WAYPOINT_SIZE_APPROX
&&
2997 ((!params
->closest_wp
) || /* was the old waypoint we already found closer than this one? */
2998 abs(x
- params
->x
)+abs(y
- params
->y
) < abs(x
- params
->closest_x
)+abs(y
- params
->closest_y
)))
3000 params
->closest_wp_name
= name
;
3001 params
->closest_wp
= wp
;
3002 params
->closest_x
= x
;
3003 params
->closest_y
= y
;
3007 static void track_search_closest_tp ( gchar
*name
, VikTrack
*t
, TPSearchParams
*params
)
3009 GList
*tpl
= t
->trackpoints
;
3018 tp
= VIK_TRACKPOINT(tpl
->data
);
3020 vik_viewport_coord_to_screen ( params
->vvp
, &(tp
->coord
), &x
, &y
);
3022 if ( abs (x
- params
->x
) <= TRACKPOINT_SIZE_APPROX
&& abs (y
- params
->y
) <= TRACKPOINT_SIZE_APPROX
&&
3023 ((!params
->closest_tp
) || /* was the old trackpoint we already found closer than this one? */
3024 abs(x
- params
->x
)+abs(y
- params
->y
) < abs(x
- params
->closest_x
)+abs(y
- params
->closest_y
)))
3026 params
->closest_track_name
= name
;
3027 params
->closest_tp
= tp
;
3028 params
->closest_tpl
= tpl
;
3029 params
->closest_x
= x
;
3030 params
->closest_y
= y
;
3036 static VikTrackpoint
*closest_tp_in_five_pixel_interval ( VikTrwLayer
*vtl
, VikViewport
*vvp
, gint x
, gint y
)
3038 TPSearchParams params
;
3042 params
.closest_track_name
= NULL
;
3043 params
.closest_tp
= NULL
;
3044 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) track_search_closest_tp
, ¶ms
);
3045 return params
.closest_tp
;
3048 static VikWaypoint
*closest_wp_in_five_pixel_interval ( VikTrwLayer
*vtl
, VikViewport
*vvp
, gint x
, gint y
)
3050 WPSearchParams params
;
3054 params
.closest_wp
= NULL
;
3055 params
.closest_wp_name
= NULL
;
3056 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) waypoint_search_closest_tp
, ¶ms
);
3057 return params
.closest_wp
;
3060 /* background drawing hook, to be passed the viewport */
3061 static gboolean tool_sync_done
= TRUE
;
3063 static gboolean
tool_sync(gpointer data
)
3065 VikViewport
*vvp
= data
;
3066 gdk_threads_enter();
3067 vik_viewport_sync(vvp
);
3068 tool_sync_done
= TRUE
;
3069 gdk_threads_leave();
3080 static void marker_begin_move ( tool_ed_t
*t
, gint x
, gint y
)
3083 t
->gc
= vik_viewport_new_gc (t
->vvp
, "black", 2);
3084 gdk_gc_set_function ( t
->gc
, GDK_INVERT
);
3085 vik_viewport_draw_rectangle ( t
->vvp
, t
->gc
, FALSE
, x
-3, y
-3, 6, 6 );
3086 vik_viewport_sync(t
->vvp
);
3091 static void marker_moveto ( tool_ed_t
*t
, gint x
, gint y
)
3093 VikViewport
*vvp
= t
->vvp
;
3094 vik_viewport_draw_rectangle ( vvp
, t
->gc
, FALSE
, t
->oldx
-3, t
->oldy
-3, 6, 6 );
3095 vik_viewport_draw_rectangle ( vvp
, t
->gc
, FALSE
, x
-3, y
-3, 6, 6 );
3099 if (tool_sync_done
) {
3100 g_idle_add_full (G_PRIORITY_HIGH_IDLE
+ 10, tool_sync
, vvp
, NULL
);
3101 tool_sync_done
= FALSE
;
3105 static void marker_end_move ( tool_ed_t
*t
)
3107 vik_viewport_draw_rectangle ( t
->vvp
, t
->gc
, FALSE
, t
->oldx
-3, t
->oldy
-3, 6, 6 );
3108 g_object_unref ( t
->gc
);
3112 /*** Edit waypoint ****/
3114 static gpointer
tool_edit_waypoint_create ( VikWindow
*vw
, VikViewport
*vvp
)
3116 tool_ed_t
*t
= g_new(tool_ed_t
, 1);
3122 static gboolean
tool_edit_waypoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3124 WPSearchParams params
;
3125 tool_ed_t
*t
= data
;
3126 VikViewport
*vvp
= t
->vvp
;
3128 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3135 if ( vtl
->current_wp
&& vtl
->current_wp
->visible
)
3137 /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
3139 vik_viewport_coord_to_screen ( vvp
, &(vtl
->current_wp
->coord
), &x
, &y
);
3141 if ( abs(x
- event
->x
) <= WAYPOINT_SIZE_APPROX
&&
3142 abs(y
- event
->y
) <= WAYPOINT_SIZE_APPROX
)
3144 if ( event
->button
== 3 )
3145 vtl
->waypoint_rightclick
= TRUE
; /* remember that we're clicking; other layers will ignore release signal */
3147 marker_begin_move(t
, event
->x
, event
->y
);
3154 params
.x
= event
->x
;
3155 params
.y
= event
->y
;
3156 params
.closest_wp_name
= NULL
;
3157 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
3158 params
.closest_wp
= NULL
;
3159 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) waypoint_search_closest_tp
, ¶ms
);
3160 if ( vtl
->current_wp
== params
.closest_wp
&& vtl
->current_wp
!= NULL
)
3162 /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
3163 marker_begin_move(t
, event
->x
, event
->y
);
3164 g_critical("shouldn't be here");
3167 else if ( params
.closest_wp
)
3169 if ( event
->button
== 3 )
3170 vtl
->waypoint_rightclick
= TRUE
; /* remember that we're clicking; other layers will ignore release signal */
3172 vtl
->waypoint_rightclick
= FALSE
;
3174 vtl
->current_wp
= params
.closest_wp
;
3175 vtl
->current_wp_name
= params
.closest_wp_name
;
3177 if ( params
.closest_wp
)
3178 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, g_hash_table_lookup ( vtl
->waypoints_iters
, vtl
->current_wp_name
) );
3180 /* could make it so don't update if old WP is off screen and new is null but oh well */
3181 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3185 vtl
->current_wp
= NULL
;
3186 vtl
->current_wp_name
= NULL
;
3187 vtl
->waypoint_rightclick
= FALSE
;
3188 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3192 static gboolean
tool_edit_waypoint_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, gpointer data
)
3194 tool_ed_t
*t
= data
;
3195 VikViewport
*vvp
= t
->vvp
;
3197 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3202 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3205 if ( event
->state
& GDK_CONTROL_MASK
)
3207 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3209 new_coord
= tp
->coord
;
3213 if ( event
->state
& GDK_SHIFT_MASK
)
3215 VikWaypoint
*wp
= closest_wp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3216 if ( wp
&& wp
!= vtl
->current_wp
)
3217 new_coord
= wp
->coord
;
3222 vik_viewport_coord_to_screen ( vvp
, &new_coord
, &x
, &y
);
3224 marker_moveto ( t
, x
, y
);
3231 static gboolean
tool_edit_waypoint_release ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3233 tool_ed_t
*t
= data
;
3234 VikViewport
*vvp
= t
->vvp
;
3236 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3239 if ( t
->holding
&& event
->button
== 1 )
3242 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3245 if ( event
->state
& GDK_CONTROL_MASK
)
3247 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3249 new_coord
= tp
->coord
;
3253 if ( event
->state
& GDK_SHIFT_MASK
)
3255 VikWaypoint
*wp
= closest_wp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3256 if ( wp
&& wp
!= vtl
->current_wp
)
3257 new_coord
= wp
->coord
;
3260 marker_end_move ( t
);
3262 vtl
->current_wp
->coord
= new_coord
;
3263 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3266 /* PUT IN RIGHT PLACE!!! */
3267 if ( event
->button
== 3 && vtl
->waypoint_rightclick
)
3269 if ( vtl
->wp_right_click_menu
)
3270 gtk_object_sink ( GTK_OBJECT(vtl
->wp_right_click_menu
) );
3271 vtl
->wp_right_click_menu
= GTK_MENU ( gtk_menu_new () );
3272 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
) );
3273 gtk_menu_popup ( vtl
->wp_right_click_menu
, NULL
, NULL
, NULL
, NULL
, event
->button
, gtk_get_current_event_time() );
3274 vtl
->waypoint_rightclick
= FALSE
;
3279 /**** Begin track ***/
3280 static gpointer
tool_begin_track_create ( VikWindow
*vw
, VikViewport
*vvp
)
3285 static gboolean
tool_begin_track_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3287 vtl
->current_track
= NULL
;
3288 return tool_new_track_click ( vtl
, event
, vvp
);
3291 /*** New track ****/
3293 static gpointer
tool_new_track_create ( VikWindow
*vw
, VikViewport
*vvp
)
3302 } new_track_move_passalong_t
;
3304 /* sync and undraw, but only when we have time */
3305 static gboolean
ct_sync ( gpointer passalong
)
3307 new_track_move_passalong_t
*p
= (new_track_move_passalong_t
*) passalong
;
3308 vik_viewport_sync ( p
->vvp
);
3309 gdk_gc_set_function ( p
->vtl
->current_track_gc
, GDK_INVERT
);
3310 vik_viewport_draw_line ( p
->vvp
, p
->vtl
->current_track_gc
, p
->x1
, p
->y1
, p
->x2
, p
->y2
);
3311 gdk_gc_set_function ( p
->vtl
->current_track_gc
, GDK_COPY
);
3312 p
->vtl
->ct_sync_done
= TRUE
;
3317 static VikLayerToolFuncStatus
tool_new_track_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, VikViewport
*vvp
)
3319 /* if we haven't sync'ed yet, we don't have time to do more. */
3320 if ( vtl
->ct_sync_done
&& vtl
->current_track
&& vtl
->current_track
->trackpoints
) {
3321 GList
*iter
= vtl
->current_track
->trackpoints
;
3322 new_track_move_passalong_t
*passalong
;
3325 while ( iter
->next
)
3327 gdk_gc_set_function ( vtl
->current_track_gc
, GDK_INVERT
);
3328 vik_viewport_coord_to_screen ( vvp
, &(VIK_TRACKPOINT(iter
->data
)->coord
), &x1
, &y1
);
3329 vik_viewport_draw_line ( vvp
, vtl
->current_track_gc
, x1
, y1
, event
->x
, event
->y
);
3330 gdk_gc_set_function ( vtl
->current_track_gc
, GDK_COPY
);
3332 passalong
= g_new(new_track_move_passalong_t
,1); /* freed by sync */
3333 passalong
->vtl
= vtl
;
3334 passalong
->vvp
= vvp
;
3337 passalong
->x2
= event
->x
;
3338 passalong
->y2
= event
->y
;
3340 /* this will sync and undraw when we have time to */
3341 g_idle_add_full (G_PRIORITY_HIGH_IDLE
+ 10, ct_sync
, passalong
, NULL
);
3342 vtl
->ct_sync_done
= FALSE
;
3343 return VIK_LAYER_TOOL_ACK_GRAB_FOCUS
;
3345 return VIK_LAYER_TOOL_ACK
;
3348 static gboolean
tool_new_track_key_press ( VikTrwLayer
*vtl
, GdkEventKey
*event
, VikViewport
*vvp
)
3350 if ( vtl
->current_track
&& event
->keyval
== GDK_Escape
) {
3351 vtl
->current_track
= NULL
;
3352 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3354 } else if ( vtl
->current_track
&& event
->keyval
== GDK_BackSpace
) {
3356 if ( vtl
->current_track
->trackpoints
)
3358 GList
*last
= g_list_last(vtl
->current_track
->trackpoints
);
3359 g_free ( last
->data
);
3360 vtl
->current_track
->trackpoints
= g_list_remove_link ( vtl
->current_track
->trackpoints
, last
);
3362 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3368 static gboolean
tool_new_track_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3372 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3375 if ( event
->button
== 3 && vtl
->current_track
)
3378 if ( vtl
->current_track
->trackpoints
)
3380 GList
*last
= g_list_last(vtl
->current_track
->trackpoints
);
3381 g_free ( last
->data
);
3382 vtl
->current_track
->trackpoints
= g_list_remove_link ( vtl
->current_track
->trackpoints
, last
);
3384 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3388 if ( event
->type
== GDK_2BUTTON_PRESS
)
3390 /* subtract last (duplicate from double click) tp then end */
3391 if ( vtl
->current_track
&& vtl
->current_track
->trackpoints
&& vtl
->ct_x1
== vtl
->ct_x2
&& vtl
->ct_y1
== vtl
->ct_y2
)
3393 GList
*last
= g_list_last(vtl
->current_track
->trackpoints
);
3394 g_free ( last
->data
);
3395 vtl
->current_track
->trackpoints
= g_list_remove_link ( vtl
->current_track
->trackpoints
, last
);
3396 /* undo last, then end */
3397 vtl
->current_track
= NULL
;
3399 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3403 if ( ! vtl
->current_track
)
3406 if ( ( name
= a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), vtl
->tracks
) ) )
3408 vtl
->current_track
= vik_track_new();
3409 vtl
->current_track
->visible
= TRUE
;
3410 vik_trw_layer_add_track ( vtl
, name
, vtl
->current_track
);
3412 /* incase it was created by begin track */
3413 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), VIK_LAYER_TRW
, TOOL_CREATE_TRACK
);
3418 tp
= vik_trackpoint_new();
3419 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &(tp
->coord
) );
3421 /* snap to other TP */
3422 if ( event
->state
& GDK_CONTROL_MASK
)
3424 VikTrackpoint
*other_tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3426 tp
->coord
= other_tp
->coord
;
3429 tp
->newsegment
= FALSE
;
3430 tp
->has_timestamp
= FALSE
;
3432 vtl
->current_track
->trackpoints
= g_list_append ( vtl
->current_track
->trackpoints
, tp
);
3434 vtl
->ct_x1
= vtl
->ct_x2
;
3435 vtl
->ct_y1
= vtl
->ct_y2
;
3436 vtl
->ct_x2
= event
->x
;
3437 vtl
->ct_y2
= event
->y
;
3439 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3444 /*** New waypoint ****/
3446 static gpointer
tool_new_waypoint_create ( VikWindow
*vw
, VikViewport
*vvp
)
3451 static gboolean
tool_new_waypoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3454 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3456 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &coord
);
3457 if (vik_trw_layer_new_waypoint ( vtl
, VIK_GTK_WINDOW_FROM_LAYER(vtl
), &coord
) && VIK_LAYER(vtl
)->visible
)
3458 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3463 /*** Edit trackpoint ****/
3465 static gpointer
tool_edit_trackpoint_create ( VikWindow
*vw
, VikViewport
*vvp
)
3467 tool_ed_t
*t
= g_new(tool_ed_t
, 1);
3473 static gboolean
tool_edit_trackpoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3475 tool_ed_t
*t
= data
;
3476 VikViewport
*vvp
= t
->vvp
;
3477 TPSearchParams params
;
3478 /* OUTDATED DOCUMENTATION:
3479 find 5 pixel range on each side. then put these UTM, and a pointer
3480 to the winning track name (and maybe the winning track itself), and a
3481 pointer to the winning trackpoint, inside an array or struct. pass
3482 this along, do a foreach on the tracks which will do a foreach on the
3485 params
.x
= event
->x
;
3486 params
.y
= event
->y
;
3487 params
.closest_track_name
= NULL
;
3488 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
3489 params
.closest_tp
= NULL
;
3491 if ( event
->button
!= 1 )
3494 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3497 if ( vtl
->current_tpl
)
3499 /* 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.) */
3500 VikTrackpoint
*tp
= VIK_TRACKPOINT(vtl
->current_tpl
->data
);
3501 VikTrack
*current_tr
= VIK_TRACK(g_hash_table_lookup(vtl
->tracks
, vtl
->current_tp_track_name
));
3503 g_assert ( current_tr
);
3505 vik_viewport_coord_to_screen ( vvp
, &(tp
->coord
), &x
, &y
);
3507 if ( current_tr
->visible
&&
3508 abs(x
- event
->x
) < TRACKPOINT_SIZE_APPROX
&&
3509 abs(y
- event
->y
) < TRACKPOINT_SIZE_APPROX
) {
3510 marker_begin_move ( t
, event
->x
, event
->y
);
3514 vtl
->last_tpl
= vtl
->current_tpl
;
3515 vtl
->last_tp_track_name
= vtl
->current_tp_track_name
;
3518 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) track_search_closest_tp
, ¶ms
);
3520 if ( params
.closest_tp
)
3522 vtl
->current_tpl
= params
.closest_tpl
;
3523 vtl
->current_tp_track_name
= params
.closest_track_name
;
3524 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, g_hash_table_lookup ( vtl
->tracks_iters
, vtl
->current_tp_track_name
) );
3525 trw_layer_tpwin_init ( vtl
);
3526 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3530 /* these aren't the droids you're looking for */
3534 static gboolean
tool_edit_trackpoint_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, gpointer data
)
3536 tool_ed_t
*t
= data
;
3537 VikViewport
*vvp
= t
->vvp
;
3539 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3545 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3548 if ( event
->state
& GDK_CONTROL_MASK
)
3550 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3551 if ( tp
&& tp
!= vtl
->current_tpl
->data
)
3552 new_coord
= tp
->coord
;
3554 // VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
3557 vik_viewport_coord_to_screen ( vvp
, &new_coord
, &x
, &y
);
3558 marker_moveto ( t
, x
, y
);
3566 static gboolean
tool_edit_trackpoint_release ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3568 tool_ed_t
*t
= data
;
3569 VikViewport
*vvp
= t
->vvp
;
3571 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3573 if ( event
->button
!= 1)
3578 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3581 if ( event
->state
& GDK_CONTROL_MASK
)
3583 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3584 if ( tp
&& tp
!= vtl
->current_tpl
->data
)
3585 new_coord
= tp
->coord
;
3588 VIK_TRACKPOINT(vtl
->current_tpl
->data
)->coord
= new_coord
;
3590 marker_end_move ( t
);
3592 /* diff dist is diff from orig */
3593 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
3594 /* can't join with itself! */
3595 trw_layer_cancel_last_tp ( vtl
);
3597 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3604 /*** Magic Scissors ***/
3605 static gpointer
tool_magic_scissors_create ( VikWindow
*vw
, VikViewport
*vvp
)
3610 static gboolean
tool_magic_scissors_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3613 if ( !vtl
) return FALSE
;
3614 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &tmp
);
3615 if ( event
->button
== 3 && vtl
->magic_scissors_current_track
) {
3617 new_end
= vik_track_cut_back_to_double_point ( vtl
->magic_scissors_current_track
);
3619 vtl
->magic_scissors_coord
= *new_end
;
3621 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3622 /* remove last ' to:...' */
3623 if ( vtl
->magic_scissors_current_track
->comment
) {
3624 gchar
*last_to
= strrchr ( vtl
->magic_scissors_current_track
->comment
, 't' );
3625 if ( last_to
&& (last_to
- vtl
->magic_scissors_current_track
->comment
> 1) ) {
3626 gchar
*new_comment
= g_strndup ( vtl
->magic_scissors_current_track
->comment
,
3627 last_to
- vtl
->magic_scissors_current_track
->comment
- 1);
3628 vik_track_set_comment_no_copy ( vtl
->magic_scissors_current_track
, new_comment
);
3633 else if ( vtl
->magic_scissors_started
|| (event
->state
& GDK_CONTROL_MASK
&& vtl
->magic_scissors_current_track
) ) {
3634 struct LatLon start
, end
;
3635 gchar startlat
[G_ASCII_DTOSTR_BUF_SIZE
], startlon
[G_ASCII_DTOSTR_BUF_SIZE
];
3636 gchar endlat
[G_ASCII_DTOSTR_BUF_SIZE
], endlon
[G_ASCII_DTOSTR_BUF_SIZE
];
3639 vik_coord_to_latlon ( &(vtl
->magic_scissors_coord
), &start
);
3640 vik_coord_to_latlon ( &(tmp
), &end
);
3641 vtl
->magic_scissors_coord
= tmp
; /* for continuations */
3643 /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
3644 if ( event
->state
& GDK_CONTROL_MASK
&& vtl
->magic_scissors_current_track
) {
3645 vtl
->magic_scissors_append
= TRUE
; // merge tracks. keep started true.
3647 vtl
->magic_scissors_check_added_track
= TRUE
;
3648 vtl
->magic_scissors_started
= FALSE
;
3651 url
= g_strdup_printf(GOOGLE_DIRECTIONS_STRING
,
3652 g_ascii_dtostr (startlat
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) start
.lat
),
3653 g_ascii_dtostr (startlon
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) start
.lon
),
3654 g_ascii_dtostr (endlat
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) end
.lat
),
3655 g_ascii_dtostr (endlon
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) end
.lon
));
3656 a_babel_convert_from_url ( vtl
, url
, "google", NULL
, NULL
);
3659 /* see if anything was done -- a track was added or appended to */
3660 if ( vtl
->magic_scissors_check_added_track
&& vtl
->magic_scissors_added_track_name
) {
3663 tr
= g_hash_table_lookup ( vtl
->tracks
, vtl
->magic_scissors_added_track_name
);
3666 vik_track_set_comment_no_copy ( tr
, g_strdup_printf("from: %f,%f to: %f%f", start
.lat
, start
.lon
, end
.lat
, end
.lon
) );
3668 vtl
->magic_scissors_current_track
= tr
;
3670 g_free ( vtl
->magic_scissors_added_track_name
);
3671 vtl
->magic_scissors_added_track_name
= NULL
;
3672 } else if ( vtl
->magic_scissors_append
== FALSE
&& vtl
->magic_scissors_current_track
) {
3673 /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
3674 gchar
*new_comment
= g_strdup_printf("%s to: %f,%f", vtl
->magic_scissors_current_track
->comment
, end
.lat
, end
.lon
);
3675 vik_track_set_comment_no_copy ( vtl
->magic_scissors_current_track
, new_comment
);
3677 vtl
->magic_scissors_check_added_track
= FALSE
;
3678 vtl
->magic_scissors_append
= FALSE
;
3680 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3682 vtl
->magic_scissors_started
= TRUE
;
3683 vtl
->magic_scissors_coord
= tmp
;
3684 vtl
->magic_scissors_current_track
= NULL
;
3689 /*** Show picture ****/
3691 static gpointer
tool_show_picture_create ( VikWindow
*vw
, VikViewport
*vvp
)
3696 /* Params are: vvp, event, last match found or NULL */
3697 static void tool_show_picture_wp ( char *name
, VikWaypoint
*wp
, gpointer params
[2] )
3699 if ( wp
->image
&& wp
->visible
)
3701 gint x
, y
, slackx
, slacky
;
3702 GdkEventButton
*event
= (GdkEventButton
*) params
[1];
3704 vik_viewport_coord_to_screen ( VIK_VIEWPORT(params
[0]), &(wp
->coord
), &x
, &y
);
3705 slackx
= wp
->image_width
/ 2;
3706 slacky
= wp
->image_height
/ 2;
3707 if ( x
<= event
->x
+ slackx
&& x
>= event
->x
- slackx
3708 && y
<= event
->y
+ slacky
&& y
>= event
->y
- slacky
)
3710 params
[2] = wp
->image
; /* we've found a match. however continue searching
3711 * since we want to find the last match -- that
3712 * is, the match that was drawn last. */
3717 static gboolean
tool_show_picture_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3719 gpointer params
[3] = { vvp
, event
, NULL
};
3720 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3722 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) tool_show_picture_wp
, params
);
3725 /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
3727 ShellExecute(NULL
, NULL
, (char *) params
[2], NULL
, ".\\", 0);
3730 gchar
*quoted_file
= g_shell_quote ( (gchar
*) params
[2] );
3731 gchar
*cmd
= g_strdup_printf ( "eog %s", quoted_file
);
3732 g_free ( quoted_file
);
3733 if ( ! g_spawn_command_line_async ( cmd
, &err
) )
3735 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), _("Could not launch eog to open file.") );
3736 g_error_free ( err
);
3739 #endif /* WINDOWS */
3740 return TRUE
; /* found a match */
3743 return FALSE
; /* go through other layers, searching for a match */
3746 /***************************************************************************
3748 ***************************************************************************/
3754 static void image_wp_make_list ( char *name
, VikWaypoint
*wp
, GSList
**pics
)
3756 if ( wp
->image
&& ( ! a_thumbnails_exists ( wp
->image
) ) )
3757 *pics
= g_slist_append ( *pics
, (gpointer
) g_strdup ( wp
->image
) );
3760 static void create_thumbnails_thread ( GSList
*pics
, gpointer threaddata
)
3762 guint total
= g_slist_length(pics
), done
= 0;
3765 a_thumbnails_create ( (gchar
*) pics
->data
);
3766 a_background_thread_progress ( threaddata
, ((gdouble
) ++done
) / total
);
3771 static void free_pics_slist ( GSList
*pics
)
3775 g_free ( pics
->data
);
3776 pics
= g_slist_delete_link ( pics
, pics
);
3780 static void trw_layer_verify_thumbnails ( VikTrwLayer
*vtl
, GtkWidget
*vp
)
3782 if ( ! vtl
->has_verified_thumbnails
)
3784 GSList
*pics
= NULL
;
3785 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) image_wp_make_list
, &pics
);
3788 gint len
= g_slist_length ( pics
);
3789 gchar
*tmp
= g_strdup_printf ( _("Creating %d Image Thumbnails..."), len
);
3790 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
);
3796 VikCoordMode
vik_trw_layer_get_coord_mode ( VikTrwLayer
*vtl
)
3798 return vtl
->coord_mode
;
3803 static void waypoint_convert ( const gchar
*name
, VikWaypoint
*wp
, VikCoordMode
*dest_mode
)
3805 vik_coord_convert ( &(wp
->coord
), *dest_mode
);
3808 static void track_convert ( const gchar
*name
, VikTrack
*tr
, VikCoordMode
*dest_mode
)
3810 vik_track_convert ( tr
, *dest_mode
);
3813 static void trw_layer_change_coord_mode ( VikTrwLayer
*vtl
, VikCoordMode dest_mode
)
3815 if ( vtl
->coord_mode
!= dest_mode
)
3817 vtl
->coord_mode
= dest_mode
;
3818 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) waypoint_convert
, &dest_mode
);
3819 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) track_convert
, &dest_mode
);
3823 VikWaypoint
*vik_trw_layer_get_waypoint ( VikTrwLayer
*vtl
, gchar
*name
)
3825 return g_hash_table_lookup ( vtl
->waypoints
, name
);
3828 VikTrack
*vik_trw_layer_get_track ( VikTrwLayer
*vtl
, gchar
*name
)
3830 return g_hash_table_lookup ( vtl
->tracks
, name
);
3833 static void vik_trw_layer_set_menu_selection(VikTrwLayer
*vtl
, guint16 selection
)
3835 vtl
->menu_selection
= selection
;
3838 static guint16
vik_trw_layer_get_menu_selection(VikTrwLayer
*vtl
)
3840 return(vtl
->menu_selection
);
3843 /* ----------- Downloading maps along tracks --------------- */
3845 static int get_download_area_width(VikViewport
*vvp
, gdouble zoom_level
, struct LatLon
*wh
)
3847 /* TODO: calculating based on current size of viewport */
3848 const gdouble w_at_zoom_0_125
= 0.0013;
3849 const gdouble h_at_zoom_0_125
= 0.0011;
3850 gdouble zoom_factor
= zoom_level
/0.125;
3852 wh
->lat
= h_at_zoom_0_125
* zoom_factor
;
3853 wh
->lon
= w_at_zoom_0_125
* zoom_factor
;
3855 return 0; /* all OK */
3858 static VikCoord
*get_next_coord(VikCoord
*from
, VikCoord
*to
, struct LatLon
*dist
, gdouble gradient
)
3860 if ((dist
->lon
>= ABS(to
->east_west
- from
->east_west
)) &&
3861 (dist
->lat
>= ABS(to
->north_south
- from
->north_south
)))
3864 VikCoord
*coord
= g_malloc(sizeof(VikCoord
));
3865 coord
->mode
= VIK_COORD_LATLON
;
3867 if (ABS(gradient
) < 1) {
3868 if (from
->east_west
> to
->east_west
)
3869 coord
->east_west
= from
->east_west
- dist
->lon
;
3871 coord
->east_west
= from
->east_west
+ dist
->lon
;
3872 coord
->north_south
= gradient
* (coord
->east_west
- from
->east_west
) + from
->north_south
;
3874 if (from
->north_south
> to
->north_south
)
3875 coord
->north_south
= from
->north_south
- dist
->lat
;
3877 coord
->north_south
= from
->north_south
+ dist
->lat
;
3878 coord
->east_west
= (1/gradient
) * (coord
->north_south
- from
->north_south
) + from
->north_south
;
3884 static GList
*add_fillins(GList
*list
, VikCoord
*from
, VikCoord
*to
, struct LatLon
*dist
)
3886 /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
3887 gdouble gradient
= (to
->north_south
- from
->north_south
)/(to
->east_west
- from
->east_west
);
3889 VikCoord
*next
= from
;
3891 if ((next
= get_next_coord(next
, to
, dist
, gradient
)) == NULL
)
3893 list
= g_list_prepend(list
, next
);
3899 void vik_track_download_map(VikTrack
*tr
, VikMapsLayer
*vml
, VikViewport
*vvp
, gdouble zoom_level
)
3901 typedef struct _Rect
{
3906 #define GLRECT(iter) ((Rect *)((iter)->data))
3909 GList
*rects_to_download
= NULL
;
3912 if (get_download_area_width(vvp
, zoom_level
, &wh
))
3915 GList
*iter
= tr
->trackpoints
;
3919 gboolean new_map
= TRUE
;
3920 VikCoord
*cur_coord
, tl
, br
;
3923 cur_coord
= &(VIK_TRACKPOINT(iter
->data
))->coord
;
3925 vik_coord_set_area(cur_coord
, &wh
, &tl
, &br
);
3926 rect
= g_malloc(sizeof(Rect
));
3929 rect
->center
= *cur_coord
;
3930 rects_to_download
= g_list_prepend(rects_to_download
, rect
);
3935 gboolean found
= FALSE
;
3936 for (rect_iter
= rects_to_download
; rect_iter
; rect_iter
= rect_iter
->next
) {
3937 if (vik_coord_inside(cur_coord
, &GLRECT(rect_iter
)->tl
, &GLRECT(rect_iter
)->br
)) {
3948 /* fill-ins for far apart points */
3949 GList
*cur_rect
, *next_rect
;
3950 GList
*fillins
= NULL
;
3951 for (cur_rect
= rects_to_download
;
3952 (next_rect
= cur_rect
->next
) != NULL
;
3953 cur_rect
= cur_rect
->next
) {
3954 if ((wh
.lon
< ABS(GLRECT(cur_rect
)->center
.east_west
- GLRECT(next_rect
)->center
.east_west
)) ||
3955 (wh
.lat
< ABS(GLRECT(cur_rect
)->center
.north_south
- GLRECT(next_rect
)->center
.north_south
))) {
3956 fillins
= add_fillins(fillins
, &GLRECT(cur_rect
)->center
, &GLRECT(next_rect
)->center
, &wh
);
3961 GList
*iter
= fillins
;
3963 cur_coord
= (VikCoord
*)(iter
->data
);
3964 vik_coord_set_area(cur_coord
, &wh
, &tl
, &br
);
3965 rect
= g_malloc(sizeof(Rect
));
3968 rect
->center
= *cur_coord
;
3969 rects_to_download
= g_list_prepend(rects_to_download
, rect
);
3974 for (rect_iter
= rects_to_download
; rect_iter
; rect_iter
= rect_iter
->next
) {
3975 maps_layer_download_section_without_redraw(vml
, vvp
, &(((Rect
*)(rect_iter
->data
))->tl
), &(((Rect
*)(rect_iter
->data
))->br
), zoom_level
);
3979 for (iter
= fillins
; iter
; iter
= iter
->next
)
3981 g_list_free(fillins
);
3983 if (rects_to_download
) {
3984 for (rect_iter
= rects_to_download
; rect_iter
; rect_iter
= rect_iter
->next
)
3985 g_free(rect_iter
->data
);
3986 g_list_free(rects_to_download
);
3990 static void trw_layer_download_map_along_track_cb(gpointer pass_along
[6])
3993 gint selected_map
, default_map
;
3994 gchar
*zoomlist
[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL
};
3995 gdouble zoom_vals
[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
3996 gint selected_zoom
, default_zoom
;
4000 VikTrwLayer
*vtl
= pass_along
[0];
4001 VikLayersPanel
*vlp
= pass_along
[1];
4002 VikTrack
*tr
= (VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
4003 VikViewport
*vvp
= vik_window_viewport((VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
)));
4005 GList
*vmls
= vik_layers_panel_get_all_layers_of_type(vlp
, VIK_LAYER_MAPS
);
4006 int num_maps
= g_list_length(vmls
);
4009 a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl
), GTK_MESSAGE_ERROR
, _("No map layer in use. Create one first"), NULL
);
4013 gchar
**map_names
= g_malloc(1 + num_maps
* sizeof(gpointer
));
4014 VikMapsLayer
**map_layers
= g_malloc(1 + num_maps
* sizeof(gpointer
));
4016 gchar
**np
= map_names
;
4017 VikMapsLayer
**lp
= map_layers
;
4018 for (i
= 0; i
< num_maps
; i
++) {
4019 gboolean dup
= FALSE
;
4020 vml
= (VikMapsLayer
*)(vmls
->data
);
4021 for (j
= 0; j
< i
; j
++) { /* no duplicate allowed */
4022 if (vik_maps_layer_get_map_type(vml
) == vik_maps_layer_get_map_type(map_layers
[j
])) {
4029 *np
++ = vik_maps_layer_get_map_label(vml
);
4035 num_maps
= lp
- map_layers
;
4037 for (default_map
= 0; default_map
< num_maps
; default_map
++) {
4038 /* TODO: check for parent layer's visibility */
4039 if (VIK_LAYER(map_layers
[default_map
])->visible
)
4042 default_map
= (default_map
== num_maps
) ? 0 : default_map
;
4044 gdouble cur_zoom
= vik_viewport_get_zoom(vvp
);
4045 for (default_zoom
= 0; default_zoom
< sizeof(zoom_vals
)/sizeof(gdouble
); default_zoom
++) {
4046 if (cur_zoom
== zoom_vals
[default_zoom
])
4049 default_zoom
= (default_zoom
== sizeof(zoom_vals
)/sizeof(gdouble
)) ? sizeof(zoom_vals
)/sizeof(gdouble
) - 1 : default_zoom
;
4051 if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl
), map_names
, default_map
, zoomlist
, default_zoom
, &selected_map
, &selected_zoom
))
4054 vik_track_download_map(tr
, map_layers
[selected_map
], vvp
, zoom_vals
[selected_zoom
]);
4057 for (i
= 0; i
< num_maps
; i
++)
4058 g_free(map_names
[i
]);
4066 /**** lowest waypoint number calculation ***/
4067 static gint
highest_wp_number_name_to_number(const gchar
*name
) {
4068 if ( strlen(name
) == 3 ) {
4070 if ( n
< 100 && name
[0] != '0' )
4072 if ( n
< 10 && name
[0] != '0' )
4080 static void highest_wp_number_reset(VikTrwLayer
*vtl
)
4082 vtl
->highest_wp_number
= -1;
4085 static void highest_wp_number_add_wp(VikTrwLayer
*vtl
, const gchar
*new_wp_name
)
4087 /* if is bigger that top, add it */
4088 gint new_wp_num
= highest_wp_number_name_to_number(new_wp_name
);
4089 if ( new_wp_num
> vtl
->highest_wp_number
)
4090 vtl
->highest_wp_number
= new_wp_num
;
4093 static void highest_wp_number_remove_wp(VikTrwLayer
*vtl
, const gchar
*old_wp_name
)
4095 /* if wasn't top, do nothing. if was top, count backwards until we find one used */
4096 gint old_wp_num
= highest_wp_number_name_to_number(old_wp_name
);
4097 if ( vtl
->highest_wp_number
== old_wp_num
) {
4099 vtl
->highest_wp_number
--;
4101 g_snprintf(buf
,4,"%03d", vtl
->highest_wp_number
);
4102 /* search down until we find something that *does* exist */
4104 while ( vtl
->highest_wp_number
> 0 && ! g_hash_table_lookup ( vtl
->waypoints
, buf
) ) {
4105 vtl
->highest_wp_number
--;
4106 g_snprintf(buf
,4,"%03d", vtl
->highest_wp_number
);
4111 /* get lowest unused number */
4112 static gchar
*highest_wp_number_get(VikTrwLayer
*vtl
)
4115 if ( vtl
->highest_wp_number
< 0 || vtl
->highest_wp_number
>= 999 )
4117 g_snprintf(buf
,4,"%03d", vtl
->highest_wp_number
+1 );
4118 return g_strdup(buf
);