X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/c3deba012b9d8f5a14c1c4be793bba389aaf0505..e6b64c5dc48ab20f0bab12abb23ba91c2c55f347:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index 4a7c2bda..99ede37a 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -1,7 +1,10 @@ /* * viking -- GPS Data and Topo Analyzer, Explorer, and Manager * - * Copyright (C) 2003-2005, Evan Battaglia + * Copyright (C) 2003-2007, Evan Battaglia + * Copyright (C) 2005-2008, Alex Foobarian + * Copyright (C) 2007, Quy Tonthat + * Copyright (C) 2009, Hein Ragas * * 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 @@ -30,7 +33,6 @@ #include "viking.h" #include "vikmapslayer.h" -#include "viktrwlayer_pixmap.h" #include "viktrwlayer_tpwin.h" #include "viktrwlayer_propwin.h" #include "garminsymbols.h" @@ -40,18 +42,39 @@ #include "babel.h" #include "dem.h" #include "dems.h" +#include "geonamessearch.h" #ifdef VIK_CONFIG_OPENSTREETMAP #include "osm-traces.h" #endif +#include "acquire.h" +#include "util.h" #include "icons/icons.h" +#ifdef HAVE_MATH_H #include +#endif +#ifdef HAVE_STRING_H #include +#endif +#ifdef HAVE_STDLIB_H #include +#endif +#include #include -#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%f,%f to %f,%f&output=js\" 2>/dev/null)" +#include +#include +#include +#include + +/* 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 ); } +#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_RATES 10 #define VIK_TRW_LAYER_TRACK_GC_MIN 0 @@ -107,6 +130,7 @@ struct _VikTrwLayer { gdouble velocity_min, velocity_max; GArray *track_gc; guint16 track_gc_iter; + GdkGC *current_track_gc; GdkGC *track_bg_gc; GdkGC *waypoint_gc; GdkGC *waypoint_text_gc; @@ -114,6 +138,8 @@ struct _VikTrwLayer { GdkFont *waypoint_font; VikTrack *current_track; guint16 ct_x1, ct_y1, ct_x2, ct_y2; + gboolean ct_sync_done; + VikCoordMode coord_mode; @@ -160,6 +186,7 @@ struct _VikTrwLayer { /* menu */ VikStdLayerMenuItem menu_selection; + gint highest_wp_number; }; /* A caached waypoint image. */ @@ -188,6 +215,7 @@ static void trw_layer_cut_item_cb( gpointer *pass_along); 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 (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 ); @@ -196,16 +224,29 @@ static gint calculate_velocity ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackp 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 ( VikLayersPanel *vlp, const VikCoord *coord ); static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] ); static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ); +static void trw_layer_goto_track_max_speed ( gpointer pass_along[5] ); +static void trw_layer_goto_track_max_alt ( gpointer pass_along[5] ); +static void trw_layer_goto_track_min_alt ( gpointer pass_along[5] ); +static void trw_layer_auto_track_view ( gpointer pass_along[5] ); static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ); static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ); static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]); static void trw_layer_centerize ( gpointer layer_and_vlp[2] ); -static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type ); +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_goto_wp ( gpointer layer_and_vlp[2] ); static void trw_layer_new_wp ( 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_new_wikipedia_wp_viewport ( gpointer lav[2] ); +static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ); +static void trw_layer_merge_with_other ( gpointer pass_along[6] ); /* pop-up items */ static void trw_layer_properties_item ( gpointer pass_along[5] ); @@ -218,10 +259,10 @@ 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( gpointer data, gint len, VikViewport *vvp ); +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 ); -static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ); +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_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ); @@ -229,7 +270,7 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i 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 void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name ); +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 ); @@ -237,24 +278,26 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl ); static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); -static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ); static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp); static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); -static gboolean tool_edit_waypoint_move ( 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_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 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 ); -static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str ); - 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 ); @@ -268,37 +311,48 @@ static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type static void waypoint_convert ( const gchar *name, 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_reset(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); + + static VikToolInterface trw_layer_tools[] = { - { "Create Waypoint", (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL, - (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, &cursor_addwp }, + { 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 }, - { "Create Track", (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL, - (VikToolMouseFunc) tool_new_track_click, NULL, NULL, &cursor_addtr }, + { 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 }, - { "Edit Waypoint", (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL, + { N_("Edit Waypoint"), (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL, (VikToolMouseFunc) tool_edit_waypoint_click, - (VikToolMouseFunc) tool_edit_waypoint_move, - (VikToolMouseFunc) tool_edit_waypoint_release, &cursor_edwp }, + (VikToolMouseMoveFunc) tool_edit_waypoint_move, + (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf }, - { "Edit Trackpoint", (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, + { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, (VikToolMouseFunc) tool_edit_trackpoint_click, - (VikToolMouseFunc) tool_edit_trackpoint_move, - (VikToolMouseFunc) tool_edit_trackpoint_release, &cursor_edtr }, + (VikToolMouseMoveFunc) tool_edit_trackpoint_move, + (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf }, - { "Show Picture", (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL, - (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, &cursor_showpic }, + { 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 }, - { "Magic Scissors", (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL, - (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, &cursor_iscissors }, + { N_("Magic Scissors"), (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_iscissors_pixbuf }, }; +enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS }; /****** PARAMETERS ******/ -static gchar *params_groups[] = { "Waypoints", "Tracks", "Waypoint Images" }; +static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") }; enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES }; -static gchar *params_drawmodes[] = { "Draw by Track", "Draw by Velocity", "All Tracks Black", 0 }; -static gchar *params_wpsymbols[] = { "Filled Square", "Square", "Circle", "X", 0 }; +static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Velocity"), N_("All Tracks Black"), 0 }; +static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 }; static VikLayerParamScale params_scales[] = { @@ -320,34 +374,34 @@ VikLayerParam trw_layer_params[] = { { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES }, { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES }, - { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Drawing Mode:", VIK_LAYER_WIDGET_RADIOGROUP, NULL }, - { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Track Lines", VIK_LAYER_WIDGET_CHECKBUTTON }, - { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Trackpoints", VIK_LAYER_WIDGET_CHECKBUTTON }, - { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Elevation", VIK_LAYER_WIDGET_CHECKBUTTON }, - { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Draw Elevation Height %:", VIK_LAYER_WIDGET_HSCALE, params_scales + 9 }, - - { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Stops", VIK_LAYER_WIDGET_CHECKBUTTON }, - { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Min Stop Length (seconds):", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 }, - - { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 }, - { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track BG Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 }, - { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, "Track Background Color", VIK_LAYER_WIDGET_COLOR, 0 }, - { "velocity_min", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, "Min Track Velocity:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 1 }, - { "velocity_max", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, "Max Track Velocity:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 2 }, - - { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Draw Labels", VIK_LAYER_WIDGET_CHECKBUTTON }, - { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Waypoint Color:", VIK_LAYER_WIDGET_COLOR, 0 }, - { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Waypoint Text:", VIK_LAYER_WIDGET_COLOR, 0 }, - { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Background:", VIK_LAYER_WIDGET_COLOR, 0 }, - { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Fake BG Color Translucency:", VIK_LAYER_WIDGET_CHECKBUTTON, 0 }, - { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint marker:", VIK_LAYER_WIDGET_RADIOGROUP, NULL }, - { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint size:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 }, - { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Draw Waypoint Symbols:", VIK_LAYER_WIDGET_CHECKBUTTON }, - - { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, "Draw Waypoint Images", VIK_LAYER_WIDGET_CHECKBUTTON }, - { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Size (pixels):", VIK_LAYER_WIDGET_HSCALE, params_scales + 3 }, - { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales + 4 }, - { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Memory Cache Size:", VIK_LAYER_WIDGET_HSCALE, params_scales + 5 }, + { "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 }, + { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON }, + { "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 }, + + { "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON }, + { "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, 0 }, + { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, 0 }, + { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, 0 }, + { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, 0 }, + { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL }, + { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 }, + { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON }, + + { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON }, + { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, params_scales + 3 }, + { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 4 }, + { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, params_scales + 5 }, }; 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 }; @@ -361,7 +415,7 @@ enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PAR VikLayerInterface vik_trw_layer_interface = { "TrackWaypoint", - &trwlayer_pixbuf, + &viktrwlayer_pixbuf, trw_layer_tools, sizeof(trw_layer_tools) / sizeof(VikToolInterface), @@ -390,6 +444,8 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncSublayerRenameRequest) vik_trw_layer_sublayer_rename_request, (VikLayerFuncSublayerToggleVisible) vik_trw_layer_sublayer_toggle_visible, + (VikLayerFuncSublayerTooltip) trw_layer_sublayer_tooltip, + (VikLayerFuncLayerTooltip) trw_layer_layer_tooltip, (VikLayerFuncMarshall) trw_layer_marshall, (VikLayerFuncUnmarshall) trw_layer_unmarshall, @@ -449,7 +505,7 @@ static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublay pass_along[0] = vtl; pass_along[1] = NULL; - pass_along[2] = (gpointer) subtype; + pass_along[2] = GINT_TO_POINTER (subtype); pass_along[3] = sublayer; pass_along[4] = NULL; @@ -459,7 +515,7 @@ static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublay static void trw_layer_copy_item_cb( gpointer pass_along[5]) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - gint subtype = (gint)pass_along[2]; + gint subtype = GPOINTER_TO_INT (pass_along[2]); gpointer * sublayer = pass_along[3]; guint8 *data = NULL; guint len; @@ -518,6 +574,9 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len); vik_trw_layer_add_waypoint ( vtl, name, w ); waypoint_convert(name, 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) ); return TRUE; } if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi ) @@ -528,6 +587,9 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len); vik_trw_layer_add_track ( vtl, name, t ); track_convert(name, 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) ); return TRUE; } return FALSE; @@ -540,7 +602,7 @@ static void trw_layer_free_copied_item ( gint subtype, gpointer item ) } } -static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp ) +static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation ) { switch ( id ) { @@ -563,14 +625,44 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara trw_layer_new_track_gcs ( vtl, vp ); } break; - case PARAM_BLT: if ( data.u > 0 && data.u <= 8 && data.u != vtl->bg_line_thickness ) + case PARAM_BLT: if ( data.u >= 0 && data.u <= 8 && data.u != vtl->bg_line_thickness ) { vtl->bg_line_thickness = data.u; trw_layer_new_track_gcs ( vtl, vp ); } break; - case PARAM_VMIN: vtl->velocity_min = data.d; break; - case PARAM_VMAX: vtl->velocity_max = data.d; 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_DLA: vtl->drawlabels = data.b; break; case PARAM_DI: vtl->drawimages = data.b; break; @@ -598,7 +690,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara return TRUE; } -static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ) +static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation ) { VikLayerParamData rv; switch ( id ) @@ -614,8 +706,38 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ) case PARAM_DL: rv.b = vtl->drawlines; break; case PARAM_LT: rv.u = vtl->line_thickness; break; case PARAM_BLT: rv.u = vtl->bg_line_thickness; break; - case PARAM_VMIN: rv.d = vtl->velocity_min; break; - case PARAM_VMAX: rv.d = vtl->velocity_max; 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; @@ -635,8 +757,10 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ) static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) { - guint8 *pd, *dd; - gint pl, dl; + guint8 *pd; + gchar *dd; + gsize dl; + gint pl; gchar *tmpname; FILE *f; @@ -646,7 +770,8 @@ static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) a_gpx_write_file(vtl, f); vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl); fclose(f); - g_file_get_contents(tmpname, (void *)&dd, (void *)&dl, NULL); + f = NULL; + g_file_get_contents(tmpname, &dd, &dl, NULL); *len = sizeof(pl) + pl + dl; *data = g_malloc(*len); memcpy(*data, &pl, sizeof(pl)); @@ -655,15 +780,15 @@ static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) g_free(pd); g_free(dd); - remove(tmpname); + g_remove(tmpname); g_free(tmpname); } } -static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp ) +static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp ) { VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE )); - guint pl; + gint pl; gchar *tmpname; FILE *f; @@ -674,41 +799,69 @@ static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport * data += pl; if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { - g_critical("couldn't open temp file\n"); + g_critical("couldn't open temp file"); exit(1); } fwrite(data, len - pl - sizeof(pl), 1, f); rewind(f); a_gpx_read_file(rv, f); fclose(f); - remove(tmpname); + f = NULL; + g_remove(tmpname); g_free(tmpname); return rv; } -static GList * a_array_to_glist(gpointer data[]) +static GList * str_array_to_glist(gchar* data[]) { GList *gl = NULL; gpointer * p; - for (p = data; *p; 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); +} + +static guint strcase_hash(gconstpointer v) +{ + /* 31 bit hash function */ + int i; + const gchar *t = v; + gchar s[128]; /* malloc is too slow for reading big files */ + gchar *p = s; + + for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++) + p[i] = toupper(t[i]); + p[i] = '\0'; + + p = s; + guint32 h = *p; + if (h) { + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + } + + return h; +} + VikTrwLayer *vik_trw_layer_new ( gint drawmode ) { if (trw_layer_params[PARAM_DM].widget_data == NULL) - trw_layer_params[PARAM_DM].widget_data = a_array_to_glist(params_drawmodes); + trw_layer_params[PARAM_DM].widget_data = str_array_to_glist(params_drawmodes); if (trw_layer_params[PARAM_WPSYM].widget_data == NULL) - trw_layer_params[PARAM_WPSYM].widget_data = a_array_to_glist(params_wpsymbols); + 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 ); - rv->waypoints = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) vik_waypoint_free ); + 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 ( g_str_hash, g_str_equal, NULL, g_free ); + rv->waypoints_iters = g_hash_table_new_full ( strcase_hash, strcase_equal, NULL, g_free ); /* TODO: constants at top */ rv->waypoints_visible = rv->tracks_visible = TRUE; @@ -737,6 +890,8 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode ) rv->moving_tp = FALSE; rv->moving_wp = FALSE; + rv->ct_sync_done = TRUE; + rv->magic_scissors_started = FALSE; rv->magic_scissors_check_added_track = FALSE; rv->magic_scissors_added_track_name = NULL; @@ -862,6 +1017,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr { /* TODO: this function is a mess, get rid of any redundancy */ GList *list = track->trackpoints; + GdkGC *main_gc; gboolean useoldvals = TRUE; gboolean drawpoints; @@ -894,6 +1050,14 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr drawstops = dp->vtl->drawstops; } + if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK ) + dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_BLACK; + + if ( track == dp->vtl->current_track ) + main_gc = dp->vtl->current_track_gc; + else + main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter); + if (list) { int x, y, oldx, oldy; VikTrackpoint *tp = VIK_TRACKPOINT(list->data); @@ -905,15 +1069,12 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr if ( (drawpoints) && dp->track_gc_iter < VIK_TRW_LAYER_TRACK_GC ) { GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} }; - vik_viewport_draw_polygon ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, trian, 3 ); + vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 ); } oldx = x; oldy = y; - if ( dp->vtl->drawmode == DRAWMODE_ALL_BLACK ) - dp->track_gc_iter = VIK_TRW_LAYER_TRACK_GC_MAX + 1; - while ((list = g_list_next(list))) { tp = VIK_TRACKPOINT(list->data); @@ -930,16 +1091,14 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr if ( drawpoints && ! drawing_white_background ) { if ( list->next ) { - vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size ); - - vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size ); + vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size ); /* stops */ if ( drawstops && 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 ); } else - vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 ); + 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)) @@ -948,10 +1107,12 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr /* 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, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y); + draw_utm_skip_insignia ( dp->vp, main_gc, x, y); - if ( dp->vtl->drawmode == DRAWMODE_BY_VELOCITY ) + 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 ); @@ -961,7 +1122,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr } else { - vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y); + 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 ) { GdkPoint tmp[4]; #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp) @@ -982,7 +1143,7 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr 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, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data)); + vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data)); } } } @@ -998,18 +1159,20 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr 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 ) + 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 ( 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, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y); + 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, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y ); + draw_utm_skip_insignia ( dp->vp, main_gc, x, y ); } } useoldvals = FALSE; @@ -1041,12 +1204,12 @@ static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name ) static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct DrawingParams *dp ) { if ( wp->visible ) - if ( (!dp->one_zone) || ( wp->coord.utm_zone == dp->center->utm_zone && + if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) && wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 && wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) ) { gint x, y; - GdkPixbuf *sym; + GdkPixbuf *sym = NULL; vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y ); /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */ @@ -1144,11 +1307,18 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct if ( dp->vtl->drawlabels ) { /* 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 ); pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height ); - vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, x + dp->vtl->wp_size - 1, y-1,width+1,height-1); - vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, x + dp->vtl->wp_size, y, dp->vtl->wplabellayout ); + label_x = x - width/2; + if (sym) + label_y = y - height - 2 - gdk_pixbuf_get_height(sym)/2; + else + label_y = y - dp->vtl->wp_size - height - 2; + + vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2); + vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout ); } } } @@ -1176,6 +1346,11 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl ) g_object_unref ( vtl->track_bg_gc ); vtl->track_bg_gc = NULL; } + if ( vtl->current_track_gc ) + { + g_object_unref ( vtl->current_track_gc ); + vtl->current_track_gc = NULL; + } if ( ! vtl->track_gc ) return; @@ -1197,6 +1372,11 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp ) g_object_unref ( vtl->track_bg_gc ); vtl->track_bg_gc = vik_viewport_new_gc ( vp, "#FFFFFF", width + vtl->bg_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->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC ); gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */ @@ -1257,7 +1437,7 @@ static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pas 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, (gint) pass_along[4], NULL, TRUE, TRUE ); + 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 ); #else vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE ); #endif @@ -1273,7 +1453,7 @@ static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer { GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter)); #ifdef VIK_CONFIG_ALPHABETIZED_TRW - vik_treeview_add_sublayer_alphabetized ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE ); + 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 ); #else vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], name, pass_along[2], name, (gint) pass_along[4], NULL, TRUE, TRUE ); #endif @@ -1292,9 +1472,9 @@ void vik_trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *lay 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 ); + 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 ); + 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 ); @@ -1302,9 +1482,9 @@ void vik_trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *lay g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along ); #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 ); + 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 ); + vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE ); #endif if ( ! vtl->waypoints_visible ) @@ -1343,6 +1523,191 @@ gboolean vik_trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, g return TRUE; } +// Structure to hold multiple track information for a layer +typedef struct { + gdouble length; + time_t start_time; + time_t end_time; + gint duration; +} tooltip_tracks; + +/* + * Build up layer multiple track information via updating the tooltip_tracks structure + */ +static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_tracks *tt ) +{ + tt->length = tt->length + vik_track_get_length (tr); + + // Ensure times are available + if ( tr->trackpoints && + VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp && + VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) { + + time_t t1, t2; + t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp; + t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp; + + // Assume never actually have a track with a time of 0 (1st Jan 1970) + // Hence initialize to the first 'proper' value + if ( tt->start_time == 0 ) + tt->start_time = t1; + if ( tt->end_time == 0 ) + tt->end_time = t2; + + // Update find the earliest / last times + if ( t1 < tt->start_time ) + tt->start_time = t1; + if ( t2 > tt->end_time ) + tt->end_time = t2; + + // Keep track of total time + // there maybe gaps within a track (eg segments) + // but this should be generally good enough for a simple indicator + tt->duration = tt->duration + (int)(t2-t1); + } +} + +/* + * Generate tooltip text for the layer. + * This is relatively complicated as it considers information for + * no tracks, a single track or multiple tracks + * (which may or may not have timing information) + */ +static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl ) +{ + gchar tbuf1[32]; + gchar tbuf2[64]; + gchar tbuf3[64]; + gchar tbuf4[10]; + tbuf1[0] = '\0'; + tbuf2[0] = '\0'; + tbuf3[0] = '\0'; + tbuf4[0] = '\0'; + + static gchar tmp_buf[128]; + tmp_buf[0] = '\0'; + + // For compact date format I'm using '%x' [The preferred date representation for the current locale without the time.] + + // Safety check - I think these should always be valid + if ( vtl->tracks && vtl->waypoints ) { + tooltip_tracks tt = { 0.0, 0, 0 }; + g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_tooltip, &tt ); + + GDate* gdate_start = g_date_new (); + g_date_set_time_t (gdate_start, tt.start_time); + + GDate* gdate_end = g_date_new (); + g_date_set_time_t (gdate_end, tt.end_time); + + if ( g_date_compare (gdate_start, gdate_end) ) { + // Dates differ so print range on separate line + g_date_strftime (tbuf1, sizeof(tbuf1), "%x", gdate_start); + g_date_strftime (tbuf2, sizeof(tbuf2), "%x", gdate_end); + g_snprintf (tbuf3, sizeof(tbuf3), "%s to %s\n", tbuf1, tbuf2); + } + else { + // Same date so just show it and keep rest of text on the same line - provided it's a valid time! + if ( tt.start_time != 0 ) + g_date_strftime (tbuf3, sizeof(tbuf3), "%x: ", gdate_start); + } + + tbuf2[0] = '\0'; + if ( tt.length > 0.0 ) { + gdouble len_in_units; + + // Setup info dependent on distance units + if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) { + g_snprintf (tbuf4, sizeof(tbuf4), "miles"); + len_in_units = tt.length/1600.0; + } + else { + g_snprintf (tbuf4, sizeof(tbuf4), "kms"); + len_in_units = tt.length/1000.0; + } + + // Timing information if available + tbuf1[0] = '\0'; + if ( tt.duration > 0 ) { + g_snprintf (tbuf1, sizeof(tbuf1), + _(" in %d:%02d hrs:mins"), + (int)round(tt.duration/3600), (int)round((tt.duration/60)%60)); + } + g_snprintf (tbuf2, sizeof(tbuf2), + _("\n%sTotal Length %.1f %s%s"), + tbuf3, len_in_units, tbuf4, tbuf1); + } + + // 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); + + g_date_free (gdate_start); + g_date_free (gdate_end); + + } + + return tmp_buf; +} + +static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer ) +{ + switch ( subtype ) + { + case VIK_TRW_LAYER_SUBLAYER_TRACKS: return NULL; + case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return NULL; + case VIK_TRW_LAYER_SUBLAYER_TRACK: + { + VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer ); + if ( tr ) { + // Could be a better way of handling strings - but this works... + gchar time_buf1[20]; + gchar time_buf2[20]; + time_buf1[0] = '\0'; + time_buf2[0] = '\0'; + static gchar tmp_buf[100]; + // Compact info: Short date eg (11/20/99), duration and length + // Hopefully these are the things that are most useful and so promoted into the tooltip + if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp ) { + // %x The preferred date representation for the current locale without the time. + strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(VIK_TRACKPOINT(tr->trackpoints->data)->timestamp))); + if ( VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) { + gint dur = ( (VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp) - (VIK_TRACKPOINT(tr->trackpoints->data)->timestamp) ); + if ( dur > 0 ) + g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) ); + } + } + // Get length and consider the appropriate distance units + gdouble tr_len = vik_track_get_length(tr); + vik_units_distance_t dist_units = a_vik_get_units_distance (); + switch (dist_units) { + case VIK_UNITS_DISTANCE_KILOMETRES: + g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f km %s"), time_buf1, tr_len/1000.0, time_buf2); + break; + case VIK_UNITS_DISTANCE_MILES: + g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, tr_len/1600.0, time_buf2); + break; + default: + break; + } + 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; + } + break; + default: break; + } + return NULL; +} + + GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l ) { return l->tracks; @@ -1387,13 +1752,44 @@ static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct } } +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; + } +} gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest ) { /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. like I don't have more important things to worry about... */ struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; - 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 ); + trw_layer_find_maxmin (vtl, maxmin); if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0) return FALSE; else @@ -1410,60 +1806,152 @@ static void trw_layer_centerize ( gpointer layer_and_vlp[2] ) if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) ) goto_coord ( VIK_LAYERS_PANEL(layer_and_vlp[1]), &coord ); else - a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "This layer has no waypoints or trackpoints." ); + a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") ); +} + +static void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] ) +{ + /* First set the center [in case previously viewing from elsewhere] */ + /* Then loop through zoom levels until provided positions are in view */ + /* This method is not particularly fast - but should work well enough */ + struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 }; + VikCoord coord; + vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average ); + vik_viewport_set_center_coord ( vvp, &coord ); + + /* Convert into definite 'smallest' and 'largest' positions */ + struct LatLon minmin; + if ( maxmin[0].lat < maxmin[1].lat ) + minmin.lat = maxmin[0].lat; + else + minmin.lat = maxmin[1].lat; + + struct LatLon maxmax; + if ( maxmin[0].lon > maxmin[1].lon ) + maxmax.lon = maxmin[0].lon; + else + maxmax.lon = maxmin[1].lon; + + /* Never zoom in too far - generally not that useful, as too close ! */ + /* Always recalculate the 'best' zoom level */ + gdouble zoom = 1.0; + vik_viewport_set_zoom ( vvp, zoom ); + + gdouble min_lat, max_lat, min_lon, max_lon; + /* Should only be a maximum of about 18 iterations from min to max zoom levels */ + while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) { + vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon ); + /* NB I think the logic used in this test to determine if the bounds is within view + fails if track goes across 180 degrees longitude. + Hopefully that situation is not too common... + Mind you viking doesn't really do edge locations to well anyway */ + if ( min_lat < minmin.lat && + max_lat > minmin.lat && + min_lon < maxmax.lon && + max_lon > maxmax.lon ) + /* Found within zoom level */ + break; + + /* Try next */ + zoom = zoom * 2; + vik_viewport_set_zoom ( vvp, zoom ); + } +} + +gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp ) +{ + /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. */ + struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; + trw_layer_find_maxmin (vtl, maxmin); + if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0) + return FALSE; + else { + trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin ); + return TRUE; + } +} + +static void trw_layer_auto_view ( gpointer layer_and_vlp[2] ) +{ + if ( vik_trw_layer_auto_set_view ( VIK_TRW_LAYER(layer_and_vlp[0]), vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(layer_and_vlp[1])) ) ) { + vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) ); + } + else + 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], guint file_type ) +static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, const gchar* trackname, guint file_type ) { GtkWidget *file_selector; const gchar *fn; gboolean failed = FALSE; - file_selector = gtk_file_selection_new ("Export Layer"); - gtk_file_selection_set_filename (GTK_FILE_SELECTION(file_selector), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0]))); - - while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_OK ) + file_selector = gtk_file_chooser_dialog_new (title, + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name); + + while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT ) { - fn = gtk_file_selection_get_filename (GTK_FILE_SELECTION(file_selector) ); - if ( access ( fn, F_OK ) != 0 ) + fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) ); + if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE ) { gtk_widget_hide ( file_selector ); - failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type ); + failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname); break; } else { - if ( a_dialog_overwrite ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "The file \"%s\" exists, do you wish to overwrite it?", a_file_basename ( fn ) ) ) + if ( a_dialog_overwrite ( 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 ); + failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trackname); break; } } } gtk_widget_destroy ( file_selector ); if ( failed ) - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "The filename you requested could not be opened for writing." ); + a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The filename you requested could not be opened for writing.") ); } static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] ) { - trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSPOINT ); + trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSPOINT ); } static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] ) { - trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSMAPPER ); + trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSMAPPER ); } static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] ) { - trw_layer_export ( layer_and_vlp, FILE_TYPE_GPX ); + trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPX ); +} + +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]; + + /* 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] ); + 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 ); + + g_free ( auto_save_name ); } 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 ("Create", + 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, GTK_STOCK_CANCEL, @@ -1473,7 +1961,7 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) NULL); GtkWidget *label, *entry; - label = gtk_label_new("Waypoint Name:"); + label = gtk_label_new(_("Waypoint Name:")); entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dia)->vbox), label, FALSE, FALSE, 0); @@ -1481,6 +1969,8 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) gtk_widget_show_all ( label ); gtk_widget_show_all ( entry ); + gtk_dialog_set_default_response ( GTK_DIALOG(dia), GTK_RESPONSE_ACCEPT ); + while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT ) { VikWaypoint *wp; @@ -1493,7 +1983,7 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) wp = g_hash_table_lookup ( wps, upname ); if (!wp) - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), "Waypoint not found in this layer." ); + a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(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) ); @@ -1510,10 +2000,9 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord ) { - gchar *name; + gchar *name = highest_wp_number_get(vtl); VikWaypoint *wp = vik_waypoint_new(); wp->coord = *def_coord; - wp->altitude = VIK_DEFAULT_ALTITUDE; if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) ) { @@ -1525,6 +2014,49 @@ gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikC return FALSE; } +static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ) +{ + VikCoord one, two; + struct LatLon one_ll, two_ll; + struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; + + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)); + VikViewport *vvp = vik_window_viewport(vw); + vik_viewport_screen_to_coord ( vvp, 0, 0, &one); + vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &two); + vik_coord_to_latlon(&one, &one_ll); + vik_coord_to_latlon(&two, &two_ll); + if (one_ll.lat > two_ll.lat) { + maxmin[0].lat = one_ll.lat; + maxmin[1].lat = two_ll.lat; + } + else { + maxmin[0].lat = two_ll.lat; + maxmin[1].lat = one_ll.lat; + } + if (one_ll.lon > two_ll.lon) { + maxmin[0].lon = one_ll.lon; + maxmin[1].lon = two_ll.lon; + } + else { + maxmin[0].lon = two_ll.lon; + maxmin[1].lon = one_ll.lon; + } + a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin); +} + +static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]); + struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} }; + + trw_layer_find_maxmin (vtl, maxmin); + a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, vlp, maxmin); +} + static void trw_layer_new_wp ( gpointer lav[2] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); @@ -1535,11 +2067,52 @@ static void trw_layer_new_wp ( gpointer lav[2] ) vik_layers_panel_emit_update ( vlp ); } +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 ); +} + void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp ) { static gpointer pass_along[2]; GtkWidget *item; GtkWidget *export_submenu; + GtkWidget *wikipedia_submenu; pass_along[0] = vtl; pass_along[1] = vlp; @@ -1547,48 +2120,95 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Goto Center of Layer" ); + 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 ); + + 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 ); + + 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 ); + + 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 ); - item = gtk_menu_item_new_with_label ( "Goto Waypoint" ); + 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_label ( "Export layer" ); + item = gtk_menu_item_new_with_mnemonic ( _("_Export Layer") ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu ); - item = gtk_menu_item_new_with_label ( "Export as GPSPoint" ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Export as GPSMapper" ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Export as GPX" ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "New Waypoint" ); + item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); +#ifdef VIK_CONFIG_GEONAMES + wikipedia_submenu = gtk_menu_new(); + item = gtk_menu_item_new_with_mnemonic ( _("_Add Wikipedia Waypoints") ); + 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") ); + 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") ); + 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_OPENSTREETMAP - item = gtk_menu_item_new_with_label ( "Upload to OSM" ); + item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM") ); 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_widget_show ( item ); #endif + + item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp, + vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl ); + if ( item ) { + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + } + + item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp, + vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl ); + if ( item ) { + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + } } void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp ) @@ -1601,19 +2221,20 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp else { 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 ); #else vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, name, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, NULL, TRUE, TRUE ); #endif + // Actual setting of visibility dependent on the waypoint + vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible ); vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter ); g_hash_table_insert ( vtl->waypoints_iters, name, iter ); - wp->visible = TRUE; } } - else - wp->visible = TRUE; + highest_wp_number_add_wp(vtl, name); g_hash_table_insert ( vtl->waypoints, name, wp ); } @@ -1628,40 +2249,25 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) else { 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 ); #else vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, name, 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 ); vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter ); g_hash_table_insert ( vtl->tracks_iters, name, iter ); - /* t->visible = TRUE; */ } } - else - ; /* t->visible = TRUE; // this is now used by file input functions */ g_hash_table_insert ( vtl->tracks, name, t ); } -static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str ) -{ - gchar *upp = g_strdup ( str ); - gboolean rv; - char *tmp = upp; - while ( *tmp ) - { - *tmp = toupper(*tmp); - tmp++; - } - rv = g_hash_table_lookup ( hash, upp ) ? TRUE : FALSE; - g_free (upp); - return rv; -} - /* to be called whenever a track has been deleted or may have been changed. */ -static void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name ) +void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name ) { if (vtl->current_tp_track_name && g_strcasecmp(trk_name, vtl->current_tp_track_name) == 0) trw_layer_cancel_current_tp ( vtl, FALSE ); @@ -1810,6 +2416,8 @@ gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name 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 ); + + highest_wp_number_remove_wp(vtl, wp_name); g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */ } @@ -1845,6 +2453,8 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) vtl->current_wp_name = NULL; vtl->moving_wp = FALSE; + highest_wp_number_reset(vtl); + g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); g_hash_table_remove_all(vtl->waypoints_iters); g_hash_table_remove_all(vtl->waypoints); @@ -1857,7 +2467,7 @@ static void trw_layer_delete_item ( gpointer pass_along[5] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); gboolean was_visible = FALSE; - if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) + if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] ); } @@ -1873,7 +2483,7 @@ static void trw_layer_delete_item ( gpointer pass_along[5] ) static void trw_layer_properties_item ( gpointer pass_along[5] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); - if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) + 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 ) @@ -1889,55 +2499,10 @@ static void trw_layer_properties_item ( gpointer pass_along[5] ) VikTrack *tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] ); if ( tr ) { - gint resp = vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), tr, pass_along[1] /* vlp */ ); - if ( resp == VIK_TRW_LAYER_PROPWIN_DEL_DUP ) - { - vik_track_remove_dup_points(tr); - /* above operation could have deleted current_tp or last_tp */ - trw_layer_cancel_tps_of_track ( vtl, (gchar *) pass_along[3] ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); - } - if ( resp == VIK_TRW_LAYER_PROPWIN_REVERSE ) - { - vik_track_reverse(tr); - vik_layer_emit_update ( VIK_LAYER(vtl) ); - } - else if ( resp == VIK_TRW_LAYER_PROPWIN_SPLIT ) - { - /* get new tracks, add them, resolve naming conflicts (free if cancel), and delete old. old can still exist on clipboard. */ - guint ntracks; - VikTrack **tracks = vik_track_split_into_segments(tr, &ntracks); - gchar *new_tr_name; - guint i; - for ( i = 0; i < ntracks; i++ ) - { - g_assert ( tracks[i] ); - new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i+1); - /* if ( (wp_exists) && (! overwrite) ) */ - /* don't need to upper case new_tr_name because old tr name was uppercase */ - if ( g_hash_table_lookup ( vtl->tracks, new_tr_name ) && - ( ! a_dialog_overwrite ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "The track \"%s\" exists, do you wish to overwrite it?", new_tr_name ) ) ) - { - gchar *new_new_tr_name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ); - g_free ( new_tr_name ); - if (new_new_tr_name) - new_tr_name = new_new_tr_name; - else - { - new_tr_name = NULL; - vik_track_free ( tracks[i] ); - } - } - if ( new_tr_name ) - vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] ); - } - if ( tracks ) - { - g_free ( tracks ); - vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); /* chase thru the hoops */ - } - } + vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl, tr, + pass_along[1], /* vlp */ + pass_along[3] /* track name */); } } } @@ -1957,6 +2522,7 @@ static void trw_layer_goto_track_startpoint ( gpointer pass_along[5] ) static void trw_layer_goto_track_center ( gpointer pass_along[5] ) { + /* 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 ) { @@ -1970,6 +2536,37 @@ static void trw_layer_goto_track_center ( gpointer pass_along[5] ) } } +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] ); + + vtl->current_track = track; + vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK); + + if ( track->trackpoints ) + goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) ); +} + +/** + * extend a track using magic scissors + */ +static void trw_layer_extend_track_end_ms ( 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; + + if ( track->trackpoints ) + goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &last_coord) ; + +} + static void trw_layer_apply_dem_data ( gpointer pass_along[6] ) { /* TODO: check & warn if no DEM data, or no applicable DEM data. */ @@ -1988,11 +2585,83 @@ static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(((VikTrackpoint *) trps->data)->coord)); } +static void trw_layer_goto_track_max_speed ( gpointer pass_along[5] ) +{ + VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) ); + if ( !vtp ) + return; + goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(vtp->coord)); +} + +static void trw_layer_goto_track_max_alt ( gpointer pass_along[5] ) +{ + VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) ); + if ( !vtp ) + return; + goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(vtp->coord)); +} + +static void trw_layer_goto_track_min_alt ( gpointer pass_along[5] ) +{ + VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ) ); + if ( !vtp ) + return; + goto_coord ( VIK_LAYERS_PANEL(pass_along[1]), &(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] ) +{ + GList **trps = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + if ( trps && *trps ) + { + struct LatLon maxmin[2] = { {0,0}, {0,0} }; + trw_layer_find_maxmin_tracks ( NULL, trps, maxmin ); + + trw_layer_zoom_to_show_latlons ( VIK_TRW_LAYER(pass_along[0]), vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(pass_along[1])), maxmin ); + vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) ); + } +} /************************************* * merge/split by time routines *************************************/ +/* called for each key in track hash table. + * If the current track has time stamp, 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). + */ +typedef struct { + GList **result; + GList *exclude; +} twt_udata; +static void find_tracks_with_timestamp(gpointer key, gpointer value, gpointer udata) +{ + twt_udata *user_data = udata; + VikTrackpoint *p1, *p2; + + if (VIK_TRACK(value)->trackpoints == user_data->exclude) { + return; + } + + if (VIK_TRACK(value)->trackpoints) { + p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data); + p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data); + + if (!p1->has_timestamp || !p2->has_timestamp) { + g_print("no timestamp\n"); + 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] */ @@ -2003,31 +2672,40 @@ static void find_nearby_track(gpointer key, gpointer value, gpointer user_data) GList **nearby_tracks = ((gpointer *)user_data)[0]; GList *orig_track = ((gpointer *)user_data)[1]; - guint thr = (guint)((gpointer *)user_data)[2]; + guint thr = GPOINTER_TO_UINT (((gpointer *)user_data)[2]); - t1 = VIK_TRACKPOINT(orig_track->data)->timestamp; - t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp; + /* 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) { return; } - p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data); - p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data); + t1 = VIK_TRACKPOINT(orig_track->data)->timestamp; + t2 = VIK_TRACKPOINT(g_list_last(orig_track)->data)->timestamp; - if (!p1->has_timestamp || !p2->has_timestamp) { - g_print("no timestamp\n"); - return; - } + if (VIK_TRACK(value)->trackpoints) { + p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data); + p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data); + + if (!p1->has_timestamp || !p2->has_timestamp) { + 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 || - /* p1 p2 t1 t2 */ - abs(p1->timestamp - t2) < thr*60 - /* t1 t2 p1 p2 */ - ) { - *nearby_tracks = g_list_prepend(*nearby_tracks, key); + /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */ + if (! (abs(t1 - p2->timestamp) < thr*60 || + /* p1 p2 t1 t2 */ + abs(p1->timestamp - t2) < thr*60) + /* t1 t2 p1 p2 */ + ) { + return; + } } + + *nearby_tracks = g_list_prepend(*nearby_tracks, key); } /* comparison function used to sort tracks; a and b are hash table keys */ @@ -2054,29 +2732,85 @@ static gint trackpoint_compare(gconstpointer a, gconstpointer b) return 0; } +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 ); + + 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")); + return; + } + + if (1) { + + 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); + } + + if (!tracks_with_timestamp) { + a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp")); + return; + } + + GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl->tracks, tracks_with_timestamp, TRUE, + _("Merge with..."), _("Select track to merge with")); + g_list_free(tracks_with_timestamp); + + 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); + } + } + /* 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) ); + } +} + /* 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 = NULL; + GList *nearby_tracks; VikTrack *track; GList *trps; static guint thr = 1; guint track_count = 0; - gchar *orig_track_name = strdup(pass_along[3]); - if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), - "Merge Threshold...", - "Merge when time between trackpoints less than:", + 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); return; } /* merge tracks until we can't */ + nearby_tracks = NULL; do { gpointer params[3]; - track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, orig_track_name ); + track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, orig_track_name ); trps = track->trackpoints; if ( !trps ) return; @@ -2093,20 +2827,17 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) /* g_print("Original track times: %d and %d\n", t1, t2); */ params[0] = &nearby_tracks; params[1] = trps; - params[2] = (gpointer)thr; + params[2] = GUINT_TO_POINTER (thr); /* get a list of adjacent-in-time tracks */ - g_hash_table_foreach(VIK_TRW_LAYER(pass_along[0])->tracks, find_nearby_track, (gpointer)params); + g_hash_table_foreach(vtl->tracks, find_nearby_track, (gpointer)params); /* add original track */ nearby_tracks = g_list_prepend(nearby_tracks, orig_track_name); - /* sort by first trackpoint; assumes they don't overlap */ - nearby_tracks = g_list_sort_with_data(nearby_tracks, track_compare, VIK_TRW_LAYER(pass_along[0])->tracks); - /* merge them */ { -#define get_track(x) VIK_TRACK(g_hash_table_lookup(VIK_TRW_LAYER(pass_along[0])->tracks, (gchar *)((x)->data))) +#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; @@ -2125,13 +2856,13 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) /* 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(VIK_TRW_LAYER(pass_along[0]), l->data); + vik_trw_layer_delete_track(vtl, l->data); track_count ++; l = g_list_next(l); } tr->trackpoints = g_list_sort(tr->trackpoints, trackpoint_compare); - vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), strdup(orig_track_name), tr); + vik_trw_layer_add_track(vtl, strdup(orig_track_name), tr); #undef get_first_trackpoint #undef get_last_trackpoint @@ -2140,7 +2871,7 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) } while (track_count > 1); g_list_free(nearby_tracks); free(orig_track_name); - vik_layer_emit_update(VIK_LAYER(pass_along[0])); + vik_layer_emit_update( VIK_LAYER(vtl) ); } /* split by time routine */ @@ -2160,8 +2891,8 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) return; if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), - "Split Threshold...", - "Split when time between trackpoints exceeds:", + _("Split Threshold..."), + _("Split when time between trackpoints exceeds:"), &thr)) { return; } @@ -2227,18 +2958,7 @@ static void trw_layer_goto_waypoint ( gpointer pass_along[5] ) static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[5] ) { gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", (gchar *) pass_along[3] ); -#ifdef WINDOWS - ShellExecute(NULL, NULL, (char *) webpage, NULL, ".\\", 0); -#else /* WINDOWS */ - GError *err = NULL; - gchar *cmd = g_strdup_printf ( "%s %s", UNIX_WEB_BROWSER, webpage ); - if ( ! g_spawn_command_line_async ( cmd, &err ) ) - { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), "Could not launch web browser." ); - g_error_free ( err ); - } - g_free ( cmd ); -#endif /* WINDOWS */ + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage); g_free ( webpage ); } @@ -2246,31 +2966,32 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar { if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - int i; gchar *rv; VikWaypoint *wp; - if ( strcasecmp ( newname, sublayer ) == 0 ) + if (strcmp(newname, sublayer) == 0 ) return NULL; - if ( uppercase_exists_in_hash ( l->waypoints, newname ) ) - { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), "Waypoint Already Exists" ); - 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") ); + return NULL; + } } iter = g_hash_table_lookup ( l->waypoints_iters, sublayer ); g_hash_table_steal ( l->waypoints_iters, sublayer ); 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); - for ( i = strlen(rv) - 1; i >= 0; i-- ) - rv[i] = toupper(rv[i]); 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 ); @@ -2284,19 +3005,20 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar } if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { - int i; gchar *rv; VikTrack *tr; GtkTreeIter *iter; gchar *orig_key; - if ( strcasecmp ( newname, sublayer ) == 0 ) + if (strcmp(newname, sublayer) == 0) return NULL; - if ( uppercase_exists_in_hash ( l->tracks, newname ) ) - { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), "Track Already Exists" ); - 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") ); + return NULL; + } } g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr ); @@ -2306,8 +3028,6 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar g_hash_table_steal ( l->tracks_iters, sublayer ); rv = g_strdup(newname); - for ( i = strlen(rv) - 1; i >= 0; i-- ) - rv[i] = toupper(rv[i]); vik_treeview_item_set_pointer ( VIK_LAYER(l)->vt, iter, rv ); @@ -2342,6 +3062,13 @@ static gboolean is_valid_geocache_name ( gchar *str ) return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6])); } +static void trw_layer_track_use_with_filter ( gpointer *pass_along ) +{ + 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 ); +} + static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gchar *track_name ) { VikTrack *tr = g_hash_table_lookup ( vtl->tracks, track_name ); @@ -2355,16 +3082,8 @@ static void trw_layer_track_google_route_webpage( gpointer *pass_along ) 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 ); - GError *err = NULL; - gchar *cmd = g_strdup_printf ( "%s %s", UNIX_WEB_BROWSER, webpage ); - - if ( ! g_spawn_command_line_async ( cmd, &err ) ) - { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), "Could not launch web browser." ); - g_error_free ( err ); - } + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage); g_free ( escaped ); - g_free ( cmd ); g_free ( webpage ); } } @@ -2379,7 +3098,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, pass_along[0] = l; pass_along[1] = vlp; - pass_along[2] = (gpointer) subtype; + pass_along[2] = GINT_TO_POINTER (subtype); pass_along[3] = sublayer; staticiter = *iter; /* will exist after function has ended */ pass_along[4] = &staticiter; @@ -2393,6 +3112,13 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) { + VikTrwLayer *vtl = l; + VikTrack *tr = g_hash_table_lookup ( vtl->tracks, sublayer ); + if (tr && tr->property_dialog) + gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE ); + } + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); @@ -2412,7 +3138,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, { /* could be a right-click using the tool */ if ( vlp != NULL ) { - item = gtk_menu_item_new_with_label ( "Goto" ); + item = gtk_menu_item_new_with_mnemonic ( _("_Goto") ); 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 ); @@ -2420,7 +3146,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, if ( is_valid_geocache_name ( (gchar *) sublayer ) ) { - item = gtk_menu_item_new_with_label ( "Visit Geocache Webpage" ); + 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 ); @@ -2431,47 +3157,94 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { + GtkWidget *goto_submenu; item = gtk_menu_item_new (); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Goto Startpoint" ); + goto_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("_Goto") ); + 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") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Goto \"Center\"" ); + item = gtk_menu_item_new_with_mnemonic ( _("\"_Center\"") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along ); - gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Goto Endpoint" ); + item = gtk_menu_item_new_with_mnemonic ( _("_Endpoint") ); 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") ); + 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") ); + 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 ); + + 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 ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Merge By Time" ); + 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 ); - item = gtk_menu_item_new_with_label ( "Split By Time" ); + 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_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 ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Download maps along track..." ); + item = gtk_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") ); 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_label ( "Apply DEM Data" ); + item = gtk_menu_item_new_with_mnemonic ( _("_Apply DEM Data") ); 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") ); + 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") ); + 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 Magic Scissors") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_ms), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + #ifdef VIK_CONFIG_OPENSTREETMAP - item = gtk_menu_item_new_with_label ( "Upload to OSM" ); + item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM") ); 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_widget_show ( item ); @@ -2479,12 +3252,24 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, if ( is_valid_google_route ( l, (gchar *) sublayer ) ) { - item = gtk_menu_item_new_with_label ( "View Google Directions" ); + item = gtk_menu_item_new_with_mnemonic ( _("_View Google Directions") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_google_route_webpage), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); } + item = gtk_menu_item_new_with_mnemonic ( _("Use with _Filter") ); + 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 ); + + 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 ) ); + if ( item ) { + 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) ) @@ -2493,7 +3278,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "New Waypoint" ); + item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint") ); 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 ); @@ -2502,6 +3287,58 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, return rv; } +static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ) +{ + /* sanity checks */ + if (!vtl->current_tpl) + return; + if (!vtl->current_tpl->next) + return; + + VikTrackpoint *tp_current = VIK_TRACKPOINT(vtl->current_tpl->data); + VikTrackpoint *tp_next = VIK_TRACKPOINT(vtl->current_tpl->next->data); + + /* Use current and next trackpoints to form a new track point which is inserted into the tracklist */ + if ( tp_next ) { + + VikTrackpoint *tp_new = vik_trackpoint_new(); + struct LatLon ll_current, ll_next; + vik_coord_to_latlon ( &tp_current->coord, &ll_current ); + vik_coord_to_latlon ( &tp_next->coord, &ll_next ); + + /* main positional interpolation */ + struct LatLon ll_new = { (ll_current.lat+ll_next.lat)/2, (ll_current.lon+ll_next.lon)/2 }; + vik_coord_load_from_latlon ( &(tp_new->coord), vtl->coord_mode, &ll_new ); + + /* Now other properties that can be interpolated */ + tp_new->altitude = (tp_current->altitude + tp_next->altitude) / 2; + + if (tp_current->has_timestamp && tp_next->has_timestamp) { + /* Note here the division is applied to each part, then added + This is to avoid potential overflow issues with a 32 time_t for dates after midpoint of this Unix time on 2004/01/04 */ + tp_new->timestamp = (tp_current->timestamp/2) + (tp_next->timestamp/2); + tp_new->has_timestamp = TRUE; + } + + if (tp_current->speed != NAN && tp_next->speed != NAN) + tp_new->speed = (tp_current->speed + tp_next->speed)/2; + + /* TODO - improve interpolation of course, as it may not be correct. + if courses in degrees are 350 + 020, the mid course more likely to be 005 (not 185) + [similar applies if value is in radians] */ + if (tp_current->course != NAN && tp_next->course != NAN) + tp_new->speed = (tp_current->course + tp_next->course)/2; + + /* 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 ); + if ( index > -1 ) { + tr->trackpoints = g_list_insert (tr->trackpoints, tp_new, index+1 ); + } + } +} /* to be called when last_tpl no long exists. */ static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl ) @@ -2540,7 +3377,7 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev ) { gchar *name; - if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks ) ) ) + if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks, NULL ) ) ) { VikTrack *tr = vik_track_new (); GList *newglist = g_list_alloc (); @@ -2557,6 +3394,8 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) 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)); } @@ -2645,6 +3484,11 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */ vik_layer_emit_update(VIK_LAYER(vtl)); } + else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next ) + { + trw_layer_insert_tp_after_current_tp ( vtl ); + vik_layer_emit_update(VIK_LAYER(vtl)); + } else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED ) vik_layer_emit_update (VIK_LAYER(vtl)); } @@ -2797,6 +3641,7 @@ static void marker_moveto ( tool_ed_t *t, gint x, gint y ) vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 ); t->oldx = x; t->oldy = y; + if (tool_sync_done) { g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL); tool_sync_done = FALSE; @@ -2833,6 +3678,9 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve return TRUE; } + if ( !vtl->vl.visible || !vtl->waypoints_visible ) + return FALSE; + if ( vtl->current_wp && vtl->current_wp->visible ) { /* first check if current WP is within area (other may be 'closer', but we want to move the current) */ @@ -2890,7 +3738,7 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve return FALSE; } -static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ) { tool_ed_t *t = data; VikViewport *vvp = t->vvp; @@ -2921,6 +3769,7 @@ static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *even { gint x, y; vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y ); + marker_moveto ( t, x, y ); } return TRUE; @@ -2976,6 +3825,18 @@ static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *e return FALSE; } +/**** Begin track ***/ +static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + vtl->current_track = NULL; + return tool_new_track_click ( vtl, event, vvp ); +} + /*** New track ****/ static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp) @@ -2983,6 +3844,76 @@ static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp) return 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 ); + return FALSE; +} + +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; + 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 ); + + passalong = g_new(new_track_move_passalong_t,1); /* freed by 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; + return VIK_LAYER_TOOL_ACK_GRAB_FOCUS; + } + return VIK_LAYER_TOOL_ACK; +} + +static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ) +{ + if ( vtl->current_track && event->keyval == GDK_Escape ) { + vtl->current_track = NULL; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) { + /* undo */ + if ( vtl->current_track->trackpoints ) + { + GList *last = g_list_last(vtl->current_track->trackpoints); + g_free ( last->data ); + vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); + } + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + return FALSE; +} + static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { VikTrackpoint *tp; @@ -3014,17 +3945,21 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, /* undo last, then end */ vtl->current_track = NULL; } + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } if ( ! vtl->current_track ) { - gchar *name; - if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ) ) ) + 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; @@ -3043,7 +3978,6 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, tp->newsegment = FALSE; tp->has_timestamp = FALSE; tp->timestamp = 0; - tp->altitude = VIK_DEFAULT_ALTITUDE; vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp ); vtl->ct_x1 = vtl->ct_x2; @@ -3109,6 +4043,9 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e if (!vtl || vtl->vl.type != VIK_LAYER_TRW) return FALSE; + if ( !vtl->vl.visible || !vtl->tracks_visible ) + 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.) */ @@ -3146,7 +4083,7 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e return FALSE; } -static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ) { tool_ed_t *t = data; VikViewport *vvp = t->vvp; @@ -3247,11 +4184,12 @@ static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *ev } else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) { struct LatLon start, end; - gchar *cmd; + 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 ( &(tmp), &end ); - cmd = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, start.lat, start.lon, end.lat, end.lon ); vtl->magic_scissors_coord = tmp; /* for continuations */ /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */ @@ -3262,8 +4200,13 @@ static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *ev vtl->magic_scissors_started = FALSE; } - a_babel_convert_from_shellcommand ( vtl, cmd, "google", NULL, NULL ); - g_free ( cmd ); + url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, + g_ascii_dtostr (startlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lat), + g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon), + g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat), + g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon)); + a_babel_convert_from_url ( vtl, url, "kml", 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 ) { @@ -3272,7 +4215,7 @@ static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *ev 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 ) ); + 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; @@ -3341,7 +4284,7 @@ static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *even g_free ( quoted_file ); if ( ! g_spawn_command_line_async ( cmd, &err ) ) { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." ); + a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch eog to open file.") ); g_error_free ( err ); } g_free ( cmd ); @@ -3395,7 +4338,7 @@ static void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp ) if ( pics ) { gint len = g_slist_length ( pics ); - gchar *tmp = g_strdup_printf ( "Creating %d Image Thumbnails...", len ); + gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len ); a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl), tmp, (vik_thr_func) create_thumbnails_thread, pics, (vik_thr_free_func) free_pics_slist, NULL, len ); g_free ( tmp ); } @@ -3434,7 +4377,7 @@ 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, gchar *name ) +VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name ) { return g_hash_table_lookup ( vtl->tracks, name ); } @@ -3554,17 +4497,22 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g new_map = TRUE; } - /* fill-ins for far apart points */ - GList *cur_rect, *next_rect; GList *fillins = NULL; - for (cur_rect = rects_to_download; - (next_rect = cur_rect->next) != NULL; - cur_rect = cur_rect->next) { - if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) || - (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) { - fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh); + /* 'fillin' doesn't work in UTM mode - potentially ending up in massive loop continually allocating memory - hence don't do it */ + /* seems that ATM the function get_next_coord works only for LATLON */ + if ( cur_coord->mode == VIK_COORD_LATLON ) { + /* fill-ins for far apart points */ + GList *cur_rect, *next_rect; + for (cur_rect = rects_to_download; + (next_rect = cur_rect->next) != NULL; + cur_rect = cur_rect->next) { + if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) || + (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) { + fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh); + } } - } + } else + g_message("%s: this feature works only in Mercator mode", __FUNCTION__); if (fillins) { GList *iter = fillins; @@ -3615,7 +4563,7 @@ static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]) int num_maps = g_list_length(vmls); if (!num_maps) { - a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR,"No map layer in use. Create one first", NULL); + a_dialog_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), GTK_MESSAGE_ERROR, _("No map layer in use. Create one first"), NULL); return; } @@ -3672,3 +4620,57 @@ done: } +/**** lowest waypoint number calculation ***/ +static gint highest_wp_number_name_to_number(const gchar *name) { + if ( strlen(name) == 3 ) { + int n = atoi(name); + if ( n < 100 && name[0] != '0' ) + return -1; + if ( n < 10 && name[0] != '0' ) + return -1; + return n; + } + return -1; +} + + +static void highest_wp_number_reset(VikTrwLayer *vtl) +{ + vtl->highest_wp_number = -1; +} + +static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name) +{ + /* if is bigger that top, add it */ + gint new_wp_num = highest_wp_number_name_to_number(new_wp_name); + if ( new_wp_num > vtl->highest_wp_number ) + vtl->highest_wp_number = new_wp_num; +} + +static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name) +{ + /* if wasn't top, do nothing. if was top, count backwards until we find one used */ + 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 --; + + 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 --; + g_snprintf(buf,4,"%03d", vtl->highest_wp_number ); + } + } +} + +/* get lowest unused number */ +static gchar *highest_wp_number_get(VikTrwLayer *vtl) +{ + gchar buf[4]; + if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 ) + return NULL; + g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 ); + return g_strdup(buf); +}