X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/3986744ba1895257f41b9bbec2148cf662579b80..ec84f3a6395b3a3c672f0572841ed6eda8ee828a:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index 81cdabca..c8220d6c 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -23,7 +23,7 @@ * */ /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */ -/* viktrwlayer.c -- 5000+ lines can make a difference in the state of things */ +/* viktrwlayer.c -- 8000+ lines can make a difference in the state of things */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -73,26 +73,22 @@ #include #include -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS -// This is currently broken as Google have disabled the KML output in Google Maps API v3 -// It has been ifdefed out in the hope that Route Finding functionality will be restored one day... -// Only have 'JSON' and 'XML' see: -// https://developers.google.com/maps/documentation/directions/#DirectionsResponses -#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml" +#ifdef VIK_CONFIG_GOOGLE +#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js" #endif -#define VIK_TRW_LAYER_TRACK_GC 16 -#define VIK_TRW_LAYER_TRACK_GC_RATES 10 -#define VIK_TRW_LAYER_TRACK_GC_MIN 0 -#define VIK_TRW_LAYER_TRACK_GC_MAX 11 -#define VIK_TRW_LAYER_TRACK_GC_BLACK 12 -#define VIK_TRW_LAYER_TRACK_GC_SLOW 13 -#define VIK_TRW_LAYER_TRACK_GC_AVER 14 -#define VIK_TRW_LAYER_TRACK_GC_FAST 15 +#define VIK_TRW_LAYER_TRACK_GC 6 +#define VIK_TRW_LAYER_TRACK_GCS 10 +#define VIK_TRW_LAYER_TRACK_GC_BLACK 0 +#define VIK_TRW_LAYER_TRACK_GC_SLOW 1 +#define VIK_TRW_LAYER_TRACK_GC_AVER 2 +#define VIK_TRW_LAYER_TRACK_GC_FAST 3 +#define VIK_TRW_LAYER_TRACK_GC_STOP 4 +#define VIK_TRW_LAYER_TRACK_GC_SINGLE 5 #define DRAWMODE_BY_TRACK 0 #define DRAWMODE_BY_SPEED 1 -#define DRAWMODE_ALL_BLACK 2 +#define DRAWMODE_ALL_SAME_COLOR 2 // Note using DRAWMODE_BY_SPEED may be slow especially for vast numbers of trackpoints // as we are (re)calculating the colour for every point @@ -126,10 +122,12 @@ struct _VikTrwLayer { VikLayer vl; GHashTable *tracks; GHashTable *tracks_iters; + GHashTable *routes; + GHashTable *routes_iters; GHashTable *waypoints_iters; GHashTable *waypoints; - GtkTreeIter waypoints_iter, tracks_iter; - gboolean tracks_visible, waypoints_visible; + GtkTreeIter tracks_iter, routes_iter, waypoints_iter; + gboolean tracks_visible, routes_visible, waypoints_visible; guint8 drawmode; guint8 drawpoints; guint8 drawpoints_size; @@ -150,6 +148,8 @@ struct _VikTrwLayer { gdouble track_draw_speed_factor; GArray *track_gc; + GdkGC *track_1color_gc; + GdkColor track_color; GdkGC *current_track_gc; // Separate GC for a track's potential new point as drawn via separate method // (compared to the actual track points drawn in the main trw_layer_draw_track function) @@ -158,7 +158,8 @@ struct _VikTrwLayer { GdkGC *waypoint_gc; GdkGC *waypoint_text_gc; GdkGC *waypoint_bg_gc; - VikTrack *current_track; + GdkFont *waypoint_font; + VikTrack *current_track; // ATM shared between new tracks and new routes guint16 ct_x1, ct_y1, ct_x2, ct_y2; gboolean draw_sync_done; gboolean draw_sync_do; @@ -218,12 +219,12 @@ typedef struct { struct DrawingParams { VikViewport *vp; VikTrwLayer *vtl; + VikWindow *vw; gdouble xmpp, ympp; guint16 width, height; gdouble cc; // Cosine factor in track directions gdouble ss; // Sine factor in track directions const VikCoord *center; - gint track_gc_iter; gboolean one_zone, lat_lon; gdouble ce1, ce2, cn1, cn2; }; @@ -234,15 +235,15 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ); static void trw_layer_copy_item_cb ( gpointer pass_along[6] ); static void trw_layer_cut_item_cb ( gpointer pass_along[6] ); -static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] ); -static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *trk, struct LatLon maxmin[2] ); +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]); static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp ); static void trw_layer_free_track_gcs ( VikTrwLayer *vtl ); -static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp ); -static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp ); +static void trw_layer_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 goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord ); static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] ); @@ -272,6 +273,9 @@ 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] ); @@ -287,11 +291,12 @@ 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_DIRECTIONS +#ifdef VIK_CONFIG_GOOGLE static void trw_layer_acquire_google_cb ( gpointer lav[2] ); #endif #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] ); #endif #ifdef VIK_CONFIG_GEOCACHES static void trw_layer_acquire_geocache_cb ( gpointer lav[2] ); @@ -302,10 +307,18 @@ static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] ); static void trw_layer_acquire_file_cb ( gpointer lav[2] ); static void trw_layer_gps_upload ( gpointer lav[2] ); +// 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] ); + /* 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_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] ); static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] ); @@ -326,8 +339,8 @@ static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp); 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 ); -static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp); -static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp ); @@ -335,7 +348,7 @@ static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, Vi static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ); static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS +#ifdef VIK_CONFIG_GOOGLE static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); #endif @@ -347,7 +360,7 @@ static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikV static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ); static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode ); -static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode ); +static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode ); static gchar *highest_wp_number_get(VikTrwLayer *vtl); static void highest_wp_number_reset(VikTrwLayer *vtl); @@ -376,11 +389,14 @@ static VikToolInterface trw_layer_tools[] = { TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf }, - { { "BeginTrack", "vik-icon-Begin Track", N_("_Begin Track"), "B", N_("Begin Track"), 0 }, - (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL, - (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL, - FALSE, - GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf }, + { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "B", N_("Create Route"), 0 }, + (VikToolConstructorFunc) tool_new_route_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_new_route_click, + (VikToolMouseMoveFunc) tool_new_track_move, // -\# + (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 }, { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "E", N_("Edit Waypoint"), 0 }, (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL, @@ -404,7 +420,7 @@ static VikToolInterface trw_layer_tools[] = { FALSE, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf }, -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS +#ifdef VIK_CONFIG_GOOGLE { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "F", N_("Route Finder"), 0 }, (VikToolConstructorFunc) tool_route_finder_create, NULL, NULL, NULL, (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL, @@ -412,14 +428,26 @@ static VikToolInterface trw_layer_tools[] = { GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf }, #endif }; -enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS }; + +enum { + TOOL_CREATE_WAYPOINT=0, + TOOL_CREATE_TRACK, + TOOL_CREATE_ROUTE, + TOOL_EDIT_WAYPOINT, + TOOL_EDIT_TRACKPOINT, + TOOL_SHOW_PICTURE, +#ifdef VIK_CONFIG_GOOGLE + TOOL_ROUTE_FINDER, +#endif + NUM_TOOLS +}; /****** PARAMETERS ******/ static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") }; enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES }; -static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Black"), 0 }; +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 }; #define MIN_POINT_SIZE 2 @@ -456,40 +484,45 @@ static gchar* params_font_sizes[] = { NULL }; VikLayerParam trw_layer_params[] = { - { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES }, - { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES }, - - { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL }, - { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 }, - { "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 11 }, - { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 10 }, - { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 9 }, - - { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 }, - - { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 }, - { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, 0 }, - { "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 1 }, - - { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL }, - { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, 0 }, - { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, 0 }, - { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, 0 }, - { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, 0 }, - { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL }, - { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 }, - { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON }, - - { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON }, - { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 3 }, - { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 4 }, - { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 }, + { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL }, + { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL }, + { "routes_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL }, + + { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL }, + { "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") }, + { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[0], NULL, NULL }, + { "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[11], NULL, NULL }, + { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[10], NULL, NULL }, + { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[9], NULL, NULL }, + + { "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") }, + { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[8], NULL, NULL }, + + { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[6], NULL, NULL}, + { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL }, + { "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") }, + + { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL }, + { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL }, + { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL }, + { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL }, + { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_COMBOBOX, params_wpsymbols, NULL, NULL }, + { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, ¶ms_scales[7], NULL, NULL }, + { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + + { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL }, + { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[3], NULL, NULL }, + { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[4], NULL, NULL }, + { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, ¶ms_scales[5], NULL, NULL }, }; // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE @@ -497,8 +530,10 @@ enum { // Sublayer visibilities PARAM_TV, PARAM_WV, + PARAM_RV, // Tracks PARAM_DM, + PARAM_TC, PARAM_DL, PARAM_LT, PARAM_DD, @@ -541,6 +576,7 @@ static VikTrwLayer* trw_layer_new ( gint drawmode ); /* Layer Interface function definitions */ static VikTrwLayer* trw_layer_create ( VikViewport *vp ); static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ); +static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp ); static void trw_layer_free ( VikTrwLayer *trwlayer ); static void trw_layer_draw ( VikTrwLayer *l, gpointer data ); static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode ); @@ -587,7 +623,7 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncCreate) trw_layer_create, (VikLayerFuncRealize) trw_layer_realize, - (VikLayerFuncPostRead) trw_layer_verify_thumbnails, + (VikLayerFuncPostRead) trw_layer_post_read, (VikLayerFuncFree) trw_layer_free, (VikLayerFuncProperties) NULL, @@ -629,12 +665,6 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncSelectedViewportMenu) trw_layer_show_selected_viewport_menu, }; -// for copy & paste -typedef struct { - guint len; - guint8 data[0]; -} FlatItem; - GType vik_trw_layer_get_type () { static GType vtl_type = 0; @@ -713,13 +743,20 @@ static void trw_layer_copy_item_cb ( gpointer pass_along[6]) else name = NULL; // Broken :( } - else { + else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { VikTrack *trk = g_hash_table_lookup ( vtl->tracks, sublayer); if ( trk && trk->name ) name = trk->name; else name = NULL; // Broken :( } + else { + VikTrack *trk = g_hash_table_lookup ( vtl->routes, sublayer); + if ( trk && trk->name ) + name = trk->name; + else + name = NULL; // Broken :( + } a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW, subtype, len, name, data); @@ -733,9 +770,14 @@ static void trw_layer_cut_item_cb ( gpointer pass_along[6]) trw_layer_delete_item(pass_along); } +static void trw_layer_paste_item_cb ( gpointer pass_along[6]) +{ + // Slightly cheating method, routing via the panels capability + a_clipboard_paste (VIK_LAYERS_PANEL(pass_along[1])); +} + static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ) { - FlatItem *fi; guint8 *id; guint il; @@ -744,38 +786,36 @@ static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer subla return; } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) - { - vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il ); - // 'Simple' memory copy of byte array from the marshalling above - *len = sizeof(FlatItem) + 1 + il; // not sure what the 1 is for yet... - fi = g_malloc ( *len ); - fi->len = *len; - memcpy(fi->data, id, il); - } else { + GByteArray *ba = g_byte_array_new (); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il ); + } else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il ); - // less magic than before... - *len = sizeof(FlatItem) + 1 + il; - fi = g_malloc ( *len ); - fi->len = *len; - memcpy(fi->data, id, il); + } else { + vik_track_marshall ( g_hash_table_lookup ( vtl->routes, sublayer ), &id, &il ); } + g_byte_array_append ( ba, id, il ); + g_free(id); - *item = (guint8 *)fi; + + *len = ba->len; + *item = ba->data; } static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len ) { - FlatItem *fi = (FlatItem *) item; + if ( !item ) + return FALSE; + + gchar *name; - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && fi ) + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { VikWaypoint *w; - gchar *name; - w = vik_waypoint_unmarshall(fi->data, fi->len); + w = vik_waypoint_unmarshall ( item, len ); // When copying - we'll create a new name based on the original name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, w->name); vik_trw_layer_add_waypoint ( vtl, name, w ); @@ -783,23 +823,37 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i // Consider if redraw necessary for the new item if ( vtl->vl.visible && vtl->waypoints_visible && w->visible ) - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi ) + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { VikTrack *t; - gchar *name; - t = vik_track_unmarshall(fi->data, fi->len); + t = vik_track_unmarshall ( item, len ); // When copying - we'll create a new name based on the original name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name); vik_trw_layer_add_track ( vtl, name, t ); - track_convert (name, t, &vtl->coord_mode); + vik_track_convert (t, vtl->coord_mode); // Consider if redraw necessary for the new item if ( vtl->vl.visible && vtl->tracks_visible && t->visible ) - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + { + VikTrack *t; + + t = vik_track_unmarshall ( item, len ); + // When copying - we'll create a new name based on the original + 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); + + // Consider if redraw necessary for the new item + if ( vtl->vl.visible && vtl->routes_visible && t->visible ) + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } return FALSE; @@ -818,7 +872,12 @@ 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_DM: vtl->drawmode = data.u; break; + case PARAM_TC: + vtl->track_color = data.c; + trw_layer_new_track_gcs ( vtl, vp ); + break; case PARAM_DP: vtl->drawpoints = data.b; break; case PARAM_DPS: if ( data.u >= MIN_POINT_SIZE && data.u <= MAX_POINT_SIZE ) @@ -844,7 +903,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara trw_layer_new_track_gcs ( vtl, vp ); } break; - case PARAM_BLT: if ( data.u >= 0 && data.u <= 8 && data.u != vtl->bg_line_thickness ) + case PARAM_BLT: if ( data.u <= 8 && data.u != vtl->bg_line_thickness ) { vtl->bg_line_thickness = data.u; trw_layer_new_track_gcs ( vtl, vp ); @@ -886,7 +945,9 @@ 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_DM: rv.u = vtl->drawmode; break; + case PARAM_TC: rv.c = vtl->track_color; break; case PARAM_DP: rv.b = vtl->drawpoints; break; case PARAM_DPS: rv.u = vtl->drawpoints_size; break; case PARAM_DE: rv.b = vtl->drawelevation; break; @@ -920,58 +981,126 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) { guint8 *pd; - gchar *dd; - gsize dl; gint pl; - gchar *tmpname; - FILE *f; *data = NULL; - if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { - a_gpx_write_file(vtl, f, NULL); - vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl); - fclose(f); - f = NULL; - g_file_get_contents(tmpname, &dd, &dl, NULL); - *len = sizeof(pl) + pl + dl; - *data = g_malloc(*len); - memcpy(*data, &pl, sizeof(pl)); - memcpy(*data + sizeof(pl), pd, pl); - memcpy(*data + sizeof(pl) + pl, dd, dl); - - g_free(pd); - g_free(dd); - g_remove(tmpname); - g_free(tmpname); + // Use byte arrays to store sublayer data + // much like done elsewhere e.g. vik_layer_marshall_params() + GByteArray *ba = g_byte_array_new ( ); + + guint8 *sl_data; + guint sl_len; + + guint object_length; + guint subtype; + // store: + // the length of the item + // the sublayer type of item + // the the actual item +#define tlm_append(object_pointer, size, type) \ + subtype = (type); \ + object_length = (size); \ + g_byte_array_append ( ba, (guint8 *)&object_length, sizeof(object_length) ); \ + g_byte_array_append ( ba, (guint8 *)&subtype, sizeof(subtype) ); \ + g_byte_array_append ( ba, (object_pointer), object_length ); + + // Layer parameters first + vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl); + g_byte_array_append ( ba, (guint8 *)&pl, sizeof(pl) ); \ + g_byte_array_append ( ba, pd, pl ); + g_free ( pd ); + + // Now sublayer data + GHashTableIter iter; + gpointer key, value; + + // Waypoints + g_hash_table_iter_init ( &iter, vtl->waypoints ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + vik_waypoint_marshall ( VIK_WAYPOINT(value), &sl_data, &sl_len ); + tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_WAYPOINT ); + g_free ( sl_data ); + } + + // Tracks + g_hash_table_iter_init ( &iter, vtl->tracks ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + vik_track_marshall ( VIK_TRACK(value), &sl_data, &sl_len ); + tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_TRACK ); + g_free ( sl_data ); + } + + // Routes + g_hash_table_iter_init ( &iter, vtl->routes ); + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + vik_track_marshall ( VIK_TRACK(value), &sl_data, &sl_len ); + tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_ROUTE ); + g_free ( sl_data ); } + +#undef tlm_append + + *data = ba->data; + *len = ba->len; } static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp ) { - VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE )); + VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE )); gint pl; - gchar *tmpname; - FILE *f; - + gint consumed_length; + // First the overall layer parameters memcpy(&pl, data, sizeof(pl)); data += sizeof(pl); - vik_layer_unmarshall_params ( VIK_LAYER(rv), data, pl, vvp ); + vik_layer_unmarshall_params ( VIK_LAYER(vtl), data, pl, vvp ); data += pl; - if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { - g_critical("couldn't open temp file"); - exit(1); - } - fwrite(data, len - pl - sizeof(pl), 1, f); - rewind(f); - a_gpx_read_file(rv, f); - fclose(f); - f = NULL; - g_remove(tmpname); - g_free(tmpname); - return rv; + consumed_length = pl; + const gint sizeof_len_and_subtype = sizeof(gint) + sizeof(gint); + +#define tlm_size (*(gint *)data) + // See marshalling above for order of how this is written +#define tlm_next \ + data += sizeof_len_and_subtype + tlm_size; + + // Now the individual sublayers: + + while ( *data && consumed_length < len ) { + // Normally four extra bytes at the end of the datastream + // (since it's a GByteArray and that's where it's length is stored) + // So only attempt read when there's an actual block of sublayer data + if ( consumed_length + tlm_size < len ) { + + // Reuse pl to read the subtype from the data stream + memcpy(&pl, data+sizeof(gint), sizeof(pl)); + + if ( pl == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 ); + gchar *name = g_strdup ( trk->name ); + vik_trw_layer_add_track ( vtl, name, trk ); + g_free ( name ); + } + if ( pl == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + VikWaypoint *wp = vik_waypoint_unmarshall ( data + sizeof_len_and_subtype, 0 ); + gchar *name = g_strdup ( wp->name ); + vik_trw_layer_add_waypoint ( vtl, name, wp ); + g_free ( name ); + } + if ( pl == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 ); + gchar *name = g_strdup ( trk->name ); + vik_trw_layer_add_route ( vtl, name, trk ); + g_free ( name ); + } + } + consumed_length += tlm_size + sizeof_len_and_subtype; + tlm_next; + } + //g_debug ("consumed_length %d vs len %d", consumed_length, len); + + return vtl; } // Keep interesting hash function at least visible @@ -1001,11 +1130,6 @@ static guint strcase_hash(gconstpointer v) static VikTrwLayer* trw_layer_new ( gint drawmode ) { - if (trw_layer_params[PARAM_DM].widget_data == NULL) - trw_layer_params[PARAM_DM].widget_data = str_array_to_glist(params_drawmodes); - if (trw_layer_params[PARAM_WPSYM].widget_data == NULL) - trw_layer_params[PARAM_WPSYM].widget_data = str_array_to_glist(params_wpsymbols); - VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) ); vik_layer_set_type ( VIK_LAYER(rv), VIK_LAYER_TRW ); @@ -1025,53 +1149,32 @@ static VikTrwLayer* trw_layer_new ( gint drawmode ) rv->waypoints_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free ); rv->tracks = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free ); rv->tracks_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free ); + rv->routes = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free ); + rv->routes_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free ); - /* TODO: constants at top */ - rv->waypoints_visible = rv->tracks_visible = TRUE; + // Default values + rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE; rv->drawmode = drawmode; rv->drawpoints = TRUE; rv->drawpoints_size = MIN_POINT_SIZE; rv->drawdirections_size = 5; - rv->drawstops = FALSE; - rv->drawelevation = FALSE; rv->elevation_factor = 30; rv->stop_length = 60; rv->drawlines = TRUE; - rv->wplabellayout = NULL; - rv->wp_right_click_menu = NULL; - rv->track_right_click_menu = NULL; - rv->waypoint_gc = NULL; - rv->waypoint_text_gc = NULL; - rv->waypoint_bg_gc = NULL; - rv->track_gc = NULL; rv->track_draw_speed_factor = 30.0; rv->line_thickness = 1; - rv->bg_line_thickness = 0; - rv->current_wp = NULL; - rv->current_wp_id = NULL; - rv->current_track = NULL; - rv->current_tpl = NULL; - rv->current_tp_track = NULL; - rv->current_tp_id = NULL; - rv->moving_tp = FALSE; - rv->moving_wp = FALSE; rv->draw_sync_done = TRUE; rv->draw_sync_do = TRUE; - rv->route_finder_started = FALSE; - rv->route_finder_check_added_track = FALSE; - rv->route_finder_current_track = NULL; - rv->route_finder_append = FALSE; - - rv->waypoint_rightclick = FALSE; - rv->tpwin = NULL; rv->image_cache = g_queue_new(); rv->image_size = 64; rv->image_alpha = 255; rv->image_cache_size = 300; rv->drawimages = TRUE; rv->drawlabels = TRUE; + // Everything else is 0, FALSE or NULL + return rv; } @@ -1113,12 +1216,13 @@ static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, Vi { dp->vtl = vtl; dp->vp = vp; + dp->vw = (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl); dp->xmpp = vik_viewport_get_xmpp ( vp ); dp->ympp = vik_viewport_get_ympp ( vp ); dp->width = vik_viewport_get_width ( vp ); dp->height = vik_viewport_get_height ( vp ); - dp->cc = vtl->drawdirections_size*cos(45 * DEG2RAD); // Calculate once per vtl update - even if not used - dp->ss = vtl->drawdirections_size*sin(45 * DEG2RAD); // Calculate once per vtl update - even if not used + dp->cc = vtl->drawdirections_size*cos(DEG2RAD(45)); // Calculate once per vtl update - even if not used + dp->ss = vtl->drawdirections_size*sin(DEG2RAD(45)); // Calculate once per vtl update - even if not used dp->center = vik_viewport_get_center ( vp ); dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */ @@ -1146,8 +1250,6 @@ static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, Vi dp->cn1 = bottomright.north_south; dp->cn2 = upperleft.north_south; } - - dp->track_gc_iter = 0; } /* @@ -1174,7 +1276,7 @@ static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1 return VIK_TRW_LAYER_TRACK_GC_BLACK; } -void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y ) +static void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y ) { vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y ); vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 ); @@ -1182,7 +1284,7 @@ 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 ( const gchar *name, VikTrack *track, struct DrawingParams *dp, gboolean drawing_white_background ) +static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline ) { /* TODO: this function is a mess, get rid of any redundancy */ GList *list = track->trackpoints; @@ -1209,10 +1311,10 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr return; /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */ - if ( dp->vtl->bg_line_thickness && !drawing_white_background ) - trw_layer_draw_track ( name, track, dp, TRUE ); + if ( dp->vtl->bg_line_thickness && !draw_track_outline ) + trw_layer_draw_track ( id, track, dp, TRUE ); - if ( drawing_white_background ) + if ( draw_track_outline ) drawpoints = drawstops = FALSE; else { drawpoints = dp->vtl->drawpoints; @@ -1229,24 +1331,29 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr /* 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 && ( ( dp->vtl == vik_window_get_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) || - ( dp->vtl->tracks == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) || - track == vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) { + 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; } - else { - if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK ) - dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK; - - main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter); - } } - else { - if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK ) - dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK; - - main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter); + if ( !drawing_highlight ) { + // Still need to figure out the gc according to the drawing mode: + switch ( dp->vtl->drawmode ) { + case DRAWMODE_BY_TRACK: + if ( dp->vtl->track_1color_gc ) + g_object_unref ( dp->vtl->track_1color_gc ); + dp->vtl->track_1color_gc = vik_viewport_new_gc_from_color ( dp->vp, &track->color, dp->vtl->line_thickness ); + main_gc = dp->vtl->track_1color_gc; + break; + default: + // Mostly for DRAWMODE_ALL_SAME_COLOR + // but includes DRAWMODE_BY_SPEED, main_gc is set later on as necessary + main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_SINGLE); + break; + } } } @@ -1258,8 +1365,9 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y ); - if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC ) - { + // Draw the first point as something a bit different from the normal points + // ATM it's slightly bigger and a triangle + if ( drawpoints ) { GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} }; vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 ); } @@ -1297,7 +1405,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr if ( useoldvals && x == oldx && y == oldy ) { // Still need to process points to ensure 'stops' are drawn if required - if ( drawstops && drawpoints && ! drawing_white_background && list->next && + if ( drawstops && drawpoints && ! draw_track_outline && list->next && (VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length) ) vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 ); @@ -1308,12 +1416,11 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr if ( drawpoints || dp->vtl->drawlines ) { // setup main_gc for both point and line drawing if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) { - dp->track_gc_iter = track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ); - main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter); + main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ) ); } } - if ( drawpoints && ! drawing_white_background ) + if ( drawpoints && ! draw_track_outline ) { if ( list->next ) { @@ -1326,8 +1433,8 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr */ /* stops */ if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length ) - /* Stop point. Draw 6x circle. */ - vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 ); + /* Stop point. Draw 6x circle. Always in redish colour */ + vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_STOP), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 ); /* Regular point - draw 2x square. */ vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size ); @@ -1347,7 +1454,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr if (!useoldvals) vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy ); - if ( drawing_white_background ) { + if ( draw_track_outline ) { vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y); } else { @@ -1409,8 +1516,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y ); if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) { - dp->track_gc_iter = track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ); - main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter); + main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed )); } /* @@ -1418,7 +1524,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr */ if ( x != oldx || y != oldy ) { - if ( drawing_white_background ) + if ( draw_track_outline ) vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y); else vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y); @@ -1440,15 +1546,12 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr } } } - if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK ) - if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC_MAX ) - dp->track_gc_iter = 0; } /* the only reason this exists is so that trw_layer_draw_track can first call itself to draw the white track background */ -static void trw_layer_draw_track_cb ( const gchar *name, VikTrack *track, struct DrawingParams *dp ) +static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp ) { - trw_layer_draw_track ( name, track, dp, FALSE ); + trw_layer_draw_track ( id, track, dp, FALSE ); } static void cached_pixbuf_free ( CachedPixbuf *cp ) @@ -1462,7 +1565,7 @@ static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name ) return strcmp ( cp->image, name ); } -static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp ) +static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp ) { if ( wp->visible ) if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) && @@ -1534,9 +1637,9 @@ static void trw_layer_draw_waypoint ( const gchar *name, 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 ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) || - dp->vtl->waypoints == vik_window_get_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) || - wp == vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) { + 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, @@ -1616,9 +1719,9 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct /* 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 ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) || - dp->vtl->waypoints == vik_window_get_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) || - wp == vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) + 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); @@ -1641,6 +1744,9 @@ static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) if ( l->tracks_visible ) g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp ); + if ( l->routes_visible ) + g_hash_table_foreach ( l->routes, (GHFunc) trw_layer_draw_track_cb, &dp ); + if (l->waypoints_visible) g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint, &dp ); } @@ -1653,6 +1759,11 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl ) g_object_unref ( vtl->track_bg_gc ); vtl->track_bg_gc = NULL; } + if ( vtl->track_1color_gc ) + { + g_object_unref ( vtl->track_1color_gc ); + vtl->track_1color_gc = NULL; + } if ( vtl->current_track_gc ) { g_object_unref ( vtl->current_track_gc ); @@ -1701,27 +1812,15 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp ) vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC ); - gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */ - - gc[1] = vik_viewport_new_gc ( vp, "#0a8742", width ); - gc[2] = vik_viewport_new_gc ( vp, "#0a8783", width ); - gc[3] = vik_viewport_new_gc ( vp, "#0a4d87", width ); - gc[4] = vik_viewport_new_gc ( vp, "#05469f", width ); - gc[5] = vik_viewport_new_gc ( vp, "#1b059f", width ); - gc[6] = vik_viewport_new_gc ( vp, "#2d059f", width ); - gc[7] = vik_viewport_new_gc ( vp, "#4a059f", width ); - gc[8] = vik_viewport_new_gc ( vp, "#84059f", width ); - gc[9] = vik_viewport_new_gc ( vp, "#96059f", width ); - gc[10] = vik_viewport_new_gc ( vp, "#f22ef2", width ); - - gc[11] = vik_viewport_new_gc ( vp, "#874200", width ); /* above range */ - - gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */ + gc[VIK_TRW_LAYER_TRACK_GC_STOP] = vik_viewport_new_gc ( vp, "#874200", width ); + gc[VIK_TRW_LAYER_TRACK_GC_BLACK] = vik_viewport_new_gc ( vp, "#000000", width ); // black gc[VIK_TRW_LAYER_TRACK_GC_SLOW] = vik_viewport_new_gc ( vp, "#E6202E", width ); // red-ish gc[VIK_TRW_LAYER_TRACK_GC_AVER] = vik_viewport_new_gc ( vp, "#D2CD26", width ); // yellow-ish gc[VIK_TRW_LAYER_TRACK_GC_FAST] = vik_viewport_new_gc ( vp, "#2B8700", width ); // green-ish + gc[VIK_TRW_LAYER_TRACK_GC_SINGLE] = vik_viewport_new_gc_from_color ( vp, &(vtl->track_color), width ); + g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC ); } @@ -1738,6 +1837,8 @@ 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(vp)->style->font_desc); + gdk_color_parse ( "#000000", &(rv->track_color) ); // Black + trw_layer_new_track_gcs ( rv, vp ); rv->waypoint_gc = vik_viewport_new_gc ( vp, "#000000", 2 ); @@ -1758,18 +1859,52 @@ static VikTrwLayer* trw_layer_create ( VikViewport *vp ) return rv; } +#define SMALL_ICON_SIZE 18 +/* + * Can accept a null symbol, and may return null value + */ +static 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. + // So needing a small icon for the treeview may need some resizing: + if ( wp_icon && gdk_pixbuf_get_width ( wp_icon ) != SMALL_ICON_SIZE ) + wp_icon = gdk_pixbuf_scale_simple ( wp_icon, SMALL_ICON_SIZE, SMALL_ICON_SIZE, GDK_INTERP_BILINEAR ); + return wp_icon; +} + static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] ) { GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter)); + GdkPixbuf *pixbuf = NULL; + + if ( track->has_color ) { + pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, SMALL_ICON_SIZE, SMALL_ICON_SIZE ); + // Annoyingly the GdkColor.pixel does not give the correct color when passed to gdk_pixbuf_fill (even when alloc'ed) + // Here is some magic found to do the conversion + // http://www.cs.binghamton.edu/~sgreene/cs360-2011s/topics/gtk+-2.20.1/gtk/gtkcolorbutton.c + guint32 pixel = ((track->color.red & 0xff00) << 16) | + ((track->color.green & 0xff00) << 8) | + (track->color.blue & 0xff00); + + gdk_pixbuf_fill ( pixbuf, pixel ); + } + #ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE ); + vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE ); #else - vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE ); + vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE ); #endif + if ( pixbuf ) + g_object_unref (pixbuf); + *new_iter = *((GtkTreeIter *) pass_along[1]); - g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, id, new_iter ); + if ( track->is_route ) + g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->routes_iters, id, new_iter ); + else + g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, id, new_iter ); if ( ! track->visible ) vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE ); @@ -1778,10 +1913,11 @@ static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pas static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] ) { GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter)); + #ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), NULL, TRUE, TRUE ); + vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE ); #else - vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), NULL, TRUE, TRUE ); + vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE ); #endif *new_iter = *((GtkTreeIter *) pass_along[1]); @@ -1791,35 +1927,67 @@ static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE ); } - -static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) +static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) { - GtkTreeIter iter2; - gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACK) }; - #ifdef VIK_CONFIG_ALPHABETIZED_TRW vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE ); #else vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE ); #endif - if ( ! vtl->tracks_visible ) - vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), FALSE ); - - g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along ); +} +static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) +{ #ifdef VIK_CONFIG_ALPHABETIZED_TRW vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE ); #else vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE ); #endif +} + +static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) +{ +#ifdef VIK_CONFIG_ALPHABETIZED_TRW + vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE ); +#else + vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE ); +#endif +} + +static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter ) +{ + GtkTreeIter iter2; + gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACK) }; + + if ( g_hash_table_size (vtl->tracks) > 0 ) { + trw_layer_add_sublayer_tracks ( vtl, vt , layer_iter ); + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along ); + + vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->tracks_iter), vtl->tracks_visible ); + } + + if ( g_hash_table_size (vtl->routes) > 0 ) { - if ( ! vtl->waypoints_visible ) - vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), FALSE ); + trw_layer_add_sublayer_routes ( vtl, vt, layer_iter ); - pass_along[0] = &(vtl->waypoints_iter); - pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT); + pass_along[0] = &(vtl->routes_iter); + pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTE); - g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along ); + g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_realize_track, pass_along ); + + vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->routes_iter), vtl->routes_visible ); + } + + if ( g_hash_table_size (vtl->waypoints) > 0 ) { + trw_layer_add_sublayer_waypoints ( vtl, vt, layer_iter ); + + pass_along[0] = &(vtl->waypoints_iter); + pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT); + + g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along ); + + vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), vtl->waypoints_visible ); + } } @@ -1829,6 +1997,7 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype { case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1); case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1); + case VIK_TRW_LAYER_SUBLAYER_ROUTES: return (l->routes_visible ^= 1); case VIK_TRW_LAYER_SUBLAYER_TRACK: { VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer ); @@ -1845,6 +2014,14 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype else return TRUE; } + case VIK_TRW_LAYER_SUBLAYER_ROUTE: + { + VikTrack *t = g_hash_table_lookup ( l->routes, sublayer ); + if (t) + return (t->visible ^= 1); + else + return TRUE; + } } return TRUE; } @@ -1974,8 +2151,8 @@ static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl ) // Put together all the elements to form compact tooltip text g_snprintf (tmp_buf, sizeof(tmp_buf), - _("Tracks: %d - Waypoints: %d%s"), - g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), tbuf2); + _("Tracks: %d - Waypoints: %d - Routes: %d%s"), + g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2); g_date_free (gdate_start); g_date_free (gdate_end); @@ -1989,11 +2166,37 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g { switch ( subtype ) { - case VIK_TRW_LAYER_SUBLAYER_TRACKS: return NULL; - case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return NULL; + case VIK_TRW_LAYER_SUBLAYER_TRACKS: + { + // Very simple tooltip - may expand detail in the future... + static gchar tmp_buf[32]; + g_snprintf (tmp_buf, sizeof(tmp_buf), + _("Tracks: %d"), + g_hash_table_size (l->tracks)); + return tmp_buf; + } + break; + case VIK_TRW_LAYER_SUBLAYER_ROUTES: + { + // Very simple tooltip - may expand detail in the future... + static gchar tmp_buf[32]; + g_snprintf (tmp_buf, sizeof(tmp_buf), + _("Routes: %d"), + g_hash_table_size (l->routes)); + return tmp_buf; + } + break; + + case VIK_TRW_LAYER_SUBLAYER_ROUTE: + // Same tooltip for a route case VIK_TRW_LAYER_SUBLAYER_TRACK: { - VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer ); + VikTrack *tr; + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + tr = g_hash_table_lookup ( l->tracks, sublayer ); + else + tr = g_hash_table_lookup ( l->routes, sublayer ); + if ( tr ) { // Could be a better way of handling strings - but this works... gchar time_buf1[20]; @@ -2029,6 +2232,16 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g } } break; + case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: + { + // Very simple tooltip - may expand detail in the future... + static gchar tmp_buf[32]; + g_snprintf (tmp_buf, sizeof(tmp_buf), + _("Waypoints: %d"), + g_hash_table_size (l->waypoints)); + return tmp_buf; + } + break; case VIK_TRW_LAYER_SUBLAYER_WAYPOINT: { VikWaypoint *w = g_hash_table_lookup ( l->waypoints, sublayer ); @@ -2168,6 +2381,21 @@ static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer subl return TRUE; } break; + case VIK_TRW_LAYER_SUBLAYER_ROUTES: + { + vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->routes, l ); + /* Mark for redraw */ + return TRUE; + } + break; + case VIK_TRW_LAYER_SUBLAYER_ROUTE: + { + VikTrack *track = g_hash_table_lookup ( l->routes, sublayer ); + vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l ); + /* Mark for redraw */ + return TRUE; + } + break; case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: { vik_window_set_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->waypoints, l ); @@ -2208,6 +2436,11 @@ GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l ) return l->tracks; } +GHashTable *vik_trw_layer_get_routes ( VikTrwLayer *l ) +{ + return l->routes; +} + GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l ) { return l->waypoints; @@ -2255,7 +2488,16 @@ VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name ) return g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find, (gpointer) name ); } -static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] ) +/* + * Get route by name - not guaranteed to be unique + * Finds the first one + */ +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 ); @@ -2269,7 +2511,7 @@ static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoi maxmin[1].lon = VIK_LATLON(&fixme)->lon; } -static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *trk, struct LatLon maxmin[2] ) +static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] ) { GList *tr = trk->trackpoints; static VikCoord fixme; @@ -2291,35 +2533,10 @@ static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *tr static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]) { - struct LatLon wpt_maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; - struct LatLon trk_maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; - - g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, wpt_maxmin ); - g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, trk_maxmin ); - if ((wpt_maxmin[0].lat != 0.0 && wpt_maxmin[0].lat > trk_maxmin[0].lat) || trk_maxmin[0].lat == 0.0) { - maxmin[0].lat = wpt_maxmin[0].lat; - } - else { - maxmin[0].lat = trk_maxmin[0].lat; - } - if ((wpt_maxmin[0].lon != 0.0 && wpt_maxmin[0].lon > trk_maxmin[0].lon) || trk_maxmin[0].lon == 0.0) { - maxmin[0].lon = wpt_maxmin[0].lon; - } - else { - maxmin[0].lon = trk_maxmin[0].lon; - } - if ((wpt_maxmin[1].lat != 0.0 && wpt_maxmin[1].lat < trk_maxmin[1].lat) || trk_maxmin[1].lat == 0.0) { - maxmin[1].lat = wpt_maxmin[1].lat; - } - else { - maxmin[1].lat = trk_maxmin[1].lat; - } - if ((wpt_maxmin[1].lon != 0.0 && wpt_maxmin[1].lon < trk_maxmin[1].lon) || trk_maxmin[1].lon == 0.0) { - maxmin[1].lon = wpt_maxmin[1].lon; - } - else { - maxmin[1].lon = trk_maxmin[1].lon; - } + // Continually reuse maxmin to find the latest maximum and minimum values + g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin ); + 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 ); } gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest ) @@ -2537,7 +2754,13 @@ static void trw_layer_export_gpx_track ( gpointer pass_along[6] ) gpointer layer_and_vlp[2]; layer_and_vlp[0] = pass_along[0]; layer_and_vlp[1] = pass_along[1]; - VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); if ( !trk || !trk->name ) return; @@ -2654,35 +2877,16 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ) { - VikCoord one, two; - struct LatLon one_ll, two_ll; 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]); VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); VikViewport *vvp = vik_window_viewport(vw); - vik_viewport_screen_to_coord ( vvp, 0, 0, &one); - vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &two); - vik_coord_to_latlon(&one, &one_ll); - vik_coord_to_latlon(&two, &two_ll); - if (one_ll.lat > two_ll.lat) { - maxmin[0].lat = one_ll.lat; - maxmin[1].lat = two_ll.lat; - } - else { - maxmin[0].lat = two_ll.lat; - maxmin[1].lat = one_ll.lat; - } - if (one_ll.lon > two_ll.lon) { - maxmin[0].lon = one_ll.lon; - maxmin[1].lon = two_ll.lon; - } - else { - maxmin[0].lon = two_ll.lon; - maxmin[1].lon = one_ll.lon; - } - a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin); + + // Note the order is max part first then min part - thus reverse order of use in min_max function: + vik_viewport_get_min_max_lat_lon ( vvp, &maxmin[1].lat, &maxmin[0].lat, &maxmin[1].lon, &maxmin[0].lon ); + a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin); + vik_layers_panel_emit_update ( vlp ); } static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ) @@ -2692,7 +2896,8 @@ static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ) struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; trw_layer_find_maxmin (vtl, maxmin); - a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin); + a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin); + vik_layers_panel_emit_update ( vlp ); } #ifdef VIK_CONFIG_GEOTAG @@ -2757,7 +2962,7 @@ static void trw_layer_acquire_gps_cb ( gpointer lav[2] ) a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface ); } -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS +#ifdef VIK_CONFIG_GOOGLE /* * Acquire into this TRW Layer from Google Directions */ @@ -2785,6 +2990,19 @@ static void trw_layer_acquire_osm_cb ( gpointer lav[2] ) a_acquire ( vw, vlp, vvp, &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] ) +{ + 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 ); +} #endif #ifdef VIK_CONFIG_GEOCACHES @@ -2843,12 +3061,32 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); VikLayersPanel *vlp = VIK_LAYERS_PANEL(pass_along[1]); - // May not actually get a track here as pass_along[3] can be null - VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + // May not actually get a track here as pass_along[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; - gboolean on_track = track ? TRUE : FALSE; + if ( pass_along[2] ) { + 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] ); + 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] ); + xfer_type = TRK; + } + else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) { + xfer_type = WPT; + } + else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) { + xfer_type = RTE; + } + } + else if ( !pass_along[4] ) + xfer_all = TRUE; // i.e. whole layer - if (on_track && !track->visible) { + if (track && !track->visible) { a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") ); return; } @@ -2871,7 +3109,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) if ( response_w ) gtk_widget_grab_focus ( response_w ); - gpointer dgs = datasource_gps_setup ( dialog, on_track ); + gpointer dgs = datasource_gps_setup ( dialog, xfer_type, xfer_all ); if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) { datasource_gps_clean_up ( dgs ); @@ -2884,6 +3122,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) gchar* port = datasource_gps_get_descriptor ( dgs ); // NB don't free the above strings as they're references to values held elsewhere gboolean do_tracks = datasource_gps_get_do_tracks ( dgs ); + gboolean do_routes = datasource_gps_get_do_routes ( dgs ); gboolean do_waypoints = datasource_gps_get_do_waypoints ( dgs ); gboolean turn_off = datasource_gps_get_off ( dgs ); @@ -2904,6 +3143,7 @@ static void trw_layer_gps_upload_any ( gpointer pass_along[6] ) vik_layers_panel_get_viewport (vlp), vlp, do_tracks, + do_routes, do_waypoints, turn_off ); } @@ -2931,6 +3171,74 @@ static void trw_layer_new_wp ( gpointer lav[2] ) vik_layers_panel_emit_update ( vlp ); } +static void new_track_create_common ( VikTrwLayer *vtl, gchar *name ) +{ + vtl->current_track = vik_track_new(); + vtl->current_track->visible = TRUE; + if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR ) + // Create track with the preferred colour from the layer properties + vtl->current_track->color = vtl->track_color; + else + gdk_color_parse ( "#000000", &(vtl->current_track->color) ); + vtl->current_track->has_color = TRUE; + vik_trw_layer_add_track ( vtl, name, vtl->current_track ); +} + +static void trw_layer_new_track ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + + 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 ); + + vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK ); + } +} + +static void new_route_create_common ( VikTrwLayer *vtl, gchar *name ) +{ + vtl->current_track = vik_track_new(); + vtl->current_track->visible = TRUE; + vtl->current_track->is_route = TRUE; + // By default make all routes red + vtl->current_track->has_color = TRUE; + gdk_color_parse ( "red", &vtl->current_track->color ); + vik_trw_layer_add_route ( vtl, name, vtl->current_track ); +} + +static void trw_layer_new_route ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + + 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 ); + 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] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + + if ( g_hash_table_size (vtl->routes) > 0 ) { + struct LatLon maxmin[2] = { {0,0}, {0,0} }; + g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin ); + trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin ); + vik_layers_panel_emit_update ( vlp ); + } +} + + +static void trw_layer_finish_track ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + vtl->current_track = NULL; + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + static void trw_layer_auto_tracks_view ( gpointer lav[2] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); @@ -2944,7 +3252,7 @@ static void trw_layer_auto_tracks_view ( gpointer lav[2] ) } } -static void trw_layer_single_waypoint_jump ( const gchar *name, const VikWaypoint *wp, gpointer vvp ) +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) ); @@ -2983,6 +3291,21 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + if ( vtl->current_track ) { + if ( vtl->current_track->is_route ) + item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") ); + else + item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + + // Add separator + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + /* Now with icons */ item = gtk_image_menu_item_new_with_mnemonic ( _("_View Layer") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) ); @@ -2990,14 +3313,26 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("View All Trac_ks") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along ); + GtkWidget *view_submenu = gtk_menu_new(); + item = gtk_image_menu_item_new_with_mnemonic ( _("V_iew") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, 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), view_submenu ); - item = gtk_menu_item_new_with_mnemonic ( _("V_iew All Waypoints") ); + item = gtk_menu_item_new_with_mnemonic ( _("View All _Tracks") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("View All _Routes") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("View All _Waypoints") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item); gtk_widget_show ( item ); item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") ); @@ -3052,32 +3387,34 @@ 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 ); - item = gtk_image_menu_item_new_with_mnemonic ( _("_New Waypoint...") ); + GtkWidget *new_submenu = gtk_menu_new(); + item = gtk_image_menu_item_new_with_mnemonic ( _("_New") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show ( item ); - -#ifdef VIK_CONFIG_GEONAMES - GtkWidget *wikipedia_submenu = gtk_menu_new(); - item = gtk_image_menu_item_new_with_mnemonic ( _("_Add Wikipedia Waypoints") ); - 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), wikipedia_submenu); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_submenu); - item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item); + item = gtk_image_menu_item_new_with_mnemonic ( _("New _Waypoint...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item); gtk_widget_show ( item ); - item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Current View") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item); + item = gtk_image_menu_item_new_with_mnemonic ( _("New _Track") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item); gtk_widget_show ( item ); -#endif + // Make it available only when a new track *not* already in progress + gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("New _Route") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item); + gtk_widget_show ( item ); + // Make it available only when a new track *not* already in progress + gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) ); #ifdef VIK_CONFIG_GEOTAG item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") ); @@ -3087,7 +3424,7 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer #endif GtkWidget *acquire_submenu = gtk_menu_new (); - item = gtk_image_menu_item_new_with_mnemonic ( _("Ac_quire") ); + item = gtk_image_menu_item_new_with_mnemonic ( _("_Acquire") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU) ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); @@ -3098,8 +3435,8 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); gtk_widget_show ( item ); -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS - item = gtk_menu_item_new_with_mnemonic ( _("From G_oogle Directions...") ); +#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 ); gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); gtk_widget_show ( item ); @@ -3110,6 +3447,32 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_cb), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("From _My OSM Traces...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_my_traces_cb), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item); + gtk_widget_show ( item ); +#endif + +#ifdef VIK_CONFIG_GEONAMES + GtkWidget *wikipedia_submenu = gtk_menu_new(); + item = gtk_image_menu_item_new_with_mnemonic ( _("From _Wikipedia Waypoints") ); + 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 (acquire_submenu), item); + gtk_widget_show(item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), wikipedia_submenu); + + item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Current View") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item); + gtk_widget_show ( item ); #endif #ifdef VIK_CONFIG_GEOCACHES @@ -3138,6 +3501,12 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_widget_show ( item ); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu ); + item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item); + gtk_widget_show ( item ); + #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) ); @@ -3146,12 +3515,6 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_widget_show ( item ); #endif - item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item); - gtk_widget_show ( item ); - GtkWidget *delete_submenu = gtk_menu_new (); item = gtk_image_menu_item_new_with_mnemonic ( _("De_lete") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) ); @@ -3170,6 +3533,18 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") ); + 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_delete_routes_from_selection), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) ); @@ -3209,13 +3584,18 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp if ( VIK_LAYER(vtl)->realized ) { + // Do we need to create the sublayer: + if ( g_hash_table_size (vtl->waypoints) == 0 ) { + trw_layer_add_sublayer_waypoints ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) ); + } + GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter)); // Visibility column always needed for waypoints #ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE ); + vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE ); #else - vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE ); + vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE ); #endif // Actual setting of visibility dependent on the waypoint vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible ); @@ -3239,6 +3619,11 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) if ( VIK_LAYER(vtl)->realized ) { + // Do we need to create the sublayer: + if ( g_hash_table_size (vtl->tracks) == 0 ) { + trw_layer_add_sublayer_tracks ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) ); + } + GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter)); // Visibility column always needed for tracks #ifdef VIK_CONFIG_ALPHABETIZED_TRW @@ -3253,7 +3638,42 @@ 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) ); +} + +// Fake Route UUIDs vi simple increasing integer +static guint rt_uuid = 0; + +void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) +{ + rt_uuid++; + + vik_track_set_name (t, name); + + if ( VIK_LAYER(vtl)->realized ) + { + // Do we need to create the sublayer: + if ( g_hash_table_size (vtl->routes) == 0 ) { + trw_layer_add_sublayer_routes ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) ); + } + + GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter)); + // Visibility column always needed for tracks +#ifdef VIK_CONFIG_ALPHABETIZED_TRW + vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE ); +#else + vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE ); +#endif + // Actual setting of visibility dependent on the track + vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible ); + + g_hash_table_insert ( vtl->routes_iters, GUINT_TO_POINTER(rt_uuid), iter ); + } + + g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t ); + + trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(rt_uuid) ); } /* to be called whenever a track has been deleted or may have been changed. */ @@ -3262,18 +3682,35 @@ void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk ) if (vtl->current_tp_track == trk ) trw_layer_cancel_current_tp ( vtl, FALSE ); } - + gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name) { - gint i = 2; - gchar *newname = g_strdup(name); - while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ? - (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) { - gchar *new_newname = g_strdup_printf("%s#%d", name, i); - g_free(newname); - newname = new_newname; - i++; - } + gint i = 2; + gchar *newname = g_strdup(name); + + gpointer id = NULL; + do { + id = NULL; + switch ( sublayer_type ) { + case VIK_TRW_LAYER_SUBLAYER_TRACK: + id = (gpointer) vik_trw_layer_get_track ( vtl, newname ); + break; + case VIK_TRW_LAYER_SUBLAYER_WAYPOINT: + id = (gpointer) vik_trw_layer_get_waypoint ( vtl, newname ); + break; + default: + id = (gpointer) vik_trw_layer_get_route ( vtl, newname ); + break; + } + // If found a name already in use try adding 1 to it and we try again + if ( id ) { + gchar *new_newname = g_strdup_printf("%s#%d", name, i); + g_free(newname); + newname = new_newname; + i++; + } + } while ( id != NULL); + return newname; } @@ -3294,7 +3731,10 @@ void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t } else { // No more uniqueness of name forced when loading from a file - vik_trw_layer_add_track ( vtl, name, tr ); + if ( tr->is_route ) + vik_trw_layer_add_route ( vtl, name, tr ); + else + vik_trw_layer_add_track ( vtl, name, tr ); if ( vtl->route_finder_check_added_track ) { vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */ @@ -3318,11 +3758,21 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name); - VikTrack *trk2 = vik_track_copy ( trk ); + VikTrack *trk2 = vik_track_copy ( trk, TRUE ); vik_trw_layer_add_track ( vtl_dest, newname, trk2 ); vik_trw_layer_delete_track ( vtl_src, trk ); } + if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) { + VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id ); + + gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name); + + VikTrack *trk2 = vik_track_copy ( trk, TRUE ); + vik_trw_layer_add_route ( vtl_dest, newname, trk2 ); + vik_trw_layer_delete_route ( vtl_src, trk ); + } + if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) { VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id ); @@ -3349,13 +3799,19 @@ static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) { g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items); } - + if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) { + g_hash_table_foreach ( vtl_src->routes, (GHFunc)trw_layer_enum_item, &items); + } + iter = items; while (iter) { if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) { - trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK); + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK); + } + else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) { + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_ROUTE); } else { - trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT); + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT); } iter = iter->next; } @@ -3420,6 +3876,60 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk ) vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it ); g_hash_table_remove ( vtl->tracks_iters, udata.uuid ); g_hash_table_remove ( vtl->tracks, udata.uuid ); + + // If last sublayer, then remove sublayer container + if ( g_hash_table_size (vtl->tracks) == 0 ) { + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) ); + } + } + } + } + return was_visible; +} + +gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk ) +{ + gboolean was_visible = FALSE; + + if ( trk && trk->name ) { + + if ( trk == vtl->current_track ) { + vtl->current_track = NULL; + vtl->current_tp_track = NULL; + vtl->current_tp_id = NULL; + vtl->moving_tp = 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; + + trku_udata udata; + udata.trk = trk; + udata.uuid = NULL; + + // Hmmm, want key of it + gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata ); + + if ( trkf && udata.uuid ) { + /* could be current_tp, so we have to check */ + trw_layer_cancel_tps_of_track ( vtl, trk ); + + GtkTreeIter *it = g_hash_table_lookup ( vtl->routes_iters, udata.uuid ); + + if ( it ) { + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it ); + g_hash_table_remove ( vtl->routes_iters, udata.uuid ); + g_hash_table_remove ( vtl->routes, udata.uuid ); + + // If last sublayer, then remove sublayer container + if ( g_hash_table_size (vtl->routes) == 0 ) { + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) ); + } } } } @@ -3456,6 +3966,11 @@ static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp ) highest_wp_number_remove_wp(vtl, wp->name); g_hash_table_remove ( vtl->waypoints, udata.uuid ); // last because this frees the name + + // If last sublayer, then remove sublayer container + if ( g_hash_table_size (vtl->waypoints) == 0 ) { + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) ); + } } } @@ -3519,9 +4034,9 @@ static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const Vik /* * Delete a track by the given name * NOTE: ATM this will delete the first encountered Track with the specified name - * as there be multiple track with the same name + * as there may be multiple tracks with the same name within the specified hash table */ -static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name ) +static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name, GHashTable *ht_tracks ) { tpu_udata udata; // Fake a track with the given name @@ -3531,21 +4046,45 @@ static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar * udata.uuid = NULL; // Hmmm, want key of it - gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata ); + gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata ); vik_track_free (udata.trk); - if ( trkf && udata.uuid ) - return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( vtl->tracks, udata.uuid )); + if ( trkf && udata.uuid ) { + // This could be a little better written... + if ( vtl->tracks == ht_tracks ) + return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid )); + if ( vtl->routes == ht_tracks ) + return vik_trw_layer_delete_route (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid )); + return FALSE; + } else return FALSE; } -static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt) +static void remove_item_from_treeview ( const gpointer id, GtkTreeIter *it, VikTreeview * vt ) { vik_treeview_item_delete (vt, it ); } +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); + + g_hash_table_foreach(vtl->routes_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); + g_hash_table_remove_all(vtl->routes_iters); + g_hash_table_remove_all(vtl->routes); + + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl ) { @@ -3559,7 +4098,9 @@ void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl ) g_hash_table_remove_all(vtl->tracks_iters); g_hash_table_remove_all(vtl->tracks); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); } void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) @@ -3574,7 +4115,9 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) g_hash_table_remove_all(vtl->waypoints_iters); g_hash_table_remove_all(vtl->waypoints); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); } static void trw_layer_delete_all_tracks ( gpointer lav[2] ) @@ -3587,6 +4130,16 @@ 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] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + // 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?"), + vik_layer_get_name ( VIK_LAYER(vtl) ) ) ) + vik_trw_layer_delete_all_routes (vtl); +} + static void trw_layer_delete_all_waypoints ( gpointer lav[2] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); @@ -3615,7 +4168,7 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) was_visible = trw_layer_delete_waypoint ( vtl, wp ); } } - else + else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) { VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); if ( trk && trk->name ) { @@ -3628,8 +4181,21 @@ static void trw_layer_delete_item ( gpointer pass_along[6] ) was_visible = vik_trw_layer_delete_track ( vtl, trk ); } } + else + { + VikTrack *trk = g_hash_table_lookup ( vtl->routes, pass_along[3] ); + if ( trk && trk->name ) { + if ( GPOINTER_TO_INT ( pass_along[4]) ) + // Get confirmation from the user + if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Are you sure you want to delete the route \"%s\""), + trk->name ) ) + return; + was_visible = vik_trw_layer_delete_route ( vtl, trk ); + } + } if ( was_visible ) - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } @@ -3645,23 +4211,70 @@ static void trw_layer_properties_item ( gpointer pass_along[7] ) gboolean updated = FALSE; a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, wp, vtl->coord_mode, FALSE, &updated ); + if ( updated && wp->symbol && pass_along[6] ) + vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) ); + if ( updated && VIK_LAYER(vtl)->visible ) - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } } else { - VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *tr; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) + tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + else + tr = g_hash_table_lookup ( vtl->routes, pass_along[3] ); + if ( tr && tr->name ) { vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - vtl, tr, + vtl, + tr, pass_along[1], /* vlp */ - pass_along[5] ); /* vvp */ + pass_along[5], /* vvp */ + pass_along[6]); /* iter */ } } } +/* + * Update the treeview of the track id - primarily to update the icon + */ +void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk, gpointer *trk_id ) +{ + trku_udata udata; + udata.trk = trk; + udata.uuid = NULL; + + gpointer *trkf = NULL; + if ( trk->is_route ) + trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata ); + else + trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata ); + + if ( trkf && udata.uuid ) { + + GtkTreeIter *iter = NULL; + if ( trk->is_route ) + iter = g_hash_table_lookup ( vtl->routes_iters, udata.uuid ); + else + iter = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid ); + + if ( iter ) { + // TODO: Make this a function + GdkPixbuf *pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, 18, 18); + guint32 pixel = ((trk->color.red & 0xff00) << 16) | + ((trk->color.green & 0xff00) << 8) | + (trk->color.blue & 0xff00); + gdk_pixbuf_fill ( pixbuf, pixel ); + vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, iter, pixbuf ); + g_object_unref (pixbuf); + } + + } +} + /* Parameter 1 -> VikLayersPanel Parameter 2 -> VikLayer @@ -3677,21 +4290,33 @@ static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoor /* since vlp not set, vl & vvp should be valid instead! */ if ( vl && vvp ) { vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord ); - vik_layer_emit_update ( VIK_LAYER(vl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vl) ); } } } static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] ) { - GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints; - if ( trps && trps->data ) - goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord)); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( track && track->trackpoints ) + goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) track->trackpoints->data)->coord) ); } static void trw_layer_goto_track_center ( gpointer pass_along[6] ) { - VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + if ( track && track->trackpoints ) { struct LatLon average, maxmin[2] = { {0,0}, {0,0} }; @@ -3699,34 +4324,95 @@ static void trw_layer_goto_track_center ( gpointer pass_along[6] ) trw_layer_find_maxmin_tracks ( NULL, track, maxmin ); average.lat = (maxmin[0].lat+maxmin[1].lat)/2; average.lon = (maxmin[0].lon+maxmin[1].lon)/2; - vik_coord_load_from_latlon ( &coord, VIK_TRW_LAYER(pass_along[0])->coord_mode, &average ); + vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average ); goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord); } } +static void trw_layer_convert_track_route ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !trk ) + return; + + // Converting a track to a route can be a bit more complicated, + // so give a chance to change our minds: + if ( !trk->is_route && + ( ( vik_track_get_segment_count ( trk ) > 1 ) || + ( vik_track_get_average_speed ( trk ) > 0.0 ) ) ) { + + if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) ) + return; +} + + // Copy it + VikTrack *trk_copy = vik_track_copy ( trk, TRUE ); + + // Convert + trk_copy->is_route = !trk_copy->is_route; + + // ATM can't set name to self - so must create temporary copy + gchar *name = g_strdup ( trk_copy->name ); + + // Delete old one and then add new one + if ( trk->is_route ) { + vik_trw_layer_delete_route ( vtl, trk ); + vik_trw_layer_add_track ( vtl, name, trk_copy ); + } + else { + // Extra route conversion bits... + vik_track_merge_segments ( trk_copy ); + vik_track_to_routepoints ( trk_copy ); + + vik_trw_layer_delete_track ( vtl, trk ); + vik_trw_layer_add_route ( vtl, name, trk_copy ); + } + g_free ( name ); + + // Update in case color of track / route changes when moving between sublayers + vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); +} + + static void trw_layer_extend_track_end ( gpointer pass_along[6] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; vtl->current_track = track; - vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK); + 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) ); } -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS +#ifdef VIK_CONFIG_GOOGLE /** * extend a track using route finder */ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] ); + 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, NUM_TOOLS ); + 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->route_finder_started = TRUE; @@ -3741,14 +4427,30 @@ static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) { /* TODO: check & warn if no DEM data, or no applicable DEM data. */ /* Also warn if overwrite old elevation data */ - VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); - vik_track_apply_dem_data ( track ); + if ( track ) + vik_track_apply_dem_data ( track ); } static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) { - GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints; + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + GList *trps = track->trackpoints; if ( !trps ) return; trps = g_list_last(trps); @@ -3757,7 +4459,17 @@ static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] ) { - VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) ); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + 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)); @@ -3765,7 +4477,17 @@ static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] ) static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] ) { - VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) ); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + 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)); @@ -3773,7 +4495,17 @@ static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] ) static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] ) { - VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) ); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; + + 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)); @@ -3784,7 +4516,13 @@ static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] ) */ static void trw_layer_auto_track_view ( gpointer pass_along[6] ) { - VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + if ( trk && trk->trackpoints ) { struct LatLon maxmin[2] = { {0,0}, {0,0} }; @@ -3793,7 +4531,7 @@ static void trw_layer_auto_track_view ( gpointer pass_along[6] ) if ( pass_along[1] ) vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) ); else - vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE ); + vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); } } @@ -3944,7 +4682,16 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; GList *other_tracks = NULL; - VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + GHashTable *ght_tracks; + if ( GPOINTER_TO_INT (pass_along[2]) == 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] ); + + if ( !track ) + return; if ( !track->trackpoints ) return; @@ -3956,7 +4703,7 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) // i.e. either those times, or those without udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp); - g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata); + g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata); other_tracks = g_list_reverse(other_tracks); if ( !other_tracks ) { @@ -3973,15 +4720,17 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) GList *other_tracks_names = NULL; GList *iter = g_list_first ( other_tracks ); while ( iter ) { - other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (vtl->tracks, iter->data))->name ); + other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (ght_tracks, iter->data))->name ); iter = g_list_next ( iter ); } other_tracks_names = g_list_sort_with_data (other_tracks_names, sort_alphabetically, NULL); GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), - other_tracks_names, TRUE, - _("Merge with..."), _("Select track to merge with")); + other_tracks_names, + TRUE, + _("Merge with..."), + track->is_route ? _("Select route to merge with") : _("Select track to merge with")); g_list_free(other_tracks); g_list_free(other_tracks_names); @@ -3989,11 +4738,19 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) { GList *l; for (l = merge_list; l != NULL; l = g_list_next(l)) { - VikTrack *merge_track = vik_trw_layer_get_track ( vtl, l->data ); + VikTrack *merge_track; + if ( track->is_route ) + merge_track = vik_trw_layer_get_route ( vtl, l->data ); + else + merge_track = vik_trw_layer_get_track ( vtl, l->data ); + if (merge_track) { track->trackpoints = g_list_concat(track->trackpoints, merge_track->trackpoints); merge_track->trackpoints = NULL; - vik_trw_layer_delete_track (vtl, merge_track); + if ( track->is_route ) + vik_trw_layer_delete_route (vtl, merge_track); + else + vik_trw_layer_delete_track (vtl, merge_track); track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare); } } @@ -4001,7 +4758,7 @@ static void trw_layer_merge_with_other ( gpointer pass_along[6] ) for (l = merge_list; l != NULL; l = g_list_next(l)) g_free(l->data); g_list_free(merge_list); - vik_layer_emit_update( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update( VIK_LAYER(vtl) ); } } @@ -4021,7 +4778,7 @@ static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer } /** - * Join - this allows combining 'routes' and 'tracks' + * Join - this allows combining 'tracks' and 'track routes' * 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 */ @@ -4029,7 +4786,17 @@ static void trw_layer_append_track ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *trk; + GHashTable *ght_tracks; + if ( GPOINTER_TO_INT (pass_along[2]) == 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] ); + + if ( !trk ) + return; GList *other_tracks_names = NULL; @@ -4040,16 +4807,17 @@ static void trw_layer_append_track ( gpointer pass_along[6] ) udata.result = &other_tracks_names; udata.exclude = trk->trackpoints; - g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata); + g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata); // Note the limit to selecting one track only // this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track // (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically) GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), - other_tracks_names, - FALSE, - _("Append Track"), - _("Select the track to append after the current track")); + other_tracks_names, + FALSE, + trk->is_route ? _("Append Route"): _("Append Track"), + trk->is_route ? _("Select the route to append after the current route") : + _("Select the track to append after the current track") ); g_list_free(other_tracks_names); @@ -4059,17 +4827,121 @@ static void trw_layer_append_track ( gpointer pass_along[6] ) for (l = append_list; l != NULL; l = g_list_next(l)) { // TODO: at present this uses the first track found by name, // which with potential multiple same named tracks may not be the one selected... - VikTrack *append_track = vik_trw_layer_get_track ( vtl, l->data ); + VikTrack *append_track; + if ( trk->is_route ) + append_track = vik_trw_layer_get_route ( vtl, l->data ); + else + append_track = vik_trw_layer_get_track ( vtl, l->data ); + if ( append_track ) { trk->trackpoints = g_list_concat(trk->trackpoints, append_track->trackpoints); append_track->trackpoints = NULL; - vik_trw_layer_delete_track (vtl, append_track); + if ( trk->is_route ) + vik_trw_layer_delete_route (vtl, append_track); + else + vik_trw_layer_delete_track (vtl, append_track); } } for (l = append_list; l != NULL; l = g_list_next(l)) g_free(l->data); g_list_free(append_list); - vik_layer_emit_update( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update( VIK_LAYER(vtl) ); + } +} + +/** + * Very similar to trw_layer_append_track for joining + * but this allows selection from the 'other' list + * 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] ) +{ + + VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; + VikTrack *trk; + GHashTable *ght_mykind, *ght_others; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + ght_mykind = vtl->routes; + ght_others = vtl->tracks; + } + else { + ght_mykind = vtl->tracks; + ght_others = vtl->routes; + } + + trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, pass_along[3] ); + + if ( !trk ) + return; + + GList *other_tracks_names = NULL; + + // Sort alphabetically for user presentation + // Convert into list of names for usage with dialog function + // TODO: Need to consider how to work best when we can have multiple tracks the same name... + twt_udata udata; + udata.result = &other_tracks_names; + udata.exclude = trk->trackpoints; + + g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata); + + // Note the limit to selecting one track only + // this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track + // (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically) + GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), + other_tracks_names, + FALSE, + trk->is_route ? _("Append Track"): _("Append Route"), + trk->is_route ? _("Select the track to append after the current route") : + _("Select the route to append after the current track") ); + + g_list_free(other_tracks_names); + + // It's a list, but shouldn't contain more than one other track! + if ( append_list ) { + GList *l; + for (l = append_list; l != NULL; l = g_list_next(l)) { + // TODO: at present this uses the first track found by name, + // which with potential multiple same named tracks may not be the one selected... + + // Get FROM THE OTHER TYPE list + VikTrack *append_track; + if ( trk->is_route ) + append_track = vik_trw_layer_get_track ( vtl, l->data ); + else + append_track = vik_trw_layer_get_route ( vtl, l->data ); + + if ( append_track ) { + + if ( !append_track->is_route && + ( ( vik_track_get_segment_count ( append_track ) > 1 ) || + ( vik_track_get_average_speed ( append_track ) > 0.0 ) ) ) { + + if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) ) { + vik_track_merge_segments ( append_track ); + vik_track_to_routepoints ( append_track ); + } + else { + break; + } + } + + trk->trackpoints = g_list_concat(trk->trackpoints, append_track->trackpoints); + append_track->trackpoints = NULL; + + // Delete copied which is FROM THE OTHER TYPE list + if ( trk->is_route ) + vik_trw_layer_delete_track (vtl, append_track); + else + vik_trw_layer_delete_route (vtl, append_track); + } + } + for (l = append_list; l != NULL; l = g_list_next(l)) + g_free(l->data); + g_list_free(append_list); + vik_layer_emit_update( VIK_LAYER(vtl) ); } } @@ -4183,21 +5055,21 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) } g_list_free(nearby_tracks); - vik_layer_emit_update( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update( VIK_LAYER(vtl) ); } /** * Split a track at the currently selected trackpoint */ -static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl ) +static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subtype ) { if ( !vtl->current_tpl ) return; if ( vtl->current_tpl->next && vtl->current_tpl->prev ) { - gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track->name); + gchar *name = trw_layer_new_unique_sublayer_name(vtl, subtype, vtl->current_tp_track->name); if ( name ) { - VikTrack *tr = vik_track_new (); + VikTrack *tr = vik_track_copy ( vtl->current_tp_track, FALSE ); GList *newglist = g_list_alloc (); newglist->prev = NULL; newglist->next = vtl->current_tpl->next; @@ -4210,22 +5082,28 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl ) vtl->current_tpl = newglist; /* change tp to first of new track. */ vtl->current_tp_track = tr; - tr->visible = TRUE; - - vik_trw_layer_add_track ( vtl, name, tr ); + if ( tr->is_route ) + vik_trw_layer_add_route ( vtl, name, tr ); + else + vik_trw_layer_add_track ( vtl, name, tr ); trku_udata udata; udata.trk = tr; udata.uuid = NULL; // Also need id of newly created track - gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata ); + gpointer *trkf; + if ( tr->is_route ) + trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata ); + else + trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata ); + if ( trkf && udata.uuid ) vtl->current_tp_id = udata.uuid; else vtl->current_tp_id = NULL; - vik_layer_emit_update(VIK_LAYER(vtl), FALSE); + vik_layer_emit_update(VIK_LAYER(vtl)); } } } @@ -4286,8 +5164,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) gchar *new_tr_name; VikTrack *tr; - tr = vik_track_new(); - tr->visible = track->visible; + tr = vik_track_copy ( track, FALSE ); tr->trackpoints = (GList *)(iter->data); new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name); @@ -4299,7 +5176,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) } // Remove original track and then update the display vik_trw_layer_delete_track (vtl, track); - vik_layer_emit_update(VIK_LAYER(pass_along[0]), FALSE); + vik_layer_emit_update(VIK_LAYER(pass_along[0])); } g_list_free(newlists); } @@ -4310,7 +5187,14 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *track = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !track ) + return; // Check valid track GList *trps = track->trackpoints; @@ -4362,18 +5246,25 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) gchar *new_tr_name; VikTrack *tr; - tr = vik_track_new(); - tr->visible = track->visible; + tr = vik_track_copy ( track, FALSE ); tr->trackpoints = (GList *)(iter->data); - 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); - + if ( track->is_route ) { + new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, track->name); + vik_trw_layer_add_route(vtl, new_tr_name, tr); + } + else { + new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name); + vik_trw_layer_add_track(vtl, new_tr_name, tr); + } iter = g_list_next(iter); } // Remove original track and then update the display - vik_trw_layer_delete_track (vtl, track); - vik_layer_emit_update(VIK_LAYER(pass_along[0]), FALSE); + if ( track->is_route ) + vik_trw_layer_delete_route (vtl, track); + else + vik_trw_layer_delete_track (vtl, track); + vik_layer_emit_update(VIK_LAYER(pass_along[0])); } g_list_free(newlists); } @@ -4384,16 +5275,22 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - trw_layer_split_at_selected_trackpoint ( vtl ); + gint subtype = GPOINTER_TO_INT (pass_along[2]); + trw_layer_split_at_selected_trackpoint ( vtl, subtype ); } /** * 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] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !trk ) + return; + guint ntracks; VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks); @@ -4409,7 +5306,7 @@ static void trw_layer_split_segments ( gpointer pass_along[6] ) g_free ( tracks ); // Remove original track vik_trw_layer_delete_track ( vtl, trk ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } else { a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments")); @@ -4424,7 +5321,14 @@ static void trw_layer_split_segments ( gpointer pass_along[6] ) static void trw_layer_delete_points_same_position ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !trk ) + return; gulong removed = vik_track_remove_dup_points ( trk ); @@ -4437,7 +5341,7 @@ static void trw_layer_delete_points_same_position ( gpointer pass_along[6] ) g_snprintf(str, 64, tmp_str, removed); a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } /** @@ -4447,7 +5351,14 @@ static void trw_layer_delete_points_same_position ( gpointer pass_along[6] ) static void trw_layer_delete_points_same_time ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *trk = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( !trk ) + return; gulong removed = vik_track_remove_same_time_points ( trk ); @@ -4460,7 +5371,7 @@ static void trw_layer_delete_points_same_time ( gpointer pass_along[6] ) g_snprintf(str, 64, tmp_str, removed); a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } /** @@ -4469,7 +5380,14 @@ static void trw_layer_delete_points_same_time ( gpointer pass_along[6] ) static void trw_layer_reverse ( gpointer pass_along[6] ) { VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0]; - VikTrack *track = (VikTrack *)g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + VikTrack *track; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + + if ( ! track ) + return; // Check valid track GList *trps = track->trackpoints; @@ -4478,7 +5396,7 @@ static void trw_layer_reverse ( gpointer pass_along[6] ) vik_track_reverse ( track ); - vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE ); + vik_layer_emit_update ( VIK_LAYER(pass_along[0]) ); } /** @@ -4540,14 +5458,14 @@ static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpo } /** - * Find out if any tracks have the same name in this layer + * Find out if any tracks have the same name in this hash table */ -static gboolean trw_layer_has_same_track_names ( VikTrwLayer *vtl ) +static gboolean trw_layer_has_same_track_names ( GHashTable *ht_tracks ) { // Sort items by name, then compare if any next to each other are the same GList *track_names = NULL; - g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names ); + g_hash_table_foreach ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names ); // No tracks if ( ! track_names ) @@ -4567,10 +5485,11 @@ static gboolean trw_layer_has_same_track_names ( VikTrwLayer *vtl ) } /** - * Force unqiue track names for this layer + * Force unqiue track names for the track table specified * Note the panel is a required parameter to enable the update of the names displayed + * Specify if on tracks or else on routes */ -static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp ) +static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp, GHashTable *track_table, gboolean ontrack ) { // . Search list for an instance of repeated name // . get track of this name @@ -4584,7 +5503,7 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl udata.has_same_track_name = FALSE; udata.same_track_name = NULL; - g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names ); + g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names ); // No tracks if ( ! track_names ) @@ -4599,7 +5518,11 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl while ( udata.has_same_track_name ) { // Find a track with the same name - VikTrack *trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name ); + VikTrack *trk; + if ( ontrack ) + trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name ); + else + trk = vik_trw_layer_get_route ( vtl, (gpointer) udata.same_track_name ); if ( ! trk ) { // Broken :( @@ -4618,11 +5541,15 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl udataU.uuid = NULL; // Need want key of it for treeview update - gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU ); + gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU ); if ( trkf && udataU.uuid ) { - GtkTreeIter *it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid ); + GtkTreeIter *it; + if ( ontrack ) + it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid ); + else + it = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid ); if ( it ) { vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname ); @@ -4634,7 +5561,7 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl // Start trying to find same names again... track_names = NULL; - g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names ); + g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names ); udata.has_same_track_name = FALSE; GList *dummy_list2 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata ); @@ -4656,10 +5583,10 @@ static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ) GList *all = NULL; // Ensure list of track names offered is unique - if ( trw_layer_has_same_track_names ( vtl ) ) { + 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]) ); + vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE ); } else return; @@ -4687,10 +5614,57 @@ static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ) GList *l; for (l = delete_list; l != NULL; l = g_list_next(l)) { // This deletes first trk it finds of that name (but uniqueness is enforced above) - trw_layer_delete_track_by_name (vtl, l->data); + trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks); + } + g_list_free(delete_list); + vik_layer_emit_update( VIK_LAYER(vtl) ); + } +} + +/** + * + */ +static void trw_layer_delete_routes_from_selection ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + 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 ); + } + else + return; + } + + // Sort list alphabetically for better presentation + g_hash_table_foreach(vtl->routes, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all); + + if ( ! all ) { + a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No routes found")); + return; + } + + // Get list of items to delete from the user + GList *delete_list = a_dialog_select_from_list ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + all, + TRUE, + _("Delete Selection"), + _("Select routes to delete") ); + g_list_free(all); + + // Delete requested routes + // since specificly requested, IMHO no need for extra confirmation + if ( delete_list ) { + GList *l; + for (l = delete_list; l != NULL; l = g_list_next(l)) { + // This deletes first route it finds of that name (but uniqueness is enforced above) + trw_layer_delete_track_by_name (vtl, l->data, vtl->routes); } g_list_free(delete_list); - vik_layer_emit_update( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update( VIK_LAYER(vtl) ); } } @@ -4870,7 +5844,7 @@ static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] ) trw_layer_delete_waypoint_by_name (vtl, l->data); } g_list_free(delete_list); - vik_layer_emit_update( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update( VIK_LAYER(vtl) ); } } @@ -4884,11 +5858,26 @@ static void trw_layer_goto_waypoint ( gpointer pass_along[6] ) static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] ) { - gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] ); + VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + 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); g_free ( webpage ); } +static void trw_layer_waypoint_webpage ( gpointer pass_along[6] ) +{ + VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + if ( !wp ) + return; + if ( !strncmp(wp->comment, "http", 4) ) { + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->comment); + } else if ( !strncmp(wp->description, "http", 4) ) { + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->description); + } +} + static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter ) { if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) @@ -4904,7 +5893,7 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc if ( wpf ) { // An existing waypoint has been found with the requested name if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l), - _("A waypoint with the name \"%s\" already exists. Really create one with the same name?"), + _("A waypoint with the name \"%s\" already exists. Really rename to the same name?"), newname ) ) return NULL; } @@ -4934,7 +5923,44 @@ static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gc if ( trkf ) { // An existing track has been found with the requested name if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l), - _("A track with the name \"%s\" already exists. Really create one with the same name?"), + _("A track with the name \"%s\" already exists. Really rename to the same name?"), + newname ) ) + return NULL; + } + // Update track name and refresh GUI parts + vik_track_set_name (trk, newname); + + // Update any subwindows that could be displaying this track which has changed name + // Only one Track Edit Window + if ( l->current_tp_track == trk && l->tpwin ) { + vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname ); + } + // Property Dialog of the track + vik_trw_layer_propwin_update ( trk ); + +#ifdef VIK_CONFIG_ALPHABETIZED_TRW + vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname ); +#endif + + vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) ); + + return newname; + } + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + { + VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer ); + + // No actual change to the name supplied + if (strcmp(newname, trk->name) == 0) + return NULL; + + VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname ); + + if ( trkf ) { + // An existing track has been found with the requested name + if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l), + _("A route with the name \"%s\" already exists. Really rename to the same name?"), newname ) ) return NULL; } @@ -4972,15 +5998,16 @@ static void trw_layer_track_use_with_filter ( gpointer pass_along[6] ) a_acquire_set_filter_track ( trk ); } +#ifdef VIK_CONFIG_GOOGLE static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id ) { - VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_id ); + VikTrack *tr = g_hash_table_lookup ( vtl->routes, track_id ); return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) ); } -static void trw_layer_track_google_route_webpage ( gpointer pass_along[6] ) +static void trw_layer_google_route_webpage ( gpointer pass_along[6] ) { - VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] ); 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 ); @@ -4989,6 +6016,7 @@ static void trw_layer_track_google_route_webpage ( gpointer pass_along[6] ) g_free ( webpage ); } } +#endif /* vlp can be NULL if necessary - i.e. right-click from a tool */ /* viewpoint is now available instead */ @@ -5007,7 +6035,7 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men pass_along[6] = iter; pass_along[7] = NULL; // For misc purposes - maybe track or waypoint - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { rv = TRUE; @@ -5017,8 +6045,12 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) { - VikTrwLayer *vtl = l; - VikTrack *tr = g_hash_table_lookup ( vtl->tracks, sublayer ); + VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer ); + if (tr && tr->property_dialog) + gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE ); + } + if (subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE) { + VikTrack *tr = g_hash_table_lookup ( l->routes, sublayer ); if (tr && tr->property_dialog) gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE ); } @@ -5114,7 +6146,36 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men #endif } - } + if ( wp ) + { + if ( ( 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) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_webpage), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + } + } + + } + } + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) { + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PASTE, NULL ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_paste_item_cb), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + // TODO: only enable if suitable item is in clipboard - want to determine *which* sublayer type + if ( a_clipboard_type ( ) == VIK_CLIPBOARD_DATA_SUBLAYER ) + gtk_widget_set_sensitive ( item, TRUE ); + else + gtk_widget_set_sensitive ( item, FALSE ); + + // Add separator + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); } if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) @@ -5158,12 +6219,31 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men { rv = TRUE; + if ( l->current_track && !l->current_track->is_route ) { + item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + // Add separator + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Tracks") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); + item = gtk_image_menu_item_new_with_mnemonic ( _("_New Track") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + // Make it available only when a new track *not* already in progress + gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) ); + item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Tracks") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along ); @@ -5177,13 +6257,76 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) + { + rv = TRUE; + + if ( l->current_track && l->current_track->is_route ) { + item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") ); + // Reuse finish track method + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + // Add separator + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + + item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Routes") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_New Route") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + // Make it available only when a new track *not* already in progress + gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") ); + 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_delete_routes_from_selection), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + + GtkWidget *upload_submenu = gtk_menu_new (); + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { item = gtk_menu_item_new (); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") ); + if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && !l->current_track->is_route ) + item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") ); + if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && l->current_track->is_route ) + item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") ); + if ( l->current_track ) { + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + + // Add separator + item = gtk_menu_item_new (); + 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 ( _("_View Track") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("_View Route") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); @@ -5227,11 +6370,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item ); gtk_widget_show ( item ); - item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item ); - gtk_widget_show ( item ); + // Routes don't have speeds + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item ); + gtk_widget_show ( item ); + } GtkWidget *combine_submenu; combine_submenu = gtk_menu_new (); @@ -5241,23 +6387,37 @@ 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), combine_submenu ); - item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item ); - gtk_widget_show ( item ); + // Routes don't have times or segments... + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item ); + gtk_widget_show ( item ); + } item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") ); + else + item = gtk_menu_item_new_with_mnemonic ( _("_Append Route...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_menu_item_new_with_mnemonic ( _("Append _Route...") ); + else + item = gtk_menu_item_new_with_mnemonic ( _("Append _Track...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_other), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item ); gtk_widget_show ( item ); @@ -5269,22 +6429,25 @@ 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), split_submenu ); - item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item ); - gtk_widget_show ( item ); + // Routes don't have times or segments... + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item ); + gtk_widget_show ( item ); + + // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy + item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item ); + gtk_widget_show ( item ); + } item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item ); gtk_widget_show ( item ); - // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy - item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item ); - gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Split at _Trackpoint") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_at_trackpoint), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item ); @@ -5310,7 +6473,10 @@ 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 ); - item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Route") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_reverse), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); @@ -5318,7 +6484,10 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */ if ( vlp ) { - item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") ); + 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 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 ); @@ -5331,33 +6500,72 @@ 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_image_menu_item_new_with_mnemonic ( _("Export Trac_k as GPX...") ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Route as GPX...") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Route End") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS - item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along ); + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) + item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") ); + else + item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + +#ifdef VIK_CONFIG_GOOGLE + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } #endif - GtkWidget *upload_submenu = gtk_menu_new (); - item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) ); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + // ATM can't upload a single waypoint but can do waypoints to a GPS + if ( subtype != VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS...") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload_any), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item ); + gtk_widget_show ( item ); + } + } + +#ifdef VIK_CONFIG_GOOGLE + if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) ) + { + item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_google_route_webpage), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu ); + } +#endif + // Some things aren't usable with routes + 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 @@ -5368,21 +6576,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_widget_show ( item ); #endif - item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS...") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload_any), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item ); - gtk_widget_show ( item ); - - if ( is_valid_google_route ( l, sublayer ) ) - { - item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") ); - gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); - gtk_widget_show ( item ); - } - item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") ); 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_use_with_filter), pass_along ); @@ -5392,21 +6585,23 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men /* ATM This function is only available via the layers panel, due to needing a vlp */ if ( vlp ) { item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp, - vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), - g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) ); + vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), + g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) ); if ( item ) { - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show ( item ); + 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_track), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show ( item ); + item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_track), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); #endif + } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) { // Only show on viewport popmenu when a trackpoint is selected if ( ! vlp && l->current_tpl ) { // Add separator @@ -5420,7 +6615,6 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); } - } return rv; @@ -5471,10 +6665,16 @@ static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ) /* 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 */ - VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id ); - gint index = g_list_index ( tr->trackpoints, tp_current ); + VikTrack *trk = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id ); + if ( !trk ) + // Otherwise try routes + trk = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id ); + if ( !trk ) + return; + + gint index = g_list_index ( trk->trackpoints, tp_current ); if ( index > -1 ) { - tr->trackpoints = g_list_insert (tr->trackpoints, tp_new, index+1 ); + trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index+1 ); } } } @@ -5496,7 +6696,7 @@ static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy ) vtl->current_tpl = NULL; vtl->current_tp_track = NULL; vtl->current_tp_id = NULL; - vik_layer_emit_update(VIK_LAYER(vtl), FALSE); + vik_layer_emit_update(VIK_LAYER(vtl)); } } @@ -5511,12 +6711,14 @@ 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 ); + 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 ); } else if ( response == VIK_TRW_LAYER_TPWIN_DELETE ) { VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id ); + if ( tr == NULL ) + tr = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id ); if ( tr == NULL ) return; @@ -5539,7 +6741,7 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) if ( vtl->current_tp_track ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name ); - vik_layer_emit_update(VIK_LAYER(vtl), FALSE); + vik_layer_emit_update(VIK_LAYER(vtl)); } else { @@ -5553,21 +6755,21 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) { if ( vtl->current_tp_track ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name ); - vik_layer_emit_update(VIK_LAYER(vtl), FALSE); /* TODO longone: either move or only update if tp is inside drawing window */ + 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_layer_emit_update(VIK_LAYER(vtl), FALSE); + 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 ); - vik_layer_emit_update(VIK_LAYER(vtl), FALSE); + vik_layer_emit_update(VIK_LAYER(vtl)); } else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED ) - vik_layer_emit_update(VIK_LAYER(vtl), FALSE); + vik_layer_emit_update(VIK_LAYER(vtl)); } static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) @@ -5671,6 +6873,8 @@ static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams * } } +// ATM: Leave this as 'Track' only. +// Not overly bothered about having a snap to route trackpoint capability static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) { TPSearchParams params; @@ -5781,7 +6985,7 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve vtl->current_wp_id = NULL; trw_layer_cancel_current_tp ( vtl, FALSE ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } return FALSE; @@ -5800,7 +7004,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event if (!vtl || vtl->vl.type != VIK_LAYER_TRW) return FALSE; - if ( !vtl->tracks_visible && !vtl->waypoints_visible ) + if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible ) return FALSE; // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track @@ -5835,20 +7039,21 @@ 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; - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } } - if (vtl->tracks_visible) { - TPSearchParams tp_params; - tp_params.vvp = vvp; - tp_params.x = event->x; - tp_params.y = event->y; - tp_params.closest_track_id = NULL; - tp_params.closest_tp = NULL; + // Used for both track and route lists + TPSearchParams tp_params; + tp_params.vvp = vvp; + tp_params.x = event->x; + tp_params.y = event->y; + tp_params.closest_track_id = NULL; + tp_params.closest_tp = NULL; + if (vtl->tracks_visible) { g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params); if ( tp_params.closest_tp ) { @@ -5877,7 +7082,42 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event if ( vtl->tpwin ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + } + + // Try again for routes + if (vtl->routes_visible) { + g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &tp_params); + + if ( tp_params.closest_tp ) { + + // Always select + highlight the track + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, tp_params.closest_track_id ), TRUE ); + + tet->is_waypoint = FALSE; + + // Select the Trackpoint + // Can move it immediately when control held or it's the previously selected tp + if ( event->state & GDK_CONTROL_MASK || + vtl->current_tpl == tp_params.closest_tpl ) { + // Put into 'move buffer' + // NB vvp & vw already set in tet + tet->vtl = (gpointer)vtl; + marker_begin_move (tet, event->x, event->y); + } + + vtl->current_tpl = tp_params.closest_tpl; + vtl->current_tp_id = tp_params.closest_track_id; + vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, tp_params.closest_track_id ); + + 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_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } } @@ -5901,7 +7141,7 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve if (!vtl || vtl->vl.type != VIK_LAYER_TRW) return FALSE; - if ( !vtl->tracks_visible && !vtl->waypoints_visible ) + if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible ) return FALSE; /* Post menu for the currently selected item */ @@ -5921,16 +7161,24 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve udataU.trk = track; udataU.uuid = NULL; - gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU ); + gpointer *trkf; + if ( track->is_route ) + trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU ); + else + trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU ); if ( trkf && udataU.uuid ) { - GtkTreeIter *iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid ); + GtkTreeIter *iter; + if ( track->is_route ) + iter = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid ); + else + iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid ); trw_layer_sublayer_add_menu_items ( vtl, vtl->track_right_click_menu, NULL, - VIK_TRW_LAYER_SUBLAYER_TRACK, + track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK, udataU.uuid, iter, vvp ); @@ -6094,14 +7342,14 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve vtl->current_wp_id = params.closest_wp_id; /* could make it so don't update if old WP is off screen and new is null but oh well */ - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } vtl->current_wp = NULL; vtl->current_wp_id = NULL; vtl->waypoint_rightclick = FALSE; - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return FALSE; } @@ -6176,7 +7424,7 @@ static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *e marker_end_move ( t ); vtl->current_wp->coord = new_coord; - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } /* PUT IN RIGHT PLACE!!! */ @@ -6194,18 +7442,6 @@ static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *e return FALSE; } -/**** Begin track ***/ -static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp) -{ - return vvp; -} - -static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - vtl->current_track = NULL; - return tool_new_track_click ( vtl, event, vvp ); -} - /*** New track ****/ static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp) @@ -6241,7 +7477,7 @@ static gboolean draw_sync ( gpointer data ) return FALSE; } -static const gchar* distance_string (gdouble distance) +static gchar* distance_string (gdouble distance) { gchar str[128]; @@ -6274,11 +7510,14 @@ static const gchar* distance_string (gdouble distance) /* * Actually set the message in statusbar */ -static void statusbar_write (const gchar *distance_string, gdouble elev_gain, gdouble elev_loss, VikTrwLayer *vtl ) +static void statusbar_write (gdouble distance, gdouble elev_gain, gdouble elev_loss, gdouble last_step, gdouble angle, VikTrwLayer *vtl ) { // Only show elevation data when track has some elevation properties gchar str_gain_loss[64]; str_gain_loss[0] = '\0'; + gchar str_last_step[64]; + str_last_step[0] = '\0'; + gchar *str_total = distance_string (distance); if ( (elev_gain > 0.1) || (elev_loss > 0.1) ) { if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES ) @@ -6286,11 +7525,20 @@ static void statusbar_write (const gchar *distance_string, gdouble elev_gain, gd else g_sprintf(str_gain_loss, _(" - Gain %dft:Loss %dft"), (int)VIK_METERS_TO_FEET(elev_gain), (int)VIK_METERS_TO_FEET(elev_loss)); } + + if ( last_step > 0 ) { + gchar *tmp = distance_string (last_step); + g_sprintf(str_last_step, _(" - Bearing %3.1f° - Step %s"), RAD2DEG(angle), tmp); + g_free ( tmp ); + } + + VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)); // Write with full gain/loss information - gchar *msg = g_strdup_printf ( "%s%s", distance_string, str_gain_loss); - vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg ); + gchar *msg = g_strdup_printf ( "Total %s%s%s", str_total, str_last_step, str_gain_loss); + vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg ); g_free ( msg ); + g_free ( str_total ); } /* @@ -6304,11 +7552,8 @@ static void update_statusbar ( VikTrwLayer *vtl ) /* Find out actual distance of current track */ gdouble distance = vik_track_get_length (vtl->current_track); - const gchar *str = distance_string (distance); - - statusbar_write (str, elev_gain, elev_loss, vtl); - g_free ((gpointer)str); + statusbar_write (distance, elev_gain, elev_loss, 0, 0, vtl); } @@ -6317,6 +7562,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); static GdkPixmap *pixmap = NULL; int w1, h1, w2, h2; @@ -6341,7 +7587,7 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo draw_sync_t *passalong; gint x1, y1; - vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 ); + vik_viewport_coord_to_screen ( vvp, &(last_tpt->coord), &x1, &y1 ); // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method) // otherwise using vik_viewport_draw_* functions puts the data into the base pixmap, @@ -6359,7 +7605,8 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo struct LatLon ll; vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord ); vik_coord_to_latlon ( &coord, &ll ); - distance = distance + vik_coord_diff( &coord, &(VIK_TRACKPOINT(iter->data)->coord)); + gdouble last_step = vik_coord_diff( &coord, &(last_tpt->coord)); + distance = distance + last_step; // Get elevation data gdouble elev_gain, elev_loss; @@ -6369,18 +7616,18 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo gdouble elev_new; elev_new = (gdouble) a_dems_get_elev_by_coord ( &coord, VIK_DEM_INTERPOL_BEST ); if ( elev_new != VIK_DEM_INVALID_ELEVATION ) { - if ( VIK_TRACKPOINT(iter->data)->altitude != VIK_DEFAULT_ALTITUDE ) { + if ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) { // Adjust elevation of last track point - if ( elev_new > VIK_TRACKPOINT(iter->data)->altitude ) + if ( elev_new > last_tpt->altitude ) // Going up - elev_gain += elev_new - VIK_TRACKPOINT(iter->data)->altitude; + elev_gain += elev_new - last_tpt->altitude; else // Going down - elev_loss += VIK_TRACKPOINT(iter->data)->altitude - elev_new; + elev_loss += last_tpt->altitude - elev_new; } } - - const gchar *str = distance_string (distance); + + gchar *str = distance_string (distance); PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL); pango_layout_set_font_description (pl, GTK_WIDGET(vvp)->style->font_desc); @@ -6408,10 +7655,14 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo passalong->drawable = GTK_WIDGET(vvp)->window; passalong->gc = vtl->current_track_newpoint_gc; + gdouble angle; + gdouble baseangle; + vik_viewport_compute_bearing ( vvp, x1, y1, event->x, event->y, &angle, &baseangle ); + // Update statusbar with full gain/loss information - statusbar_write (str, elev_gain, elev_loss, vtl); + statusbar_write (distance, elev_gain, elev_loss, last_step, angle, vtl); - g_free ((gpointer)str); + g_free (str); // draw pixmap when we have time to g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL); @@ -6425,7 +7676,7 @@ static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, { if ( vtl->current_track && event->keyval == GDK_Escape ) { vtl->current_track = NULL; - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) { /* undo */ @@ -6435,16 +7686,22 @@ static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, g_free ( last->data ); vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); } - + update_statusbar ( vtl ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } return FALSE; } -static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +/* + * Common function to handle trackpoint button requests on either a route or a track + * . enables adding a point via normal click + * . enables removal of last point via right click + * . finishing of the track or route via double clicking + */ +static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { VikTrackpoint *tp; @@ -6458,8 +7715,10 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, return FALSE; } - if ( event->button == 3 && vtl->current_track ) + if ( event->button == 3 ) { + if ( !vtl->current_track ) + return FALSE; /* undo */ if ( vtl->current_track->trackpoints ) { @@ -6469,7 +7728,7 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, } update_statusbar ( vtl ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -6484,25 +7743,10 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, /* undo last, then end */ vtl->current_track = NULL; } - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } - if ( ! vtl->current_track ) - { - gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")); - if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name ) ) ) - { - vtl->current_track = vik_track_new(); - vtl->current_track->visible = TRUE; - vik_trw_layer_add_track ( vtl, name, vtl->current_track ); - - /* incase it was created by begin track */ - vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK ); - } - else - return TRUE; - } tp = vik_trackpoint_new(); vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) ); @@ -6517,19 +7761,38 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, tp->newsegment = FALSE; tp->has_timestamp = FALSE; tp->timestamp = 0; - vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp ); - /* Auto attempt to get elevation from DEM data (if it's available) */ - vik_track_apply_dem_data_last_trackpoint ( vtl->current_track ); + + if ( vtl->current_track ) { + vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp ); + /* Auto attempt to get elevation from DEM data (if it's available) */ + vik_track_apply_dem_data_last_trackpoint ( vtl->current_track ); + } vtl->ct_x1 = vtl->ct_x2; vtl->ct_y1 = vtl->ct_y2; vtl->ct_x2 = event->x; vtl->ct_y2 = event->y; - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } +static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + // ----------------------------------------------------- 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 ); + } + else + return TRUE; + } + return tool_new_track_or_route_click ( vtl, event, vvp ); +} + static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { if ( event->button == 2 ) { @@ -6539,6 +7802,27 @@ static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, Vi } } +/*** New route ****/ + +static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp) +{ + return 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 ) ) ) + { + 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; + } + return tool_new_track_or_route_click ( vtl, event, vvp ); +} + /*** New waypoint ****/ static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp) @@ -6553,7 +7837,7 @@ static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *even return FALSE; vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -6592,7 +7876,7 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e if (!vtl || vtl->vl.type != VIK_LAYER_TRW) return FALSE; - if ( !vtl->vl.visible || !vtl->tracks_visible ) + if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible ) return FALSE; if ( vtl->current_tpl ) @@ -6615,7 +7899,8 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e } - g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); + if ( vtl->tracks_visible ) + g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); if ( params.closest_tp ) { @@ -6625,7 +7910,22 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, params.closest_track_id ); trw_layer_tpwin_init ( vtl ); set_statusbar_msg_info_trkpt ( vtl, params.closest_tp ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + + if ( vtl->routes_visible ) + g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, ¶ms); + + if ( params.closest_tp ) + { + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, params.closest_track_id ), TRUE ); + vtl->current_tpl = params.closest_tpl; + vtl->current_tp_id = params.closest_track_id; + vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, params.closest_track_id ); + trw_layer_tpwin_init ( vtl ); + set_statusbar_msg_info_trkpt ( vtl, params.closest_tp ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -6695,14 +7995,14 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton if ( vtl->tpwin ) vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } return FALSE; } -#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS +#ifdef VIK_CONFIG_GOOGLE /*** Route Finder ***/ static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp) { @@ -6720,7 +8020,7 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even if ( new_end ) { vtl->route_finder_coord = *new_end; g_free ( new_end ); - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + 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' ); @@ -6755,7 +8055,8 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon), g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat), g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon)); - a_babel_convert_from_url ( vtl, url, "kml", NULL, NULL ); + // NB normally this returns a GPX Route - so subsequent usage of it must lookup via the routes hash + a_babel_convert_from_url ( vtl, url, "google", NULL, NULL, NULL ); g_free ( url ); /* see if anything was done -- a track was added or appended to */ @@ -6770,7 +8071,7 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even vtl->route_finder_check_added_track = FALSE; vtl->route_finder_append = FALSE; - vik_layer_emit_update ( VIK_LAYER(vtl), FALSE ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); } else { vtl->route_finder_started = TRUE; vtl->route_finder_coord = tmp; @@ -6788,7 +8089,7 @@ static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp) } /* Params are: vvp, event, last match found or NULL */ -static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[3] ) +static void tool_show_picture_wp ( const gpointer id, VikWaypoint *wp, gpointer params[3] ) { if ( wp->image && wp->visible ) { @@ -6850,10 +8151,7 @@ static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *even ***************************************************************************/ - - - -static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics ) +static void image_wp_make_list ( const gpointer id, VikWaypoint *wp, GSList **pics ) { if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) ) *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) ); @@ -6880,7 +8178,7 @@ static int create_thumbnails_thread ( thumbnail_create_thread_data *tctd, gpoint // Redraw to show the thumbnails as they are now created if ( IS_VIK_LAYER(tctd->vtl) ) - vik_layer_emit_update ( VIK_LAYER(tctd->vtl), TRUE ); // Yes update from background thread + vik_layer_emit_update ( VIK_LAYER(tctd->vtl) ); // NB update from background thread return 0; } @@ -6920,6 +8218,79 @@ void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp ) } } +static const gchar* my_track_colors ( gint ii ) +{ + static const gchar* colors[VIK_TRW_LAYER_TRACK_GCS] = { + "#2d870a", + "#135D34", + "#0a8783", + "#0e4d87", + "#05469f", + "#695CBB", + "#2d059f", + "#4a059f", + "#5A171A", + "#96059f" + }; + // Fast and reliable way of returning a colour + return colors[(ii % VIK_TRW_LAYER_TRACK_GCS)]; +} + +static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl ) +{ + GHashTableIter iter; + gpointer key, value; + + gint ii = 0; + // Tracks + g_hash_table_iter_init ( &iter, vtl->tracks ); + + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + + // Tracks get a random spread of colours if not already assigned + if ( ! VIK_TRACK(value)->has_color ) { + if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR ) + VIK_TRACK(value)->color = vtl->track_color; + else { + gdk_color_parse ( my_track_colors (ii), &(VIK_TRACK(value)->color) ); + } + VIK_TRACK(value)->has_color = TRUE; + } + + trw_layer_update_treeview ( vtl, VIK_TRACK(value), key ); + + ii++; + if (ii > VIK_TRW_LAYER_TRACK_GCS) + ii = 0; + } + + // Routes + ii = 0; + g_hash_table_iter_init ( &iter, vtl->routes ); + + while ( g_hash_table_iter_next (&iter, &key, &value) ) { + + // Routes get an intermix of reds + if ( ! VIK_TRACK(value)->has_color ) { + if ( ii ) + gdk_color_parse ( "#FF0000" , &(VIK_TRACK(value)->color) ); // Red + else + gdk_color_parse ( "#B40916" , &(VIK_TRACK(value)->color) ); // Dark Red + VIK_TRACK(value)->has_color = TRUE; + } + + trw_layer_update_treeview ( vtl, VIK_TRACK(value), key ); + + ii = !ii; + } +} + +static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vp ) +{ + trw_layer_verify_thumbnails ( vtl, vp ); + trw_layer_track_alloc_colors ( vtl ); +} + VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl ) { return vtl->coord_mode; @@ -6933,7 +8304,8 @@ VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl ) gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp ) { if ( vtl && vlp ) { - vik_trw_layer_uniquify_tracks ( vtl, vlp ); + vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->tracks, TRUE ); + vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->routes, FALSE ); vik_trw_layer_uniquify_waypoints ( vtl, vlp ); return TRUE; } @@ -6945,7 +8317,7 @@ static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode vik_coord_convert ( &(wp->coord), *dest_mode ); } -static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode ) +static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode ) { vik_track_convert ( tr, *dest_mode ); } @@ -6957,6 +8329,7 @@ static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mo vtl->coord_mode = dest_mode; g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_convert, &dest_mode ); g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode ); + g_hash_table_foreach ( vtl->routes, (GHFunc) track_convert, &dest_mode ); } } @@ -7134,7 +8507,14 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) VikTrwLayer *vtl = pass_along[0]; VikLayersPanel *vlp = pass_along[1]; - VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikTrack *trk; + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) + trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] ); + else + trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] ); + if ( !trk ) + return; + VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl))); GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types @@ -7186,7 +8566,7 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom)) goto done; - vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]); + vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]); done: for (i = 0; i < num_maps; i++)