X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/6528571dd95dff9aad0b4dae903ed49641a3f4fd..bd78ae7d70bd7388d4950f3e7331b72f84eab208:/src/viktrwlayer.c?ds=sidebyside diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index ebb314b2..a5d79e1d 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -56,6 +56,7 @@ #include "datasource_gps.h" #include "vikexttool_datasources.h" #include "util.h" +#include "vikutils.h" #include "vikrouting.h" @@ -131,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; @@ -145,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; @@ -454,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 }; @@ -516,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 @@ -537,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 }, @@ -584,6 +592,8 @@ enum { PARAM_WV, PARAM_RV, // Tracks + PARAM_TDL, + PARAM_TLFONTSIZE, PARAM_DM, PARAM_TC, PARAM_DL, @@ -931,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; @@ -1040,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; @@ -1287,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 ) ); @@ -1300,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) ); @@ -1385,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 ) @@ -1646,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 ); + } + } } } @@ -1933,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 ); @@ -2327,52 +2629,30 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g return NULL; } -/* - * Function to show basic track point information on the statusbar +#define VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT "trkpt_selected_statusbar_format" + +/** + * set_statusbar_msg_info_trkpt: + * + * Function to show track point information on the statusbar + * Items displayed is controlled by the settings format code */ static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt ) { - gchar tmp_buf1[64]; - switch (a_vik_get_units_height ()) { - case VIK_UNITS_HEIGHT_FEET: - g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(trkpt->altitude))); - break; - default: - //VIK_UNITS_HEIGHT_METRES: - g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dm"), (int)round(trkpt->altitude)); - } - - gchar tmp_buf2[64]; - tmp_buf2[0] = '\0'; - if ( trkpt->has_timestamp ) { - // Compact date time format - strftime (tmp_buf2, sizeof(tmp_buf2), _(" | Time %x %X"), localtime(&(trkpt->timestamp))); + gchar *statusbar_format_code = NULL; + gboolean need2free = FALSE; + if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) { + // Otherwise use default + statusbar_format_code = g_strdup ( "KATDN" ); + need2free = TRUE; } - // Position part - // Position is put later on, as this bit may not be seen if the display is not big enough, - // one can easily use the current pointer position to see this if needed - gchar *lat = NULL, *lon = NULL; - static struct LatLon ll; - vik_coord_to_latlon (&(trkpt->coord), &ll); - a_coords_latlon_to_string ( &ll, &lat, &lon ); - - // Track name - // Again is put later on, as this bit may not be seen if the display is not big enough - // trackname can be seen from the treeview (when enabled) - // Also name could be very long to not leave room for anything else - gchar tmp_buf3[64]; - tmp_buf3[0] = '\0'; - if ( vtl->current_tp_track ) { - g_snprintf(tmp_buf3, sizeof(tmp_buf3), _(" | Track: %s"), vtl->current_tp_track->name ); - } - - // Combine parts to make overall message - gchar *msg = g_strdup_printf (_("%s%s | %s %s %s"), tmp_buf1, tmp_buf2, lat, lon, tmp_buf3); + gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, NULL, vtl->current_tp_track ); vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg ); - g_free ( lat ); - g_free ( lon ); g_free ( msg ); + + if ( need2free ) + g_free ( statusbar_format_code ); } /* @@ -3262,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 @@ -3288,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 @@ -4304,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 ); @@ -4317,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 ); @@ -4330,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 ); @@ -4401,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 */ @@ -7143,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") ); @@ -7979,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 ) { @@ -7989,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; } @@ -8818,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 ); @@ -8851,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 ); } @@ -9397,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 ); @@ -9618,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]; @@ -9645,45 +9959,31 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) 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]);