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=kml"
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( guint8
*data
, gint len
, VikViewport
*vvp
);
251 static gboolean
trw_layer_set_param ( VikTrwLayer
*vtl
, guint16 id
, VikLayerParamData data
, VikViewport
*vp
, gboolean is_file_operation
);
252 static VikLayerParamData
trw_layer_get_param ( VikTrwLayer
*vtl
, guint16 id
, gboolean is_file_operation
);
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
, gboolean is_file_operation
)
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
, gboolean is_file_operation
)
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
)
687 if ((f
= fdopen(g_file_open_tmp (NULL
, &tmpname
, NULL
), "r+"))) {
688 a_gpx_write_file(vtl
, f
);
689 vik_layer_marshall_params(VIK_LAYER(vtl
), &pd
, &pl
);
692 g_file_get_contents(tmpname
, &dd
, &dl
, NULL
);
693 *len
= sizeof(pl
) + pl
+ dl
;
694 *data
= g_malloc(*len
);
695 memcpy(*data
, &pl
, sizeof(pl
));
696 memcpy(*data
+ sizeof(pl
), pd
, pl
);
697 memcpy(*data
+ sizeof(pl
) + pl
, dd
, dl
);
706 static VikTrwLayer
*trw_layer_unmarshall( guint8
*data
, gint len
, VikViewport
*vvp
)
708 VikTrwLayer
*rv
= VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW
, vvp
, NULL
, FALSE
));
714 memcpy(&pl
, data
, sizeof(pl
));
716 vik_layer_unmarshall_params ( VIK_LAYER(rv
), data
, pl
, vvp
);
719 if (!(f
= fdopen(g_file_open_tmp (NULL
, &tmpname
, NULL
), "r+"))) {
720 g_critical("couldn't open temp file");
723 fwrite(data
, len
- pl
- sizeof(pl
), 1, f
);
725 a_gpx_read_file(rv
, f
);
733 static GList
* str_array_to_glist(gchar
* data
[])
737 for (p
= (gpointer
)data
; *p
; p
++)
738 gl
= g_list_prepend(gl
, *p
);
739 return(g_list_reverse(gl
));
742 static gboolean
strcase_equal(gconstpointer s1
, gconstpointer s2
)
744 return (strcasecmp(s1
, s2
) == 0);
747 static guint
strcase_hash(gconstpointer v
)
749 /* 31 bit hash function */
752 gchar s
[128]; /* malloc is too slow for reading big files */
755 for (i
= 0; (i
< (sizeof(s
)- 1)) && t
[i
]; i
++)
756 p
[i
] = toupper(t
[i
]);
762 for (p
+= 1; *p
!= '\0'; p
++)
763 h
= (h
<< 5) - h
+ *p
;
769 VikTrwLayer
*vik_trw_layer_new ( gint drawmode
)
771 if (trw_layer_params
[PARAM_DM
].widget_data
== NULL
)
772 trw_layer_params
[PARAM_DM
].widget_data
= str_array_to_glist(params_drawmodes
);
773 if (trw_layer_params
[PARAM_WPSYM
].widget_data
== NULL
)
774 trw_layer_params
[PARAM_WPSYM
].widget_data
= str_array_to_glist(params_wpsymbols
);
776 VikTrwLayer
*rv
= VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE
, NULL
) );
777 vik_layer_init ( VIK_LAYER(rv
), VIK_LAYER_TRW
);
779 rv
->waypoints
= g_hash_table_new_full ( strcase_hash
, strcase_equal
, g_free
, (GDestroyNotify
) vik_waypoint_free
);
780 rv
->tracks
= g_hash_table_new_full ( g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) vik_track_free
);
781 rv
->tracks_iters
= g_hash_table_new_full ( g_str_hash
, g_str_equal
, NULL
, g_free
);
782 rv
->waypoints_iters
= g_hash_table_new_full ( strcase_hash
, strcase_equal
, NULL
, g_free
);
784 /* TODO: constants at top */
785 rv
->waypoints_visible
= rv
->tracks_visible
= TRUE
;
786 rv
->drawmode
= drawmode
;
787 rv
->drawpoints
= TRUE
;
788 rv
->drawstops
= FALSE
;
789 rv
->drawelevation
= FALSE
;
790 rv
->elevation_factor
= 30;
791 rv
->stop_length
= 60;
792 rv
->drawlines
= TRUE
;
793 rv
->wplabellayout
= NULL
;
794 rv
->wp_right_click_menu
= NULL
;
795 rv
->waypoint_gc
= NULL
;
796 rv
->waypoint_text_gc
= NULL
;
797 rv
->waypoint_bg_gc
= NULL
;
799 rv
->velocity_max
= 5.0;
800 rv
->velocity_min
= 0.0;
801 rv
->line_thickness
= 1;
802 rv
->bg_line_thickness
= 0;
803 rv
->current_wp
= NULL
;
804 rv
->current_wp_name
= NULL
;
805 rv
->current_track
= NULL
;
806 rv
->current_tpl
= NULL
;
807 rv
->current_tp_track_name
= NULL
;
808 rv
->moving_tp
= FALSE
;
809 rv
->moving_wp
= FALSE
;
811 rv
->ct_sync_done
= TRUE
;
813 rv
->magic_scissors_started
= FALSE
;
814 rv
->magic_scissors_check_added_track
= FALSE
;
815 rv
->magic_scissors_added_track_name
= NULL
;
816 rv
->magic_scissors_current_track
= NULL
;
817 rv
->magic_scissors_append
= FALSE
;
819 rv
->waypoint_rightclick
= FALSE
;
821 rv
->last_tp_track_name
= NULL
;
823 rv
->image_cache
= g_queue_new();
825 rv
->image_alpha
= 255;
826 rv
->image_cache_size
= 300;
827 rv
->drawimages
= TRUE
;
828 rv
->drawlabels
= TRUE
;
833 void vik_trw_layer_free ( VikTrwLayer
*trwlayer
)
835 g_hash_table_destroy(trwlayer
->waypoints
);
836 g_hash_table_destroy(trwlayer
->tracks
);
838 /* ODC: replace with GArray */
839 trw_layer_free_track_gcs ( trwlayer
);
841 if ( trwlayer
->wp_right_click_menu
)
842 gtk_object_sink ( GTK_OBJECT(trwlayer
->wp_right_click_menu
) );
844 if ( trwlayer
->wplabellayout
!= NULL
)
845 g_object_unref ( G_OBJECT ( trwlayer
->wplabellayout
) );
847 if ( trwlayer
->waypoint_gc
!= NULL
)
848 g_object_unref ( G_OBJECT ( trwlayer
->waypoint_gc
) );
850 if ( trwlayer
->waypoint_text_gc
!= NULL
)
851 g_object_unref ( G_OBJECT ( trwlayer
->waypoint_text_gc
) );
853 if ( trwlayer
->waypoint_bg_gc
!= NULL
)
854 g_object_unref ( G_OBJECT ( trwlayer
->waypoint_bg_gc
) );
856 if ( trwlayer
->waypoint_font
!= NULL
)
857 gdk_font_unref ( trwlayer
->waypoint_font
);
859 if ( trwlayer
->tpwin
!= NULL
)
860 gtk_widget_destroy ( GTK_WIDGET(trwlayer
->tpwin
) );
862 g_list_foreach ( trwlayer
->image_cache
->head
, (GFunc
) cached_pixbuf_free
, NULL
);
863 g_queue_free ( trwlayer
->image_cache
);
866 static void init_drawing_params ( struct DrawingParams
*dp
, VikViewport
*vp
)
869 dp
->xmpp
= vik_viewport_get_xmpp ( vp
);
870 dp
->ympp
= vik_viewport_get_ympp ( vp
);
871 dp
->width
= vik_viewport_get_width ( vp
);
872 dp
->height
= vik_viewport_get_height ( vp
);
873 dp
->center
= vik_viewport_get_center ( vp
);
874 dp
->one_zone
= vik_viewport_is_one_zone ( vp
); /* false if some other projection besides UTM */
875 dp
->lat_lon
= vik_viewport_get_coord_mode ( vp
) == VIK_COORD_LATLON
;
880 w2
= dp
->xmpp
* (dp
->width
/ 2) + 1600 / dp
->xmpp
;
881 h2
= dp
->ympp
* (dp
->height
/ 2) + 1600 / dp
->ympp
;
882 /* leniency -- for tracks. Obviously for waypoints this SHOULD be a lot smaller */
884 dp
->ce1
= dp
->center
->east_west
-w2
;
885 dp
->ce2
= dp
->center
->east_west
+w2
;
886 dp
->cn1
= dp
->center
->north_south
-h2
;
887 dp
->cn2
= dp
->center
->north_south
+h2
;
888 } else if ( dp
->lat_lon
) {
889 VikCoord upperleft
, bottomright
;
890 /* quick & dirty calculation; really want to check all corners due to lat/lon smaller at top in northern hemisphere */
891 /* this also DOESN'T WORK if you are crossing 180/-180 lon. I don't plan to in the near future... */
892 vik_viewport_screen_to_coord ( vp
, -500, -500, &upperleft
);
893 vik_viewport_screen_to_coord ( vp
, dp
->width
+500, dp
->height
+500, &bottomright
);
894 dp
->ce1
= upperleft
.east_west
;
895 dp
->ce2
= bottomright
.east_west
;
896 dp
->cn1
= bottomright
.north_south
;
897 dp
->cn2
= upperleft
.north_south
;
900 dp
->track_gc_iter
= 0;
903 static gint
calculate_velocity ( VikTrwLayer
*vtl
, VikTrackpoint
*tp1
, VikTrackpoint
*tp2
)
905 static gdouble rv
= 0;
906 if ( tp1
->has_timestamp
&& tp2
->has_timestamp
)
908 rv
= ( vik_coord_diff ( &(tp1
->coord
), &(tp2
->coord
) )
909 / (tp1
->timestamp
- tp2
->timestamp
) ) - vtl
->velocity_min
;
912 return VIK_TRW_LAYER_TRACK_GC_MIN
;
913 else if ( vtl
->velocity_min
>= vtl
->velocity_max
)
914 return VIK_TRW_LAYER_TRACK_GC_MAX
;
916 rv
*= (VIK_TRW_LAYER_TRACK_GC_RATES
/ (vtl
->velocity_max
- vtl
->velocity_min
));
918 if ( rv
>= VIK_TRW_LAYER_TRACK_GC_MAX
)
919 return VIK_TRW_LAYER_TRACK_GC_MAX
;
923 return VIK_TRW_LAYER_TRACK_GC_BLACK
;
926 void draw_utm_skip_insignia ( VikViewport
*vvp
, GdkGC
*gc
, gint x
, gint y
)
928 vik_viewport_draw_line ( vvp
, gc
, x
+5, y
, x
-5, y
);
929 vik_viewport_draw_line ( vvp
, gc
, x
, y
+5, x
, y
-5 );
930 vik_viewport_draw_line ( vvp
, gc
, x
+5, y
+5, x
-5, y
-5 );
931 vik_viewport_draw_line ( vvp
, gc
, x
+5, y
-5, x
-5, y
+5 );
934 static void trw_layer_draw_track ( const gchar
*name
, VikTrack
*track
, struct DrawingParams
*dp
, gboolean drawing_white_background
)
936 /* TODO: this function is a mess, get rid of any redundancy */
937 GList
*list
= track
->trackpoints
;
939 gboolean useoldvals
= TRUE
;
943 gboolean drawelevation
;
944 gdouble min_alt
, max_alt
, alt_diff
= 0;
946 const guint8 tp_size_reg
= 2;
947 const guint8 tp_size_cur
= 4;
950 if ( dp
->vtl
->drawelevation
)
952 /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
953 if ( ( drawelevation
= vik_track_get_minmax_alt ( track
, &min_alt
, &max_alt
) ) )
954 alt_diff
= max_alt
- min_alt
;
957 if ( ! track
->visible
)
960 /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
961 if ( dp
->vtl
->bg_line_thickness
&& !drawing_white_background
)
962 trw_layer_draw_track ( name
, track
, dp
, TRUE
);
964 if ( drawing_white_background
)
965 drawpoints
= drawstops
= FALSE
;
967 drawpoints
= dp
->vtl
->drawpoints
;
968 drawstops
= dp
->vtl
->drawstops
;
971 if ( dp
->vtl
->drawmode
== DRAWMODE_ALL_BLACK
)
972 dp
->track_gc_iter
= VIK_TRW_LAYER_TRACK_GC_BLACK
;
974 if ( track
== dp
->vtl
->current_track
)
975 main_gc
= dp
->vtl
->current_track_gc
;
977 main_gc
= g_array_index(dp
->vtl
->track_gc
, GdkGC
*, dp
->track_gc_iter
);
980 int x
, y
, oldx
, oldy
;
981 VikTrackpoint
*tp
= VIK_TRACKPOINT(list
->data
);
983 tp_size
= (list
== dp
->vtl
->current_tpl
) ? tp_size_cur
: tp_size_reg
;
985 vik_viewport_coord_to_screen ( dp
->vp
, &(tp
->coord
), &x
, &y
);
987 if ( (drawpoints
) && dp
->track_gc_iter
< VIK_TRW_LAYER_TRACK_GC
)
989 GdkPoint trian
[3] = { { x
, y
-(3*tp_size
) }, { x
-(2*tp_size
), y
+(2*tp_size
) }, {x
+(2*tp_size
), y
+(2*tp_size
)} };
990 vik_viewport_draw_polygon ( dp
->vp
, main_gc
, TRUE
, trian
, 3 );
996 while ((list
= g_list_next(list
)))
998 tp
= VIK_TRACKPOINT(list
->data
);
999 tp_size
= (list
== dp
->vtl
->current_tpl
) ? tp_size_cur
: tp_size_reg
;
1001 /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
1002 if ( (!dp
->one_zone
&& !dp
->lat_lon
) || /* UTM & zones; do everything */
1003 ( ((!dp
->one_zone
) || tp
->coord
.utm_zone
== dp
->center
->utm_zone
) && /* only check zones if UTM & one_zone */
1004 tp
->coord
.east_west
< dp
->ce2
&& tp
->coord
.east_west
> dp
->ce1
&& /* both UTM and lat lon */
1005 tp
->coord
.north_south
> dp
->cn1
&& tp
->coord
.north_south
< dp
->cn2
) )
1007 vik_viewport_coord_to_screen ( dp
->vp
, &(tp
->coord
), &x
, &y
);
1009 if ( drawpoints
&& ! drawing_white_background
)
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
);
1032 main_gc
= g_array_index(dp
->vtl
->track_gc
, GdkGC
*, dp
->track_gc_iter
);
1036 vik_viewport_coord_to_screen ( dp
->vp
, &(tp2
->coord
), &oldx
, &oldy
);
1038 if ( drawing_white_background
) {
1039 vik_viewport_draw_line ( dp
->vp
, dp
->vtl
->track_bg_gc
, oldx
, oldy
, x
, y
);
1043 vik_viewport_draw_line ( dp
->vp
, main_gc
, oldx
, oldy
, x
, y
);
1044 if ( dp
->vtl
->drawelevation
&& list
&& list
->next
&& VIK_TRACKPOINT(list
->next
->data
)->altitude
!= VIK_DEFAULT_ALTITUDE
) {
1046 #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
1047 if ( list
&& list
->next
&& VIK_TRACKPOINT(list
->next
->data
)->altitude
!= VIK_DEFAULT_ALTITUDE
) {
1051 tmp
[1].y
= oldy
-FIXALTITUDE(list
->data
);
1053 tmp
[2].y
= y
-FIXALTITUDE(list
->next
->data
);
1058 if ( ((oldx
- x
) > 0 && (oldy
- y
) > 0) || ((oldx
- x
) < 0 && (oldy
- y
) < 0))
1059 tmp_gc
= GTK_WIDGET(dp
->vp
)->style
->light_gc
[3];
1061 tmp_gc
= GTK_WIDGET(dp
->vp
)->style
->dark_gc
[0];
1062 vik_viewport_draw_polygon ( dp
->vp
, tmp_gc
, TRUE
, tmp
, 4);
1064 vik_viewport_draw_line ( dp
->vp
, main_gc
, oldx
, oldy
-FIXALTITUDE(list
->data
), x
, y
-FIXALTITUDE(list
->next
->data
));
1074 if (useoldvals
&& dp
->vtl
->drawlines
&& (!tp
->newsegment
))
1076 VikTrackpoint
*tp2
= VIK_TRACKPOINT(list
->prev
->data
);
1077 if ( dp
->vtl
->coord_mode
!= VIK_COORD_UTM
|| tp
->coord
.utm_zone
== dp
->center
->utm_zone
)
1079 vik_viewport_coord_to_screen ( dp
->vp
, &(tp
->coord
), &x
, &y
);
1080 if ( dp
->vtl
->drawmode
== DRAWMODE_BY_VELOCITY
) {
1081 dp
->track_gc_iter
= calculate_velocity ( dp
->vtl
, tp
, tp2
);
1082 main_gc
= g_array_index(dp
->vtl
->track_gc
, GdkGC
*, dp
->track_gc_iter
);
1085 if ( drawing_white_background
)
1086 vik_viewport_draw_line ( dp
->vp
, dp
->vtl
->track_bg_gc
, oldx
, oldy
, x
, y
);
1088 vik_viewport_draw_line ( dp
->vp
, main_gc
, oldx
, oldy
, x
, y
);
1092 vik_viewport_coord_to_screen ( dp
->vp
, &(tp2
->coord
), &x
, &y
);
1093 draw_utm_skip_insignia ( dp
->vp
, main_gc
, x
, y
);
1100 if ( dp
->vtl
->drawmode
== DRAWMODE_BY_TRACK
)
1101 if ( ++(dp
->track_gc_iter
) >= VIK_TRW_LAYER_TRACK_GC
)
1102 dp
->track_gc_iter
= 0;
1105 /* the only reason this exists is so that trw_layer_draw_track can first call itself to draw the white track background */
1106 static void trw_layer_draw_track_cb ( const gchar
*name
, VikTrack
*track
, struct DrawingParams
*dp
)
1108 trw_layer_draw_track ( name
, track
, dp
, FALSE
);
1111 static void cached_pixbuf_free ( CachedPixbuf
*cp
)
1113 g_object_unref ( G_OBJECT(cp
->pixbuf
) );
1114 g_free ( cp
->image
);
1117 static gint
cached_pixbuf_cmp ( CachedPixbuf
*cp
, const gchar
*name
)
1119 return strcmp ( cp
->image
, name
);
1122 static void trw_layer_draw_waypoint ( const gchar
*name
, VikWaypoint
*wp
, struct DrawingParams
*dp
)
1125 if ( (!dp
->one_zone
&& !dp
->lat_lon
) || ( ( dp
->lat_lon
|| wp
->coord
.utm_zone
== dp
->center
->utm_zone
) &&
1126 wp
->coord
.east_west
< dp
->ce2
&& wp
->coord
.east_west
> dp
->ce1
&&
1127 wp
->coord
.north_south
> dp
->cn1
&& wp
->coord
.north_south
< dp
->cn2
) )
1130 GdkPixbuf
*sym
= NULL
;
1131 vik_viewport_coord_to_screen ( dp
->vp
, &(wp
->coord
), &x
, &y
);
1133 /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
1135 if ( wp
->image
&& dp
->vtl
->drawimages
)
1137 GdkPixbuf
*pixbuf
= NULL
;
1140 if ( dp
->vtl
->image_alpha
== 0)
1143 l
= g_list_find_custom ( dp
->vtl
->image_cache
->head
, wp
->image
, (GCompareFunc
) cached_pixbuf_cmp
);
1145 pixbuf
= ((CachedPixbuf
*) l
->data
)->pixbuf
;
1148 gchar
*image
= wp
->image
;
1149 GdkPixbuf
*regularthumb
= a_thumbnails_get ( wp
->image
);
1150 if ( ! regularthumb
)
1152 regularthumb
= a_thumbnails_get_default (); /* cache one 'not yet loaded' for all thumbs not loaded */
1153 image
= "\x12\x00"; /* this shouldn't occur naturally. */
1157 CachedPixbuf
*cp
= NULL
;
1158 cp
= g_malloc ( sizeof ( CachedPixbuf
) );
1159 if ( dp
->vtl
->image_size
== 128 )
1160 cp
->pixbuf
= regularthumb
;
1163 cp
->pixbuf
= a_thumbnails_scale_pixbuf(regularthumb
, dp
->vtl
->image_size
, dp
->vtl
->image_size
);
1164 g_assert ( cp
->pixbuf
);
1165 g_object_unref ( G_OBJECT(regularthumb
) );
1167 cp
->image
= g_strdup ( image
);
1169 /* needed so 'click picture' tool knows how big the pic is; we don't
1170 * store it in cp because they may have been freed already. */
1171 wp
->image_width
= gdk_pixbuf_get_width ( cp
->pixbuf
);
1172 wp
->image_height
= gdk_pixbuf_get_height ( cp
->pixbuf
);
1174 g_queue_push_head ( dp
->vtl
->image_cache
, cp
);
1175 if ( dp
->vtl
->image_cache
->length
> dp
->vtl
->image_cache_size
)
1176 cached_pixbuf_free ( g_queue_pop_tail ( dp
->vtl
->image_cache
) );
1178 pixbuf
= cp
->pixbuf
;
1182 pixbuf
= a_thumbnails_get_default (); /* thumbnail not yet loaded */
1188 w
= gdk_pixbuf_get_width ( pixbuf
);
1189 h
= gdk_pixbuf_get_height ( pixbuf
);
1191 if ( x
+(w
/2) > 0 && y
+(h
/2) > 0 && x
-(w
/2) < dp
->width
&& y
-(h
/2) < dp
->height
) /* always draw within boundaries */
1193 if ( dp
->vtl
->image_alpha
== 255 )
1194 vik_viewport_draw_pixbuf ( dp
->vp
, pixbuf
, 0, 0, x
- (w
/2), y
- (h
/2), w
, h
);
1196 vik_viewport_draw_pixbuf_with_alpha ( dp
->vp
, pixbuf
, dp
->vtl
->image_alpha
, 0, 0, x
- (w
/2), y
- (h
/2), w
, h
);
1198 return; /* if failed to draw picture, default to drawing regular waypoint (below) */
1202 /* DRAW ACTUAL DOT */
1203 if ( dp
->vtl
->wp_draw_symbols
&& wp
->symbol
&& (sym
= a_get_wp_sym(wp
->symbol
)) ) {
1204 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 );
1206 else if ( wp
== dp
->vtl
->current_wp
) {
1207 switch ( dp
->vtl
->wp_symbol
) {
1208 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;
1209 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;
1210 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;
1211 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 );
1212 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 );
1216 switch ( dp
->vtl
->wp_symbol
) {
1217 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;
1218 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;
1219 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;
1220 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
);
1221 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;
1225 if ( dp
->vtl
->drawlabels
)
1227 /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
1228 gint label_x
, label_y
;
1230 pango_layout_set_text ( dp
->vtl
->wplabellayout
, name
, -1 );
1231 pango_layout_get_pixel_size ( dp
->vtl
->wplabellayout
, &width
, &height
);
1232 label_x
= x
- width
/2;
1234 label_y
= y
- height
- 2 - gdk_pixbuf_get_height(sym
)/2;
1236 label_y
= y
- dp
->vtl
->wp_size
- height
- 2;
1238 vik_viewport_draw_rectangle ( dp
->vp
, dp
->vtl
->waypoint_bg_gc
, TRUE
, label_x
- 1, label_y
-1,width
+2,height
+2);
1239 vik_viewport_draw_layout ( dp
->vp
, dp
->vtl
->waypoint_text_gc
, label_x
, label_y
, dp
->vtl
->wplabellayout
);
1244 void vik_trw_layer_draw ( VikTrwLayer
*l
, gpointer data
)
1246 static struct DrawingParams dp
;
1247 g_assert ( l
!= NULL
);
1249 init_drawing_params ( &dp
, VIK_VIEWPORT(data
) );
1252 if ( l
->tracks_visible
)
1253 g_hash_table_foreach ( l
->tracks
, (GHFunc
) trw_layer_draw_track_cb
, &dp
);
1255 if (l
->waypoints_visible
)
1256 g_hash_table_foreach ( l
->waypoints
, (GHFunc
) trw_layer_draw_waypoint
, &dp
);
1259 static void trw_layer_free_track_gcs ( VikTrwLayer
*vtl
)
1262 if ( vtl
->track_bg_gc
)
1264 g_object_unref ( vtl
->track_bg_gc
);
1265 vtl
->track_bg_gc
= NULL
;
1267 if ( vtl
->current_track_gc
)
1269 g_object_unref ( vtl
->current_track_gc
);
1270 vtl
->current_track_gc
= NULL
;
1273 if ( ! vtl
->track_gc
)
1275 for ( i
= vtl
->track_gc
->len
- 1; i
>= 0; i
-- )
1276 g_object_unref ( g_array_index ( vtl
->track_gc
, GObject
*, i
) );
1277 g_array_free ( vtl
->track_gc
, TRUE
);
1278 vtl
->track_gc
= NULL
;
1281 static void trw_layer_new_track_gcs ( VikTrwLayer
*vtl
, VikViewport
*vp
)
1283 GdkGC
*gc
[ VIK_TRW_LAYER_TRACK_GC
];
1284 gint width
= vtl
->line_thickness
;
1286 if ( vtl
->track_gc
)
1287 trw_layer_free_track_gcs ( vtl
);
1289 if ( vtl
->track_bg_gc
)
1290 g_object_unref ( vtl
->track_bg_gc
);
1291 vtl
->track_bg_gc
= vik_viewport_new_gc ( vp
, "#FFFFFF", width
+ vtl
->bg_line_thickness
);
1293 if ( vtl
->current_track_gc
)
1294 g_object_unref ( vtl
->current_track_gc
);
1295 vtl
->current_track_gc
= vik_viewport_new_gc ( vp
, "#FF0000", 2 );
1296 gdk_gc_set_line_attributes ( vtl
->current_track_gc
, 2, GDK_LINE_ON_OFF_DASH
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1298 vtl
->track_gc
= g_array_sized_new ( FALSE
, FALSE
, sizeof ( GdkGC
* ), VIK_TRW_LAYER_TRACK_GC
);
1300 gc
[0] = vik_viewport_new_gc ( vp
, "#2d870a", width
); /* below range */
1302 gc
[1] = vik_viewport_new_gc ( vp
, "#0a8742", width
);
1303 gc
[2] = vik_viewport_new_gc ( vp
, "#0a8783", width
);
1304 gc
[3] = vik_viewport_new_gc ( vp
, "#0a4d87", width
);
1305 gc
[4] = vik_viewport_new_gc ( vp
, "#05469f", width
);
1306 gc
[5] = vik_viewport_new_gc ( vp
, "#1b059f", width
);
1307 gc
[6] = vik_viewport_new_gc ( vp
, "#2d059f", width
);
1308 gc
[7] = vik_viewport_new_gc ( vp
, "#4a059f", width
);
1309 gc
[8] = vik_viewport_new_gc ( vp
, "#84059f", width
);
1310 gc
[9] = vik_viewport_new_gc ( vp
, "#96059f", width
);
1311 gc
[10] = vik_viewport_new_gc ( vp
, "#f22ef2", width
);
1313 gc
[11] = vik_viewport_new_gc ( vp
, "#ff0000", width
); /* above range */
1315 gc
[12] = vik_viewport_new_gc ( vp
, "#000000", width
); /* black / no speed data */
1317 g_array_append_vals ( vtl
->track_gc
, gc
, VIK_TRW_LAYER_TRACK_GC
);
1320 VikTrwLayer
*vik_trw_layer_create ( VikViewport
*vp
)
1322 VikTrwLayer
*rv
= vik_trw_layer_new ( 0 );
1323 PangoFontDescription
*pfd
;
1324 rv
->wplabellayout
= gtk_widget_create_pango_layout (GTK_WIDGET(vp
), NULL
);
1325 pfd
= pango_font_description_from_string (WAYPOINT_FONT
);
1326 pango_layout_set_font_description (rv
->wplabellayout
, pfd
);
1327 /* freeing PangoFontDescription, cause it has been copied by prev. call */
1328 pango_font_description_free (pfd
);
1330 vik_layer_rename ( VIK_LAYER(rv
), vik_trw_layer_interface
.name
);
1332 trw_layer_new_track_gcs ( rv
, vp
);
1334 rv
->waypoint_gc
= vik_viewport_new_gc ( vp
, "#000000", 2 );
1335 rv
->waypoint_text_gc
= vik_viewport_new_gc ( vp
, "#FFFFFF", 1 );
1336 rv
->waypoint_bg_gc
= vik_viewport_new_gc ( vp
, "#8383C4", 1 );
1337 gdk_gc_set_function ( rv
->waypoint_bg_gc
, GDK_AND
);
1339 rv
->waypoint_font
= gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
1341 rv
->has_verified_thumbnails
= FALSE
;
1342 rv
->wp_symbol
= WP_SYMBOL_FILLED_SQUARE
;
1344 rv
->wp_draw_symbols
= TRUE
;
1346 rv
->coord_mode
= vik_viewport_get_coord_mode ( vp
);
1348 rv
->menu_selection
= vik_layer_get_interface(VIK_LAYER(rv
)->type
)->menu_items_selection
;
1353 static void trw_layer_realize_track ( gchar
*name
, VikTrack
*track
, gpointer pass_along
[4] )
1355 GtkTreeIter
*new_iter
= g_malloc(sizeof(GtkTreeIter
));
1357 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1358 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
);
1360 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
);
1363 *new_iter
= *((GtkTreeIter
*) pass_along
[1]);
1364 g_hash_table_insert ( VIK_TRW_LAYER(pass_along
[2])->tracks_iters
, name
, new_iter
);
1366 if ( ! track
->visible
)
1367 vik_treeview_item_set_visible ( (VikTreeview
*) pass_along
[3], (GtkTreeIter
*) pass_along
[1], FALSE
);
1370 static void trw_layer_realize_waypoint ( gchar
*name
, VikWaypoint
*wp
, gpointer pass_along
[4] )
1372 GtkTreeIter
*new_iter
= g_malloc(sizeof(GtkTreeIter
));
1373 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1374 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
);
1376 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
);
1379 *new_iter
= *((GtkTreeIter
*) pass_along
[1]);
1380 g_hash_table_insert ( VIK_TRW_LAYER(pass_along
[2])->waypoints_iters
, name
, new_iter
);
1382 if ( ! wp
->visible
)
1383 vik_treeview_item_set_visible ( (VikTreeview
*) pass_along
[3], (GtkTreeIter
*) pass_along
[1], FALSE
);
1387 void vik_trw_layer_realize ( VikTrwLayer
*vtl
, VikTreeview
*vt
, GtkTreeIter
*layer_iter
)
1390 gpointer pass_along
[5] = { &(vtl
->tracks_iter
), &iter2
, vtl
, vt
, (gpointer
) VIK_TRW_LAYER_SUBLAYER_TRACK
};
1392 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1393 vik_treeview_add_sublayer_alphabetized ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->tracks_iter
), _("Tracks"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_TRACKS
, NULL
, TRUE
, FALSE
);
1395 vik_treeview_add_sublayer ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->tracks_iter
), _("Tracks"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_TRACKS
, NULL
, TRUE
, FALSE
);
1397 if ( ! vtl
->tracks_visible
)
1398 vik_treeview_item_set_visible ( (VikTreeview
*) vt
, &(vtl
->tracks_iter
), FALSE
);
1400 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) trw_layer_realize_track
, pass_along
);
1402 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1403 vik_treeview_add_sublayer_alphabetized ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->waypoints_iter
), _("Waypoints"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
, NULL
, TRUE
, FALSE
);
1405 vik_treeview_add_sublayer ( (VikTreeview
*) vt
, layer_iter
, &(vtl
->waypoints_iter
), _("Waypoints"), vtl
, NULL
, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
, NULL
, TRUE
, FALSE
);
1408 if ( ! vtl
->waypoints_visible
)
1409 vik_treeview_item_set_visible ( (VikTreeview
*) vt
, &(vtl
->waypoints_iter
), FALSE
);
1411 pass_along
[0] = &(vtl
->waypoints_iter
);
1412 pass_along
[4] = (gpointer
) VIK_TRW_LAYER_SUBLAYER_WAYPOINT
;
1414 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) trw_layer_realize_waypoint
, pass_along
);
1418 gboolean
vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer
*l
, gint subtype
, gpointer sublayer
)
1422 case VIK_TRW_LAYER_SUBLAYER_TRACKS
: return (l
->tracks_visible
^= 1);
1423 case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
: return (l
->waypoints_visible
^= 1);
1424 case VIK_TRW_LAYER_SUBLAYER_TRACK
:
1426 VikTrack
*t
= g_hash_table_lookup ( l
->tracks
, sublayer
);
1428 return (t
->visible
^= 1);
1432 case VIK_TRW_LAYER_SUBLAYER_WAYPOINT
:
1434 VikWaypoint
*t
= g_hash_table_lookup ( l
->waypoints
, sublayer
);
1436 return (t
->visible
^= 1);
1444 GHashTable
*vik_trw_layer_get_tracks ( VikTrwLayer
*l
)
1449 GHashTable
*vik_trw_layer_get_waypoints ( VikTrwLayer
*l
)
1451 return l
->waypoints
;
1454 static void trw_layer_find_maxmin_waypoints ( const gchar
*name
, const VikWaypoint
*w
, struct LatLon maxmin
[2] )
1456 static VikCoord fixme
;
1457 vik_coord_copy_convert ( &(w
->coord
), VIK_COORD_LATLON
, &fixme
);
1458 if ( VIK_LATLON(&fixme
)->lat
> maxmin
[0].lat
|| maxmin
[0].lat
== 0.0 )
1459 maxmin
[0].lat
= VIK_LATLON(&fixme
)->lat
;
1460 if ( VIK_LATLON(&fixme
)->lat
< maxmin
[1].lat
|| maxmin
[1].lat
== 0.0 )
1461 maxmin
[1].lat
= VIK_LATLON(&fixme
)->lat
;
1462 if ( VIK_LATLON(&fixme
)->lon
> maxmin
[0].lon
|| maxmin
[0].lon
== 0.0 )
1463 maxmin
[0].lon
= VIK_LATLON(&fixme
)->lon
;
1464 if ( VIK_LATLON(&fixme
)->lon
< maxmin
[1].lon
|| maxmin
[1].lon
== 0.0 )
1465 maxmin
[1].lon
= VIK_LATLON(&fixme
)->lon
;
1468 static void trw_layer_find_maxmin_tracks ( const gchar
*name
, GList
**t
, struct LatLon maxmin
[2] )
1471 static VikCoord fixme
;
1475 vik_coord_copy_convert ( &(VIK_TRACKPOINT(tr
->data
)->coord
), VIK_COORD_LATLON
, &fixme
);
1476 if ( VIK_LATLON(&fixme
)->lat
> maxmin
[0].lat
|| maxmin
[0].lat
== 0.0 )
1477 maxmin
[0].lat
= VIK_LATLON(&fixme
)->lat
;
1478 if ( VIK_LATLON(&fixme
)->lat
< maxmin
[1].lat
|| maxmin
[1].lat
== 0.0 )
1479 maxmin
[1].lat
= VIK_LATLON(&fixme
)->lat
;
1480 if ( VIK_LATLON(&fixme
)->lon
> maxmin
[0].lon
|| maxmin
[0].lon
== 0.0 )
1481 maxmin
[0].lon
= VIK_LATLON(&fixme
)->lon
;
1482 if ( VIK_LATLON(&fixme
)->lon
< maxmin
[1].lon
|| maxmin
[1].lon
== 0.0 )
1483 maxmin
[1].lon
= VIK_LATLON(&fixme
)->lon
;
1488 static void trw_layer_find_maxmin (VikTrwLayer
*vtl
, struct LatLon maxmin
[2])
1490 struct LatLon wpt_maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1491 struct LatLon trk_maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1493 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) trw_layer_find_maxmin_waypoints
, wpt_maxmin
);
1494 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) trw_layer_find_maxmin_tracks
, trk_maxmin
);
1495 if ((wpt_maxmin
[0].lat
!= 0.0 && wpt_maxmin
[0].lat
> trk_maxmin
[0].lat
) || trk_maxmin
[0].lat
== 0.0) {
1496 maxmin
[0].lat
= wpt_maxmin
[0].lat
;
1499 maxmin
[0].lat
= trk_maxmin
[0].lat
;
1501 if ((wpt_maxmin
[0].lon
!= 0.0 && wpt_maxmin
[0].lon
> trk_maxmin
[0].lon
) || trk_maxmin
[0].lon
== 0.0) {
1502 maxmin
[0].lon
= wpt_maxmin
[0].lon
;
1505 maxmin
[0].lon
= trk_maxmin
[0].lon
;
1507 if ((wpt_maxmin
[1].lat
!= 0.0 && wpt_maxmin
[1].lat
< trk_maxmin
[1].lat
) || trk_maxmin
[1].lat
== 0.0) {
1508 maxmin
[1].lat
= wpt_maxmin
[1].lat
;
1511 maxmin
[1].lat
= trk_maxmin
[1].lat
;
1513 if ((wpt_maxmin
[1].lon
!= 0.0 && wpt_maxmin
[1].lon
< trk_maxmin
[1].lon
) || trk_maxmin
[1].lon
== 0.0) {
1514 maxmin
[1].lon
= wpt_maxmin
[1].lon
;
1517 maxmin
[1].lon
= trk_maxmin
[1].lon
;
1521 gboolean
vik_trw_layer_find_center ( VikTrwLayer
*vtl
, VikCoord
*dest
)
1523 /* 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... */
1524 struct LatLon maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1525 trw_layer_find_maxmin (vtl
, maxmin
);
1526 if (maxmin
[0].lat
== 0.0 && maxmin
[0].lon
== 0.0 && maxmin
[1].lat
== 0.0 && maxmin
[1].lon
== 0.0)
1530 struct LatLon average
= { (maxmin
[0].lat
+maxmin
[1].lat
)/2, (maxmin
[0].lon
+maxmin
[1].lon
)/2 };
1531 vik_coord_load_from_latlon ( dest
, vtl
->coord_mode
, &average
);
1536 static void trw_layer_centerize ( gpointer layer_and_vlp
[2] )
1539 if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp
[0]), &coord
) )
1540 goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp
[1]), &coord
);
1542 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]), _("This layer has no waypoints or trackpoints.") );
1545 static void trw_layer_export ( gpointer layer_and_vlp
[2], guint file_type
)
1547 GtkWidget
*file_selector
;
1549 gboolean failed
= FALSE
;
1550 file_selector
= gtk_file_chooser_dialog_new (_("Export Layer"),
1552 GTK_FILE_CHOOSER_ACTION_SAVE
,
1553 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1554 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
1556 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector
), vik_layer_get_name(VIK_LAYER(layer_and_vlp
[0])));
1558 while ( gtk_dialog_run ( GTK_DIALOG(file_selector
) ) == GTK_RESPONSE_ACCEPT
)
1560 fn
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector
) );
1561 if ( g_file_test ( fn
, G_FILE_TEST_EXISTS
) == FALSE
)
1563 gtk_widget_hide ( file_selector
);
1564 failed
= ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp
[0]), fn
, file_type
);
1569 if ( a_dialog_overwrite ( GTK_WINDOW(file_selector
), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn
) ) )
1571 gtk_widget_hide ( file_selector
);
1572 failed
= ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp
[0]), fn
, file_type
);
1577 gtk_widget_destroy ( file_selector
);
1579 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]), _("The filename you requested could not be opened for writing.") );
1582 static void trw_layer_export_gpspoint ( gpointer layer_and_vlp
[2] )
1584 trw_layer_export ( layer_and_vlp
, FILE_TYPE_GPSPOINT
);
1587 static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp
[2] )
1589 trw_layer_export ( layer_and_vlp
, FILE_TYPE_GPSMAPPER
);
1592 static void trw_layer_export_gpx ( gpointer layer_and_vlp
[2] )
1594 trw_layer_export ( layer_and_vlp
, FILE_TYPE_GPX
);
1597 static void trw_layer_goto_wp ( gpointer layer_and_vlp
[2] )
1599 GHashTable
*wps
= vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp
[0]) );
1600 GtkWidget
*dia
= gtk_dialog_new_with_buttons (_("Find"),
1601 VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]),
1602 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
,
1604 GTK_RESPONSE_REJECT
,
1606 GTK_RESPONSE_ACCEPT
,
1609 GtkWidget
*label
, *entry
;
1610 label
= gtk_label_new(_("Waypoint Name:"));
1611 entry
= gtk_entry_new();
1613 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), label
, FALSE
, FALSE
, 0);
1614 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia
)->vbox
), entry
, FALSE
, FALSE
, 0);
1615 gtk_widget_show_all ( label
);
1616 gtk_widget_show_all ( entry
);
1618 while ( gtk_dialog_run ( GTK_DIALOG(dia
) ) == GTK_RESPONSE_ACCEPT
)
1621 gchar
*upname
= g_strdup(gtk_entry_get_text(GTK_ENTRY(entry
)));
1624 for ( i
= strlen(upname
)-1; i
>= 0; i
-- )
1625 upname
[i
] = toupper(upname
[i
]);
1627 wp
= g_hash_table_lookup ( wps
, upname
);
1630 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp
[0]), _("Waypoint not found in this layer.") );
1633 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp
[1])), &(wp
->coord
) );
1634 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp
[1]) );
1635 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
) );
1642 gtk_widget_destroy ( dia
);
1645 gboolean
vik_trw_layer_new_waypoint ( VikTrwLayer
*vtl
, GtkWindow
*w
, const VikCoord
*def_coord
)
1647 gchar
*name
= highest_wp_number_get(vtl
);
1648 VikWaypoint
*wp
= vik_waypoint_new();
1649 wp
->coord
= *def_coord
;
1651 if ( a_dialog_new_waypoint ( w
, &name
, wp
, vik_trw_layer_get_waypoints ( vtl
), vtl
->coord_mode
) )
1654 vik_trw_layer_add_waypoint ( vtl
, name
, wp
);
1657 vik_waypoint_free(wp
);
1661 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav
[2] )
1664 struct LatLon one_ll
, two_ll
;
1665 struct LatLon maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1667 VikTrwLayer
*vtl
= VIK_TRW_LAYER(lav
[0]);
1668 VikLayersPanel
*vlp
= VIK_LAYERS_PANEL(lav
[1]);
1669 VikWindow
*vw
= (VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
));
1670 VikViewport
*vvp
= vik_window_viewport(vw
);
1671 vik_viewport_screen_to_coord ( vvp
, 0, 0, &one
);
1672 vik_viewport_screen_to_coord ( vvp
, vik_viewport_get_width(vvp
), vik_viewport_get_height(vvp
), &two
);
1673 vik_coord_to_latlon(&one
, &one_ll
);
1674 vik_coord_to_latlon(&two
, &two_ll
);
1675 if (one_ll
.lat
> two_ll
.lat
) {
1676 maxmin
[0].lat
= one_ll
.lat
;
1677 maxmin
[1].lat
= two_ll
.lat
;
1680 maxmin
[0].lat
= two_ll
.lat
;
1681 maxmin
[1].lat
= one_ll
.lat
;
1683 if (one_ll
.lon
> two_ll
.lon
) {
1684 maxmin
[0].lon
= one_ll
.lon
;
1685 maxmin
[1].lon
= two_ll
.lon
;
1688 maxmin
[0].lon
= two_ll
.lon
;
1689 maxmin
[1].lon
= one_ll
.lon
;
1691 a_geonames_wikipedia_box((VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vtl
, vlp
, maxmin
);
1694 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav
[2] )
1696 VikTrwLayer
*vtl
= VIK_TRW_LAYER(lav
[0]);
1697 VikLayersPanel
*vlp
= VIK_LAYERS_PANEL(lav
[1]);
1698 struct LatLon maxmin
[2] = { {0.0,0.0}, {0.0,0.0} };
1700 trw_layer_find_maxmin (vtl
, maxmin
);
1701 a_geonames_wikipedia_box((VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vtl
, vlp
, maxmin
);
1704 static void trw_layer_new_wp ( gpointer lav
[2] )
1706 VikTrwLayer
*vtl
= VIK_TRW_LAYER(lav
[0]);
1707 VikLayersPanel
*vlp
= VIK_LAYERS_PANEL(lav
[1]);
1708 /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
1709 instead return true if you want to update. */
1710 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
)
1711 vik_layers_panel_emit_update ( vlp
);
1714 void vik_trw_layer_add_menu_items ( VikTrwLayer
*vtl
, GtkMenu
*menu
, gpointer vlp
)
1716 static gpointer pass_along
[2];
1718 GtkWidget
*export_submenu
;
1719 GtkWidget
*wikipedia_submenu
;
1720 pass_along
[0] = vtl
;
1721 pass_along
[1] = vlp
;
1723 item
= gtk_menu_item_new();
1724 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
1725 gtk_widget_show ( item
);
1727 item
= gtk_menu_item_new_with_label ( _("Goto Center of Layer") );
1728 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_centerize
), pass_along
);
1729 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1730 gtk_widget_show ( item
);
1732 item
= gtk_menu_item_new_with_label ( _("Goto Waypoint") );
1733 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_wp
), pass_along
);
1734 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1735 gtk_widget_show ( item
);
1737 export_submenu
= gtk_menu_new ();
1738 item
= gtk_menu_item_new_with_label ( _("Export layer") );
1739 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1740 gtk_widget_show ( item
);
1741 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item
), export_submenu
);
1743 item
= gtk_menu_item_new_with_label ( _("Export as GPSPoint") );
1744 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_export_gpspoint
), pass_along
);
1745 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu
), item
);
1746 gtk_widget_show ( item
);
1748 item
= gtk_menu_item_new_with_label ( _("Export as GPSMapper") );
1749 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_export_gpsmapper
), pass_along
);
1750 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu
), item
);
1751 gtk_widget_show ( item
);
1753 item
= gtk_menu_item_new_with_label ( _("Export as GPX") );
1754 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_export_gpx
), pass_along
);
1755 gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu
), item
);
1756 gtk_widget_show ( item
);
1758 item
= gtk_menu_item_new_with_label ( _("New Waypoint") );
1759 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wp
), pass_along
);
1760 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1761 gtk_widget_show ( item
);
1763 #ifdef VIK_CONFIG_GEONAMES
1764 wikipedia_submenu
= gtk_menu_new();
1765 item
= gtk_menu_item_new_with_label ( _("Add Wikipedia Waypoints") );
1766 gtk_menu_shell_append(GTK_MENU_SHELL (menu
), item
);
1767 gtk_widget_show(item
);
1768 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
), wikipedia_submenu
);
1770 item
= gtk_menu_item_new_with_label ( _("Within layer bounds") );
1771 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer
), pass_along
);
1772 gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu
), item
);
1773 gtk_widget_show ( item
);
1775 item
= gtk_menu_item_new_with_label ( _("Within current view") );
1776 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport
), pass_along
);
1777 gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu
), item
);
1778 gtk_widget_show ( item
);
1781 #ifdef VIK_CONFIG_OPENSTREETMAP
1782 item
= gtk_menu_item_new_with_label ( _("Upload to OSM") );
1783 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(osm_traces_upload_cb
), pass_along
);
1784 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1785 gtk_widget_show ( item
);
1788 item
= a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vlp
,
1789 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp
)), vtl
);
1791 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1792 gtk_widget_show ( item
);
1795 item
= a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), vlp
,
1796 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp
)), vtl
);
1798 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1799 gtk_widget_show ( item
);
1803 void vik_trw_layer_add_waypoint ( VikTrwLayer
*vtl
, gchar
*name
, VikWaypoint
*wp
)
1805 if ( VIK_LAYER(vtl
)->realized
)
1807 VikWaypoint
*oldwp
= VIK_WAYPOINT ( g_hash_table_lookup ( vtl
->waypoints
, name
) );
1809 wp
->visible
= oldwp
->visible
; /* same visibility so we don't have to update viktreeview */
1812 GtkTreeIter
*iter
= g_malloc(sizeof(GtkTreeIter
));
1813 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1814 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl
)->vt
, &(vtl
->waypoints_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, NULL
, TRUE
, TRUE
);
1816 vik_treeview_add_sublayer ( VIK_LAYER(vtl
)->vt
, &(vtl
->waypoints_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, NULL
, TRUE
, TRUE
);
1818 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, iter
);
1819 g_hash_table_insert ( vtl
->waypoints_iters
, name
, iter
);
1826 highest_wp_number_add_wp(vtl
, name
);
1827 g_hash_table_insert ( vtl
->waypoints
, name
, wp
);
1831 void vik_trw_layer_add_track ( VikTrwLayer
*vtl
, gchar
*name
, VikTrack
*t
)
1833 if ( VIK_LAYER(vtl
)->realized
)
1835 VikTrack
*oldt
= VIK_TRACK ( g_hash_table_lookup ( vtl
->tracks
, name
) );
1837 t
->visible
= oldt
->visible
; /* same visibility so we don't have to update viktreeview */
1840 GtkTreeIter
*iter
= g_malloc(sizeof(GtkTreeIter
));
1841 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
1842 vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl
)->vt
, &(vtl
->tracks_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_TRACK
, NULL
, t
->visible
, TRUE
);
1844 vik_treeview_add_sublayer ( VIK_LAYER(vtl
)->vt
, &(vtl
->tracks_iter
), iter
, name
, vtl
, name
, VIK_TRW_LAYER_SUBLAYER_TRACK
, NULL
, t
->visible
, TRUE
);
1846 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, iter
);
1847 g_hash_table_insert ( vtl
->tracks_iters
, name
, iter
);
1848 /* t->visible = TRUE; */
1852 ; /* t->visible = TRUE; // this is now used by file input functions */
1854 g_hash_table_insert ( vtl
->tracks
, name
, t
);
1858 /* to be called whenever a track has been deleted or may have been changed. */
1859 void trw_layer_cancel_tps_of_track ( VikTrwLayer
*vtl
, const gchar
*trk_name
)
1861 if (vtl
->current_tp_track_name
&& g_strcasecmp(trk_name
, vtl
->current_tp_track_name
) == 0)
1862 trw_layer_cancel_current_tp ( vtl
, FALSE
);
1863 else if (vtl
->last_tp_track_name
&& g_strcasecmp(trk_name
, vtl
->last_tp_track_name
) == 0)
1864 trw_layer_cancel_last_tp ( vtl
);
1867 static gchar
*get_new_unique_sublayer_name (VikTrwLayer
*vtl
, gint sublayer_type
, const gchar
*name
)
1870 gchar
*newname
= g_strdup(name
);
1871 while ((sublayer_type
== VIK_TRW_LAYER_SUBLAYER_TRACK
) ?
1872 (void *)vik_trw_layer_get_track(vtl
, newname
) : (void *)vik_trw_layer_get_waypoint(vtl
, newname
)) {
1873 gchar
*new_newname
= g_strdup_printf("%s#%d", name
, i
);
1875 newname
= new_newname
;
1881 void vik_trw_layer_filein_add_waypoint ( VikTrwLayer
*vtl
, gchar
*name
, VikWaypoint
*wp
)
1883 vik_trw_layer_add_waypoint ( vtl
,
1884 get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
, name
),
1887 void vik_trw_layer_filein_add_track ( VikTrwLayer
*vtl
, gchar
*name
, VikTrack
*tr
)
1889 if ( vtl
->magic_scissors_append
&& vtl
->magic_scissors_current_track
) {
1890 vik_track_remove_dup_points ( tr
); /* make "double point" track work to undo */
1891 vik_track_steal_and_append_trackpoints ( vtl
->magic_scissors_current_track
, tr
);
1892 vik_track_free ( tr
);
1893 vtl
->magic_scissors_append
= FALSE
; /* this means we have added it */
1895 gchar
*new_name
= get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_TRACK
, name
);
1896 vik_trw_layer_add_track ( vtl
, new_name
, tr
);
1898 if ( vtl
->magic_scissors_check_added_track
) {
1899 vik_track_remove_dup_points ( tr
); /* make "double point" track work to undo */
1900 if ( vtl
->magic_scissors_added_track_name
) /* for google routes */
1901 g_free ( vtl
->magic_scissors_added_track_name
);
1902 vtl
->magic_scissors_added_track_name
= g_strdup(new_name
);
1907 static void trw_layer_enum_item ( const gchar
*name
, GList
**tr
, GList
**l
)
1909 *l
= g_list_append(*l
, (gpointer
)name
);
1912 static void trw_layer_move_item ( VikTrwLayer
*vtl_src
, VikTrwLayer
*vtl_dest
, gchar
*name
, gint type
)
1914 gchar
*newname
= get_new_unique_sublayer_name(vtl_dest
, type
, name
);
1915 if (type
== VIK_TRW_LAYER_SUBLAYER_TRACK
) {
1917 t
= vik_track_copy(vik_trw_layer_get_track(vtl_src
, name
));
1918 vik_trw_layer_delete_track(vtl_src
, name
);
1919 vik_trw_layer_add_track(vtl_dest
, newname
, t
);
1921 if (type
==VIK_TRW_LAYER_SUBLAYER_WAYPOINT
) {
1923 w
= vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src
, name
));
1924 vik_trw_layer_delete_waypoint(vtl_src
, name
);
1925 vik_trw_layer_add_waypoint(vtl_dest
, newname
, w
);
1929 static void trw_layer_drag_drop_request ( VikTrwLayer
*vtl_src
, VikTrwLayer
*vtl_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
)
1931 VikTreeview
*vt
= VIK_LAYER(vtl_src
)->vt
;
1932 gint type
= vik_treeview_item_get_data(vt
, src_item_iter
);
1934 if (!vik_treeview_item_get_pointer(vt
, src_item_iter
)) {
1935 GList
*items
= NULL
;
1938 if (type
==VIK_TRW_LAYER_SUBLAYER_TRACKS
) {
1939 g_hash_table_foreach ( vtl_src
->tracks
, (GHFunc
)trw_layer_enum_item
, &items
);
1941 if (type
==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
) {
1942 g_hash_table_foreach ( vtl_src
->waypoints
, (GHFunc
)trw_layer_enum_item
, &items
);
1947 if (type
==VIK_TRW_LAYER_SUBLAYER_TRACKS
) {
1948 trw_layer_move_item ( vtl_src
, vtl_dest
, iter
->data
, VIK_TRW_LAYER_SUBLAYER_TRACK
);
1950 trw_layer_move_item ( vtl_src
, vtl_dest
, iter
->data
, VIK_TRW_LAYER_SUBLAYER_WAYPOINT
);
1957 gchar
*name
= vik_treeview_item_get_pointer(vt
, src_item_iter
);
1958 trw_layer_move_item(vtl_src
, vtl_dest
, name
, type
);
1963 gboolean
vik_trw_layer_delete_track ( VikTrwLayer
*vtl
, const gchar
*trk_name
)
1965 VikTrack
*t
= g_hash_table_lookup ( vtl
->tracks
, trk_name
);
1966 gboolean was_visible
= FALSE
;
1970 was_visible
= t
->visible
;
1971 if ( t
== vtl
->current_track
)
1972 vtl
->current_track
= NULL
;
1973 if ( t
== vtl
->magic_scissors_current_track
)
1974 vtl
->magic_scissors_current_track
= NULL
;
1976 /* could be current_tp, so we have to check */
1977 trw_layer_cancel_tps_of_track ( vtl
, trk_name
);
1979 g_assert ( ( it
= g_hash_table_lookup ( vtl
->tracks_iters
, trk_name
) ) );
1980 vik_treeview_item_delete ( VIK_LAYER(vtl
)->vt
, it
);
1981 g_hash_table_remove ( vtl
->tracks_iters
, trk_name
);
1983 /* do this last because trk_name may be pointing to actual orig key */
1984 g_hash_table_remove ( vtl
->tracks
, trk_name
);
1989 gboolean
vik_trw_layer_delete_waypoint ( VikTrwLayer
*vtl
, const gchar
*wp_name
)
1991 gboolean was_visible
= FALSE
;
1994 wp
= g_hash_table_lookup ( vtl
->waypoints
, wp_name
);
1998 if ( wp
== vtl
->current_wp
) {
1999 vtl
->current_wp
= NULL
;
2000 vtl
->current_wp_name
= NULL
;
2001 vtl
->moving_wp
= FALSE
;
2004 was_visible
= wp
->visible
;
2005 g_assert ( ( it
= g_hash_table_lookup ( vtl
->waypoints_iters
, (gchar
*) wp_name
) ) );
2006 vik_treeview_item_delete ( VIK_LAYER(vtl
)->vt
, it
);
2007 g_hash_table_remove ( vtl
->waypoints_iters
, (gchar
*) wp_name
);
2009 highest_wp_number_remove_wp(vtl
, wp_name
);
2010 g_hash_table_remove ( vtl
->waypoints
, wp_name
); /* last because this frees name */
2016 static void remove_item_from_treeview(const gchar
*name
, GtkTreeIter
*it
, VikTreeview
* vt
)
2018 vik_treeview_item_delete (vt
, it
);
2021 void vik_trw_layer_delete_all_tracks ( VikTrwLayer
*vtl
)
2024 vtl
->current_track
= NULL
;
2025 vtl
->magic_scissors_current_track
= NULL
;
2026 if (vtl
->current_tp_track_name
)
2027 trw_layer_cancel_current_tp(vtl
, FALSE
);
2028 if (vtl
->last_tp_track_name
)
2029 trw_layer_cancel_last_tp ( vtl
);
2031 g_hash_table_foreach(vtl
->tracks_iters
, (GHFunc
) remove_item_from_treeview
, VIK_LAYER(vtl
)->vt
);
2032 g_hash_table_remove_all(vtl
->tracks_iters
);
2033 g_hash_table_remove_all(vtl
->tracks
);
2035 /* TODO: only update if the layer is visible (ticked) */
2036 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2039 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer
*vtl
)
2041 vtl
->current_wp
= NULL
;
2042 vtl
->current_wp_name
= NULL
;
2043 vtl
->moving_wp
= FALSE
;
2045 highest_wp_number_reset(vtl
);
2047 g_hash_table_foreach(vtl
->waypoints_iters
, (GHFunc
) remove_item_from_treeview
, VIK_LAYER(vtl
)->vt
);
2048 g_hash_table_remove_all(vtl
->waypoints_iters
);
2049 g_hash_table_remove_all(vtl
->waypoints
);
2051 /* TODO: only update if the layer is visible (ticked) */
2052 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2055 static void trw_layer_delete_item ( gpointer pass_along
[5] )
2057 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2058 gboolean was_visible
= FALSE
;
2059 if ( GPOINTER_TO_INT (pass_along
[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2061 was_visible
= vik_trw_layer_delete_waypoint ( vtl
, (gchar
*) pass_along
[3] );
2065 was_visible
= vik_trw_layer_delete_track ( vtl
, (gchar
*) pass_along
[3] );
2068 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2072 static void trw_layer_properties_item ( gpointer pass_along
[5] )
2074 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2075 if ( GPOINTER_TO_INT (pass_along
[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2077 VikWaypoint
*wp
= g_hash_table_lookup ( vtl
->waypoints
, pass_along
[3] );
2080 if ( a_dialog_new_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), NULL
, wp
, NULL
, vtl
->coord_mode
) )
2082 if ( VIK_LAYER(vtl
)->visible
)
2083 vik_layer_emit_update ( VIK_LAYER(vtl
) );
2088 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, pass_along
[3] );
2091 vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl
),
2093 pass_along
[1], /* vlp */
2094 pass_along
[3] /* track name */);
2099 static void goto_coord ( VikLayersPanel
*vlp
, const VikCoord
*coord
)
2101 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp
), coord
);
2102 vik_layers_panel_emit_update ( vlp
);
2105 static void trw_layer_goto_track_startpoint ( gpointer pass_along
[5] )
2107 GList
*trps
= ((VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] ))->trackpoints
;
2108 if ( trps
&& trps
->data
)
2109 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(((VikTrackpoint
*) trps
->data
)->coord
));
2112 static void trw_layer_goto_track_center ( gpointer pass_along
[5] )
2114 /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
2115 GList
**trps
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2116 if ( trps
&& *trps
)
2118 struct LatLon average
, maxmin
[2] = { {0,0}, {0,0} };
2120 trw_layer_find_maxmin_tracks ( NULL
, trps
, maxmin
);
2121 average
.lat
= (maxmin
[0].lat
+maxmin
[1].lat
)/2;
2122 average
.lon
= (maxmin
[0].lon
+maxmin
[1].lon
)/2;
2123 vik_coord_load_from_latlon ( &coord
, VIK_TRW_LAYER(pass_along
[0])->coord_mode
, &average
);
2124 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &coord
);
2128 static void trw_layer_extend_track_end ( gpointer pass_along
[6] )
2130 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2131 VikTrack
*track
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2133 vtl
->current_track
= track
;
2134 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), VIK_LAYER_TRW
, TOOL_CREATE_TRACK
);
2136 if ( track
->trackpoints
)
2137 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(((VikTrackpoint
*)g_list_last(track
->trackpoints
)->data
)->coord
) );
2141 * extend a track using magic scissors
2143 static void trw_layer_extend_track_end_ms ( gpointer pass_along
[6] )
2145 VikTrwLayer
*vtl
= VIK_TRW_LAYER(pass_along
[0]);
2146 VikTrack
*track
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2147 VikCoord last_coord
= (((VikTrackpoint
*)g_list_last(track
->trackpoints
)->data
)->coord
);
2149 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), VIK_LAYER_TRW
, NUM_TOOLS
);
2150 vtl
->magic_scissors_coord
= last_coord
;
2151 vtl
->magic_scissors_current_track
= track
;
2153 if ( track
->trackpoints
)
2154 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &last_coord
) ;
2158 static void trw_layer_apply_dem_data ( gpointer pass_along
[6] )
2160 /* TODO: check & warn if no DEM data, or no applicable DEM data. */
2161 /* Also warn if overwrite old elevation data */
2162 VikTrack
*track
= (VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2164 vik_track_apply_dem_data ( track
);
2167 static void trw_layer_goto_track_endpoint ( gpointer pass_along
[6] )
2169 GList
*trps
= ((VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] ))->trackpoints
;
2172 trps
= g_list_last(trps
);
2173 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(((VikTrackpoint
*) trps
->data
)->coord
));
2177 /*************************************
2178 * merge/split by time routines
2179 *************************************/
2181 /* called for each key in track hash table.
2182 * If the current track has time stamp, add it to the result,
2183 * except the one pointed by "exclude".
2184 * set exclude to NULL if there is no exclude to check.
2185 * Not that result is in reverse (for performance reason).
2191 static void find_tracks_with_timestamp(gpointer key
, gpointer value
, gpointer udata
)
2193 twt_udata
*user_data
= udata
;
2194 VikTrackpoint
*p1
, *p2
;
2196 if (VIK_TRACK(value
)->trackpoints
== user_data
->exclude
) {
2200 if (VIK_TRACK(value
)->trackpoints
) {
2201 p1
= VIK_TRACKPOINT(VIK_TRACK(value
)->trackpoints
->data
);
2202 p2
= VIK_TRACKPOINT(g_list_last(VIK_TRACK(value
)->trackpoints
)->data
);
2204 if (!p1
->has_timestamp
|| !p2
->has_timestamp
) {
2205 g_print("no timestamp\n");
2211 *(user_data
->result
) = g_list_prepend(*(user_data
->result
), key
);
2214 /* called for each key in track hash table. if original track user_data[1] is close enough
2215 * to the passed one, add it to list in user_data[0]
2217 static void find_nearby_track(gpointer key
, gpointer value
, gpointer user_data
)
2220 VikTrackpoint
*p1
, *p2
;
2222 GList
**nearby_tracks
= ((gpointer
*)user_data
)[0];
2223 GList
*orig_track
= ((gpointer
*)user_data
)[1];
2224 guint thr
= GPOINTER_TO_UINT (((gpointer
*)user_data
)[2]);
2227 * detect reasons for not merging, and return
2228 * if no reason is found not to merge, then do it.
2231 if (VIK_TRACK(value
)->trackpoints
== orig_track
) {
2235 t1
= VIK_TRACKPOINT(orig_track
->data
)->timestamp
;
2236 t2
= VIK_TRACKPOINT(g_list_last(orig_track
)->data
)->timestamp
;
2238 if (VIK_TRACK(value
)->trackpoints
) {
2239 p1
= VIK_TRACKPOINT(VIK_TRACK(value
)->trackpoints
->data
);
2240 p2
= VIK_TRACKPOINT(g_list_last(VIK_TRACK(value
)->trackpoints
)->data
);
2242 if (!p1
->has_timestamp
|| !p2
->has_timestamp
) {
2243 g_print("no timestamp\n");
2247 /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
2248 if (! (abs(t1
- p2
->timestamp
) < thr
*60 ||
2250 abs(p1
->timestamp
- t2
) < thr
*60)
2257 *nearby_tracks
= g_list_prepend(*nearby_tracks
, key
);
2260 /* comparison function used to sort tracks; a and b are hash table keys */
2261 static gint
track_compare(gconstpointer a
, gconstpointer b
, gpointer user_data
)
2263 GHashTable
*tracks
= user_data
;
2266 t1
= VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks
, a
))->trackpoints
->data
)->timestamp
;
2267 t2
= VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks
, b
))->trackpoints
->data
)->timestamp
;
2269 if (t1
< t2
) return -1;
2270 if (t1
> t2
) return 1;
2274 /* comparison function used to sort trackpoints */
2275 static gint
trackpoint_compare(gconstpointer a
, gconstpointer b
)
2277 time_t t1
= VIK_TRACKPOINT(a
)->timestamp
, t2
= VIK_TRACKPOINT(b
)->timestamp
;
2279 if (t1
< t2
) return -1;
2280 if (t1
> t2
) return 1;
2284 static void trw_layer_merge_with_other ( gpointer pass_along
[6] )
2286 VikTrwLayer
*vtl
= (VikTrwLayer
*)pass_along
[0];
2287 gchar
*orig_track_name
= pass_along
[3];
2288 GList
*tracks_with_timestamp
= NULL
;
2289 VikTrack
*track
= (VikTrack
*) g_hash_table_lookup ( vtl
->tracks
, orig_track_name
);
2291 if (track
->trackpoints
&&
2292 !VIK_TRACKPOINT(track
->trackpoints
->data
)->has_timestamp
) {
2293 a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl
), _("Failed. This track does not have timestamp"));
2300 udata
.result
= &tracks_with_timestamp
;
2301 udata
.exclude
= track
->trackpoints
;
2302 g_hash_table_foreach(vtl
->tracks
, find_tracks_with_timestamp
, (gpointer
)&udata
);
2303 tracks_with_timestamp
= g_list_reverse(tracks_with_timestamp
);
2306 if (!tracks_with_timestamp
) {
2307 a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl
), _("Failed. No other track in this layer has timestamp"));
2311 GList
*merge_list
= a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl
),
2312 vtl
->tracks
, tracks_with_timestamp
, TRUE
,
2313 _("Merge with..."), _("Select track to merge with"));
2314 g_list_free(tracks_with_timestamp
);
2319 for (l
= merge_list
; l
!= NULL
; l
= g_list_next(l
)) {
2320 VikTrack
*merge_track
= (VikTrack
*) g_hash_table_lookup (vtl
->tracks
, l
->data
);
2322 track
->trackpoints
= g_list_concat(track
->trackpoints
, merge_track
->trackpoints
);
2323 merge_track
->trackpoints
= NULL
;
2324 vik_trw_layer_delete_track(vtl
, l
->data
);
2325 track
->trackpoints
= g_list_sort(track
->trackpoints
, trackpoint_compare
);
2328 /* TODO: free data before free merge_list */
2329 for (l
= merge_list
; l
!= NULL
; l
= g_list_next(l
))
2331 g_list_free(merge_list
);
2332 vik_layer_emit_update( VIK_LAYER(vtl
) );
2336 /* merge by time routine */
2337 static void trw_layer_merge_by_timestamp ( gpointer pass_along
[6] )
2339 VikTrwLayer
*vtl
= (VikTrwLayer
*)pass_along
[0];
2340 gchar
*orig_track_name
= strdup(pass_along
[3]);
2343 GList
*nearby_tracks
;
2346 static guint thr
= 1;
2347 guint track_count
= 0;
2349 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl
),
2350 _("Merge Threshold..."),
2351 _("Merge when time between tracks less than:"),
2353 free(orig_track_name
);
2357 /* merge tracks until we can't */
2358 nearby_tracks
= NULL
;
2362 track
= (VikTrack
*) g_hash_table_lookup ( vtl
->tracks
, orig_track_name
);
2363 trps
= track
->trackpoints
;
2368 if (nearby_tracks
) {
2369 g_list_free(nearby_tracks
);
2370 nearby_tracks
= NULL
;
2373 t1
= ((VikTrackpoint
*)trps
->data
)->timestamp
;
2374 t2
= ((VikTrackpoint
*)g_list_last(trps
)->data
)->timestamp
;
2376 /* g_print("Original track times: %d and %d\n", t1, t2); */
2377 params
[0] = &nearby_tracks
;
2379 params
[2] = GUINT_TO_POINTER (thr
);
2381 /* get a list of adjacent-in-time tracks */
2382 g_hash_table_foreach(vtl
->tracks
, find_nearby_track
, (gpointer
)params
);
2384 /* add original track */
2385 nearby_tracks
= g_list_prepend(nearby_tracks
, orig_track_name
);
2389 #define get_track(x) VIK_TRACK(g_hash_table_lookup(vtl->tracks, (gchar *)((x)->data)))
2390 #define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
2391 #define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
2392 GList
*l
= nearby_tracks
;
2393 VikTrack
*tr
= vik_track_new();
2394 tr
->visible
= track
->visible
;
2399 t1 = get_first_trackpoint(l)->timestamp;
2400 t2 = get_last_trackpoint(l)->timestamp;
2401 g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
2405 /* remove trackpoints from merged track, delete track */
2406 tr
->trackpoints
= g_list_concat(tr
->trackpoints
, get_track(l
)->trackpoints
);
2407 get_track(l
)->trackpoints
= NULL
;
2408 vik_trw_layer_delete_track(vtl
, l
->data
);
2413 tr
->trackpoints
= g_list_sort(tr
->trackpoints
, trackpoint_compare
);
2414 vik_trw_layer_add_track(vtl
, strdup(orig_track_name
), tr
);
2416 #undef get_first_trackpoint
2417 #undef get_last_trackpoint
2420 } while (track_count
> 1);
2421 g_list_free(nearby_tracks
);
2422 free(orig_track_name
);
2423 vik_layer_emit_update( VIK_LAYER(vtl
) );
2426 /* split by time routine */
2427 static void trw_layer_split_by_timestamp ( gpointer pass_along
[6] )
2429 VikTrack
*track
= (VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
2430 GList
*trps
= track
->trackpoints
;
2432 GList
*newlists
= NULL
;
2433 GList
*newtps
= NULL
;
2435 static guint thr
= 1;
2442 if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along
[0]),
2443 _("Split Threshold..."),
2444 _("Split when time between trackpoints exceeds:"),
2449 /* iterate through trackpoints, and copy them into new lists without touching original list */
2450 prev_ts
= VIK_TRACKPOINT(trps
->data
)->timestamp
;
2454 ts
= VIK_TRACKPOINT(iter
->data
)->timestamp
;
2456 g_print("panic: ts < prev_ts: this should never happen!\n");
2459 if (ts
- prev_ts
> thr
*60) {
2460 /* flush accumulated trackpoints into new list */
2461 newlists
= g_list_prepend(newlists
, g_list_reverse(newtps
));
2465 /* accumulate trackpoint copies in newtps, in reverse order */
2466 newtps
= g_list_prepend(newtps
, vik_trackpoint_copy(VIK_TRACKPOINT(iter
->data
)));
2468 iter
= g_list_next(iter
);
2471 newlists
= g_list_prepend(newlists
, g_list_reverse(newtps
));
2474 /* put lists of trackpoints into tracks */
2481 tr
= vik_track_new();
2482 tr
->visible
= track
->visible
;
2483 tr
->trackpoints
= (GList
*)(iter
->data
);
2485 new_tr_name
= g_strdup_printf("%s #%d", (gchar
*) pass_along
[3], i
++);
2486 vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along
[0]), new_tr_name
, tr
);
2487 /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
2488 VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
2490 iter
= g_list_next(iter
);
2492 g_list_free(newlists
);
2493 vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along
[0]), (gchar
*)pass_along
[3]);
2494 vik_layer_emit_update(VIK_LAYER(pass_along
[0]));
2497 /* end of split/merge routines */
2500 static void trw_layer_goto_waypoint ( gpointer pass_along
[5] )
2502 VikWaypoint
*wp
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->waypoints
, pass_along
[3] );
2504 goto_coord ( VIK_LAYERS_PANEL(pass_along
[1]), &(wp
->coord
) );
2507 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along
[5] )
2509 gchar
*webpage
= g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar
*) pass_along
[3] );
2510 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along
[0])), webpage
);
2514 const gchar
*vik_trw_layer_sublayer_rename_request ( VikTrwLayer
*l
, const gchar
*newname
, gpointer vlp
, gint subtype
, gpointer sublayer
, GtkTreeIter
*iter
)
2516 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2521 if (strcmp(newname
, sublayer
) == 0 )
2524 if (strcasecmp(newname
, sublayer
)) { /* Not just changing case */
2525 if (g_hash_table_lookup( l
->waypoints
, newname
))
2527 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l
), _("Waypoint Already Exists") );
2532 iter
= g_hash_table_lookup ( l
->waypoints_iters
, sublayer
);
2533 g_hash_table_steal ( l
->waypoints_iters
, sublayer
);
2535 wp
= vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l
->waypoints
, sublayer
)) );
2536 highest_wp_number_remove_wp(l
, sublayer
);
2537 g_hash_table_remove ( l
->waypoints
, sublayer
);
2539 rv
= g_strdup(newname
);
2541 vik_treeview_item_set_pointer ( VIK_LAYER(l
)->vt
, iter
, rv
);
2543 highest_wp_number_add_wp(l
, rv
);
2544 g_hash_table_insert ( l
->waypoints
, rv
, wp
);
2545 g_hash_table_insert ( l
->waypoints_iters
, rv
, iter
);
2547 /* it hasn't been updated yet so we pass new name */
2548 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
2549 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l
)->vt
, iter
, rv
);
2552 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp
) );
2555 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
)
2562 if (strcmp(newname
, sublayer
) == 0)
2565 if (strcasecmp(newname
, sublayer
)) { /* Not just changing case */
2566 if (g_hash_table_lookup( l
->tracks
, newname
))
2568 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l
), _("Track Already Exists") );
2573 g_hash_table_lookup_extended ( l
->tracks
, sublayer
, (void *)&orig_key
, (void *)&tr
);
2574 g_hash_table_steal ( l
->tracks
, sublayer
);
2576 iter
= g_hash_table_lookup ( l
->tracks_iters
, sublayer
);
2577 g_hash_table_steal ( l
->tracks_iters
, sublayer
);
2579 rv
= g_strdup(newname
);
2581 vik_treeview_item_set_pointer ( VIK_LAYER(l
)->vt
, iter
, rv
);
2583 g_hash_table_insert ( l
->tracks
, rv
, tr
);
2584 g_hash_table_insert ( l
->tracks_iters
, rv
, iter
);
2586 /* don't forget about current_tp_track_name, update that too */
2587 if ( l
->current_tp_track_name
&& g_strcasecmp(orig_key
,l
->current_tp_track_name
) == 0 )
2589 l
->current_tp_track_name
= rv
;
2591 vik_trw_layer_tpwin_set_track_name ( l
->tpwin
, rv
);
2593 else if ( l
->last_tp_track_name
&& g_strcasecmp(orig_key
,l
->last_tp_track_name
) == 0 )
2594 l
->last_tp_track_name
= rv
;
2596 g_free ( orig_key
);
2598 #ifdef VIK_CONFIG_ALPHABETIZED_TRW
2599 vik_treeview_sublayer_realphabetize ( VIK_LAYER(l
)->vt
, iter
, rv
);
2602 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp
) );
2608 static gboolean
is_valid_geocache_name ( gchar
*str
)
2610 gint len
= strlen ( str
);
2611 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]));
2614 static void trw_layer_track_use_with_filter ( gpointer
*pass_along
)
2616 gchar
*track_name
= (gchar
*) pass_along
[3];
2617 VikTrack
*tr
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, track_name
);
2618 a_acquire_set_filter_track ( tr
, track_name
);
2621 static gboolean
is_valid_google_route ( VikTrwLayer
*vtl
, const gchar
*track_name
)
2623 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, track_name
);
2624 return ( tr
&& tr
->comment
&& strlen(tr
->comment
) > 7 && !strncmp(tr
->comment
, "from:", 5) );
2627 static void trw_layer_track_google_route_webpage( gpointer
*pass_along
)
2629 gchar
*track_name
= (gchar
*) pass_along
[3];
2630 VikTrack
*tr
= g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, track_name
);
2632 gchar
*escaped
= uri_escape ( tr
->comment
);
2633 gchar
*webpage
= g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped
);
2634 open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along
[0])), webpage
);
2640 /* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */
2641 gboolean
vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer
*l
, GtkMenu
*menu
, gpointer vlp
, gint subtype
, gpointer sublayer
, GtkTreeIter
*iter
)
2643 static GtkTreeIter staticiter
;
2644 static gpointer pass_along
[5];
2646 gboolean rv
= FALSE
;
2649 pass_along
[1] = vlp
;
2650 pass_along
[2] = GINT_TO_POINTER (subtype
);
2651 pass_along
[3] = sublayer
;
2652 staticiter
= *iter
; /* will exist after function has ended */
2653 pass_along
[4] = &staticiter
;
2655 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
|| subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
)
2659 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES
, NULL
);
2660 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_properties_item
), pass_along
);
2661 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2662 gtk_widget_show ( item
);
2664 if (subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
) {
2665 VikTrwLayer
*vtl
= l
;
2666 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, sublayer
);
2667 if (tr
&& tr
->property_dialog
)
2668 gtk_widget_set_sensitive(GTK_WIDGET(item
), FALSE
);
2671 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT
, NULL
);
2672 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_cut_item_cb
), pass_along
);
2673 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2674 gtk_widget_show ( item
);
2676 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY
, NULL
);
2677 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_copy_item_cb
), pass_along
);
2678 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2679 gtk_widget_show ( item
);
2681 item
= gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE
, NULL
);
2682 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_delete_item
), pass_along
);
2683 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2684 gtk_widget_show ( item
);
2686 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
)
2688 /* could be a right-click using the tool */
2689 if ( vlp
!= NULL
) {
2690 item
= gtk_menu_item_new_with_label ( _("Goto") );
2691 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_waypoint
), pass_along
);
2692 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2693 gtk_widget_show ( item
);
2696 if ( is_valid_geocache_name ( (gchar
*) sublayer
) )
2698 item
= gtk_menu_item_new_with_label ( _("Visit Geocache Webpage") );
2699 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage
), pass_along
);
2700 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2701 gtk_widget_show ( item
);
2707 if ( subtype
== VIK_TRW_LAYER_SUBLAYER_TRACK
)
2709 item
= gtk_menu_item_new ();
2710 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2711 gtk_widget_show ( item
);
2713 item
= gtk_menu_item_new_with_label ( _("Goto Startpoint") );
2714 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_track_startpoint
), pass_along
);
2715 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2716 gtk_widget_show ( item
);
2718 item
= gtk_menu_item_new_with_label ( _("Goto \"Center\"") );
2719 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_track_center
), pass_along
);
2720 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2721 gtk_widget_show ( item
);
2723 item
= gtk_menu_item_new_with_label ( _("Goto Endpoint") );
2724 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_goto_track_endpoint
), pass_along
);
2725 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2726 gtk_widget_show ( item
);
2728 item
= gtk_menu_item_new_with_label ( _("Merge By Time") );
2729 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_merge_by_timestamp
), pass_along
);
2730 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2731 gtk_widget_show ( item
);
2733 item
= gtk_menu_item_new_with_label ( _("Merge With Other Tracks...") );
2734 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_merge_with_other
), pass_along
);
2735 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2736 gtk_widget_show ( item
);
2738 item
= gtk_menu_item_new_with_label ( _("Split By Time") );
2739 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_split_by_timestamp
), pass_along
);
2740 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2741 gtk_widget_show ( item
);
2743 item
= gtk_menu_item_new_with_label ( _("Download maps along track...") );
2744 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb
), pass_along
);
2745 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2746 gtk_widget_show ( item
);
2748 item
= gtk_menu_item_new_with_label ( _("Apply DEM Data") );
2749 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_apply_dem_data
), pass_along
);
2750 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2751 gtk_widget_show ( item
);
2753 item
= gtk_menu_item_new_with_label ( _("Extend track end") );
2754 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_extend_track_end
), pass_along
);
2755 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2756 gtk_widget_show ( item
);
2758 item
= gtk_menu_item_new_with_label ( _("Extend using magic scissors") );
2759 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_extend_track_end_ms
), pass_along
);
2760 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2761 gtk_widget_show ( item
);
2763 #ifdef VIK_CONFIG_OPENSTREETMAP
2764 item
= gtk_menu_item_new_with_label ( _("Upload to OSM") );
2765 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(osm_traces_upload_track_cb
), pass_along
);
2766 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2767 gtk_widget_show ( item
);
2770 if ( is_valid_google_route ( l
, (gchar
*) sublayer
) )
2772 item
= gtk_menu_item_new_with_label ( _("View Google Directions") );
2773 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_track_google_route_webpage
), pass_along
);
2774 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2775 gtk_widget_show ( item
);
2778 item
= gtk_menu_item_new_with_label ( _("Use with filter") );
2779 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_track_use_with_filter
), pass_along
);
2780 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2781 gtk_widget_show ( item
);
2783 item
= a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l
)), vlp
,
2784 vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp
)),
2785 g_hash_table_lookup ( l
->tracks
, (gchar
*) sublayer
) );
2787 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
2788 gtk_widget_show ( item
);
2792 if ( vlp
&& (subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINTS
|| subtype
== VIK_TRW_LAYER_SUBLAYER_WAYPOINT
) )
2794 item
= gtk_menu_item_new ();
2795 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
2796 gtk_widget_show ( item
);
2798 item
= gtk_menu_item_new_with_label ( _("New Waypoint") );
2799 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(trw_layer_new_wp
), pass_along
);
2800 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
2801 gtk_widget_show ( item
);
2808 /* to be called when last_tpl no long exists. */
2809 static void trw_layer_cancel_last_tp ( VikTrwLayer
*vtl
)
2811 if ( vtl
->tpwin
) /* can't join with a non-existant TP. */
2812 vik_trw_layer_tpwin_disable_join ( vtl
->tpwin
);
2813 vtl
->last_tpl
= NULL
;
2814 vtl
->last_tp_track_name
= NULL
;
2817 static void trw_layer_cancel_current_tp ( VikTrwLayer
*vtl
, gboolean destroy
)
2823 gtk_widget_destroy ( GTK_WIDGET(vtl
->tpwin
) );
2827 vik_trw_layer_tpwin_set_empty ( vtl
->tpwin
);
2829 if ( vtl
->current_tpl
)
2831 vtl
->current_tpl
= NULL
;
2832 vtl
->current_tp_track_name
= NULL
;
2833 vik_layer_emit_update(VIK_LAYER(vtl
));
2837 static void trw_layer_tpwin_response ( VikTrwLayer
*vtl
, gint response
)
2839 g_assert ( vtl
->tpwin
!= NULL
);
2840 if ( response
== VIK_TRW_LAYER_TPWIN_CLOSE
)
2841 trw_layer_cancel_current_tp ( vtl
, TRUE
);
2842 else if ( response
== VIK_TRW_LAYER_TPWIN_SPLIT
&& vtl
->current_tpl
->next
&& vtl
->current_tpl
->prev
)
2845 if ( ( name
= a_dialog_new_track ( GTK_WINDOW(vtl
->tpwin
), vtl
->tracks
, NULL
) ) )
2847 VikTrack
*tr
= vik_track_new ();
2848 GList
*newglist
= g_list_alloc ();
2849 newglist
->prev
= NULL
;
2850 newglist
->next
= vtl
->current_tpl
->next
;
2851 newglist
->data
= vik_trackpoint_copy(VIK_TRACKPOINT(vtl
->current_tpl
->data
));
2852 tr
->trackpoints
= newglist
;
2854 vtl
->current_tpl
->next
->prev
= newglist
; /* end old track here */
2855 vtl
->current_tpl
->next
= NULL
;
2857 vtl
->current_tpl
= newglist
; /* change tp to first of new track. */
2858 vtl
->current_tp_track_name
= name
;
2860 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
2864 vik_trw_layer_add_track ( vtl
, name
, tr
);
2865 vik_layer_emit_update(VIK_LAYER(vtl
));
2868 else if ( response
== VIK_TRW_LAYER_TPWIN_DELETE
)
2870 VikTrack
*tr
= g_hash_table_lookup ( vtl
->tracks
, vtl
->current_tp_track_name
);
2872 g_assert(tr
!= NULL
);
2874 /* can't join with a non-existent trackpoint */
2875 vtl
->last_tpl
= NULL
;
2876 vtl
->last_tp_track_name
= NULL
;
2878 if ( (new_tpl
= vtl
->current_tpl
->next
) || (new_tpl
= vtl
->current_tpl
->prev
) )
2880 if ( VIK_TRACKPOINT(vtl
->current_tpl
->data
)->newsegment
&& vtl
->current_tpl
->next
)
2881 VIK_TRACKPOINT(vtl
->current_tpl
->next
->data
)->newsegment
= TRUE
; /* don't concat segments on del */
2883 tr
->trackpoints
= g_list_remove_link ( tr
->trackpoints
, vtl
->current_tpl
); /* this nulls current_tpl->prev and next */
2885 /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
2886 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, new_tpl
, vtl
->current_tp_track_name
);
2888 trw_layer_cancel_last_tp ( vtl
);
2890 g_free ( vtl
->current_tpl
->data
); /* TODO: vik_trackpoint_free() */
2891 g_list_free_1 ( vtl
->current_tpl
);
2892 vtl
->current_tpl
= new_tpl
;
2893 vik_layer_emit_update(VIK_LAYER(vtl
));
2897 tr
->trackpoints
= g_list_remove_link ( tr
->trackpoints
, vtl
->current_tpl
);
2898 g_free ( vtl
->current_tpl
->data
); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
2899 g_list_free_1 ( vtl
->current_tpl
);
2900 trw_layer_cancel_current_tp ( vtl
, FALSE
);
2903 else if ( response
== VIK_TRW_LAYER_TPWIN_FORWARD
&& vtl
->current_tpl
->next
)
2905 vtl
->last_tpl
= vtl
->current_tpl
;
2906 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
= vtl
->current_tpl
->next
, vtl
->current_tp_track_name
);
2907 vik_layer_emit_update(VIK_LAYER(vtl
)); /* TODO longone: either move or only update if tp is inside drawing window */
2909 else if ( response
== VIK_TRW_LAYER_TPWIN_BACK
&& vtl
->current_tpl
->prev
)
2911 vtl
->last_tpl
= vtl
->current_tpl
;
2912 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
= vtl
->current_tpl
->prev
, vtl
->current_tp_track_name
);
2913 vik_layer_emit_update(VIK_LAYER(vtl
));
2915 else if ( response
== VIK_TRW_LAYER_TPWIN_JOIN
)
2917 VikTrack
*tr1
= g_hash_table_lookup ( vtl
->tracks
, vtl
->last_tp_track_name
);
2918 VikTrack
*tr2
= g_hash_table_lookup ( vtl
->tracks
, vtl
->current_tp_track_name
);
2920 VikTrack
*tr_first
= tr1
, *tr_last
= tr2
;
2924 if ( (!vtl
->last_tpl
->next
) && (!vtl
->current_tpl
->next
) ) /* both endpoints */
2925 vik_track_reverse ( tr2
); /* reverse the second, that way second track clicked will be later. */
2926 else if ( (!vtl
->last_tpl
->prev
) && (!vtl
->current_tpl
->prev
) )
2927 vik_track_reverse ( tr1
);
2928 else if ( (!vtl
->last_tpl
->prev
) && (!vtl
->current_tpl
->next
) ) /* clicked startpoint, then endpoint -- concat end to start */
2933 /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
2935 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. */
2936 VIK_TRACKPOINT(tr_last
->trackpoints
->data
)->newsegment
= FALSE
;
2937 tr1
->trackpoints
= g_list_concat ( tr_first
->trackpoints
, tr_last
->trackpoints
);
2938 tr2
->trackpoints
= NULL
;
2940 tmp
= vtl
->current_tp_track_name
;
2942 vtl
->current_tp_track_name
= vtl
->last_tp_track_name
; /* current_tp stays the same (believe it or not!) */
2943 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
2945 /* if we did this before, trw_layer_delete_track would have canceled the current tp because
2946 * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
2947 vik_trw_layer_delete_track ( vtl
, tmp
);
2949 trw_layer_cancel_last_tp ( vtl
); /* same TP, can't join. */
2950 vik_layer_emit_update(VIK_LAYER(vtl
));
2952 else if ( response
== VIK_TRW_LAYER_TPWIN_DATA_CHANGED
)
2953 vik_layer_emit_update (VIK_LAYER(vtl
));
2956 static void trw_layer_tpwin_init ( VikTrwLayer
*vtl
)
2960 vtl
->tpwin
= vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl
) );
2961 g_signal_connect_swapped ( GTK_DIALOG(vtl
->tpwin
), "response", G_CALLBACK(trw_layer_tpwin_response
), vtl
);
2962 /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
2963 g_signal_connect_swapped ( vtl
->tpwin
, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp
), vtl
);
2964 gtk_widget_show_all ( GTK_WIDGET(vtl
->tpwin
) );
2966 if ( vtl
->current_tpl
)
2967 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
2968 /* set layer name and TP data */
2971 /***************************************************************************
2973 ***************************************************************************/
2975 /*** Utility data structures and functions ****/
2979 gint closest_x
, closest_y
;
2980 gchar
*closest_wp_name
;
2981 VikWaypoint
*closest_wp
;
2987 gint closest_x
, closest_y
;
2988 gchar
*closest_track_name
;
2989 VikTrackpoint
*closest_tp
;
2994 static void waypoint_search_closest_tp ( gchar
*name
, VikWaypoint
*wp
, WPSearchParams
*params
)
3000 vik_viewport_coord_to_screen ( params
->vvp
, &(wp
->coord
), &x
, &y
);
3002 if ( abs (x
- params
->x
) <= WAYPOINT_SIZE_APPROX
&& abs (y
- params
->y
) <= WAYPOINT_SIZE_APPROX
&&
3003 ((!params
->closest_wp
) || /* was the old waypoint we already found closer than this one? */
3004 abs(x
- params
->x
)+abs(y
- params
->y
) < abs(x
- params
->closest_x
)+abs(y
- params
->closest_y
)))
3006 params
->closest_wp_name
= name
;
3007 params
->closest_wp
= wp
;
3008 params
->closest_x
= x
;
3009 params
->closest_y
= y
;
3013 static void track_search_closest_tp ( gchar
*name
, VikTrack
*t
, TPSearchParams
*params
)
3015 GList
*tpl
= t
->trackpoints
;
3024 tp
= VIK_TRACKPOINT(tpl
->data
);
3026 vik_viewport_coord_to_screen ( params
->vvp
, &(tp
->coord
), &x
, &y
);
3028 if ( abs (x
- params
->x
) <= TRACKPOINT_SIZE_APPROX
&& abs (y
- params
->y
) <= TRACKPOINT_SIZE_APPROX
&&
3029 ((!params
->closest_tp
) || /* was the old trackpoint we already found closer than this one? */
3030 abs(x
- params
->x
)+abs(y
- params
->y
) < abs(x
- params
->closest_x
)+abs(y
- params
->closest_y
)))
3032 params
->closest_track_name
= name
;
3033 params
->closest_tp
= tp
;
3034 params
->closest_tpl
= tpl
;
3035 params
->closest_x
= x
;
3036 params
->closest_y
= y
;
3042 static VikTrackpoint
*closest_tp_in_five_pixel_interval ( VikTrwLayer
*vtl
, VikViewport
*vvp
, gint x
, gint y
)
3044 TPSearchParams params
;
3048 params
.closest_track_name
= NULL
;
3049 params
.closest_tp
= NULL
;
3050 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) track_search_closest_tp
, ¶ms
);
3051 return params
.closest_tp
;
3054 static VikWaypoint
*closest_wp_in_five_pixel_interval ( VikTrwLayer
*vtl
, VikViewport
*vvp
, gint x
, gint y
)
3056 WPSearchParams params
;
3060 params
.closest_wp
= NULL
;
3061 params
.closest_wp_name
= NULL
;
3062 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) waypoint_search_closest_tp
, ¶ms
);
3063 return params
.closest_wp
;
3066 /* background drawing hook, to be passed the viewport */
3067 static gboolean tool_sync_done
= TRUE
;
3069 static gboolean
tool_sync(gpointer data
)
3071 VikViewport
*vvp
= data
;
3072 gdk_threads_enter();
3073 vik_viewport_sync(vvp
);
3074 tool_sync_done
= TRUE
;
3075 gdk_threads_leave();
3086 static void marker_begin_move ( tool_ed_t
*t
, gint x
, gint y
)
3089 t
->gc
= vik_viewport_new_gc (t
->vvp
, "black", 2);
3090 gdk_gc_set_function ( t
->gc
, GDK_INVERT
);
3091 vik_viewport_draw_rectangle ( t
->vvp
, t
->gc
, FALSE
, x
-3, y
-3, 6, 6 );
3092 vik_viewport_sync(t
->vvp
);
3097 static void marker_moveto ( tool_ed_t
*t
, gint x
, gint y
)
3099 VikViewport
*vvp
= t
->vvp
;
3100 vik_viewport_draw_rectangle ( vvp
, t
->gc
, FALSE
, t
->oldx
-3, t
->oldy
-3, 6, 6 );
3101 vik_viewport_draw_rectangle ( vvp
, t
->gc
, FALSE
, x
-3, y
-3, 6, 6 );
3105 if (tool_sync_done
) {
3106 g_idle_add_full (G_PRIORITY_HIGH_IDLE
+ 10, tool_sync
, vvp
, NULL
);
3107 tool_sync_done
= FALSE
;
3111 static void marker_end_move ( tool_ed_t
*t
)
3113 vik_viewport_draw_rectangle ( t
->vvp
, t
->gc
, FALSE
, t
->oldx
-3, t
->oldy
-3, 6, 6 );
3114 g_object_unref ( t
->gc
);
3118 /*** Edit waypoint ****/
3120 static gpointer
tool_edit_waypoint_create ( VikWindow
*vw
, VikViewport
*vvp
)
3122 tool_ed_t
*t
= g_new(tool_ed_t
, 1);
3128 static gboolean
tool_edit_waypoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3130 WPSearchParams params
;
3131 tool_ed_t
*t
= data
;
3132 VikViewport
*vvp
= t
->vvp
;
3134 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3141 if ( !vtl
->vl
.visible
|| !vtl
->waypoints_visible
)
3144 if ( vtl
->current_wp
&& vtl
->current_wp
->visible
)
3146 /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
3148 vik_viewport_coord_to_screen ( vvp
, &(vtl
->current_wp
->coord
), &x
, &y
);
3150 if ( abs(x
- event
->x
) <= WAYPOINT_SIZE_APPROX
&&
3151 abs(y
- event
->y
) <= WAYPOINT_SIZE_APPROX
)
3153 if ( event
->button
== 3 )
3154 vtl
->waypoint_rightclick
= TRUE
; /* remember that we're clicking; other layers will ignore release signal */
3156 marker_begin_move(t
, event
->x
, event
->y
);
3163 params
.x
= event
->x
;
3164 params
.y
= event
->y
;
3165 params
.closest_wp_name
= NULL
;
3166 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
3167 params
.closest_wp
= NULL
;
3168 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) waypoint_search_closest_tp
, ¶ms
);
3169 if ( vtl
->current_wp
== params
.closest_wp
&& vtl
->current_wp
!= NULL
)
3171 /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
3172 marker_begin_move(t
, event
->x
, event
->y
);
3173 g_critical("shouldn't be here");
3176 else if ( params
.closest_wp
)
3178 if ( event
->button
== 3 )
3179 vtl
->waypoint_rightclick
= TRUE
; /* remember that we're clicking; other layers will ignore release signal */
3181 vtl
->waypoint_rightclick
= FALSE
;
3183 vtl
->current_wp
= params
.closest_wp
;
3184 vtl
->current_wp_name
= params
.closest_wp_name
;
3186 if ( params
.closest_wp
)
3187 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, g_hash_table_lookup ( vtl
->waypoints_iters
, vtl
->current_wp_name
) );
3189 /* could make it so don't update if old WP is off screen and new is null but oh well */
3190 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3194 vtl
->current_wp
= NULL
;
3195 vtl
->current_wp_name
= NULL
;
3196 vtl
->waypoint_rightclick
= FALSE
;
3197 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3201 static gboolean
tool_edit_waypoint_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, gpointer data
)
3203 tool_ed_t
*t
= data
;
3204 VikViewport
*vvp
= t
->vvp
;
3206 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3211 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3214 if ( event
->state
& GDK_CONTROL_MASK
)
3216 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3218 new_coord
= tp
->coord
;
3222 if ( event
->state
& GDK_SHIFT_MASK
)
3224 VikWaypoint
*wp
= closest_wp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3225 if ( wp
&& wp
!= vtl
->current_wp
)
3226 new_coord
= wp
->coord
;
3231 vik_viewport_coord_to_screen ( vvp
, &new_coord
, &x
, &y
);
3233 marker_moveto ( t
, x
, y
);
3240 static gboolean
tool_edit_waypoint_release ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3242 tool_ed_t
*t
= data
;
3243 VikViewport
*vvp
= t
->vvp
;
3245 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3248 if ( t
->holding
&& event
->button
== 1 )
3251 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3254 if ( event
->state
& GDK_CONTROL_MASK
)
3256 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3258 new_coord
= tp
->coord
;
3262 if ( event
->state
& GDK_SHIFT_MASK
)
3264 VikWaypoint
*wp
= closest_wp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3265 if ( wp
&& wp
!= vtl
->current_wp
)
3266 new_coord
= wp
->coord
;
3269 marker_end_move ( t
);
3271 vtl
->current_wp
->coord
= new_coord
;
3272 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3275 /* PUT IN RIGHT PLACE!!! */
3276 if ( event
->button
== 3 && vtl
->waypoint_rightclick
)
3278 if ( vtl
->wp_right_click_menu
)
3279 gtk_object_sink ( GTK_OBJECT(vtl
->wp_right_click_menu
) );
3280 vtl
->wp_right_click_menu
= GTK_MENU ( gtk_menu_new () );
3281 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
) );
3282 gtk_menu_popup ( vtl
->wp_right_click_menu
, NULL
, NULL
, NULL
, NULL
, event
->button
, gtk_get_current_event_time() );
3283 vtl
->waypoint_rightclick
= FALSE
;
3288 /**** Begin track ***/
3289 static gpointer
tool_begin_track_create ( VikWindow
*vw
, VikViewport
*vvp
)
3294 static gboolean
tool_begin_track_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3296 vtl
->current_track
= NULL
;
3297 return tool_new_track_click ( vtl
, event
, vvp
);
3300 /*** New track ****/
3302 static gpointer
tool_new_track_create ( VikWindow
*vw
, VikViewport
*vvp
)
3311 } new_track_move_passalong_t
;
3313 /* sync and undraw, but only when we have time */
3314 static gboolean
ct_sync ( gpointer passalong
)
3316 new_track_move_passalong_t
*p
= (new_track_move_passalong_t
*) passalong
;
3317 vik_viewport_sync ( p
->vvp
);
3318 gdk_gc_set_function ( p
->vtl
->current_track_gc
, GDK_INVERT
);
3319 vik_viewport_draw_line ( p
->vvp
, p
->vtl
->current_track_gc
, p
->x1
, p
->y1
, p
->x2
, p
->y2
);
3320 gdk_gc_set_function ( p
->vtl
->current_track_gc
, GDK_COPY
);
3321 p
->vtl
->ct_sync_done
= TRUE
;
3326 static VikLayerToolFuncStatus
tool_new_track_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, VikViewport
*vvp
)
3328 /* if we haven't sync'ed yet, we don't have time to do more. */
3329 if ( vtl
->ct_sync_done
&& vtl
->current_track
&& vtl
->current_track
->trackpoints
) {
3330 GList
*iter
= vtl
->current_track
->trackpoints
;
3331 new_track_move_passalong_t
*passalong
;
3334 while ( iter
->next
)
3336 gdk_gc_set_function ( vtl
->current_track_gc
, GDK_INVERT
);
3337 vik_viewport_coord_to_screen ( vvp
, &(VIK_TRACKPOINT(iter
->data
)->coord
), &x1
, &y1
);
3338 vik_viewport_draw_line ( vvp
, vtl
->current_track_gc
, x1
, y1
, event
->x
, event
->y
);
3339 gdk_gc_set_function ( vtl
->current_track_gc
, GDK_COPY
);
3341 passalong
= g_new(new_track_move_passalong_t
,1); /* freed by sync */
3342 passalong
->vtl
= vtl
;
3343 passalong
->vvp
= vvp
;
3346 passalong
->x2
= event
->x
;
3347 passalong
->y2
= event
->y
;
3349 /* this will sync and undraw when we have time to */
3350 g_idle_add_full (G_PRIORITY_HIGH_IDLE
+ 10, ct_sync
, passalong
, NULL
);
3351 vtl
->ct_sync_done
= FALSE
;
3352 return VIK_LAYER_TOOL_ACK_GRAB_FOCUS
;
3354 return VIK_LAYER_TOOL_ACK
;
3357 static gboolean
tool_new_track_key_press ( VikTrwLayer
*vtl
, GdkEventKey
*event
, VikViewport
*vvp
)
3359 if ( vtl
->current_track
&& event
->keyval
== GDK_Escape
) {
3360 vtl
->current_track
= NULL
;
3361 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3363 } else if ( vtl
->current_track
&& event
->keyval
== GDK_BackSpace
) {
3365 if ( vtl
->current_track
->trackpoints
)
3367 GList
*last
= g_list_last(vtl
->current_track
->trackpoints
);
3368 g_free ( last
->data
);
3369 vtl
->current_track
->trackpoints
= g_list_remove_link ( vtl
->current_track
->trackpoints
, last
);
3371 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3377 static gboolean
tool_new_track_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3381 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3384 if ( event
->button
== 3 && vtl
->current_track
)
3387 if ( vtl
->current_track
->trackpoints
)
3389 GList
*last
= g_list_last(vtl
->current_track
->trackpoints
);
3390 g_free ( last
->data
);
3391 vtl
->current_track
->trackpoints
= g_list_remove_link ( vtl
->current_track
->trackpoints
, last
);
3393 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3397 if ( event
->type
== GDK_2BUTTON_PRESS
)
3399 /* subtract last (duplicate from double click) tp then end */
3400 if ( vtl
->current_track
&& vtl
->current_track
->trackpoints
&& vtl
->ct_x1
== vtl
->ct_x2
&& vtl
->ct_y1
== vtl
->ct_y2
)
3402 GList
*last
= g_list_last(vtl
->current_track
->trackpoints
);
3403 g_free ( last
->data
);
3404 vtl
->current_track
->trackpoints
= g_list_remove_link ( vtl
->current_track
->trackpoints
, last
);
3405 /* undo last, then end */
3406 vtl
->current_track
= NULL
;
3408 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3412 if ( ! vtl
->current_track
)
3414 gchar
*name
= get_new_unique_sublayer_name(vtl
, VIK_TRW_LAYER_SUBLAYER_TRACK
, _("Track"));
3415 if ( ( name
= a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), vtl
->tracks
, name
) ) )
3417 vtl
->current_track
= vik_track_new();
3418 vtl
->current_track
->visible
= TRUE
;
3419 vik_trw_layer_add_track ( vtl
, name
, vtl
->current_track
);
3421 /* incase it was created by begin track */
3422 vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl
)), VIK_LAYER_TRW
, TOOL_CREATE_TRACK
);
3427 tp
= vik_trackpoint_new();
3428 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &(tp
->coord
) );
3430 /* snap to other TP */
3431 if ( event
->state
& GDK_CONTROL_MASK
)
3433 VikTrackpoint
*other_tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3435 tp
->coord
= other_tp
->coord
;
3438 tp
->newsegment
= FALSE
;
3439 tp
->has_timestamp
= FALSE
;
3441 vtl
->current_track
->trackpoints
= g_list_append ( vtl
->current_track
->trackpoints
, tp
);
3443 vtl
->ct_x1
= vtl
->ct_x2
;
3444 vtl
->ct_y1
= vtl
->ct_y2
;
3445 vtl
->ct_x2
= event
->x
;
3446 vtl
->ct_y2
= event
->y
;
3448 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3453 /*** New waypoint ****/
3455 static gpointer
tool_new_waypoint_create ( VikWindow
*vw
, VikViewport
*vvp
)
3460 static gboolean
tool_new_waypoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3463 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3465 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &coord
);
3466 if (vik_trw_layer_new_waypoint ( vtl
, VIK_GTK_WINDOW_FROM_LAYER(vtl
), &coord
) && VIK_LAYER(vtl
)->visible
)
3467 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3472 /*** Edit trackpoint ****/
3474 static gpointer
tool_edit_trackpoint_create ( VikWindow
*vw
, VikViewport
*vvp
)
3476 tool_ed_t
*t
= g_new(tool_ed_t
, 1);
3482 static gboolean
tool_edit_trackpoint_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3484 tool_ed_t
*t
= data
;
3485 VikViewport
*vvp
= t
->vvp
;
3486 TPSearchParams params
;
3487 /* OUTDATED DOCUMENTATION:
3488 find 5 pixel range on each side. then put these UTM, and a pointer
3489 to the winning track name (and maybe the winning track itself), and a
3490 pointer to the winning trackpoint, inside an array or struct. pass
3491 this along, do a foreach on the tracks which will do a foreach on the
3494 params
.x
= event
->x
;
3495 params
.y
= event
->y
;
3496 params
.closest_track_name
= NULL
;
3497 /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
3498 params
.closest_tp
= NULL
;
3500 if ( event
->button
!= 1 )
3503 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3506 if ( !vtl
->vl
.visible
|| !vtl
->tracks_visible
)
3509 if ( vtl
->current_tpl
)
3511 /* 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.) */
3512 VikTrackpoint
*tp
= VIK_TRACKPOINT(vtl
->current_tpl
->data
);
3513 VikTrack
*current_tr
= VIK_TRACK(g_hash_table_lookup(vtl
->tracks
, vtl
->current_tp_track_name
));
3515 g_assert ( current_tr
);
3517 vik_viewport_coord_to_screen ( vvp
, &(tp
->coord
), &x
, &y
);
3519 if ( current_tr
->visible
&&
3520 abs(x
- event
->x
) < TRACKPOINT_SIZE_APPROX
&&
3521 abs(y
- event
->y
) < TRACKPOINT_SIZE_APPROX
) {
3522 marker_begin_move ( t
, event
->x
, event
->y
);
3526 vtl
->last_tpl
= vtl
->current_tpl
;
3527 vtl
->last_tp_track_name
= vtl
->current_tp_track_name
;
3530 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) track_search_closest_tp
, ¶ms
);
3532 if ( params
.closest_tp
)
3534 vtl
->current_tpl
= params
.closest_tpl
;
3535 vtl
->current_tp_track_name
= params
.closest_track_name
;
3536 vik_treeview_select_iter ( VIK_LAYER(vtl
)->vt
, g_hash_table_lookup ( vtl
->tracks_iters
, vtl
->current_tp_track_name
) );
3537 trw_layer_tpwin_init ( vtl
);
3538 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3542 /* these aren't the droids you're looking for */
3546 static gboolean
tool_edit_trackpoint_move ( VikTrwLayer
*vtl
, GdkEventMotion
*event
, gpointer data
)
3548 tool_ed_t
*t
= data
;
3549 VikViewport
*vvp
= t
->vvp
;
3551 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3557 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3560 if ( event
->state
& GDK_CONTROL_MASK
)
3562 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3563 if ( tp
&& tp
!= vtl
->current_tpl
->data
)
3564 new_coord
= tp
->coord
;
3566 // VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
3569 vik_viewport_coord_to_screen ( vvp
, &new_coord
, &x
, &y
);
3570 marker_moveto ( t
, x
, y
);
3578 static gboolean
tool_edit_trackpoint_release ( VikTrwLayer
*vtl
, GdkEventButton
*event
, gpointer data
)
3580 tool_ed_t
*t
= data
;
3581 VikViewport
*vvp
= t
->vvp
;
3583 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3585 if ( event
->button
!= 1)
3590 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &new_coord
);
3593 if ( event
->state
& GDK_CONTROL_MASK
)
3595 VikTrackpoint
*tp
= closest_tp_in_five_pixel_interval ( vtl
, vvp
, event
->x
, event
->y
);
3596 if ( tp
&& tp
!= vtl
->current_tpl
->data
)
3597 new_coord
= tp
->coord
;
3600 VIK_TRACKPOINT(vtl
->current_tpl
->data
)->coord
= new_coord
;
3602 marker_end_move ( t
);
3604 /* diff dist is diff from orig */
3605 vik_trw_layer_tpwin_set_tp ( vtl
->tpwin
, vtl
->current_tpl
, vtl
->current_tp_track_name
);
3606 /* can't join with itself! */
3607 trw_layer_cancel_last_tp ( vtl
);
3609 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3616 /*** Magic Scissors ***/
3617 static gpointer
tool_magic_scissors_create ( VikWindow
*vw
, VikViewport
*vvp
)
3622 static gboolean
tool_magic_scissors_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3625 if ( !vtl
) return FALSE
;
3626 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &tmp
);
3627 if ( event
->button
== 3 && vtl
->magic_scissors_current_track
) {
3629 new_end
= vik_track_cut_back_to_double_point ( vtl
->magic_scissors_current_track
);
3631 vtl
->magic_scissors_coord
= *new_end
;
3633 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3634 /* remove last ' to:...' */
3635 if ( vtl
->magic_scissors_current_track
->comment
) {
3636 gchar
*last_to
= strrchr ( vtl
->magic_scissors_current_track
->comment
, 't' );
3637 if ( last_to
&& (last_to
- vtl
->magic_scissors_current_track
->comment
> 1) ) {
3638 gchar
*new_comment
= g_strndup ( vtl
->magic_scissors_current_track
->comment
,
3639 last_to
- vtl
->magic_scissors_current_track
->comment
- 1);
3640 vik_track_set_comment_no_copy ( vtl
->magic_scissors_current_track
, new_comment
);
3645 else if ( vtl
->magic_scissors_started
|| (event
->state
& GDK_CONTROL_MASK
&& vtl
->magic_scissors_current_track
) ) {
3646 struct LatLon start
, end
;
3647 gchar startlat
[G_ASCII_DTOSTR_BUF_SIZE
], startlon
[G_ASCII_DTOSTR_BUF_SIZE
];
3648 gchar endlat
[G_ASCII_DTOSTR_BUF_SIZE
], endlon
[G_ASCII_DTOSTR_BUF_SIZE
];
3651 vik_coord_to_latlon ( &(vtl
->magic_scissors_coord
), &start
);
3652 vik_coord_to_latlon ( &(tmp
), &end
);
3653 vtl
->magic_scissors_coord
= tmp
; /* for continuations */
3655 /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
3656 if ( event
->state
& GDK_CONTROL_MASK
&& vtl
->magic_scissors_current_track
) {
3657 vtl
->magic_scissors_append
= TRUE
; // merge tracks. keep started true.
3659 vtl
->magic_scissors_check_added_track
= TRUE
;
3660 vtl
->magic_scissors_started
= FALSE
;
3663 url
= g_strdup_printf(GOOGLE_DIRECTIONS_STRING
,
3664 g_ascii_dtostr (startlat
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) start
.lat
),
3665 g_ascii_dtostr (startlon
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) start
.lon
),
3666 g_ascii_dtostr (endlat
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) end
.lat
),
3667 g_ascii_dtostr (endlon
, G_ASCII_DTOSTR_BUF_SIZE
, (gdouble
) end
.lon
));
3668 a_babel_convert_from_url ( vtl
, url
, "kml", NULL
, NULL
);
3671 /* see if anything was done -- a track was added or appended to */
3672 if ( vtl
->magic_scissors_check_added_track
&& vtl
->magic_scissors_added_track_name
) {
3675 tr
= g_hash_table_lookup ( vtl
->tracks
, vtl
->magic_scissors_added_track_name
);
3678 vik_track_set_comment_no_copy ( tr
, g_strdup_printf("from: %f,%f to: %f,%f", start
.lat
, start
.lon
, end
.lat
, end
.lon
) );
3680 vtl
->magic_scissors_current_track
= tr
;
3682 g_free ( vtl
->magic_scissors_added_track_name
);
3683 vtl
->magic_scissors_added_track_name
= NULL
;
3684 } else if ( vtl
->magic_scissors_append
== FALSE
&& vtl
->magic_scissors_current_track
) {
3685 /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
3686 gchar
*new_comment
= g_strdup_printf("%s to: %f,%f", vtl
->magic_scissors_current_track
->comment
, end
.lat
, end
.lon
);
3687 vik_track_set_comment_no_copy ( vtl
->magic_scissors_current_track
, new_comment
);
3689 vtl
->magic_scissors_check_added_track
= FALSE
;
3690 vtl
->magic_scissors_append
= FALSE
;
3692 vik_layer_emit_update ( VIK_LAYER(vtl
) );
3694 vtl
->magic_scissors_started
= TRUE
;
3695 vtl
->magic_scissors_coord
= tmp
;
3696 vtl
->magic_scissors_current_track
= NULL
;
3701 /*** Show picture ****/
3703 static gpointer
tool_show_picture_create ( VikWindow
*vw
, VikViewport
*vvp
)
3708 /* Params are: vvp, event, last match found or NULL */
3709 static void tool_show_picture_wp ( char *name
, VikWaypoint
*wp
, gpointer params
[2] )
3711 if ( wp
->image
&& wp
->visible
)
3713 gint x
, y
, slackx
, slacky
;
3714 GdkEventButton
*event
= (GdkEventButton
*) params
[1];
3716 vik_viewport_coord_to_screen ( VIK_VIEWPORT(params
[0]), &(wp
->coord
), &x
, &y
);
3717 slackx
= wp
->image_width
/ 2;
3718 slacky
= wp
->image_height
/ 2;
3719 if ( x
<= event
->x
+ slackx
&& x
>= event
->x
- slackx
3720 && y
<= event
->y
+ slacky
&& y
>= event
->y
- slacky
)
3722 params
[2] = wp
->image
; /* we've found a match. however continue searching
3723 * since we want to find the last match -- that
3724 * is, the match that was drawn last. */
3729 static gboolean
tool_show_picture_click ( VikTrwLayer
*vtl
, GdkEventButton
*event
, VikViewport
*vvp
)
3731 gpointer params
[3] = { vvp
, event
, NULL
};
3732 if (!vtl
|| vtl
->vl
.type
!= VIK_LAYER_TRW
)
3734 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) tool_show_picture_wp
, params
);
3737 /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
3739 ShellExecute(NULL
, NULL
, (char *) params
[2], NULL
, ".\\", 0);
3742 gchar
*quoted_file
= g_shell_quote ( (gchar
*) params
[2] );
3743 gchar
*cmd
= g_strdup_printf ( "eog %s", quoted_file
);
3744 g_free ( quoted_file
);
3745 if ( ! g_spawn_command_line_async ( cmd
, &err
) )
3747 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), _("Could not launch eog to open file.") );
3748 g_error_free ( err
);
3751 #endif /* WINDOWS */
3752 return TRUE
; /* found a match */
3755 return FALSE
; /* go through other layers, searching for a match */
3758 /***************************************************************************
3760 ***************************************************************************/
3766 static void image_wp_make_list ( char *name
, VikWaypoint
*wp
, GSList
**pics
)
3768 if ( wp
->image
&& ( ! a_thumbnails_exists ( wp
->image
) ) )
3769 *pics
= g_slist_append ( *pics
, (gpointer
) g_strdup ( wp
->image
) );
3772 static void create_thumbnails_thread ( GSList
*pics
, gpointer threaddata
)
3774 guint total
= g_slist_length(pics
), done
= 0;
3777 a_thumbnails_create ( (gchar
*) pics
->data
);
3778 a_background_thread_progress ( threaddata
, ((gdouble
) ++done
) / total
);
3783 static void free_pics_slist ( GSList
*pics
)
3787 g_free ( pics
->data
);
3788 pics
= g_slist_delete_link ( pics
, pics
);
3792 static void trw_layer_verify_thumbnails ( VikTrwLayer
*vtl
, GtkWidget
*vp
)
3794 if ( ! vtl
->has_verified_thumbnails
)
3796 GSList
*pics
= NULL
;
3797 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) image_wp_make_list
, &pics
);
3800 gint len
= g_slist_length ( pics
);
3801 gchar
*tmp
= g_strdup_printf ( _("Creating %d Image Thumbnails..."), len
);
3802 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
);
3808 VikCoordMode
vik_trw_layer_get_coord_mode ( VikTrwLayer
*vtl
)
3810 return vtl
->coord_mode
;
3815 static void waypoint_convert ( const gchar
*name
, VikWaypoint
*wp
, VikCoordMode
*dest_mode
)
3817 vik_coord_convert ( &(wp
->coord
), *dest_mode
);
3820 static void track_convert ( const gchar
*name
, VikTrack
*tr
, VikCoordMode
*dest_mode
)
3822 vik_track_convert ( tr
, *dest_mode
);
3825 static void trw_layer_change_coord_mode ( VikTrwLayer
*vtl
, VikCoordMode dest_mode
)
3827 if ( vtl
->coord_mode
!= dest_mode
)
3829 vtl
->coord_mode
= dest_mode
;
3830 g_hash_table_foreach ( vtl
->waypoints
, (GHFunc
) waypoint_convert
, &dest_mode
);
3831 g_hash_table_foreach ( vtl
->tracks
, (GHFunc
) track_convert
, &dest_mode
);
3835 VikWaypoint
*vik_trw_layer_get_waypoint ( VikTrwLayer
*vtl
, gchar
*name
)
3837 return g_hash_table_lookup ( vtl
->waypoints
, name
);
3840 VikTrack
*vik_trw_layer_get_track ( VikTrwLayer
*vtl
, gchar
*name
)
3842 return g_hash_table_lookup ( vtl
->tracks
, name
);
3845 static void vik_trw_layer_set_menu_selection(VikTrwLayer
*vtl
, guint16 selection
)
3847 vtl
->menu_selection
= selection
;
3850 static guint16
vik_trw_layer_get_menu_selection(VikTrwLayer
*vtl
)
3852 return(vtl
->menu_selection
);
3855 /* ----------- Downloading maps along tracks --------------- */
3857 static int get_download_area_width(VikViewport
*vvp
, gdouble zoom_level
, struct LatLon
*wh
)
3859 /* TODO: calculating based on current size of viewport */
3860 const gdouble w_at_zoom_0_125
= 0.0013;
3861 const gdouble h_at_zoom_0_125
= 0.0011;
3862 gdouble zoom_factor
= zoom_level
/0.125;
3864 wh
->lat
= h_at_zoom_0_125
* zoom_factor
;
3865 wh
->lon
= w_at_zoom_0_125
* zoom_factor
;
3867 return 0; /* all OK */
3870 static VikCoord
*get_next_coord(VikCoord
*from
, VikCoord
*to
, struct LatLon
*dist
, gdouble gradient
)
3872 if ((dist
->lon
>= ABS(to
->east_west
- from
->east_west
)) &&
3873 (dist
->lat
>= ABS(to
->north_south
- from
->north_south
)))
3876 VikCoord
*coord
= g_malloc(sizeof(VikCoord
));
3877 coord
->mode
= VIK_COORD_LATLON
;
3879 if (ABS(gradient
) < 1) {
3880 if (from
->east_west
> to
->east_west
)
3881 coord
->east_west
= from
->east_west
- dist
->lon
;
3883 coord
->east_west
= from
->east_west
+ dist
->lon
;
3884 coord
->north_south
= gradient
* (coord
->east_west
- from
->east_west
) + from
->north_south
;
3886 if (from
->north_south
> to
->north_south
)
3887 coord
->north_south
= from
->north_south
- dist
->lat
;
3889 coord
->north_south
= from
->north_south
+ dist
->lat
;
3890 coord
->east_west
= (1/gradient
) * (coord
->north_south
- from
->north_south
) + from
->north_south
;
3896 static GList
*add_fillins(GList
*list
, VikCoord
*from
, VikCoord
*to
, struct LatLon
*dist
)
3898 /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
3899 gdouble gradient
= (to
->north_south
- from
->north_south
)/(to
->east_west
- from
->east_west
);
3901 VikCoord
*next
= from
;
3903 if ((next
= get_next_coord(next
, to
, dist
, gradient
)) == NULL
)
3905 list
= g_list_prepend(list
, next
);
3911 void vik_track_download_map(VikTrack
*tr
, VikMapsLayer
*vml
, VikViewport
*vvp
, gdouble zoom_level
)
3913 typedef struct _Rect
{
3918 #define GLRECT(iter) ((Rect *)((iter)->data))
3921 GList
*rects_to_download
= NULL
;
3924 if (get_download_area_width(vvp
, zoom_level
, &wh
))
3927 GList
*iter
= tr
->trackpoints
;
3931 gboolean new_map
= TRUE
;
3932 VikCoord
*cur_coord
, tl
, br
;
3935 cur_coord
= &(VIK_TRACKPOINT(iter
->data
))->coord
;
3937 vik_coord_set_area(cur_coord
, &wh
, &tl
, &br
);
3938 rect
= g_malloc(sizeof(Rect
));
3941 rect
->center
= *cur_coord
;
3942 rects_to_download
= g_list_prepend(rects_to_download
, rect
);
3947 gboolean found
= FALSE
;
3948 for (rect_iter
= rects_to_download
; rect_iter
; rect_iter
= rect_iter
->next
) {
3949 if (vik_coord_inside(cur_coord
, &GLRECT(rect_iter
)->tl
, &GLRECT(rect_iter
)->br
)) {
3960 GList
*fillins
= NULL
;
3961 /* 'fillin' doesn't work in UTM mode - potentially ending up in massive loop continually allocating memory - hence don't do it */
3962 /* seems that ATM the function get_next_coord works only for LATLON */
3963 if ( cur_coord
->mode
== VIK_COORD_LATLON
) {
3964 /* fill-ins for far apart points */
3965 GList
*cur_rect
, *next_rect
;
3966 for (cur_rect
= rects_to_download
;
3967 (next_rect
= cur_rect
->next
) != NULL
;
3968 cur_rect
= cur_rect
->next
) {
3969 if ((wh
.lon
< ABS(GLRECT(cur_rect
)->center
.east_west
- GLRECT(next_rect
)->center
.east_west
)) ||
3970 (wh
.lat
< ABS(GLRECT(cur_rect
)->center
.north_south
- GLRECT(next_rect
)->center
.north_south
))) {
3971 fillins
= add_fillins(fillins
, &GLRECT(cur_rect
)->center
, &GLRECT(next_rect
)->center
, &wh
);
3975 g_message("%s: this feature works only in Mercator mode", __FUNCTION__
);
3978 GList
*iter
= fillins
;
3980 cur_coord
= (VikCoord
*)(iter
->data
);
3981 vik_coord_set_area(cur_coord
, &wh
, &tl
, &br
);
3982 rect
= g_malloc(sizeof(Rect
));
3985 rect
->center
= *cur_coord
;
3986 rects_to_download
= g_list_prepend(rects_to_download
, rect
);
3991 for (rect_iter
= rects_to_download
; rect_iter
; rect_iter
= rect_iter
->next
) {
3992 maps_layer_download_section_without_redraw(vml
, vvp
, &(((Rect
*)(rect_iter
->data
))->tl
), &(((Rect
*)(rect_iter
->data
))->br
), zoom_level
);
3996 for (iter
= fillins
; iter
; iter
= iter
->next
)
3998 g_list_free(fillins
);
4000 if (rects_to_download
) {
4001 for (rect_iter
= rects_to_download
; rect_iter
; rect_iter
= rect_iter
->next
)
4002 g_free(rect_iter
->data
);
4003 g_list_free(rects_to_download
);
4007 static void trw_layer_download_map_along_track_cb(gpointer pass_along
[6])
4010 gint selected_map
, default_map
;
4011 gchar
*zoomlist
[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL
};
4012 gdouble zoom_vals
[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
4013 gint selected_zoom
, default_zoom
;
4017 VikTrwLayer
*vtl
= pass_along
[0];
4018 VikLayersPanel
*vlp
= pass_along
[1];
4019 VikTrack
*tr
= (VikTrack
*) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along
[0])->tracks
, pass_along
[3] );
4020 VikViewport
*vvp
= vik_window_viewport((VikWindow
*)(VIK_GTK_WINDOW_FROM_LAYER(vtl
)));
4022 GList
*vmls
= vik_layers_panel_get_all_layers_of_type(vlp
, VIK_LAYER_MAPS
);
4023 int num_maps
= g_list_length(vmls
);
4026 a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl
), GTK_MESSAGE_ERROR
, _("No map layer in use. Create one first"), NULL
);
4030 gchar
**map_names
= g_malloc(1 + num_maps
* sizeof(gpointer
));
4031 VikMapsLayer
**map_layers
= g_malloc(1 + num_maps
* sizeof(gpointer
));
4033 gchar
**np
= map_names
;
4034 VikMapsLayer
**lp
= map_layers
;
4035 for (i
= 0; i
< num_maps
; i
++) {
4036 gboolean dup
= FALSE
;
4037 vml
= (VikMapsLayer
*)(vmls
->data
);
4038 for (j
= 0; j
< i
; j
++) { /* no duplicate allowed */
4039 if (vik_maps_layer_get_map_type(vml
) == vik_maps_layer_get_map_type(map_layers
[j
])) {
4046 *np
++ = vik_maps_layer_get_map_label(vml
);
4052 num_maps
= lp
- map_layers
;
4054 for (default_map
= 0; default_map
< num_maps
; default_map
++) {
4055 /* TODO: check for parent layer's visibility */
4056 if (VIK_LAYER(map_layers
[default_map
])->visible
)
4059 default_map
= (default_map
== num_maps
) ? 0 : default_map
;
4061 gdouble cur_zoom
= vik_viewport_get_zoom(vvp
);
4062 for (default_zoom
= 0; default_zoom
< sizeof(zoom_vals
)/sizeof(gdouble
); default_zoom
++) {
4063 if (cur_zoom
== zoom_vals
[default_zoom
])
4066 default_zoom
= (default_zoom
== sizeof(zoom_vals
)/sizeof(gdouble
)) ? sizeof(zoom_vals
)/sizeof(gdouble
) - 1 : default_zoom
;
4068 if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl
), map_names
, default_map
, zoomlist
, default_zoom
, &selected_map
, &selected_zoom
))
4071 vik_track_download_map(tr
, map_layers
[selected_map
], vvp
, zoom_vals
[selected_zoom
]);
4074 for (i
= 0; i
< num_maps
; i
++)
4075 g_free(map_names
[i
]);
4083 /**** lowest waypoint number calculation ***/
4084 static gint
highest_wp_number_name_to_number(const gchar
*name
) {
4085 if ( strlen(name
) == 3 ) {
4087 if ( n
< 100 && name
[0] != '0' )
4089 if ( n
< 10 && name
[0] != '0' )
4097 static void highest_wp_number_reset(VikTrwLayer
*vtl
)
4099 vtl
->highest_wp_number
= -1;
4102 static void highest_wp_number_add_wp(VikTrwLayer
*vtl
, const gchar
*new_wp_name
)
4104 /* if is bigger that top, add it */
4105 gint new_wp_num
= highest_wp_number_name_to_number(new_wp_name
);
4106 if ( new_wp_num
> vtl
->highest_wp_number
)
4107 vtl
->highest_wp_number
= new_wp_num
;
4110 static void highest_wp_number_remove_wp(VikTrwLayer
*vtl
, const gchar
*old_wp_name
)
4112 /* if wasn't top, do nothing. if was top, count backwards until we find one used */
4113 gint old_wp_num
= highest_wp_number_name_to_number(old_wp_name
);
4114 if ( vtl
->highest_wp_number
== old_wp_num
) {
4116 vtl
->highest_wp_number
--;
4118 g_snprintf(buf
,4,"%03d", vtl
->highest_wp_number
);
4119 /* search down until we find something that *does* exist */
4121 while ( vtl
->highest_wp_number
> 0 && ! g_hash_table_lookup ( vtl
->waypoints
, buf
) ) {
4122 vtl
->highest_wp_number
--;
4123 g_snprintf(buf
,4,"%03d", vtl
->highest_wp_number
);
4128 /* get lowest unused number */
4129 static gchar
*highest_wp_number_get(VikTrwLayer
*vtl
)
4132 if ( vtl
->highest_wp_number
< 0 || vtl
->highest_wp_number
>= 999 )
4134 g_snprintf(buf
,4,"%03d", vtl
->highest_wp_number
+1 );
4135 return g_strdup(buf
);