X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/657bb8fc94acd80433435209eedb03a80189aeb9..bd78ae7d70bd7388d4950f3e7331b72f84eab208:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index 9b791a10..a5d79e1d 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -6,6 +6,7 @@ * Copyright (C) 2007, Quy Tonthat * Copyright (C) 2009, Hein Ragas * Copyright (c) 2012, Rob Norris + * Copyright (c) 2012-2013, Guilhem Bonnefille * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,6 +35,7 @@ #include "vikgpslayer.h" #include "viktrwlayer_tpwin.h" #include "viktrwlayer_propwin.h" +#include "viktrwlayer_analysis.h" #ifdef VIK_CONFIG_GEOTAG #include "viktrwlayer_geotag.h" #include "geotag_exif.h" @@ -52,7 +54,11 @@ #include "acquire.h" #include "datasources.h" #include "datasource_gps.h" +#include "vikexttool_datasources.h" #include "util.h" +#include "vikutils.h" + +#include "vikrouting.h" #include "icons/icons.h" @@ -73,10 +79,6 @@ #include #include -#ifdef VIK_CONFIG_GOOGLE -#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js" -#endif - #define VIK_TRW_LAYER_TRACK_GC 6 #define VIK_TRW_LAYER_TRACK_GCS 10 #define VIK_TRW_LAYER_TRACK_GC_BLACK 0 @@ -128,6 +130,9 @@ struct _VikTrwLayer { GHashTable *waypoints; GtkTreeIter tracks_iter, routes_iter, waypoints_iter; gboolean tracks_visible, routes_visible, waypoints_visible; + LatLonBBox waypoints_bbox; + + gboolean track_draw_labels; guint8 drawmode; guint8 drawpoints; guint8 drawpoints_size; @@ -140,11 +145,18 @@ struct _VikTrwLayer { guint8 drawdirections_size; guint8 line_thickness; 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; font_size_t wp_font_size; + gchar *wp_fsize_str; + vik_layer_sort_order_t wp_sort_order; gdouble track_draw_speed_factor; GArray *track_gc; @@ -209,6 +221,9 @@ struct _VikTrwLayer { VikStdLayerMenuItem menu_selection; gint highest_wp_number; + + // One per layer + GtkWidget *tracks_analysis_dialog; }; /* A caached waypoint image. */ @@ -228,6 +243,7 @@ struct DrawingParams { const VikCoord *center; gboolean one_zone, lat_lon; gdouble ce1, ce2, cn1, cn2; + LatLonBBox bbox; }; static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp ); @@ -236,7 +252,6 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ); static void trw_layer_copy_item_cb ( gpointer pass_along[6] ); static void trw_layer_cut_item_cb ( gpointer pass_along[6] ); -static void trw_layer_find_maxmin_waypoints ( const gpointer id, const VikWaypoint *w, struct LatLon maxmin[2] ); static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] ); static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]); @@ -246,6 +261,8 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl ); static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp ); static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp ); +static void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl ); + static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord ); static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] ); static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ); @@ -292,9 +309,7 @@ static void trw_layer_geotagging_track ( gpointer pass_along[6] ); static void trw_layer_geotagging ( gpointer lav[2] ); #endif static void trw_layer_acquire_gps_cb ( gpointer lav[2] ); -#ifdef VIK_CONFIG_GOOGLE -static void trw_layer_acquire_google_cb ( gpointer lav[2] ); -#endif +static void trw_layer_acquire_routing_cb ( gpointer lav[2] ); #ifdef VIK_CONFIG_OPENSTREETMAP static void trw_layer_acquire_osm_cb ( gpointer lav[2] ); static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] ); @@ -331,12 +346,14 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ); static void trw_layer_tpwin_init ( VikTrwLayer *vtl ); static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp); +static void tool_edit_trackpoint_destroy ( tool_ed_t *t ); static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ); static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp); +static void tool_edit_waypoint_destroy ( tool_ed_t *t ); static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ); static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); @@ -349,10 +366,8 @@ static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, Vi 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 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 ); @@ -400,7 +415,9 @@ static VikToolInterface trw_layer_tools[] = { GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf }, { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "E", N_("Edit Waypoint"), 0 }, - (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL, + (VikToolConstructorFunc) tool_edit_waypoint_create, + (VikToolDestructorFunc) tool_edit_waypoint_destroy, + NULL, NULL, (VikToolMouseFunc) tool_edit_waypoint_click, (VikToolMouseMoveFunc) tool_edit_waypoint_move, (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, @@ -408,7 +425,9 @@ static VikToolInterface trw_layer_tools[] = { GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf }, { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "K", N_("Edit Trackpoint"), 0 }, - (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, + (VikToolConstructorFunc) tool_edit_trackpoint_create, + (VikToolDestructorFunc) tool_edit_trackpoint_destroy, + NULL, NULL, (VikToolMouseFunc) tool_edit_trackpoint_click, (VikToolMouseMoveFunc) tool_edit_trackpoint_move, (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, @@ -421,13 +440,11 @@ static VikToolInterface trw_layer_tools[] = { FALSE, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf }, -#ifdef VIK_CONFIG_GOOGLE { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "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 { @@ -437,16 +454,14 @@ enum { TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, -#ifdef VIK_CONFIG_GOOGLE TOOL_ROUTE_FINDER, -#endif NUM_TOOLS }; /****** 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 }; @@ -484,6 +499,14 @@ static gchar* params_font_sizes[] = { N_("Extra Extra Large"), NULL }; +// Needs to align with vik_layer_sort_order_t +static gchar* params_sort_order[] = { + N_("None"), + N_("Name Ascending"), + N_("Name Descending"), + NULL +}; + static VikLayerParamData black_color_default ( void ) { VikLayerParamData data; gdk_color_parse ( "#000000", &data.c ); return data; // Black } @@ -499,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 @@ -513,46 +537,52 @@ static VikLayerParamData image_size_default ( void ) { return VIK_LPD_UINT ( 64 static VikLayerParamData image_alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); } static VikLayerParamData image_cache_size_default ( void ) { return VIK_LPD_UINT ( 300 ); } -VikLayerParam trw_layer_params[] = { - { VIK_LAYER_TRW, "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default }, - { VIK_LAYER_TRW, "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default }, - { VIK_LAYER_TRW, "routes_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default }, +static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); } - { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default }, +VikLayerParam trw_layer_params[] = { + { VIK_LAYER_TRW, "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, + { 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 }, - { 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 }, - { 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 }, - { 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 }, - { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[11], NULL, NULL, trkdirectionsize_default }, - { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default }, - { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[10], NULL, NULL, trkpointsize_default }, - { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default }, - { 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 }, - + 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_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_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_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_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 }, - { 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 }, - - { 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 }, - { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default }, - { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, 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 }, - - { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default }, - { 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 }, - { VIK_LAYER_TRW, "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, black_color_default }, - { VIK_LAYER_TRW, "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wptextcolor_default }, - { VIK_LAYER_TRW, "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wpbgcolor_default }, - { VIK_LAYER_TRW, "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default }, - { VIK_LAYER_TRW, "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_COMBOBOX, params_wpsymbols, NULL, NULL, wpsymbol_default }, - { VIK_LAYER_TRW, "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[7], NULL, NULL, wpsize_default }, - { VIK_LAYER_TRW, "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default }, - - { VIK_LAYER_TRW, "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default }, - { VIK_LAYER_TRW, "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[3], NULL, NULL, image_size_default }, - { VIK_LAYER_TRW, "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[4], NULL, NULL, image_alpha_default }, - { VIK_LAYER_TRW, "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[5], NULL, NULL, image_cache_size_default }, + 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_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_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_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 }, + { VIK_LAYER_TRW, "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, black_color_default, NULL, NULL }, + { VIK_LAYER_TRW, "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wptextcolor_default, NULL, NULL }, + { VIK_LAYER_TRW, "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wpbgcolor_default, NULL, NULL }, + { VIK_LAYER_TRW, "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL }, + { VIK_LAYER_TRW, "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_COMBOBOX, params_wpsymbols, NULL, NULL, wpsymbol_default, NULL, NULL }, + { VIK_LAYER_TRW, "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[7], NULL, NULL, wpsize_default, NULL, NULL }, + { VIK_LAYER_TRW, "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, + { VIK_LAYER_TRW, "wpsortorder", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL }, + + { VIK_LAYER_TRW, "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL }, + { VIK_LAYER_TRW, "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[3], NULL, NULL, image_size_default, NULL, NULL }, + { VIK_LAYER_TRW, "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[4], NULL, NULL, image_alpha_default, NULL, NULL }, + { VIK_LAYER_TRW, "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[5], NULL, NULL, image_cache_size_default, NULL, NULL }, }; // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE @@ -562,6 +592,8 @@ enum { PARAM_WV, PARAM_RV, // Tracks + PARAM_TDL, + PARAM_TLFONTSIZE, PARAM_DM, PARAM_TC, PARAM_DL, @@ -577,6 +609,7 @@ enum { PARAM_BLT, PARAM_TBGC, PARAM_TDSF, + PARAM_TSO, // Waypoints PARAM_DLA, PARAM_WPFONTSIZE, @@ -587,6 +620,7 @@ enum { PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, + PARAM_WPSO, // WP images PARAM_DI, PARAM_IS, @@ -605,7 +639,7 @@ enum { /* Layer Interface function definitions */ static VikTrwLayer* trw_layer_create ( VikViewport *vp ); static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ); -static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp ); +static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file ); static void trw_layer_free ( VikTrwLayer *trwlayer ); static void trw_layer_draw ( VikTrwLayer *l, gpointer data ); static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode ); @@ -849,6 +883,9 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i 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); + g_free ( name ); + + trw_layer_calculate_bounds_waypoints ( vtl ); // Consider if redraw necessary for the new item if ( vtl->vl.visible && vtl->waypoints_visible && w->visible ) @@ -864,6 +901,7 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name); vik_trw_layer_add_track ( vtl, name, t ); vik_track_convert (t, vtl->coord_mode); + g_free ( name ); // Consider if redraw necessary for the new item if ( vtl->vl.visible && vtl->tracks_visible && t->visible ) @@ -879,6 +917,7 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, t->name); vik_trw_layer_add_route ( vtl, name, t ); vik_track_convert (t, vtl->coord_mode); + g_free ( name ); // Consider if redraw necessary for the new item if ( vtl->vl.visible && vtl->routes_visible && t->visible ) @@ -902,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; @@ -944,6 +999,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(vtl->track_bg_color)); break; case PARAM_TDSF: vtl->track_draw_speed_factor = data.d; break; + case PARAM_TSO: if ( data.u < VL_SO_LAST ) vtl->track_sort_order = data.u; 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 ) @@ -982,7 +1038,22 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break; case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break; case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break; - case PARAM_WPFONTSIZE: if ( data.u < FS_NUM_SIZES ) vtl->wp_font_size = data.u; break; + case PARAM_WPFONTSIZE: + if ( data.u < FS_NUM_SIZES ) { + vtl->wp_font_size = data.u; + g_free ( vtl->wp_fsize_str ); + switch ( vtl->wp_font_size ) { + case FS_XX_SMALL: vtl->wp_fsize_str = g_strdup ( "xx-small" ); break; + case FS_X_SMALL: vtl->wp_fsize_str = g_strdup ( "x-small" ); break; + case FS_SMALL: vtl->wp_fsize_str = g_strdup ( "small" ); break; + case FS_LARGE: vtl->wp_fsize_str = g_strdup ( "large" ); break; + case FS_X_LARGE: vtl->wp_fsize_str = g_strdup ( "x-large" ); break; + case FS_XX_LARGE: vtl->wp_fsize_str = g_strdup ( "xx-large" ); break; + default: vtl->wp_fsize_str = g_strdup ( "medium" ); break; + } + } + break; + case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break; } return TRUE; } @@ -995,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; @@ -1012,6 +1085,7 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo case PARAM_DI: rv.b = vtl->drawimages; break; case PARAM_TBGC: rv.c = vtl->track_bg_color; break; case PARAM_TDSF: rv.d = vtl->track_draw_speed_factor; break; + case PARAM_TSO: rv.u = vtl->track_sort_order; 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; @@ -1023,6 +1097,7 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo case PARAM_WPSIZE: rv.u = vtl->wp_size; break; case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break; case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break; + case PARAM_WPSO: rv.u = vtl->wp_sort_order; break; } return rv; } @@ -1149,6 +1224,9 @@ static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *v } //g_debug ("consumed_length %d vs len %d", consumed_length, len); + // Not stored anywhere else so need to regenerate + trw_layer_calculate_bounds_waypoints ( vtl ); + return vtl; } @@ -1213,6 +1291,7 @@ static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp ) rv->draw_sync_done = TRUE; rv->draw_sync_do = TRUE; + // Everything else is 0, FALSE or NULL return rv; } @@ -1221,7 +1300,11 @@ static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp ) static void trw_layer_free ( VikTrwLayer *trwlayer ) { g_hash_table_destroy(trwlayer->waypoints); + g_hash_table_destroy(trwlayer->waypoints_iters); g_hash_table_destroy(trwlayer->tracks); + g_hash_table_destroy(trwlayer->tracks_iters); + g_hash_table_destroy(trwlayer->routes); + g_hash_table_destroy(trwlayer->routes_iters); /* ODC: replace with GArray */ trw_layer_free_track_gcs ( trwlayer ); @@ -1232,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 ) ); @@ -1244,9 +1330,15 @@ static void trw_layer_free ( VikTrwLayer *trwlayer ) if ( trwlayer->waypoint_bg_gc != NULL ) 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) ); + if ( trwlayer->tracks_analysis_dialog != NULL ) + gtk_widget_destroy ( GTK_WIDGET(trwlayer->tracks_analysis_dialog) ); + g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL ); g_queue_free ( trwlayer->image_cache ); } @@ -1289,6 +1381,8 @@ static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, Vi dp->cn1 = bottomright.north_south; dp->cn2 = upperleft.north_south; } + + vik_viewport_get_min_max_lat_lon ( vp, &(dp->bbox.south), &(dp->bbox.north), &(dp->bbox.west), &(dp->bbox.east) ); } /* @@ -1323,8 +1417,267 @@ 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 ) + return; + /* TODO: this function is a mess, get rid of any redundancy */ GList *list = track->trackpoints; GdkGC *main_gc; @@ -1346,9 +1699,6 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr alt_diff = max_alt - min_alt; } - if ( ! track->visible ) - return; - /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */ if ( dp->vtl->bg_line_thickness && !draw_track_outline ) trw_layer_draw_track ( id, track, dp, TRUE ); @@ -1584,13 +1934,25 @@ 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 ); + } + } } } -/* the only reason this exists is so that trw_layer_draw_track can first call itself to draw the white track background */ static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp ) { - trw_layer_draw_track ( id, track, dp, FALSE ); + if ( BBOX_INTERSECT ( track->bbox, dp->bbox ) ) { + trw_layer_draw_track ( id, track, dp, FALSE ); + } } static void cached_pixbuf_free ( CachedPixbuf *cp ) @@ -1612,7 +1974,6 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) ) { gint x, y; - GdkPixbuf *sym = NULL; vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y ); /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */ @@ -1696,9 +2057,9 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct } } - /* DRAW ACTUAL DOT */ - if ( dp->vtl->wp_draw_symbols && wp->symbol && (sym = a_get_wp_sym(wp->symbol)) ) { - vik_viewport_draw_pixbuf ( dp->vp, sym, 0, 0, x - gdk_pixbuf_get_width(sym)/2, y - gdk_pixbuf_get_height(sym)/2, -1, -1 ); + // Draw appropriate symbol - either symbol image or simple types + if ( dp->vtl->wp_draw_symbols && wp->symbol && wp->symbol_pixbuf ) { + vik_viewport_draw_pixbuf ( dp->vp, wp->symbol_pixbuf, 0, 0, x - gdk_pixbuf_get_width(wp->symbol_pixbuf)/2, y - gdk_pixbuf_get_height(wp->symbol_pixbuf)/2, -1, -1 ); } else if ( wp == dp->vtl->current_wp ) { switch ( dp->vtl->wp_symbol ) { @@ -1727,18 +2088,7 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct // Hopefully name won't break the markup (may need to sanitize - g_markup_escape_text()) // Could this stored in the waypoint rather than recreating each pass? - gchar *fsize = NULL; - switch (dp->vtl->wp_font_size) { - case FS_XX_SMALL: fsize = g_strdup ( "xx-small" ); break; - case FS_X_SMALL: fsize = g_strdup ( "x-small" ); break; - case FS_SMALL: fsize = g_strdup ( "small" ); break; - case FS_LARGE: fsize = g_strdup ( "large" ); break; - case FS_X_LARGE: fsize = g_strdup ( "x-large" ); break; - case FS_XX_LARGE: fsize = g_strdup ( "xx-large" ); break; - default: fsize = g_strdup ( "medium" ); break; - } - - gchar *wp_label_markup = g_strdup_printf ( "%s", fsize, wp->name ); + gchar *wp_label_markup = g_strdup_printf ( "%s", dp->vtl->wp_fsize_str, wp->name ); if ( pango_parse_markup ( wp_label_markup, -1, 0, NULL, NULL, NULL, NULL ) ) pango_layout_set_markup ( dp->vtl->wplabellayout, wp_label_markup, -1 ); @@ -1747,12 +2097,11 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct pango_layout_set_text ( dp->vtl->wplabellayout, wp->name, -1 ); g_free ( wp_label_markup ); - g_free ( fsize ); pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height ); label_x = x - width/2; - if (sym) - label_y = y - height - 2 - gdk_pixbuf_get_height(sym)/2; + if ( wp->symbol_pixbuf ) + label_y = y - height - 2 - gdk_pixbuf_get_height(wp->symbol_pixbuf)/2; else label_y = y - dp->vtl->wp_size - height - 2; @@ -1773,6 +2122,13 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct } } +static void trw_layer_draw_waypoint_cb ( gpointer id, VikWaypoint *wp, struct DrawingParams *dp ) +{ + if ( BBOX_INTERSECT ( dp->vtl->waypoints_bbox, dp->bbox ) ) { + trw_layer_draw_waypoint ( id, wp, dp ); + } +} + static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) { static struct DrawingParams dp; @@ -1787,7 +2143,7 @@ static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) g_hash_table_foreach ( l->routes, (GHFunc) trw_layer_draw_track_cb, &dp ); if (l->waypoints_visible) - g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint, &dp ); + g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint_cb, &dp ); } static void trw_layer_free_track_gcs ( VikTrwLayer *vtl ) @@ -1868,7 +2224,7 @@ static VikTrwLayer* trw_layer_create ( VikViewport *vp ) VikTrwLayer *rv = trw_layer_new1 ( vp ); vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name ); - if ( vp == NULL || GTK_WIDGET(vp)->window == NULL ) { + if ( vp == NULL || gtk_widget_get_window(GTK_WIDGET(vp)) == NULL ) { /* early exit, as the rest is GUI related */ return rv; } @@ -1876,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 ); @@ -1922,11 +2281,7 @@ static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pas gdk_pixbuf_fill ( pixbuf, pixel ); } -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE ); -#else vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE ); -#endif if ( pixbuf ) g_object_unref (pixbuf); @@ -1945,11 +2300,7 @@ static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer { GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter)); -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE ); -#else vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE ); -#endif *new_iter = *((GtkTreeIter *) pass_along[1]); g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter ); @@ -1960,29 +2311,17 @@ static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) { -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE ); -#else vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE ); -#endif } static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) { -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE ); -#else vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE ); -#endif } static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) { -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE ); -#else vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE ); -#endif } static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) @@ -1992,13 +2331,13 @@ static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter * if ( g_hash_table_size (vtl->tracks) > 0 ) { trw_layer_add_sublayer_tracks ( vtl, vt , layer_iter ); + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along ); - vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), vtl->tracks_visible ); + vik_treeview_item_set_visible ( vt, &(vtl->tracks_iter), vtl->tracks_visible ); } if ( g_hash_table_size (vtl->routes) > 0 ) { - trw_layer_add_sublayer_routes ( vtl, vt, layer_iter ); pass_along[0] = &(vtl->routes_iter); @@ -2290,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))); - } - - // 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 ); + 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; } - // 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 ); } /* @@ -2488,6 +2805,21 @@ gboolean vik_trw_layer_is_empty ( VikTrwLayer *vtl ) g_hash_table_size ( vtl->waypoints ) ); } +gboolean vik_trw_layer_get_tracks_visibility ( VikTrwLayer *vtl ) +{ + return vtl->tracks_visible; +} + +gboolean vik_trw_layer_get_routes_visibility ( VikTrwLayer *vtl ) +{ + return vtl->routes_visible; +} + +gboolean vik_trw_layer_get_waypoints_visibility ( VikTrwLayer *vtl ) +{ + return vtl->waypoints_visible; +} + /* * ATM use a case sensitive find * Finds the first one @@ -2539,44 +2871,26 @@ VikTrack *vik_trw_layer_get_route ( VikTrwLayer *vtl, const gchar *name ) return g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find, (gpointer) name ); } -static void trw_layer_find_maxmin_waypoints ( const gpointer id, const VikWaypoint *w, struct LatLon maxmin[2] ) -{ - static VikCoord fixme; - vik_coord_copy_convert ( &(w->coord), VIK_COORD_LATLON, &fixme ); - if ( VIK_LATLON(&fixme)->lat > maxmin[0].lat || maxmin[0].lat == 0.0 ) - maxmin[0].lat = VIK_LATLON(&fixme)->lat; - if ( VIK_LATLON(&fixme)->lat < maxmin[1].lat || maxmin[1].lat == 0.0 ) - maxmin[1].lat = VIK_LATLON(&fixme)->lat; - if ( VIK_LATLON(&fixme)->lon > maxmin[0].lon || maxmin[0].lon == 0.0 ) - maxmin[0].lon = VIK_LATLON(&fixme)->lon; - if ( VIK_LATLON(&fixme)->lon < maxmin[1].lon || maxmin[1].lon == 0.0 ) - maxmin[1].lon = VIK_LATLON(&fixme)->lon; -} - static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] ) { - GList *tr = trk->trackpoints; - static VikCoord fixme; - - while ( tr ) - { - vik_coord_copy_convert ( &(VIK_TRACKPOINT(tr->data)->coord), VIK_COORD_LATLON, &fixme ); - if ( VIK_LATLON(&fixme)->lat > maxmin[0].lat || maxmin[0].lat == 0.0 ) - maxmin[0].lat = VIK_LATLON(&fixme)->lat; - if ( VIK_LATLON(&fixme)->lat < maxmin[1].lat || maxmin[1].lat == 0.0 ) - maxmin[1].lat = VIK_LATLON(&fixme)->lat; - if ( VIK_LATLON(&fixme)->lon > maxmin[0].lon || maxmin[0].lon == 0.0 ) - maxmin[0].lon = VIK_LATLON(&fixme)->lon; - if ( VIK_LATLON(&fixme)->lon < maxmin[1].lon || maxmin[1].lon == 0.0 ) - maxmin[1].lon = VIK_LATLON(&fixme)->lon; - tr = tr->next; - } + if ( trk->bbox.north > maxmin[0].lat || maxmin[0].lat == 0.0 ) + maxmin[0].lat = trk->bbox.north; + if ( trk->bbox.south < maxmin[1].lat || maxmin[1].lat == 0.0 ) + maxmin[1].lat = trk->bbox.south; + if ( trk->bbox.east > maxmin[0].lon || maxmin[0].lon == 0.0 ) + maxmin[0].lon = trk->bbox.east; + if ( trk->bbox.west < maxmin[1].lon || maxmin[1].lon == 0.0 ) + maxmin[1].lon = trk->bbox.west; } static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]) { // Continually reuse maxmin to find the latest maximum and minimum values - g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin ); + // First set to waypoints bounds + maxmin[0].lat = vtl->waypoints_bbox.north; + maxmin[1].lat = vtl->waypoints_bbox.south; + maxmin[0].lon = vtl->waypoints_bbox.east; + maxmin[1].lon = vtl->waypoints_bbox.west; g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin ); g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin ); } @@ -2687,6 +3001,12 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, co GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); + gchar *cwd = g_get_current_dir(); + if ( cwd ) { + gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(file_selector), cwd ); + g_free ( cwd ); + } + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name); while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT ) @@ -2695,7 +3015,9 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, co if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE ) { gtk_widget_hide ( file_selector ); + vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) ); failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE ); + vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) ); break; } else @@ -2703,7 +3025,9 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, co if ( a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) ) { gtk_widget_hide ( file_selector ); + vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) ); failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE ); + vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) ); break; } } @@ -2757,7 +3081,9 @@ static void trw_layer_export_external_gpx ( gpointer layer_and_vlp[2], const gch int fd; if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) { + vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) ); gboolean failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), name_used, FILE_TYPE_GPX, NULL, TRUE); + vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) ); if (failed) { a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Could not create temporary file for export.") ); } @@ -2847,8 +3173,8 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) label = gtk_label_new(_("Waypoint Name:")); entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), entry, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), entry, FALSE, FALSE, 0); gtk_widget_show_all ( label ); gtk_widget_show_all ( entry ); @@ -2898,11 +3224,9 @@ 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, wp, vtl->coord_mode, TRUE, &updated ); + returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated ); if ( returned_name ) { @@ -2928,6 +3252,7 @@ static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ) // Note the order is max part first then min part - thus reverse order of use in min_max function: vik_viewport_get_min_max_lat_lon ( vvp, &maxmin[1].lat, &maxmin[0].lat, &maxmin[1].lon, &maxmin[0].lon ); a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin); + trw_layer_calculate_bounds_waypoints ( vtl ); vik_layers_panel_emit_update ( vlp ); } @@ -2939,6 +3264,7 @@ static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ) trw_layer_find_maxmin (vtl, maxmin); a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin); + trw_layer_calculate_bounds_waypoints ( vtl ); vik_layers_panel_emit_update ( vlp ); } @@ -3001,23 +3327,21 @@ static void trw_layer_acquire_gps_cb ( gpointer lav[2] ) VikViewport *vvp = vik_window_viewport(vw); vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER; - a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface, NULL, NULL ); } -#ifdef VIK_CONFIG_GOOGLE /* - * Acquire into this TRW Layer from Google Directions + * Acquire into this TRW Layer from Directions */ -static void trw_layer_acquire_google_cb ( gpointer lav[2] ) +static void trw_layer_acquire_routing_cb ( gpointer lav[2] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - a_acquire ( vw, vlp, vvp, &vik_datasource_google_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_routing_interface, NULL, NULL ); } -#endif #ifdef VIK_CONFIG_OPENSTREETMAP /* @@ -3030,7 +3354,7 @@ static void trw_layer_acquire_osm_cb ( gpointer lav[2] ) VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - a_acquire ( vw, vlp, vvp, &vik_datasource_osm_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_osm_interface, NULL, NULL ); } /** @@ -3043,7 +3367,7 @@ static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] ) VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - a_acquire ( vw, vlp, vvp, &vik_datasource_osm_my_traces_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_osm_my_traces_interface, NULL, NULL ); } #endif @@ -3058,7 +3382,7 @@ static void trw_layer_acquire_geocache_cb ( gpointer lav[2] ) VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - a_acquire ( vw, vlp, vvp, &vik_datasource_gc_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_gc_interface, NULL, NULL ); } #endif @@ -3074,7 +3398,7 @@ static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] ) VikViewport *vvp = vik_window_viewport(vw); vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER; - a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface, NULL, NULL ); // Reverify thumbnails as they may have changed vtl->has_verified_thumbnails = FALSE; @@ -3200,7 +3524,7 @@ static void trw_layer_acquire_file_cb ( gpointer lav[2] ) VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface ); + a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL ); } static void trw_layer_new_wp ( gpointer lav[2] ) @@ -3209,13 +3533,16 @@ static void trw_layer_new_wp ( gpointer lav[2] ) VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason. instead return true if you want to update. */ - if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) + if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) { + trw_layer_calculate_bounds_waypoints ( vtl ); vik_layers_panel_emit_update ( vlp ); + } } 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 @@ -3233,6 +3560,7 @@ static void trw_layer_new_track ( gpointer lav[2] ) if ( ! vtl->current_track ) { gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ; new_track_create_common ( vtl, name ); + g_free ( name ); vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK ); } @@ -3241,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 @@ -3256,6 +3585,7 @@ static void trw_layer_new_route ( gpointer lav[2] ) if ( ! vtl->current_track ) { gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ; new_route_create_common ( vtl, name ); + g_free ( name ); vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_ROUTE ); } } @@ -3314,7 +3644,10 @@ static void trw_layer_auto_waypoints_view ( gpointer lav[2] ) else if ( g_hash_table_size (vtl->waypoints) > 1 ) { struct LatLon maxmin[2] = { {0,0}, {0,0} }; - g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin ); + maxmin[0].lat = vtl->waypoints_bbox.north; + maxmin[1].lat = vtl->waypoints_bbox.south; + maxmin[0].lon = vtl->waypoints_bbox.east; + maxmin[1].lon = vtl->waypoints_bbox.west; trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin ); } @@ -3477,12 +3810,11 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); gtk_widget_show ( item ); -#ifdef VIK_CONFIG_GOOGLE - item = gtk_menu_item_new_with_mnemonic ( _("From Google _Directions...") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_google_cb), pass_along ); + /* FIXME: only add menu when at least a routing engine has support for Directions */ + item = gtk_menu_item_new_with_mnemonic ( _("From _Directions...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_routing_cb), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); gtk_widget_show ( item ); -#endif #ifdef VIK_CONFIG_OPENSTREETMAP item = gtk_menu_item_new_with_mnemonic ( _("From _OSM Traces...") ); @@ -3536,6 +3868,8 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); gtk_widget_show ( item ); + vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) ); + GtkWidget *upload_submenu = gtk_menu_new (); item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) ); @@ -3634,15 +3968,15 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter)); // Visibility column always needed for waypoints -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE ); -#else vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE ); -#endif + // Actual setting of visibility dependent on the waypoint vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible ); g_hash_table_insert ( vtl->waypoints_iters, GUINT_TO_POINTER(wp_uuid), iter ); + + // Sort now as post_read is not called on a realized waypoint + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order ); } highest_wp_number_add_wp(vtl, name); @@ -3668,15 +4002,15 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter)); // Visibility column always needed for tracks -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE ); -#else vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE ); -#endif + // Actual setting of visibility dependent on the track vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible ); g_hash_table_insert ( vtl->tracks_iters, GUINT_TO_POINTER(tr_uuid), iter ); + + // Sort now as post_read is not called on a realized track + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order ); } g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t ); @@ -3701,16 +4035,15 @@ void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) } GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter)); - // Visibility column always needed for tracks -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE ); -#else + // Visibility column always needed for routes vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE ); -#endif - // Actual setting of visibility dependent on the track + // Actual setting of visibility dependent on the route vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible ); g_hash_table_insert ( vtl->routes_iters, GUINT_TO_POINTER(rt_uuid), iter ); + + // Sort now as post_read is not called on a realized route + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order ); } g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t ); @@ -3725,6 +4058,32 @@ void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk ) trw_layer_cancel_current_tp ( vtl, FALSE ); } +/** + * Normally this is done to due the waypoint size preference having changed + */ +void vik_trw_layer_reset_waypoints ( VikTrwLayer *vtl ) +{ + GHashTableIter iter; + gpointer key, value; + + // Foreach waypoint + g_hash_table_iter_init ( &iter, vtl->waypoints ); + while ( g_hash_table_iter_next ( &iter, &key, &value ) ) { + VikWaypoint *wp = VIK_WAYPOINT(value); + if ( wp->symbol ) { + // Reapply symbol setting to update the pixbuf + gchar *tmp_symbol = g_strdup ( wp->symbol ); + vik_waypoint_set_symbol ( wp, tmp_symbol ); + g_free ( tmp_symbol ); + } + } +} + +/** + * trw_layer_new_unique_sublayer_name: + * + * Allocates a unique new name + */ gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name) { gint i = 2; @@ -3795,34 +4154,58 @@ static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l ) */ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type ) { + // TODO reconsider strategy when moving within layer (if anything...) + gboolean rename = ( vtl_src != vtl_dest ); + if ( ! rename ) + return; + if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) { VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id ); - gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name); + gchar *newname; + if ( rename ) + newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name ); + else + newname = g_strdup ( trk->name ); VikTrack *trk2 = vik_track_copy ( trk, TRUE ); vik_trw_layer_add_track ( vtl_dest, newname, trk2 ); + g_free ( newname ); vik_trw_layer_delete_track ( vtl_src, trk ); } if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) { VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id ); - gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name); + gchar *newname; + if ( rename ) + newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name ); + else + newname = g_strdup ( trk->name ); VikTrack *trk2 = vik_track_copy ( trk, TRUE ); vik_trw_layer_add_route ( vtl_dest, newname, trk2 ); + g_free ( newname ); vik_trw_layer_delete_route ( vtl_src, trk ); } if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) { VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id ); - gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, wp->name); + gchar *newname; + if ( rename ) + newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name ); + else + newname = g_strdup ( wp->name ); VikWaypoint *wp2 = vik_waypoint_copy ( wp ); vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 ); + g_free ( newname ); trw_layer_delete_waypoint ( vtl_src, wp ); + + // Recalculate bounds even if not renamed as maybe dragged between layers + trw_layer_calculate_bounds_waypoints ( vtl_dest ); + trw_layer_calculate_bounds_waypoints ( vtl_src ); } } @@ -3849,8 +4232,7 @@ static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl while (iter) { if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) { trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK); - } - else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) { + } else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) { trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_ROUTE); } else { trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT); @@ -4204,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 ); @@ -4217,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 ); @@ -4230,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 ); @@ -4240,6 +4622,30 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) vik_layer_emit_update ( VIK_LAYER(vtl) ); } +/** + * Rename waypoint and maintain corresponding name of waypoint in the treeview + */ +static void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name ) +{ + vik_waypoint_set_name ( wp, new_name ); + + // Now update the treeview as well + wpu_udata udataU; + udataU.wp = wp; + udataU.uuid = NULL; + + // Need 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, new_name ); + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order ); + } + } +} static void trw_layer_properties_item ( gpointer pass_along[7] ) { @@ -4251,9 +4657,11 @@ static void trw_layer_properties_item ( gpointer pass_along[7] ) if ( wp && wp->name ) { gboolean updated = FALSE; - a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, wp, vtl->coord_mode, FALSE, &updated ); + gchar *new_name = a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, vtl, wp, vtl->coord_mode, FALSE, &updated ); + if ( new_name ) + trw_layer_waypoint_rename ( vtl, wp, new_name ); - if ( updated && wp->symbol && pass_along[6] ) + if ( updated && pass_along[6] ) vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) ); if ( updated && VIK_LAYER(vtl)->visible ) @@ -4275,21 +4683,49 @@ 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 ); } } } -/* - * Update the treeview of the track id - primarily to update the icon +/** + * 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? */ -void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk, gpointer *trk_id ) +static void trw_layer_track_statistics ( gpointer pass_along[7] ) { - trku_udata udata; - udata.trk = trk; - udata.uuid = NULL; - - gpointer *trkf = NULL; + 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 + */ +void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk, gpointer *trk_id ) +{ + trku_udata udata; + udata.trk = trk; + udata.uuid = NULL; + + gpointer *trkf = NULL; if ( trk->is_route ) trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata ); else @@ -4422,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] ) { @@ -4442,7 +4890,6 @@ static void trw_layer_extend_track_end ( gpointer pass_along[6] ) goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) ); } -#ifdef VIK_CONFIG_GOOGLE /** * extend a track using route finder */ @@ -4463,12 +4910,44 @@ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] ) 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] ) +/** + * + */ +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 ) @@ -4477,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] ) @@ -4558,7 +5167,7 @@ static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] ) */ static void trw_layer_auto_track_view ( gpointer pass_along[6] ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[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] ); @@ -4569,11 +5178,96 @@ static void trw_layer_auto_track_view ( gpointer pass_along[6] ) { struct LatLon maxmin[2] = { {0,0}, {0,0} }; trw_layer_find_maxmin_tracks ( NULL, trk, maxmin ); - trw_layer_zoom_to_show_latlons ( VIK_TRW_LAYER(pass_along[0]), pass_along[5], maxmin ); + trw_layer_zoom_to_show_latlons ( vtl, pass_along[5], maxmin ); if ( pass_along[1] ) vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) ); else - vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + } +} + +/* + * 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 ); } } @@ -4795,10 +5489,10 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare); } } - /* TODO: free data before free merge_list */ for (l = merge_list; l != NULL; l = g_list_next(l)) g_free(l->data); g_list_free(merge_list); + vik_layer_emit_update( VIK_LAYER(vtl) ); } } @@ -4885,6 +5579,7 @@ static void trw_layer_append_track ( gpointer pass_along[6] ) 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) ); } } @@ -5093,6 +5788,7 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) } g_list_free(nearby_tracks); + vik_layer_emit_update( VIK_LAYER(vtl) ); } @@ -5117,6 +5813,9 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subt vtl->current_tpl->next->prev = newglist; /* end old track here */ vtl->current_tpl->next = NULL; + // Bounds of the selected track changed due to the split + vik_track_calculate_bounds ( vtl->current_tp_track ); + vtl->current_tpl = newglist; /* change tp to first of new track. */ vtl->current_tp_track = tr; @@ -5125,6 +5824,9 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subt else vik_trw_layer_add_track ( vtl, name, tr ); + // Bounds of the new track created by the split + vik_track_calculate_bounds ( tr ); + trku_udata udata; udata.trk = tr; udata.uuid = NULL; @@ -5143,6 +5845,7 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subt vik_layer_emit_update(VIK_LAYER(vtl)); } + g_free ( name ); } } @@ -5175,10 +5878,19 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) while (iter) { ts = VIK_TRACKPOINT(iter->data)->timestamp; + + // Check for unordered time points - this is quite a rare occurence - unless one has reversed a track. if (ts < prev_ts) { - g_print("panic: ts < prev_ts: this should never happen!\n"); + gchar tmp_str[64]; + strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&ts) ); + if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Can not split track due to trackpoints not ordered in time - such as at %s.\n\nGoto this trackpoint?"), + tmp_str ) ) { + goto_coord ( pass_along[1], vtl, pass_along[5], &(VIK_TRACKPOINT(iter->data)->coord) ); + } return; } + if (ts - prev_ts > thr*60) { /* flush accumulated trackpoints into new list */ newlists = g_list_append(newlists, g_list_reverse(newtps)); @@ -5209,7 +5921,8 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) 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);*/ - + g_free ( new_tr_name ); + vik_track_calculate_bounds ( tr ); iter = g_list_next(iter); } // Remove original track and then update the display @@ -5295,6 +6008,9 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) 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_free ( new_tr_name ); + vik_track_calculate_bounds ( tr ); + iter = g_list_next(iter); } // Remove original track and then update the display @@ -5338,6 +6054,7 @@ static void trw_layer_split_segments ( gpointer pass_along[6] ) 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] ); + g_free ( new_tr_name ); } } if ( tracks ) { @@ -5427,11 +6144,6 @@ static void trw_layer_reverse ( gpointer pass_along[6] ) if ( ! track ) return; - // Check valid track - GList *trps = track->trackpoints; - if ( !trps ) - return; - vik_track_reverse ( track ); vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); @@ -5591,9 +6303,10 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl 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 + if ( ontrack ) + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->wp_sort_order ); + else + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->wp_sort_order ); } } @@ -5612,6 +6325,52 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl vik_layers_panel_emit_update ( vlp ); } +static void trw_layer_sort_order_a2z ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + GtkTreeIter *iter; + + switch (GPOINTER_TO_INT (pass_along[2])) { + case VIK_TRW_LAYER_SUBLAYER_TRACKS: + iter = &(vtl->tracks_iter); + vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING; + break; + case VIK_TRW_LAYER_SUBLAYER_ROUTES: + iter = &(vtl->routes_iter); + vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING; + break; + default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: + iter = &(vtl->waypoints_iter); + vtl->wp_sort_order = VL_SO_ALPHABETICAL_ASCENDING; + break; + } + + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING ); +} + +static void trw_layer_sort_order_z2a ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + GtkTreeIter *iter; + + switch (GPOINTER_TO_INT (pass_along[2])) { + case VIK_TRW_LAYER_SUBLAYER_TRACKS: + iter = &(vtl->tracks_iter); + vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING; + break; + case VIK_TRW_LAYER_SUBLAYER_ROUTES: + iter = &(vtl->routes_iter); + vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING; + break; + default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: + iter = &(vtl->waypoints_iter); + vtl->wp_sort_order = VL_SO_ALPHABETICAL_DESCENDING; + break; + } + + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_DESCENDING ); +} + /** * */ @@ -5802,26 +6561,8 @@ static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel // 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 - } - } + trw_layer_waypoint_rename ( vtl, waypoint, newname ); // Start trying to find same names again... waypoint_names = NULL; @@ -5856,35 +6597,273 @@ static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] ) return; } - // Sort list alphabetically for better presentation - g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all); - if ( ! all ) { - a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found")); - return; + // Sort list alphabetically for better presentation + g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all); + if ( ! all ) { + a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found")); + return; + } + + all = g_list_sort_with_data(all, sort_alphabetically, NULL); + + // Get list of items to delete from the user + GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), + all, + TRUE, + _("Delete Selection"), + _("Select waypoints to delete")); + g_list_free(all); + + // Delete requested waypoints + // since specificly requested, IMHO no need for extra confirmation + if ( delete_list ) { + GList *l; + for (l = delete_list; l != NULL; l = g_list_next(l)) { + // 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); + + trw_layer_calculate_bounds_waypoints ( vtl ); + vik_layer_emit_update( VIK_LAYER(vtl) ); + } + +} + +/** + * + */ +static void trw_layer_iter_visibility_toggle ( gpointer id, GtkTreeIter *it, VikTreeview *vt ) +{ + vik_treeview_item_toggle_visible ( vt, it ); +} + +/** + * + */ +static void trw_layer_iter_visibility ( gpointer id, GtkTreeIter *it, gpointer vis_data[2] ) +{ + vik_treeview_item_set_visible ( (VikTreeview*)vis_data[0], it, GPOINTER_TO_INT (vis_data[1]) ); +} + +/** + * + */ +static void trw_layer_waypoints_visibility ( gpointer id, VikWaypoint *wp, gpointer on_off ) +{ + wp->visible = GPOINTER_TO_INT (on_off); +} + +/** + * + */ +static void trw_layer_waypoints_toggle_visibility ( gpointer id, VikWaypoint *wp ) +{ + wp->visible = !wp->visible; +} + +/** + * + */ +static void trw_layer_waypoints_visibility_off ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) }; + g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data ); + g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_waypoints_visibility_on ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) }; + g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data ); + g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_waypoints_visibility_toggle ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt ); + g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_toggle_visibility, NULL ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_tracks_visibility ( gpointer id, VikTrack *trk, gpointer on_off ) +{ + trk->visible = GPOINTER_TO_INT (on_off); +} + +/** + * + */ +static void trw_layer_tracks_toggle_visibility ( gpointer id, VikTrack *trk ) +{ + trk->visible = !trk->visible; +} + +/** + * + */ +static void trw_layer_tracks_visibility_off ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) }; + g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data ); + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_tracks_visibility_on ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) }; + g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data ); + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt ); + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_toggle_visibility, NULL ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_routes_visibility_off ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) }; + g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data ); + g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_routes_visibility_on ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) }; + g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data ); + g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * + */ +static void trw_layer_routes_visibility_toggle ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt ); + g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_toggle_visibility, NULL ); + // Redraw + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * trw_layer_analyse_close: + * + * Stuff to do on dialog closure + */ +static void trw_layer_analyse_close ( GtkWidget *dialog, gint resp, VikLayer* vl ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(vl); + gtk_widget_destroy ( dialog ); + vtl->tracks_analysis_dialog = NULL; +} + +/** + * trw_layer_analyse_create_list: + * + * Create the latest list of tracks with the associated layer(s) + * Although this will always be from a single layer here + */ +static GList* trw_layer_analyse_create_list ( VikLayer *vl, gpointer user_data ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(vl); + GList *tracks = NULL; + if ( GPOINTER_TO_INT(user_data) == VIK_TRW_LAYER_SUBLAYER_TRACKS ) + tracks = g_hash_table_get_values ( vik_trw_layer_get_tracks(vtl) ); + else + tracks = g_hash_table_get_values ( vik_trw_layer_get_routes(vtl) ); + + GList *tracks_and_layers = NULL; + // build tracks_and_layers list + tracks = g_list_first ( tracks ); + while ( tracks ) { + vik_trw_track_list_t *vtdl = g_malloc (sizeof(vik_trw_track_list_t)); + vtdl->trk = VIK_TRACK(tracks->data); + vtdl->vtl = vtl; + tracks_and_layers = g_list_prepend ( tracks_and_layers, vtdl ); + tracks = g_list_next ( tracks ); } - all = g_list_sort_with_data(all, sort_alphabetically, NULL); + return tracks_and_layers; +} - // Get list of items to delete from the user - GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), - all, - TRUE, - _("Delete Selection"), - _("Select waypoints to delete")); - g_list_free(all); +static void trw_layer_tracks_stats ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + // There can only be one! + if ( vtl->tracks_analysis_dialog ) + return; - // Delete requested waypoints - // since specificly requested, IMHO no need for extra confirmation - if ( delete_list ) { - GList *l; - for (l = delete_list; l != NULL; l = g_list_next(l)) { - // 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); - vik_layer_emit_update( VIK_LAYER(vtl) ); - } + vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + VIK_LAYER(vtl)->name, + VIK_LAYER(vtl), + GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACKS), + trw_layer_analyse_create_list, + trw_layer_analyse_close ); +} + +/** + * + */ +static void trw_layer_routes_stats ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + // There can only be one! + if ( vtl->tracks_analysis_dialog ) + return; + vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + VIK_LAYER(vtl)->name, + VIK_LAYER(vtl), + GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTES), + trw_layer_analyse_create_list, + trw_layer_analyse_close ); } static void trw_layer_goto_waypoint ( gpointer pass_along[6] ) @@ -5923,8 +6902,9 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer ); // No actual change to the name supplied - if (strcmp(newname, wp->name) == 0 ) - return NULL; + if ( wp->name ) + if (strcmp(newname, wp->name) == 0 ) + return NULL; VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname ); @@ -5939,9 +6919,8 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc // Update WP name and refresh the treeview vik_waypoint_set_name (wp, newname); -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname ); -#endif + vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname ); + vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->waypoints_iter), l->wp_sort_order ); vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) ); @@ -5953,8 +6932,9 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer ); // No actual change to the name supplied - if (strcmp(newname, trk->name) == 0) - return NULL; + if ( trk->name ) + if (strcmp(newname, trk->name) == 0) + return NULL; VikTrack *trkf = vik_trw_layer_get_track ( l, (gpointer) newname ); @@ -5976,9 +6956,8 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc // Property Dialog of the track vik_trw_layer_propwin_update ( trk ); -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname ); -#endif + vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname ); + vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order ); vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) ); @@ -5990,8 +6969,9 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer ); // No actual change to the name supplied - if (strcmp(newname, trk->name) == 0) - return NULL; + if ( trk->name ) + if (strcmp(newname, trk->name) == 0) + return NULL; VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname ); @@ -6013,9 +6993,8 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc // Property Dialog of the track vik_trw_layer_propwin_update ( trk ); -#ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname ); -#endif + vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname ); + vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order ); vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) ); @@ -6159,7 +7138,7 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men pass_along[5] = wp->image; item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -6251,6 +7230,30 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + + GtkWidget *vis_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Waypoints") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_on), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Waypoints") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_off), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_toggle), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); } if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS ) @@ -6293,6 +7296,35 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + + GtkWidget *vis_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Tracks") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_on), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Tracks") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_off), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_toggle), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), 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_tracks_stats), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); } if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) @@ -6336,6 +7368,57 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + + GtkWidget *vis_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Routes") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_on), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Routes") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_off), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_toggle), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), 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_routes_stats), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) { + GtkWidget *submenu_sort = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Sort") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, 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), submenu_sort ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Ascending") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_a2z), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Descending") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_DESCENDING, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_z2a), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item ); + gtk_widget_show ( item ); } GtkWidget *upload_submenu = gtk_menu_new (); @@ -6370,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") ); @@ -6511,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 @@ -6520,24 +7672,26 @@ 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 ) item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") ); else item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Route...") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Maps Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Maps 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_download_map_along_track_cb), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); 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 ("DEM Download/Import", 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 @@ -6556,24 +7710,13 @@ 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 ); - -#ifdef VIK_CONFIG_GOOGLE 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 ("Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + 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 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 // ATM can't upload a single waypoint but can do waypoints to a GPS if ( subtype != VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { @@ -6655,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; } @@ -6698,7 +7872,7 @@ static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ) if courses in degrees are 350 + 020, the mid course more likely to be 005 (not 185) [similar applies if value is in radians] */ if (tp_current->course != NAN && tp_next->course != NAN) - tp_new->speed = (tp_current->course + tp_next->course)/2; + tp_new->course = (tp_current->course + tp_next->course)/2; /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */ @@ -6712,6 +7886,7 @@ static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ) gint index = g_list_index ( trk->trackpoints, tp_current ); if ( index > -1 ) { + // NB no recalculation of bounds since it is inserted between points trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index+1 ); } } @@ -6776,8 +7951,10 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) vtl->current_tpl = new_tpl; // Reset dialog with the available adjacent trackpoint - if ( vtl->current_tp_track ) + if ( vtl->current_tp_track ) { + vik_track_calculate_bounds ( vtl->current_tp_track ); vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name ); + } vik_layer_emit_update(VIK_LAYER(vtl)); } @@ -6810,6 +7987,99 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) vik_layer_emit_update(VIK_LAYER(vtl)); } +/** + * trw_layer_dialog_shift: + * @vertical: The reposition strategy. If Vertical moves dialog vertically, otherwise moves it horizontally + * + * Try to reposition a dialog if it's over the specified coord + * so to not obscure the item of interest + */ +void trw_layer_dialog_shift ( VikTrwLayer *vtl, GtkWindow *dialog, VikCoord *coord, gboolean vertical ) +{ + GtkWindow *parent = VIK_GTK_WINDOW_FROM_LAYER(vtl); //i.e. the main window + + // Attempt force dialog to be shown so we can find out where it is more reliably... + while ( gtk_events_pending() ) + gtk_main_iteration (); + + // get parent window position & size + gint win_pos_x, win_pos_y; + gtk_window_get_position ( parent, &win_pos_x, &win_pos_y ); + + gint win_size_x, win_size_y; + gtk_window_get_size ( parent, &win_size_x, &win_size_y ); + + // get own dialog size + gint dia_size_x, dia_size_y; + gtk_window_get_size ( dialog, &dia_size_x, &dia_size_y ); + + // get own dialog position + gint dia_pos_x, dia_pos_y; + gtk_window_get_position ( dialog, &dia_pos_x, &dia_pos_y ); + + // Dialog not 'realized'/positioned - so can't really do any repositioning logic + if ( dia_pos_x > 2 && dia_pos_y > 2 ) { + + VikViewport *vvp = vik_window_viewport ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) ); + + gint vp_xx, vp_yy; // In viewport pixels + vik_viewport_coord_to_screen ( vvp, coord, &vp_xx, &vp_yy ); + + // Work out the 'bounding box' in pixel terms of the dialog and only move it when over the position + + gint dest_x = 0; + gint dest_y = 0; + if ( gtk_widget_translate_coordinates ( GTK_WIDGET(vvp), GTK_WIDGET(parent), 0, 0, &dest_x, &dest_y ) ) { + + // Transform Viewport pixels into absolute pixels + gint tmp_xx = vp_xx + dest_x + win_pos_x - 10; + gint tmp_yy = vp_yy + dest_y + win_pos_y - 10; + + // Is dialog over the point (to within an ^^ edge value) + if ( (tmp_xx > dia_pos_x) && (tmp_xx < (dia_pos_x + dia_size_x)) && + (tmp_yy > dia_pos_y) && (tmp_yy < (dia_pos_y + dia_size_y)) ) { + + if ( vertical ) { + // Shift up<->down + gint hh = vik_viewport_get_height ( vvp ); + + // Consider the difference in viewport to the full window + gint offset_y = dest_y; + // Add difference between dialog and window sizes + offset_y += win_pos_y + (hh/2 - dia_size_y)/2; + + if ( vp_yy > hh/2 ) { + // Point in bottom half, move window to top half + gtk_window_move ( dialog, dia_pos_x, offset_y ); + } + else { + // Point in top half, move dialog down + gtk_window_move ( dialog, dia_pos_x, hh/2 + offset_y ); + } + } + else { + // Shift left<->right + gint ww = vik_viewport_get_width ( vvp ); + + // Consider the difference in viewport to the full window + gint offset_x = dest_x; + // Add difference between dialog and window sizes + offset_x += win_pos_x + (ww/2 - dia_size_x)/2; + + if ( vp_xx > ww/2 ) { + // Point on right, move window to left + gtk_window_move ( dialog, offset_x, dia_pos_y ); + } + else { + // Point on left, move right + gtk_window_move ( dialog, ww/2 + offset_x, dia_pos_y ); + } + } + } + } + } +} + static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) { if ( ! vtl->tpwin ) @@ -6818,8 +8088,18 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) g_signal_connect_swapped ( GTK_DIALOG(vtl->tpwin), "response", G_CALLBACK(trw_layer_tpwin_response), vtl ); /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */ g_signal_connect_swapped ( vtl->tpwin, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp), vtl ); + gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) ); + + if ( vtl->current_tpl ) { + // get tp pixel position + VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data); + + // Shift up<->down to try not to obscure the trackpoint. + trw_layer_dialog_shift ( vtl, GTK_WINDOW(vtl->tpwin), &(tp->coord), TRUE ); + } } + if ( vtl->current_tpl ) if ( vtl->current_tp_track ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); @@ -6835,6 +8115,7 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) typedef struct { gint x, y; gint closest_x, closest_y; + gboolean draw_images; gpointer *closest_wp_id; VikWaypoint *closest_wp; VikViewport *vvp; @@ -6847,6 +8128,7 @@ typedef struct { VikTrackpoint *closest_tp; VikViewport *vvp; GList *closest_tpl; + LatLonBBox bbox; } TPSearchParams; static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchParams *params ) @@ -6858,7 +8140,7 @@ static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchP vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y ); // If waypoint has an image then use the image size to select - if ( wp->image ) { + if ( params->draw_images && wp->image ) { gint slackx, slacky; slackx = wp->image_width / 2; slacky = wp->image_height / 2; @@ -6890,6 +8172,9 @@ static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams * if ( !t->visible ) return; + if ( ! BBOX_INTERSECT ( t->bbox, params->bbox ) ) + return; + while (tpl) { gint x, y; @@ -6921,6 +8206,7 @@ static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikV params.vvp = vvp; params.closest_track_id = NULL; params.closest_tp = NULL; + vik_viewport_get_min_max_lat_lon ( params.vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) ); g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); return params.closest_tp; } @@ -6931,6 +8217,7 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie params.x = x; params.y = y; params.vvp = vvp; + params.draw_images = vtl->drawimages; params.closest_wp = NULL; params.closest_wp_id = NULL; g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); @@ -7006,23 +8293,28 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve marker_end_move ( t ); // Determine if working on a waypoint or a trackpoint - if ( t->is_waypoint ) + 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 ) { VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; - - if ( vtl->tpwin ) + + if ( vtl->current_tp_track ) + vik_track_calculate_bounds ( vtl->current_tp_track ); + + 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; } @@ -7045,13 +8337,17 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible ) return FALSE; + LatLonBBox bbox; + vik_viewport_get_min_max_lat_lon ( vvp, &(bbox.south), &(bbox.north), &(bbox.west), &(bbox.east) ); + // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track - if (vtl->waypoints_visible) { + if ( vtl->waypoints_visible && BBOX_INTERSECT (vtl->waypoints_bbox, bbox ) ) { WPSearchParams wp_params; wp_params.vvp = vvp; wp_params.x = event->x; wp_params.y = event->y; + wp_params.draw_images = vtl->drawimages; wp_params.closest_wp_id = NULL; wp_params.closest_wp = NULL; @@ -7090,6 +8386,8 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event tp_params.y = event->y; tp_params.closest_track_id = NULL; tp_params.closest_tp = NULL; + tp_params.closest_tpl = NULL; + tp_params.bbox = bbox; if (vtl->tracks_visible) { g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params); @@ -7319,6 +8617,11 @@ static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp) return t; } +static void tool_edit_waypoint_destroy ( tool_ed_t *t ) +{ + g_free ( t ); +} + static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) { WPSearchParams params; @@ -7356,6 +8659,7 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve params.vvp = vvp; params.x = event->x; params.y = event->y; + params.draw_images = vtl->drawimages; params.closest_wp_id = NULL; /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ params.closest_wp = NULL; @@ -7462,6 +8766,8 @@ static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *e marker_end_move ( t ); vtl->current_wp->coord = new_coord; + + trw_layer_calculate_bounds_waypoints ( vtl ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -7512,6 +8818,7 @@ static gboolean draw_sync ( gpointer data ) ds->vtl->draw_sync_done = TRUE; gdk_threads_leave(); } + g_free ( ds ); return FALSE; } @@ -7608,12 +8915,12 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo 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 ); + pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), 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 ); + pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 ); } // Reset to background @@ -7664,33 +8971,39 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo elev_loss += last_tpt->altitude - elev_new; } } - - gchar *str = distance_string (distance); - PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL); - pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc); + // + // Display of the distance 'tooltip' during track creation is controlled by a preference + // + if ( a_vik_get_create_track_tooltip() ) { + + gchar *str = distance_string (distance); - pango_layout_set_text (pl, str, -1); - gint wd, hd; - pango_layout_get_pixel_size ( pl, &wd, &hd ); + PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL); + pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc); + pango_layout_set_text (pl, str, -1); + gint wd, hd; + pango_layout_get_pixel_size ( pl, &wd, &hd ); - gint xd,yd; - // offset from cursor a bit depending on font size - xd = event->x + 10; - yd = event->y - hd; + gint xd,yd; + // offset from cursor a bit depending on font size + xd = event->x + 10; + yd = event->y - 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); + // 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 ) ); + g_object_unref ( G_OBJECT ( pl ) ); + g_object_unref ( G_OBJECT ( background_block_gc ) ); + g_free (str); + } passalong = g_new(draw_sync_t,1); // freed by draw_sync() passalong->vtl = vtl; passalong->pixmap = pixmap; - passalong->drawable = GTK_WIDGET(vvp)->window; + passalong->drawable = gtk_widget_get_window(GTK_WIDGET(vvp)); passalong->gc = vtl->current_track_newpoint_gc; gdouble angle; @@ -7700,8 +9013,6 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo // Update statusbar with full gain/loss information statusbar_write (distance, elev_gain, elev_loss, last_step, angle, vtl); - g_free (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; @@ -7764,6 +9075,7 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton g_free ( last->data ); vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); } + vik_track_calculate_bounds ( vtl->current_track ); update_statusbar ( vtl ); vik_layer_emit_update ( VIK_LAYER(vtl) ); @@ -7801,7 +9113,7 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton tp->timestamp = 0; if ( vtl->current_track ) { - vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp ); + vik_track_add_trackpoint ( vtl->current_track, tp, TRUE ); // Ensure bounds is updated /* Auto attempt to get elevation from DEM data (if it's available) */ vik_track_apply_dem_data_last_trackpoint ( vtl->current_track ); } @@ -7821,9 +9133,10 @@ 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 ); } else return TRUE; @@ -7853,8 +9166,10 @@ 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 ); + } else return TRUE; } @@ -7874,8 +9189,10 @@ static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *even if (!vtl || vtl->vl.type != VIK_LAYER_TRW) return FALSE; vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); - if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) + if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) { + trw_layer_calculate_bounds_waypoints ( vtl ); vik_layer_emit_update ( VIK_LAYER(vtl) ); + } return TRUE; } @@ -7890,6 +9207,11 @@ static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp) return t; } +static void tool_edit_trackpoint_destroy ( tool_ed_t *t ) +{ + g_free ( t ); +} + static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) { tool_ed_t *t = data; @@ -7907,6 +9229,8 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e params.closest_track_id = NULL; /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ params.closest_tp = NULL; + params.closest_tpl = NULL; + vik_viewport_get_min_max_lat_lon ( vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) ); if ( event->button != 1 ) return FALSE; @@ -8026,6 +9350,8 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton } VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; + if ( vtl->current_tp_track ) + vik_track_calculate_bounds ( vtl->current_tp_track ); marker_end_move ( t ); @@ -8040,7 +9366,6 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton } -#ifdef VIK_CONFIG_GOOGLE /*** Route Finder ***/ static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp) { @@ -8072,9 +9397,6 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even } else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) { struct LatLon start, end; - gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE]; - gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE]; - gchar *url; vik_coord_to_latlon ( &(vtl->route_finder_coord), &start ); vik_coord_to_latlon ( &(tmp), &end ); @@ -8088,14 +9410,7 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even vtl->route_finder_started = FALSE; } - url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, - g_ascii_dtostr (startlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lat), - g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon), - g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat), - g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon)); - // NB normally this returns a GPX Route - so subsequent usage of it must lookup via the routes hash - a_babel_convert_from_url ( vtl, url, "google", NULL, NULL, NULL ); - g_free ( url ); + vik_routing_default_find ( vtl, start, end); /* see if anything was done -- a track was added or appended to */ if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) { @@ -8105,6 +9420,10 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon ); vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment ); } + + 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; vtl->route_finder_append = FALSE; @@ -8117,7 +9436,6 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even } return TRUE; } -#endif /*** Show picture ****/ @@ -8323,10 +9641,90 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl ) } } -static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vp ) +/* + * (Re)Calculate the bounds of the waypoints in this layer, + * This should be called whenever waypoints are changed + */ +static void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl ) +{ + struct LatLon topleft = { 0.0, 0.0 }; + struct LatLon bottomright = { 0.0, 0.0 }; + struct LatLon ll; + + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init ( &iter, vtl->waypoints ); + + // Set bounds to first point + if ( g_hash_table_iter_next (&iter, &key, &value) ) { + vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &topleft ); + vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &bottomright ); + } + + // Ensure there is another point... + if ( g_hash_table_size ( vtl->waypoints ) > 1 ) { + + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + + // See if this point increases the bounds. + vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &ll ); + + if ( ll.lat > topleft.lat) topleft.lat = ll.lat; + if ( ll.lon < topleft.lon) topleft.lon = ll.lon; + if ( ll.lat < bottomright.lat) bottomright.lat = ll.lat; + if ( ll.lon > bottomright.lon) bottomright.lon = ll.lon; + } + } + + vtl->waypoints_bbox.north = topleft.lat; + vtl->waypoints_bbox.east = bottomright.lon; + vtl->waypoints_bbox.south = bottomright.lat; + vtl->waypoints_bbox.west = topleft.lon; +} + +static void trw_layer_calculate_bounds_track ( gpointer id, VikTrack *trk ) +{ + vik_track_calculate_bounds ( trk ); +} + +static void trw_layer_calculate_bounds_tracks ( VikTrwLayer *vtl ) +{ + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_calculate_bounds_track, NULL ); + g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_calculate_bounds_track, NULL ); +} + +static void trw_layer_sort_all ( VikTrwLayer *vtl ) +{ + if ( ! VIK_LAYER(vtl)->vt ) + return; + + // Obviously need 2 to tango - sorting with only 1 (or less) is a lonely activity! + if ( g_hash_table_size (vtl->tracks) > 1 ) + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order ); + + if ( g_hash_table_size (vtl->routes) > 1 ) + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order ); + + if ( g_hash_table_size (vtl->waypoints) > 1 ) + vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order ); +} + +static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file ) { - trw_layer_verify_thumbnails ( vtl, vp ); + if ( VIK_LAYER(vtl)->realized ) + trw_layer_verify_thumbnails ( vtl, vvp ); trw_layer_track_alloc_colors ( vtl ); + + trw_layer_calculate_bounds_waypoints ( vtl ); + trw_layer_calculate_bounds_tracks ( vtl ); + + // Apply treeview sort after loading all the tracks for this layer + // (rather than sorted insert on each individual track additional) + // and after subsequent changes to the properties as the specified order may have changed. + // since the sorting of a treeview section is now very quick + // NB sorting is also performed after every name change as well to maintain the list order + trw_layer_sort_all ( vtl ); } VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl ) @@ -8518,7 +9916,7 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g } for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) { - maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level); + vik_maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level); } if (fillins) { @@ -8536,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]; @@ -8559,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]);