X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/60626a3efdf1be7b641c68458b3e430aa87369a5..bd78ae7d70bd7388d4950f3e7331b72f84eab208:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index 437434a1..a5d79e1d 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -132,6 +132,7 @@ struct _VikTrwLayer { gboolean tracks_visible, routes_visible, waypoints_visible; LatLonBBox waypoints_bbox; + gboolean track_draw_labels; guint8 drawmode; guint8 drawpoints; guint8 drawpoints_size; @@ -146,6 +147,10 @@ struct _VikTrwLayer { guint8 bg_line_thickness; vik_layer_sort_order_t track_sort_order; + PangoLayout *tracklabellayout; + font_size_t track_font_size; + gchar *track_fsize_str; + guint8 wp_symbol; guint8 wp_size; gboolean wp_draw_symbols; @@ -455,8 +460,8 @@ enum { /****** PARAMETERS ******/ -static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") }; -enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES }; +static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced") }; +enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV }; static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL }; static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 }; @@ -517,6 +522,7 @@ static VikLayerParamData elevation_factor_default ( void ) { return VIK_LPD_UINT static VikLayerParamData stop_length_default ( void ) { return VIK_LPD_UINT ( 60 ); } static VikLayerParamData speed_factor_default ( void ) { return VIK_LPD_DOUBLE ( 30.0 ); } +static VikLayerParamData tnfontsize_default ( void ) { return VIK_LPD_UINT ( FS_MEDIUM ); } static VikLayerParamData wpfontsize_default ( void ) { return VIK_LPD_UINT ( FS_MEDIUM ); } static VikLayerParamData wptextcolor_default ( void ) { VikLayerParamData data; gdk_color_parse ( "#FFFFFF", &data.c ); return data; // White @@ -538,28 +544,29 @@ VikLayerParam trw_layer_params[] = { { VIK_LAYER_TRW, "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, { VIK_LAYER_TRW, "routes_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, + { VIK_LAYER_TRW, "trackdrawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, + N_("Note: the individual track controls what labels may be displayed"), vik_lpd_true_default, NULL, NULL }, + { VIK_LAYER_TRW, "trackfontsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Labels Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, tnfontsize_default, NULL, NULL }, { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default, NULL, NULL }, { VIK_LAYER_TRW, "trackcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("All Tracks Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, N_("The color used when 'All Tracks Same Color' drawing mode is selected"), black_color_default, NULL, NULL }, { VIK_LAYER_TRW, "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, - { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[0], NULL, NULL, line_thickness_default, NULL, NULL }, + { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[0], NULL, NULL, line_thickness_default, NULL, NULL }, { VIK_LAYER_TRW, "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL }, - { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL }, + { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL }, { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, - { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL }, + { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL }, { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL }, - { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL }, - + { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL }, { VIK_LAYER_TRW, "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, N_("Whether to draw a marker when trackpoints are at the same position but over the minimum stop length apart in time"), vik_lpd_false_default, NULL, NULL }, - { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[8], NULL, NULL, stop_length_default, NULL, NULL }, + { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[8], NULL, NULL, stop_length_default, NULL, NULL }, - { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL }, - { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL }, - { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[1], NULL, + { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL }, + { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS_ADV, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL }, + { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS_ADV, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[1], NULL, N_("The percentage factor away from the average speed determining the color used"), speed_factor_default, NULL, NULL }, - - { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL }, + { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS_ADV, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL }, { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, { VIK_LAYER_TRW, "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, wpfontsize_default, NULL, NULL }, @@ -585,6 +592,8 @@ enum { PARAM_WV, PARAM_RV, // Tracks + PARAM_TDL, + PARAM_TLFONTSIZE, PARAM_DM, PARAM_TC, PARAM_DL, @@ -932,6 +941,22 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara case PARAM_TV: vtl->tracks_visible = data.b; break; case PARAM_WV: vtl->waypoints_visible = data.b; break; case PARAM_RV: vtl->routes_visible = data.b; break; + case PARAM_TDL: vtl->track_draw_labels = data.b; break; + case PARAM_TLFONTSIZE: + if ( data.u < FS_NUM_SIZES ) { + vtl->track_font_size = data.u; + g_free ( vtl->track_fsize_str ); + switch ( vtl->track_font_size ) { + case FS_XX_SMALL: vtl->track_fsize_str = g_strdup ( "xx-small" ); break; + case FS_X_SMALL: vtl->track_fsize_str = g_strdup ( "x-small" ); break; + case FS_SMALL: vtl->track_fsize_str = g_strdup ( "small" ); break; + case FS_LARGE: vtl->track_fsize_str = g_strdup ( "large" ); break; + case FS_X_LARGE: vtl->track_fsize_str = g_strdup ( "x-large" ); break; + case FS_XX_LARGE: vtl->track_fsize_str = g_strdup ( "xx-large" ); break; + default: vtl->track_fsize_str = g_strdup ( "medium" ); break; + } + } + break; case PARAM_DM: vtl->drawmode = data.u; break; case PARAM_TC: vtl->track_color = data.c; @@ -1041,6 +1066,8 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo case PARAM_TV: rv.b = vtl->tracks_visible; break; case PARAM_WV: rv.b = vtl->waypoints_visible; break; case PARAM_RV: rv.b = vtl->routes_visible; break; + case PARAM_TDL: rv.b = vtl->track_draw_labels; break; + case PARAM_TLFONTSIZE: rv.u = vtl->track_font_size; break; case PARAM_DM: rv.u = vtl->drawmode; break; case PARAM_TC: rv.c = vtl->track_color; break; case PARAM_DP: rv.b = vtl->drawpoints; break; @@ -1288,6 +1315,9 @@ static void trw_layer_free ( VikTrwLayer *trwlayer ) if ( trwlayer->track_right_click_menu ) g_object_ref_sink ( G_OBJECT(trwlayer->track_right_click_menu) ); + if ( trwlayer->tracklabellayout != NULL) + g_object_unref ( G_OBJECT ( trwlayer->tracklabellayout ) ); + if ( trwlayer->wplabellayout != NULL) g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) ); @@ -1301,6 +1331,7 @@ static void trw_layer_free ( VikTrwLayer *trwlayer ) g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) ); g_free ( trwlayer->wp_fsize_str ); + g_free ( trwlayer->track_fsize_str ); if ( trwlayer->tpwin != NULL ) gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) ); @@ -1386,6 +1417,262 @@ static void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y vik_viewport_draw_line ( vvp, gc, x+5, y-5, x-5, y+5 ); } + +static void trw_layer_draw_track_label ( gchar *name, gchar *fgcolour, gchar *bgcolour, struct DrawingParams *dp, VikCoord *coord ) +{ + gchar *label_markup = g_strdup_printf ( "%s", fgcolour, bgcolour, dp->vtl->track_fsize_str, name ); + + if ( pango_parse_markup ( label_markup, -1, 0, NULL, NULL, NULL, NULL ) ) + pango_layout_set_markup ( dp->vtl->tracklabellayout, label_markup, -1 ); + else + // Fallback if parse failure + pango_layout_set_text ( dp->vtl->tracklabellayout, name, -1 ); + + g_free ( label_markup ); + + gint label_x, label_y; + gint width, height; + pango_layout_get_pixel_size ( dp->vtl->tracklabellayout, &width, &height ); + + vik_viewport_coord_to_screen ( dp->vp, coord, &label_x, &label_y ); + vik_viewport_draw_layout ( dp->vp, dp->vtl->track_bg_gc, label_x-width/2, label_y-height/2, dp->vtl->tracklabellayout ); +} + +/** + * distance_in_preferred_units: + * @dist: The source distance in standard SI Units (i.e. metres) + * + * TODO: This is a generic function that could be moved into globals.c or utils.c + * + * Probably best used if you have a only few conversions to perform. + * However if doing many points (such as on all points along a track) then this may be a bit slow, + * since it will be doing the preference check on each call + * + * Returns: The distance in the units as specified by the preferences + */ +static gdouble distance_in_preferred_units ( gdouble dist ) +{ + gdouble mydist; + vik_units_distance_t dist_units = a_vik_get_units_distance (); + switch (dist_units) { + case VIK_UNITS_DISTANCE_MILES: + mydist = VIK_METERS_TO_MILES(dist); + break; + // VIK_UNITS_DISTANCE_KILOMETRES: + default: + mydist = dist/1000.0; + break; + } + return mydist; +} + +/** + * trw_layer_draw_dist_labels: + * + * Draw a few labels along a track at nicely seperated distances + * This might slow things down if there's many tracks being displayed with this on. + */ +static void trw_layer_draw_dist_labels ( struct DrawingParams *dp, VikTrack *trk, gboolean drawing_highlight ) +{ + static const gdouble chunksd[] = {0.25, 0.5, 1.0, 2.0, 5.0, 10.0, 15.0, 20.0, + 25.0, 40.0, 50.0, 75.0, 100.0, + 150.0, 200.0, 250.0, 500.0, 1000.0}; + + gdouble dist = vik_track_get_length_including_gaps ( trk ) / (trk->max_number_dist_labels+1); + + // Convert to specified unit to find the friendly breakdown value + dist = distance_in_preferred_units ( dist ); + + gint index = 0; + gint i=0; + for ( i = 0; i < G_N_ELEMENTS(chunksd); i++ ) { + if ( chunksd[i] > dist ) { + index = i; + dist = chunksd[index]; + break; + } + } + + vik_units_distance_t dist_units = a_vik_get_units_distance (); + + for ( i = 1; i < trk->max_number_dist_labels+1; i++ ) { + gdouble dist_i = dist * i; + + // Convert distance back into metres for use in finding a trackpoint + switch (dist_units) { + case VIK_UNITS_DISTANCE_MILES: + dist_i = VIK_MILES_TO_METERS(dist_i); + break; + // VIK_UNITS_DISTANCE_KILOMETRES: + default: + dist_i = dist_i*1000.0; + break; + } + + gdouble dist_current = 0.0; + VikTrackpoint *tp_current = vik_track_get_tp_by_dist ( trk, dist_i, FALSE, &dist_current ); + gdouble dist_next = 0.0; + VikTrackpoint *tp_next = vik_track_get_tp_by_dist ( trk, dist_i, TRUE, &dist_next ); + + gdouble dist_between_tps = fabs (dist_next - dist_current); + gdouble ratio = 0.0; + // Prevent division by 0 errors + if ( dist_between_tps > 0.0 ) + ratio = fabs(dist_i-dist_current)/dist_between_tps; + + if ( tp_current && tp_next ) { + // Construct the name based on the distance value + gchar *name; + gchar *units; + switch (dist_units) { + case VIK_UNITS_DISTANCE_MILES: + units = g_strdup ( _("miles") ); + break; + // VIK_UNITS_DISTANCE_KILOMETRES: + default: + units = g_strdup ( _("km") ); + break; + } + + // Convert for display + dist_i = distance_in_preferred_units ( dist_i ); + + // Make the precision of the output related to the unit size. + if ( index == 0 ) + name = g_strdup_printf ( "%.2f %s", dist_i, units); + else if ( index == 1 ) + name = g_strdup_printf ( "%.1f %s", dist_i, units); + else + name = g_strdup_printf ( "%d %s", (gint)round(dist_i), units); // TODO single vs plurals + g_free ( units ); + + struct LatLon ll_current, ll_next; + vik_coord_to_latlon ( &tp_current->coord, &ll_current ); + vik_coord_to_latlon ( &tp_next->coord, &ll_next ); + + // positional interpolation + // Using a simple ratio - may not be perfectly correct due to lat/long projections + // but should be good enough over the small scale that I anticipate usage on + struct LatLon ll_new = { ll_current.lat + (ll_next.lat-ll_current.lat)*ratio, + ll_current.lon + (ll_next.lon-ll_current.lon)*ratio }; + VikCoord coord; + vik_coord_load_from_latlon ( &coord, dp->vtl->coord_mode, &ll_new ); + + gchar *fgcolour; + if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK ) + fgcolour = gdk_color_to_string ( &(trk->color) ); + else + fgcolour = gdk_color_to_string ( &(dp->vtl->track_color) ); + + // if highlight mode on, then colour the background in the highlight colour + gchar *bgcolour; + if ( drawing_highlight ) + bgcolour = g_strdup ( vik_viewport_get_highlight_color ( dp->vp ) ); + else + bgcolour = gdk_color_to_string ( &(dp->vtl->track_bg_color) ); + + trw_layer_draw_track_label ( name, fgcolour, bgcolour, dp, &coord ); + + g_free ( fgcolour ); + g_free ( bgcolour ); + g_free ( name ); + } + } +} + +/** + * trw_layer_draw_track_name_labels: + * + * Draw a label (or labels) for the track name somewhere depending on the track's properties + */ +static void trw_layer_draw_track_name_labels ( struct DrawingParams *dp, VikTrack *trk, gboolean drawing_highlight ) +{ + gchar *fgcolour; + if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK ) + fgcolour = gdk_color_to_string ( &(trk->color) ); + else + fgcolour = gdk_color_to_string ( &(dp->vtl->track_color) ); + + // if highlight mode on, then colour the background in the highlight colour + gchar *bgcolour; + if ( drawing_highlight ) + bgcolour = g_strdup ( vik_viewport_get_highlight_color ( dp->vp ) ); + else + bgcolour = gdk_color_to_string ( &(dp->vtl->track_bg_color) ); + + gchar *ename = g_markup_escape_text ( trk->name, -1 ); + + if ( trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE || + trk->draw_name_mode == TRACK_DRAWNAME_CENTRE ) { + struct LatLon average, maxmin[2] = { {0,0}, {0,0} }; + trw_layer_find_maxmin_tracks ( NULL, trk, maxmin ); + average.lat = (maxmin[0].lat+maxmin[1].lat)/2; + average.lon = (maxmin[0].lon+maxmin[1].lon)/2; + VikCoord coord; + vik_coord_load_from_latlon ( &coord, dp->vtl->coord_mode, &average ); + + trw_layer_draw_track_label ( ename, fgcolour, bgcolour, dp, &coord ); + } + + if ( trk->draw_name_mode == TRACK_DRAWNAME_CENTRE ) + // No other labels to draw + return; + + GList *ending = g_list_last ( trk->trackpoints ); + VikCoord begin_coord = VIK_TRACKPOINT(trk->trackpoints->data)->coord; + VikCoord end_coord = VIK_TRACKPOINT(ending->data)->coord; + + gboolean done_start_end = FALSE; + + if ( trk->draw_name_mode == TRACK_DRAWNAME_START_END || + trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ) { + + // This number can be configured via the settings if you really want to change it + gdouble distance_diff; + if ( ! a_settings_get_double ( "trackwaypoint_start_end_distance_diff", &distance_diff ) ) + distance_diff = 100.0; // Metres + + if ( vik_coord_diff ( &begin_coord, &end_coord ) < distance_diff ) { + // Start and end 'close' together so only draw one label at an average location + gint x1, x2, y1, y2; + vik_viewport_coord_to_screen ( dp->vp, &begin_coord, &x1, &y1); + vik_viewport_coord_to_screen ( dp->vp, &end_coord, &x2, &y2); + VikCoord av_coord; + vik_viewport_screen_to_coord ( dp->vp, (x1 + x2) / 2, (y1 + y2) / 2, &av_coord ); + + gchar *name = g_strdup_printf ( "%s: %s", ename, _("start/end") ); + trw_layer_draw_track_label ( name, fgcolour, bgcolour, dp, &av_coord ); + g_free ( name ); + + done_start_end = TRUE; + } + } + + if ( ! done_start_end ) { + if ( trk->draw_name_mode == TRACK_DRAWNAME_START || + trk->draw_name_mode == TRACK_DRAWNAME_START_END || + trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ) { + gchar *name_start = g_strdup_printf ( "%s: %s", ename, _("start") ); + trw_layer_draw_track_label ( name_start, fgcolour, bgcolour, dp, &begin_coord ); + g_free ( name_start ); + } + // Don't draw end label if this is the one being created + if ( trk != dp->vtl->current_track ) { + if ( trk->draw_name_mode == TRACK_DRAWNAME_END || + trk->draw_name_mode == TRACK_DRAWNAME_START_END || + trk->draw_name_mode == TRACK_DRAWNAME_START_END_CENTRE ) { + gchar *name_end = g_strdup_printf ( "%s: %s", ename, _("end") ); + trw_layer_draw_track_label ( name_end, fgcolour, bgcolour, dp, &end_coord ); + g_free ( name_end ); + } + } + } + + g_free ( fgcolour ); + g_free ( bgcolour ); + g_free ( ename ); +} + static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline ) { if ( ! track->visible ) @@ -1647,6 +1934,17 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr useoldvals = FALSE; } } + + // Labels drawn after the trackpoints, so the labels are on top + if ( dp->vtl->track_draw_labels ) { + if ( track->max_number_dist_labels > 0 ) { + trw_layer_draw_dist_labels ( dp, track, drawing_highlight ); + } + + if ( track->draw_name_mode != TRACK_DRAWNAME_NO ) { + trw_layer_draw_track_name_labels ( dp, track, drawing_highlight ); + } + } } } @@ -1934,6 +2232,9 @@ static VikTrwLayer* trw_layer_create ( VikViewport *vp ) rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL); pango_layout_set_font_description (rv->wplabellayout, gtk_widget_get_style(GTK_WIDGET(vp))->font_desc); + rv->tracklabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL); + pango_layout_set_font_description (rv->tracklabellayout, gtk_widget_get_style(GTK_WIDGET(vp))->font_desc); + trw_layer_new_track_gcs ( rv, vp ); rv->waypoint_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_color), 2 ); @@ -2923,9 +3224,7 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC wp->coord = *def_coord; // Attempt to auto set height if DEM data is available - gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST ); - if ( elev != VIK_DEM_INVALID_ELEVATION ) - wp->altitude = (gdouble)elev; + vik_waypoint_apply_dem_data ( wp, TRUE ); returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated ); @@ -3243,6 +3542,7 @@ static void trw_layer_new_wp ( gpointer lav[2] ) static void new_track_create_common ( VikTrwLayer *vtl, gchar *name ) { vtl->current_track = vik_track_new(); + vik_track_set_defaults ( vtl->current_track ); vtl->current_track->visible = TRUE; if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR ) // Create track with the preferred colour from the layer properties @@ -3269,6 +3569,7 @@ static void trw_layer_new_track ( gpointer lav[2] ) static void new_route_create_common ( VikTrwLayer *vtl, gchar *name ) { vtl->current_track = vik_track_new(); + vik_track_set_defaults ( vtl->current_track ); vtl->current_track->visible = TRUE; vtl->current_track->is_route = TRUE; // By default make all routes red @@ -4285,7 +4586,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) // Get confirmation from the user // Maybe this Waypoint Delete should be optional as is it could get annoying... if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - _("Are you sure you want to delete the waypoint \"%s\""), + _("Are you sure you want to delete the waypoint \"%s\"?"), wp->name ) ) return; was_visible = trw_layer_delete_waypoint ( vtl, wp ); @@ -4298,7 +4599,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) if ( GPOINTER_TO_INT ( pass_along[4]) ) // Get confirmation from the user if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - _("Are you sure you want to delete the track \"%s\""), + _("Are you sure you want to delete the track \"%s\"?"), trk->name ) ) return; was_visible = vik_trw_layer_delete_track ( vtl, trk ); @@ -4311,7 +4612,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) if ( GPOINTER_TO_INT ( pass_along[4]) ) // Get confirmation from the user if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - _("Are you sure you want to delete the route \"%s\""), + _("Are you sure you want to delete the route \"%s\"?"), trk->name ) ) return; was_visible = vik_trw_layer_delete_route ( vtl, trk ); @@ -4382,11 +4683,39 @@ static void trw_layer_properties_item ( gpointer pass_along[7] ) tr, pass_along[1], /* vlp */ pass_along[5], /* vvp */ - pass_along[6]); /* iter */ + pass_along[6], /* iter */ + FALSE ); } } } +/** + * trw_layer_track_statistics: + * + * Show track statistics. + * ATM jump to the stats page in the properties + * TODO: consider separating the stats into an individual dialog? + */ +static void trw_layer_track_statistics ( gpointer pass_along[7] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) + trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + else + trk = g_hash_table_lookup ( vtl->routes, pass_along[3] ); + + if ( trk && trk->name ) { + vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl, + trk, + pass_along[1], // vlp + pass_along[5], // vvp + pass_along[6], // iter + TRUE ); + } +} + /* * Update the treeview of the track id - primarily to update the icon */ @@ -4529,6 +4858,18 @@ static void trw_layer_convert_track_route ( gpointer pass_along[6] ) vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); } +static void trw_layer_anonymize_times ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( track ) + vik_track_anonymize_times ( track ); +} static void trw_layer_extend_track_end ( gpointer pass_along[6] ) { @@ -4570,10 +4911,43 @@ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] ) } -static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) +/** + * + */ +static gboolean trw_layer_dem_test ( VikTrwLayer *vtl, VikLayersPanel *vlp ) +{ + // If have a vlp then perform a basic test to see if any DEM info available... + if ( vlp ) { + GList *dems = vik_layers_panel_get_all_layers_of_type (vlp, VIK_LAYER_DEM, TRUE); // Includes hidden DEM layer types + + if ( !g_list_length(dems) ) { + a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No DEM layers available, thus no DEM values can be applied.") ); + return FALSE; + } + } + return TRUE; +} + +/** + * apply_dem_data_common: + * + * A common function for applying the DEM values and reporting the results. + */ +static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTrack *track, gboolean skip_existing_elevations ) +{ + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gulong changed = vik_track_apply_dem_data ( track, skip_existing_elevations ); + // Inform user how much was changed + gchar str[64]; + const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed); + g_snprintf(str, 64, tmp_str, changed); + a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); +} + +static void trw_layer_apply_dem_data_all ( gpointer pass_along[6] ) { - /* TODO: check & warn if no DEM data, or no applicable DEM data. */ - /* Also warn if overwrite old elevation data */ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; VikTrack *track; if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) @@ -4582,7 +4956,137 @@ static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); if ( track ) - vik_track_apply_dem_data ( track ); + apply_dem_data_common ( vtl, pass_along[1], track, FALSE ); +} + +static void trw_layer_apply_dem_data_only_missing ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( track ) + apply_dem_data_common ( vtl, pass_along[1], track, TRUE ); +} + +/** + * smooth_it: + * + * A common function for applying the elevation smoothing and reporting the results. + */ +static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat ) +{ + gulong changed = vik_track_smooth_missing_elevation_data ( track, flat ); + // Inform user how much was changed + gchar str[64]; + const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed); + g_snprintf(str, 64, tmp_str, changed); + a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); +} + +/** + * + */ +static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + smooth_it ( vtl, track, FALSE ); +} + +static void trw_layer_missing_elevation_data_flat ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + smooth_it ( vtl, track, TRUE ); +} + +/** + * Commonal helper function + */ +static void wp_changed_message ( VikTrwLayer *vtl, gint changed ) +{ + gchar str[64]; + const gchar *tmp_str = ngettext("%ld waypoint changed", "%ld waypoints changed", changed); + g_snprintf(str, 64, tmp_str, changed); + a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); +} + +static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1]; + + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gint changed = 0; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + // Single Waypoint + VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); + if ( wp ) + changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE ); + } + else { + // All waypoints + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init ( &iter, vtl->waypoints ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + VikWaypoint *wp = VIK_WAYPOINT(value); + changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, FALSE ); + } + } + wp_changed_message ( vtl, changed ); +} + +static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1]; + + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gint changed = 0; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + // Single Waypoint + VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); + if ( wp ) + changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE ); + } + else { + // All waypoints + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init ( &iter, vtl->waypoints ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + VikWaypoint *wp = VIK_WAYPOINT(value); + changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, TRUE ); + } + } + wp_changed_message ( vtl, changed ); } static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) @@ -4682,6 +5186,91 @@ static void trw_layer_auto_track_view ( gpointer pass_along[6] ) } } +/* + * Refine the selected track/route with a routing engine. + * The routing engine is selected by the user, when requestiong the job. + */ +static void trw_layer_route_refine ( gpointer pass_along[6] ) +{ + static gint last_engine = 0; + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrack *trk; + + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( trk && trk->trackpoints ) + { + /* Check size of the route */ + int nb = vik_track_get_tp_count(trk); + if (nb > 100) { + GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER (vtl), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, + _("Refining a track with many points (%d) is unlikely to yield sensible results. Do you want to Continue?"), + nb); + gint response = gtk_dialog_run ( GTK_DIALOG(dialog) ); + gtk_widget_destroy ( dialog ); + if (response != GTK_RESPONSE_OK ) + return; + } + /* Select engine from dialog */ + GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Refine Route with Routing Engine..."), + VIK_GTK_WINDOW_FROM_LAYER (vtl), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + NULL); + GtkWidget *label = gtk_label_new ( _("Select routing engine") ); + gtk_widget_show_all(label); + + gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 0 ); + + GtkWidget * combo = vik_routing_ui_selector_new ( (Predicate)vik_routing_engine_supports_refine, NULL ); + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), last_engine); + gtk_widget_show_all(combo); + + gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), combo, TRUE, TRUE, 0 ); + + gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT ); + + if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + /* Dialog validated: retrieve selected engine and do the job */ + last_engine = gtk_combo_box_get_active ( GTK_COMBO_BOX(combo) ); + VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine); + + /* Change cursor */ + vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) ); + + /* Force saving track */ + /* FIXME: remove or rename this hack */ + vtl->route_finder_check_added_track = TRUE; + + /* the job */ + vik_routing_engine_refine (routing, vtl, trk); + + /* FIXME: remove or rename this hack */ + if ( vtl->route_finder_added_track ) + vik_track_calculate_bounds ( vtl->route_finder_added_track ); + + vtl->route_finder_added_track = NULL; + vtl->route_finder_check_added_track = FALSE; + + vik_layer_emit_update ( VIK_LAYER(vtl) ); + + /* Restore cursor */ + vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) ); + } + gtk_widget_destroy ( dialog ); + } +} + static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); @@ -6864,6 +7453,11 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_statistics), 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") ); @@ -7005,6 +7599,70 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); gtk_widget_show ( item ); + GtkWidget *transform_submenu; + transform_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, 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), transform_submenu ); + + GtkWidget *dem_submenu; + dem_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_all), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values")); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_only_missing), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values")); + gtk_widget_show ( item ); + + GtkWidget *smooth_submenu; + smooth_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("_Smooth Missing Elevation Data") ); + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smooth_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolated") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_interp), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Interpolate between known elevation values to derive values for the missing elevations")); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Flat") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_flat), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Set unknown elevation values to the last known value")); + gtk_widget_show ( item ); + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_widget_show ( item ); + + // Routes don't have timestamps - so this is only available for tracks + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01")); + gtk_widget_show ( item ); + } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") ); else @@ -7014,6 +7672,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("Refine Route...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_route_refine), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */ if ( vlp ) { if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) @@ -7026,12 +7692,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); } - item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") ); else @@ -7050,15 +7710,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) - item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") ); - else - item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { 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 ("vik-icon-Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c @@ -7147,6 +7798,37 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men } } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + GtkWidget *transform_submenu; + transform_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, 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), transform_submenu ); + + GtkWidget *dem_submenu; + dem_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_all), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values")); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_only_missing), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item ); + gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values")); + gtk_widget_show ( item ); + } + + gtk_widget_show_all ( GTK_WIDGET(menu) ); + return rv; } @@ -7612,8 +8294,12 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve // Determine if working on a waypoint or a trackpoint if ( t->is_waypoint ) { + // Update waypoint position vtl->current_wp->coord = new_coord; trw_layer_calculate_bounds_waypoints ( vtl ); + // Reset waypoint pointer + vtl->current_wp = NULL; + vtl->current_wp_id = NULL; } else { if ( vtl->current_tpl ) { @@ -7622,17 +8308,13 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve if ( vtl->current_tp_track ) vik_track_calculate_bounds ( vtl->current_tp_track ); - if ( vtl->tpwin ) + if ( vtl->tpwin ) if ( vtl->current_tp_track ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin } } - // Reset - vtl->current_wp = NULL; - vtl->current_wp_id = NULL; - trw_layer_cancel_current_tp ( vtl, FALSE ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -8451,7 +9133,7 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) )) { 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, FALSE ) ) ) + if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ) ) ) { new_track_create_common ( vtl, name ); g_free ( name ); @@ -8484,7 +9166,7 @@ static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) ) { gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")); - if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->routes, name, TRUE ) ) ) { + if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ) ) ) { new_route_create_common ( vtl, name ); g_free ( name ); } @@ -9030,7 +9712,8 @@ static void trw_layer_sort_all ( VikTrwLayer *vtl ) static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file ) { - trw_layer_verify_thumbnails ( vtl, vvp ); + if ( VIK_LAYER(vtl)->realized ) + trw_layer_verify_thumbnails ( vtl, vvp ); trw_layer_track_alloc_colors ( vtl ); trw_layer_calculate_bounds_waypoints ( vtl ); @@ -9251,12 +9934,10 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) { VikMapsLayer *vml; - gint selected_map, default_map; + gint selected_map; gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL }; gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}; gint selected_zoom, default_zoom; - int i,j; - VikTrwLayer *vtl = pass_along[0]; VikLayersPanel *vlp = pass_along[1]; @@ -9274,49 +9955,35 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) int num_maps = g_list_length(vmls); if (!num_maps) { - a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR, _("No map layer in use. Create one first"), NULL); + a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No map layer in use. Create one first") ); return; } + // Convert from list of vmls to list of names. Allowing the user to select one of them gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer)); VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer)); gchar **np = map_names; VikMapsLayer **lp = map_layers; + int i; for (i = 0; i < num_maps; i++) { - gboolean dup = FALSE; vml = (VikMapsLayer *)(vmls->data); - for (j = 0; j < i; j++) { /* no duplicate allowed */ - if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) { - dup = TRUE; - break; - } - } - if (!dup) { - *lp++ = vml; - *np++ = vik_maps_layer_get_map_label(vml); - } + *lp++ = vml; + *np++ = vik_maps_layer_get_map_label(vml); vmls = vmls->next; } + // Mark end of the array lists *lp = NULL; *np = NULL; - num_maps = lp - map_layers; - - for (default_map = 0; default_map < num_maps; default_map++) { - /* TODO: check for parent layer's visibility */ - if (VIK_LAYER(map_layers[default_map])->visible) - break; - } - default_map = (default_map == num_maps) ? 0 : default_map; gdouble cur_zoom = vik_viewport_get_zoom(vvp); - for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) { + for (default_zoom = 0; default_zoom < G_N_ELEMENTS(zoom_vals); default_zoom++) { if (cur_zoom == zoom_vals[default_zoom]) break; } - default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom; + default_zoom = (default_zoom == G_N_ELEMENTS(zoom_vals)) ? G_N_ELEMENTS(zoom_vals) - 1 : default_zoom; - if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom)) + if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, 0, zoomlist, default_zoom, &selected_map, &selected_zoom)) goto done; vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);