X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/c9cac05887761bf019da619f20a6e651ade5b47e..a000257bf45acd950c7dbfa380c339532f6f5e1f:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index 49adb23c..09e30fb7 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -33,8 +33,12 @@ #include "viking.h" #include "vikmapslayer.h" #include "vikgpslayer.h" +#include "viktrwlayer_export.h" #include "viktrwlayer_tpwin.h" #include "viktrwlayer_propwin.h" +#include "viktrwlayer_analysis.h" +#include "viktrwlayer_tracklist.h" +#include "viktrwlayer_waypointlist.h" #ifdef VIK_CONFIG_GEOTAG #include "viktrwlayer_geotag.h" #include "geotag_exif.h" @@ -43,6 +47,7 @@ #include "thumbnails.h" #include "background.h" #include "gpx.h" +#include "geojson.h" #include "babel.h" #include "dem.h" #include "dems.h" @@ -55,6 +60,7 @@ #include "datasource_gps.h" #include "vikexttool_datasources.h" #include "util.h" +#include "vikutils.h" #include "vikrouting.h" @@ -130,6 +136,7 @@ struct _VikTrwLayer { gboolean tracks_visible, routes_visible, waypoints_visible; LatLonBBox waypoints_bbox; + gboolean track_draw_labels; guint8 drawmode; guint8 drawpoints; guint8 drawpoints_size; @@ -144,6 +151,13 @@ struct _VikTrwLayer { guint8 bg_line_thickness; vik_layer_sort_order_t track_sort_order; + // Metadata + VikTRWMetadata *metadata; + + PangoLayout *tracklabellayout; + font_size_t track_font_size; + gchar *track_fsize_str; + guint8 wp_symbol; guint8 wp_size; gboolean wp_draw_symbols; @@ -189,10 +203,8 @@ struct _VikTrwLayer { /* route finder tool */ gboolean route_finder_started; - VikCoord route_finder_coord; gboolean route_finder_check_added_track; VikTrack *route_finder_added_track; - VikTrack *route_finder_current_track; gboolean route_finder_append; gboolean drawlabels; @@ -214,6 +226,9 @@ struct _VikTrwLayer { VikStdLayerMenuItem menu_selection; gint highest_wp_number; + + // One per layer + GtkWidget *tracks_analysis_dialog; }; /* A caached waypoint image. */ @@ -234,15 +249,30 @@ struct DrawingParams { gboolean one_zone, lat_lon; gdouble ce1, ce2, cn1, cn2; LatLonBBox bbox; + gboolean highlight; }; static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp ); -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] ); +typedef enum { + MA_VTL = 0, + MA_VLP, + MA_SUBTYPE, // OR END for Layer only + MA_SUBLAYER_ID, + MA_CONFIRM, + MA_VVP, + MA_TV_ITER, + MA_MISC, + MA_LAST, +} menu_array_index; + +typedef gpointer menu_array_layer[2]; +typedef gpointer menu_array_sublayer[MA_LAST]; + +static void trw_layer_delete_item ( menu_array_sublayer values ); +static void trw_layer_copy_item_cb ( menu_array_sublayer values ); +static void trw_layer_cut_item_cb ( menu_array_sublayer values ); -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]); @@ -252,99 +282,101 @@ 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] ); -static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] ); -static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] ); -static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] ); -static void trw_layer_goto_track_center ( gpointer pass_along[6] ); -static void trw_layer_merge_by_segment ( gpointer pass_along[6] ); -static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ); -static void trw_layer_merge_with_other ( gpointer pass_along[6] ); -static void trw_layer_append_track ( gpointer pass_along[6] ); -static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ); -static void trw_layer_split_by_n_points ( gpointer pass_along[6] ); -static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] ); -static void trw_layer_split_segments ( gpointer pass_along[6] ); -static void trw_layer_delete_points_same_position ( gpointer pass_along[6] ); -static void trw_layer_delete_points_same_time ( gpointer pass_along[6] ); -static void trw_layer_reverse ( gpointer pass_along[6] ); -static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ); -static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ); -static void trw_layer_show_picture ( gpointer pass_along[6] ); -static void trw_layer_gps_upload_any ( gpointer pass_along[6] ); - -static void trw_layer_centerize ( gpointer layer_and_vlp[2] ); -static void trw_layer_auto_view ( gpointer layer_and_vlp[2] ); -static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type ); -static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ); -static void trw_layer_new_wp ( gpointer lav[2] ); -static void trw_layer_new_track ( gpointer lav[2] ); -static void trw_layer_new_route ( gpointer lav[2] ); -static void trw_layer_finish_track ( gpointer lav[2] ); -static void trw_layer_auto_waypoints_view ( gpointer lav[2] ); -static void trw_layer_auto_tracks_view ( gpointer lav[2] ); -static void trw_layer_delete_all_tracks ( gpointer lav[2] ); -static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ); -static void trw_layer_delete_all_waypoints ( gpointer lav[2] ); -static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] ); -static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ); -static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ); +static void trw_layer_goto_track_startpoint ( menu_array_sublayer values ); +static void trw_layer_goto_track_endpoint ( menu_array_sublayer values ); +static void trw_layer_goto_track_max_speed ( menu_array_sublayer values ); +static void trw_layer_goto_track_max_alt ( menu_array_sublayer values ); +static void trw_layer_goto_track_min_alt ( menu_array_sublayer values ); +static void trw_layer_goto_track_center ( menu_array_sublayer values ); +static void trw_layer_merge_by_segment ( menu_array_sublayer values ); +static void trw_layer_merge_by_timestamp ( menu_array_sublayer values ); +static void trw_layer_merge_with_other ( menu_array_sublayer values ); +static void trw_layer_append_track ( menu_array_sublayer values ); +static void trw_layer_split_by_timestamp ( menu_array_sublayer values ); +static void trw_layer_split_by_n_points ( menu_array_sublayer values ); +static void trw_layer_split_at_trackpoint ( menu_array_sublayer values ); +static void trw_layer_split_segments ( menu_array_sublayer values ); +static void trw_layer_delete_point_selected ( menu_array_sublayer values ); +static void trw_layer_delete_points_same_position ( menu_array_sublayer values ); +static void trw_layer_delete_points_same_time ( menu_array_sublayer values ); +static void trw_layer_reverse ( menu_array_sublayer values ); +static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values ); +static void trw_layer_edit_trackpoint ( menu_array_sublayer values ); +static void trw_layer_show_picture ( menu_array_sublayer values ); +static void trw_layer_gps_upload_any ( menu_array_sublayer values ); + +static void trw_layer_centerize ( menu_array_layer values ); +static void trw_layer_auto_view ( menu_array_layer values ); +static void trw_layer_goto_wp ( menu_array_layer values ); +static void trw_layer_new_wp ( menu_array_layer values ); +static void trw_layer_new_track ( menu_array_layer values ); +static void trw_layer_new_route ( menu_array_layer values ); +static void trw_layer_finish_track ( menu_array_layer values ); +static void trw_layer_auto_waypoints_view ( menu_array_layer values ); +static void trw_layer_auto_tracks_view ( menu_array_layer values ); +static void trw_layer_delete_all_tracks ( menu_array_layer values ); +static void trw_layer_delete_tracks_from_selection ( menu_array_layer values ); +static void trw_layer_delete_all_waypoints ( menu_array_layer values ); +static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values ); +static void trw_layer_new_wikipedia_wp_viewport ( menu_array_layer values ); +static void trw_layer_new_wikipedia_wp_layer ( menu_array_layer values ); #ifdef VIK_CONFIG_GEOTAG -static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] ); -static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] ); -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] ); +static void trw_layer_geotagging_waypoint_mtime_keep ( menu_array_sublayer values ); +static void trw_layer_geotagging_waypoint_mtime_update ( menu_array_sublayer values ); +static void trw_layer_geotagging_track ( menu_array_sublayer values ); +static void trw_layer_geotagging ( menu_array_layer values ); #endif +static void trw_layer_acquire_gps_cb ( menu_array_layer values ); +static void trw_layer_acquire_routing_cb ( menu_array_layer values ); +static void trw_layer_acquire_url_cb ( menu_array_layer values ); #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] ); +static void trw_layer_acquire_osm_cb ( menu_array_layer values ); +static void trw_layer_acquire_osm_my_traces_cb ( menu_array_layer values ); #endif #ifdef VIK_CONFIG_GEOCACHES -static void trw_layer_acquire_geocache_cb ( gpointer lav[2] ); +static void trw_layer_acquire_geocache_cb ( menu_array_layer values ); #endif #ifdef VIK_CONFIG_GEOTAG -static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] ); +static void trw_layer_acquire_geotagged_cb ( menu_array_layer values ); #endif -static void trw_layer_acquire_file_cb ( gpointer lav[2] ); -static void trw_layer_gps_upload ( gpointer lav[2] ); +static void trw_layer_acquire_file_cb ( menu_array_layer values ); +static void trw_layer_gps_upload ( menu_array_layer values ); + +static void trw_layer_track_list_dialog_single ( menu_array_sublayer values ); +static void trw_layer_track_list_dialog ( menu_array_layer values ); +static void trw_layer_waypoint_list_dialog ( menu_array_layer values ); // Specific route versions: // Most track handling functions can handle operating on the route list // However these ones are easier in separate functions -static void trw_layer_auto_routes_view ( gpointer lav[2] ); -static void trw_layer_delete_all_routes ( gpointer lav[2] ); -static void trw_layer_delete_routes_from_selection ( gpointer lav[2] ); +static void trw_layer_auto_routes_view ( menu_array_layer values ); +static void trw_layer_delete_all_routes ( menu_array_layer values ); +static void trw_layer_delete_routes_from_selection ( menu_array_layer values ); /* pop-up items */ -static void trw_layer_properties_item ( gpointer pass_along[7] ); -static void trw_layer_goto_waypoint ( gpointer pass_along[6] ); -static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] ); -static void trw_layer_waypoint_webpage ( gpointer pass_along[6] ); +static void trw_layer_properties_item ( gpointer pass_along[7] ); //TODO?? +static void trw_layer_goto_waypoint ( menu_array_sublayer values ); +static void trw_layer_waypoint_gc_webpage ( menu_array_sublayer values ); +static void trw_layer_waypoint_webpage ( menu_array_sublayer values ); static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] ); static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] ); -static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp ); -static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ); +static void trw_layer_insert_tp_beside_current_tp ( VikTrwLayer *vtl, gboolean ); static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy ); static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ); static void trw_layer_tpwin_init ( VikTrwLayer *vtl ); static gpointer tool_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 ); @@ -357,8 +389,9 @@ 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 ); -static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp); -static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gpointer tool_extended_route_finder_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_extended_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gboolean tool_extended_route_finder_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ); static void cached_pixbuf_free ( CachedPixbuf *cp ); static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name ); @@ -385,7 +418,7 @@ static VikToolInterface trw_layer_tools[] = { (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL, (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL, FALSE, - GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf }, + GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf, NULL }, { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "T", N_("Create Track"), 0 }, (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL, @@ -394,7 +427,7 @@ static VikToolInterface trw_layer_tools[] = { (VikToolMouseFunc) tool_new_track_release, (VikToolKeyFunc) tool_new_track_key_press, TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing - GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf }, + GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf, NULL }, { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "B", N_("Create Route"), 0 }, (VikToolConstructorFunc) tool_new_route_create, NULL, NULL, NULL, @@ -403,52 +436,60 @@ static VikToolInterface trw_layer_tools[] = { (VikToolMouseFunc) tool_new_track_release, // -> Reuse these track methods on a route (VikToolKeyFunc) tool_new_track_key_press, // -/# TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing - GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf }, + GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf, NULL }, + + { { "ExtendedRouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "F", N_("Route Finder"), 0 }, + (VikToolConstructorFunc) tool_extended_route_finder_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_extended_route_finder_click, + (VikToolMouseMoveFunc) tool_new_track_move, // -\# + (VikToolMouseFunc) tool_new_track_release, // -> Reuse these track methods on a route + (VikToolKeyFunc) tool_extended_route_finder_key_press, + TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing + GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf, NULL }, { { "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, FALSE, - GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf }, + GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf, NULL }, { { "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, FALSE, - GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf }, + GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf, NULL }, { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "I", N_("Show Picture"), 0 }, (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL, (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL, FALSE, - GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf }, + GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf, NULL }, - { { "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 }, }; enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_CREATE_ROUTE, + TOOL_ROUTE_FINDER, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, - TOOL_ROUTE_FINDER, 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"), N_("Metadata") }; +enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV, GROUP_METADATA }; 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 }; @@ -509,6 +550,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 @@ -525,50 +567,62 @@ static VikLayerParamData image_cache_size_default ( void ) { return VIK_LPD_UINT static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); } -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 string_default ( void ) +{ + VikLayerParamData data; + data.s = ""; + return data; +} - { 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, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default }, - - // Waypoint Options: - { 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, "wpsortorder", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_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 }, + + { VIK_LAYER_TRW, "metadatadesc", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Description"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL }, + { VIK_LAYER_TRW, "metadataauthor", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Author"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL }, + { VIK_LAYER_TRW, "metadatatime", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Creation Time"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL }, + { VIK_LAYER_TRW, "metadatakeywords", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Keywords"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL }, }; // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE @@ -578,6 +632,8 @@ enum { PARAM_WV, PARAM_RV, // Tracks + PARAM_TDL, + PARAM_TLFONTSIZE, PARAM_DM, PARAM_TC, PARAM_DL, @@ -610,6 +666,11 @@ enum { PARAM_IS, PARAM_IA, PARAM_ICS, + // Metadata + PARAM_MDDESC, + PARAM_MDAUTH, + PARAM_MDTIME, + PARAM_MDKEYS, NUM_PARAMS }; @@ -640,6 +701,7 @@ static void trw_layer_marshall ( VikTrwLayer *vtl, guint8 **data, gint *len ); static VikTrwLayer *trw_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp ); static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation ); static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation ); +static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values ); static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ); static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ); static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ); @@ -694,6 +756,7 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncSetParam) trw_layer_set_param, (VikLayerFuncGetParam) trw_layer_get_param, + (VikLayerFuncChangeParam) trw_layer_change_param, (VikLayerFuncReadFileData) a_gpspoint_read_file, (VikLayerFuncWriteFileData) a_gpspoint_write_file, @@ -712,6 +775,51 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncSelectedViewportMenu) trw_layer_show_selected_viewport_menu, }; +static gboolean have_diary_program = FALSE; +static gboolean have_geojson_export = FALSE; + + +// NB Only performed once per program run +static void vik_trwlayer_class_init ( VikTrwLayerClass *klass ) +{ + if ( g_find_program_in_path( "rednotebook" ) ) { + gchar *stdout = NULL; + gchar *stderr = NULL; + // Needs RedNotebook 1.7.3+ for support of opening on a specified date + if ( g_spawn_command_line_sync ( "rednotebook --version", &stdout, &stderr, NULL, NULL ) ) { + // Annoyingly 1.7.1|2|3 versions of RedNotebook prints the version to stderr!! + if ( stdout ) + g_debug ("Diary: %s", stdout ); // Should be something like 'RedNotebook 1.4' + if ( stderr ) + g_warning ("Diary: stderr: %s", stderr ); + + gchar **tokens = NULL; + if ( stdout && g_strcmp0(stdout, "") ) + tokens = g_strsplit(stdout, " ", 0); + else if ( stderr ) + tokens = g_strsplit(stderr, " ", 0); + + gint num = 0; + gchar *token = tokens[num]; + while ( token && num < 2 ) { + if (num == 1) { + if ( viking_version_to_number(token) >= viking_version_to_number("1.7.3") ) + have_diary_program = TRUE; + } + num++; + token = tokens[num]; + } + g_strfreev ( tokens ); + } + g_free ( stdout ); + g_free ( stderr ); + } + + if ( g_find_program_in_path ( a_geojson_program_export() ) ) { + have_geojson_export = TRUE; + } +} + GType vik_trw_layer_get_type () { static GType vtl_type = 0; @@ -723,7 +831,7 @@ GType vik_trw_layer_get_type () sizeof (VikTrwLayerClass), NULL, /* base_init */ NULL, /* base_finalize */ - NULL, /* class init */ + (GClassInitFunc) vik_trwlayer_class_init, /* class init */ NULL, /* class_finalize */ NULL, /* class_data */ sizeof (VikTrwLayer), @@ -732,50 +840,150 @@ GType vik_trw_layer_get_type () }; vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 ); } - return vtl_type; } +VikTRWMetadata *vik_trw_metadata_new() +{ + return (VikTRWMetadata*)g_malloc0(sizeof(VikTRWMetadata)); +} + +void vik_trw_metadata_free ( VikTRWMetadata *metadata) +{ + g_free (metadata); +} + +VikTRWMetadata *vik_trw_layer_get_metadata ( VikTrwLayer *vtl ) +{ + return vtl->metadata; +} + +void vik_trw_layer_set_metadata ( VikTrwLayer *vtl, VikTRWMetadata *metadata) +{ + if ( vtl->metadata ) + vik_trw_metadata_free ( vtl->metadata ); + vtl->metadata = metadata; +} + +typedef struct { + gboolean found; + const gchar *date_str; + const VikTrack *trk; + const VikWaypoint *wpt; + gpointer *trk_id; + gpointer *wpt_id; +} date_finder_type; + +static gboolean trw_layer_find_date_track ( const gpointer id, const VikTrack *trk, date_finder_type *df ) +{ + gchar date_buf[20]; + date_buf[0] = '\0'; + // Might be an easier way to compare dates rather than converting the strings all the time... + if ( trk->trackpoints && VIK_TRACKPOINT(trk->trackpoints->data)->has_timestamp ) { + strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(VIK_TRACKPOINT(trk->trackpoints->data)->timestamp))); + + if ( ! g_strcmp0 ( df->date_str, date_buf ) ) { + df->found = TRUE; + df->trk = trk; + df->trk_id = id; + } + } + return df->found; +} + +static gboolean trw_layer_find_date_waypoint ( const gpointer id, const VikWaypoint *wpt, date_finder_type *df ) +{ + gchar date_buf[20]; + date_buf[0] = '\0'; + // Might be an easier way to compare dates rather than converting the strings all the time... + if ( wpt->has_timestamp ) { + strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(wpt->timestamp))); + + if ( ! g_strcmp0 ( df->date_str, date_buf ) ) { + df->found = TRUE; + df->wpt = wpt; + df->wpt_id = id; + } + } + return df->found; +} + +/** + * Find an item by date + */ +gboolean vik_trw_layer_find_date ( VikTrwLayer *vtl, const gchar *date_str, VikCoord *position, VikViewport *vvp, gboolean do_tracks, gboolean select ) +{ + date_finder_type df; + df.found = FALSE; + df.date_str = date_str; + df.trk = NULL; + df.wpt = NULL; + // Only tracks ATM + if ( do_tracks ) + g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_find_date_track, &df ); + else + g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_find_date_waypoint, &df ); + + if ( select && df.found ) { + if ( do_tracks && df.trk ) { + struct LatLon maxmin[2] = { {0,0}, {0,0} }; + trw_layer_find_maxmin_tracks ( NULL, df.trk, maxmin ); + trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin ); + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->tracks_iters, df.trk_id), TRUE ); + } + else if ( df.wpt ) { + vik_viewport_set_center_coord ( vvp, &(df.wpt->coord), TRUE ); + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->waypoints_iters, df.wpt_id), TRUE ); + } + vik_layer_emit_update ( VIK_LAYER(vtl) ); + } + return df.found; +} + static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ) { - static gpointer pass_along[6]; + static menu_array_sublayer values; if (!sublayer) { return; } - - pass_along[0] = vtl; - pass_along[1] = NULL; - pass_along[2] = GINT_TO_POINTER (subtype); - pass_along[3] = sublayer; - pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request - pass_along[5] = NULL; - trw_layer_delete_item ( pass_along ); + gint ii; + for ( ii = MA_VTL; ii < MA_LAST; ii++ ) + values[ii] = NULL; + + values[MA_VTL] = vtl; + values[MA_SUBTYPE] = GINT_TO_POINTER (subtype); + values[MA_SUBLAYER_ID] = sublayer; + values[MA_CONFIRM] = GINT_TO_POINTER (1); // Confirm delete request + + trw_layer_delete_item ( values ); } static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ) { - static gpointer pass_along[6]; + static menu_array_sublayer values; if (!sublayer) { return; } - pass_along[0] = vtl; - pass_along[1] = NULL; - pass_along[2] = GINT_TO_POINTER (subtype); - pass_along[3] = sublayer; - pass_along[4] = GINT_TO_POINTER (0); // No delete confirmation needed for auto delete - pass_along[5] = NULL; + gint ii; + for ( ii = MA_VTL; ii < MA_LAST; ii++ ) + values[ii] = NULL; - trw_layer_copy_item_cb(pass_along); - trw_layer_cut_item_cb(pass_along); + values[MA_VTL] = vtl; + values[MA_SUBTYPE] = GINT_TO_POINTER (subtype); + values[MA_SUBLAYER_ID] = sublayer; + values[MA_CONFIRM] = GINT_TO_POINTER (1); // Confirm delete request + + trw_layer_copy_item_cb(values); + trw_layer_cut_item_cb(values); } -static void trw_layer_copy_item_cb ( gpointer pass_along[6]) +static void trw_layer_copy_item_cb ( menu_array_sublayer values) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - gint subtype = GPOINTER_TO_INT (pass_along[2]); - gpointer * sublayer = pass_along[3]; + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]); + gpointer * sublayer = values[MA_SUBLAYER_ID]; guint8 *data = NULL; guint len; @@ -810,17 +1018,17 @@ 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_cut_item_cb ( menu_array_sublayer values) { - trw_layer_copy_item_cb(pass_along); - pass_along[4] = GINT_TO_POINTER (0); // Never need to confirm automatic delete - trw_layer_delete_item(pass_along); + trw_layer_copy_item_cb(values); + values[MA_CONFIRM] = GINT_TO_POINTER (0); // Never need to confirm automatic delete + trw_layer_delete_item(values); } -static void trw_layer_paste_item_cb ( gpointer pass_along[6]) +static void trw_layer_paste_item_cb ( menu_array_sublayer values) { // Slightly cheating method, routing via the panels capability - a_clipboard_paste (VIK_LAYERS_PANEL(pass_along[1])); + a_clipboard_paste (VIK_LAYERS_PANEL(values[MA_VLP])); } static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ) @@ -867,6 +1075,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_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 ); @@ -884,6 +1093,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 ) @@ -899,6 +1109,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 ) @@ -922,6 +1133,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; @@ -1019,6 +1246,12 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara } break; case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break; + // Metadata + case PARAM_MDDESC: if ( data.s && vtl->metadata ) vtl->metadata->description = g_strdup (data.s); break; + case PARAM_MDAUTH: if ( data.s && vtl->metadata ) vtl->metadata->author = g_strdup (data.s); break; + case PARAM_MDTIME: if ( data.s && vtl->metadata ) vtl->metadata->timestamp = g_strdup (data.s); break; + case PARAM_MDKEYS: if ( data.s && vtl->metadata ) vtl->metadata->keywords = g_strdup (data.s); break; + default: break; } return TRUE; } @@ -1031,6 +1264,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; @@ -1061,10 +1296,91 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo 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; + // Metadata + case PARAM_MDDESC: if (vtl->metadata) { rv.s = vtl->metadata->description; } break; + case PARAM_MDAUTH: if (vtl->metadata) { rv.s = vtl->metadata->author; } break; + case PARAM_MDTIME: if (vtl->metadata) { rv.s = vtl->metadata->timestamp; } break; + case PARAM_MDKEYS: if (vtl->metadata) { rv.s = vtl->metadata->keywords; } break; + default: break; } return rv; } +static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values ) +{ + // This '-3' is to account for the first few parameters not in the properties + const gint OFFSET = -3; + + switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) { + // Alter sensitivity of waypoint draw image related widgets according to the draw image setting. + case PARAM_DI: { + // Get new value + VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] ); + GtkWidget **ww1 = values[UI_CHG_WIDGETS]; + GtkWidget **ww2 = values[UI_CHG_LABELS]; + GtkWidget *w1 = ww1[OFFSET + PARAM_IS]; + GtkWidget *w2 = ww2[OFFSET + PARAM_IS]; + GtkWidget *w3 = ww1[OFFSET + PARAM_IA]; + GtkWidget *w4 = ww2[OFFSET + PARAM_IA]; + GtkWidget *w5 = ww1[OFFSET + PARAM_ICS]; + GtkWidget *w6 = ww2[OFFSET + PARAM_ICS]; + if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b ); + if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b ); + if ( w3 ) gtk_widget_set_sensitive ( w3, vlpd.b ); + if ( w4 ) gtk_widget_set_sensitive ( w4, vlpd.b ); + if ( w5 ) gtk_widget_set_sensitive ( w5, vlpd.b ); + if ( w6 ) gtk_widget_set_sensitive ( w6, vlpd.b ); + break; + } + // Alter sensitivity of waypoint label related widgets according to the draw label setting. + case PARAM_DLA: { + // Get new value + VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] ); + GtkWidget **ww1 = values[UI_CHG_WIDGETS]; + GtkWidget **ww2 = values[UI_CHG_LABELS]; + GtkWidget *w1 = ww1[OFFSET + PARAM_WPTC]; + GtkWidget *w2 = ww2[OFFSET + PARAM_WPTC]; + GtkWidget *w3 = ww1[OFFSET + PARAM_WPBC]; + GtkWidget *w4 = ww2[OFFSET + PARAM_WPBC]; + GtkWidget *w5 = ww1[OFFSET + PARAM_WPBA]; + GtkWidget *w6 = ww2[OFFSET + PARAM_WPBA]; + GtkWidget *w7 = ww1[OFFSET + PARAM_WPFONTSIZE]; + GtkWidget *w8 = ww2[OFFSET + PARAM_WPFONTSIZE]; + if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b ); + if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b ); + if ( w3 ) gtk_widget_set_sensitive ( w3, vlpd.b ); + if ( w4 ) gtk_widget_set_sensitive ( w4, vlpd.b ); + if ( w5 ) gtk_widget_set_sensitive ( w5, vlpd.b ); + if ( w6 ) gtk_widget_set_sensitive ( w6, vlpd.b ); + if ( w7 ) gtk_widget_set_sensitive ( w7, vlpd.b ); + if ( w8 ) gtk_widget_set_sensitive ( w8, vlpd.b ); + break; + } + // Alter sensitivity of all track colours according to the draw track mode. + case PARAM_DM: { + // Get new value + VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] ); + gboolean sensitive = ( vlpd.u == DRAWMODE_ALL_SAME_COLOR ); + GtkWidget **ww1 = values[UI_CHG_WIDGETS]; + GtkWidget **ww2 = values[UI_CHG_LABELS]; + GtkWidget *w1 = ww1[OFFSET + PARAM_TC]; + GtkWidget *w2 = ww2[OFFSET + PARAM_TC]; + if ( w1 ) gtk_widget_set_sensitive ( w1, sensitive ); + if ( w2 ) gtk_widget_set_sensitive ( w2, sensitive ); + break; + } + case PARAM_MDTIME: { + // Force metadata->timestamp to be always read-only for now. + GtkWidget **ww = values[UI_CHG_WIDGETS]; + GtkWidget *w1 = ww[OFFSET + PARAM_MDTIME]; + if ( w1 ) gtk_widget_set_sensitive ( w1, FALSE ); + } + // NB Since other track settings have been split across tabs, + // I don't think it's useful to set sensitivities on widgets you can't immediately see + default: break; + } +} + static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) { guint8 *pd; @@ -1134,7 +1450,7 @@ static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE )); + VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, FALSE )); gint pl; gint consumed_length; @@ -1252,6 +1568,7 @@ static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp ) // Force to on after processing params (which defaults them to off with a zero value) rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE; + rv->metadata = vik_trw_metadata_new (); rv->draw_sync_done = TRUE; rv->draw_sync_do = TRUE; // Everything else is 0, FALSE or NULL @@ -1263,7 +1580,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 ); @@ -1274,6 +1595,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 ) ); @@ -1287,18 +1611,23 @@ static void trw_layer_free ( VikTrwLayer *trwlayer ) g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) ); g_free ( trwlayer->wp_fsize_str ); + g_free ( trwlayer->track_fsize_str ); if ( trwlayer->tpwin != NULL ) gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) ); + 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 ); } -static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp ) +static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp, gboolean highlight ) { dp->vtl = vtl; dp->vp = vp; + dp->highlight = highlight; dp->vw = (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl); dp->xmpp = vik_viewport_get_xmpp ( vp ); dp->ympp = vik_viewport_get_ympp ( vp ); @@ -1369,6 +1698,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; + + VikTrackpoint *tp_end = vik_track_get_tp_last ( trk ); + if ( !tp_end ) + return; + VikTrackpoint *tp_begin = vik_track_get_tp_first ( trk ); + if ( !tp_begin ) + return; + VikCoord begin_coord = tp_begin->coord; + VikCoord end_coord = tp_end->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 ) @@ -1411,18 +2001,11 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr if ( track == dp->vtl->current_track ) main_gc = dp->vtl->current_track_gc; else { - if ( vik_viewport_get_draw_highlight ( dp->vp ) ) { - /* Draw all tracks of the layer in special colour */ - /* if track is member of selected layer or is the current selected track - then draw in the highlight colour. - NB this supercedes the drawmode */ - if ( ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ) || - ( !track->is_route && ( dp->vtl->tracks == vik_window_get_selected_tracks ( dp->vw ) ) ) || - ( track->is_route && ( dp->vtl->routes == vik_window_get_selected_tracks ( dp->vw ) ) ) || - ( track == vik_window_get_selected_track ( dp->vw ) ) ) { - main_gc = vik_viewport_get_gc_highlight (dp->vp); - drawing_highlight = TRUE; - } + if ( dp->highlight ) { + /* Draw all tracks of the layer in special colour + NB this supercedes the drawmode */ + main_gc = vik_viewport_get_gc_highlight (dp->vp); + drawing_highlight = TRUE; } if ( !drawing_highlight ) { // Still need to figure out the gc according to the drawing mode: @@ -1630,6 +2213,17 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr useoldvals = FALSE; } } + + // Labels drawn after the trackpoints, so the labels are on top + if ( dp->vtl->track_draw_labels ) { + if ( track->max_number_dist_labels > 0 ) { + trw_layer_draw_dist_labels ( dp, track, drawing_highlight ); + } + + if ( track->draw_name_mode != TRACK_DRAWNAME_NO ) { + trw_layer_draw_track_name_labels ( dp, track, drawing_highlight ); + } + } } } @@ -1721,18 +2315,15 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */ { - if ( vik_viewport_get_draw_highlight ( dp->vp ) ) { - if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) || - dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) || - wp == vik_window_get_selected_waypoint ( dp->vw ) ) { - // Highlighted - so draw a little border around the chosen one - // single line seems a little weak so draw 2 of them - vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE, - x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 ); - vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE, - x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 ); - } - } + if ( dp->highlight ) { + // Highlighted - so draw a little border around the chosen one + // single line seems a little weak so draw 2 of them + vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE, + x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 ); + vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE, + x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 ); + } + if ( dp->vtl->image_alpha == 255 ) vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h ); else @@ -1753,6 +2344,7 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - dp->vtl->wp_size, y - dp->vtl->wp_size, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break; case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y - dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y + dp->vtl->wp_size*2 ); vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y + dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y - dp->vtl->wp_size*2 ); + default: break; } } else { @@ -1762,6 +2354,7 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x-dp->vtl->wp_size/2, y-dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break; case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y-dp->vtl->wp_size, x+dp->vtl->wp_size, y+dp->vtl->wp_size ); vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y+dp->vtl->wp_size, x+dp->vtl->wp_size, y-dp->vtl->wp_size ); break; + default: break; } } @@ -1791,17 +2384,10 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct label_y = y - dp->vtl->wp_size - height - 2; /* if highlight mode on, then draw background text in highlight colour */ - if ( vik_viewport_get_draw_highlight ( dp->vp ) ) { - if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) || - dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) || - wp == vik_window_get_selected_waypoint ( dp->vw ) ) - vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2); - else - vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2); - } - else { - vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2); - } + if ( dp->highlight ) + vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2); + else + vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2); vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout ); } } @@ -1814,12 +2400,12 @@ static void trw_layer_draw_waypoint_cb ( gpointer id, VikWaypoint *wp, struct Dr } } -static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) +static void trw_layer_draw_with_highlight ( VikTrwLayer *l, gpointer data, gboolean highlight ) { static struct DrawingParams dp; g_assert ( l != NULL ); - init_drawing_params ( &dp, l, VIK_VIEWPORT(data) ); + init_drawing_params ( &dp, l, VIK_VIEWPORT(data), highlight ); if ( l->tracks_visible ) g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp ); @@ -1831,6 +2417,77 @@ static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint_cb, &dp ); } +static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) +{ + // If this layer is to be highlighted - then don't draw now - as it will be drawn later on in the specific highlight draw stage + // This may seem slightly inefficient to test each time for every layer + // but for a layer with *lots* of tracks & waypoints this can save some effort by not drawing the items twice + if ( vik_viewport_get_draw_highlight ( (VikViewport*)data ) && + vik_window_get_selected_trw_layer ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER((VikLayer*)l)) == l ) + return; + trw_layer_draw_with_highlight ( l, data, FALSE ); +} + +void vik_trw_layer_draw_highlight ( VikTrwLayer *vtl, VikViewport *vvp ) +{ + // Check the layer for visibility (including all the parents visibilities) + if ( !vik_treeview_item_get_visible_tree (VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter)) ) + return; + trw_layer_draw_with_highlight ( vtl, vvp, TRUE ); +} + +/** + * vik_trw_layer_draw_highlight_item: + * + * Only handles a single track or waypoint ATM + * It assumes the track or waypoint belongs to the TRW Layer (it doesn't check this is the case) + */ +void vik_trw_layer_draw_highlight_item ( VikTrwLayer *vtl, VikTrack *trk, VikWaypoint *wpt, VikViewport *vvp ) +{ + // Check the layer for visibility (including all the parents visibilities) + if ( !vik_treeview_item_get_visible_tree (VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter)) ) + return; + + static struct DrawingParams dp; + init_drawing_params ( &dp, vtl, vvp, TRUE ); + + if ( trk ) { + gboolean draw = ( trk->is_route && vtl->routes_visible ) || ( !trk->is_route && vtl->tracks_visible ); + if ( draw ) + trw_layer_draw_track_cb ( NULL, trk, &dp ); + } + if ( vtl->waypoints_visible && wpt ) { + trw_layer_draw_waypoint_cb ( NULL, wpt, &dp ); + } +} + +/** + * vik_trw_layer_draw_highlight_item: + * + * Generally for drawing all tracks or routes or waypoints + * trks may be actually routes + * It assumes they belong to the TRW Layer (it doesn't check this is the case) + */ +void vik_trw_layer_draw_highlight_items ( VikTrwLayer *vtl, GHashTable *trks, GHashTable *wpts, VikViewport *vvp ) +{ + // Check the layer for visibility (including all the parents visibilities) + if ( !vik_treeview_item_get_visible_tree (VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter)) ) + return; + + static struct DrawingParams dp; + init_drawing_params ( &dp, vtl, vvp, TRUE ); + + if ( trks ) { + gboolean is_routes = (trks == vtl->routes); + gboolean draw = ( is_routes && vtl->routes_visible ) || ( !is_routes && vtl->tracks_visible ); + if ( draw ) + g_hash_table_foreach ( trks, (GHFunc) trw_layer_draw_track_cb, &dp ); + } + + if ( vtl->waypoints_visible && wpts ) + g_hash_table_foreach ( wpts, (GHFunc) trw_layer_draw_waypoint_cb, &dp ); +} + static void trw_layer_free_track_gcs ( VikTrwLayer *vtl ) { int i; @@ -1917,6 +2574,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 ); @@ -1935,7 +2595,7 @@ static VikTrwLayer* trw_layer_create ( VikViewport *vp ) /* * Can accept a null symbol, and may return null value */ -static GdkPixbuf* get_wp_sym_small ( gchar *symbol ) +GdkPixbuf* get_wp_sym_small ( gchar *symbol ) { GdkPixbuf* wp_icon = a_get_wp_sym (symbol); // ATM a_get_wp_sym returns a cached icon, with the size dependent on the preferences. @@ -2013,7 +2673,7 @@ 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 ); - pass_along[5] = GINT_TO_POINTER(g_hash_table_size (vtl->tracks)); + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along ); vik_treeview_item_set_visible ( vt, &(vtl->tracks_iter), vtl->tracks_visible ); @@ -2074,6 +2734,7 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype else return TRUE; } + default: break; } return TRUE; } @@ -2102,31 +2763,32 @@ static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_ tt->length = tt->length + vik_track_get_length (tr); // Ensure times are available - if ( tr->trackpoints && - VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp && - VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) { - - time_t t1, t2; - t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp; - t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp; + if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) { + // Get trkpt only once - as using vik_track_get_tp_last() iterates whole track each time + VikTrackpoint *trkpt_last = vik_track_get_tp_last(tr); + if ( trkpt_last->has_timestamp ) { + time_t t1, t2; + t1 = vik_track_get_tp_first(tr)->timestamp; + t2 = trkpt_last->timestamp; - // Assume never actually have a track with a time of 0 (1st Jan 1970) - // Hence initialize to the first 'proper' value - if ( tt->start_time == 0 ) - tt->start_time = t1; - if ( tt->end_time == 0 ) - tt->end_time = t2; + // Assume never actually have a track with a time of 0 (1st Jan 1970) + // Hence initialize to the first 'proper' value + if ( tt->start_time == 0 ) + tt->start_time = t1; + if ( tt->end_time == 0 ) + tt->end_time = t2; - // Update find the earliest / last times - if ( t1 < tt->start_time ) - tt->start_time = t1; - if ( t2 > tt->end_time ) - tt->end_time = t2; + // Update find the earliest / last times + if ( t1 < tt->start_time ) + tt->start_time = t1; + if ( t2 > tt->end_time ) + tt->end_time = t2; - // Keep track of total time - // there maybe gaps within a track (eg segments) - // but this should be generally good enough for a simple indicator - tt->duration = tt->duration + (int)(t2-t1); + // Keep track of total time + // there maybe gaps within a track (eg segments) + // but this should be generally good enough for a simple indicator + tt->duration = tt->duration + (int)(t2-t1); + } } } @@ -2154,7 +2816,7 @@ static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl ) // Safety check - I think these should always be valid if ( vtl->tracks && vtl->waypoints ) { - tooltip_tracks tt = { 0.0, 0, 0 }; + tooltip_tracks tt = { 0.0, 0, 0, 0 }; g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_tooltip, &tt ); GDate* gdate_start = g_date_new (); @@ -2258,14 +2920,12 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g static gchar tmp_buf[100]; // Compact info: Short date eg (11/20/99), duration and length // Hopefully these are the things that are most useful and so promoted into the tooltip - if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp ) { + if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) { // %x The preferred date representation for the current locale without the time. - strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(VIK_TRACKPOINT(tr->trackpoints->data)->timestamp))); - if ( VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) { - gint dur = ( (VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp) - (VIK_TRACKPOINT(tr->trackpoints->data)->timestamp) ); - if ( dur > 0 ) - g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) ); - } + strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(vik_track_get_tp_first(tr)->timestamp))); + time_t dur = vik_track_get_duration ( tr ); + if ( dur > 0 ) + g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) ); } // Get length and consider the appropriate distance units gdouble tr_len = vik_track_get_length(tr); @@ -2311,52 +2971,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 ( "KEATDN" ); + 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 ); } /* @@ -2502,6 +3140,21 @@ GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l ) return l->waypoints; } +GHashTable *vik_trw_layer_get_tracks_iters ( VikTrwLayer *vtl ) +{ + return vtl->tracks_iters; +} + +GHashTable *vik_trw_layer_get_routes_iters ( VikTrwLayer *vtl ) +{ + return vtl->routes_iters; +} + +GHashTable *vik_trw_layer_get_waypoints_iters ( VikTrwLayer *vtl ) +{ + return vtl->waypoints; +} + gboolean vik_trw_layer_is_empty ( VikTrwLayer *vtl ) { return ! ( g_hash_table_size ( vtl->tracks ) || @@ -2509,6 +3162,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 @@ -2560,44 +3228,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 ); } @@ -2617,16 +3267,17 @@ gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest ) } } -static void trw_layer_centerize ( gpointer layer_and_vlp[2] ) +static void trw_layer_centerize ( menu_array_layer values ) { + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); VikCoord coord; - if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) ) - goto_coord ( layer_and_vlp[1], NULL, NULL, &coord ); + if ( vik_trw_layer_find_center ( vtl, &coord ) ) + goto_coord ( values[MA_VLP], NULL, NULL, &coord ); else - a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") ); + a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") ); } -static void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] ) +void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] ) { /* First set the center [in case previously viewing from elsewhere] */ /* Then loop through zoom levels until provided positions are in view */ @@ -2634,7 +3285,7 @@ static void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 }; VikCoord coord; vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average ); - vik_viewport_set_center_coord ( vvp, &coord ); + vik_viewport_set_center_coord ( vvp, &coord, TRUE ); /* Convert into definite 'smallest' and 'largest' positions */ struct LatLon minmin; @@ -2688,174 +3339,103 @@ gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp ) } } -static void trw_layer_auto_view ( gpointer layer_and_vlp[2] ) +static void trw_layer_auto_view ( menu_array_layer values ) { - if ( vik_trw_layer_auto_set_view ( VIK_TRW_LAYER(layer_and_vlp[0]), vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(layer_and_vlp[1])) ) ) { - vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) ); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); + if ( vik_trw_layer_auto_set_view ( vtl, vik_layers_panel_get_viewport (vlp) ) ) { + vik_layers_panel_emit_update ( vlp ); } else - a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") ); + a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") ); } -static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type ) +static void trw_layer_export_gpspoint ( menu_array_layer values ) { - GtkWidget *file_selector; - const gchar *fn; - gboolean failed = FALSE; - file_selector = gtk_file_chooser_dialog_new (title, - NULL, - GTK_FILE_CHOOSER_ACTION_SAVE, - 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 ); - } + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPSPOINT ); - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name); + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPSPOINT ); - while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT ) - { - fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) ); - 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 - { - 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; - } - } - } - gtk_widget_destroy ( file_selector ); - if ( failed ) - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The filename you requested could not be opened for writing.") ); + g_free ( auto_save_name ); } -static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] ) +static void trw_layer_export_gpsmapper ( menu_array_layer values ) { - trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSPOINT ); -} + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPSMAPPER ); -static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] ) -{ - trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSMAPPER ); + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPSMAPPER ); + + g_free ( auto_save_name ); } -static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] ) +static void trw_layer_export_gpx ( menu_array_layer values ) { - /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */ - gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) ); - if ( ! check_file_ext ( auto_save_name, ".gpx" ) ) - auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL ); + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPX ); - trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX ); + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX ); g_free ( auto_save_name ); } -static void trw_layer_export_kml ( gpointer layer_and_vlp[2] ) +static void trw_layer_export_kml ( menu_array_layer values ) { - /* Auto append '.kml' to the name (providing it's not already there) for the default filename */ - gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) ); - if ( ! check_file_ext ( auto_save_name, ".kml" ) ) - auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL ); + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_KML ); - trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML ); + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML ); g_free ( auto_save_name ); } -/** - * Convert the given TRW layer into a temporary GPX file and open it with the specified program - * - */ -static void trw_layer_export_external_gpx ( gpointer layer_and_vlp[2], const gchar* external_program ) +static void trw_layer_export_geojson ( menu_array_layer values ) { - gchar *name_used = NULL; - int fd; + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GEOJSON ); - 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.") ); - } - else { - GError *err = NULL; - gchar *quoted_file = g_shell_quote ( name_used ); - gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file ); - g_free ( quoted_file ); - if ( ! g_spawn_command_line_async ( cmd, &err ) ) - { - a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( layer_and_vlp[0]), _("Could not launch %s."), external_program ); - g_error_free ( err ); - } - g_free ( cmd ); - } - // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous - //g_remove ( name_used ); - // Perhaps should be deleted when the program ends? - // For now leave it to the user to delete it / use system temp cleanup methods. - g_free ( name_used ); - } + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GEOJSON ); + + g_free ( auto_save_name ); } -static void trw_layer_export_external_gpx_1 ( gpointer layer_and_vlp[2] ) +static void trw_layer_export_babel ( gpointer layer_and_vlp[2] ) { - trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_1() ); + const gchar *auto_save_name = vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])); + vik_trw_layer_export_gpsbabel ( VIK_TRW_LAYER (layer_and_vlp[0]), _("Export Layer"), auto_save_name ); } -static void trw_layer_export_external_gpx_2 ( gpointer layer_and_vlp[2] ) +static void trw_layer_export_external_gpx_1 ( menu_array_layer values ) { - trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_2() ); + vik_trw_layer_export_external_gpx ( VIK_TRW_LAYER (values[MA_VTL]), a_vik_get_external_gpx_program_1() ); } -static void trw_layer_export_gpx_track ( gpointer pass_along[6] ) +static void trw_layer_export_external_gpx_2 ( menu_array_layer values ) { - gpointer layer_and_vlp[2]; - layer_and_vlp[0] = pass_along[0]; - layer_and_vlp[1] = pass_along[1]; + vik_trw_layer_export_external_gpx ( VIK_TRW_LAYER (values[MA_VTL]), a_vik_get_external_gpx_program_2() ); +} - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); +static void trw_layer_export_gpx_track ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !trk || !trk->name ) return; - /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */ - gchar *auto_save_name = g_strdup ( trk->name ); - if ( ! check_file_ext ( auto_save_name, ".gpx" ) ) - auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL ); + gchar *auto_save_name = append_file_ext ( trk->name, FILE_TYPE_GPX ); - trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, trk, FILE_TYPE_GPX ); + gchar *label = NULL; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + label = _("Export Route as GPX"); + else + label = _("Export Track as GPX"); + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), label, auto_save_name, trk, FILE_TYPE_GPX ); g_free ( auto_save_name ); } -typedef struct { - VikWaypoint *wp; // input - gpointer uuid; // output -} wpu_udata; - -static gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata ) +gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata ) { wpu_udata *user_data = udata; if ( wp == user_data->wp ) { @@ -2865,10 +3445,12 @@ static gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypo return FALSE; } -static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) +static void trw_layer_goto_wp ( menu_array_layer values ) { + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"), - VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), + VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, @@ -2891,14 +3473,14 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) { gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); // Find *first* wp with the given name - VikWaypoint *wp = vik_trw_layer_get_waypoint ( VIK_TRW_LAYER(layer_and_vlp[0]), name ); + VikWaypoint *wp = vik_trw_layer_get_waypoint ( vtl, name ); if ( !wp ) - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") ); + a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Waypoint not found in this layer.") ); else { - vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) ); - vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) ); + vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), &(wp->coord), TRUE ); + vik_layers_panel_emit_update ( vlp ); // Find and select on the side panel wpu_udata udata; @@ -2906,11 +3488,11 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) udata.uuid = NULL; // Hmmm, want key of it - gpointer *wpf = g_hash_table_find ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata ); + gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata ); if ( wpf && udata.uuid ) { - GtkTreeIter *it = g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, udata.uuid ); - vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, it, TRUE ); + GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid ); + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, it, TRUE ); } break; @@ -2931,9 +3513,7 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC wp->coord = *def_coord; // Attempt to auto set height if DEM data is available - gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST ); - if ( elev != VIK_DEM_INVALID_ELEVATION ) - wp->altitude = (gdouble)elev; + vik_waypoint_apply_dem_data ( wp, TRUE ); returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated ); @@ -2950,11 +3530,11 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC return FALSE; } -static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ) +static void trw_layer_new_wikipedia_wp_viewport ( menu_array_layer values ) { struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); @@ -2965,10 +3545,10 @@ static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ) vik_layers_panel_emit_update ( vlp ); } -static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ) +static void trw_layer_new_wikipedia_wp_layer ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; trw_layer_find_maxmin (vtl, maxmin); @@ -2978,17 +3558,17 @@ static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ) } #ifdef VIK_CONFIG_GEOTAG -static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] ) +static void trw_layer_geotagging_waypoint_mtime_keep ( menu_array_sublayer values ) { - VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->waypoints, values[MA_SUBLAYER_ID] ); if ( wp ) // Update directly - not changing the mtime a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE ); } -static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] ) +static void trw_layer_geotagging_waypoint_mtime_update ( menu_array_sublayer values ) { - VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->waypoints, values[MA_SUBLAYER_ID] ); if ( wp ) // Update directly a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE ); @@ -2997,88 +3577,97 @@ static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] /* * Use code in separate file for this feature as reasonably complex */ -static void trw_layer_geotagging_track ( gpointer pass_along[6] ) +static void trw_layer_geotagging_track ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikTrack *track = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); // Unset so can be reverified later if necessary vtl->has_verified_thumbnails = FALSE; trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - vtl, - track, - track->name ); + vtl, + NULL, + track ); +} + +static void trw_layer_geotagging_waypoint ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikWaypoint *wpt = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); + + trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl, + wpt, + NULL ); } -static void trw_layer_geotagging ( gpointer lav[2] ) +static void trw_layer_geotagging ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); // Unset so can be reverified later if necessary vtl->has_verified_thumbnails = FALSE; trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - vtl, - NULL, - NULL); + vtl, + NULL, + NULL ); } #endif // 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer // -/* - * Acquire into this TRW Layer straight from GPS Device - */ -static void trw_layer_acquire_gps_cb ( gpointer lav[2] ) +static void trw_layer_acquire ( menu_array_layer values, VikDataSourceInterface *datasource ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER; - a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface, NULL, NULL ); + vik_datasource_mode_t mode = datasource->mode; + if ( mode == VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT ) + mode = VIK_DATASOURCE_ADDTOLAYER; + a_acquire ( vw, vlp, vvp, mode, datasource, NULL, NULL ); } -#ifdef VIK_CONFIG_GOOGLE /* - * Acquire into this TRW Layer from Google Directions + * Acquire into this TRW Layer straight from GPS Device */ -static void trw_layer_acquire_google_cb ( gpointer lav[2] ) +static void trw_layer_acquire_gps_cb ( menu_array_layer values ) { - 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); + trw_layer_acquire ( values, &vik_datasource_gps_interface ); +} - a_acquire ( vw, vlp, vvp, &vik_datasource_google_interface, NULL, NULL ); +/* + * Acquire into this TRW Layer from Directions + */ +static void trw_layer_acquire_routing_cb ( menu_array_layer values ) +{ + trw_layer_acquire ( values, &vik_datasource_routing_interface ); +} + +/* + * Acquire into this TRW Layer from an entered URL + */ +static void trw_layer_acquire_url_cb ( menu_array_layer values ) +{ + trw_layer_acquire ( values, &vik_datasource_url_interface ); } -#endif #ifdef VIK_CONFIG_OPENSTREETMAP /* * Acquire into this TRW Layer from OSM */ -static void trw_layer_acquire_osm_cb ( gpointer lav[2] ) +static void trw_layer_acquire_osm_cb ( menu_array_layer values ) { - 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_osm_interface, NULL, NULL ); + trw_layer_acquire ( values, &vik_datasource_osm_interface ); } /** * Acquire into this TRW Layer from OSM for 'My' Traces */ -static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] ) +static void trw_layer_acquire_osm_my_traces_cb ( menu_array_layer values ) { - 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_osm_my_traces_interface, NULL, NULL ); + trw_layer_acquire ( values, &vik_datasource_osm_my_traces_interface ); } #endif @@ -3086,14 +3675,9 @@ static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] ) /* * Acquire into this TRW Layer from Geocaching.com */ -static void trw_layer_acquire_geocache_cb ( gpointer lav[2] ) +static void trw_layer_acquire_geocache_cb ( menu_array_layer values ) { - 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_gc_interface, NULL, NULL ); + trw_layer_acquire ( values, &vik_datasource_gc_interface ); } #endif @@ -3101,15 +3685,11 @@ static void trw_layer_acquire_geocache_cb ( gpointer lav[2] ) /* * Acquire into this TRW Layer from images */ -static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] ) +static void trw_layer_acquire_geotagged_cb ( menu_array_layer values ) { - 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); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); - vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER; - a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface, NULL, NULL ); + trw_layer_acquire ( values, &vik_datasource_geotag_interface ); // Reverify thumbnails as they may have changed vtl->has_verified_thumbnails = FALSE; @@ -3117,50 +3697,57 @@ static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] ) } #endif -static void trw_layer_gps_upload ( gpointer lav[2] ) +/* + * Acquire into this TRW Layer from any GPS Babel supported file + */ +static void trw_layer_acquire_file_cb ( menu_array_layer values ) { - gpointer pass_along[6]; - pass_along[0] = lav[0]; - pass_along[1] = lav[1]; - pass_along[2] = NULL; // No track - operate on the layer - pass_along[3] = NULL; - pass_along[4] = NULL; - pass_along[5] = NULL; + trw_layer_acquire ( values, &vik_datasource_file_interface ); +} - trw_layer_gps_upload_any ( pass_along ); +static void trw_layer_gps_upload ( menu_array_layer values ) +{ + menu_array_sublayer data; + gint ii; + for ( ii = MA_VTL; ii < MA_LAST; ii++ ) + data[ii] = NULL; + data[MA_VTL] = values[MA_VTL]; + data[MA_VLP] = values[MA_VLP]; + + trw_layer_gps_upload_any ( data ); } /** * If pass_along[3] is defined that this will upload just that track */ -static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) +static void trw_layer_gps_upload_any ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(pass_along[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); - // May not actually get a track here as pass_along[2&3] can be null + // May not actually get a track here as values[2&3] can be null VikTrack *track = NULL; vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL! gboolean xfer_all = FALSE; - if ( pass_along[2] ) { + if ( values[MA_SUBTYPE] ) { xfer_all = FALSE; - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { - track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); xfer_type = RTE; } - else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) { - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); xfer_type = TRK; } - else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) { + else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) { xfer_type = WPT; } - else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) { + else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) { xfer_type = RTE; } } - else if ( !pass_along[4] ) + else if ( !values[MA_CONFIRM] ) xfer_all = TRUE; // i.e. whole layer if (track && !track->visible) { @@ -3169,7 +3756,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) } GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"), - VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), + VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, @@ -3225,23 +3812,10 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) turn_off ); } -/* - * Acquire into this TRW Layer from any GPS Babel supported file - */ -static void trw_layer_acquire_file_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_file_interface, NULL, NULL ); -} - -static void trw_layer_new_wp ( gpointer lav[2] ) +static void trw_layer_new_wp ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); /* 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 ) { @@ -3253,6 +3827,7 @@ static void trw_layer_new_wp ( gpointer lav[2] ) static void new_track_create_common ( VikTrwLayer *vtl, gchar *name ) { vtl->current_track = vik_track_new(); + vik_track_set_defaults ( vtl->current_track ); vtl->current_track->visible = TRUE; if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR ) // Create track with the preferred colour from the layer properties @@ -3263,13 +3838,14 @@ static void new_track_create_common ( VikTrwLayer *vtl, gchar *name ) vik_trw_layer_add_track ( vtl, name, vtl->current_track ); } -static void trw_layer_new_track ( gpointer lav[2] ) +static void trw_layer_new_track ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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 ); } @@ -3278,6 +3854,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 @@ -3286,21 +3863,22 @@ static void new_route_create_common ( VikTrwLayer *vtl, gchar *name ) vik_trw_layer_add_route ( vtl, name, vtl->current_track ); } -static void trw_layer_new_route ( gpointer lav[2] ) +static void trw_layer_new_route ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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 ); } } -static void trw_layer_auto_routes_view ( gpointer lav[2] ) +static void trw_layer_auto_routes_view ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); if ( g_hash_table_size (vtl->routes) > 0 ) { struct LatLon maxmin[2] = { {0,0}, {0,0} }; @@ -3311,17 +3889,18 @@ static void trw_layer_auto_routes_view ( gpointer lav[2] ) } -static void trw_layer_finish_track ( gpointer lav[2] ) +static void trw_layer_finish_track ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); vtl->current_track = NULL; + vtl->route_finder_started = FALSE; vik_layer_emit_update ( VIK_LAYER(vtl) ); } -static void trw_layer_auto_tracks_view ( gpointer lav[2] ) +static void trw_layer_auto_tracks_view ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); if ( g_hash_table_size (vtl->tracks) > 0 ) { struct LatLon maxmin[2] = { {0,0}, {0,0} }; @@ -3334,13 +3913,13 @@ static void trw_layer_auto_tracks_view ( gpointer lav[2] ) static void trw_layer_single_waypoint_jump ( const gpointer id, const VikWaypoint *wp, gpointer vvp ) { /* NB do not care if wp is visible or not */ - vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) ); + vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord), TRUE ); } -static void trw_layer_auto_waypoints_view ( gpointer lav[2] ) +static void trw_layer_auto_waypoints_view ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); - VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]); /* Only 1 waypoint - jump straight to it */ if ( g_hash_table_size (vtl->waypoints) == 1 ) { @@ -3351,20 +3930,36 @@ 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 ); } vik_layers_panel_emit_update ( vlp ); } +void trw_layer_osm_traces_upload_cb ( menu_array_layer values ) +{ + osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), NULL); +} + +void trw_layer_osm_traces_upload_track_cb ( menu_array_sublayer values ) +{ + if ( values[MA_MISC] ) { + VikTrack *trk = VIK_TRACK(values[MA_MISC]); + osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), trk); + } +} + static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp ) { - static gpointer pass_along[2]; + static menu_array_layer pass_along; GtkWidget *item; GtkWidget *export_submenu; - pass_along[0] = vtl; - pass_along[1] = vlp; + pass_along[MA_VTL] = vtl; + pass_along[MA_VLP] = vlp; item = gtk_menu_item_new(); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); @@ -3452,14 +4047,26 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - gchar* external1 = g_strconcat ( _("Open with External Program_1: "), a_vik_get_external_gpx_program_1(), NULL ); + if ( have_geojson_export ) { + item = gtk_menu_item_new_with_mnemonic ( _("Export as GEO_JSON...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_geojson), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); + gtk_widget_show ( item ); + } + + item = gtk_menu_item_new_with_mnemonic ( _("Export via GPSbabel...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_babel), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); + gtk_widget_show ( item ); + + gchar* external1 = g_strdup_printf ( _("Open with External Program_1: %s"), a_vik_get_external_gpx_program_1() ); item = gtk_menu_item_new_with_mnemonic ( external1 ); g_free ( external1 ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - gchar* external2 = g_strconcat ( _("Open with External Program_2: "), a_vik_get_external_gpx_program_2(), NULL ); + gchar* external2 = g_strdup_printf ( _("Open with External Program_2: %s"), a_vik_get_external_gpx_program_2() ); item = gtk_menu_item_new_with_mnemonic ( external2 ); g_free ( external2 ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along ); @@ -3514,12 +4121,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...") ); @@ -3533,6 +4139,11 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_widget_show ( item ); #endif + item = gtk_menu_item_new_with_mnemonic ( _("From _URL...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_url_cb), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); + gtk_widget_show ( item ); + #ifdef VIK_CONFIG_GEONAMES GtkWidget *wikipedia_submenu = gtk_menu_new(); item = gtk_image_menu_item_new_with_mnemonic ( _("From _Wikipedia Waypoints") ); @@ -3571,6 +4182,7 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer item = gtk_menu_item_new_with_mnemonic ( _("From _File...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); + gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel...")); 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) ); @@ -3591,7 +4203,7 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer #ifdef VIK_CONFIG_OPENSTREETMAP item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_cb), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item); gtk_widget_show ( item ); #endif @@ -3651,7 +4263,21 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer if ( item ) { gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); - } + } + + item = gtk_image_menu_item_new_with_mnemonic ( _("Track _List...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->tracks)+g_hash_table_size (vtl->routes)) ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Waypoint List...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->waypoints)) ); } // Fake Waypoint UUIDs vi simple increasing integer @@ -3679,6 +4305,9 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp 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); @@ -3717,7 +4346,7 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t ); - trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(tr_uuid) ); + trw_layer_update_treeview ( vtl, t ); } // Fake Route UUIDs vi simple increasing integer @@ -3750,7 +4379,7 @@ void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t ); - trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(rt_uuid) ); + trw_layer_update_treeview ( vtl, t ); } /* to be called whenever a track has been deleted or may have been changed. */ @@ -3781,6 +4410,11 @@ void vik_trw_layer_reset_waypoints ( VikTrwLayer *vtl ) } } +/** + * 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; @@ -3821,9 +4455,19 @@ void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypo void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr ) { - if ( vtl->route_finder_append && vtl->route_finder_current_track ) { + if ( vtl->route_finder_append && vtl->current_track ) { vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */ - vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr ); + + // enforce end of current track equal to start of tr + VikTrackpoint *cur_end = vik_track_get_tp_last ( vtl->current_track ); + VikTrackpoint *new_start = vik_track_get_tp_first ( tr ); + if ( ! vik_coord_equals ( &cur_end->coord, &new_start->coord ) ) { + vik_track_add_trackpoint ( vtl->current_track, + vik_trackpoint_copy ( cur_end ), + FALSE ); + } + + vik_track_steal_and_append_trackpoints ( vtl->current_track, tr ); vik_track_free ( tr ); vtl->route_finder_append = FALSE; /* this means we have added it */ } else { @@ -3867,6 +4511,7 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g 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 ); } @@ -3881,6 +4526,7 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g 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 ); } @@ -3895,6 +4541,7 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g 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 @@ -3941,12 +4588,7 @@ static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl } } -typedef struct { - VikTrack *trk; // input - gpointer uuid; // output -} trku_udata; - -static gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata ) +gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata ) { trku_udata *user_data = udata; if ( trk == user_data->trk ) { @@ -3959,7 +4601,6 @@ static gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *t gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk ) { gboolean was_visible = FALSE; - if ( trk && trk->name ) { if ( trk == vtl->current_track ) { @@ -3967,13 +4608,11 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk ) vtl->current_tp_track = NULL; vtl->current_tp_id = NULL; vtl->moving_tp = FALSE; + vtl->route_finder_started = FALSE; } was_visible = trk->visible; - if ( trk == vtl->route_finder_current_track ) - vtl->route_finder_current_track = NULL; - if ( trk == vtl->route_finder_added_track ) vtl->route_finder_added_track = NULL; @@ -4000,6 +4639,8 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk ) vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) ); } } + // Incase it was selected (no item delete signal ATM) + vik_window_clear_highlight ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) ); } } return was_visible; @@ -4020,9 +4661,6 @@ gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk ) was_visible = trk->visible; - if ( trk == vtl->route_finder_current_track ) - vtl->route_finder_current_track = NULL; - if ( trk == vtl->route_finder_added_track ) vtl->route_finder_added_track = NULL; @@ -4049,6 +4687,8 @@ gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk ) vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) ); } } + // Incase it was selected (no item delete signal ATM) + vik_window_clear_highlight ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) ); } } return was_visible; @@ -4090,6 +4730,8 @@ static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp ) vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) ); } } + // Incase it was selected (no item delete signal ATM) + vik_window_clear_highlight ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) ); } } @@ -4189,7 +4831,6 @@ void vik_trw_layer_delete_all_routes ( VikTrwLayer *vtl ) { vtl->current_track = NULL; - vtl->route_finder_current_track = NULL; vtl->route_finder_added_track = NULL; if (vtl->current_tp_track) trw_layer_cancel_current_tp(vtl, FALSE); @@ -4207,7 +4848,6 @@ void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl ) { vtl->current_track = NULL; - vtl->route_finder_current_track = NULL; vtl->route_finder_added_track = NULL; if (vtl->current_tp_track) trw_layer_cancel_current_tp(vtl, FALSE); @@ -4238,9 +4878,9 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) vik_layer_emit_update ( VIK_LAYER(vtl) ); } -static void trw_layer_delete_all_tracks ( gpointer lav[2] ) +static void trw_layer_delete_all_tracks ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); // Get confirmation from the user if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Are you sure you want to delete all tracks in %s?"), @@ -4248,9 +4888,9 @@ static void trw_layer_delete_all_tracks ( gpointer lav[2] ) vik_trw_layer_delete_all_tracks (vtl); } -static void trw_layer_delete_all_routes ( gpointer lav[2] ) +static void trw_layer_delete_all_routes ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); // Get confirmation from the user if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Are you sure you want to delete all routes in %s?"), @@ -4258,9 +4898,9 @@ static void trw_layer_delete_all_routes ( gpointer lav[2] ) vik_trw_layer_delete_all_routes (vtl); } -static void trw_layer_delete_all_waypoints ( gpointer lav[2] ) +static void trw_layer_delete_all_waypoints ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); // Get confirmation from the user if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Are you sure you want to delete all waypoints in %s?"), @@ -4268,32 +4908,32 @@ static void trw_layer_delete_all_waypoints ( gpointer lav[2] ) vik_trw_layer_delete_all_waypoints (vtl); } -static void trw_layer_delete_item ( gpointer pass_along[6] ) +static void trw_layer_delete_item ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); gboolean was_visible = FALSE; - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); + VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); if ( wp && wp->name ) { - if ( GPOINTER_TO_INT ( pass_along[4]) ) + if ( GPOINTER_TO_INT (values[MA_CONFIRM]) ) // 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 ); } } - else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) + else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) { - VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( trk && trk->name ) { - if ( GPOINTER_TO_INT ( pass_along[4]) ) + if ( GPOINTER_TO_INT (values[MA_CONFIRM]) ) // 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 ); @@ -4301,12 +4941,12 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) } else { - VikTrack *trk = g_hash_table_lookup ( vtl->routes, pass_along[3] ); + VikTrack *trk = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); if ( trk && trk->name ) { - if ( GPOINTER_TO_INT ( pass_along[4]) ) + if ( GPOINTER_TO_INT (values[MA_CONFIRM]) ) // 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 ); @@ -4319,7 +4959,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) /** * 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 ) +void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name ) { vik_waypoint_set_name ( wp, new_name ); @@ -4341,12 +4981,34 @@ static void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const } } -static void trw_layer_properties_item ( gpointer pass_along[7] ) +/** + * Maintain icon of waypoint in the treeview + */ +void trw_layer_waypoint_reset_icon ( VikTrwLayer *vtl, VikWaypoint *wp ) +{ + // update the treeview + 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_icon ( VIK_LAYER(vtl)->vt, it, get_wp_sym_small (wp->symbol) ); + } + } +} + +static void trw_layer_properties_item ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); // sublayer + VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); if ( wp && wp->name ) { @@ -4355,8 +5017,8 @@ static void trw_layer_properties_item ( gpointer pass_along[7] ) if ( new_name ) trw_layer_waypoint_rename ( vtl, wp, new_name ); - 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 && values[MA_TV_ITER] ) + vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, values[MA_TV_ITER], get_wp_sym_small (wp->symbol) ); if ( updated && VIK_LAYER(vtl)->visible ) vik_layer_emit_update ( VIK_LAYER(vtl) ); @@ -4365,27 +5027,53 @@ static void trw_layer_properties_item ( gpointer pass_along[7] ) else { VikTrack *tr; - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) - tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) + tr = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); else - tr = g_hash_table_lookup ( vtl->routes, pass_along[3] ); + tr = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); if ( tr && tr->name ) { vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - vtl, + vtl, tr, - pass_along[1], /* vlp */ - pass_along[5], /* vvp */ - pass_along[6]); /* iter */ + values[MA_VLP], + values[MA_VVP], + FALSE ); } } } +/** + * trw_layer_track_statistics: + * + * Show track statistics. + * ATM jump to the stats page in the properties + * TODO: consider separating the stats into an individual dialog? + */ +static void trw_layer_track_statistics ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikTrack *trk; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) + trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + else + trk = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + + if ( trk && trk->name ) { + vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl, + trk, + values[MA_VLP], + values[MA_VVP], + 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 ) +void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk ) { trku_udata udata; udata.trk = trk; @@ -4427,39 +5115,39 @@ void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk, gpointer *trk_ static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord ) { if ( vlp ) { - vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord ); + vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord, TRUE ); vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) ); } else { /* since vlp not set, vl & vvp should be valid instead! */ if ( vl && vvp ) { - vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord ); + vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord, TRUE ); vik_layer_emit_update ( VIK_LAYER(vl) ); } } } -static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] ) +static void trw_layer_goto_track_startpoint ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( track && track->trackpoints ) - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) track->trackpoints->data)->coord) ); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_first(track)->coord) ); } -static void trw_layer_goto_track_center ( gpointer pass_along[6] ) +static void trw_layer_goto_track_center ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( track && track->trackpoints ) { @@ -4469,18 +5157,18 @@ static void trw_layer_goto_track_center ( gpointer pass_along[6] ) average.lat = (maxmin[0].lat+maxmin[1].lat)/2; average.lon = (maxmin[0].lon+maxmin[1].lon)/2; vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average ); - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &coord); } } -static void trw_layer_convert_track_route ( gpointer pass_along[6] ) +static void trw_layer_convert_track_route ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -4521,18 +5209,30 @@ static void trw_layer_convert_track_route ( gpointer pass_along[6] ) g_free ( name ); // Update in case color of track / route changes when moving between sublayers - vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } +static void trw_layer_anonymize_times ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); -static void trw_layer_extend_track_end ( gpointer pass_along[6] ) + if ( track ) + vik_track_anonymize_times ( track ); +} + +static void trw_layer_extend_track_end ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; @@ -4541,72 +5241,229 @@ static void trw_layer_extend_track_end ( gpointer pass_along[6] ) vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, track->is_route ? TOOL_CREATE_ROUTE : TOOL_CREATE_TRACK); if ( track->trackpoints ) - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) ); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_last(track)->coord) ); } /** * extend a track using route finder */ -static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] ) +static void trw_layer_extend_track_end_route_finder ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] ); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikTrack *track = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); if ( !track ) return; - VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord); vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER ); - vtl->route_finder_coord = last_coord; - vtl->route_finder_current_track = track; + vtl->current_track = track; vtl->route_finder_started = TRUE; if ( track->trackpoints ) - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ; + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &vik_track_get_tp_last(track)->coord ); +} + +/** + * + */ +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 ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + if ( track ) + apply_dem_data_common ( vtl, values[MA_VLP], track, FALSE ); } -static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) +static void trw_layer_apply_dem_data_only_missing ( menu_array_sublayer values ) { - /* 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]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( track ) - vik_track_apply_dem_data ( track ); + apply_dem_data_common ( vtl, values[MA_VLP], 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 ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + if ( !track ) + return; + + smooth_it ( vtl, track, FALSE ); } -static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) +static void trw_layer_missing_elevation_data_flat ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; - GList *trps = track->trackpoints; - if ( !trps ) + 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 ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikLayersPanel *vlp = (VikLayersPanel *)values[MA_VLP]; + + if ( !trw_layer_dem_test ( vtl, vlp ) ) return; - trps = g_list_last(trps); - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord)); + + gint changed = 0; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + // Single Waypoint + VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); + 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 ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikLayersPanel *vlp = (VikLayersPanel *)values[MA_VLP]; + + if ( !trw_layer_dem_test ( vtl, vlp ) ) + return; + + gint changed = 0; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + // Single Waypoint + VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); + 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 ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + if ( !track ) + return; + if ( !track->trackpoints ) + return; + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vik_track_get_tp_last(track)->coord)); } -static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] ) +static void trw_layer_goto_track_max_speed ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; @@ -4614,17 +5471,17 @@ static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] ) VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track ); if ( !vtp ) return; - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord)); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord)); } -static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] ) +static void trw_layer_goto_track_max_alt ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; @@ -4632,17 +5489,17 @@ static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] ) VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track ); if ( !vtp ) return; - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord)); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord)); } -static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] ) +static void trw_layer_goto_track_min_alt ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; @@ -4650,36 +5507,121 @@ static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] ) VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track ); if ( !vtp ) return; - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord)); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(vtp->coord)); } /* * Automatically change the viewport to center on the track and zoom to see the extent of the track */ -static void trw_layer_auto_track_view ( gpointer pass_along[6] ) +static void trw_layer_auto_track_view ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( trk && trk->trackpoints ) { struct LatLon maxmin[2] = { {0,0}, {0,0} }; trw_layer_find_maxmin_tracks ( NULL, trk, 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]) ); + trw_layer_zoom_to_show_latlons ( vtl, values[MA_VVP], maxmin ); + if ( values[MA_VLP] ) + vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(values[MA_VLP]) ); else vik_layer_emit_update ( VIK_LAYER(vtl) ); } } -static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ) +/* + * Refine the selected track/route with a routing engine. + * The routing engine is selected by the user, when requestiong the job. + */ +static void trw_layer_route_refine ( menu_array_sublayer values ) +{ + static gint last_engine = 0; + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikTrack *trk; + + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + 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(vtl)) ); + + /* 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(vtl)) ); + } + gtk_widget_destroy ( dialog ); + } +} + +static void trw_layer_edit_trackpoint ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); trw_layer_tpwin_init ( vtl ); } @@ -4695,21 +5637,21 @@ static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ) */ typedef struct { GList **result; - GList *exclude; + VikTrack *exclude; gboolean with_timestamps; } twt_udata; static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata) { twt_udata *user_data = udata; VikTrackpoint *p1, *p2; - - if (VIK_TRACK(value)->trackpoints == user_data->exclude) { + VikTrack *trk = VIK_TRACK(value); + if (trk == user_data->exclude) { return; } - if (VIK_TRACK(value)->trackpoints) { - p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data); - p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data); + if (trk->trackpoints) { + p1 = vik_track_get_tp_first(trk); + p2 = vik_track_get_tp_last(trk); if ( user_data->with_timestamps ) { if (!p1->has_timestamp || !p2->has_timestamp) { @@ -4727,34 +5669,41 @@ static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpoint *(user_data->result) = g_list_prepend(*(user_data->result), key); } -/* called for each key in track hash table. if original track user_data[1] is close enough - * to the passed one, add it to list in user_data[0] +/** + * find_nearby_tracks_by_time: + * + * Called for each track in track hash table. + * If the original track (in user_data[1]) is close enough (threshold period in user_data[2]) + * to the current track, then the current track is added to the list in user_data[0] */ static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data) { - time_t t1, t2; - VikTrackpoint *p1, *p2; VikTrack *trk = VIK_TRACK(value); GList **nearby_tracks = ((gpointer *)user_data)[0]; - GList *tpoints = ((gpointer *)user_data)[1]; + VikTrack *orig_trk = VIK_TRACK(((gpointer *)user_data)[1]); + + if ( !orig_trk || !orig_trk->trackpoints ) + return; /* outline: * detect reasons for not merging, and return * if no reason is found not to merge, then do it. */ + twt_udata *udata = user_data; // Exclude the original track from the compiled list - if (trk->trackpoints == tpoints) { + if (trk == udata->exclude) { return; } - t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp; - t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp; + time_t t1 = vik_track_get_tp_first(orig_trk)->timestamp; + time_t t2 = vik_track_get_tp_last(orig_trk)->timestamp; if (trk->trackpoints) { - p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data); - p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data); + + VikTrackpoint *p1 = vik_track_get_tp_first(trk); + VikTrackpoint *p2 = vik_track_get_tp_last(trk); if (!p1->has_timestamp || !p2->has_timestamp) { //g_print("no timestamp\n"); @@ -4820,17 +5769,17 @@ static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user * Tracks to merge with must be of the same 'type' as the selected track - * either all with timestamps, or all without timestamps */ -static void trw_layer_merge_with_other ( gpointer pass_along[6] ) +static void trw_layer_merge_with_other ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; GList *other_tracks = NULL; GHashTable *ght_tracks; - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) ght_tracks = vtl->routes; else ght_tracks = vtl->tracks; - VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] ); + VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; @@ -4840,10 +5789,10 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) twt_udata udata; udata.result = &other_tracks; - udata.exclude = track->trackpoints; + udata.exclude = track; // Allow merging with 'similar' time type time tracks // i.e. either those times, or those without - udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp); + udata.with_timestamps = vik_track_get_tp_first(track)->has_timestamp; g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata); other_tracks = g_list_reverse(other_tracks); @@ -4910,7 +5859,7 @@ static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer twt_udata *user_data = udata; // Skip self - if (trk->trackpoints == user_data->exclude) { + if (trk == user_data->exclude) { return; } @@ -4923,18 +5872,18 @@ static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer * i.e. doesn't care about whether tracks have consistent timestamps * ATM can only append one track at a time to the currently selected track */ -static void trw_layer_append_track ( gpointer pass_along[6] ) +static void trw_layer_append_track ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; VikTrack *trk; GHashTable *ght_tracks; - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) ght_tracks = vtl->routes; else ght_tracks = vtl->tracks; - trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -4946,7 +5895,7 @@ static void trw_layer_append_track ( gpointer pass_along[6] ) // TODO: Need to consider how to work best when we can have multiple tracks the same name... twt_udata udata; udata.result = &other_tracks_names; - udata.exclude = trk->trackpoints; + udata.exclude = trk; g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata); @@ -4996,13 +5945,13 @@ static void trw_layer_append_track ( gpointer pass_along[6] ) * If a track is selected, then is shows routes and joins the selected one * If a route is selected, then is shows tracks and joins the selected one */ -static void trw_layer_append_other ( gpointer pass_along[6] ) +static void trw_layer_append_other ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; VikTrack *trk; GHashTable *ght_mykind, *ght_others; - if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { ght_mykind = vtl->routes; ght_others = vtl->tracks; } @@ -5011,7 +5960,7 @@ static void trw_layer_append_other ( gpointer pass_along[6] ) ght_others = vtl->routes; } - trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -5023,7 +5972,7 @@ static void trw_layer_append_other ( gpointer pass_along[6] ) // TODO: Need to consider how to work best when we can have multiple tracks the same name... twt_udata udata; udata.result = &other_tracks_names; - udata.exclude = trk->trackpoints; + udata.exclude = trk; g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata); @@ -5086,10 +6035,10 @@ static void trw_layer_append_other ( gpointer pass_along[6] ) } /* merge by segments */ -static void trw_layer_merge_by_segment ( gpointer pass_along[6] ) +static void trw_layer_merge_by_segment ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); guint segments = vik_track_merge_segments ( trk ); // NB currently no need to redraw as segments not actually shown on the display // However inform the user of what happened: @@ -5100,23 +6049,23 @@ static void trw_layer_merge_by_segment ( gpointer pass_along[6] ) } /* merge by time routine */ -static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) +static void trw_layer_merge_by_timestamp ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; //time_t t1, t2; GList *tracks_with_timestamp = NULL; - VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if (orig_trk->trackpoints && - !VIK_TRACKPOINT(orig_trk->trackpoints->data)->has_timestamp) { + !vik_track_get_tp_first(orig_trk)->has_timestamp) { a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp")); return; } twt_udata udata; udata.result = &tracks_with_timestamp; - udata.exclude = orig_trk->trackpoints; + udata.exclude = orig_trk; udata.with_timestamps = TRUE; g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata); tracks_with_timestamp = g_list_reverse(tracks_with_timestamp); @@ -5155,12 +6104,8 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) nearby_tracks = NULL; } - //t1 = ((VikTrackpoint *)trps->data)->timestamp; - //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp; - - /* g_print("Original track times: %d and %d\n", t1, t2); */ params[0] = &nearby_tracks; - params[1] = (gpointer)trps; + params[1] = orig_trk; params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds /* get a list of adjacent-in-time tracks */ @@ -5169,17 +6114,6 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) /* merge them */ GList *l = nearby_tracks; while ( l ) { - /* -#define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data) -#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data) - time_t t1, t2; - t1 = get_first_trackpoint(l)->timestamp; - t2 = get_last_trackpoint(l)->timestamp; -#undef get_first_trackpoint -#undef get_last_trackpoint - g_print(" %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2); - */ - /* remove trackpoints from merged track, delete track */ vik_track_steal_and_append_trackpoints ( orig_trk, VIK_TRACK(l->data) ); vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data)); @@ -5251,14 +6185,15 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subt vik_layer_emit_update(VIK_LAYER(vtl)); } + g_free ( name ); } } /* split by time routine */ -static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) +static void trw_layer_split_by_timestamp ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); GList *trps = track->trackpoints; GList *iter; GList *newlists = NULL; @@ -5270,7 +6205,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) if ( !trps ) return; - if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), + if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Split Threshold..."), _("Split when time between trackpoints exceeds:"), &thr)) { @@ -5291,7 +6226,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) 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) ); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(VIK_TRACKPOINT(iter->data)->coord) ); } return; } @@ -5324,15 +6259,13 @@ static void trw_layer_split_by_timestamp ( 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_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 vik_trw_layer_delete_track (vtl, track); - vik_layer_emit_update(VIK_LAYER(pass_along[0])); + vik_layer_emit_update(VIK_LAYER(vtl)); } g_list_free(newlists); } @@ -5340,14 +6273,14 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) /** * Split a track by the number of points as specified by the user */ -static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) +static void trw_layer_split_by_n_points ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !track ) return; @@ -5357,7 +6290,7 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) if ( !trps ) return; - gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), + gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Split Every Nth Point"), _("Split on every Nth point:"), 250, // Default value as per typical limited track capacity of various GPS devices @@ -5413,6 +6346,7 @@ 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); @@ -5422,7 +6356,7 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) vik_trw_layer_delete_route (vtl, track); else vik_trw_layer_delete_track (vtl, track); - vik_layer_emit_update(VIK_LAYER(pass_along[0])); + vik_layer_emit_update(VIK_LAYER(vtl)); } g_list_free(newlists); } @@ -5430,10 +6364,10 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) /** * Split a track at the currently selected trackpoint */ -static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] ) +static void trw_layer_split_at_trackpoint ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - gint subtype = GPOINTER_TO_INT (pass_along[2]); + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]); trw_layer_split_at_selected_trackpoint ( vtl, subtype ); } @@ -5441,10 +6375,10 @@ static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] ) * Split a track by its segments * Routes do not have segments so don't call this for routes */ -static void trw_layer_split_segments ( gpointer pass_along[6] ) +static void trw_layer_split_segments ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *trk = g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -5458,6 +6392,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 ) { @@ -5472,18 +6407,72 @@ static void trw_layer_split_segments ( gpointer pass_along[6] ) } /* end of split/merge routines */ +static void trw_layer_trackpoint_selected_delete ( VikTrwLayer *vtl, VikTrack *trk ) +{ + GList *new_tpl; + + // Find available adjacent trackpoint + if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) ) { + if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next ) + VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */ + + // Delete current trackpoint + vik_trackpoint_free ( vtl->current_tpl->data ); + trk->trackpoints = g_list_delete_link ( trk->trackpoints, vtl->current_tpl ); + + // Set to current to the available adjacent trackpoint + vtl->current_tpl = new_tpl; + + if ( vtl->current_tp_track ) { + vik_track_calculate_bounds ( vtl->current_tp_track ); + } + } + else { + // Delete current trackpoint + vik_trackpoint_free ( vtl->current_tpl->data ); + trk->trackpoints = g_list_delete_link ( trk->trackpoints, vtl->current_tpl ); + trw_layer_cancel_current_tp ( vtl, FALSE ); + } +} + +/** + * Delete the selected point + */ +static void trw_layer_delete_point_selected ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *trk; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + if ( !trk ) + return; + + if ( !vtl->current_tpl ) + return; + + trw_layer_trackpoint_selected_delete ( vtl, trk ); + + // Track has been updated so update tps: + trw_layer_cancel_tps_of_track ( vtl, trk ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + /** * Delete adjacent track points at the same position * AKA Delete Dulplicates on the Properties Window */ -static void trw_layer_delete_points_same_position ( gpointer pass_along[6] ) +static void trw_layer_delete_points_same_position ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -5506,14 +6495,14 @@ static void trw_layer_delete_points_same_position ( gpointer pass_along[6] ) * Delete adjacent track points with the same timestamp * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track */ -static void trw_layer_delete_points_same_time ( gpointer pass_along[6] ) +static void trw_layer_delete_points_same_time ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -5532,24 +6521,112 @@ static void trw_layer_delete_points_same_time ( gpointer pass_along[6] ) vik_layer_emit_update ( VIK_LAYER(vtl) ); } +/** + * Insert a point + */ +static void trw_layer_insert_point_after ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + if ( ! track ) + return; + + trw_layer_insert_tp_beside_current_tp ( vtl, FALSE ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +static void trw_layer_insert_point_before ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; + VikTrack *track; + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + + if ( ! track ) + return; + + trw_layer_insert_tp_beside_current_tp ( vtl, TRUE ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + /** * Reverse a track */ -static void trw_layer_reverse ( gpointer pass_along[6] ) +static void trw_layer_reverse ( menu_array_sublayer values ) { - VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( ! track ) return; vik_track_reverse ( track ); - vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +/** + * Open a diary at the specified date + */ +static void trw_layer_diary_open ( VikTrwLayer *vtl, const gchar *date_str ) +{ + GError *err = NULL; + gchar *cmd = g_strdup_printf ( "%s%s", "rednotebook --date=", date_str ); + if ( ! g_spawn_command_line_async ( cmd, &err ) ) { + a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s to open file."), "rednotebook" ); + g_error_free ( err ); + } + g_free ( cmd ); +} + +/** + * Open a diary at the date of the track or waypoint + */ +static void trw_layer_diary ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + + if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); + if ( ! trk ) + return; + + gchar date_buf[20]; + date_buf[0] = '\0'; + if ( trk->trackpoints && VIK_TRACKPOINT(trk->trackpoints->data)->has_timestamp ) { + strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(VIK_TRACKPOINT(trk->trackpoints->data)->timestamp))); + trw_layer_diary_open ( vtl, date_buf ); + } + else + a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This track has no date information.") ); + } + else if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + VikWaypoint *wpt = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); + if ( ! wpt ) + return; + + gchar date_buf[20]; + date_buf[0] = '\0'; + if ( wpt->has_timestamp ) { + strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(wpt->timestamp))); + trw_layer_diary_open ( vtl, date_buf ); + } + else + a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This waypoint has no date information.") ); + } } /** @@ -5728,12 +6805,12 @@ 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] ) +static void trw_layer_sort_order_a2z ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); GtkTreeIter *iter; - switch (GPOINTER_TO_INT (pass_along[2])) { + switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) { case VIK_TRW_LAYER_SUBLAYER_TRACKS: iter = &(vtl->tracks_iter); vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING; @@ -5751,12 +6828,12 @@ static void trw_layer_sort_order_a2z ( gpointer pass_along[6] ) vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING ); } -static void trw_layer_sort_order_z2a ( gpointer pass_along[6] ) +static void trw_layer_sort_order_z2a ( menu_array_sublayer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); GtkTreeIter *iter; - switch (GPOINTER_TO_INT (pass_along[2])) { + switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) { case VIK_TRW_LAYER_SUBLAYER_TRACKS: iter = &(vtl->tracks_iter); vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING; @@ -5777,16 +6854,16 @@ static void trw_layer_sort_order_z2a ( gpointer pass_along[6] ) /** * */ -static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ) +static void trw_layer_delete_tracks_from_selection ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); GList *all = NULL; // Ensure list of track names offered is unique if ( trw_layer_has_same_track_names ( vtl->tracks ) ) { if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) { - vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE ); + vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]), vtl->tracks, TRUE ); } else return; @@ -5824,16 +6901,16 @@ static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ) /** * */ -static void trw_layer_delete_routes_from_selection ( gpointer lav[2] ) +static void trw_layer_delete_routes_from_selection ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); GList *all = NULL; // Ensure list of track names offered is unique if ( trw_layer_has_same_track_names ( vtl->routes ) ) { if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) { - vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->routes, FALSE ); + vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]), vtl->routes, FALSE ); } else return; @@ -5985,16 +7062,16 @@ static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel /** * */ -static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] ) +static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); GList *all = NULL; // Ensure list of waypoint names offered is unique if ( trw_layer_has_same_waypoint_names ( vtl ) ) { if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) { - vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) ); + vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(values[MA_VLP]) ); } else return; @@ -6068,9 +7145,9 @@ static void trw_layer_waypoints_toggle_visibility ( gpointer id, VikWaypoint *wp /** * */ -static void trw_layer_waypoints_visibility_off ( gpointer lav[2] ) +static void trw_layer_waypoints_visibility_off ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); @@ -6081,9 +7158,9 @@ static void trw_layer_waypoints_visibility_off ( gpointer lav[2] ) /** * */ -static void trw_layer_waypoints_visibility_on ( gpointer lav[2] ) +static void trw_layer_waypoints_visibility_on ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); @@ -6094,9 +7171,9 @@ static void trw_layer_waypoints_visibility_on ( gpointer lav[2] ) /** * */ -static void trw_layer_waypoints_visibility_toggle ( gpointer lav[2] ) +static void trw_layer_waypoints_visibility_toggle ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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 @@ -6122,9 +7199,9 @@ static void trw_layer_tracks_toggle_visibility ( gpointer id, VikTrack *trk ) /** * */ -static void trw_layer_tracks_visibility_off ( gpointer lav[2] ) +static void trw_layer_tracks_visibility_off ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); @@ -6135,9 +7212,9 @@ static void trw_layer_tracks_visibility_off ( gpointer lav[2] ) /** * */ -static void trw_layer_tracks_visibility_on ( gpointer lav[2] ) +static void trw_layer_tracks_visibility_on ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); @@ -6148,9 +7225,9 @@ static void trw_layer_tracks_visibility_on ( gpointer lav[2] ) /** * */ -static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] ) +static void trw_layer_tracks_visibility_toggle ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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 @@ -6160,9 +7237,9 @@ static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] ) /** * */ -static void trw_layer_routes_visibility_off ( gpointer lav[2] ) +static void trw_layer_routes_visibility_off ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); @@ -6173,9 +7250,9 @@ static void trw_layer_routes_visibility_off ( gpointer lav[2] ) /** * */ -static void trw_layer_routes_visibility_on ( gpointer lav[2] ) +static void trw_layer_routes_visibility_on ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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] ); @@ -6186,41 +7263,161 @@ static void trw_layer_routes_visibility_on ( gpointer lav[2] ) /** * */ -static void trw_layer_routes_visibility_toggle ( gpointer lav[2] ) +static void trw_layer_routes_visibility_toggle ( menu_array_layer values ) { - VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); 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) ); } -static void trw_layer_goto_waypoint ( gpointer pass_along[6] ) +/** + * vik_trw_layer_build_waypoint_list_t: + * + * Helper function to construct a list of #vik_trw_waypoint_list_t + */ +GList *vik_trw_layer_build_waypoint_list_t ( VikTrwLayer *vtl, GList *waypoints ) { - VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + GList *waypoints_and_layers = NULL; + // build waypoints_and_layers list + while ( waypoints ) { + vik_trw_waypoint_list_t *vtdl = g_malloc (sizeof(vik_trw_waypoint_list_t)); + vtdl->wpt = VIK_WAYPOINT(waypoints->data); + vtdl->vtl = vtl; + waypoints_and_layers = g_list_prepend ( waypoints_and_layers, vtdl ); + waypoints = g_list_next ( waypoints ); + } + return waypoints_and_layers; +} + +/** + * trw_layer_create_waypoint_list: + * + * Create the latest list of waypoints with the associated layer(s) + * Although this will always be from a single layer here + */ +static GList* trw_layer_create_waypoint_list ( VikLayer *vl, gpointer user_data ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(vl); + GList *waypoints = g_hash_table_get_values ( vik_trw_layer_get_waypoints(vtl) ); + + return vik_trw_layer_build_waypoint_list_t ( vtl, waypoints ); +} + +/** + * 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; +} + +/** + * vik_trw_layer_build_track_list_t: + * + * Helper function to construct a list of #vik_trw_track_list_t + */ +GList *vik_trw_layer_build_track_list_t ( VikTrwLayer *vtl, GList *tracks ) +{ + GList *tracks_and_layers = NULL; + // build tracks_and_layers list + 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 ); + } + return tracks_and_layers; +} + +/** + * trw_layer_create_track_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_create_track_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) ); + + return vik_trw_layer_build_track_list_t ( vtl, tracks ); +} + +static void trw_layer_tracks_stats ( menu_array_layer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + // 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_TRACKS), + trw_layer_create_track_list, + trw_layer_analyse_close ); +} + +/** + * + */ +static void trw_layer_routes_stats ( menu_array_layer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + // 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_create_track_list, + trw_layer_analyse_close ); +} + +static void trw_layer_goto_waypoint ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); if ( wp ) - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(wp->coord) ); + goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &(wp->coord) ); } -static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] ) +static void trw_layer_waypoint_gc_webpage ( menu_array_sublayer values ) { - VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); if ( !wp ) return; gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", wp->name ); - open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage); + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), webpage); g_free ( webpage ); } -static void trw_layer_waypoint_webpage ( gpointer pass_along[6] ) +static void trw_layer_waypoint_webpage ( menu_array_sublayer values ) { - VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] ); if ( !wp ) return; - if ( !strncmp(wp->comment, "http", 4) ) { - open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->comment); + if ( wp->url ) { + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->url); + } else if ( !strncmp(wp->comment, "http", 4) ) { + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->comment); } else if ( !strncmp(wp->description, "http", 4) ) { - open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->description); + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->description); } } @@ -6338,9 +7535,9 @@ static gboolean is_valid_geocache_name ( gchar *str ) return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6])); } -static void trw_layer_track_use_with_filter ( gpointer pass_along[6] ) +static void trw_layer_track_use_with_filter ( menu_array_sublayer values ) { - VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->tracks, values[MA_SUBLAYER_ID] ); a_acquire_set_filter_track ( trk ); } @@ -6351,13 +7548,13 @@ static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_i return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) ); } -static void trw_layer_google_route_webpage ( gpointer pass_along[6] ) +static void trw_layer_google_route_webpage ( menu_array_sublayer values ) { - VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] ); + VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->routes, values[MA_SUBLAYER_ID] ); if ( tr ) { gchar *escaped = uri_escape ( tr->comment ); gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped ); - open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage); + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(values[MA_VTL])), webpage); g_free ( escaped ); g_free ( webpage ); } @@ -6368,18 +7565,18 @@ static void trw_layer_google_route_webpage ( gpointer pass_along[6] ) /* viewpoint is now available instead */ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp ) { - static gpointer pass_along[8]; + static menu_array_sublayer pass_along; GtkWidget *item; gboolean rv = FALSE; - pass_along[0] = l; - pass_along[1] = vlp; - pass_along[2] = GINT_TO_POINTER (subtype); - pass_along[3] = sublayer; - pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request - pass_along[5] = vvp; - pass_along[6] = iter; - pass_along[7] = NULL; // For misc purposes - maybe track or waypoint + pass_along[MA_VTL] = l; + pass_along[MA_VLP] = vlp; + pass_along[MA_SUBTYPE] = GINT_TO_POINTER (subtype); + pass_along[MA_SUBLAYER_ID] = sublayer; + pass_along[MA_CONFIRM] = GINT_TO_POINTER (1); // Confirm delete request + pass_along[MA_VVP] = vvp; + pass_along[MA_TV_ITER] = iter; + pass_along[MA_MISC] = NULL; // For misc purposes - maybe track or waypoint if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { @@ -6418,18 +7615,15 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - gboolean separator_created = FALSE; + // Always create separator as now there is always at least the transform menu option + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); /* could be a right-click using the tool */ if ( vlp != NULL ) { - item = gtk_menu_item_new (); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - - separator_created = TRUE; - item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -6439,35 +7633,27 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men if ( wp && wp->name ) { if ( is_valid_geocache_name ( wp->name ) ) { - - if ( !separator_created ) { - item = gtk_menu_item_new (); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - separator_created = TRUE; - } - item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); } +#ifdef VIK_CONFIG_GEOTAG + item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_set_tooltip_text (item, _("Geotag multiple images against this waypoint")); + gtk_widget_show ( item ); +#endif } if ( wp && wp->image ) { - if ( !separator_created ) { - item = gtk_menu_item_new (); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - separator_created = TRUE; - } - - // Set up image paramater - pass_along[5] = wp->image; + // Set up image paramater + pass_along[MA_MISC] = 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 ); @@ -6494,7 +7680,8 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men if ( wp ) { - if ( ( wp->comment && !strncmp(wp->comment, "http", 4) ) || + if ( wp->url || + ( wp->comment && !strncmp(wp->comment, "http", 4) ) || ( wp->description && !strncmp(wp->description, "http", 4) )) { item = gtk_image_menu_item_new_with_mnemonic ( _("Visit _Webpage") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) ); @@ -6503,7 +7690,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); } } - } } @@ -6583,6 +7769,11 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men 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 ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_List Waypoints...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); } if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS ) @@ -6648,6 +7839,16 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men 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 ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_List Tracks...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along ); + 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_tracks_stats), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); } @@ -6715,6 +7916,17 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men 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 ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_List Routes...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along ); + 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_routes_stats), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); } @@ -6772,6 +7984,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") ); @@ -6895,6 +8112,27 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men // Make it available only when a trackpoint is selected. gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) ); + GtkWidget *insert_submenu = gtk_menu_new (); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Insert Points") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, 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), insert_submenu ); + + item = gtk_menu_item_new_with_mnemonic ( _("Insert Point _Before Selected Point") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_insert_point_before), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(insert_submenu), item ); + gtk_widget_show ( item ); + // Make it available only when a point is selected + gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) ); + + item = gtk_menu_item_new_with_mnemonic ( _("Insert Point _After Selected Point") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_insert_point_after), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(insert_submenu), item ); + gtk_widget_show ( item ); + // Make it available only when a point is selected + gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) ); + GtkWidget *delete_submenu; delete_submenu = gtk_menu_new (); item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") ); @@ -6903,6 +8141,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu ); + item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _Selected Point") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_point_selected), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); + // Make it available only when a point is selected + gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) ); + item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); @@ -6913,6 +8159,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 @@ -6922,24 +8232,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 @@ -6958,18 +8270,9 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) - item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") ); - else - item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("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 ); @@ -6991,6 +8294,17 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men } } + // Only made available if a suitable program is installed + if ( have_diary_program ) { + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("Diar_y") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_diary), 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 && is_valid_google_route ( l, sublayer ) ) { @@ -7006,10 +8320,10 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { #ifdef VIK_CONFIG_OPENSTREETMAP item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") ); - // Convert internal pointer into actual track for usage outside this file - pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer); + // Convert internal pointer into track + pass_along[MA_MISC] = g_hash_table_lookup ( l->tracks, sublayer); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_track_cb), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item ); gtk_widget_show ( item ); #endif @@ -7055,54 +8369,94 @@ 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; } -static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ) +// TODO: Probably better to rework this track manipulation in viktrack.c +static void trw_layer_insert_tp_beside_current_tp ( VikTrwLayer *vtl, gboolean before ) { - /* sanity checks */ + // sanity check if (!vtl->current_tpl) return; - if (!vtl->current_tpl->next) - return; VikTrackpoint *tp_current = VIK_TRACKPOINT(vtl->current_tpl->data); - VikTrackpoint *tp_next = VIK_TRACKPOINT(vtl->current_tpl->next->data); + VikTrackpoint *tp_other = NULL; + + if ( before ) { + if (!vtl->current_tpl->prev) + return; + tp_other = VIK_TRACKPOINT(vtl->current_tpl->prev->data); + } else { + if (!vtl->current_tpl->next) + return; + tp_other = VIK_TRACKPOINT(vtl->current_tpl->next->data); + } - /* Use current and next trackpoints to form a new track point which is inserted into the tracklist */ - if ( tp_next ) { + // Use current and other trackpoints to form a new track point which is inserted into the tracklist + if ( tp_other ) { VikTrackpoint *tp_new = vik_trackpoint_new(); - struct LatLon ll_current, ll_next; + struct LatLon ll_current, ll_other; vik_coord_to_latlon ( &tp_current->coord, &ll_current ); - vik_coord_to_latlon ( &tp_next->coord, &ll_next ); + vik_coord_to_latlon ( &tp_other->coord, &ll_other ); /* main positional interpolation */ - struct LatLon ll_new = { (ll_current.lat+ll_next.lat)/2, (ll_current.lon+ll_next.lon)/2 }; + struct LatLon ll_new = { (ll_current.lat+ll_other.lat)/2, (ll_current.lon+ll_other.lon)/2 }; vik_coord_load_from_latlon ( &(tp_new->coord), vtl->coord_mode, &ll_new ); /* Now other properties that can be interpolated */ - tp_new->altitude = (tp_current->altitude + tp_next->altitude) / 2; + tp_new->altitude = (tp_current->altitude + tp_other->altitude) / 2; - if (tp_current->has_timestamp && tp_next->has_timestamp) { + if (tp_current->has_timestamp && tp_other->has_timestamp) { /* Note here the division is applied to each part, then added This is to avoid potential overflow issues with a 32 time_t for dates after midpoint of this Unix time on 2004/01/04 */ - tp_new->timestamp = (tp_current->timestamp/2) + (tp_next->timestamp/2); + tp_new->timestamp = (tp_current->timestamp/2) + (tp_other->timestamp/2); tp_new->has_timestamp = TRUE; } - if (tp_current->speed != NAN && tp_next->speed != NAN) - tp_new->speed = (tp_current->speed + tp_next->speed)/2; + if (tp_current->speed != NAN && tp_other->speed != NAN) + tp_new->speed = (tp_current->speed + tp_other->speed)/2; /* TODO - improve interpolation of course, as it may not be correct. 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; + if (tp_current->course != NAN && tp_other->course != NAN) + tp_new->course = (tp_current->course + tp_other->course)/2; /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */ - /* Insert new point into the trackpoints list after the current TP */ + // Insert new point into the appropriate trackpoint list, either before or after the current trackpoint as directed VikTrack *trk = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id ); if ( !trk ) // Otherwise try routes @@ -7112,8 +8466,10 @@ static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ) gint index = g_list_index ( trk->trackpoints, tp_current ); if ( index > -1 ) { + if ( !before ) + index = index + 1; // NB no recalculation of bounds since it is inserted between points - trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index+1 ); + trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index ); } } } @@ -7151,7 +8507,7 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev ) { trw_layer_split_at_selected_trackpoint ( vtl, vtl->current_tp_track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK ); - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); } else if ( response == VIK_TRW_LAYER_TPWIN_DELETE ) { @@ -7161,52 +8517,29 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) if ( tr == NULL ) return; - GList *new_tpl; - - // Find available adjacent trackpoint - if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) ) - { - if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next ) - VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */ - - // Delete current trackpoint - vik_trackpoint_free ( vtl->current_tpl->data ); - tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl ); - - // Set to current to the available adjacent trackpoint - vtl->current_tpl = new_tpl; + trw_layer_trackpoint_selected_delete ( vtl, tr ); + if ( vtl->current_tpl ) // Reset dialog with the available adjacent trackpoint - 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_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); - vik_layer_emit_update(VIK_LAYER(vtl)); - } - else - { - // Delete current trackpoint - vik_trackpoint_free ( vtl->current_tpl->data ); - tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl ); - trw_layer_cancel_current_tp ( vtl, FALSE ); - } + vik_layer_emit_update(VIK_LAYER(vtl)); } else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next ) { if ( vtl->current_tp_track ) - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */ } else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev ) { if ( vtl->current_tp_track ) - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update(VIK_LAYER(vtl)); } else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next ) { - trw_layer_insert_tp_after_current_tp ( vtl ); + trw_layer_insert_tp_beside_current_tp ( vtl, FALSE ); vik_layer_emit_update(VIK_LAYER(vtl)); } else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED ) @@ -7224,6 +8557,10 @@ void trw_layer_dialog_shift ( VikTrwLayer *vtl, GtkWindow *dialog, VikCoord *coo { 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 ); @@ -7324,7 +8661,7 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) 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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); /* set layer name and TP data */ } @@ -7516,8 +8853,12 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve // Determine if working on a waypoint or a trackpoint if ( t->is_waypoint ) { + // Update waypoint position vtl->current_wp->coord = new_coord; trw_layer_calculate_bounds_waypoints ( vtl ); + // Reset waypoint pointer + vtl->current_wp = NULL; + vtl->current_wp_id = NULL; } else { if ( vtl->current_tpl ) { @@ -7526,17 +8867,13 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve if ( vtl->current_tp_track ) vik_track_calculate_bounds ( vtl->current_tp_track ); - if ( vtl->tpwin ) + if ( vtl->tpwin ) if ( vtl->current_tp_track ) - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); + // 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; } @@ -7595,6 +8932,15 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event vtl->current_wp = wp_params.closest_wp; vtl->current_wp_id = wp_params.closest_wp_id; + if ( event->type == GDK_2BUTTON_PRESS ) { + if ( vtl->current_wp->image ) { + menu_array_sublayer values; + values[MA_VTL] = vtl; + values[MA_MISC] = vtl->current_wp->image; + trw_layer_show_picture ( values ); + } + } + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -7608,6 +8954,7 @@ 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) { @@ -7637,7 +8984,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp ); if ( vtl->tpwin ) - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -7672,7 +9019,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp ); if ( vtl->tpwin ) - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -7838,6 +9185,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; @@ -7877,14 +9229,14 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve 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; g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); - if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL ) + if ( vtl->current_wp && (vtl->current_wp == params.closest_wp) ) { - // how do we get here? - marker_begin_move(t, event->x, event->y); - g_critical("shouldn't be here"); + if ( event->button == 3 ) + vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */ + else + marker_begin_move(t, event->x, event->y); return FALSE; } else if ( params.closest_wp ) @@ -8034,6 +9386,7 @@ static gboolean draw_sync ( gpointer data ) ds->vtl->draw_sync_done = TRUE; gdk_threads_leave(); } + g_free ( ds ); return FALSE; } @@ -8121,8 +9474,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo { /* if we haven't sync'ed yet, we don't have time to do more. */ if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) { - GList *iter = g_list_last ( vtl->current_track->trackpoints ); - VikTrackpoint *last_tpt = VIK_TRACKPOINT(iter->data); + VikTrackpoint *last_tpt = vik_track_get_tp_last(vtl->current_track); static GdkPixmap *pixmap = NULL; int w1, h1, w2, h2; @@ -8236,23 +9588,37 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo return VIK_LAYER_TOOL_ACK; } +// NB vtl->current_track must be valid +static void undo_trackpoint_add ( VikTrwLayer *vtl ) +{ + // 'undo' + if ( vtl->current_track->trackpoints ) { + // TODO rework this... + //vik_trackpoint_free ( vik_track_get_tp_last (vtl->current_track) ); + GList *last = g_list_last(vtl->current_track->trackpoints); + g_free ( last->data ); + vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); + + vik_track_calculate_bounds ( vtl->current_track ); + } +} + static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ) { if ( vtl->current_track && event->keyval == GDK_Escape ) { + // Bin track if only one point as it's not very useful + if ( vik_track_get_tp_count(vtl->current_track) == 1 ) { + if ( vtl->current_track->is_route ) + vik_trw_layer_delete_route ( vtl, vtl->current_track ); + else + vik_trw_layer_delete_track ( vtl, vtl->current_track ); + } vtl->current_track = NULL; vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) { - /* undo */ - if ( vtl->current_track->trackpoints ) - { - GList *last = g_list_last(vtl->current_track->trackpoints); - g_free ( last->data ); - vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); - } - + undo_trackpoint_add ( vtl ); update_statusbar ( vtl ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -8283,16 +9649,8 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton { if ( !vtl->current_track ) return FALSE; - /* undo */ - if ( vtl->current_track->trackpoints ) - { - GList *last = g_list_last(vtl->current_track->trackpoints); - g_free ( last->data ); - vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); - } - vik_track_calculate_bounds ( vtl->current_track ); + undo_trackpoint_add ( vtl ); update_statusbar ( vtl ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -8302,10 +9660,8 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton /* subtract last (duplicate from double click) tp then end */ if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 ) { - GList *last = g_list_last(vtl->current_track->trackpoints); - g_free ( last->data ); - vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); /* undo last, then end */ + undo_trackpoint_add ( vtl ); vtl->current_track = NULL; } vik_layer_emit_update ( VIK_LAYER(vtl) ); @@ -8344,16 +9700,20 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { + // if we were running the route finder, cancel it + vtl->route_finder_started = FALSE; + // ----------------------------------------------------- if current is a route - switch to new track 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 ) ) ) - { - new_track_create_common ( vtl, name ); + if ( a_vik_get_ask_for_create_track_name() ) { + name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ); + if ( !name ) + return FALSE; } - else - return TRUE; + new_track_create_common ( vtl, name ); + g_free ( name ); } return tool_new_track_or_route_click ( vtl, event, vvp ); } @@ -8376,14 +9736,21 @@ static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp) static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { - // -------------------------- if current is a track - switch to new route - if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) ) + // if we were running the route finder, cancel it + vtl->route_finder_started = FALSE; + + // -------------------------- if current is a track - switch to new route, + 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 ) ) ) - new_route_create_common ( vtl, name ); - else - return TRUE; + if ( a_vik_get_ask_for_create_track_name() ) { + name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ); + if ( !name ) + return FALSE; + } + new_route_create_common ( vtl, name ); + g_free ( name ); } return tool_new_track_or_route_click ( vtl, event, vvp ); } @@ -8419,6 +9786,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; @@ -8436,6 +9808,7 @@ 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 ) @@ -8563,7 +9936,7 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton /* diff dist is diff from orig */ if ( vtl->tpwin ) - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -8572,77 +9945,121 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton } -/*** Route Finder ***/ -static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp) +/*** Extended Route Finder ***/ + +static gpointer tool_extended_route_finder_create ( VikWindow *vw, VikViewport *vvp) { return vvp; } -static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static void tool_extended_route_finder_undo ( VikTrwLayer *vtl ) +{ + VikCoord *new_end; + new_end = vik_track_cut_back_to_double_point ( vtl->current_track ); + if ( new_end ) { + g_free ( new_end ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + + /* remove last ' to:...' */ + if ( vtl->current_track->comment ) { + gchar *last_to = strrchr ( vtl->current_track->comment, 't' ); + if ( last_to && (last_to - vtl->current_track->comment > 1) ) { + gchar *new_comment = g_strndup ( vtl->current_track->comment, + last_to - vtl->current_track->comment - 1); + vik_track_set_comment_no_copy ( vtl->current_track, new_comment ); + } + } + } +} + + +static gboolean tool_extended_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { VikCoord tmp; if ( !vtl ) return FALSE; vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp ); - if ( event->button == 3 && vtl->route_finder_current_track ) { - VikCoord *new_end; - new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track ); - if ( new_end ) { - vtl->route_finder_coord = *new_end; - g_free ( new_end ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); - /* remove last ' to:...' */ - if ( vtl->route_finder_current_track->comment ) { - gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' ); - if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) { - gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment, - last_to - vtl->route_finder_current_track->comment - 1); - vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment ); - } - } - } + if ( event->button == 3 && vtl->current_track ) { + tool_extended_route_finder_undo ( vtl ); + } + else if ( event->button == 2 ) { + vtl->draw_sync_do = FALSE; + return FALSE; + } + // if we started the track but via undo deleted all the track points, begin again + else if ( vtl->current_track && vtl->current_track->is_route && ! vik_track_get_tp_first ( vtl->current_track ) ) { + return tool_new_track_or_route_click ( vtl, event, vvp ); } - else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) { + else if ( ( vtl->current_track && vtl->current_track->is_route ) || + ( event->state & GDK_CONTROL_MASK && vtl->current_track ) ) { struct LatLon start, end; - vik_coord_to_latlon ( &(vtl->route_finder_coord), &start ); + VikTrackpoint *tp_start = vik_track_get_tp_last ( vtl->current_track ); + vik_coord_to_latlon ( &(tp_start->coord), &start ); vik_coord_to_latlon ( &(tmp), &end ); - vtl->route_finder_coord = tmp; /* for continuations */ - /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */ - if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) { - vtl->route_finder_append = TRUE; // merge tracks. keep started true. - } else { - vtl->route_finder_check_added_track = TRUE; - vtl->route_finder_started = FALSE; + vtl->route_finder_started = TRUE; + vtl->route_finder_append = TRUE; // merge tracks. keep started true. + + // update UI to let user know what's going on + VikStatusbar *sb = vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))); + VikRoutingEngine *engine = vik_routing_default_engine ( ); + if ( ! engine ) { + vik_statusbar_set_message ( sb, VIK_STATUSBAR_INFO, "Cannot plan route without a default routing engine." ); + return TRUE; } + gchar *msg = g_strdup_printf ( _("Querying %s for route between (%.3f, %.3f) and (%.3f, %.3f)."), + vik_routing_engine_get_label ( engine ), + start.lat, start.lon, end.lat, end.lon ); + vik_statusbar_set_message ( sb, VIK_STATUSBAR_INFO, msg ); + g_free ( msg ); + vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) ); - 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 ) { - vik_track_set_comment_no_copy ( vtl->route_finder_added_track, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) ); - } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) { - /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */ - 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 ); - } + /* Give GTK a change to display the new status bar before querying the web */ + while ( gtk_events_pending ( ) ) + gtk_main_iteration ( ); - if ( vtl->route_finder_added_track ) - vik_track_calculate_bounds ( vtl->route_finder_added_track ); + gboolean find_status = vik_routing_default_find ( vtl, start, end ); - vtl->route_finder_added_track = NULL; - vtl->route_finder_check_added_track = FALSE; - vtl->route_finder_append = FALSE; + /* Update UI to say we're done */ + vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) ); + msg = ( find_status ) ? g_strdup_printf ( _("%s returned route between (%.3f, %.3f) and (%.3f, %.3f)."), + vik_routing_engine_get_label ( engine ), + start.lat, start.lon, end.lat, end.lon ) + : g_strdup_printf ( _("Error getting route from %s."), + vik_routing_engine_get_label ( engine ) ); + vik_statusbar_set_message ( sb, VIK_STATUSBAR_INFO, msg ); + g_free ( msg ); vik_layer_emit_update ( VIK_LAYER(vtl) ); } else { + vtl->current_track = NULL; + + // create a new route where we will add the planned route to + gboolean ret = tool_new_route_click( vtl, event, vvp ); + vtl->route_finder_started = TRUE; - vtl->route_finder_coord = tmp; - vtl->route_finder_current_track = NULL; + + return ret; } return TRUE; } +static gboolean tool_extended_route_finder_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ) +{ + if ( vtl->current_track && event->keyval == GDK_Escape ) { + vtl->route_finder_started = FALSE; + vtl->current_track = NULL; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) { + tool_extended_route_finder_undo ( vtl ); + } + return FALSE; +} + + + /*** Show picture ****/ static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp) @@ -8671,19 +10088,19 @@ static void tool_show_picture_wp ( const gpointer id, VikWaypoint *wp, gpointer } } -static void trw_layer_show_picture ( gpointer pass_along[6] ) +static void trw_layer_show_picture ( menu_array_sublayer values ) { /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */ #ifdef WINDOWS - ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, "open", (char *) values[MA_MISC], NULL, NULL, SW_SHOWNORMAL); #else /* WINDOWS */ GError *err = NULL; - gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] ); + gchar *quoted_file = g_shell_quote ( (gchar *) values[MA_MISC] ); gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file ); g_free ( quoted_file ); if ( ! g_spawn_command_line_async ( cmd, &err ) ) { - a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch %s to open file."), a_vik_get_image_viewer() ); + a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(values[MA_VTL]), _("Could not launch %s to open file."), a_vik_get_image_viewer() ); g_error_free ( err ); } g_free ( cmd ); @@ -8698,10 +10115,10 @@ static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *even g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params ); if ( params[2] ) { - static gpointer pass_along[6]; - pass_along[0] = vtl; - pass_along[5] = params[2]; - trw_layer_show_picture ( pass_along ); + static menu_array_sublayer values; + values[MA_VTL] = vtl; + values[MA_MISC] = params[2]; + trw_layer_show_picture ( values ); return TRUE; /* found a match */ } else @@ -8819,7 +10236,7 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl ) VIK_TRACK(value)->has_color = TRUE; } - trw_layer_update_treeview ( vtl, VIK_TRACK(value), key ); + trw_layer_update_treeview ( vtl, VIK_TRACK(value) ); ii++; if (ii > VIK_TRW_LAYER_TRACK_GCS) @@ -8841,7 +10258,7 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl ) VIK_TRACK(value)->has_color = TRUE; } - trw_layer_update_treeview ( vtl, VIK_TRACK(value), key ); + trw_layer_update_treeview ( vtl, VIK_TRACK(value) ); ii = !ii; } @@ -8851,7 +10268,7 @@ static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl ) * (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 ) +void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl ) { struct LatLon topleft = { 0.0, 0.0 }; struct LatLon bottomright = { 0.0, 0.0 }; @@ -8902,6 +10319,9 @@ static void trw_layer_calculate_bounds_tracks ( VikTrwLayer *vtl ) 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 ); @@ -8915,7 +10335,8 @@ static void trw_layer_sort_all ( VikTrwLayer *vtl ) static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file ) { - trw_layer_verify_thumbnails ( vtl, vvp ); + if ( VIK_LAYER(vtl)->realized ) + trw_layer_verify_thumbnails ( vtl, vvp ); trw_layer_track_alloc_colors ( vtl ); trw_layer_calculate_bounds_waypoints ( vtl ); @@ -8927,6 +10348,64 @@ static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean fro // 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 ); + + // Setting metadata time if not otherwise set + if ( vtl->metadata ) { + + gboolean need_to_set_time = TRUE; + if ( vtl->metadata->timestamp ) { + need_to_set_time = FALSE; + if ( !g_strcmp0(vtl->metadata->timestamp, "" ) ) + need_to_set_time = TRUE; + } + + if ( need_to_set_time ) { + // Could rewrite this as a general get first time of a TRW Layer function + GTimeVal timestamp; + timestamp.tv_usec = 0; + gboolean has_timestamp = FALSE; + + GList *gl = NULL; + gl = g_hash_table_get_values ( vtl->tracks ); + gl = g_list_sort ( gl, vik_track_compare_timestamp ); + gl = g_list_first ( gl ); + + // Check times of tracks + if ( gl ) { + // Only need to check the first track as they have been sorted by time + VikTrack *trk = (VikTrack*)gl->data; + // Assume trackpoints already sorted by time + VikTrackpoint *tpt = vik_track_get_tp_first(trk); + if ( tpt && tpt->has_timestamp ) { + timestamp.tv_sec = tpt->timestamp; + has_timestamp = TRUE; + } + g_list_free ( gl ); + } + + if ( !has_timestamp ) { + // 'Last' resort - current time + // Get before waypoint tests - so that if a waypoint time value (in the past) is found it should be used + g_get_current_time ( ×tamp ); + + // Check times of waypoints + gl = g_hash_table_get_values ( vtl->waypoints ); + GList *iter; + for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) { + VikWaypoint *wpt = (VikWaypoint*)iter->data; + if ( wpt->has_timestamp ) { + if ( timestamp.tv_sec > wpt->timestamp ) { + timestamp.tv_sec = wpt->timestamp; + has_timestamp = TRUE; + } + } + } + g_list_free ( gl ); + } + + vtl->metadata->timestamp = g_time_val_to_iso8601 ( ×tamp ); + } + } } VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl ) @@ -9104,16 +10583,16 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g g_message("%s: this feature works only in Mercator mode", __FUNCTION__); if (fillins) { - GList *iter = fillins; - while (iter) { - cur_coord = (VikCoord *)(iter->data); + GList *fiter = fillins; + while (fiter) { + cur_coord = (VikCoord *)(fiter->data); vik_coord_set_area(cur_coord, &wh, &tl, &br); rect = g_malloc(sizeof(Rect)); rect->tl = tl; rect->br = br; rect->center = *cur_coord; rects_to_download = g_list_prepend(rects_to_download, rect); - iter = iter->next; + fiter = fiter->next; } } @@ -9133,23 +10612,21 @@ 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] ) +static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values ) { 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]; + VikTrwLayer *vtl = values[MA_VTL]; + VikLayersPanel *vlp = values[MA_VLP]; 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] ); + if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] ); else - trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] ); if ( !trk ) return; @@ -9159,49 +10636,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]); @@ -9270,3 +10733,50 @@ static gchar *highest_wp_number_get(VikTrwLayer *vtl) g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 ); return g_strdup(buf); } + +/** + * trw_layer_create_track_list_both: + * + * Create the latest list of tracks and routes + */ +static GList* trw_layer_create_track_list_both ( VikLayer *vl, gpointer user_data ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(vl); + GList *tracks = NULL; + tracks = g_list_concat ( tracks, g_hash_table_get_values ( vik_trw_layer_get_tracks ( vtl ) ) ); + tracks = g_list_concat ( tracks, g_hash_table_get_values ( vik_trw_layer_get_routes ( vtl ) ) ); + + return vik_trw_layer_build_track_list_t ( vtl, tracks ); +} + +static void trw_layer_track_list_dialog_single ( menu_array_sublayer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + + gchar *title = NULL; + if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACKS ) + title = g_strdup_printf ( _("%s: Track List"), VIK_LAYER(vtl)->name ); + else + title = g_strdup_printf ( _("%s: Route List"), VIK_LAYER(vtl)->name ); + + vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), values[MA_SUBTYPE], trw_layer_create_track_list, FALSE ); + g_free ( title ); +} + +static void trw_layer_track_list_dialog ( menu_array_layer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + + gchar *title = g_strdup_printf ( _("%s: Track and Route List"), VIK_LAYER(vtl)->name ); + vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_track_list_both, FALSE ); + g_free ( title ); +} + +static void trw_layer_waypoint_list_dialog ( menu_array_layer values ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]); + + gchar *title = g_strdup_printf ( _("%s: Waypoint List"), VIK_LAYER(vtl)->name ); + vik_trw_layer_waypoint_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_waypoint_list, FALSE ); + g_free ( title ); +}