static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
#endif
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+// This is currently broken as Google have disabled the KML output in Google Maps API v3
+// It has been ifdefed out in the hope that Route Finding functionality will be restored one day...
+// Only have 'JSON' and 'XML' see:
+// https://developers.google.com/maps/documentation/directions/#DirectionsResponses
#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml"
-#define VIK_TRW_LAYER_TRACK_GC 13
+#endif
+
+#define VIK_TRW_LAYER_TRACK_GC 16
#define VIK_TRW_LAYER_TRACK_GC_RATES 10
#define VIK_TRW_LAYER_TRACK_GC_MIN 0
#define VIK_TRW_LAYER_TRACK_GC_MAX 11
#define VIK_TRW_LAYER_TRACK_GC_BLACK 12
+#define VIK_TRW_LAYER_TRACK_GC_SLOW 13
+#define VIK_TRW_LAYER_TRACK_GC_AVER 14
+#define VIK_TRW_LAYER_TRACK_GC_FAST 15
#define DRAWMODE_BY_TRACK 0
-#define DRAWMODE_BY_VELOCITY 1
+#define DRAWMODE_BY_SPEED 1
#define DRAWMODE_ALL_BLACK 2
+// Note using DRAWMODE_BY_SPEED may be slow especially for vast numbers of trackpoints
+// as we are (re)calculating the colour for every point
#define POINTS 1
#define LINES 2
#define MAX_STOP_LENGTH 86400
#define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
/* this is multiplied by user-inputted value from 1-100. */
-enum {
-VIK_TRW_LAYER_SUBLAYER_TRACKS,
-VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
-VIK_TRW_LAYER_SUBLAYER_TRACK,
-VIK_TRW_LAYER_SUBLAYER_WAYPOINT
-};
enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
guint8 wp_size;
gboolean wp_draw_symbols;
- gdouble velocity_min, velocity_max;
+ gdouble track_draw_speed_factor;
GArray *track_gc;
- guint16 track_gc_iter;
GdkGC *current_track_gc;
+ // Separate GC for a track's potential new point as drawn via separate method
+ // (compared to the actual track points drawn in the main trw_layer_draw_track function)
+ GdkGC *current_track_newpoint_gc;
GdkGC *track_bg_gc;
GdkGC *waypoint_gc;
GdkGC *waypoint_text_gc;
GdkFont *waypoint_font;
VikTrack *current_track;
guint16 ct_x1, ct_y1, ct_x2, ct_y2;
- gboolean ct_sync_done;
-
+ gboolean draw_sync_done;
+ gboolean draw_sync_do;
VikCoordMode coord_mode;
gpointer current_tp_id;
VikTrwLayerTpwin *tpwin;
- /* weird hack for joining tracks */
- GList *last_tpl;
- VikTrack *last_tp_track;
-
/* track editing tool -- more specifically, moving tps */
gboolean moving_tp;
static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
-static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 );
static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp );
static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp );
static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
static void trw_layer_goto_track_center ( gpointer pass_along[6] );
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] );
static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
static void trw_layer_merge_with_other ( gpointer pass_along[6] );
+static void trw_layer_append_track ( gpointer pass_along[6] );
static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
static void trw_layer_split_by_n_points ( gpointer pass_along[6] );
+static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] );
+static void trw_layer_split_segments ( gpointer pass_along[6] );
+static void trw_layer_delete_points_same_position ( gpointer pass_along[6] );
+static void trw_layer_delete_points_same_time ( gpointer pass_along[6] );
static void trw_layer_reverse ( gpointer pass_along[6] );
static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] );
static void trw_layer_edit_trackpoint ( gpointer pass_along[6] );
static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl );
static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp );
+static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp );
static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-
+#endif
static void cached_pixbuf_free ( CachedPixbuf *cp );
static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
-static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name);
static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode );
static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode );
static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
-
+// Note for the following tool GtkRadioActionEntry texts:
+// the very first text value is an internal name not displayed anywhere
+// the first N_ text value is the name used for menu entries - hence has an underscore for the keyboard accelerator
+// * remember not to clash with the values used for VikWindow level tools (Pan, Zoom, Ruler + Select)
+// the second N_ text value is used for the button tooltip (i.e. generally don't want an underscore here)
+// the value is always set to 0 and the tool loader in VikWindow will set the actual appropriate value used
static VikToolInterface trw_layer_tools[] = {
- { N_("Create Waypoint"), (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
-
- { N_("Create Track"), (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_new_track_click, (VikToolMouseMoveFunc) tool_new_track_move, NULL,
- (VikToolKeyFunc) tool_new_track_key_press, GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
-
- { N_("Begin Track"), (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
-
- { N_("Edit Waypoint"), (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL,
+ { { "CreateWaypoint", "vik-icon-Create Waypoint", N_("Create _Waypoint"), "<control><shift>W", N_("Create Waypoint"), 0 },
+ (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
+
+ { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
+ (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_new_track_click,
+ (VikToolMouseMoveFunc) tool_new_track_move,
+ (VikToolMouseFunc) tool_new_track_release,
+ (VikToolKeyFunc) tool_new_track_key_press,
+ TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
+ GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
+
+ { { "BeginTrack", "vik-icon-Begin Track", N_("_Begin Track"), "<control><shift>B", N_("Begin Track"), 0 },
+ (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
+
+ { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "<control><shift>E", N_("Edit Waypoint"), 0 },
+ (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL,
(VikToolMouseFunc) tool_edit_waypoint_click,
(VikToolMouseMoveFunc) tool_edit_waypoint_move,
- (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
+ (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
- { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
+ { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
+ (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
(VikToolMouseFunc) tool_edit_trackpoint_click,
(VikToolMouseMoveFunc) tool_edit_trackpoint_move,
- (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
-
- { N_("Show Picture"), (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
-
- { N_("Route Finder"), (VikToolConstructorFunc) tool_route_finder_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
+ (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
+
+ { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
+ (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
+
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+ { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
+ (VikToolConstructorFunc) tool_route_finder_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
+#endif
};
enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
-static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 };
+static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Black"), 0 };
static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
static VikLayerParamScale params_scales[] = {
/* min max step digits */
{ 1, 10, 1, 0 }, /* line_thickness */
- { 0.0, 99.0, 1, 2 }, /* velocity_min */
- { 1.0, 100.0, 1.0, 2 }, /* velocity_max */
+ { 0, 100, 1, 0 }, /* track draw speed factor */
+ { 1.0, 100.0, 1.0, 2 }, /* UNUSED */
/* 5 * step == how much to turn */
{ 16, 128, 3.2, 0 }, /* image_size */
{ 0, 255, 5, 0 }, /* image alpha */
{ "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
{ "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 },
{ "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, 0 },
- { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Min Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
- { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Max Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 },
+ { "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
{ "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON },
{ "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
{ "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
};
-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 };
+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_TDSF, 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 };
/*** TO ADD A PARAM:
*** 1) Add to trw_layer_params and enumeration
/* End Layer Interface function definitions */
VikLayerInterface vik_trw_layer_interface = {
- "TrackWaypoint",
+ N_("TrackWaypoint"),
+ "<control><shift>Y",
&viktrwlayer_pixbuf,
trw_layer_tools,
w = vik_waypoint_unmarshall(fi->data, fi->len);
// When copying - we'll create a new name based on the original
- name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, w->name);
+ name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, w->name);
vik_trw_layer_add_waypoint ( vtl, name, w );
waypoint_convert (NULL, w, &vtl->coord_mode);
t = vik_track_unmarshall(fi->data, fi->len);
// When copying - we'll create a new name based on the original
- name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name);
+ name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name);
vik_trw_layer_add_track ( vtl, name, t );
track_convert (name, t, &vtl->coord_mode);
trw_layer_new_track_gcs ( vtl, vp );
}
break;
- case PARAM_VMIN:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- vtl->velocity_min = data.d;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- vtl->velocity_min = VIK_KPH_TO_MPS(data.d);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- vtl->velocity_min = VIK_MPH_TO_MPS(data.d);
- else
- /* Knots */
- vtl->velocity_min = VIK_KNOTS_TO_MPS(data.d);
- break;
- }
- case PARAM_VMAX:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- vtl->velocity_max = data.d;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- vtl->velocity_max = VIK_KPH_TO_MPS(data.d);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- vtl->velocity_max = VIK_MPH_TO_MPS(data.d);
- else
- /* Knots */
- vtl->velocity_max = VIK_KNOTS_TO_MPS(data.d);
- break;
- }
case PARAM_TBGC: gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(data.c)); break;
+ case PARAM_TDSF: vtl->track_draw_speed_factor = data.d; break;
case PARAM_DLA: vtl->drawlabels = data.b; break;
case PARAM_DI: vtl->drawimages = data.b; break;
case PARAM_IS: if ( data.u != vtl->image_size )
case PARAM_DL: rv.b = vtl->drawlines; break;
case PARAM_LT: rv.u = vtl->line_thickness; break;
case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
- case PARAM_VMIN:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- rv.d = vtl->velocity_min;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- rv.d = VIK_MPS_TO_KPH(vtl->velocity_min);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- rv.d = VIK_MPS_TO_MPH(vtl->velocity_min);
- else
- /* Knots */
- rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_min);
- break;
- }
- case PARAM_VMAX:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- rv.d = vtl->velocity_max;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- rv.d = VIK_MPS_TO_KPH(vtl->velocity_max);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- rv.d = VIK_MPS_TO_MPH(vtl->velocity_max);
- else
- /* Knots */
- rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_max);
- break;
- }
case PARAM_DLA: rv.b = vtl->drawlabels; break;
case PARAM_DI: rv.b = vtl->drawimages; break;
case PARAM_TBGC: vik_gc_get_fg_color(vtl->track_bg_gc, &(rv.c)); break;
+ case PARAM_TDSF: rv.d = vtl->track_draw_speed_factor; break;
case PARAM_IS: rv.u = vtl->image_size; break;
case PARAM_IA: rv.u = vtl->image_alpha; break;
case PARAM_ICS: rv.u = vtl->image_cache_size; break;
rv->waypoint_text_gc = NULL;
rv->waypoint_bg_gc = NULL;
rv->track_gc = NULL;
- rv->velocity_max = 5.0;
- rv->velocity_min = 0.0;
+ rv->track_draw_speed_factor = 30.0;
rv->line_thickness = 1;
rv->bg_line_thickness = 0;
rv->current_wp = NULL;
rv->moving_tp = FALSE;
rv->moving_wp = FALSE;
- rv->ct_sync_done = TRUE;
+ rv->draw_sync_done = TRUE;
+ rv->draw_sync_do = TRUE;
rv->route_finder_started = FALSE;
rv->route_finder_check_added_track = FALSE;
rv->route_finder_append = FALSE;
rv->waypoint_rightclick = FALSE;
- rv->last_tpl = NULL;
- rv->last_tp_track = NULL;
rv->tpwin = NULL;
rv->image_cache = g_queue_new();
rv->image_size = 64;
dp->track_gc_iter = 0;
}
-static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 )
-{
- static gdouble rv = 0;
- if ( tp1->has_timestamp && tp2->has_timestamp )
- {
- rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) )
- / (tp1->timestamp - tp2->timestamp) ) - vtl->velocity_min;
-
- if ( rv < 0 )
- return VIK_TRW_LAYER_TRACK_GC_MIN;
- else if ( vtl->velocity_min >= vtl->velocity_max )
- return VIK_TRW_LAYER_TRACK_GC_MAX;
-
- rv *= (VIK_TRW_LAYER_TRACK_GC_RATES / (vtl->velocity_max - vtl->velocity_min));
-
- if ( rv >= VIK_TRW_LAYER_TRACK_GC_MAX )
- return VIK_TRW_LAYER_TRACK_GC_MAX;
- return (gint) rv;
- }
- else
- return VIK_TRW_LAYER_TRACK_GC_BLACK;
+/*
+ * Determine the colour of the trackpoint (and/or trackline) relative to the average speed
+ * Here a simple traffic like light colour system is used:
+ * . slow points are red
+ * . average is yellow
+ * . fast points are green
+ */
+static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2, gdouble average_speed, gdouble low_speed, gdouble high_speed )
+{
+ gdouble rv = 0;
+ if ( tp1->has_timestamp && tp2->has_timestamp ) {
+ if ( average_speed > 0 ) {
+ rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) ) / (tp1->timestamp - tp2->timestamp) );
+ if ( rv < low_speed )
+ return VIK_TRW_LAYER_TRACK_GC_SLOW;
+ else if ( rv > high_speed )
+ return VIK_TRW_LAYER_TRACK_GC_FAST;
+ else
+ return VIK_TRW_LAYER_TRACK_GC_AVER;
+ }
+ }
+ return VIK_TRW_LAYER_TRACK_GC_BLACK;
}
void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
drawstops = dp->vtl->drawstops;
}
+ gboolean drawing_highlight = FALSE;
/* Current track - used for creation */
if ( track == dp->vtl->current_track )
main_gc = dp->vtl->current_track_gc;
( dp->vtl->tracks == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ||
track == vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) {
main_gc = vik_viewport_get_gc_highlight (dp->vp);
+ drawing_highlight = TRUE;
}
else {
if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
oldx = x;
oldy = y;
+ gdouble average_speed = 0.0;
+ gdouble low_speed = 0.0;
+ gdouble high_speed = 0.0;
+ // If necessary calculate these values - which is done only once per track redraw
+ if ( dp->vtl->drawmode == DRAWMODE_BY_SPEED ) {
+ // the percentage factor away from the average speed determines transistions between the levels
+ average_speed = vik_track_get_average_speed_moving(track, dp->vtl->stop_length);
+ low_speed = average_speed - (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
+ high_speed = average_speed + (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
+ }
+
while ((list = g_list_next(list)))
{
tp = VIK_TRACKPOINT(list->data);
goto skip;
}
+ VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
+ if ( drawpoints || dp->vtl->drawlines ) {
+ // setup main_gc for both point and line drawing
+ if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
+ dp->track_gc_iter = track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed );
+ main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
+ }
+ }
+
if ( drawpoints && ! drawing_white_background )
{
+
if ( list->next ) {
/*
* The concept of drawing stops is that a trackpoint
if ((!tp->newsegment) && (dp->vtl->drawlines))
{
- VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
/* UTM only: zone check */
if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
draw_utm_skip_insignia ( dp->vp, main_gc, x, y);
- if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
- dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
- main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
- }
-
if (!useoldvals)
vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
{
vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
- if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
- dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
+
+ if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
+ dp->track_gc_iter = track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed );
main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
- }
+ }
/*
* If points are the same in display coordinates, don't draw.
}
}
if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
- if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC )
+ if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC_MAX )
dp->track_gc_iter = 0;
}
g_object_unref ( vtl->current_track_gc );
vtl->current_track_gc = NULL;
}
+ if ( vtl->current_track_newpoint_gc )
+ {
+ g_object_unref ( vtl->current_track_newpoint_gc );
+ vtl->current_track_newpoint_gc = NULL;
+ }
if ( ! vtl->track_gc )
return;
vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+ // 'newpoint' gc is exactly the same as the current track gc
+ if ( vtl->current_track_newpoint_gc )
+ g_object_unref ( vtl->current_track_newpoint_gc );
+ vtl->current_track_newpoint_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
+ gdk_gc_set_line_attributes ( vtl->current_track_newpoint_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+
vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */
+ gc[VIK_TRW_LAYER_TRACK_GC_SLOW] = vik_viewport_new_gc ( vp, "#E6202E", width ); // red-ish
+ gc[VIK_TRW_LAYER_TRACK_GC_AVER] = vik_viewport_new_gc ( vp, "#D2CD26", width ); // yellow-ish
+ gc[VIK_TRW_LAYER_TRACK_GC_FAST] = vik_viewport_new_gc ( vp, "#2B8700", width ); // green-ish
+
g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
}
trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
vtl,
track,
- pass_along[3] );
+ track->name );
}
static void trw_layer_geotagging ( gpointer lav[2] )
{
if (vtl->current_tp_track == trk )
trw_layer_cancel_current_tp ( vtl, FALSE );
- else if (vtl->last_tp_track == trk )
- trw_layer_cancel_last_tp ( vtl );
}
-static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
+gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
{
gint i = 2;
gchar *newname = g_strdup(name);
if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
- gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, trk->name);
+ gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name);
VikTrack *trk2 = vik_track_copy ( trk );
vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
- gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, wp->name);
+ gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, wp->name);
VikWaypoint *wp2 = vik_waypoint_copy ( wp );
vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
vtl->route_finder_added_track = NULL;
if (vtl->current_tp_track)
trw_layer_cancel_current_tp(vtl, FALSE);
- if (vtl->last_tp_track)
- trw_layer_cancel_last_tp ( vtl );
g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
g_hash_table_remove_all(vtl->tracks_iters);
goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
}
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
/**
* extend a track using route finder
*/
goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
}
+#endif
static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
{
/* called for each key in track hash table. if original track user_data[1] is close enough
* to the passed one, add it to list in user_data[0]
*/
-static void find_nearby_track(gpointer key, gpointer value, gpointer user_data)
+static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
{
time_t t1, t2;
VikTrackpoint *p1, *p2;
+ VikTrack *trk = VIK_TRACK(value);
GList **nearby_tracks = ((gpointer *)user_data)[0];
- GList *orig_track = ((gpointer *)user_data)[1];
- guint thr = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
+ GList *tpoints = ((gpointer *)user_data)[1];
/* outline:
* detect reasons for not merging, and return
* if no reason is found not to merge, then do it.
*/
- if (VIK_TRACK(value)->trackpoints == orig_track) {
+ // Exclude the original track from the compiled list
+ if (trk->trackpoints == tpoints) {
return;
}
- t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
- t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
+ t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp;
+ t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp;
- if (VIK_TRACK(value)->trackpoints) {
- p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
- p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+ if (trk->trackpoints) {
+ p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data);
+ p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data);
if (!p1->has_timestamp || !p2->has_timestamp) {
- g_print("no timestamp\n");
+ //g_print("no timestamp\n");
return;
}
- /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
- if (! (abs(t1 - p2->timestamp) < thr*60 ||
+ guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
+ //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
+ if (! (abs(t1 - p2->timestamp) < threshold ||
/* p1 p2 t1 t2 */
- abs(p1->timestamp - t2) < thr*60)
+ abs(p1->timestamp - t2) < threshold)
/* t1 t2 p1 p2 */
) {
return;
}
}
- *nearby_tracks = g_list_prepend(*nearby_tracks, key);
+ *nearby_tracks = g_list_prepend(*nearby_tracks, value);
}
/* comparison function used to sort tracks; a and b are hash table keys */
}
}
+// c.f. trw_layer_sorted_track_id_by_name_list
+// but don't add the specified track to the list (normally current track)
+static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer id, const VikTrack *trk, gpointer udata)
+{
+ twt_udata *user_data = udata;
+
+ // Skip self
+ if (trk->trackpoints == user_data->exclude) {
+ return;
+ }
+
+ // Sort named list alphabetically
+ *(user_data->result) = g_list_insert_sorted_with_data (*(user_data->result), trk->name, sort_alphabetically, NULL);
+}
+
+/**
+ * Join - this allows combining 'routes' and 'tracks'
+ * i.e. doesn't care about whether tracks have consistent timestamps
+ * ATM can only append one track at a time to the currently selected track
+ */
+static void trw_layer_append_track ( gpointer pass_along[6] )
+{
+
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+ GList *other_tracks_names = NULL;
+
+ // Sort alphabetically for user presentation
+ // Convert into list of names for usage with dialog function
+ // TODO: Need to consider how to work best when we can have multiple tracks the same name...
+ twt_udata udata;
+ udata.result = &other_tracks_names;
+ udata.exclude = trk->trackpoints;
+
+ g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
+
+ // Note the limit to selecting one track only
+ // this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
+ // (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
+ GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ other_tracks_names,
+ FALSE,
+ _("Append Track"),
+ _("Select the track to append after the current track"));
+
+ g_list_free(other_tracks_names);
+
+ // It's a list, but shouldn't contain more than one other track!
+ if ( append_list ) {
+ GList *l;
+ for (l = append_list; l != NULL; l = g_list_next(l)) {
+ // TODO: at present this uses the first track found by name,
+ // which with potential multiple same named tracks may not be the one selected...
+ VikTrack *append_track = vik_trw_layer_get_track ( vtl, l->data );
+ if ( append_track ) {
+ trk->trackpoints = g_list_concat(trk->trackpoints, append_track->trackpoints);
+ append_track->trackpoints = NULL;
+ vik_trw_layer_delete_track (vtl, append_track);
+ }
+ }
+ for (l = append_list; l != NULL; l = g_list_next(l))
+ g_free(l->data);
+ g_list_free(append_list);
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+ }
+}
+
+/* merge by segments */
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+ guint segments = vik_track_merge_segments ( trk );
+ // NB currently no need to redraw as segments not actually shown on the display
+ // However inform the user of what happened:
+ gchar str[64];
+ const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
+ g_snprintf(str, 64, tmp_str, segments);
+ a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
+}
+
/* merge by time routine */
static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
{
VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
//time_t t1, t2;
- GList *nearby_tracks;
- GList *trps;
- static guint thr = 1;
- guint track_count = 0;
GList *tracks_with_timestamp = NULL;
VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
}
g_list_free(tracks_with_timestamp);
- if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
- _("Merge Threshold..."),
- _("Merge when time between tracks less than:"),
- &thr)) {
+ static guint threshold_in_minutes = 1;
+ if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Merge Threshold..."),
+ _("Merge when time between tracks less than:"),
+ &threshold_in_minutes)) {
return;
}
- /* merge tracks until we can't */
- //VikTrack *track;
- nearby_tracks = NULL;
- do {
- gpointer params[3];
+ // keep attempting to merge all tracks until no merges within the time specified is possible
+ gboolean attempt_merge = TRUE;
+ GList *nearby_tracks = NULL;
+ GList *trps;
+ static gpointer params[3];
+
+ while ( attempt_merge ) {
+
+ // Don't try again unless tracks have changed
+ attempt_merge = FALSE;
- // Need to refind original track incase we've deleted and recreated it??
- //track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
trps = orig_trk->trackpoints;
if ( !trps )
return;
-
if (nearby_tracks) {
g_list_free(nearby_tracks);
nearby_tracks = NULL;
/* g_print("Original track times: %d and %d\n", t1, t2); */
params[0] = &nearby_tracks;
- params[1] = trps;
- params[2] = GUINT_TO_POINTER (thr);
+ params[1] = (gpointer)trps;
+ params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
/* get a list of adjacent-in-time tracks */
- g_hash_table_foreach(vtl->tracks, find_nearby_track, (gpointer)params);
-
- /* add original track */
- nearby_tracks = g_list_prepend(nearby_tracks, orig_trk);
+ g_hash_table_foreach(vtl->tracks, find_nearby_tracks_by_time, params);
/* merge them */
- {
-#define get_track(x) VIK_TRACK(g_hash_table_lookup(vtl->tracks, ((x)->data)))
- GList *l = nearby_tracks;
- // VikTrack *tr = vik_track_new();
- //tr->visible = track->visible;
- track_count = 0;
- while (l) {
- /*
-#define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
-#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
- time_t t1, t2;
- t1 = get_first_trackpoint(l)->timestamp;
- t2 = get_last_trackpoint(l)->timestamp;
+ GList *l = nearby_tracks;
+ while ( l ) {
+ /*
+#define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data)
+#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data)
+ time_t t1, t2;
+ t1 = get_first_trackpoint(l)->timestamp;
+ t2 = get_last_trackpoint(l)->timestamp;
#undef get_first_trackpoint
#undef get_last_trackpoint
- g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
- */
+ g_print(" %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2);
+ */
+ /* remove trackpoints from merged track, delete track */
+ orig_trk->trackpoints = g_list_concat(orig_trk->trackpoints, VIK_TRACK(l->data)->trackpoints);
+ VIK_TRACK(l->data)->trackpoints = NULL;
+ vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
- /* remove trackpoints from merged track, delete track */
- orig_trk->trackpoints = g_list_concat(orig_trk->trackpoints, get_track(l)->trackpoints);
- get_track(l)->trackpoints = NULL;
- vik_trw_layer_delete_track (vtl, l->data);
-
- track_count++;
- l = g_list_next(l);
- }
-#undef get_track
- orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
- //vik_trw_layer_add_track(vtl, strdup(orig_track_name), tr);
+ // Tracks have changed, therefore retry again against all the remaining tracks
+ attempt_merge = TRUE;
+ l = g_list_next(l);
}
- } while (track_count > 1);
+
+ orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
+ }
+
g_list_free(nearby_tracks);
vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
}
+/**
+ * Split a track at the currently selected trackpoint
+ */
+static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl )
+{
+ if ( !vtl->current_tpl )
+ return;
+
+ if ( vtl->current_tpl->next && vtl->current_tpl->prev ) {
+ gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track->name);
+ if ( name ) {
+ VikTrack *tr = vik_track_new ();
+ GList *newglist = g_list_alloc ();
+ newglist->prev = NULL;
+ newglist->next = vtl->current_tpl->next;
+ newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
+ tr->trackpoints = newglist;
+
+ vtl->current_tpl->next->prev = newglist; /* end old track here */
+ vtl->current_tpl->next = NULL;
+
+ vtl->current_tpl = newglist; /* change tp to first of new track. */
+ vtl->current_tp_track = tr;
+
+ tr->visible = TRUE;
+
+ vik_trw_layer_add_track ( vtl, name, tr );
+
+ trku_udata udata;
+ udata.trk = tr;
+ udata.uuid = NULL;
+
+ // Also need id of newly created track
+ gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
+ if ( trkf && udata.uuid )
+ vtl->current_tp_id = udata.uuid;
+ else
+ vtl->current_tp_id = NULL;
+
+ vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
+ }
+ }
+}
+
/* split by time routine */
static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
{
- VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
GList *trps = track->trackpoints;
GList *iter;
GList *newlists = NULL;
GList *newtps = NULL;
- guint i;
static guint thr = 1;
time_t ts, prev_ts;
/* put lists of trackpoints into tracks */
iter = newlists;
- i = 1;
// Only bother updating if the split results in new tracks
if (g_list_length (newlists) > 1) {
while (iter) {
tr->visible = track->visible;
tr->trackpoints = (GList *)(iter->data);
- new_tr_name = g_strdup_printf ("%s #%d", track->name, i++);
- vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
+ new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
+ vik_trw_layer_add_track(vtl, new_tr_name, tr);
/* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
iter = g_list_next(iter);
}
// Remove original track and then update the display
- vik_trw_layer_delete_track (VIK_TRW_LAYER(pass_along[0]), track);
+ vik_trw_layer_delete_track (vtl, track);
vik_layer_emit_update(VIK_LAYER(pass_along[0]), FALSE);
}
g_list_free(newlists);
/* put lists of trackpoints into tracks */
iter = newlists;
- guint i = 1;
// Only bother updating if the split results in new tracks
if (g_list_length (newlists) > 1) {
while (iter) {
tr->visible = track->visible;
tr->trackpoints = (GList *)(iter->data);
- new_tr_name = g_strdup_printf ("%s #%d", track->name, i++);
- vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
+ new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
+ vik_trw_layer_add_track(vtl, new_tr_name, tr);
iter = g_list_next(iter);
}
// Remove original track and then update the display
- vik_trw_layer_delete_track (VIK_TRW_LAYER(pass_along[0]), track);
+ vik_trw_layer_delete_track (vtl, track);
vik_layer_emit_update(VIK_LAYER(pass_along[0]), FALSE);
}
g_list_free(newlists);
}
+/**
+ * Split a track at the currently selected trackpoint
+ */
+static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ trw_layer_split_at_selected_trackpoint ( vtl );
+}
+
+/**
+ * Split a track by its segments
+ */
+static void trw_layer_split_segments ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+ guint ntracks;
+
+ VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
+ gchar *new_tr_name;
+ guint i;
+ for ( i = 0; i < ntracks; i++ ) {
+ if ( tracks[i] ) {
+ new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, trk->name);
+ vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
+ }
+ }
+ if ( tracks ) {
+ g_free ( tracks );
+ // Remove original track
+ vik_trw_layer_delete_track ( vtl, trk );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+ }
+ else {
+ a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments"));
+ }
+}
/* end of split/merge routines */
+/**
+ * Delete adjacent track points at the same position
+ * AKA Delete Dulplicates on the Properties Window
+ */
+static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+ gulong removed = vik_track_remove_dup_points ( trk );
+
+ // Track has been updated so update tps:
+ trw_layer_cancel_tps_of_track ( vtl, trk );
+
+ // Inform user how much was deleted as it's not obvious from the normal view
+ gchar str[64];
+ const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
+ g_snprintf(str, 64, tmp_str, removed);
+ a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
+
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+}
+
+/**
+ * Delete adjacent track points with the same timestamp
+ * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
+ */
+static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+ gulong removed = vik_track_remove_same_time_points ( trk );
+
+ // Track has been updated so update tps:
+ trw_layer_cancel_tps_of_track ( vtl, trk );
+
+ // Inform user how much was deleted as it's not obvious from the normal view
+ gchar str[64];
+ const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
+ g_snprintf(str, 64, tmp_str, removed);
+ a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
+
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+}
+
/**
* Reverse a track
*/
*list = g_list_insert_sorted_with_data (*list, trk->name, sort_alphabetically, NULL);
}
+
+typedef struct {
+ gboolean has_same_track_name;
+ const gchar *same_track_name;
+} same_track_name_udata;
+
+static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
+{
+ const gchar* namea = (const gchar*) aa;
+ const gchar* nameb = (const gchar*) bb;
+
+ // the test
+ gint result = strcmp ( namea, nameb );
+
+ if ( result == 0 ) {
+ // Found two names the same
+ same_track_name_udata *user_data = udata;
+ user_data->has_same_track_name = TRUE;
+ user_data->same_track_name = namea;
+ }
+
+ // Leave ordering the same
+ return 0;
+}
+
+/**
+ * Find out if any tracks have the same name in this layer
+ */
+static gboolean trw_layer_has_same_track_names ( VikTrwLayer *vtl )
+{
+ // Sort items by name, then compare if any next to each other are the same
+
+ GList *track_names = NULL;
+ g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+
+ // No tracks
+ if ( ! track_names )
+ return FALSE;
+
+ same_track_name_udata udata;
+ udata.has_same_track_name = FALSE;
+
+ // Use sort routine to traverse list comparing items
+ // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
+ GList *dummy_list = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
+ // Still no tracks...
+ if ( ! dummy_list )
+ return FALSE;
+
+ return udata.has_same_track_name;
+}
+
+/**
+ * Force unqiue track names for this layer
+ * Note the panel is a required parameter to enable the update of the names displayed
+ */
+static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+ // . Search list for an instance of repeated name
+ // . get track of this name
+ // . create new name
+ // . rename track & update equiv. treeview iter
+ // . repeat until all different
+
+ same_track_name_udata udata;
+
+ GList *track_names = NULL;
+ udata.has_same_track_name = FALSE;
+ udata.same_track_name = NULL;
+
+ g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+
+ // No tracks
+ if ( ! track_names )
+ return;
+
+ GList *dummy_list1 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
+
+ // Still no tracks...
+ if ( ! dummy_list1 )
+ return;
+
+ while ( udata.has_same_track_name ) {
+
+ // Find a track with the same name
+ VikTrack *trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name );
+
+ if ( ! trk ) {
+ // Broken :(
+ g_critical("Houston, we've had a problem.");
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO,
+ _("Internal Error in vik_trw_layer_uniquify_tracks") );
+ return;
+ }
+
+ // Rename it
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, udata.same_track_name );
+ vik_track_set_name ( trk, newname );
+
+ trku_udata udataU;
+ udataU.trk = trk;
+ udataU.uuid = NULL;
+
+ // Need want key of it for treeview update
+ gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+
+ if ( trkf && udataU.uuid ) {
+
+ GtkTreeIter *it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
+
+ if ( it ) {
+ vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+ vik_treeview_sublayer_realphabetize ( VIK_LAYER(vtl)->vt, it, newname );
+#endif
+ }
+ }
+
+ // Start trying to find same names again...
+ track_names = NULL;
+ g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+ udata.has_same_track_name = FALSE;
+ GList *dummy_list2 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
+
+ // No tracks any more - give up searching
+ if ( ! dummy_list2 )
+ udata.has_same_track_name = FALSE;
+ }
+
+ // Update
+ vik_layers_panel_emit_update ( vlp );
+}
+
/**
*
*/
VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
GList *all = NULL;
- // TODO consider disabling this with warning message about
- // not working due to multiple same names
- // enable calling (yet to be defined) uniqify method?
+ // Ensure list of track names offered is unique
+ if ( trw_layer_has_same_track_names ( vtl ) ) {
+ if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
+ vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]) );
+ }
+ else
+ return;
+ }
// Sort list alphabetically for better presentation
g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
if ( delete_list ) {
GList *l;
for (l = delete_list; l != NULL; l = g_list_next(l)) {
- // TODO Hmmm conversion needed here -- not 1:1 relationship any more of name to reference
- // -- new functionality / or need to extend list to have uuid with it / or have uuids and ways to find out the name for display
- // may need to rework the general dialog functions
- // ATM This deletes first trk it finds of that name
+ // This deletes first trk it finds of that name (but uniqueness is enforced above)
trw_layer_delete_track_by_name (vtl, l->data);
}
g_list_free(delete_list);
}
}
+typedef struct {
+ gboolean has_same_waypoint_name;
+ const gchar *same_waypoint_name;
+} same_waypoint_name_udata;
+
+static gint check_waypoints_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
+{
+ const gchar* namea = (const gchar*) aa;
+ const gchar* nameb = (const gchar*) bb;
+
+ // the test
+ gint result = strcmp ( namea, nameb );
+
+ if ( result == 0 ) {
+ // Found two names the same
+ same_waypoint_name_udata *user_data = udata;
+ user_data->has_same_waypoint_name = TRUE;
+ user_data->same_waypoint_name = namea;
+ }
+
+ // Leave ordering the same
+ return 0;
+}
+
+/**
+ * Find out if any waypoints have the same name in this layer
+ */
+gboolean trw_layer_has_same_waypoint_names ( VikTrwLayer *vtl )
+{
+ // Sort items by name, then compare if any next to each other are the same
+
+ GList *waypoint_names = NULL;
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+
+ // No waypoints
+ if ( ! waypoint_names )
+ return FALSE;
+
+ same_waypoint_name_udata udata;
+ udata.has_same_waypoint_name = FALSE;
+
+ // Use sort routine to traverse list comparing items
+ // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
+ GList *dummy_list = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+ // Still no waypoints...
+ if ( ! dummy_list )
+ return FALSE;
+
+ return udata.has_same_waypoint_name;
+}
+
+/**
+ * Force unqiue waypoint names for this layer
+ * Note the panel is a required parameter to enable the update of the names displayed
+ */
+static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+ // . Search list for an instance of repeated name
+ // . get waypoint of this name
+ // . create new name
+ // . rename waypoint & update equiv. treeview iter
+ // . repeat until all different
+
+ same_waypoint_name_udata udata;
+
+ GList *waypoint_names = NULL;
+ udata.has_same_waypoint_name = FALSE;
+ udata.same_waypoint_name = NULL;
+
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+
+ // No waypoints
+ if ( ! waypoint_names )
+ return;
+
+ GList *dummy_list1 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+
+ // Still no waypoints...
+ if ( ! dummy_list1 )
+ return;
+
+ while ( udata.has_same_waypoint_name ) {
+
+ // Find a waypoint with the same name
+ VikWaypoint *waypoint = vik_trw_layer_get_waypoint ( vtl, (gpointer) udata.same_waypoint_name );
+
+ if ( ! waypoint ) {
+ // Broken :(
+ g_critical("Houston, we've had a problem.");
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO,
+ _("Internal Error in vik_trw_layer_uniquify_waypoints") );
+ return;
+ }
+
+ // Rename it
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, udata.same_waypoint_name );
+ vik_waypoint_set_name ( waypoint, newname );
+
+ wpu_udata udataU;
+ udataU.wp = waypoint;
+ udataU.uuid = NULL;
+
+ // Need want key of it for treeview update
+ gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+
+ if ( wpf && udataU.uuid ) {
+
+ GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
+
+ if ( it ) {
+ vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+ vik_treeview_sublayer_realphabetize ( VIK_LAYER(vtl)->vt, it, newname );
+#endif
+ }
+ }
+
+ // Start trying to find same names again...
+ waypoint_names = NULL;
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+ udata.has_same_waypoint_name = FALSE;
+ GList *dummy_list2 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+
+ // No waypoints any more - give up searching
+ if ( ! dummy_list2 )
+ udata.has_same_waypoint_name = FALSE;
+ }
+
+ // Update
+ vik_layers_panel_emit_update ( vlp );
+}
+
/**
*
*/
VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
GList *all = NULL;
- // TODO consider disabling this with warning message about
- // not working due to multiple same names
- // enable calling (yet to be defined) uniqify method?
+ // Ensure list of waypoint names offered is unique
+ if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
+ if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
+ vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) );
+ }
+ else
+ return;
+ }
// Sort list alphabetically for better presentation
g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all);
if ( delete_list ) {
GList *l;
for (l = delete_list; l != NULL; l = g_list_next(l)) {
- // TODO Hmmm conversion needed here -- not 1:1 relationship any more of name to reference
- // -- new functionality / or need to extend list to have uuid with it / or have uuids and ways to find out the name for display
- // may need to rework the general dialog functions
- // ARM This deletes first WP it finds of that name
+ // This deletes first waypoint it finds of that name (but uniqueness is enforced above)
trw_layer_delete_waypoint_by_name (vtl, l->data);
}
g_list_free(delete_list);
if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
{
- GtkWidget *goto_submenu;
item = gtk_menu_item_new ();
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_widget_show ( item );
+
+ GtkWidget *goto_submenu;
goto_submenu = gtk_menu_new ();
item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
gtk_widget_show ( item );
- item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
- gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ GtkWidget *combine_submenu;
+ combine_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Co_mbine") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU) );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show ( item );
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), combine_submenu );
item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
gtk_widget_show ( item );
item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
gtk_widget_show ( item );
+ item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
+ gtk_widget_show ( item );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
+ gtk_widget_show ( item );
+
+ GtkWidget *split_submenu;
+ split_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Split") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU) );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), split_submenu );
+
item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
gtk_widget_show ( item );
item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
+ gtk_widget_show ( item );
+
+ // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy
+ item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
+ gtk_widget_show ( item );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Split at _Trackpoint") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_at_trackpoint), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
+ gtk_widget_show ( item );
+ // Make it available only when a trackpoint is selected.
+ gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
+
+ GtkWidget *delete_submenu;
+ delete_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+ gtk_widget_show ( item );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Time") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_time), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
gtk_widget_show ( item );
item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
+#endif
#ifdef VIK_CONFIG_OPENSTREETMAP
item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
}
}
-/* to be called when last_tpl no longer exists. */
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
-{
- if ( vtl->tpwin ) /* can't join with a non-existant TP. */
- vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
- vtl->last_tpl = NULL;
- vtl->last_tp_track = NULL;
-}
-
static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
{
if ( vtl->tpwin )
if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
{
- gchar *name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track->name);
- if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks, name ) ) )
- {
- VikTrack *tr = vik_track_new ();
- GList *newglist = g_list_alloc ();
- newglist->prev = NULL;
- newglist->next = vtl->current_tpl->next;
- newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
- tr->trackpoints = newglist;
-
- vtl->current_tpl->next->prev = newglist; /* end old track here */
- vtl->current_tpl->next = NULL;
-
- vtl->current_tpl = newglist; /* change tp to first of new track. */
- vtl->current_tp_track->name = name;
-
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
-
- tr->visible = TRUE;
-
- vik_trw_layer_add_track ( vtl, name, tr );
- vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
- }
+ trw_layer_split_at_selected_trackpoint ( vtl );
+ vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
}
else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
{
return;
GList *new_tpl;
- /* can't join with a non-existent trackpoint */
- vtl->last_tpl = NULL;
- vtl->last_tp_track = NULL;
+ // Find available adjacent trackpoint
if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
{
if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
- tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl ); /* this nulls current_tpl->prev and next */
+ // Delete current trackpoint
+ vik_trackpoint_free ( vtl->current_tpl->data );
+ tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
- /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
+ // Set to current to the available adjacent trackpoint
+ vtl->current_tpl = new_tpl;
+
+ // Reset dialog with the available adjacent trackpoint
if ( vtl->current_tp_track )
vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name );
- trw_layer_cancel_last_tp ( vtl );
-
- g_free ( vtl->current_tpl->data ); /* TODO: vik_trackpoint_free() */
- g_list_free_1 ( vtl->current_tpl );
- vtl->current_tpl = new_tpl;
vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
}
else
{
- tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl );
- g_free ( vtl->current_tpl->data ); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
- g_list_free_1 ( vtl->current_tpl );
+ // Delete current trackpoint
+ vik_trackpoint_free ( vtl->current_tpl->data );
+ tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
trw_layer_cancel_current_tp ( vtl, FALSE );
}
}
else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
{
- vtl->last_tpl = vtl->current_tpl;
if ( vtl->current_tp_track )
vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name );
vik_layer_emit_update(VIK_LAYER(vtl), FALSE); /* TODO longone: either move or only update if tp is inside drawing window */
}
else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
{
- vtl->last_tpl = vtl->current_tpl;
if ( vtl->current_tp_track )
vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name );
vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
}
- else if ( response == VIK_TRW_LAYER_TPWIN_JOIN )
- {
- // Check tracks exist and are different before joining
- if ( ! vtl->last_tp_track || ! vtl->current_tp_track || vtl->last_tp_track == vtl->current_tp_track )
- return;
-
- VikTrack *tr1 = vtl->last_tp_track;
- VikTrack *tr2 = vtl->current_tp_track;
-
- VikTrack *tr_first = tr1, *tr_last = tr2;
-
- if ( (!vtl->last_tpl->next) && (!vtl->current_tpl->next) ) /* both endpoints */
- vik_track_reverse ( tr2 ); /* reverse the second, that way second track clicked will be later. */
- else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->prev) )
- vik_track_reverse ( tr1 );
- else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->next) ) /* clicked startpoint, then endpoint -- concat end to start */
- {
- tr_first = tr2;
- tr_last = tr1;
- }
- /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
-
- 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. */
- VIK_TRACKPOINT(tr_last->trackpoints->data)->newsegment = FALSE;
- tr1->trackpoints = g_list_concat ( tr_first->trackpoints, tr_last->trackpoints );
- tr2->trackpoints = NULL;
-
- vtl->current_tp_track = vtl->last_tp_track; /* current_tp stays the same (believe it or not!) */
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
-
- /* if we did this before, trw_layer_delete_track would have canceled the current tp because
- * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
- vik_trw_layer_delete_track ( vtl, vtl->current_tp_track );
-
- trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
- vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
- }
else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
{
trw_layer_insert_tp_after_current_tp ( vtl );
if ( vtl->tpwin )
if ( vtl->current_tp_track )
vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
-
- // Don't really know what this is for but seems like it might be handy...
- /* can't join with itself! */
- trw_layer_cancel_last_tp ( vtl );
}
}
VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
if ( track && track->visible ) {
- if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
+ if ( track->name ) {
if ( vtl->track_right_click_menu )
- gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
+ gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
- trw_layer_sublayer_add_menu_items ( vtl,
- vtl->track_right_click_menu,
- NULL,
- VIK_TRW_LAYER_SUBLAYER_TRACK,
- vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
- g_hash_table_lookup ( vtl->tracks_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
- vvp);
+ trku_udata udataU;
+ udataU.trk = track;
+ udataU.uuid = NULL;
+
+ gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+
+ if ( trkf && udataU.uuid ) {
+
+ GtkTreeIter *iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
+
+ trw_layer_sublayer_add_menu_items ( vtl,
+ vtl->track_right_click_menu,
+ NULL,
+ VIK_TRW_LAYER_SUBLAYER_TRACK,
+ udataU.uuid,
+ iter,
+ vvp );
+ }
gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
/* See if a waypoint is selected */
VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
if ( waypoint && waypoint->visible ) {
- if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
+ if ( waypoint->name ) {
if ( vtl->wp_right_click_menu )
- gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
+ gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
- trw_layer_sublayer_add_menu_items ( vtl,
- vtl->wp_right_click_menu,
- NULL,
- VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
- vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
- g_hash_table_lookup ( vtl->waypoints_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
- vvp);
+
+ wpu_udata udata;
+ udata.wp = waypoint;
+ udata.uuid = NULL;
+
+ gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+ if ( wpf && udata.uuid ) {
+ GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+
+ trw_layer_sublayer_add_menu_items ( vtl,
+ vtl->wp_right_click_menu,
+ NULL,
+ VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
+ udata.uuid,
+ iter,
+ vvp );
+ }
gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
return TRUE;
typedef struct {
VikTrwLayer *vtl;
- VikViewport *vvp;
- gint x1,y1,x2,y2,x3,y3;
- const gchar* str;
-} new_track_move_passalong_t;
-
-/* sync and undraw, but only when we have time */
-static gboolean ct_sync ( gpointer passalong )
-{
- new_track_move_passalong_t *p = (new_track_move_passalong_t *) passalong;
+ GdkDrawable *drawable;
+ GdkGC *gc;
+ GdkPixmap *pixmap;
+} draw_sync_t;
- vik_viewport_sync ( p->vvp );
- gdk_gc_set_function ( p->vtl->current_track_gc, GDK_INVERT );
- vik_viewport_draw_line ( p->vvp, p->vtl->current_track_gc, p->x1, p->y1, p->x2, p->y2 );
- vik_viewport_draw_string (p->vvp, gdk_font_from_description (pango_font_description_from_string ("Sans 8")), p->vtl->current_track_gc, p->x3, p->y3, p->str);
- gdk_gc_set_function ( p->vtl->current_track_gc, GDK_COPY );
-
- g_free ( (gpointer) p->str ) ;
- p->vtl->ct_sync_done = TRUE;
- g_free ( p );
+/*
+ * Draw specified pixmap
+ */
+static gboolean draw_sync ( gpointer data )
+{
+ draw_sync_t *ds = (draw_sync_t*) data;
+ // Sometimes don't want to draw
+ // normally because another update has taken precedent such as panning the display
+ // which means this pixmap is no longer valid
+ if ( ds->vtl->draw_sync_do ) {
+ gdk_threads_enter();
+ gdk_draw_drawable (ds->drawable,
+ ds->gc,
+ ds->pixmap,
+ 0, 0, 0, 0, -1, -1);
+ ds->vtl->draw_sync_done = TRUE;
+ gdk_threads_leave();
+ }
return FALSE;
}
static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
{
/* if we haven't sync'ed yet, we don't have time to do more. */
- if ( vtl->ct_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
- GList *iter = vtl->current_track->trackpoints;
- new_track_move_passalong_t *passalong;
+ if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
+ GList *iter = g_list_last ( vtl->current_track->trackpoints );
+
+ static GdkPixmap *pixmap = NULL;
+ int w1, h1, w2, h2;
+ // Need to check in case window has been resized
+ w1 = vik_viewport_get_width(vvp);
+ h1 = vik_viewport_get_height(vvp);
+ if (!pixmap) {
+ pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+ }
+ gdk_drawable_get_size (pixmap, &w2, &h2);
+ if (w1 != w2 || h1 != h2) {
+ g_object_unref ( G_OBJECT ( pixmap ) );
+ pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+ }
+
+ // Reset to background
+ gdk_draw_drawable (pixmap,
+ vtl->current_track_newpoint_gc,
+ vik_viewport_get_pixmap(vvp),
+ 0, 0, 0, 0, -1, -1);
+
+ draw_sync_t *passalong;
gint x1, y1;
- while ( iter->next )
- iter = iter->next;
- gdk_gc_set_function ( vtl->current_track_gc, GDK_INVERT );
vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
- vik_viewport_draw_line ( vvp, vtl->current_track_gc, x1, y1, event->x, event->y );
+
+ // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method)
+ // otherwise using vik_viewport_draw_* functions puts the data into the base pixmap,
+ // thus when we come to reset to the background it would include what we have already drawn!!
+ gdk_draw_line ( pixmap,
+ vtl->current_track_newpoint_gc,
+ x1, y1, event->x, event->y );
+ // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
/* Find out actual distance of current track */
gdouble distance = vik_track_get_length (vtl->current_track);
/* offset from cursor a bit */
xd = event->x + 10;
yd = event->y - 10;
- /* note attempted setting text using pango layouts - but the 'undraw' technique didn't work */
- vik_viewport_draw_string (vvp, gdk_font_from_description (pango_font_description_from_string ("Sans 8")), vtl->current_track_gc, xd, yd, str);
- gdk_gc_set_function ( vtl->current_track_gc, GDK_COPY );
+ PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
+ PangoFontDescription *pfd = pango_font_description_from_string ("Sans 8"); // FIXME: settable option? global variable?
+ pango_layout_set_font_description (pl, pfd);
+ pango_font_description_free (pfd);
- passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
+ pango_layout_set_text (pl, str, -1);
+ gint wd, hd;
+ pango_layout_get_pixel_size ( pl, &wd, &hd );
+
+ // Create a background block to make the text easier to read over the background map
+ GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
+ gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
+ gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
+
+ g_object_unref ( G_OBJECT ( pl ) );
+ g_object_unref ( G_OBJECT ( background_block_gc ) );
+
+ passalong = g_new(draw_sync_t,1); // freed by draw_sync()
passalong->vtl = vtl;
- passalong->vvp = vvp;
- passalong->x1 = x1;
- passalong->y1 = y1;
- passalong->x2 = event->x;
- passalong->y2 = event->y;
- passalong->x3 = xd;
- passalong->y3 = yd;
- passalong->str = str;
+ passalong->pixmap = pixmap;
+ passalong->drawable = GTK_WIDGET(vvp)->window;
+ passalong->gc = vtl->current_track_newpoint_gc;
// Update statusbar with full gain/loss information
statusbar_write (str, elev_gain, elev_loss, vtl);
- /* this will sync and undraw when we have time to */
- g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, ct_sync, passalong, NULL);
- vtl->ct_sync_done = FALSE;
+ g_free ((gpointer)str);
+
+ // draw pixmap when we have time to
+ g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
+ vtl->draw_sync_done = FALSE;
return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
}
return VIK_LAYER_TOOL_ACK;
if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
return FALSE;
+ if ( event->button == 2 ) {
+ // As the display is panning, the new track pixmap is now invalid so don't draw it
+ // otherwise this drawing done results in flickering back to an old image
+ vtl->draw_sync_do = FALSE;
+ return FALSE;
+ }
+
if ( event->button == 3 && vtl->current_track )
{
/* undo */
if ( ! vtl->current_track )
{
- gchar *name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
+ gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name ) ) )
{
vtl->current_track = vik_track_new();
return TRUE;
}
+static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+ if ( event->button == 2 ) {
+ // Pan moving ended - enable potential point drawing again
+ vtl->draw_sync_do = TRUE;
+ vtl->draw_sync_done = TRUE;
+ }
+}
+
/*** New waypoint ****/
static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
return TRUE;
}
- vtl->last_tpl = vtl->current_tpl;
- vtl->last_tp_track = vtl->current_tp_track;
}
g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms);
vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, params.closest_track_id ), TRUE );
vtl->current_tpl = params.closest_tpl;
vtl->current_tp_id = params.closest_track_id;
+ vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, params.closest_track_id );
trw_layer_tpwin_init ( vtl );
set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
/* diff dist is diff from orig */
if ( vtl->tpwin )
vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
- /* can't join with itself! */
- trw_layer_cancel_last_tp ( vtl );
vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
/*** Route Finder ***/
static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
{
}
return TRUE;
}
+#endif
/*** Show picture ****/
{
/* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
#ifdef WINDOWS
- ShellExecute(NULL, NULL, (char *) pass_along[5], NULL, ".\\", 0);
+ ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL);
#else /* WINDOWS */
GError *err = NULL;
gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
return vtl->coord_mode;
}
-
+/**
+ * Uniquify the whole layer
+ * Also requires the layers panel as the names shown there need updating too
+ * Returns whether the operation was successful or not
+ */
+gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+ if ( vtl && vlp ) {
+ vik_trw_layer_uniquify_tracks ( vtl, vlp );
+ vik_trw_layer_uniquify_waypoints ( vtl, vlp );
+ return TRUE;
+ }
+ return FALSE;
+}
static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode )
{