* Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
* Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
* Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
+ * Copyright (c) 2012, Rob Norris <rw_norris@hotmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-
-#define WAYPOINT_FONT "Sans 8"
-
/* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
-/* viktrwlayer.c -- 2200 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"
#include "viking.h"
#include "vikmapslayer.h"
+#include "vikgpslayer.h"
#include "viktrwlayer_tpwin.h"
#include "viktrwlayer_propwin.h"
+#ifdef VIK_CONFIG_GEOTAG
+#include "viktrwlayer_geotag.h"
+#include "geotag_exif.h"
+#endif
#include "garminsymbols.h"
#include "thumbnails.h"
#include "background.h"
#include "osm-traces.h"
#endif
#include "acquire.h"
+#include "datasources.h"
+#include "datasource_gps.h"
#include "util.h"
#include "icons/icons.h"
#include <glib/gstdio.h>
#include <glib/gi18n.h>
-/* Relax some dependencies */
-#if ! GLIB_CHECK_VERSION(2,12,0)
-static gboolean return_true (gpointer a, gpointer b, gpointer c) { return TRUE; }
-static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
+#ifdef VIK_CONFIG_GOOGLE
+#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=js"
#endif
-#define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml"
-#define VIK_TRW_LAYER_TRACK_GC 13
+#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 DRAWMODE_BY_TRACK 0
-#define DRAWMODE_BY_VELOCITY 1
+#define DRAWMODE_BY_SPEED 1
#define DRAWMODE_ALL_BLACK 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
#define POINTS 1
#define LINES 2
#define MAX_STOP_LENGTH 86400
#define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
/* this is multiplied by user-inputted value from 1-100. */
-enum {
-VIK_TRW_LAYER_SUBLAYER_TRACKS,
-VIK_TRW_LAYER_SUBLAYER_WAYPOINTS,
-VIK_TRW_LAYER_SUBLAYER_TRACK,
-VIK_TRW_LAYER_SUBLAYER_WAYPOINT
-};
enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
+// See http://developer.gnome.org/pango/stable/PangoMarkupFormat.html
+typedef enum {
+ FS_XX_SMALL = 0, // 'xx-small'
+ FS_X_SMALL,
+ FS_SMALL,
+ FS_MEDIUM, // DEFAULT
+ FS_LARGE,
+ FS_X_LARGE,
+ FS_XX_LARGE,
+ FS_NUM_SIZES
+} font_size_t;
+
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;
guint8 drawelevation;
guint8 elevation_factor;
guint8 drawstops;
guint32 stop_length;
guint8 drawlines;
+ guint8 drawdirections;
+ guint8 drawdirections_size;
guint8 line_thickness;
guint8 bg_line_thickness;
guint8 wp_symbol;
guint8 wp_size;
gboolean wp_draw_symbols;
+ font_size_t wp_font_size;
- gdouble velocity_min, velocity_max;
+ gdouble track_draw_speed_factor;
GArray *track_gc;
- guint16 track_gc_iter;
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)
+ GdkGC *current_track_newpoint_gc;
GdkGC *track_bg_gc;
GdkGC *waypoint_gc;
GdkGC *waypoint_text_gc;
GdkGC *waypoint_bg_gc;
GdkFont *waypoint_font;
- VikTrack *current_track;
+ VikTrack *current_track; // ATM shared between new tracks and new routes
guint16 ct_x1, ct_y1, ct_x2, ct_y2;
- gboolean ct_sync_done;
-
+ gboolean draw_sync_done;
+ gboolean draw_sync_do;
VikCoordMode coord_mode;
/* wp editing tool */
VikWaypoint *current_wp;
- gchar *current_wp_name;
+ gpointer current_wp_id;
gboolean moving_wp;
gboolean waypoint_rightclick;
/* track editing tool */
GList *current_tpl;
- gchar *current_tp_track_name;
+ VikTrack *current_tp_track;
+ gpointer current_tp_id;
VikTrwLayerTpwin *tpwin;
- /* weird hack for joining tracks */
- GList *last_tpl;
- gchar *last_tp_track_name;
-
/* track editing tool -- more specifically, moving tps */
gboolean moving_tp;
- /* magic scissors tool */
- gboolean magic_scissors_started;
- VikCoord magic_scissors_coord;
- gboolean magic_scissors_check_added_track;
- gchar *magic_scissors_added_track_name;
- VikTrack *magic_scissors_current_track;
- gboolean magic_scissors_append;
+ /* route finder tool */
+ gboolean route_finder_started;
+ VikCoord route_finder_coord;
+ gboolean route_finder_check_added_track;
+ VikTrack *route_finder_added_track;
+ VikTrack *route_finder_current_track;
+ gboolean route_finder_append;
gboolean drawlabels;
gboolean drawimages;
VikTrwLayer *vtl;
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;
};
-static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16);
-static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl);
+static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
static void trw_layer_delete_item ( gpointer pass_along[6] );
static void trw_layer_copy_item_cb ( gpointer pass_along[6] );
static void trw_layer_cut_item_cb ( gpointer pass_along[6] );
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, GList **t, 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 (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 gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 );
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 const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
-static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
-
static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] );
static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
static void trw_layer_goto_track_center ( gpointer pass_along[6] );
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] );
static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
static void trw_layer_merge_with_other ( gpointer pass_along[6] );
+static void trw_layer_append_track ( gpointer pass_along[6] );
static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
static void trw_layer_split_by_n_points ( gpointer pass_along[6] );
+static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] );
+static void trw_layer_split_segments ( gpointer pass_along[6] );
+static void trw_layer_delete_points_same_position ( gpointer pass_along[6] );
+static void trw_layer_delete_points_same_time ( gpointer pass_along[6] );
+static void trw_layer_reverse ( gpointer pass_along[6] );
static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] );
static void trw_layer_edit_trackpoint ( gpointer pass_along[6] );
static void trw_layer_show_picture ( gpointer pass_along[6] );
+static void trw_layer_gps_upload_any ( gpointer pass_along[6] );
static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
static void trw_layer_auto_view ( gpointer layer_and_vlp[2] );
-static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, const gchar* trackname, guint file_type );
+static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type );
static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
static void trw_layer_new_wp ( gpointer lav[2] );
+static void trw_layer_new_track ( gpointer lav[2] );
+static void trw_layer_new_route ( gpointer lav[2] );
+static void trw_layer_finish_track ( gpointer lav[2] );
static void trw_layer_auto_waypoints_view ( gpointer lav[2] );
static void trw_layer_auto_tracks_view ( gpointer lav[2] );
static void trw_layer_delete_all_tracks ( gpointer lav[2] );
static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] );
static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] );
static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] );
+#ifdef VIK_CONFIG_GEOTAG
+static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] );
+static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] );
+static void trw_layer_geotagging_track ( gpointer pass_along[6] );
+static void trw_layer_geotagging ( gpointer lav[2] );
+#endif
+static void trw_layer_acquire_gps_cb ( gpointer lav[2] );
+#ifdef VIK_CONFIG_GOOGLE
+static void trw_layer_acquire_google_cb ( gpointer lav[2] );
+#endif
+#ifdef VIK_CONFIG_OPENSTREETMAP
+static void trw_layer_acquire_osm_cb ( gpointer lav[2] );
+#endif
+#ifdef VIK_CONFIG_GEOCACHES
+static void trw_layer_acquire_geocache_cb ( gpointer lav[2] );
+#endif
+#ifdef VIK_CONFIG_GEOTAG
+static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] );
+#endif
+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_routes_from_selection ( gpointer lav[2] );
/* pop-up items */
-static void trw_layer_properties_item ( gpointer pass_along[6] );
+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_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[5] );
-static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[5] );
-static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp );
-
-
-static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len );
-static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
-
-static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
-static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
-
-static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
-static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
-
-static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
-static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
-static void trw_layer_free_copied_item ( gint subtype, gpointer item );
-static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
-
-static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
-static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
-static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
-static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
+static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
+static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp );
static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl );
static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
static 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 );
+static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp );
static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp);
-static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-
+#ifdef VIK_CONFIG_GOOGLE
+static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+#endif
static void cached_pixbuf_free ( CachedPixbuf *cp );
static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
-static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp );
static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
-static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
-
-static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name);
-static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode );
+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 gchar *highest_wp_number_get(VikTrwLayer *vtl);
static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
-
+// Note for the following tool GtkRadioActionEntry texts:
+// the very first text value is an internal name not displayed anywhere
+// the first N_ text value is the name used for menu entries - hence has an underscore for the keyboard accelerator
+// * remember not to clash with the values used for VikWindow level tools (Pan, Zoom, Ruler + Select)
+// the second N_ text value is used for the button tooltip (i.e. generally don't want an underscore here)
+// the value is always set to 0 and the tool loader in VikWindow will set the actual appropriate value used
static VikToolInterface trw_layer_tools[] = {
- { N_("Create Waypoint"), (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
-
- { N_("Create Track"), (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_new_track_click, (VikToolMouseMoveFunc) tool_new_track_move, NULL,
- (VikToolKeyFunc) tool_new_track_key_press, GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
-
- { N_("Begin Track"), (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
-
- { N_("Edit Waypoint"), (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL,
+ { { "CreateWaypoint", "vik-icon-Create Waypoint", N_("Create _Waypoint"), "<control><shift>W", N_("Create Waypoint"), 0 },
+ (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
+
+ { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
+ (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_new_track_click,
+ (VikToolMouseMoveFunc) tool_new_track_move,
+ (VikToolMouseFunc) tool_new_track_release,
+ (VikToolKeyFunc) tool_new_track_key_press,
+ TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
+ GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
+
+ { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "<control><shift>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"), "<control><shift>E", N_("Edit Waypoint"), 0 },
+ (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL,
(VikToolMouseFunc) tool_edit_waypoint_click,
(VikToolMouseMoveFunc) tool_edit_waypoint_move,
- (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
+ (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
- { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
+ { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
+ (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
(VikToolMouseFunc) tool_edit_trackpoint_click,
(VikToolMouseMoveFunc) tool_edit_trackpoint_move,
- (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
-
- { N_("Show Picture"), (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
-
- { N_("Route Finder"), (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL,
- (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_iscissors_pixbuf },
+ (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
+
+ { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
+ (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
+
+#ifdef VIK_CONFIG_GOOGLE
+ { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
+ (VikToolConstructorFunc) tool_route_finder_create, NULL, NULL, NULL,
+ (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
+ FALSE,
+ GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
+#endif
};
-enum { 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, 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 Velocity"), N_("All Tracks Black"), 0 };
+static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Black"), 0 };
static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
+#define MIN_POINT_SIZE 2
+#define MAX_POINT_SIZE 10
+
+#define MIN_ARROW_SIZE 3
+#define MAX_ARROW_SIZE 20
static VikLayerParamScale params_scales[] = {
/* min max step digits */
{ 1, 10, 1, 0 }, /* line_thickness */
- { 0.0, 99.0, 1, 2 }, /* velocity_min */
- { 1.0, 100.0, 1.0, 2 }, /* velocity_max */
+ { 0, 100, 1, 0 }, /* track draw speed factor */
+ { 1.0, 100.0, 1.0, 2 }, /* UNUSED */
/* 5 * step == how much to turn */
- { 16, 128, 3.2, 0 }, /* image_size */
- { 0, 255, 5, 0 }, /* image alpha */
- { 5, 500, 5, 0 }, /* image cache_size */
- { 0, 8, 1, 0 }, /* image cache_size */
+ { 16, 128, 4, 0 }, // 3: image_size - NB step size ignored when an HSCALE used
+ { 0, 255, 5, 0 }, // 4: image alpha - " " " "
+ { 5, 500, 5, 0 }, // 5: image cache_size - " "
+ { 0, 8, 1, 0 }, // 6: Background line thickness
{ 1, 64, 1, 0 }, /* wpsize */
{ MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1, 0 }, /* stop_length */
- { 1, 100, 1, 0 }, /* stop_length */
+ { 1, 100, 1, 0 }, // 9: elevation factor
+ { MIN_POINT_SIZE, MAX_POINT_SIZE, 1, 0 }, // 10: track point size
+ { MIN_ARROW_SIZE, MAX_ARROW_SIZE, 1, 0 }, // 11: direction arrow size
};
+static gchar* params_font_sizes[] = {
+ N_("Extra Extra Small"),
+ N_("Extra Small"),
+ N_("Small"),
+ N_("Medium"),
+ N_("Large"),
+ N_("Extra Large"),
+ N_("Extra Extra Large"),
+ 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 },
+ { "routes_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 },
- { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 },
{ "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 },
- { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Min Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 },
- { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Max Track Velocity:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 },
+ { "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 },
{ "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
};
-enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS };
+// ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
+enum {
+ // Sublayer visibilities
+ PARAM_TV,
+ PARAM_WV,
+ PARAM_RV,
+ // Tracks
+ PARAM_DM,
+ PARAM_DL,
+ PARAM_LT,
+ PARAM_DD,
+ PARAM_DDS,
+ PARAM_DP,
+ PARAM_DPS,
+ PARAM_DE,
+ PARAM_EF,
+ PARAM_DS,
+ PARAM_SL,
+ PARAM_BLT,
+ PARAM_TBGC,
+ PARAM_TDSF,
+ // Waypoints
+ PARAM_DLA,
+ PARAM_WPFONTSIZE,
+ PARAM_WPC,
+ PARAM_WPTC,
+ PARAM_WPBC,
+ PARAM_WPBA,
+ PARAM_WPSYM,
+ PARAM_WPSIZE,
+ PARAM_WPSYMS,
+ // WP images
+ PARAM_DI,
+ PARAM_IS,
+ PARAM_IA,
+ PARAM_ICS,
+ NUM_PARAMS
+};
/*** TO ADD A PARAM:
*** 1) Add to trw_layer_params and enumeration
/****** END PARAMETERS ******/
+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_free ( VikTrwLayer *trwlayer );
+static void trw_layer_draw ( VikTrwLayer *l, gpointer data );
+static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
+static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 );
+static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl );
+static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp );
+static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp );
+static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter );
+static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer );
+static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
+static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
+static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp );
+static void trw_layer_marshall ( VikTrwLayer *vtl, guint8 **data, gint *len );
+static VikTrwLayer *trw_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp );
+static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
+static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
+static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
+static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
+static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
+static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
+static void trw_layer_free_copied_item ( gint subtype, gpointer item );
+static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
+static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+/* End Layer Interface function definitions */
+
VikLayerInterface vik_trw_layer_interface = {
"TrackWaypoint",
+ N_("TrackWaypoint"),
+ "<control><shift>Y",
&viktrwlayer_pixbuf,
trw_layer_tools,
VIK_MENU_ITEM_ALL,
- (VikLayerFuncCreate) vik_trw_layer_create,
- (VikLayerFuncRealize) vik_trw_layer_realize,
+ (VikLayerFuncCreate) trw_layer_create,
+ (VikLayerFuncRealize) trw_layer_realize,
(VikLayerFuncPostRead) trw_layer_verify_thumbnails,
- (VikLayerFuncFree) vik_trw_layer_free,
+ (VikLayerFuncFree) trw_layer_free,
(VikLayerFuncProperties) NULL,
- (VikLayerFuncDraw) vik_trw_layer_draw,
+ (VikLayerFuncDraw) trw_layer_draw,
(VikLayerFuncChangeCoordMode) trw_layer_change_coord_mode,
- (VikLayerFuncSetMenuItemsSelection) vik_trw_layer_set_menu_selection,
- (VikLayerFuncGetMenuItemsSelection) vik_trw_layer_get_menu_selection,
+ (VikLayerFuncSetMenuItemsSelection) trw_layer_set_menu_selection,
+ (VikLayerFuncGetMenuItemsSelection) trw_layer_get_menu_selection,
- (VikLayerFuncAddMenuItems) vik_trw_layer_add_menu_items,
- (VikLayerFuncSublayerAddMenuItems) vik_trw_layer_sublayer_add_menu_items,
+ (VikLayerFuncAddMenuItems) trw_layer_add_menu_items,
+ (VikLayerFuncSublayerAddMenuItems) trw_layer_sublayer_add_menu_items,
- (VikLayerFuncSublayerRenameRequest) vik_trw_layer_sublayer_rename_request,
- (VikLayerFuncSublayerToggleVisible) vik_trw_layer_sublayer_toggle_visible,
+ (VikLayerFuncSublayerRenameRequest) trw_layer_sublayer_rename_request,
+ (VikLayerFuncSublayerToggleVisible) trw_layer_sublayer_toggle_visible,
(VikLayerFuncSublayerTooltip) trw_layer_sublayer_tooltip,
(VikLayerFuncLayerTooltip) trw_layer_layer_tooltip,
- (VikLayerFuncLayerSelected) vik_trw_layer_selected,
+ (VikLayerFuncLayerSelected) trw_layer_selected,
(VikLayerFuncMarshall) trw_layer_marshall,
(VikLayerFuncUnmarshall) trw_layer_unmarshall,
(VikLayerFuncSelectedViewportMenu) trw_layer_show_selected_viewport_menu,
};
-/* for copy & paste (I think?) */
+// for copy & paste
typedef struct {
guint len;
guint8 data[0];
- // gchar *name;
- // VikWaypoint *wp;
} FlatItem;
GType vik_trw_layer_get_type ()
trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
if (data) {
+ const gchar* name;
+ if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+ VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, sublayer);
+ if ( wp && wp->name )
+ name = wp->name;
+ else
+ name = NULL; // Broken :(
+ }
+ 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, data);
+ subtype, len, name, data);
}
}
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;
if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
{
vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
- } else {
+ // '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 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 );
+ // less magic than before...
+ *len = sizeof(FlatItem) + 1 + il;
+ fi = g_malloc ( *len );
+ fi->len = *len;
+ memcpy(fi->data, id, il);
}
- *len = sizeof(FlatItem) + strlen(sublayer) + 1 + il;
- fi = g_malloc ( *len );
- fi->len = strlen(sublayer) + 1;
- memcpy(fi->data, sublayer, fi->len);
- memcpy(fi->data + fi->len, id, il);
g_free(id);
*item = (guint8 *)fi;
}
VikWaypoint *w;
gchar *name;
- name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, (gchar *)fi->data);
- w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
+ w = vik_waypoint_unmarshall(fi->data, fi->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 );
- waypoint_convert(name, w, &vtl->coord_mode);
+ waypoint_convert (NULL, w, &vtl->coord_mode);
+
// Consider if redraw necessary for the new item
if ( vtl->vl.visible && vtl->waypoints_visible && w->visible )
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi )
{
VikTrack *t;
gchar *name;
- name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, (gchar *)fi->data);
- t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len);
+
+ t = vik_track_unmarshall(fi->data, fi->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) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+ return TRUE;
+ }
+ if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && fi )
+ {
+ VikTrack *t;
+ gchar *name;
+
+ t = vik_track_unmarshall(fi->data, fi->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), FALSE );
return TRUE;
}
return FALSE;
{
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_DP: vtl->drawpoints = data.b; break;
+ case PARAM_DPS:
+ if ( data.u >= MIN_POINT_SIZE && data.u <= MAX_POINT_SIZE )
+ vtl->drawpoints_size = data.u;
+ break;
case PARAM_DE: vtl->drawelevation = data.b; break;
case PARAM_DS: vtl->drawstops = data.b; break;
case PARAM_DL: vtl->drawlines = data.b; break;
+ case PARAM_DD: vtl->drawdirections = data.b; break;
+ case PARAM_DDS:
+ if ( data.u >= MIN_ARROW_SIZE && data.u <= MAX_ARROW_SIZE )
+ vtl->drawdirections_size = data.u;
+ break;
case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
vtl->stop_length = data.u;
break;
trw_layer_new_track_gcs ( vtl, vp );
}
break;
- case PARAM_VMIN:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- vtl->velocity_min = data.d;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- vtl->velocity_min = VIK_KPH_TO_MPS(data.d);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- vtl->velocity_min = VIK_MPH_TO_MPS(data.d);
- else
- /* Knots */
- vtl->velocity_min = VIK_KNOTS_TO_MPS(data.d);
- break;
- }
- case PARAM_VMAX:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- vtl->velocity_max = data.d;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- vtl->velocity_max = VIK_KPH_TO_MPS(data.d);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- vtl->velocity_max = VIK_MPH_TO_MPS(data.d);
- else
- /* Knots */
- vtl->velocity_max = VIK_KNOTS_TO_MPS(data.d);
- break;
- }
case PARAM_TBGC: gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(data.c)); break;
+ case PARAM_TDSF: vtl->track_draw_speed_factor = data.d; break;
case PARAM_DLA: vtl->drawlabels = data.b; break;
case PARAM_DI: vtl->drawimages = data.b; break;
case PARAM_IS: if ( data.u != vtl->image_size )
case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
+ case PARAM_WPFONTSIZE: if ( data.u < FS_NUM_SIZES ) vtl->wp_font_size = data.u; break;
}
return TRUE;
}
{
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_DP: rv.b = vtl->drawpoints; break;
+ case PARAM_DPS: rv.u = vtl->drawpoints_size; break;
case PARAM_DE: rv.b = vtl->drawelevation; break;
case PARAM_EF: rv.u = vtl->elevation_factor; break;
case PARAM_DS: rv.b = vtl->drawstops; break;
case PARAM_SL: rv.u = vtl->stop_length; break;
case PARAM_DL: rv.b = vtl->drawlines; break;
+ case PARAM_DD: rv.b = vtl->drawdirections; break;
+ case PARAM_DDS: rv.u = vtl->drawdirections_size; break;
case PARAM_LT: rv.u = vtl->line_thickness; break;
case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
- case PARAM_VMIN:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- rv.d = vtl->velocity_min;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- rv.d = VIK_MPS_TO_KPH(vtl->velocity_min);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- rv.d = VIK_MPS_TO_MPH(vtl->velocity_min);
- else
- /* Knots */
- rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_min);
- break;
- }
- case PARAM_VMAX:
- {
- /* Convert to store internally
- NB file operation always in internal units (metres per second) */
- vik_units_speed_t speed_units = a_vik_get_units_speed ();
- if ( is_file_operation || speed_units == VIK_UNITS_SPEED_METRES_PER_SECOND )
- rv.d = vtl->velocity_max;
- else if ( speed_units == VIK_UNITS_SPEED_KILOMETRES_PER_HOUR )
- rv.d = VIK_MPS_TO_KPH(vtl->velocity_max);
- else if ( speed_units == VIK_UNITS_SPEED_MILES_PER_HOUR )
- rv.d = VIK_MPS_TO_MPH(vtl->velocity_max);
- else
- /* Knots */
- rv.d = VIK_MPS_TO_KNOTS(vtl->velocity_max);
- break;
- }
case PARAM_DLA: rv.b = vtl->drawlabels; break;
case PARAM_DI: rv.b = vtl->drawimages; break;
case PARAM_TBGC: vik_gc_get_fg_color(vtl->track_bg_gc, &(rv.c)); break;
+ case PARAM_TDSF: rv.d = vtl->track_draw_speed_factor; break;
case PARAM_IS: rv.u = vtl->image_size; break;
case PARAM_IA: rv.u = vtl->image_alpha; break;
case PARAM_ICS: rv.u = vtl->image_cache_size; break;
case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
+ case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
}
return rv;
}
*data = NULL;
if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) {
- a_gpx_write_file(vtl, f);
+ a_gpx_write_file(vtl, f, NULL);
vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
fclose(f);
f = NULL;
return rv;
}
-static GList * str_array_to_glist(gchar* data[])
-{
- GList *gl = NULL;
- gpointer * p;
- for (p = (gpointer)data; *p; p++)
- gl = g_list_prepend(gl, *p);
- return(g_list_reverse(gl));
-}
-
-static gboolean strcase_equal(gconstpointer s1, gconstpointer s2)
-{
- return (strcasecmp(s1, s2) == 0);
-}
-
+// Keep interesting hash function at least visible
+/*
static guint strcase_hash(gconstpointer v)
{
- /* 31 bit hash function */
+ // 31 bit hash function
int i;
const gchar *t = v;
- gchar s[128]; /* malloc is too slow for reading big files */
+ gchar s[128]; // malloc is too slow for reading big files
gchar *p = s;
for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
return h;
}
+*/
-VikTrwLayer *vik_trw_layer_new ( gint drawmode )
+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);
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_init ( VIK_LAYER(rv), VIK_LAYER_TRW );
+ vik_layer_set_type ( VIK_LAYER(rv), VIK_LAYER_TRW );
+
+ // It's not entirely clear the benefits of hash tables usage here - possibly the simplicity of first implementation for unique names
+ // Now with the name of the item stored as part of the item - these tables are effectively straightforward lists
- rv->waypoints = g_hash_table_new_full ( strcase_hash, strcase_equal, g_free, (GDestroyNotify) vik_waypoint_free );
- rv->tracks = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_track_free );
- rv->tracks_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
- rv->waypoints_iters = g_hash_table_new_full ( strcase_hash, strcase_equal, NULL, g_free );
+ // For this reworking I've choosen to keep the use of hash tables since for the expected data sizes
+ // - even many hundreds of waypoints and tracks is quite small in the grand scheme of things,
+ // and with normal PC processing capabilities - it has negligibile performance impact
+ // This also minimized the amount of rework - as the management of the hash tables already exists.
+
+ // The hash tables are indexed by simple integers acting as a UUID hash, which again shouldn't affect performance much
+ // we have to maintain a uniqueness (as before when multiple names where not allowed),
+ // this is to ensure it refers to the same item in the data structures used on the viewport and on the layers panel
+
+ rv->waypoints = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_waypoint_free );
+ 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;
+ 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->waypoint_text_gc = NULL;
rv->waypoint_bg_gc = NULL;
rv->track_gc = NULL;
- rv->velocity_max = 5.0;
- rv->velocity_min = 0.0;
+ rv->track_draw_speed_factor = 30.0;
rv->line_thickness = 1;
rv->bg_line_thickness = 0;
rv->current_wp = NULL;
- rv->current_wp_name = NULL;
+ rv->current_wp_id = NULL;
rv->current_track = NULL;
rv->current_tpl = NULL;
- rv->current_tp_track_name = NULL;
+ rv->current_tp_track = NULL;
+ rv->current_tp_id = NULL;
rv->moving_tp = FALSE;
rv->moving_wp = FALSE;
- rv->ct_sync_done = TRUE;
+ rv->draw_sync_done = TRUE;
+ rv->draw_sync_do = TRUE;
- rv->magic_scissors_started = FALSE;
- rv->magic_scissors_check_added_track = FALSE;
- rv->magic_scissors_added_track_name = NULL;
- rv->magic_scissors_current_track = NULL;
- rv->magic_scissors_append = FALSE;
+ 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->last_tpl = NULL;
- rv->last_tp_track_name = NULL;
rv->tpwin = NULL;
rv->image_cache = g_queue_new();
rv->image_size = 64;
}
-void vik_trw_layer_free ( VikTrwLayer *trwlayer )
+static void trw_layer_free ( VikTrwLayer *trwlayer )
{
g_hash_table_destroy(trwlayer->waypoints);
g_hash_table_destroy(trwlayer->tracks);
if ( trwlayer->waypoint_bg_gc != NULL )
g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
- if ( trwlayer->waypoint_font != NULL )
- gdk_font_unref ( trwlayer->waypoint_font );
-
if ( trwlayer->tpwin != NULL )
gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
g_queue_free ( trwlayer->image_cache );
}
-static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp )
+static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp )
{
+ dp->vtl = vtl;
dp->vp = vp;
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->center = vik_viewport_get_center ( vp );
dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */
dp->lat_lon = vik_viewport_get_coord_mode ( vp ) == VIK_COORD_LATLON;
dp->track_gc_iter = 0;
}
-static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2 )
-{
- static gdouble rv = 0;
- if ( tp1->has_timestamp && tp2->has_timestamp )
- {
- rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) )
- / (tp1->timestamp - tp2->timestamp) ) - vtl->velocity_min;
-
- if ( rv < 0 )
- return VIK_TRW_LAYER_TRACK_GC_MIN;
- else if ( vtl->velocity_min >= vtl->velocity_max )
- return VIK_TRW_LAYER_TRACK_GC_MAX;
-
- rv *= (VIK_TRW_LAYER_TRACK_GC_RATES / (vtl->velocity_max - vtl->velocity_min));
-
- if ( rv >= VIK_TRW_LAYER_TRACK_GC_MAX )
- return VIK_TRW_LAYER_TRACK_GC_MAX;
- return (gint) rv;
- }
- else
- return VIK_TRW_LAYER_TRACK_GC_BLACK;
+/*
+ * Determine the colour of the trackpoint (and/or trackline) relative to the average speed
+ * Here a simple traffic like light colour system is used:
+ * . slow points are red
+ * . average is yellow
+ * . fast points are green
+ */
+static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2, gdouble average_speed, gdouble low_speed, gdouble high_speed )
+{
+ gdouble rv = 0;
+ if ( tp1->has_timestamp && tp2->has_timestamp ) {
+ if ( average_speed > 0 ) {
+ rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) ) / (tp1->timestamp - tp2->timestamp) );
+ if ( rv < low_speed )
+ return VIK_TRW_LAYER_TRACK_GC_SLOW;
+ else if ( rv > high_speed )
+ return VIK_TRW_LAYER_TRACK_GC_FAST;
+ else
+ return VIK_TRW_LAYER_TRACK_GC_AVER;
+ }
+ }
+ 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 );
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 gchar *name, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline )
{
/* TODO: this function is a mess, get rid of any redundancy */
GList *list = track->trackpoints;
gboolean drawelevation;
gdouble min_alt, max_alt, alt_diff = 0;
- const guint8 tp_size_reg = 2;
- const guint8 tp_size_cur = 4;
+ const guint8 tp_size_reg = dp->vtl->drawpoints_size;
+ const guint8 tp_size_cur = dp->vtl->drawpoints_size*2;
guint8 tp_size;
if ( dp->vtl->drawelevation )
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 )
+ if ( dp->vtl->bg_line_thickness && !draw_track_outline )
trw_layer_draw_track ( name, track, dp, TRUE );
- if ( drawing_white_background )
+ if ( draw_track_outline )
drawpoints = drawstops = FALSE;
else {
drawpoints = dp->vtl->drawpoints;
drawstops = dp->vtl->drawstops;
}
+ gboolean drawing_highlight = FALSE;
/* Current track - used for creation */
if ( track == dp->vtl->current_track )
main_gc = dp->vtl->current_track_gc;
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->is_route && ( dp->vtl->tracks == vik_window_get_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl) ) ) ) ||
+ ( track->is_route && ( dp->vtl->routes == 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) ) ) ) {
main_gc = vik_viewport_get_gc_highlight (dp->vp);
+ drawing_highlight = TRUE;
}
else {
if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK )
oldx = x;
oldy = y;
+ gdouble average_speed = 0.0;
+ gdouble low_speed = 0.0;
+ gdouble high_speed = 0.0;
+ // If necessary calculate these values - which is done only once per track redraw
+ if ( dp->vtl->drawmode == DRAWMODE_BY_SPEED ) {
+ // the percentage factor away from the average speed determines transistions between the levels
+ average_speed = vik_track_get_average_speed_moving(track, dp->vtl->stop_length);
+ low_speed = average_speed - (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
+ high_speed = average_speed + (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
+ }
+
while ((list = g_list_next(list)))
{
tp = VIK_TRACKPOINT(list->data);
{
vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
- if ( drawpoints && ! drawing_white_background )
+ /*
+ * If points are the same in display coordinates, don't draw.
+ */
+ if ( useoldvals && x == oldx && y == oldy )
+ {
+ // Still need to process points to ensure 'stops' are drawn if required
+ 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 );
+
+ goto skip;
+ }
+
+ VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
+ 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);
+ }
+ }
+
+ if ( drawpoints && ! draw_track_outline )
{
- if ( list->next ) {
- vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
+ if ( list->next ) {
+ /*
+ * The concept of drawing stops is that a trackpoint
+ * that is if the next trackpoint has a timestamp far into
+ * the future, we draw a circle of 6x trackpoint size,
+ * instead of a rectangle of 2x trackpoint size.
+ * This is drawn first so the trackpoint will be drawn on top
+ */
/* 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 );
+
+ /* 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 );
}
else
+ /* Final point - draw 4x circle. */
vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
}
if ((!tp->newsegment) && (dp->vtl->drawlines))
{
- VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
/* UTM only: zone check */
if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
draw_utm_skip_insignia ( dp->vp, main_gc, x, y);
- if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
- dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
- main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter);
- }
-
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 {
vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
- if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
+
+ if ( dp->vtl->drawelevation && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
GdkPoint tmp[4];
#define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
- if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
- tmp[0].x = oldx;
- tmp[0].y = oldy;
- tmp[1].x = oldx;
- tmp[1].y = oldy-FIXALTITUDE(list->data);
- tmp[2].x = x;
- tmp[2].y = y-FIXALTITUDE(list->next->data);
- tmp[3].x = x;
- tmp[3].y = y;
-
- GdkGC *tmp_gc;
- if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
- tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
- else
- tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
- vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
- }
+
+ tmp[0].x = oldx;
+ tmp[0].y = oldy;
+ tmp[1].x = oldx;
+ tmp[1].y = oldy-FIXALTITUDE(list->data);
+ tmp[2].x = x;
+ tmp[2].y = y-FIXALTITUDE(list->next->data);
+ tmp[3].x = x;
+ tmp[3].y = y;
+
+ GdkGC *tmp_gc;
+ if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
+ tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3];
+ else
+ tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0];
+ vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
+
vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
}
}
}
+ if ( (!tp->newsegment) && dp->vtl->drawdirections ) {
+ // Draw an arrow at the mid point to show the direction of the track
+ // Code is a rework from vikwindow::draw_ruler()
+ gint midx = (oldx + x) / 2;
+ gint midy = (oldy + y) / 2;
+
+ gdouble len = sqrt ( ((midx-oldx) * (midx-oldx)) + ((midy-oldy) * (midy-oldy)) );
+ // Avoid divide by zero and ensure at least 1 pixel big
+ if ( len > 1 ) {
+ gdouble dx = (oldx - midx) / len;
+ gdouble dy = (oldy - midy) / len;
+ vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc + dy * dp->ss), midy + (dy * dp->cc - dx * dp->ss) );
+ vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc - dy * dp->ss), midy + (dy * dp->cc + dx * dp->ss) );
+ }
+ }
+
+ skip:
oldx = x;
oldy = y;
useoldvals = TRUE;
if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
{
vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
- if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) {
- dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 );
+
+ 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);
- }
+ }
- if ( drawing_white_background )
- 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);
+ /*
+ * If points are the same in display coordinates, don't draw.
+ */
+ if ( x != oldx || y != oldy )
+ {
+ 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);
+ }
}
else
{
- vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
- draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
+ /*
+ * If points are the same in display coordinates, don't draw.
+ */
+ if ( x != oldx && y != oldy )
+ {
+ vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
+ draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
+ }
}
}
useoldvals = FALSE;
}
}
if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
- if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC )
+ if ( ++(dp->track_gc_iter) >= VIK_TRW_LAYER_TRACK_GC_MAX )
dp->track_gc_iter = 0;
}
/* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
gint label_x, label_y;
gint width, height;
- pango_layout_set_text ( dp->vtl->wplabellayout, name, -1 );
+ // Hopefully name won't break the markup (may need to sanitize - g_markup_escape_text())
+
+ // Could this stored in the waypoint rather than recreating each pass?
+ gchar *fsize = NULL;
+ switch (dp->vtl->wp_font_size) {
+ case FS_XX_SMALL: fsize = g_strdup ( "xx-small" ); break;
+ case FS_X_SMALL: fsize = g_strdup ( "x-small" ); break;
+ case FS_SMALL: fsize = g_strdup ( "small" ); break;
+ case FS_LARGE: fsize = g_strdup ( "large" ); break;
+ case FS_X_LARGE: fsize = g_strdup ( "x-large" ); break;
+ case FS_XX_LARGE: fsize = g_strdup ( "xx-large" ); break;
+ default: fsize = g_strdup ( "medium" ); break;
+ }
+
+ gchar *wp_label_markup = g_strdup_printf ( "<span size=\"%s\">%s</span>", fsize, wp->name );
+
+ if ( pango_parse_markup ( wp_label_markup, -1, 0, NULL, NULL, NULL, NULL ) )
+ pango_layout_set_markup ( dp->vtl->wplabellayout, wp_label_markup, -1 );
+ else
+ // Fallback if parse failure
+ pango_layout_set_text ( dp->vtl->wplabellayout, wp->name, -1 );
+
+ g_free ( wp_label_markup );
+ g_free ( fsize );
+
pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
label_x = x - width/2;
if (sym)
}
}
-void vik_trw_layer_draw ( VikTrwLayer *l, gpointer data )
+static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
{
static struct DrawingParams dp;
g_assert ( l != NULL );
- init_drawing_params ( &dp, VIK_VIEWPORT(data) );
- dp.vtl = l;
+ init_drawing_params ( &dp, l, VIK_VIEWPORT(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 );
}
g_object_unref ( vtl->current_track_gc );
vtl->current_track_gc = NULL;
}
+ if ( vtl->current_track_newpoint_gc )
+ {
+ g_object_unref ( vtl->current_track_newpoint_gc );
+ vtl->current_track_newpoint_gc = NULL;
+ }
if ( ! vtl->track_gc )
return;
g_object_unref ( vtl->track_bg_gc );
vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_line_thickness );
+ // Ensure new track drawing heeds line thickness setting
+ // however always have a minium of 2, as 1 pixel is really narrow
+ gint new_track_width = (vtl->line_thickness < 2) ? 2 : vtl->line_thickness;
+
if ( vtl->current_track_gc )
g_object_unref ( vtl->current_track_gc );
- vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
- gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+ vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
+ gdk_gc_set_line_attributes ( vtl->current_track_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+
+ // 'newpoint' gc is exactly the same as the current track gc
+ if ( vtl->current_track_newpoint_gc )
+ g_object_unref ( vtl->current_track_newpoint_gc );
+ vtl->current_track_newpoint_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
+ gdk_gc_set_line_attributes ( vtl->current_track_newpoint_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
gc[12] = vik_viewport_new_gc ( vp, "#000000", width ); /* black / no speed data */
+ 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
+
g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
}
-VikTrwLayer *vik_trw_layer_create ( VikViewport *vp )
+static VikTrwLayer* trw_layer_create ( VikViewport *vp )
{
- VikTrwLayer *rv = vik_trw_layer_new ( 0 );
- PangoFontDescription *pfd;
- rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
- pfd = pango_font_description_from_string (WAYPOINT_FONT);
- pango_layout_set_font_description (rv->wplabellayout, pfd);
- /* freeing PangoFontDescription, cause it has been copied by prev. call */
- pango_font_description_free (pfd);
-
+ VikTrwLayer *rv = trw_layer_new ( DRAWMODE_BY_TRACK );
vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
+ if ( vp == NULL || GTK_WIDGET(vp)->window == NULL ) {
+ /* early exit, as the rest is GUI related */
+ return rv;
+ }
+
+ rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
+ pango_layout_set_font_description (rv->wplabellayout, GTK_WIDGET(vp)->style->font_desc);
+
trw_layer_new_track_gcs ( rv, vp );
rv->waypoint_gc = vik_viewport_new_gc ( vp, "#000000", 2 );
rv->waypoint_bg_gc = vik_viewport_new_gc ( vp, "#8383C4", 1 );
gdk_gc_set_function ( rv->waypoint_bg_gc, GDK_AND );
- rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" );
-
rv->has_verified_thumbnails = FALSE;
rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE;
rv->wp_size = 4;
rv->wp_draw_symbols = TRUE;
+ rv->wp_font_size = FS_MEDIUM;
rv->coord_mode = vik_viewport_get_coord_mode ( vp );
return rv;
}
-static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[5] )
+#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));
#ifdef VIK_CONFIG_ALPHABETIZED_TRW
- vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, 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]), NULL, TRUE, TRUE );
#else
- vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, 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]), NULL, TRUE, TRUE );
#endif
*new_iter = *((GtkTreeIter *) pass_along[1]);
- g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, name, 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 );
}
-static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer pass_along[5] )
+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], name, pass_along[2], name, 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], name, pass_along[2], name, 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], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
#endif
*new_iter = *((GtkTreeIter *) pass_along[1]);
- g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, name, new_iter );
+ g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter );
if ( ! wp->visible )
vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
}
-
-void vik_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, (gpointer) 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] = (gpointer) 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 );
+ }
}
-gboolean vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
+static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
{
switch ( 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 );
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;
}
+/*
+ * Return a property about tracks for this layer
+ */
+gint vik_trw_layer_get_property_tracks_line_thickness ( VikTrwLayer *vtl )
+{
+ return vtl->line_thickness;
+}
+
// Structure to hold multiple track information for a layer
typedef struct {
gdouble length;
// 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);
{
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];
}
}
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 );
// NB It's OK to return NULL
- return w->comment;
+ if ( w )
+ return w->comment;
}
break;
default: break;
return NULL;
}
-/**
- * General layer selection function, find out which bit is selected and take appropriate action
+/*
+ * Function to show basic track point information on the statusbar
*/
-gboolean vik_trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp )
+static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt )
{
- // Reset
- l->current_wp = NULL;
- l->current_wp_name = NULL;
- trw_layer_cancel_current_tp ( l, FALSE );
+ gchar tmp_buf1[64];
+ switch (a_vik_get_units_height ()) {
+ case VIK_UNITS_HEIGHT_FEET:
+ g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(trkpt->altitude)));
+ break;
+ default:
+ //VIK_UNITS_HEIGHT_METRES:
+ g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dm"), (int)round(trkpt->altitude));
+ }
+
+ gchar tmp_buf2[64];
+ tmp_buf2[0] = '\0';
+ if ( trkpt->has_timestamp ) {
+ // Compact date time format
+ strftime (tmp_buf2, sizeof(tmp_buf2), _(" | Time %x %X"), localtime(&(trkpt->timestamp)));
+ }
+
+ // Position part
+ // Position is put later on, as this bit may not be seen if the display is not big enough,
+ // one can easily use the current pointer position to see this if needed
+ gchar *lat = NULL, *lon = NULL;
+ static struct LatLon ll;
+ vik_coord_to_latlon (&(trkpt->coord), &ll);
+ a_coords_latlon_to_string ( &ll, &lat, &lon );
+
+ // Track name
+ // Again is put later on, as this bit may not be seen if the display is not big enough
+ // trackname can be seen from the treeview (when enabled)
+ // Also name could be very long to not leave room for anything else
+ gchar tmp_buf3[64];
+ tmp_buf3[0] = '\0';
+ if ( vtl->current_tp_track ) {
+ g_snprintf(tmp_buf3, sizeof(tmp_buf3), _(" | Track: %s"), vtl->current_tp_track->name );
+ }
+
+ // Combine parts to make overall message
+ gchar *msg = g_strdup_printf (_("%s%s | %s %s %s"), tmp_buf1, tmp_buf2, lat, lon, tmp_buf3);
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
+ g_free ( lat );
+ g_free ( lon );
+ g_free ( msg );
+}
- switch ( type )
- {
- case VIK_TREEVIEW_TYPE_LAYER:
- {
- vik_window_set_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l );
- /* Mark for redraw */
- return TRUE;
+/*
+ * Function to show basic waypoint information on the statusbar
+ */
+static void set_statusbar_msg_info_wpt ( VikTrwLayer *vtl, VikWaypoint *wpt )
+{
+ gchar tmp_buf1[64];
+ switch (a_vik_get_units_height ()) {
+ case VIK_UNITS_HEIGHT_FEET:
+ g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(wpt->altitude)));
+ break;
+ default:
+ //VIK_UNITS_HEIGHT_METRES:
+ g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dm"), (int)round(wpt->altitude));
+ }
+
+ // Position part
+ // Position is put last, as this bit is most likely not to be seen if the display is not big enough,
+ // one can easily use the current pointer position to see this if needed
+ gchar *lat = NULL, *lon = NULL;
+ static struct LatLon ll;
+ vik_coord_to_latlon (&(wpt->coord), &ll);
+ a_coords_latlon_to_string ( &ll, &lat, &lon );
+
+ // Combine parts to make overall message
+ gchar *msg;
+ if ( wpt->comment )
+ // Add comment if available
+ msg = g_strdup_printf ( _("%s | %s %s | Comment: %s"), tmp_buf1, lat, lon, wpt->comment );
+ else
+ msg = g_strdup_printf ( _("%s | %s %s"), tmp_buf1, lat, lon );
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
+ g_free ( lat );
+ g_free ( lon );
+ g_free ( msg );
+}
+
+/**
+ * General layer selection function, find out which bit is selected and take appropriate action
+ */
+static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp )
+{
+ // Reset
+ l->current_wp = NULL;
+ l->current_wp_id = NULL;
+ trw_layer_cancel_current_tp ( l, FALSE );
+
+ // Clear statusbar
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l))), VIK_STATUSBAR_INFO, "" );
+
+ switch ( type )
+ {
+ case VIK_TREEVIEW_TYPE_LAYER:
+ {
+ vik_window_set_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l );
+ /* Mark for redraw */
+ return TRUE;
}
break;
break;
case VIK_TRW_LAYER_SUBLAYER_TRACK:
{
- vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), g_hash_table_lookup ( l->tracks, sublayer ), l, sublayer );
+ VikTrack *track = g_hash_table_lookup ( l->tracks, 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_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_WAYPOINT:
{
- vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), g_hash_table_lookup ( l->waypoints, sublayer ), l, sublayer );
- /* Mark for redraw */
- return TRUE;
+ VikWaypoint *wpt = g_hash_table_lookup ( l->waypoints, sublayer );
+ if ( wpt ) {
+ vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)wpt, l );
+ // Show some waypoint info
+ set_statusbar_msg_info_wpt ( l, wpt );
+ /* Mark for redraw */
+ return TRUE;
+ }
}
break;
default:
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;
}
+/*
+ * ATM use a case sensitive find
+ * Finds the first one
+ */
+static gboolean trw_layer_waypoint_find ( const gpointer id, const VikWaypoint *wp, const gchar *name )
+{
+ if ( wp && wp->name )
+ if ( ! strcmp ( wp->name, name ) )
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Get waypoint by name - not guaranteed to be unique
+ * Finds the first one
+ */
+VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, const gchar *name )
+{
+ return g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find, (gpointer) name );
+}
+
+/*
+ * ATM use a case sensitive find
+ * Finds the first one
+ */
+static gboolean trw_layer_track_find ( const gpointer id, const VikTrack *trk, const gchar *name )
+{
+ if ( trk && trk->name )
+ if ( ! strcmp ( trk->name, name ) )
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Get track by name - not guaranteed to be unique
+ * Finds the first one
+ */
+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 );
+}
+
+/*
+ * 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 gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] )
{
static VikCoord fixme;
maxmin[1].lon = VIK_LATLON(&fixme)->lon;
}
-static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] )
+static void trw_layer_find_maxmin_tracks ( const gchar *name, const VikTrack *trk, struct LatLon maxmin[2] )
{
- GList *tr = *t;
+ GList *tr = trk->trackpoints;
static VikCoord fixme;
while ( 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 )
a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
}
-static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, const gchar* trackname, guint file_type )
+static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type )
{
GtkWidget *file_selector;
const gchar *fn;
if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE )
{
gtk_widget_hide ( file_selector );
- failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname);
+ failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
break;
}
else
if ( a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
{
gtk_widget_hide ( file_selector );
- failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname);
+ failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
break;
}
}
static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
{
- trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPX );
+ /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
+ gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
+ if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
+ auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
+
+ trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
+
+ g_free ( auto_save_name );
}
static void trw_layer_export_kml ( gpointer layer_and_vlp[2] )
g_free ( auto_save_name );
}
+/**
+ * Convert the given TRW layer into a temporary GPX file and open it with the specified program
+ *
+ */
+static void trw_layer_export_external_gpx ( gpointer layer_and_vlp[2], const gchar* external_program )
+{
+ gchar *name_used = NULL;
+ int fd;
+
+ if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) {
+ gboolean failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), name_used, FILE_TYPE_GPX, NULL, TRUE);
+ if (failed) {
+ a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Could not create temporary file for export.") );
+ }
+ else {
+ GError *err = NULL;
+ gchar *quoted_file = g_shell_quote ( name_used );
+ gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file );
+ g_free ( quoted_file );
+ if ( ! g_spawn_command_line_async ( cmd, &err ) )
+ {
+ a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( layer_and_vlp[0]), _("Could not launch %s."), external_program );
+ g_error_free ( err );
+ }
+ g_free ( cmd );
+ }
+ // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous
+ //g_remove ( name_used );
+ // Perhaps should be deleted when the program ends?
+ // For now leave it to the user to delete it / use system temp cleanup methods.
+ g_free ( name_used );
+ }
+}
+
+static void trw_layer_export_external_gpx_1 ( gpointer layer_and_vlp[2] )
+{
+ trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_1() );
+}
+
+static void trw_layer_export_external_gpx_2 ( gpointer layer_and_vlp[2] )
+{
+ trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_2() );
+}
+
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];
+ 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;
+
/* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
- gchar *auto_save_name = g_strdup ( pass_along[3] );
+ gchar *auto_save_name = g_strdup ( trk->name );
if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
- trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, pass_along[3], FILE_TYPE_GPX );
+ trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, trk, FILE_TYPE_GPX );
g_free ( auto_save_name );
}
+typedef struct {
+ VikWaypoint *wp; // input
+ gpointer uuid; // output
+} wpu_udata;
+
+static gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata )
+{
+ wpu_udata *user_data = udata;
+ if ( wp == user_data->wp ) {
+ user_data->uuid = id;
+ return TRUE;
+ }
+ return FALSE;
+}
+
static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
{
- GHashTable *wps = vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp[0]) );
GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
{
- VikWaypoint *wp;
- gchar *upname = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
- int i;
-
- for ( i = strlen(upname)-1; i >= 0; i-- )
- upname[i] = toupper(upname[i]);
+ gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+ // Find *first* wp with the given name
+ VikWaypoint *wp = vik_trw_layer_get_waypoint ( VIK_TRW_LAYER(layer_and_vlp[0]), name );
- wp = g_hash_table_lookup ( wps, upname );
-
- if (!wp)
+ if ( !wp )
a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
else
{
vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
- vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, upname ), TRUE );
+
+ // Find and select on the side panel
+ wpu_udata udata;
+ udata.wp = wp;
+ udata.uuid = NULL;
+
+ // Hmmm, want key of it
+ gpointer *wpf = g_hash_table_find ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+ if ( wpf && udata.uuid ) {
+ GtkTreeIter *it = g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, udata.uuid );
+ vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, it, TRUE );
+ }
+
break;
}
- g_free ( upname );
+ g_free ( name );
}
gtk_widget_destroy ( dia );
gchar *returned_name;
gboolean updated;
wp->coord = *def_coord;
+
+ // Attempt to auto set height if DEM data is available
+ gint16 elev = a_dems_get_elev_by_coord ( &(wp->coord), VIK_DEM_INTERPOL_BEST );
+ if ( elev != VIK_DEM_INVALID_ELEVATION )
+ wp->altitude = (gdouble)elev;
+
+ returned_name = a_dialog_waypoint ( w, default_name, wp, vtl->coord_mode, TRUE, &updated );
- if ( ( returned_name = a_dialog_waypoint ( w, default_name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode, TRUE, &updated ) ) )
+ if ( returned_name )
{
wp->visible = TRUE;
vik_trw_layer_add_waypoint ( vtl, returned_name, wp );
g_free (default_name);
+ g_free (returned_name);
return TRUE;
}
g_free (default_name);
a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin);
}
-static void trw_layer_new_wp ( gpointer lav[2] )
+#ifdef VIK_CONFIG_GEOTAG
+static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] )
+{
+ VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+ if ( wp )
+ // Update directly - not changing the mtime
+ a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE );
+}
+
+static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] )
+{
+ VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
+ if ( wp )
+ // Update directly
+ a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE );
+}
+
+/*
+ * Use code in separate file for this feature as reasonably complex
+ */
+static void trw_layer_geotagging_track ( 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] );
+ // Unset so can be reverified later if necessary
+ vtl->has_verified_thumbnails = FALSE;
+
+ trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ vtl,
+ track,
+ track->name );
+}
+
+static void trw_layer_geotagging ( gpointer lav[2] )
{
VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
- VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
- /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
- instead return true if you want to update. */
- if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible )
- vik_layers_panel_emit_update ( vlp );
+ // Unset so can be reverified later if necessary
+ vtl->has_verified_thumbnails = FALSE;
+
+ trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ vtl,
+ NULL,
+ NULL);
}
+#endif
-static void trw_layer_auto_tracks_view ( gpointer lav[2] )
+// 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
+
+/*
+ * Acquire into this TRW Layer straight from GPS Device
+ */
+static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
{
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);
- if ( g_hash_table_size (vtl->tracks) > 0 ) {
- struct LatLon maxmin[2] = { {0,0}, {0,0} };
- g_hash_table_foreach ( vtl->tracks, (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 );
- }
+ vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
+ a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface );
}
-static void trw_layer_single_waypoint_jump ( const gchar *name, const VikWaypoint *wp, gpointer vvp )
+#ifdef VIK_CONFIG_GOOGLE
+/*
+ * Acquire into this TRW Layer from Google Directions
+ */
+static void trw_layer_acquire_google_cb ( gpointer lav[2] )
{
- /* NB do not care if wp is visible or not */
- vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
+ VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+ VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+ VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+ VikViewport *vvp = vik_window_viewport(vw);
+
+ a_acquire ( vw, vlp, vvp, &vik_datasource_google_interface );
}
+#endif
-static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
+#ifdef VIK_CONFIG_OPENSTREETMAP
+/*
+ * Acquire into this TRW Layer from OSM
+ */
+static void trw_layer_acquire_osm_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);
- /* Only 1 waypoint - jump straight to it */
- if ( g_hash_table_size (vtl->waypoints) == 1 ) {
- VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
- g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
- }
- /* If at least 2 waypoints - find center and then zoom to fit */
- else if ( g_hash_table_size (vtl->waypoints) > 1 )
- {
- struct LatLon maxmin[2] = { {0,0}, {0,0} };
- g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin );
- trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
- }
+ a_acquire ( vw, vlp, vvp, &vik_datasource_osm_interface );
+}
+#endif
- vik_layers_panel_emit_update ( vlp );
+#ifdef VIK_CONFIG_GEOCACHES
+/*
+ * Acquire into this TRW Layer from Geocaching.com
+ */
+static void trw_layer_acquire_geocache_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_gc_interface );
}
+#endif
-void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
+#ifdef VIK_CONFIG_GEOTAG
+/*
+ * Acquire into this TRW Layer from images
+ */
+static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
{
- static gpointer pass_along[2];
- GtkWidget *item;
- GtkWidget *export_submenu;
- GtkWidget *wikipedia_submenu;
- pass_along[0] = vtl;
- pass_along[1] = vlp;
+ 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);
- item = gtk_menu_item_new();
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
- gtk_widget_show ( item );
+ vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
+ a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface );
- item = gtk_menu_item_new_with_mnemonic ( _("_View Layer") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show ( item );
+ // Reverify thumbnails as they may have changed
+ vtl->has_verified_thumbnails = FALSE;
+ trw_layer_verify_thumbnails ( vtl, NULL );
+}
+#endif
- 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 );
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show ( item );
+static void trw_layer_gps_upload ( gpointer lav[2] )
+{
+ gpointer pass_along[6];
+ pass_along[0] = lav[0];
+ pass_along[1] = lav[1];
+ pass_along[2] = NULL; // No track - operate on the layer
+ pass_along[3] = NULL;
+ pass_along[4] = NULL;
+ pass_along[5] = NULL;
- item = gtk_menu_item_new_with_mnemonic ( _("V_iew 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_widget_show ( item );
+ trw_layer_gps_upload_any ( pass_along );
+}
- item = gtk_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show ( item );
+/**
+ * If pass_along[3] is defined that this will upload just that track
+ */
+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[2&3] can be null
+ VikTrack *track = NULL;
+ vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
+ gboolean xfer_all = FALSE;
+
+ if ( pass_along[2] ) {
+ 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
- item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show ( item );
+ if (track && !track->visible) {
+ a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") );
+ return;
+ }
+
+ GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
+ VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ NULL );
+
+ gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+ GtkWidget *response_w = NULL;
+#if GTK_CHECK_VERSION (2, 20, 0)
+ response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+#endif
+
+ if ( response_w )
+ gtk_widget_grab_focus ( response_w );
+
+ 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 );
+ gtk_widget_destroy ( dialog );
+ return;
+ }
+
+ // Get info from reused datasource dialog widgets
+ gchar* protocol = datasource_gps_get_protocol ( dgs );
+ 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 );
+
+ gtk_widget_destroy ( dialog );
+
+ // When called from the viewport - work the corresponding layerspanel:
+ if ( !vlp ) {
+ vlp = vik_window_layers_panel ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
+ }
+
+ // Apply settings to transfer to the GPS device
+ vik_gps_comm ( vtl,
+ track,
+ GPS_UP,
+ protocol,
+ port,
+ FALSE,
+ vik_layers_panel_get_viewport (vlp),
+ vlp,
+ do_tracks,
+ do_routes,
+ do_waypoints,
+ turn_off );
+}
+
+/*
+ * Acquire into this TRW Layer from any GPS Babel supported file
+ */
+static void trw_layer_acquire_file_cb ( gpointer lav[2] )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+ VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+ VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
+ VikViewport *vvp = vik_window_viewport(vw);
+
+ a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface );
+}
+
+static void trw_layer_new_wp ( gpointer lav[2] )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+ VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+ /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
+ instead return true if you want to update. */
+ if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible )
+ vik_layers_panel_emit_update ( vlp );
+}
+
+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")) ;
+ vtl->current_track = vik_track_new();
+ vtl->current_track->visible = TRUE;
+ vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+
+ vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_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")) ;
+ vtl->current_track = vik_track_new();
+ vtl->current_track->visible = TRUE;
+ vtl->current_track->is_route = TRUE;
+ vik_trw_layer_add_route ( vtl, name, vtl->current_track );
+
+ 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), FALSE );
+}
+
+static void trw_layer_auto_tracks_view ( gpointer lav[2] )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+ VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+
+ if ( g_hash_table_size (vtl->tracks) > 0 ) {
+ struct LatLon maxmin[2] = { {0,0}, {0,0} };
+ g_hash_table_foreach ( vtl->tracks, (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_single_waypoint_jump ( const gchar *name, 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) );
+}
+
+static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
+ VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
+
+ /* Only 1 waypoint - jump straight to it */
+ if ( g_hash_table_size (vtl->waypoints) == 1 ) {
+ VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
+ }
+ /* If at least 2 waypoints - find center and then zoom to fit */
+ else if ( g_hash_table_size (vtl->waypoints) > 1 )
+ {
+ struct LatLon maxmin[2] = { {0,0}, {0,0} };
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_find_maxmin_waypoints, maxmin );
+ trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
+ }
+
+ vik_layers_panel_emit_update ( vlp );
+}
+
+static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
+{
+ static gpointer pass_along[2];
+ GtkWidget *item;
+ GtkWidget *export_submenu;
+ pass_along[0] = vtl;
+ pass_along[1] = vlp;
+
+ item = gtk_menu_item_new();
+ 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) );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+
+ 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 ( _("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 (view_submenu), item);
+ gtk_widget_show ( item );
+
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
export_submenu = gtk_menu_new ();
- item = gtk_menu_item_new_with_mnemonic ( _("_Export Layer") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Layer") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, 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), export_submenu );
gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
+ gchar* external1 = g_strconcat ( _("Open with External Program_1: "), a_vik_get_external_gpx_program_1(), NULL );
+ item = gtk_menu_item_new_with_mnemonic ( external1 );
+ g_free ( external1 );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+ gtk_widget_show ( item );
+
+ gchar* external2 = g_strconcat ( _("Open with External Program_2: "), a_vik_get_external_gpx_program_2(), NULL );
+ item = gtk_menu_item_new_with_mnemonic ( external2 );
+ g_free ( external2 );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+ gtk_widget_show ( item );
+
+ 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) );
+ gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
+ gtk_widget_show(item);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_submenu);
+
+ 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 (menu), item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), 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 (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) );
+
+ 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_GEONAMES
- wikipedia_submenu = gtk_menu_new();
- item = gtk_menu_item_new_with_mnemonic ( _("_Add Wikipedia Waypoints") );
+ 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);
- item = gtk_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
+ 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_menu_item_new_with_mnemonic ( _("Within _Current View") );
+ 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_GEOTAG
+ item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+#endif
+
+ GtkWidget *acquire_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Ac_quire") );
+ 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 );
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), acquire_submenu );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("From _GPS...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_gps_cb), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+ gtk_widget_show ( item );
+
+#ifdef VIK_CONFIG_GOOGLE
+ item = gtk_menu_item_new_with_mnemonic ( _("From G_oogle 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 );
+#endif
+
+#ifdef VIK_CONFIG_OPENSTREETMAP
+ item = gtk_menu_item_new_with_mnemonic ( _("From _OSM Traces...") );
+ 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 );
+#endif
+
+#ifdef VIK_CONFIG_GEOCACHES
+ item = gtk_menu_item_new_with_mnemonic ( _("From Geo_caching...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geocache_cb), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+ gtk_widget_show ( item );
+#endif
+
+#ifdef VIK_CONFIG_GEOTAG
+ item = gtk_menu_item_new_with_mnemonic ( _("From Geotagged _Images...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geotagged_cb), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+ gtk_widget_show ( item );
+#endif
+
+ item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+ gtk_widget_show ( item );
+
+ 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);
+ 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_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
gtk_widget_show ( item );
#endif
GtkWidget *delete_submenu = gtk_menu_new ();
- item = gtk_menu_item_new_with_mnemonic ( _("De_lete") );
+ 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) );
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show ( item );
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
- item = gtk_menu_item_new_with_mnemonic ( _("Delete All _Tracks") );
+ 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 );
gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("Delete Tracks _From Selection...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Tracks _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_tracks_from_selection), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") );
+ 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) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("Delete Waypoints From _Selection...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Waypoints 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_waypoints_from_selection), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
gtk_widget_show ( item );
}
}
+// Fake Waypoint UUIDs vi simple increasing integer
+static guint wp_uuid = 0;
+
void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
{
+ wp_uuid++;
+
+ vik_waypoint_set_name (wp, name);
+
if ( VIK_LAYER(vtl)->realized )
{
- VikWaypoint *oldwp = VIK_WAYPOINT ( g_hash_table_lookup ( vtl->waypoints, name ) );
- if ( oldwp )
- wp->visible = oldwp->visible; /* same visibility so we don't have to update viktreeview */
- else
- {
- GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
- // Visibility column always needed for waypoints
+ // 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, name, 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, name, 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 );
- g_hash_table_insert ( vtl->waypoints_iters, name, iter );
- }
+ // Actual setting of visibility dependent on the waypoint
+ vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
+
+ g_hash_table_insert ( vtl->waypoints_iters, GUINT_TO_POINTER(wp_uuid), iter );
}
highest_wp_number_add_wp(vtl, name);
- g_hash_table_insert ( vtl->waypoints, name, wp );
+ g_hash_table_insert ( vtl->waypoints, GUINT_TO_POINTER(wp_uuid), wp );
}
+// Fake Track UUIDs vi simple increasing integer
+static guint tr_uuid = 0;
+
void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
{
+ tr_uuid++;
+
+ vik_track_set_name (t, name);
+
if ( VIK_LAYER(vtl)->realized )
{
- VikTrack *oldt = VIK_TRACK ( g_hash_table_lookup ( vtl->tracks, name ) );
- if ( oldt )
- t->visible = oldt->visible; /* same visibility so we don't have to update viktreeview */
- else
- {
- GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
- // Visibility column always needed for tracks
+ // 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
- vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
+ vik_treeview_add_sublayer_alphabetized ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
#else
- vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
+ vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
#endif
- // Actual setting of visibility dependent on the track
- vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
- g_hash_table_insert ( vtl->tracks_iters, name, iter );
- }
+ // Actual setting of visibility dependent on the track
+ vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
+
+ g_hash_table_insert ( vtl->tracks_iters, GUINT_TO_POINTER(tr_uuid), iter );
}
- g_hash_table_insert ( vtl->tracks, name, t );
+ g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t );
}
+// 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 );
+
+}
+
/* to be called whenever a track has been deleted or may have been changed. */
-void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name )
+void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk )
{
- if (vtl->current_tp_track_name && g_strcasecmp(trk_name, vtl->current_tp_track_name) == 0)
+ if (vtl->current_tp_track == trk )
trw_layer_cancel_current_tp ( vtl, FALSE );
- else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0)
- trw_layer_cancel_last_tp ( vtl );
}
-
-static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
+
+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;
}
void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
{
- vik_trw_layer_add_waypoint ( vtl,
- get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name),
- wp );
+ // No more uniqueness of name forced when loading from a file
+ // This now makes this function a little redunant as we just flow the parameters through
+ vik_trw_layer_add_waypoint ( vtl, name, wp );
}
+
void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
{
- if ( vtl->magic_scissors_append && vtl->magic_scissors_current_track ) {
+ if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
- vik_track_steal_and_append_trackpoints ( vtl->magic_scissors_current_track, tr );
+ vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
vik_track_free ( tr );
- vtl->magic_scissors_append = FALSE; /* this means we have added it */
+ vtl->route_finder_append = FALSE; /* this means we have added it */
} else {
- gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name);
- vik_trw_layer_add_track ( vtl, new_name, tr );
- if ( vtl->magic_scissors_check_added_track ) {
+ // No more uniqueness of name forced when loading from a file
+ 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 */
- if ( vtl->magic_scissors_added_track_name ) /* for google routes */
- g_free ( vtl->magic_scissors_added_track_name );
- vtl->magic_scissors_added_track_name = g_strdup(new_name);
+ vtl->route_finder_added_track = tr;
}
}
}
-static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l )
+static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l )
{
- *l = g_list_append(*l, (gpointer)name);
+ *l = g_list_append(*l, id);
}
-static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type )
+/*
+ * Move an item from one TRW layer to another TRW layer
+ */
+static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
{
- gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name);
if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
- VikTrack *t;
- t = vik_track_copy(vik_trw_layer_get_track(vtl_src, name));
- vik_trw_layer_delete_track(vtl_src, name);
- vik_trw_layer_add_track(vtl_dest, newname, t);
+ VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
+
+ gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, trk->name);
+
+ VikTrack *trk2 = vik_track_copy ( trk );
+ vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
+ vik_trw_layer_delete_track ( vtl_src, trk );
}
- if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
- VikWaypoint *w;
- w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, name));
- vik_trw_layer_delete_waypoint(vtl_src, name);
- vik_trw_layer_add_waypoint(vtl_dest, newname, w);
+
+ 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 );
+ 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 );
+
+ gchar *newname = trw_layer_new_unique_sublayer_name(vtl_dest, type, wp->name);
+
+ VikWaypoint *wp2 = vik_waypoint_copy ( wp );
+ vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
+ trw_layer_delete_waypoint ( vtl_src, wp );
}
}
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;
}
}
}
-gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name )
-{
- VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name );
- gboolean was_visible = FALSE;
- if ( t )
- {
- GtkTreeIter *it;
- was_visible = t->visible;
- if ( t == vtl->current_track ) {
- vtl->current_track = NULL;
- }
- if ( t == vtl->magic_scissors_current_track )
- vtl->magic_scissors_current_track = NULL;
- /* could be current_tp, so we have to check */
- trw_layer_cancel_tps_of_track ( vtl, trk_name );
+typedef struct {
+ VikTrack *trk; // input
+ gpointer uuid; // output
+} trku_udata;
+
+static gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata )
+{
+ trku_udata *user_data = udata;
+ if ( trk == user_data->trk ) {
+ user_data->uuid = id;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean vik_trw_layer_delete_track ( 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->tracks, (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->tracks_iters, udata.uuid );
+
+ if ( it ) {
+ 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 );
- g_assert ( ( it = g_hash_table_lookup ( vtl->tracks_iters, trk_name ) ) );
- vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
- g_hash_table_remove ( vtl->tracks_iters, trk_name );
+ 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 );
- /* do this last because trk_name may be pointing to actual orig key */
- g_hash_table_remove ( vtl->tracks, trk_name );
+ // 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) );
+ }
+ }
+ }
}
return was_visible;
}
-gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name )
+static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
{
gboolean was_visible = FALSE;
- VikWaypoint *wp;
- wp = g_hash_table_lookup ( vtl->waypoints, wp_name );
- if ( wp ) {
- GtkTreeIter *it;
+ if ( wp && wp->name ) {
if ( wp == vtl->current_wp ) {
vtl->current_wp = NULL;
- vtl->current_wp_name = NULL;
+ vtl->current_wp_id = NULL;
vtl->moving_wp = FALSE;
}
was_visible = wp->visible;
- g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) wp_name ) ) );
- vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
- g_hash_table_remove ( vtl->waypoints_iters, (gchar *) wp_name );
+
+ wpu_udata udata;
+ udata.wp = wp;
+ udata.uuid = NULL;
+
+ // Hmmm, want key of it
+ gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+ if ( wpf && udata.uuid ) {
+ GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+
+ if ( it ) {
+ vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
+ g_hash_table_remove ( vtl->waypoints_iters, udata.uuid );
+
+ 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) );
+ }
+ }
+ }
- highest_wp_number_remove_wp(vtl, wp_name);
- g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */
}
return was_visible;
}
+// Only for temporary use by trw_layer_delete_waypoint_by_name
+static gboolean trw_layer_waypoint_find_uuid_by_name ( const gpointer id, const VikWaypoint *wp, gpointer udata )
+{
+ wpu_udata *user_data = udata;
+ if ( ! strcmp ( wp->name, user_data->wp->name ) ) {
+ user_data->uuid = id;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Delete a waypoint by the given name
+ * NOTE: ATM this will delete the first encountered Waypoint with the specified name
+ * as there be multiple waypoints with the same name
+ */
+static gboolean trw_layer_delete_waypoint_by_name ( VikTrwLayer *vtl, const gchar *name )
+{
+ wpu_udata udata;
+ // Fake a waypoint with the given name
+ udata.wp = vik_waypoint_new ();
+ vik_waypoint_set_name (udata.wp, name);
+ // Currently only the name is used in this waypoint find function
+ udata.uuid = NULL;
+
+ // Hmmm, want key of it
+ gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
+
+ vik_waypoint_free (udata.wp);
+
+ if ( wpf && udata.uuid )
+ return trw_layer_delete_waypoint (vtl, g_hash_table_lookup ( vtl->waypoints, udata.uuid ));
+ else
+ return FALSE;
+}
+
+typedef struct {
+ VikTrack *trk; // input
+ gpointer uuid; // output
+} tpu_udata;
+
+// Only for temporary use by trw_layer_delete_track_by_name
+static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const VikTrack *trk, gpointer udata )
+{
+ tpu_udata *user_data = udata;
+ if ( ! strcmp ( trk->name, user_data->trk->name ) ) {
+ user_data->uuid = id;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Delete a track by the given name
+ * NOTE: ATM this will delete the first encountered Track with the specified 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, GHashTable *ht_tracks )
+{
+ tpu_udata udata;
+ // Fake a track with the given name
+ udata.trk = vik_track_new ();
+ vik_track_set_name (udata.trk, name);
+ // Currently only the name is used in this waypoint find function
+ udata.uuid = NULL;
+
+ // Hmmm, want key of it
+ 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 ) {
+ // 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)
{
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), FALSE );
+}
+
void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
{
vtl->current_track = NULL;
- vtl->magic_scissors_current_track = NULL;
- if (vtl->current_tp_track_name)
+ vtl->route_finder_current_track = NULL;
+ vtl->route_finder_added_track = NULL;
+ if (vtl->current_tp_track)
trw_layer_cancel_current_tp(vtl, FALSE);
- if (vtl->last_tp_track_name)
- trw_layer_cancel_last_tp ( vtl );
g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
g_hash_table_remove_all(vtl->tracks_iters);
g_hash_table_remove_all(vtl->tracks);
- /* TODO: only update if the layer is visible (ticked) */
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
+
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
}
void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
{
vtl->current_wp = NULL;
- vtl->current_wp_name = NULL;
+ vtl->current_wp_id = NULL;
vtl->moving_wp = FALSE;
highest_wp_number_reset(vtl);
g_hash_table_remove_all(vtl->waypoints_iters);
g_hash_table_remove_all(vtl->waypoints);
- /* TODO: only update if the layer is visible (ticked) */
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
+
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
}
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]);
gboolean was_visible = FALSE;
if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
{
- if ( GPOINTER_TO_INT ( pass_along[4]) )
- // Get confirmation from the user
- // Maybe this Waypoint Delete should be optional as is it could get annoying...
- if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
- _("Are you sure you want to delete the waypoint \"%s\""),
- pass_along[3] ) )
- return;
- was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] );
+ VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
+ if ( wp && wp->name ) {
+ if ( GPOINTER_TO_INT ( pass_along[4]) )
+ // Get confirmation from the user
+ // Maybe this Waypoint Delete should be optional as is it could get annoying...
+ if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Are you sure you want to delete the waypoint \"%s\""),
+ wp->name ) )
+ return;
+ was_visible = trw_layer_delete_waypoint ( vtl, wp );
+ }
}
- else
+ else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
{
- if ( GPOINTER_TO_INT ( pass_along[4]) )
- // Get confirmation from the user
- if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ VikTrack *trk = g_hash_table_lookup ( vtl->tracks, 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 track \"%s\""),
- pass_along[3] ) )
- return;
- was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] );
+ trk->name ) )
+ return;
+ 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) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
}
-static void trw_layer_properties_item ( gpointer pass_along[6] )
+static void trw_layer_properties_item ( gpointer pass_along[7] )
{
VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
{
- VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
- if ( wp )
+ VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); // sublayer
+
+ if ( wp && wp->name )
{
gboolean updated = FALSE;
- a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), pass_along[3], wp, NULL, vtl->coord_mode, FALSE, &updated );
+ a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, wp, vtl->coord_mode, FALSE, &updated );
+
+ if ( updated && pass_along[6] )
+ vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) );
if ( updated && VIK_LAYER(vtl)->visible )
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
}
}
else
{
- VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
- if ( tr )
+ 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,
pass_along[1], /* vlp */
- pass_along[3], /* track name */
pass_along[5] ); /* vvp */
}
}
/* 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) );
+ vik_layer_emit_update ( VIK_LAYER(vl), FALSE );
}
}
}
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] )
{
- /* FIXME: get this into viktrack.c, and should be ->trackpoints right? */
- GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
- if ( trps && *trps )
+ 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} };
VikCoord coord;
- trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
+ 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 );
+
+ // 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]), FALSE );
+}
+
+
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
/**
- * extend a track using magic scissors
+ * extend a track using route finder
*/
-static void trw_layer_extend_track_end_ms ( gpointer pass_along[6] )
+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] );
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 );
- vtl->magic_scissors_coord = last_coord;
- vtl->magic_scissors_current_track = track;
- vtl->magic_scissors_started = TRUE;
+ vtl->route_finder_coord = last_coord;
+ vtl->route_finder_current_track = track;
+ vtl->route_finder_started = TRUE;
if ( track->trackpoints )
goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
}
+#endif
static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
{
/* 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);
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));
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));
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));
}
-/*
+/*
* Automatically change the viewport to center on the track and zoom to see the extent of the track
- */
-static void trw_layer_auto_track_view ( gpointer pass_along[5] )
+ */
+static void trw_layer_auto_track_view ( gpointer pass_along[6] )
{
- GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
- if ( trps && *trps )
+ 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} };
- trw_layer_find_maxmin_tracks ( NULL, trps, maxmin );
+ trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
trw_layer_zoom_to_show_latlons ( VIK_TRW_LAYER(pass_along[0]), pass_along[5], maxmin );
if ( pass_along[1] )
vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
else
- vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
+ vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE );
}
}
*************************************/
/* called for each key in track hash table.
- * If the current track has time stamp, add it to the result,
+ * If the current track has the same time stamp type, add it to the result,
* except the one pointed by "exclude".
* set exclude to NULL if there is no exclude to check.
- * Not that result is in reverse (for performance reason).
+ * Note that the result is in reverse (for performance reasons).
*/
typedef struct {
GList **result;
GList *exclude;
+ gboolean with_timestamps;
} twt_udata;
-static void find_tracks_with_timestamp(gpointer key, gpointer value, gpointer udata)
+static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata)
{
twt_udata *user_data = udata;
VikTrackpoint *p1, *p2;
p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
- if (!p1->has_timestamp || !p2->has_timestamp) {
- g_print("no timestamp\n");
- return;
+ if ( user_data->with_timestamps ) {
+ if (!p1->has_timestamp || !p2->has_timestamp) {
+ return;
+ }
+ }
+ else {
+ // Don't add tracks with timestamps when getting non timestamp tracks
+ if (p1->has_timestamp || p2->has_timestamp) {
+ return;
+ }
}
-
}
*(user_data->result) = g_list_prepend(*(user_data->result), key);
/* called for each key in track hash table. if original track user_data[1] is close enough
* to the passed one, add it to list in user_data[0]
*/
-static void find_nearby_track(gpointer key, gpointer value, gpointer user_data)
+static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
{
time_t t1, t2;
VikTrackpoint *p1, *p2;
+ VikTrack *trk = VIK_TRACK(value);
GList **nearby_tracks = ((gpointer *)user_data)[0];
- GList *orig_track = ((gpointer *)user_data)[1];
- guint thr = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
+ GList *tpoints = ((gpointer *)user_data)[1];
/* outline:
* detect reasons for not merging, and return
* if no reason is found not to merge, then do it.
*/
- if (VIK_TRACK(value)->trackpoints == orig_track) {
+ // Exclude the original track from the compiled list
+ if (trk->trackpoints == tpoints) {
return;
}
- t1 = VIK_TRACKPOINT(orig_track->data)->timestamp;
- t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp;
+ t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp;
+ t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp;
- if (VIK_TRACK(value)->trackpoints) {
- p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
- p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
+ if (trk->trackpoints) {
+ p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data);
+ p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data);
if (!p1->has_timestamp || !p2->has_timestamp) {
- g_print("no timestamp\n");
+ //g_print("no timestamp\n");
return;
}
- /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */
- if (! (abs(t1 - p2->timestamp) < thr*60 ||
+ guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
+ //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
+ if (! (abs(t1 - p2->timestamp) < threshold ||
/* p1 p2 t1 t2 */
- abs(p1->timestamp - t2) < thr*60)
+ abs(p1->timestamp - t2) < threshold)
/* t1 t2 p1 p2 */
) {
return;
}
}
- *nearby_tracks = g_list_prepend(*nearby_tracks, key);
+ *nearby_tracks = g_list_prepend(*nearby_tracks, value);
}
/* comparison function used to sort tracks; a and b are hash table keys */
return 0;
}
-#ifdef VIK_CONFIG_ALPHABETIZED_TRW
/**
* comparison function which can be used to sort tracks or waypoints by name
*/
// Same sort method as used in the vik_treeview_*_alphabetize functions
return strcmp ( namea, nameb );
}
-#endif
+/**
+ * Attempt to merge selected track with other tracks specified by the user
+ * Tracks to merge with must be of the same 'type' as the selected track -
+ * either all with timestamps, or all without timestamps
+ */
static void trw_layer_merge_with_other ( gpointer pass_along[6] )
{
VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
- gchar *orig_track_name = pass_along[3];
- GList *tracks_with_timestamp = NULL;
- VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
+ GList *other_tracks = NULL;
+ GHashTable *ght_tracks;
+ if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+ ght_tracks = vtl->routes;
+ else
+ ght_tracks = vtl->tracks;
- if (track->trackpoints &&
- !VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp) {
- a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
+ VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
+
+ if ( !track )
+ return;
+
+ if ( !track->trackpoints )
+ return;
+
+ twt_udata udata;
+ udata.result = &other_tracks;
+ udata.exclude = track->trackpoints;
+ // Allow merging with 'similar' time type time tracks
+ // i.e. either those times, or those without
+ udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp);
+
+ g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
+ other_tracks = g_list_reverse(other_tracks);
+
+ if ( !other_tracks ) {
+ if ( udata.with_timestamps )
+ a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks with timestamps in this layer found"));
+ else
+ a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks without timestamps in this layer found"));
return;
}
- if (1) {
+ // 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...
+ 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 (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..."),
+ track->is_route ? _("Select route to merge with") : _("Select track to merge with"));
+ g_list_free(other_tracks);
+ g_list_free(other_tracks_names);
+
+ if (merge_list)
+ {
+ GList *l;
+ for (l = merge_list; l != NULL; l = g_list_next(l)) {
+ 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;
+ 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);
+ }
+ }
+ /* TODO: free data before free merge_list */
+ for (l = merge_list; l != NULL; l = g_list_next(l))
+ g_free(l->data);
+ g_list_free(merge_list);
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+ }
+}
+
+// c.f. trw_layer_sorted_track_id_by_name_list
+// but don't add the specified track to the list (normally current track)
+static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer id, const VikTrack *trk, gpointer udata)
+{
+ twt_udata *user_data = udata;
- twt_udata udata;
- udata.result = &tracks_with_timestamp;
- udata.exclude = track->trackpoints;
- g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp, (gpointer)&udata);
- tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
+ // Skip self
+ if (trk->trackpoints == user_data->exclude) {
+ return;
}
- if (!tracks_with_timestamp) {
- a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
+ // Sort named list alphabetically
+ *(user_data->result) = g_list_insert_sorted_with_data (*(user_data->result), trk->name, sort_alphabetically, NULL);
+}
+
+/**
+ * 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
+ */
+static void trw_layer_append_track ( gpointer pass_along[6] )
+{
+
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ 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;
+
+ // 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_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,
+ 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);
+
+ // 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...
+ 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;
+ 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 );
}
+}
+
+/**
+ * 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;
-#ifdef VIK_CONFIG_ALPHABETIZED_TRW
// Sort alphabetically for user presentation
- tracks_with_timestamp = g_list_sort_with_data (tracks_with_timestamp, sort_alphabetically, NULL);
-#endif
+ // 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 );
- GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
- tracks_with_timestamp, TRUE,
- _("Merge with..."), _("Select track to merge with"));
- g_list_free(tracks_with_timestamp);
+ 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;
+ }
+ }
- if (merge_list)
- {
- GList *l;
- for (l = merge_list; l != NULL; l = g_list_next(l)) {
- VikTrack *merge_track = (VikTrack *) g_hash_table_lookup (vtl->tracks, 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, l->data);
- track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
+ 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);
}
}
- /* TODO: free data before free merge_list */
- for (l = merge_list; l != NULL; l = g_list_next(l))
+ for (l = append_list; l != NULL; l = g_list_next(l))
g_free(l->data);
- g_list_free(merge_list);
- vik_layer_emit_update( VIK_LAYER(vtl) );
+ g_list_free(append_list);
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
}
}
+/* merge by segments */
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+ guint segments = vik_track_merge_segments ( trk );
+ // NB currently no need to redraw as segments not actually shown on the display
+ // However inform the user of what happened:
+ gchar str[64];
+ const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
+ g_snprintf(str, 64, tmp_str, segments);
+ a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
+}
+
/* merge by time routine */
static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
{
VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
- gchar *orig_track_name = strdup(pass_along[3]);
//time_t t1, t2;
- GList *nearby_tracks;
- VikTrack *track;
- GList *trps;
- static guint thr = 1;
- guint track_count = 0;
- if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
- _("Merge Threshold..."),
- _("Merge when time between tracks less than:"),
- &thr)) {
- free(orig_track_name);
+ GList *tracks_with_timestamp = NULL;
+ VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+ if (orig_trk->trackpoints &&
+ !VIK_TRACKPOINT(orig_trk->trackpoints->data)->has_timestamp) {
+ a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
return;
}
- /* merge tracks until we can't */
- nearby_tracks = NULL;
- do {
- gpointer params[3];
+ twt_udata udata;
+ udata.result = &tracks_with_timestamp;
+ udata.exclude = orig_trk->trackpoints;
+ udata.with_timestamps = TRUE;
+ g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
+ tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
+
+ if (!tracks_with_timestamp) {
+ a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
+ return;
+ }
+ g_list_free(tracks_with_timestamp);
+
+ static guint threshold_in_minutes = 1;
+ if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Merge Threshold..."),
+ _("Merge when time between tracks less than:"),
+ &threshold_in_minutes)) {
+ return;
+ }
- track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name );
- trps = track->trackpoints;
+ // keep attempting to merge all tracks until no merges within the time specified is possible
+ gboolean attempt_merge = TRUE;
+ GList *nearby_tracks = NULL;
+ GList *trps;
+ static gpointer params[3];
+
+ while ( attempt_merge ) {
+
+ // Don't try again unless tracks have changed
+ attempt_merge = FALSE;
+
+ trps = orig_trk->trackpoints;
if ( !trps )
return;
-
if (nearby_tracks) {
g_list_free(nearby_tracks);
nearby_tracks = NULL;
/* g_print("Original track times: %d and %d\n", t1, t2); */
params[0] = &nearby_tracks;
- params[1] = trps;
- params[2] = GUINT_TO_POINTER (thr);
+ params[1] = (gpointer)trps;
+ params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
/* get a list of adjacent-in-time tracks */
- g_hash_table_foreach(vtl->tracks, find_nearby_track, (gpointer)params);
-
- /* add original track */
- nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name);
+ g_hash_table_foreach(vtl->tracks, find_nearby_tracks_by_time, params);
/* merge them */
- {
-#define get_track(x) VIK_TRACK(g_hash_table_lookup(vtl->tracks, (gchar *)((x)->data)))
-#define get_first_trackpoint(x) VIK_TRACKPOINT(get_track(x)->trackpoints->data)
-#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(get_track(x)->trackpoints)->data)
- GList *l = nearby_tracks;
- VikTrack *tr = vik_track_new();
- tr->visible = track->visible;
- track_count = 0;
- while (l) {
- /*
- time_t t1, t2;
- t1 = get_first_trackpoint(l)->timestamp;
- t2 = get_last_trackpoint(l)->timestamp;
- g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2);
- */
-
+ GList *l = nearby_tracks;
+ while ( l ) {
+ /*
+#define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data)
+#define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data)
+ time_t t1, t2;
+ t1 = get_first_trackpoint(l)->timestamp;
+ t2 = get_last_trackpoint(l)->timestamp;
+#undef get_first_trackpoint
+#undef get_last_trackpoint
+ g_print(" %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2);
+ */
- /* remove trackpoints from merged track, delete track */
- tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints);
- get_track(l)->trackpoints = NULL;
- vik_trw_layer_delete_track(vtl, l->data);
+ /* remove trackpoints from merged track, delete track */
+ orig_trk->trackpoints = g_list_concat(orig_trk->trackpoints, VIK_TRACK(l->data)->trackpoints);
+ VIK_TRACK(l->data)->trackpoints = NULL;
+ vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
- track_count ++;
- l = g_list_next(l);
- }
- tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare);
- vik_trw_layer_add_track(vtl, strdup(orig_track_name), tr);
+ // Tracks have changed, therefore retry again against all the remaining tracks
+ attempt_merge = TRUE;
-#undef get_first_trackpoint
-#undef get_last_trackpoint
-#undef get_track
+ l = g_list_next(l);
}
- } while (track_count > 1);
+
+ orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
+ }
+
g_list_free(nearby_tracks);
- free(orig_track_name);
- vik_layer_emit_update( VIK_LAYER(vtl) );
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+}
+
+/**
+ * Split a track at the currently selected trackpoint
+ */
+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, subtype, vtl->current_tp_track->name);
+ if ( name ) {
+ VikTrack *tr = vik_track_new ();
+ GList *newglist = g_list_alloc ();
+ newglist->prev = NULL;
+ newglist->next = vtl->current_tpl->next;
+ newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
+ tr->trackpoints = newglist;
+ tr->is_route = vtl->current_tp_track->is_route;
+ tr->visible = TRUE;
+
+ vtl->current_tpl->next->prev = newglist; /* end old track here */
+ vtl->current_tpl->next = NULL;
+
+ vtl->current_tpl = newglist; /* change tp to first of new track. */
+ vtl->current_tp_track = 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;
+ 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);
+ }
+ }
}
/* split by time routine */
static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
{
- 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 = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
GList *trps = track->trackpoints;
GList *iter;
GList *newlists = NULL;
GList *newtps = NULL;
- guint i;
static guint thr = 1;
time_t ts, prev_ts;
/* put lists of trackpoints into tracks */
iter = newlists;
- i = 1;
// Only bother updating if the split results in new tracks
if (g_list_length (newlists) > 1) {
while (iter) {
tr->visible = track->visible;
tr->trackpoints = (GList *)(iter->data);
- new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
- vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr);
+ new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
+ vik_trw_layer_add_track(vtl, new_tr_name, tr);
/* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
iter = g_list_next(iter);
}
- vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
- vik_layer_emit_update(VIK_LAYER(pass_along[0]));
+ // 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);
}
g_list_free(newlists);
}
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;
/* put lists of trackpoints into tracks */
iter = newlists;
- guint i = 1;
// Only bother updating if the split results in new tracks
if (g_list_length (newlists) > 1) {
while (iter) {
tr = vik_track_new();
tr->visible = track->visible;
+ tr->is_route = track->is_route;
tr->trackpoints = (GList *)(iter->data);
- new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++);
- vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), 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(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]);
- vik_layer_emit_update(VIK_LAYER(pass_along[0]));
+ 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]), FALSE);
}
g_list_free(newlists);
}
+/**
+ * Split a track at the currently selected trackpoint
+ */
+static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ 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 = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+ if ( !trk )
+ return;
+
+ guint ntracks;
+
+ VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
+ gchar *new_tr_name;
+ guint i;
+ for ( i = 0; i < ntracks; i++ ) {
+ if ( tracks[i] ) {
+ new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, trk->name);
+ vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
+ }
+ }
+ if ( tracks ) {
+ g_free ( tracks );
+ // Remove original track
+ vik_trw_layer_delete_track ( vtl, trk );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
+ }
+ else {
+ a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments"));
+ }
+}
/* end of split/merge routines */
+/**
+ * Delete adjacent track points at the same position
+ * AKA Delete Dulplicates on the Properties Window
+ */
+static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
+{
+ 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;
+
+ gulong removed = vik_track_remove_dup_points ( trk );
+
+ // Track has been updated so update tps:
+ trw_layer_cancel_tps_of_track ( vtl, trk );
+
+ // Inform user how much was deleted as it's not obvious from the normal view
+ gchar str[64];
+ const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
+ 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 );
+}
+
+/**
+ * Delete adjacent track points with the same timestamp
+ * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
+ */
+static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
+{
+ 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;
+
+ gulong removed = vik_track_remove_same_time_points ( trk );
+
+ // Track has been updated so update tps:
+ trw_layer_cancel_tps_of_track ( vtl, trk );
+
+ // Inform user how much was deleted as it's not obvious from the normal view
+ gchar str[64];
+ const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
+ 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 );
+}
+
+/**
+ * Reverse a track
+ */
+static void trw_layer_reverse ( gpointer pass_along[6] )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+ VikTrack *track;
+ if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+ track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
+ else
+ track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+
+ if ( ! track )
+ return;
+
+ // Check valid track
+ GList *trps = track->trackpoints;
+ if ( !trps )
+ return;
+
+ vik_track_reverse ( track );
+
+ vik_layer_emit_update ( VIK_LAYER(pass_along[0]), FALSE );
+}
+
/**
* Similar to trw_layer_enum_item, but this uses a sorted method
*/
+/* Currently unused
static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata)
{
GList **list = (GList**)udata;
- //*list = g_list_prepend(*all, key); //unsorted method
+ // *list = g_list_prepend(*all, key); //unsorted method
// Sort named list alphabetically
*list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL);
}
+*/
+
+/**
+ * Now Waypoint specific sort
+ */
+static void trw_layer_sorted_wp_id_by_name_list (const gpointer id, const VikWaypoint *wp, gpointer udata)
+{
+ GList **list = (GList**)udata;
+ // Sort named list alphabetically
+ *list = g_list_insert_sorted_with_data (*list, wp->name, sort_alphabetically, NULL);
+}
+
+/**
+ * Track specific sort
+ */
+static void trw_layer_sorted_track_id_by_name_list (const gpointer id, const VikTrack *trk, gpointer udata)
+{
+ GList **list = (GList**)udata;
+ // Sort named list alphabetically
+ *list = g_list_insert_sorted_with_data (*list, trk->name, sort_alphabetically, NULL);
+}
+
+
+typedef struct {
+ gboolean has_same_track_name;
+ const gchar *same_track_name;
+} same_track_name_udata;
+
+static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
+{
+ const gchar* namea = (const gchar*) aa;
+ const gchar* nameb = (const gchar*) bb;
+
+ // the test
+ gint result = strcmp ( namea, nameb );
+
+ if ( result == 0 ) {
+ // Found two names the same
+ same_track_name_udata *user_data = udata;
+ user_data->has_same_track_name = TRUE;
+ user_data->same_track_name = namea;
+ }
+
+ // Leave ordering the same
+ return 0;
+}
+
+/**
+ * Find out if any tracks have the same name in this hash table
+ */
+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 ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+
+ // No tracks
+ if ( ! track_names )
+ return FALSE;
+
+ same_track_name_udata udata;
+ udata.has_same_track_name = FALSE;
+
+ // Use sort routine to traverse list comparing items
+ // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
+ GList *dummy_list = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
+ // Still no tracks...
+ if ( ! dummy_list )
+ return FALSE;
+
+ return udata.has_same_track_name;
+}
+
+/**
+ * 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, GHashTable *track_table, gboolean ontrack )
+{
+ // . Search list for an instance of repeated name
+ // . get track of this name
+ // . create new name
+ // . rename track & update equiv. treeview iter
+ // . repeat until all different
+
+ same_track_name_udata udata;
+
+ GList *track_names = NULL;
+ udata.has_same_track_name = FALSE;
+ udata.same_track_name = NULL;
+
+ g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
+
+ // No tracks
+ if ( ! track_names )
+ return;
+
+ GList *dummy_list1 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
+
+ // Still no tracks...
+ if ( ! dummy_list1 )
+ return;
+
+ while ( udata.has_same_track_name ) {
+
+ // Find a track with the same 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 :(
+ g_critical("Houston, we've had a problem.");
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO,
+ _("Internal Error in vik_trw_layer_uniquify_tracks") );
+ return;
+ }
+
+ // Rename it
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, udata.same_track_name );
+ vik_track_set_name ( trk, newname );
+
+ trku_udata udataU;
+ udataU.trk = trk;
+ udataU.uuid = NULL;
+
+ // Need want key of it for treeview update
+ gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+
+ if ( trkf && 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 );
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+ vik_treeview_sublayer_realphabetize ( VIK_LAYER(vtl)->vt, it, newname );
+#endif
+ }
+ }
+
+ // Start trying to find same names again...
+ track_names = NULL;
+ 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 );
+
+ // No tracks any more - give up searching
+ if ( ! dummy_list2 )
+ udata.has_same_track_name = FALSE;
+ }
+
+ // Update
+ vik_layers_panel_emit_update ( vlp );
+}
+
+/**
+ *
+ */
+static void trw_layer_delete_tracks_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->tracks ) ) {
+ if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
+ vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE );
+ }
+ else
+ return;
+ }
+
+ // Sort list alphabetically for better presentation
+ g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
+
+ if ( ! all ) {
+ a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No tracks 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 tracks to delete"));
+ g_list_free(all);
+
+ // Delete requested tracks
+ // 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 trk it finds of that name (but uniqueness is enforced above)
+ trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
+ }
+ g_list_free(delete_list);
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+ }
+}
/**
*
*/
-static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
+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->tracks, trw_layer_sorted_name_list, &all);
+ 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 tracks found"));
+ 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 tracks to delete"));
+ 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 tracks
+ // 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)) {
- vik_trw_layer_delete_track(vtl, l->data);
+ // 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) );
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
+ }
+}
+
+typedef struct {
+ gboolean has_same_waypoint_name;
+ const gchar *same_waypoint_name;
+} same_waypoint_name_udata;
+
+static gint check_waypoints_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
+{
+ const gchar* namea = (const gchar*) aa;
+ const gchar* nameb = (const gchar*) bb;
+
+ // the test
+ gint result = strcmp ( namea, nameb );
+
+ if ( result == 0 ) {
+ // Found two names the same
+ same_waypoint_name_udata *user_data = udata;
+ user_data->has_same_waypoint_name = TRUE;
+ user_data->same_waypoint_name = namea;
+ }
+
+ // Leave ordering the same
+ return 0;
+}
+
+/**
+ * Find out if any waypoints have the same name in this layer
+ */
+gboolean trw_layer_has_same_waypoint_names ( VikTrwLayer *vtl )
+{
+ // Sort items by name, then compare if any next to each other are the same
+
+ GList *waypoint_names = NULL;
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+
+ // No waypoints
+ if ( ! waypoint_names )
+ return FALSE;
+
+ same_waypoint_name_udata udata;
+ udata.has_same_waypoint_name = FALSE;
+
+ // Use sort routine to traverse list comparing items
+ // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
+ GList *dummy_list = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+ // Still no waypoints...
+ if ( ! dummy_list )
+ return FALSE;
+
+ return udata.has_same_waypoint_name;
+}
+
+/**
+ * Force unqiue waypoint names for this layer
+ * Note the panel is a required parameter to enable the update of the names displayed
+ */
+static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+ // . Search list for an instance of repeated name
+ // . get waypoint of this name
+ // . create new name
+ // . rename waypoint & update equiv. treeview iter
+ // . repeat until all different
+
+ same_waypoint_name_udata udata;
+
+ GList *waypoint_names = NULL;
+ udata.has_same_waypoint_name = FALSE;
+ udata.same_waypoint_name = NULL;
+
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+
+ // No waypoints
+ if ( ! waypoint_names )
+ return;
+
+ GList *dummy_list1 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+
+ // Still no waypoints...
+ if ( ! dummy_list1 )
+ return;
+
+ while ( udata.has_same_waypoint_name ) {
+
+ // Find a waypoint with the same name
+ VikWaypoint *waypoint = vik_trw_layer_get_waypoint ( vtl, (gpointer) udata.same_waypoint_name );
+
+ if ( ! waypoint ) {
+ // Broken :(
+ g_critical("Houston, we've had a problem.");
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO,
+ _("Internal Error in vik_trw_layer_uniquify_waypoints") );
+ return;
+ }
+
+ // Rename it
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, udata.same_waypoint_name );
+ vik_waypoint_set_name ( waypoint, newname );
+
+ wpu_udata udataU;
+ udataU.wp = waypoint;
+ udataU.uuid = NULL;
+
+ // Need want key of it for treeview update
+ gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+
+ if ( wpf && udataU.uuid ) {
+
+ GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
+
+ if ( it ) {
+ vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
+#ifdef VIK_CONFIG_ALPHABETIZED_TRW
+ vik_treeview_sublayer_realphabetize ( VIK_LAYER(vtl)->vt, it, newname );
+#endif
+ }
+ }
+
+ // Start trying to find same names again...
+ waypoint_names = NULL;
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
+ udata.has_same_waypoint_name = FALSE;
+ GList *dummy_list2 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
+
+ // No waypoints any more - give up searching
+ if ( ! dummy_list2 )
+ udata.has_same_waypoint_name = FALSE;
}
+
+ // Update
+ vik_layers_panel_emit_update ( vlp );
}
/**
VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
GList *all = NULL;
+ // Ensure list of waypoint names offered is unique
+ if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
+ if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
+ vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) );
+ }
+ else
+ return;
+ }
+
// Sort list alphabetically for better presentation
- g_hash_table_foreach ( vtl->waypoints, trw_layer_sorted_name_list, &all);
+ g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all);
if ( ! all ) {
a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found"));
return;
if ( delete_list ) {
GList *l;
for (l = delete_list; l != NULL; l = g_list_next(l)) {
- vik_trw_layer_delete_waypoint(vtl, l->data);
+ // This deletes first waypoint it finds of that name (but uniqueness is enforced above)
+ trw_layer_delete_waypoint_by_name (vtl, l->data);
}
g_list_free(delete_list);
- vik_layer_emit_update( VIK_LAYER(vtl) );
+ vik_layer_emit_update( VIK_LAYER(vtl), FALSE );
}
}
g_free ( webpage );
}
-const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
+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 )
{
- gchar *rv;
- VikWaypoint *wp;
+ VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
- if (strcmp(newname, sublayer) == 0 )
+ // No actual change to the name supplied
+ if (strcmp(newname, wp->name) == 0 )
return NULL;
- if (strcasecmp(newname, sublayer)) { /* Not just changing case */
- if (g_hash_table_lookup( l->waypoints, newname))
- {
- a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Waypoint Already Exists") );
+ VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname );
+
+ 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 rename to the same name?"),
+ newname ) )
return NULL;
- }
}
- iter = g_hash_table_lookup ( l->waypoints_iters, sublayer );
- g_hash_table_steal ( l->waypoints_iters, sublayer );
+ // Update WP name and refresh the treeview
+ vik_waypoint_set_name (wp, newname);
- wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) );
- highest_wp_number_remove_wp(l, sublayer);
- g_hash_table_remove ( l->waypoints, sublayer );
-
- rv = g_strdup(newname);
-
- vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
-
- highest_wp_number_add_wp(l, rv);
- g_hash_table_insert ( l->waypoints, rv, wp );
- g_hash_table_insert ( l->waypoints_iters, rv, iter );
-
- /* it hasn't been updated yet so we pass new name */
#ifdef VIK_CONFIG_ALPHABETIZED_TRW
- vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, rv );
+ vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname );
#endif
vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
- return rv;
+
+ return newname;
}
+
if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
{
- gchar *rv;
- VikTrack *tr;
- GtkTreeIter *iter;
- gchar *orig_key;
+ VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
- if (strcmp(newname, sublayer) == 0)
+ // No actual change to the name supplied
+ if (strcmp(newname, trk->name) == 0)
return NULL;
- if (strcasecmp(newname, sublayer)) { /* Not just changing case */
- if (g_hash_table_lookup( l->tracks, newname))
- {
- a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Track Already Exists") );
+ VikTrack *trkf = vik_trw_layer_get_track ( 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 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
- g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr );
- g_hash_table_steal ( l->tracks, sublayer );
+ vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
- iter = g_hash_table_lookup ( l->tracks_iters, sublayer );
- g_hash_table_steal ( l->tracks_iters, sublayer );
+ return newname;
+ }
- rv = g_strdup(newname);
+ if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+ {
+ VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer );
- vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv );
+ // No actual change to the name supplied
+ if (strcmp(newname, trk->name) == 0)
+ return NULL;
- g_hash_table_insert ( l->tracks, rv, tr );
- g_hash_table_insert ( l->tracks_iters, rv, iter );
+ VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname );
- /* don't forget about current_tp_track_name, update that too */
- if ( l->current_tp_track_name && g_strcasecmp(orig_key,l->current_tp_track_name) == 0 )
- {
- l->current_tp_track_name = rv;
- if ( l->tpwin )
- vik_trw_layer_tpwin_set_track_name ( l->tpwin, rv );
+ 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;
}
- else if ( l->last_tp_track_name && g_strcasecmp(orig_key,l->last_tp_track_name) == 0 )
- l->last_tp_track_name = rv;
+ // Update track name and refresh GUI parts
+ vik_track_set_name (trk, newname);
- g_free ( orig_key );
+ // 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, rv );
+ vik_treeview_sublayer_realphabetize ( VIK_LAYER(l)->vt, iter, newname );
#endif
vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
- return rv;
+
+ return newname;
}
return NULL;
}
static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
{
- gchar *track_name = (gchar *) pass_along[3];
- VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
- a_acquire_set_filter_track ( tr, track_name );
+ VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+ a_acquire_set_filter_track ( trk );
}
-static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name )
+#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_name );
+ VikTrack *tr = g_hash_table_lookup ( vtl->tracks, 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] )
{
- gchar *track_name = (gchar *) pass_along[3];
- VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, track_name );
+ VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, 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 );
g_free ( webpage );
}
}
+#endif
/* vlp can be NULL if necessary - i.e. right-click from a tool */
/* viewpoint is now available instead */
-gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
+static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
{
- static gpointer pass_along[6];
+ static gpointer pass_along[8];
GtkWidget *item;
gboolean rv = FALSE;
pass_along[3] = sublayer;
pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
pass_along[5] = vvp;
+ pass_along[6] = iter;
+ pass_along[7] = NULL; // For misc purposes - maybe track or waypoint
- 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;
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 );
}
separator_created = TRUE;
- item = gtk_menu_item_new_with_mnemonic ( _("_Goto") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
}
- if ( is_valid_geocache_name ( (gchar *) sublayer ) )
- {
- if ( !separator_created ) {
- item = gtk_menu_item_new ();
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
- gtk_widget_show ( item );
- separator_created = TRUE;
- }
+ VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
- item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
- gtk_widget_show ( item );
- }
+ if ( wp && wp->name ) {
+ if ( is_valid_geocache_name ( wp->name ) ) {
- VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
+ if ( !separator_created ) {
+ item = gtk_menu_item_new ();
+ gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_widget_show ( item );
+ separator_created = TRUE;
+ }
+
+ item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_widget_show ( item );
+ }
+ }
if ( wp && wp->image )
{
// Set up image paramater
pass_along[5] = wp->image;
- item = gtk_menu_item_new_with_mnemonic ( _("_Show Picture...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
+
+#ifdef VIK_CONFIG_GEOTAG
+ GtkWidget *geotag_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Update Geotag on _Image") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), geotag_submenu );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("_Update") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_update), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
+ gtk_widget_show ( item );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Update and _Keep File Timestamp") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_keep), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
+ gtk_widget_show ( item );
+#endif
}
}
}
+ 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) )
{
rv = TRUE;
- item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
+ 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 (menu), item);
gtk_widget_show ( item );
if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS )
{
- item = gtk_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
+ 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_waypoints_view), pass_along );
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") );
+ 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) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_Delete Waypoints From Selection...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Waypoints 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_waypoints_from_selection), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
{
rv = TRUE;
- item = gtk_menu_item_new_with_mnemonic ( _("_View All Tracks") );
+ 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_menu_item_new_with_mnemonic ( _("Delete _All Tracks") );
+ 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 );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_Delete Tracks From Selection...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Tracks 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_tracks_from_selection), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
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 )
{
- GtkWidget *goto_submenu;
item = gtk_menu_item_new ();
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
+ 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 );
+ gtk_widget_show ( item );
+
+ GtkWidget *goto_submenu;
goto_submenu = gtk_menu_new ();
- item = gtk_menu_item_new_with_mnemonic ( _("_Goto") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show ( item );
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), goto_submenu );
- item = gtk_menu_item_new_with_mnemonic ( _("_Startpoint") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Startpoint") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("\"_Center\"") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("\"_Center\"") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_Endpoint") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Endpoint") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
- 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 );
+ }
- item = gtk_menu_item_new_with_mnemonic ( _("_View Track") );
- 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 );
+ GtkWidget *combine_submenu;
+ combine_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Co_mbine") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONNECT, 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), 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(menu), 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(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
gtk_widget_show ( item );
- 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(menu), item );
+ 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 );
+
+ 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 );
+
+ GtkWidget *split_submenu;
+ split_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Split") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, 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), split_submenu );
+
+ // 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 );
+
+ 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 );
+ gtk_widget_show ( item );
+ // Make it available only when a trackpoint is selected.
+ gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
+
+ GtkWidget *delete_submenu;
+ delete_submenu = gtk_menu_new ();
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, 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), delete_submenu );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+ gtk_widget_show ( item );
+
+ item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Time") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_time), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
+ gtk_widget_show ( item );
+
+ 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 );
gtk_widget_show ( item );
/* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
if ( vlp ) {
- item = gtk_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 );
gtk_widget_show ( item );
}
- item = gtk_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("DEM Download/Import", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
- item = gtk_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_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 );
- item = gtk_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_ms), 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
+ 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
+
+ // 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 );
+ }
+ }
+ // Some things aren't usable with routes
+ if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
#ifdef VIK_CONFIG_OPENSTREETMAP
- item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
+ // Convert internal pointer into actual track for usage outside this file
+ pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer);
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
gtk_widget_show ( item );
#endif
- if ( is_valid_google_route ( l, (gchar *) sublayer ) )
+ 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 ( is_valid_google_route ( l, sublayer ) )
{
- item = gtk_menu_item_new_with_mnemonic ( _("_View Google Directions") );
+ 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 );
}
+#endif
- item = gtk_menu_item_new_with_mnemonic ( _("Use with _Filter") );
+ 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 );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
/* ATM This function is only available via the layers panel, due to 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 );
+#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
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
}
-
}
return rv;
/* 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_track_name );
- 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 );
}
}
}
-/* to be called when last_tpl no long exists. */
-static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl )
-{
- if ( vtl->tpwin ) /* can't join with a non-existant TP. */
- vik_trw_layer_tpwin_disable_join ( vtl->tpwin );
- vtl->last_tpl = NULL;
- vtl->last_tp_track_name = NULL;
-}
-
static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
{
if ( vtl->tpwin )
if ( vtl->current_tpl )
{
vtl->current_tpl = NULL;
- vtl->current_tp_track_name = NULL;
- vik_layer_emit_update(VIK_LAYER(vtl));
+ vtl->current_tp_track = NULL;
+ vtl->current_tp_id = NULL;
+ vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
}
}
if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
{
- gchar *name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track_name);
- if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks, name ) ) )
- {
- VikTrack *tr = vik_track_new ();
- GList *newglist = g_list_alloc ();
- newglist->prev = NULL;
- newglist->next = vtl->current_tpl->next;
- newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
- tr->trackpoints = newglist;
-
- vtl->current_tpl->next->prev = newglist; /* end old track here */
- vtl->current_tpl->next = NULL;
-
- vtl->current_tpl = newglist; /* change tp to first of new track. */
- vtl->current_tp_track_name = name;
-
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
-
- tr->visible = TRUE;
-
- vik_trw_layer_add_track ( vtl, name, tr );
- vik_layer_emit_update(VIK_LAYER(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_track_name );
- GList *new_tpl;
- g_assert(tr != NULL);
+ 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;
- /* can't join with a non-existent trackpoint */
- vtl->last_tpl = NULL;
- vtl->last_tp_track_name = NULL;
+ GList *new_tpl;
+ // Find available adjacent trackpoint
if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
{
if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
- tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl ); /* this nulls current_tpl->prev and next */
+ // Delete current trackpoint
+ vik_trackpoint_free ( vtl->current_tpl->data );
+ tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
- /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track_name );
+ // Set to current to the available adjacent trackpoint
+ vtl->current_tpl = new_tpl;
- trw_layer_cancel_last_tp ( vtl );
+ // Reset dialog with the available adjacent trackpoint
+ if ( vtl->current_tp_track )
+ vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name );
- g_free ( vtl->current_tpl->data ); /* TODO: vik_trackpoint_free() */
- g_list_free_1 ( vtl->current_tpl );
- vtl->current_tpl = new_tpl;
- vik_layer_emit_update(VIK_LAYER(vtl));
+ vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
}
else
{
- tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl );
- g_free ( vtl->current_tpl->data ); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
- g_list_free_1 ( vtl->current_tpl );
+ // Delete current trackpoint
+ vik_trackpoint_free ( vtl->current_tpl->data );
+ tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
trw_layer_cancel_current_tp ( vtl, FALSE );
}
}
else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
{
- vtl->last_tpl = vtl->current_tpl;
- 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)); /* TODO longone: either move or only update if tp is inside drawing window */
+ 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 */
}
else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
{
- vtl->last_tpl = vtl->current_tpl;
- 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));
- }
- else if ( response == VIK_TRW_LAYER_TPWIN_JOIN )
- {
- VikTrack *tr1 = g_hash_table_lookup ( vtl->tracks, vtl->last_tp_track_name );
- VikTrack *tr2 = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_track_name );
-
- VikTrack *tr_first = tr1, *tr_last = tr2;
-
- gchar *tmp;
-
- if ( (!vtl->last_tpl->next) && (!vtl->current_tpl->next) ) /* both endpoints */
- vik_track_reverse ( tr2 ); /* reverse the second, that way second track clicked will be later. */
- else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->prev) )
- vik_track_reverse ( tr1 );
- else if ( (!vtl->last_tpl->prev) && (!vtl->current_tpl->next) ) /* clicked startpoint, then endpoint -- concat end to start */
- {
- tr_first = tr2;
- tr_last = tr1;
- }
- /* default -- clicked endpoint then startpoint -- connect endpoint to startpoint */
-
- if ( tr_last->trackpoints ) /* deleting this part here joins them into 1 segmented track. useful but there's no place in the UI for this feature. segments should be deprecated anyway. */
- VIK_TRACKPOINT(tr_last->trackpoints->data)->newsegment = FALSE;
- tr1->trackpoints = g_list_concat ( tr_first->trackpoints, tr_last->trackpoints );
- tr2->trackpoints = NULL;
-
- tmp = vtl->current_tp_track_name;
-
- vtl->current_tp_track_name = vtl->last_tp_track_name; /* current_tp stays the same (believe it or not!) */
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
-
- /* if we did this before, trw_layer_delete_track would have canceled the current tp because
- * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */
- vik_trw_layer_delete_track ( vtl, tmp );
-
- trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */
- vik_layer_emit_update(VIK_LAYER(vtl));
+ 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);
}
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));
+ vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
}
else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
- vik_layer_emit_update (VIK_LAYER(vtl));
+ vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
}
static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
}
if ( vtl->current_tpl )
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
+ if ( vtl->current_tp_track )
+ vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
/* set layer name and TP data */
}
typedef struct {
gint x, y;
gint closest_x, closest_y;
- gchar *closest_wp_name;
+ gpointer *closest_wp_id;
VikWaypoint *closest_wp;
VikViewport *vvp;
} WPSearchParams;
typedef struct {
gint x, y;
gint closest_x, closest_y;
- gchar *closest_track_name;
+ gpointer closest_track_id;
VikTrackpoint *closest_tp;
VikViewport *vvp;
GList *closest_tpl;
} TPSearchParams;
-static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params )
+static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchParams *params )
{
gint x, y;
if ( !wp->visible )
if ( x <= params->x + slackx && x >= params->x - slackx
&& y <= params->y + slacky && y >= params->y - slacky ) {
- params->closest_wp_name = name;
+ params->closest_wp_id = id;
params->closest_wp = wp;
params->closest_x = x;
params->closest_y = y;
((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */
abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
{
- params->closest_wp_name = name;
+ params->closest_wp_id = id;
params->closest_wp = wp;
params->closest_x = x;
params->closest_y = y;
}
}
-static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params )
+static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams *params )
{
GList *tpl = t->trackpoints;
VikTrackpoint *tp;
((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */
abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
{
- params->closest_track_name = name;
+ params->closest_track_id = id;
params->closest_tp = tp;
params->closest_tpl = tpl;
params->closest_x = x;
}
}
+// 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;
params.x = x;
params.y = y;
params.vvp = vvp;
- params.closest_track_name = NULL;
+ params.closest_track_id = NULL;
params.closest_tp = NULL;
g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms);
return params.closest_tp;
params.y = y;
params.vvp = vvp;
params.closest_wp = NULL;
- params.closest_wp_name = NULL;
+ params.closest_wp_id = NULL;
g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms);
return params.closest_wp;
}
+
// Some forward declarations
static void marker_begin_move ( tool_ed_t *t, gint x, gint y );
static void marker_moveto ( tool_ed_t *t, gint x, gint y );
vtl->current_wp->coord = new_coord;
else {
if ( vtl->current_tpl ) {
- VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
+ VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
if ( vtl->tpwin )
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
-
- // Don't really know what this is for but seems like it might be handy...
- /* can't join with itself! */
- trw_layer_cancel_last_tp ( vtl );
+ if ( vtl->current_tp_track )
+ vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
}
}
// Reset
- vtl->current_wp = NULL;
- vtl->current_wp_name = NULL;
+ vtl->current_wp = NULL;
+ vtl->current_wp_id = NULL;
trw_layer_cancel_current_tp ( vtl, FALSE );
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
return FALSE;
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
wp_params.vvp = vvp;
wp_params.x = event->x;
wp_params.y = event->y;
- wp_params.closest_wp_name = NULL;
+ wp_params.closest_wp_id = NULL;
wp_params.closest_wp = NULL;
g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params);
if ( wp_params.closest_wp ) {
// Select
- vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_name ), TRUE );
+ vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_id ), TRUE );
// Too easy to move it so must be holding shift to start immediately moving it
- // or otherwise be previously selected
+ // or otherwise be previously selected but not have an image (otherwise clicking within image bounds (again) moves it)
if ( event->state & GDK_SHIFT_MASK ||
- vtl->current_wp == wp_params.closest_wp ) {
+ ( vtl->current_wp == wp_params.closest_wp && !vtl->current_wp->image ) ) {
// 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_wp = wp_params.closest_wp;
- vtl->current_wp_name = wp_params.closest_wp_name;
+ vtl->current_wp = wp_params.closest_wp;
+ vtl->current_wp_id = wp_params.closest_wp_id;
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
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_name = 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 ) {
// Always select + highlight the track
- vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, tp_params.closest_track_name ), TRUE );
+ vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_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->tracks, 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), FALSE );
+ 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;
}
vtl->current_tpl = tp_params.closest_tpl;
- vtl->current_tp_track_name = tp_params.closest_track_name;
+ 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_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
}
/* these aren't the droids you're looking for */
- vtl->current_wp = NULL;
- vtl->current_wp_name = NULL;
+ vtl->current_wp = NULL;
+ vtl->current_wp_id = NULL;
trw_layer_cancel_current_tp ( vtl, FALSE );
+ // Blank info
+ vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, "" );
+
return FALSE;
}
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 */
VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
if ( track && track->visible ) {
- if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
+ if ( track->name ) {
if ( vtl->track_right_click_menu )
- gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
+ gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
- vik_trw_layer_sublayer_add_menu_items ( vtl,
- vtl->track_right_click_menu,
- NULL,
- VIK_TRW_LAYER_SUBLAYER_TRACK,
- vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
- g_hash_table_lookup ( vtl->tracks_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
- vvp);
+ trku_udata udataU;
+ udataU.trk = track;
+ udataU.uuid = NULL;
+
+ 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;
+ 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,
+ track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK,
+ udataU.uuid,
+ iter,
+ vvp );
+ }
gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
/* See if a waypoint is selected */
VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
if ( waypoint && waypoint->visible ) {
- if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
+ if ( waypoint->name ) {
if ( vtl->wp_right_click_menu )
- gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
+ gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
- vik_trw_layer_sublayer_add_menu_items ( vtl,
- vtl->wp_right_click_menu,
- NULL,
- VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
- vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
- g_hash_table_lookup ( vtl->waypoints_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
- vvp);
+
+ wpu_udata udata;
+ udata.wp = waypoint;
+ udata.uuid = NULL;
+
+ gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+ if ( wpf && udata.uuid ) {
+ GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+
+ trw_layer_sublayer_add_menu_items ( vtl,
+ vtl->wp_right_click_menu,
+ NULL,
+ VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
+ udata.uuid,
+ iter,
+ vvp );
+ }
gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
return TRUE;
params.vvp = vvp;
params.x = event->x;
params.y = event->y;
- params.closest_wp_name = NULL;
+ params.closest_wp_id = NULL;
/* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
params.closest_wp = NULL;
g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms);
if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
{
- /* how do we get here? I'm putting in the abort until we can figure it out. -alex */
+ // how do we get here?
marker_begin_move(t, event->x, event->y);
g_critical("shouldn't be here");
- exit(1);
+ return FALSE;
}
else if ( params.closest_wp )
{
else
vtl->waypoint_rightclick = FALSE;
- vtl->current_wp = params.closest_wp;
- vtl->current_wp_name = params.closest_wp_name;
+ vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, params.closest_wp_id ), TRUE );
- if ( params.closest_wp )
- vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ), TRUE );
+ vtl->current_wp = params.closest_wp;
+ 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) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
vtl->current_wp = NULL;
- vtl->current_wp_name = NULL;
+ vtl->current_wp_id = NULL;
vtl->waypoint_rightclick = FALSE;
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return FALSE;
}
marker_end_move ( t );
vtl->current_wp->coord = new_coord;
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
/* PUT IN RIGHT PLACE!!! */
{
if ( vtl->wp_right_click_menu )
g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
- vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
- vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ), vvp );
- gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
+ if ( vtl->current_wp ) {
+ vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
+ trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_id, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_id ), vvp );
+ gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
+ }
vtl->waypoint_rightclick = FALSE;
}
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)
typedef struct {
VikTrwLayer *vtl;
- VikViewport *vvp;
- gint x1,y1,x2,y2;
-} new_track_move_passalong_t;
-
-/* sync and undraw, but only when we have time */
-static gboolean ct_sync ( gpointer passalong )
-{
- new_track_move_passalong_t *p = (new_track_move_passalong_t *) passalong;
- vik_viewport_sync ( p->vvp );
- gdk_gc_set_function ( p->vtl->current_track_gc, GDK_INVERT );
- vik_viewport_draw_line ( p->vvp, p->vtl->current_track_gc, p->x1, p->y1, p->x2, p->y2 );
- gdk_gc_set_function ( p->vtl->current_track_gc, GDK_COPY );
- p->vtl->ct_sync_done = TRUE;
- g_free ( p );
+ GdkDrawable *drawable;
+ GdkGC *gc;
+ GdkPixmap *pixmap;
+} draw_sync_t;
+
+/*
+ * Draw specified pixmap
+ */
+static gboolean draw_sync ( gpointer data )
+{
+ draw_sync_t *ds = (draw_sync_t*) data;
+ // Sometimes don't want to draw
+ // normally because another update has taken precedent such as panning the display
+ // which means this pixmap is no longer valid
+ if ( ds->vtl->draw_sync_do ) {
+ gdk_threads_enter();
+ gdk_draw_drawable (ds->drawable,
+ ds->gc,
+ ds->pixmap,
+ 0, 0, 0, 0, -1, -1);
+ ds->vtl->draw_sync_done = TRUE;
+ gdk_threads_leave();
+ }
return FALSE;
}
+static gchar* distance_string (gdouble distance)
+{
+ gchar str[128];
+
+ /* draw label with distance */
+ vik_units_distance_t dist_units = a_vik_get_units_distance ();
+ switch (dist_units) {
+ case VIK_UNITS_DISTANCE_MILES:
+ if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
+ g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
+ } else if (distance < 1609.4) {
+ g_sprintf(str, "%d yards", (int)(distance*1.0936133));
+ } else {
+ g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
+ }
+ break;
+ default:
+ // VIK_UNITS_DISTANCE_KILOMETRES
+ if (distance >= 1000 && distance < 100000) {
+ g_sprintf(str, "%3.2f km", distance/1000.0);
+ } else if (distance < 1000) {
+ g_sprintf(str, "%d m", (int)distance);
+ } else {
+ g_sprintf(str, "%d km", (int)distance/1000);
+ }
+ break;
+ }
+ return g_strdup (str);
+}
+
+/*
+ * Actually set the message in statusbar
+ */
+static void statusbar_write (const gchar *distance_string, gdouble elev_gain, gdouble elev_loss, VikTrwLayer *vtl )
+{
+ // Only show elevation data when track has some elevation properties
+ gchar str_gain_loss[64];
+ str_gain_loss[0] = '\0';
+
+ if ( (elev_gain > 0.1) || (elev_loss > 0.1) ) {
+ if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
+ g_sprintf(str_gain_loss, _(" - Gain %dm:Loss %dm"), (int)elev_gain, (int)elev_loss);
+ else
+ g_sprintf(str_gain_loss, _(" - Gain %dft:Loss %dft"), (int)VIK_METERS_TO_FEET(elev_gain), (int)VIK_METERS_TO_FEET(elev_loss));
+ }
+
+ // 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 );
+ g_free ( msg );
+}
+
+/*
+ * Figure out what information should be set in the statusbar and then write it
+ */
+static void update_statusbar ( VikTrwLayer *vtl )
+{
+ // Get elevation data
+ gdouble elev_gain, elev_loss;
+ vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
+
+ /* Find out actual distance of current track */
+ gdouble distance = vik_track_get_length (vtl->current_track);
+ gchar *str = distance_string (distance);
+
+ statusbar_write (str, elev_gain, elev_loss, vtl);
+
+ g_free (str);
+}
+
+
static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
{
/* if we haven't sync'ed yet, we don't have time to do more. */
- if ( vtl->ct_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
- GList *iter = vtl->current_track->trackpoints;
- new_track_move_passalong_t *passalong;
+ 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;
+ // Need to check in case window has been resized
+ w1 = vik_viewport_get_width(vvp);
+ h1 = vik_viewport_get_height(vvp);
+ if (!pixmap) {
+ pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+ }
+ gdk_drawable_get_size (pixmap, &w2, &h2);
+ if (w1 != w2 || h1 != h2) {
+ g_object_unref ( G_OBJECT ( pixmap ) );
+ pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+ }
+
+ // Reset to background
+ gdk_draw_drawable (pixmap,
+ vtl->current_track_newpoint_gc,
+ vik_viewport_get_pixmap(vvp),
+ 0, 0, 0, 0, -1, -1);
+
+ draw_sync_t *passalong;
gint x1, y1;
- while ( iter->next )
- iter = iter->next;
- gdk_gc_set_function ( vtl->current_track_gc, GDK_INVERT );
- vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
- vik_viewport_draw_line ( vvp, vtl->current_track_gc, x1, y1, event->x, event->y );
- gdk_gc_set_function ( vtl->current_track_gc, GDK_COPY );
+ 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,
+ // thus when we come to reset to the background it would include what we have already drawn!!
+ gdk_draw_line ( pixmap,
+ vtl->current_track_newpoint_gc,
+ x1, y1, event->x, event->y );
+ // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
+
+ /* Find out actual distance of current track */
+ gdouble distance = vik_track_get_length (vtl->current_track);
+
+ // Now add distance to where the pointer is //
+ VikCoord coord;
+ 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, &(last_tpt->coord));
+
+ // Get elevation data
+ gdouble elev_gain, elev_loss;
+ vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
+
+ // Adjust elevation data (if available) for the current pointer position
+ 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 ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) {
+ // Adjust elevation of last track point
+ if ( elev_new > last_tpt->altitude )
+ // Going up
+ elev_gain += elev_new - last_tpt->altitude;
+ else
+ // Going down
+ elev_loss += last_tpt->altitude - elev_new;
+ }
+ }
+
+ gchar *str = distance_string (distance);
+
+ PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
+ pango_layout_set_font_description (pl, GTK_WIDGET(vvp)->style->font_desc);
+
+ pango_layout_set_text (pl, str, -1);
+ gint wd, hd;
+ pango_layout_get_pixel_size ( pl, &wd, &hd );
+
+ gint xd,yd;
+ // offset from cursor a bit depending on font size
+ xd = event->x + 10;
+ yd = event->y - hd;
- passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
+ // Create a background block to make the text easier to read over the background map
+ GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
+ gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
+ gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
+
+ g_object_unref ( G_OBJECT ( pl ) );
+ g_object_unref ( G_OBJECT ( background_block_gc ) );
+
+ passalong = g_new(draw_sync_t,1); // freed by draw_sync()
passalong->vtl = vtl;
- passalong->vvp = vvp;
- passalong->x1 = x1;
- passalong->y1 = y1;
- passalong->x2 = event->x;
- passalong->y2 = event->y;
-
- /* this will sync and undraw when we have time to */
- g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, ct_sync, passalong, NULL);
- vtl->ct_sync_done = FALSE;
+ passalong->pixmap = pixmap;
+ passalong->drawable = GTK_WIDGET(vvp)->window;
+ passalong->gc = vtl->current_track_newpoint_gc;
+
+ // Update statusbar with full gain/loss information
+ statusbar_write (str, elev_gain, elev_loss, vtl);
+
+ g_free (str);
+
+ // draw pixmap when we have time to
+ g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
+ vtl->draw_sync_done = FALSE;
return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
}
return VIK_LAYER_TOOL_ACK;
{
if ( vtl->current_track && event->keyval == GDK_Escape ) {
vtl->current_track = NULL;
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
} else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
/* undo */
g_free ( last->data );
vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
}
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+
+ update_statusbar ( vtl );
+
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
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;
if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
return FALSE;
- if ( event->button == 3 && vtl->current_track )
+ if ( event->button == 2 ) {
+ // As the display is panning, the new track pixmap is now invalid so don't draw it
+ // otherwise this drawing done results in flickering back to an old image
+ vtl->draw_sync_do = FALSE;
+ return FALSE;
+ }
+
+ if ( event->button == 3 )
{
+ if ( !vtl->current_track )
+ return FALSE;
/* undo */
if ( vtl->current_track->trackpoints )
{
g_free ( last->data );
vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
}
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ update_statusbar ( vtl );
+
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
/* undo last, then end */
vtl->current_track = NULL;
}
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
- if ( ! vtl->current_track )
- {
- gchar *name = get_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) );
tp->newsegment = FALSE;
tp->has_timestamp = FALSE;
tp->timestamp = 0;
- vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp );
+
+ 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) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
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 ) ) )
+ {
+ vtl->current_track = vik_track_new();
+ vtl->current_track->visible = TRUE;
+ vik_trw_layer_add_track ( vtl, name, vtl->current_track );
+ }
+ 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 ) {
+ // Pan moving ended - enable potential point drawing again
+ vtl->draw_sync_do = TRUE;
+ vtl->draw_sync_done = TRUE;
+ }
+}
+
+/*** 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 ) ) )
+ {
+ vtl->current_track = vik_track_new();
+ vtl->current_track->visible = TRUE;
+ vtl->current_track->is_route = TRUE;
+ vik_trw_layer_add_route ( vtl, name, vtl->current_track );
+ }
+ 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)
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) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
params.vvp = vvp;
params.x = event->x;
params.y = event->y;
- params.closest_track_name = NULL;
+ params.closest_track_id = NULL;
/* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
params.closest_tp = NULL;
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 )
{
/* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
- VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name));
- gint x, y;
- g_assert ( current_tr );
+ VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
+ if ( !current_tr )
+ return FALSE;
+ gint x, y;
vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
if ( current_tr->visible &&
return TRUE;
}
- vtl->last_tpl = vtl->current_tpl;
- vtl->last_tp_track_name = vtl->current_tp_track_name;
}
- 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 )
+ {
+ vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_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->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 );
+ 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_track_name = params.closest_track_name;
- vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ), TRUE );
+ 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 );
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
marker_end_move ( t );
/* diff dist is diff from orig */
- vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name );
- /* can't join with itself! */
- trw_layer_cancel_last_tp ( vtl );
+ 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) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
return TRUE;
}
return FALSE;
}
-/*** Magic Scissors ***/
-static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
+#ifdef VIK_CONFIG_GOOGLE
+/*** Route Finder ***/
+static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
{
return vvp;
}
-static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
{
VikCoord tmp;
if ( !vtl ) return FALSE;
vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
- if ( event->button == 3 && vtl->magic_scissors_current_track ) {
+ if ( event->button == 3 && vtl->route_finder_current_track ) {
VikCoord *new_end;
- new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track );
+ new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
if ( new_end ) {
- vtl->magic_scissors_coord = *new_end;
+ vtl->route_finder_coord = *new_end;
g_free ( new_end );
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
/* remove last ' to:...' */
- if ( vtl->magic_scissors_current_track->comment ) {
- gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' );
- if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) {
- gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment,
- last_to - vtl->magic_scissors_current_track->comment - 1);
- vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+ if ( vtl->route_finder_current_track->comment ) {
+ gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
+ if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
+ gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
+ last_to - vtl->route_finder_current_track->comment - 1);
+ vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
}
}
}
}
- else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) {
+ else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
struct LatLon start, end;
gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE];
gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE];
gchar *url;
- vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start );
+ vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
vik_coord_to_latlon ( &(tmp), &end );
- vtl->magic_scissors_coord = tmp; /* for continuations */
+ vtl->route_finder_coord = tmp; /* for continuations */
/* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
- if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) {
- vtl->magic_scissors_append = TRUE; // merge tracks. keep started true.
+ if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
+ vtl->route_finder_append = TRUE; // merge tracks. keep started true.
} else {
- vtl->magic_scissors_check_added_track = TRUE;
- vtl->magic_scissors_started = FALSE;
+ vtl->route_finder_check_added_track = TRUE;
+ vtl->route_finder_started = FALSE;
}
url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING,
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 );
+ a_babel_convert_from_url ( vtl, url, "google", NULL, NULL );
g_free ( url );
/* see if anything was done -- a track was added or appended to */
- if ( vtl->magic_scissors_check_added_track && vtl->magic_scissors_added_track_name ) {
- VikTrack *tr;
-
- tr = g_hash_table_lookup ( vtl->tracks, vtl->magic_scissors_added_track_name );
-
- if ( tr )
- vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
-
- vtl->magic_scissors_current_track = tr;
-
- g_free ( vtl->magic_scissors_added_track_name );
- vtl->magic_scissors_added_track_name = NULL;
- } else if ( vtl->magic_scissors_append == FALSE && vtl->magic_scissors_current_track ) {
- /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
- gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->magic_scissors_current_track->comment, end.lat, end.lon );
- vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+ if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) {
+ vik_track_set_comment_no_copy ( vtl->route_finder_added_track, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
+ } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
+ /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
+ gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
+ vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
}
- vtl->magic_scissors_check_added_track = FALSE;
- vtl->magic_scissors_append = FALSE;
+ vtl->route_finder_added_track = NULL;
+ vtl->route_finder_check_added_track = FALSE;
+ vtl->route_finder_append = FALSE;
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ vik_layer_emit_update ( VIK_LAYER(vtl), FALSE );
} else {
- vtl->magic_scissors_started = TRUE;
- vtl->magic_scissors_coord = tmp;
- vtl->magic_scissors_current_track = NULL;
+ vtl->route_finder_started = TRUE;
+ vtl->route_finder_coord = tmp;
+ vtl->route_finder_current_track = NULL;
}
return TRUE;
}
+#endif
/*** Show picture ****/
}
/* Params are: vvp, event, last match found or NULL */
-static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] )
+static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[3] )
{
if ( wp->image && wp->visible )
{
{
/* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
#ifdef WINDOWS
- ShellExecute(NULL, NULL, (char *) pass_along[2], NULL, ".\\", 0);
+ ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL);
#else /* WINDOWS */
GError *err = NULL;
gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
- gchar *cmd = g_strdup_printf ( "eog %s", quoted_file );
+ gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
g_free ( quoted_file );
if ( ! g_spawn_command_line_async ( cmd, &err ) )
{
- a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch eog to open file.") );
+ a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch %s to open file."), a_vik_get_image_viewer() );
g_error_free ( err );
}
g_free ( cmd );
}
// Redraw to show the thumbnails as they are now created
- gdk_threads_enter();
if ( IS_VIK_LAYER(tctd->vtl) )
- vik_layer_emit_update ( VIK_LAYER(tctd->vtl) );
- gdk_threads_leave();
+ vik_layer_emit_update ( VIK_LAYER(tctd->vtl), TRUE ); // Yes update from background thread
return 0;
}
g_free ( tctd );
}
-static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
+void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
{
if ( ! vtl->has_verified_thumbnails )
{
return vtl->coord_mode;
}
+/**
+ * Uniquify the whole layer
+ * Also requires the layers panel as the names shown there need updating too
+ * Returns whether the operation was successful or not
+ */
+gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
+{
+ if ( 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;
+ }
+ return FALSE;
+}
-
-static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode )
+static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode )
{
vik_coord_convert ( &(wp->coord), *dest_mode );
}
}
}
-VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, gchar *name )
-{
- return g_hash_table_lookup ( vtl->waypoints, name );
-}
-
-VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name )
-{
- return g_hash_table_lookup ( vtl->tracks, name );
-}
-
-static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection)
+static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 selection )
{
vtl->menu_selection = selection;
}
-static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl)
+static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl )
{
- return(vtl->menu_selection);
+ return (vtl->menu_selection);
}
/* ----------- Downloading maps along tracks --------------- */
}
for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
- maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
+ maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
}
if (fillins) {
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
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++)
gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
if ( vtl->highest_wp_number == old_wp_num ) {
gchar buf[4];
- vtl->highest_wp_number --;
+ vtl->highest_wp_number--;
g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
/* search down until we find something that *does* exist */
- while ( vtl->highest_wp_number > 0 && ! g_hash_table_lookup ( vtl->waypoints, buf ) ) {
- vtl->highest_wp_number --;
+ while ( vtl->highest_wp_number > 0 && ! vik_trw_layer_get_waypoint ( vtl, buf )) {
+ vtl->highest_wp_number--;
g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
}
}