X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/e4afc73a345f54f278134db0a9641394411410be..de2fc9aa9e8db8e0258c8328161c6b5eda176a0a:/src/viktrwlayer.c?ds=sidebyside diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index acf98a0b..9fb218ed 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -24,18 +24,48 @@ /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */ /* viktrwlayer.c -- 2200 lines can make a difference in the state of things */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "viking.h" -#include "viktrwlayer_pixmap.h" +#include "vikmapslayer.h" #include "viktrwlayer_tpwin.h" #include "viktrwlayer_propwin.h" +#include "garminsymbols.h" #include "thumbnails.h" #include "background.h" +#include "gpx.h" +#include "babel.h" +#include "dem.h" +#include "dems.h" +#include "googlesearch.h" +#ifdef VIK_CONFIG_OPENSTREETMAP +#include "osm-traces.h" +#endif +#include "acquire.h" +#include "util.h" + +#include "icons/icons.h" #include #include #include +#include #include +#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=js" #define VIK_TRW_LAYER_TRACK_GC 13 #define VIK_TRW_LAYER_TRACK_GC_RATES 10 #define VIK_TRW_LAYER_TRACK_GC_MIN 0 @@ -86,10 +116,12 @@ struct _VikTrwLayer { guint8 wp_symbol; guint8 wp_size; + gboolean wp_draw_symbols; 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; @@ -97,6 +129,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; @@ -118,6 +152,14 @@ struct _VikTrwLayer { /* track editing tool -- more specifically, moving tps */ gboolean moving_tp; + /* magic scissors tool */ + gboolean magic_scissors_started; + VikCoord magic_scissors_coord; + gboolean magic_scissors_check_added_track; + gchar *magic_scissors_added_track_name; + VikTrack *magic_scissors_current_track; + gboolean magic_scissors_append; + gboolean drawlabels; gboolean drawimages; guint8 image_alpha; @@ -132,6 +174,10 @@ struct _VikTrwLayer { GtkMenu *wp_right_click_menu; + /* menu */ + VikStdLayerMenuItem menu_selection; + + gint highest_wp_number; }; /* A caached waypoint image. */ @@ -151,6 +197,13 @@ struct DrawingParams { gdouble ce1, ce2, cn1, cn2; }; +static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16); +static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl); + +static void trw_layer_delete_item ( gpointer *pass_along ); +static void trw_layer_copy_item_cb( gpointer *pass_along); +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] ); @@ -166,6 +219,7 @@ 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_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_goto_wp ( gpointer layer_and_vlp[2] ); @@ -180,30 +234,45 @@ static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] ); static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp ); -static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ); +static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ); +static VikTrwLayer *trw_layer_unmarshall( gpointer 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 gpointer trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ); -static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer item ); +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 ); +static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len ); static void trw_layer_free_copied_item ( gint subtype, gpointer item ); +static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path ); -static void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name ); static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl ); static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy ); static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ); static void trw_layer_tpwin_init ( VikTrwLayer *vtl ); -static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +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, 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, 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 ); @@ -214,22 +283,52 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode ); +static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name); +static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode ); +static void 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", (VikToolInterfaceFunc) tool_new_waypoint, NULL }, - { "Create Track", (VikToolInterfaceFunc) tool_new_track, NULL }, - { "Edit Waypoint", (VikToolInterfaceFunc) tool_edit_waypoint, (VikToolInterfaceFunc) tool_edit_waypoint_release }, - { "Edit Trackpoint", (VikToolInterfaceFunc) tool_edit_trackpoint, (VikToolInterfaceFunc) tool_edit_trackpoint_release }, - { "Show Picture", (VikToolInterfaceFunc) tool_show_picture, NULL }, -}; + { N_("Create Waypoint"), (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf }, + + { N_("Create Track"), (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_new_track_click, (VikToolMouseMoveFunc) tool_new_track_move, NULL, + (VikToolKeyFunc) tool_new_track_key_press, GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf }, + + { N_("Begin Track"), (VikToolConstructorFunc) tool_begin_track_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_begin_track_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf }, + + { N_("Edit Waypoint"), (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_edit_waypoint_click, + (VikToolMouseMoveFunc) tool_edit_waypoint_move, + (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf }, + { N_("Edit Trackpoint"), (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_edit_trackpoint_click, + (VikToolMouseMoveFunc) tool_edit_trackpoint_move, + (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf }, + + { N_("Show Picture"), (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_show_picture_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf }, + + { N_("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[] = { @@ -251,42 +350,48 @@ 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, params_drawmodes }, - { "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 symbol:", VIK_LAYER_WIDGET_RADIOGROUP, params_wpsymbols }, - { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint size:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 }, - - { "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_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS }; +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 }; + +/*** TO ADD A PARAM: + *** 1) Add to trw_layer_params and enumeration + *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct) + ***/ /****** END PARAMETERS ******/ VikLayerInterface vik_trw_layer_interface = { "TrackWaypoint", - &trwlayer_pixbuf, + &viktrwlayer_pixbuf, trw_layer_tools, sizeof(trw_layer_tools) / sizeof(VikToolInterface), @@ -296,6 +401,8 @@ VikLayerInterface vik_trw_layer_interface = { params_groups, /* params_groups */ sizeof(params_groups)/sizeof(params_groups[0]), /* number of groups */ + VIK_MENU_ITEM_ALL, + (VikLayerFuncCreate) vik_trw_layer_create, (VikLayerFuncRealize) vik_trw_layer_realize, (VikLayerFuncPostRead) trw_layer_verify_thumbnails, @@ -305,13 +412,17 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncDraw) vik_trw_layer_draw, (VikLayerFuncChangeCoordMode) trw_layer_change_coord_mode, + (VikLayerFuncSetMenuItemsSelection) vik_trw_layer_set_menu_selection, + (VikLayerFuncGetMenuItemsSelection) vik_trw_layer_get_menu_selection, + (VikLayerFuncAddMenuItems) vik_trw_layer_add_menu_items, (VikLayerFuncSublayerAddMenuItems) vik_trw_layer_sublayer_add_menu_items, (VikLayerFuncSublayerRenameRequest) vik_trw_layer_sublayer_rename_request, (VikLayerFuncSublayerToggleVisible) vik_trw_layer_sublayer_toggle_visible, - (VikLayerFuncCopy) trw_layer_copy, + (VikLayerFuncMarshall) trw_layer_marshall, + (VikLayerFuncUnmarshall) trw_layer_unmarshall, (VikLayerFuncSetParam) trw_layer_set_param, (VikLayerFuncGetParam) trw_layer_get_param, @@ -319,21 +430,21 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncReadFileData) a_gpspoint_read_file, (VikLayerFuncWriteFileData) a_gpspoint_write_file, + (VikLayerFuncDeleteItem) trw_layer_del_item, (VikLayerFuncCopyItem) trw_layer_copy_item, (VikLayerFuncPasteItem) trw_layer_paste_item, (VikLayerFuncFreeCopiedItem) trw_layer_free_copied_item, + + (VikLayerFuncDragDropRequest) trw_layer_drag_drop_request, }; /* for copy & paste (I think?) */ typedef struct { - gchar *name; - VikWaypoint *wp; -} NamedWaypoint; - -typedef struct { - gchar *name; - VikTrack *tr; -} NamedTrack; + guint len; + guint8 data[0]; + // gchar *name; + // VikWaypoint *wp; +} FlatItem; GType vik_trw_layer_get_type () { @@ -359,39 +470,94 @@ GType vik_trw_layer_get_type () return vtl_type; } +static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ) +{ + static gpointer pass_along[5]; + if (!sublayer) { + return; + } + + pass_along[0] = vtl; + pass_along[1] = NULL; + pass_along[2] = GINT_TO_POINTER (subtype); + pass_along[3] = sublayer; + pass_along[4] = NULL; + + trw_layer_delete_item ( pass_along ); +} + +static void trw_layer_copy_item_cb( gpointer pass_along[5]) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + gint subtype = GPOINTER_TO_INT (pass_along[2]); + gpointer * sublayer = pass_along[3]; + guint8 *data = NULL; + guint len; + + trw_layer_copy_item( vtl, subtype, sublayer, &data, &len); + + if (data) { + a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW, + subtype, len, data); + } +} -static gpointer trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ) +static void trw_layer_cut_item_cb( gpointer pass_along[5]) { - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && sublayer ) - { - NamedWaypoint *nw = g_malloc ( sizeof ( NamedWaypoint ) ); - nw->name = g_strdup(sublayer); - nw->wp = vik_waypoint_copy ( g_hash_table_lookup ( vtl->waypoints, sublayer ) ); - return nw; + trw_layer_copy_item_cb(pass_along); + trw_layer_delete_item(pass_along); +} + +static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ) +{ + FlatItem *fi; + guint8 *id; + guint il; + + if (!sublayer) { + *item = NULL; + return; } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && sublayer ) + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - NamedTrack *nt = g_malloc ( sizeof ( NamedTrack ) ); - nt->name = g_strdup(sublayer); - nt->tr = g_hash_table_lookup ( vtl->tracks, sublayer ); - vik_track_ref(nt->tr); - return nt; + vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il ); + } else { + vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il ); } - return NULL; + + *len = sizeof(FlatItem) + strlen(sublayer) + 1 + il; + fi = g_malloc ( *len ); + fi->len = strlen(sublayer) + 1; + memcpy(fi->data, sublayer, fi->len); + memcpy(fi->data + fi->len, id, il); + g_free(id); + *item = (guint8 *)fi; } -static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer item ) +static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len ) { - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && item ) + FlatItem *fi = (FlatItem *) item; + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && fi ) { - NamedWaypoint *nw = (NamedWaypoint *) item; - vik_trw_layer_add_waypoint ( vtl, g_strdup(nw->name), vik_waypoint_copy(nw->wp) ); + VikWaypoint *w; + gchar *name; + + name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, (gchar *)fi->data); + w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len); + vik_trw_layer_add_waypoint ( vtl, name, w ); + waypoint_convert(name, w, &vtl->coord_mode); return TRUE; } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item ) + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi ) { - NamedTrack *nt = (NamedTrack *) item; - vik_trw_layer_add_track ( vtl, g_strdup(nt->name), vik_track_copy(nt->tr) ); + VikTrack *t; + gchar *name; + name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, (gchar *)fi->data); + t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len); + vik_trw_layer_add_track ( vtl, name, t ); + track_convert(name, t, &vtl->coord_mode); return TRUE; } return FALSE; @@ -399,27 +565,11 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer static void trw_layer_free_copied_item ( gint subtype, gpointer item ) { - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && item ) - { - NamedWaypoint *nw = (NamedWaypoint *) item; - g_free ( nw->name ); - vik_waypoint_free ( nw->wp ); - g_free ( nw ); - } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item ) - { - NamedTrack *nt = (NamedTrack *) item; - g_free ( nt->name ); - vik_track_free ( nt->tr ); - g_free ( nt ); + if (item) { + g_free(item); } } -static void waypoint_copy ( const gchar *name, VikWaypoint *wp, GHashTable *dest ) -{ - g_hash_table_insert ( dest, g_strdup(name), vik_waypoint_copy(wp) ); -} - static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp ) { switch ( id ) @@ -473,6 +623,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara case PARAM_WPBA: gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY ); break; case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break; case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break; + case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break; } return TRUE; } @@ -507,75 +658,116 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ) case PARAM_WPBA: rv.b = (vik_gc_get_function(vtl->waypoint_bg_gc)==GDK_AND); break; case PARAM_WPSYM: rv.u = vtl->wp_symbol; break; case PARAM_WPSIZE: rv.u = vtl->wp_size; break; + case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break; } return rv; } -static void track_copy ( const gchar *name, VikTrack *tr, GHashTable *dest ) +static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) { - g_hash_table_insert ( dest, g_strdup ( name ), vik_track_copy(tr) ); + guint8 *pd, *dd; + gint pl, dl; + gchar *tmpname; + FILE *f; + + *data = NULL; + + if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { + a_gpx_write_file(vtl, f); + vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl); + fclose(f); + f = NULL; + g_file_get_contents(tmpname, (void *)&dd, (void *)&dl, NULL); + *len = sizeof(pl) + pl + dl; + *data = g_malloc(*len); + memcpy(*data, &pl, sizeof(pl)); + memcpy(*data + sizeof(pl), pd, pl); + memcpy(*data + sizeof(pl) + pl, dd, dl); + + g_free(pd); + g_free(dd); + g_remove(tmpname); + g_free(tmpname); + } } -static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ) +static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp ) { - VikTrwLayer *rv = vik_trw_layer_new ( vtl->drawmode ); - PangoFontDescription *pfd; - rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL); - pfd = pango_font_description_from_string (WAYPOINT_FONT); - pango_layout_set_font_description (rv->wplabellayout, pfd); - /* freeing PangoFontDescription, cause it has been copied by prev. call */ - pango_font_description_free (pfd); - - rv->tracks_visible = vtl->tracks_visible; - rv->waypoints_visible = vtl->waypoints_visible; - rv->drawpoints = vtl->drawpoints; - rv->drawstops = vtl->drawstops; - rv->drawelevation = vtl->drawelevation; - rv->elevation_factor = vtl->elevation_factor; - rv->drawlines = vtl->drawlines; - rv->stop_length = vtl->stop_length; - rv->line_thickness = vtl->line_thickness; - rv->bg_line_thickness = vtl->bg_line_thickness; - rv->velocity_min = vtl->velocity_min; - rv->velocity_max = vtl->velocity_max; - rv->drawlabels = vtl->drawlabels; - rv->drawimages = vtl->drawimages; - rv->image_size = vtl->image_size; - rv->image_alpha = vtl->image_alpha; - rv->image_cache_size = vtl->image_cache_size; - rv->has_verified_thumbnails = TRUE; - rv->coord_mode = vtl->coord_mode; - rv->wp_symbol = vtl->wp_symbol; - rv->wp_size = vtl->wp_size; - - trw_layer_new_track_gcs ( rv, VIK_VIEWPORT(vp) ); - - rv->waypoint_gc = gdk_gc_new ( GTK_WIDGET(vp)->window ); - gdk_gc_set_line_attributes ( rv->waypoint_gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); - - rv->waypoint_text_gc = gdk_gc_new ( GTK_WIDGET(vp)->window ); - rv->waypoint_bg_gc = gdk_gc_new ( GTK_WIDGET(vp)->window ); - gdk_gc_copy ( rv->waypoint_gc, vtl->waypoint_gc ); - gdk_gc_copy ( rv->waypoint_text_gc, vtl->waypoint_text_gc ); - gdk_gc_copy ( rv->waypoint_bg_gc, vtl->waypoint_bg_gc ); + VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE )); + guint pl; + gchar *tmpname; + FILE *f; - rv->waypoint_font = gdk_font_load ( "-*-helvetica-bold-r-normal-*-*-100-*-*-p-*-iso8859-1" ); - g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_copy, rv->waypoints ); - g_hash_table_foreach ( vtl->tracks, (GHFunc) track_copy, rv->tracks ); + memcpy(&pl, data, sizeof(pl)); + data += sizeof(pl); + vik_layer_unmarshall_params ( VIK_LAYER(rv), data, pl, vvp ); + data += pl; + if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { + g_critical("couldn't open temp file"); + exit(1); + } + fwrite(data, len - pl - sizeof(pl), 1, f); + rewind(f); + a_gpx_read_file(rv, f); + fclose(f); + f = NULL; + g_remove(tmpname); + g_free(tmpname); return rv; } +static GList * str_array_to_glist(gchar* data[]) +{ + GList *gl = NULL; + gpointer * p; + for (p = (gpointer)data; *p; p++) + gl = g_list_prepend(gl, *p); + return(g_list_reverse(gl)); +} + +static gboolean strcase_equal(gconstpointer s1, gconstpointer s2) +{ + return (strcasecmp(s1, s2) == 0); +} + +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 = str_array_to_glist(params_drawmodes); + if (trw_layer_params[PARAM_WPSYM].widget_data == NULL) + trw_layer_params[PARAM_WPSYM].widget_data = str_array_to_glist(params_wpsymbols); + VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) ); vik_layer_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; @@ -603,6 +795,15 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode ) rv->current_tp_track_name = NULL; 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; + rv->magic_scissors_current_track = NULL; + rv->magic_scissors_append = FALSE; + rv->waypoint_rightclick = FALSE; rv->last_tpl = NULL; rv->last_tp_track_name = NULL; @@ -722,12 +923,13 @@ 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; gboolean drawstops; gboolean drawelevation; - gdouble min_alt, max_alt, alt_diff; + gdouble min_alt, max_alt, alt_diff = 0; const guint8 tp_size_reg = 2; const guint8 tp_size_cur = 4; @@ -754,6 +956,11 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr drawstops = dp->vtl->drawstops; } + 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); @@ -765,7 +972,7 @@ 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; @@ -790,16 +997,16 @@ 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, main_gc, 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)) @@ -808,7 +1015,7 @@ 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 ) dp->track_gc_iter = calculate_velocity ( dp->vtl, tp, tp2 ); @@ -821,7 +1028,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) @@ -842,7 +1049,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)); } } } @@ -864,12 +1071,12 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr 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; @@ -901,11 +1108,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; 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 */ @@ -978,7 +1186,10 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct } /* DRAW ACTUAL DOT */ - if ( wp == dp->vtl->current_wp ) { + if ( dp->vtl->wp_draw_symbols && wp->symbol && (sym = a_get_wp_sym(wp->symbol)) ) { + vik_viewport_draw_pixbuf ( dp->vp, sym, 0, 0, x - gdk_pixbuf_get_width(sym)/2, y - gdk_pixbuf_get_height(sym)/2, -1, -1 ); + } + else if ( wp == dp->vtl->current_wp ) { switch ( dp->vtl->wp_symbol ) { case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break; case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break; @@ -1032,6 +1243,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; @@ -1053,6 +1269,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 */ @@ -1099,9 +1320,12 @@ VikTrwLayer *vik_trw_layer_create ( VikViewport *vp ) rv->has_verified_thumbnails = FALSE; rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE; rv->wp_size = 4; + rv->wp_draw_symbols = TRUE; rv->coord_mode = vik_viewport_get_coord_mode ( vp ); + rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection; + return rv; } @@ -1110,7 +1334,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 @@ -1126,7 +1350,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 @@ -1145,9 +1369,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 ); @@ -1155,9 +1379,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 ) @@ -1263,7 +1487,7 @@ 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_export ( gpointer layer_and_vlp[2], guint file_type ) @@ -1271,12 +1495,18 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type ) GtkWidget *file_selector; const gchar *fn; gboolean failed = FALSE; - file_selector = gtk_file_selection_new ("Export Layer"); - - while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_OK ) + file_selector = gtk_file_chooser_dialog_new (_("Export Layer"), + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(file_selector), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0]))); + + 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 ); @@ -1284,7 +1514,7 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type ) } 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 ); @@ -1294,7 +1524,7 @@ static void trw_layer_export ( gpointer layer_and_vlp[2], guint file_type ) } 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] ) @@ -1315,7 +1545,7 @@ static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] ) 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 (_("Create"), VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, @@ -1325,7 +1555,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); @@ -1345,7 +1575,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) ); @@ -1362,18 +1592,18 @@ 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; - static VikWaypoint st_wp; - st_wp.coord = *def_coord; - st_wp.altitude = VIK_DEFAULT_ALTITUDE; + 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, &st_wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) ) + if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) ) { - VikWaypoint *wp = vik_waypoint_new(); - *wp = st_wp; + wp->visible = TRUE; vik_trw_layer_add_waypoint ( vtl, name, wp ); return TRUE; } + vik_waypoint_free(wp); return FALSE; } @@ -1391,6 +1621,7 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl { static gpointer pass_along[2]; GtkWidget *item; + GtkWidget *export_submenu; pass_along[0] = vtl; pass_along[1] = vlp; @@ -1398,35 +1629,62 @@ 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_label ( _("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_label ( _("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 ); - item = gtk_menu_item_new_with_label ( "Export Layer as GPSPoint" ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along ); + export_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_label ( _("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") ); + 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 Layer as GPSMapper" ); + item = gtk_menu_item_new_with_label ( _("Export as GPSMapper") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along ); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Export Layer as GPX" ); + item = gtk_menu_item_new_with_label ( _("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 (menu), item); + 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_label ( _("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_OPENSTREETMAP + item = gtk_menu_item_new_with_label ( _("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 ) @@ -1452,6 +1710,7 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp else wp->visible = TRUE; + highest_wp_number_add_wp(vtl, name); g_hash_table_insert ( vtl->waypoints, name, wp ); } @@ -1473,67 +1732,117 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) #endif vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter ); g_hash_table_insert ( vtl->tracks_iters, name, iter ); - t->visible = TRUE; + /* t->visible = TRUE; */ } } else - t->visible = TRUE; + ; /* 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 ); else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0) trw_layer_cancel_last_tp ( vtl ); } + +static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name) +{ + gint i = 2; + gchar *newname = g_strdup(name); + while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ? + (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) { + gchar *new_newname = g_strdup_printf("%s#%d", name, i); + g_free(newname); + newname = new_newname; + i++; + } + return newname; +} -void vik_trw_layer_move_iter ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreeIter *dest_iter ) +void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp ) { - VikTreeview *vt = VIK_LAYER(vtl_src)->vt; - if (!vik_treeview_item_get_pointer(vt, src_item_iter)) { - fprintf(stderr, "moving a container: not implemented yet.\n"); + vik_trw_layer_add_waypoint ( vtl, + get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name), + wp ); +} +void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr ) +{ + if ( vtl->magic_scissors_append && vtl->magic_scissors_current_track ) { + vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */ + vik_track_steal_and_append_trackpoints ( vtl->magic_scissors_current_track, tr ); + vik_track_free ( tr ); + vtl->magic_scissors_append = FALSE; /* this means we have added it */ } else { - gint type = vik_treeview_item_get_data(vt, src_item_iter); - gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter); + gchar *new_name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name); + vik_trw_layer_add_track ( vtl, new_name, tr ); + + if ( vtl->magic_scissors_check_added_track ) { + vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */ + if ( vtl->magic_scissors_added_track_name ) /* for google routes */ + g_free ( vtl->magic_scissors_added_track_name ); + vtl->magic_scissors_added_track_name = g_strdup(new_name); + } + } +} - fprintf(stderr, "moving item '%s'\n", name); +static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l ) +{ + *l = g_list_append(*l, (gpointer)name); +} - if (type==VIK_TRW_LAYER_SUBLAYER_TRACK) { - VikTrack *t; - gchar *newname = strdup(name); - printf(" Moving track '%s' from layer '%s' to layer '%s'\n", newname, VIK_LAYER(vtl_src)->name, VIK_LAYER(vtl_dest)->name); - t = vik_track_copy(vik_trw_layer_get_track(vtl_src, newname)); - vik_trw_layer_delete_track(vtl_src, name); - vik_trw_layer_add_track(vtl_dest, newname, t); - } - if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) { - VikWaypoint *w; - gchar *newname = strdup(name); - printf(" Moving waypoint '%s' from layer '%s' to layer '%s'\n", newname, VIK_LAYER(vtl_src)->name, VIK_LAYER(vtl_dest)->name); - w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, newname)); - vik_trw_layer_delete_waypoint(vtl_src, name); - vik_trw_layer_add_waypoint(vtl_dest, newname, w); +static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type ) +{ + gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name); + if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) { + VikTrack *t; + t = vik_track_copy(vik_trw_layer_get_track(vtl_src, name)); + vik_trw_layer_delete_track(vtl_src, name); + vik_trw_layer_add_track(vtl_dest, newname, t); + } + if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) { + VikWaypoint *w; + w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, name)); + vik_trw_layer_delete_waypoint(vtl_src, name); + vik_trw_layer_add_waypoint(vtl_dest, newname, w); + } +} + +static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path ) +{ + VikTreeview *vt = VIK_LAYER(vtl_src)->vt; + gint type = vik_treeview_item_get_data(vt, src_item_iter); + + if (!vik_treeview_item_get_pointer(vt, src_item_iter)) { + GList *items = NULL; + GList *iter; + + if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) { + g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items); + } + if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) { + g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items); + } + + iter = items; + while (iter) { + if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) { + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK); + } else { + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT); + } + iter = iter->next; } + if (items) + g_list_free(items); + } else { + gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter); + trw_layer_move_item(vtl_src, vtl_dest, name, type); } } @@ -1548,6 +1857,8 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name ) was_visible = t->visible; if ( t == vtl->current_track ) vtl->current_track = NULL; + if ( t == vtl->magic_scissors_current_track ) + vtl->magic_scissors_current_track = NULL; /* could be current_tp, so we have to check */ trw_layer_cancel_tps_of_track ( vtl, trk_name ); @@ -1581,17 +1892,58 @@ 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 */ } return was_visible; } +static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt) +{ + vik_treeview_item_delete (vt, it ); +} + +void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl ) +{ + + vtl->current_track = NULL; + vtl->magic_scissors_current_track = NULL; + if (vtl->current_tp_track_name) + trw_layer_cancel_current_tp(vtl, FALSE); + if (vtl->last_tp_track_name) + trw_layer_cancel_last_tp ( vtl ); + + g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); + g_hash_table_remove_all(vtl->tracks_iters); + g_hash_table_remove_all(vtl->tracks); + + /* TODO: only update if the layer is visible (ticked) */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) +{ + vtl->current_wp = NULL; + 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); + + /* TODO: only update if the layer is visible (ticked) */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + 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] ); } @@ -1607,7 +1959,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 ) @@ -1623,56 +1975,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 */); } } } @@ -1692,6 +1998,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 ) { @@ -1705,6 +2012,45 @@ 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; + + 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. */ + /* Also warn if overwrite old elevation data */ + VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + + vik_track_apply_dem_data ( track ); +} + static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] ) { GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints; @@ -1729,31 +2075,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) { - printf("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; + } - /* printf("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 */ @@ -1783,26 +2138,29 @@ static gint trackpoint_compare(gconstpointer a, gconstpointer b) /* 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)) { 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; @@ -1816,23 +2174,20 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) t1 = ((VikTrackpoint *)trps->data)->timestamp; t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp; - /* printf("Original track times: %d and %d\n", t1, t2); */ + /* 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; @@ -1844,20 +2199,20 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) time_t t1, t2; t1 = get_first_trackpoint(l)->timestamp; t2 = get_last_trackpoint(l)->timestamp; - printf(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2); + g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2); */ /* remove trackpoints from merged track, delete track */ tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints); get_track(l)->trackpoints = NULL; - vik_trw_layer_delete_track(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 @@ -1866,7 +2221,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 */ @@ -1886,8 +2241,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; } @@ -1899,7 +2254,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) while (iter) { ts = VIK_TRACKPOINT(iter->data)->timestamp; if (ts < prev_ts) { - printf("panic: ts < prev_ts: this should never happen!\n"); + g_print("panic: ts < prev_ts: this should never happen!\n"); return; } if (ts - prev_ts > thr*60) { @@ -1930,7 +2285,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++); vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr); - /* fprintf(stderr, "adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp, + /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp, VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/ iter = g_list_next(iter); @@ -1953,18 +2308,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 ); } @@ -1972,31 +2316,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 ); @@ -2010,30 +2355,29 @@ 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->waypoints, newname)) + { + a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(l), _("Track Already Exists") ); + return NULL; + } } - g_hash_table_lookup_extended ( l->tracks, sublayer, (gpointer *)&orig_key, (gpointer *)&tr ); + g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr ); g_hash_table_steal ( l->tracks, sublayer ); iter = g_hash_table_lookup ( l->tracks_iters, sublayer ); 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 ); @@ -2065,7 +2409,33 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar static gboolean is_valid_geocache_name ( gchar *str ) { gint len = strlen ( str ); - return len >= 3 && len <= 6 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])); + 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 ); + return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) ); +} + +static void trw_layer_track_google_route_webpage( 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 ); + if ( tr ) { + gchar *escaped = uri_escape ( tr->comment ); + gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped ); + open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage); + g_free ( escaped ); + g_free ( webpage ); + } } /* vlp can be NULL if necessary - i.e. right-click from a tool -- but be careful, some functions may try to use it */ @@ -2078,7 +2448,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; @@ -2092,8 +2462,25 @@ 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_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL ); - g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along ); + 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 ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -2101,7 +2488,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_label ( _("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 ); @@ -2109,7 +2496,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_label ( _("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 ); @@ -2124,142 +2511,96 @@ 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 ( "Goto Startpoint" ); + item = gtk_menu_item_new_with_label ( _("Goto 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_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Goto \"Center\"" ); + item = gtk_menu_item_new_with_label ( _("Goto \"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_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Goto Endpoint" ); + item = gtk_menu_item_new_with_label ( _("Goto 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(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_label ( "Merge By Time" ); + item = gtk_menu_item_new_with_label ( _("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_label ( _("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 ); - } - if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) - { - item = gtk_menu_item_new (); + item = gtk_menu_item_new_with_label ( _("Download 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 ( "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); + item = gtk_menu_item_new_with_label ( _("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 ); - } - return rv; -} + item = gtk_menu_item_new_with_label ( _("Extend 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 ); -/* Params are: vvp, event, last match found or NULL */ -static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] ) -{ - if ( wp->image && wp->visible ) - { - gint x, y, slackx, slacky; - GdkEventButton *event = (GdkEventButton *) params[1]; + item = gtk_menu_item_new_with_label ( _("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 ); - vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y ); - slackx = wp->image_width / 2; - slacky = wp->image_height / 2; - if ( x <= event->x + slackx && x >= event->x - slackx - && y <= event->y + slacky && y >= event->y - slacky ) - { - params[2] = wp->image; /* we've found a match. however continue searching - * since we want to find the last match -- that - * is, the match that was drawn last. */ - } - } -} +#ifdef VIK_CONFIG_OPENSTREETMAP + item = gtk_menu_item_new_with_label ( _("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 ); +#endif -static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - gpointer params[3] = { vvp, event, NULL }; - g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params ); - if ( params[2] ) - { - /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */ -#ifdef WINDOWS - ShellExecute(NULL, NULL, (char *) params[2], NULL, ".\\", 0); -#else /* WINDOWS */ - GError *err = NULL; - gchar *quoted_file = g_shell_quote ( (gchar *) params[2] ); - gchar *cmd = g_strdup_printf ( "eog %s", quoted_file ); - g_free ( quoted_file ); - if ( ! g_spawn_command_line_async ( cmd, &err ) ) + if ( is_valid_google_route ( l, (gchar *) sublayer ) ) { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." ); - g_error_free ( err ); + item = gtk_menu_item_new_with_label ( _("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 ); } - g_free ( cmd ); -#endif /* WINDOWS */ - return TRUE; /* found a match */ - } - else - return FALSE; /* go through other layers, searching for a match */ -} - -static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - VikCoord coord; - vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); - if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; -} - -typedef struct { - gint x, y; - gint closest_x, closest_y; - gchar *closest_track_name; - VikTrackpoint *closest_tp; - VikViewport *vvp; - GList *closest_tpl; -} TPSearchParams; -static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params ) -{ - GList *tpl = t->trackpoints; - VikTrackpoint *tp; + item = gtk_menu_item_new_with_label ( _("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 ); - if ( !t->visible ) - return; + 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 ); + } + } - while (tpl) + if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) { - gint x, y; - tp = VIK_TRACKPOINT(tpl->data); + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); - vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y ); - - if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX && - ((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */ - abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) - { - params->closest_track_name = name; - params->closest_tp = tp; - params->closest_tpl = tpl; - params->closest_x = x; - params->closest_y = y; - } - tpl = tpl->next; + item = gtk_menu_item_new_with_label ( _("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 ); } + + return rv; } + /* to be called when last_tpl no long exists. */ static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl ) { @@ -2421,102 +2762,11 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) /* set layer name and TP data */ } -static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) -{ - TPSearchParams params; - params.x = x; - params.y = y; - params.vvp = vvp; - params.closest_track_name = NULL; - params.closest_tp = NULL; - g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); - return params.closest_tp; -} - -static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - if ( vtl->moving_tp ) - { - /* vtl->moving_tp_x, vtl->moving_tp_y, etc. */ - VikCoord new_coord; - vtl->moving_tp = FALSE; - vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); - - /* snap to TP */ - if ( event->state & GDK_CONTROL_MASK ) - { - VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( tp && tp != vtl->current_tpl->data ) - new_coord = tp->coord; - } - - VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; - - /* diff dist is diff from orig */ - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name ); - /* can't join with itself! */ - trw_layer_cancel_last_tp ( vtl ); - - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; - } - return FALSE; -} - -static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - TPSearchParams params; - /* OUTDATED DOCUMENTATION: - find 5 pixel range on each side. then put these UTM, and a pointer - to the winning track name (and maybe the winning track itself), and a - pointer to the winning trackpoint, inside an array or struct. pass - this along, do a foreach on the tracks which will do a foreach on the - trackpoints. */ - params.vvp = vvp; - params.x = event->x; - params.y = event->y; - params.closest_track_name = NULL; - /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ - params.closest_tp = NULL; - - if ( vtl->current_tpl ) - { - /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */ - VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data); - VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name)); - gint x, y; - g_assert ( current_tr ); - - vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y ); - - if ( current_tr->visible && - abs(x - event->x) < TRACKPOINT_SIZE_APPROX && - abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) - { - vtl->moving_tp = TRUE; - return TRUE; - } - - vtl->last_tpl = vtl->current_tpl; - vtl->last_tp_track_name = vtl->current_tp_track_name; - } - - g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); - - if ( params.closest_tp ) - { - vtl->current_tpl = params.closest_tpl; - vtl->current_tp_track_name = params.closest_track_name; - vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ) ); - trw_layer_tpwin_init ( vtl ); - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; - } - +/*************************************************************************** + ** Tool code + ***************************************************************************/ - /* these aren't the droids you're looking for */ - return FALSE; -} +/*** Utility data structures and functions ****/ typedef struct { gint x, y; @@ -2526,6 +2776,15 @@ typedef struct { VikViewport *vvp; } WPSearchParams; +typedef struct { + gint x, y; + gint closest_x, closest_y; + gchar *closest_track_name; + VikTrackpoint *closest_tp; + VikViewport *vvp; + GList *closest_tpl; +} TPSearchParams; + static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params ) { gint x, y; @@ -2545,45 +2804,45 @@ static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchP } } -static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params ) { - if ( vtl->moving_wp ) - { - VikCoord new_coord; - vtl->moving_wp = FALSE; - vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + GList *tpl = t->trackpoints; + VikTrackpoint *tp; - /* snap to TP */ - if ( event->state & GDK_CONTROL_MASK ) - { - VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( tp ) - new_coord = tp->coord; - } + if ( !t->visible ) + return; - /* snap to WP */ - if ( event->state & GDK_SHIFT_MASK ) + while (tpl) + { + gint x, y; + tp = VIK_TRACKPOINT(tpl->data); + + vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y ); + + if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX && + ((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */ + abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) { - VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( wp && wp != vtl->current_wp ) - new_coord = wp->coord; + params->closest_track_name = name; + params->closest_tp = tp; + params->closest_tpl = tpl; + params->closest_x = x; + params->closest_y = y; } + tpl = tpl->next; + } +} - vtl->current_wp->coord = new_coord; - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; - } - /* PUT IN RIGHT PLACE!!! */ - if ( vtl->waypoint_rightclick ) - { - if ( vtl->wp_right_click_menu ) - gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) ); - vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () ); - vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); - gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() ); - vtl->waypoint_rightclick = FALSE; - } - return FALSE; +static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) +{ + TPSearchParams params; + params.x = x; + params.y = y; + params.vvp = vvp; + params.closest_track_name = NULL; + params.closest_tp = NULL; + g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); + return params.closest_tp; } static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) @@ -2598,9 +2857,80 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie return params.closest_wp; } -static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +/* background drawing hook, to be passed the viewport */ +static gboolean tool_sync_done = TRUE; + +static gboolean tool_sync(gpointer data) +{ + VikViewport *vvp = data; + gdk_threads_enter(); + vik_viewport_sync(vvp); + tool_sync_done = TRUE; + gdk_threads_leave(); + return FALSE; +} + +typedef struct { + VikViewport *vvp; + gboolean holding; + GdkGC *gc; + int oldx, oldy; +} tool_ed_t; + +static void marker_begin_move ( tool_ed_t *t, gint x, gint y ) +{ + t->holding = TRUE; + t->gc = vik_viewport_new_gc (t->vvp, "black", 2); + gdk_gc_set_function ( t->gc, GDK_INVERT ); + vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 ); + vik_viewport_sync(t->vvp); + t->oldx = x; + t->oldy = y; +} + +static void marker_moveto ( tool_ed_t *t, gint x, gint y ) +{ + VikViewport *vvp = t->vvp; + vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 ); + 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; + } +} + +static void marker_end_move ( tool_ed_t *t ) +{ + vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 ); + g_object_unref ( t->gc ); + t->holding = FALSE; +} + +/*** Edit waypoint ****/ + +static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp) +{ + tool_ed_t *t = g_new(tool_ed_t, 1); + t->vvp = vvp; + t->holding = FALSE; + return t; +} + +static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) { WPSearchParams params; + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding ) { + return TRUE; + } if ( vtl->current_wp && vtl->current_wp->visible ) { @@ -2608,13 +2938,14 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi gint x, y; vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y ); - if ( abs(x - event->x) < WAYPOINT_SIZE_APPROX && - abs(y - event->y) < WAYPOINT_SIZE_APPROX ) + if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX && + abs(y - event->y) <= WAYPOINT_SIZE_APPROX ) { if ( event->button == 3 ) vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */ - else - vtl->moving_wp = TRUE; + else { + marker_begin_move(t, event->x, event->y); + } return TRUE; } } @@ -2628,7 +2959,10 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL ) { - vtl->moving_wp = TRUE; + /* how do we get here? I'm putting in the abort until we can figure it out. -alex */ + marker_begin_move(t, event->x, event->y); + g_critical("shouldn't be here"); + exit(1); } else if ( params.closest_wp ) { @@ -2639,7 +2973,6 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi vtl->current_wp = params.closest_wp; vtl->current_wp_name = params.closest_wp_name; - vtl->moving_wp = FALSE; if ( params.closest_wp ) vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); @@ -2651,15 +2984,194 @@ static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, Vi vtl->current_wp = NULL; vtl->current_wp_name = NULL; - vtl->moving_wp = FALSE; vtl->waypoint_rightclick = FALSE; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return FALSE; +} + +static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding ) { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp ) + new_coord = tp->coord; + } + + /* snap to WP */ + if ( event->state & GDK_SHIFT_MASK ) + { + VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( wp && wp != vtl->current_wp ) + new_coord = wp->coord; + } + + { + gint x, y; + vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y ); + + marker_moveto ( t, x, y ); + } + return TRUE; + } + return FALSE; +} + +static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding && event->button == 1 ) + { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp ) + new_coord = tp->coord; + } + + /* snap to WP */ + if ( event->state & GDK_SHIFT_MASK ) + { + VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( wp && wp != vtl->current_wp ) + new_coord = wp->coord; + } + + marker_end_move ( t ); + + vtl->current_wp->coord = new_coord; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + /* PUT IN RIGHT PLACE!!! */ + if ( event->button == 3 && vtl->waypoint_rightclick ) + { + if ( vtl->wp_right_click_menu ) + gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) ); + vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () ); + vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); + gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() ); + vtl->waypoint_rightclick = FALSE; + } + return FALSE; +} + +/**** Begin track ***/ +static gpointer tool_begin_track_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + vtl->current_track = NULL; + return tool_new_track_click ( vtl, event, vvp ); +} + +/*** New track ****/ + +static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp) +{ + 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 ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { VikTrackpoint *tp; + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + if ( event->button == 3 && vtl->current_track ) { /* undo */ @@ -2684,6 +3196,7 @@ static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikVie /* undo last, then end */ vtl->current_track = NULL; } + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } @@ -2695,6 +3208,9 @@ static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikVie 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; @@ -2725,6 +3241,317 @@ static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikVie return TRUE; } + +/*** New waypoint ****/ + +static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + VikCoord coord; + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); + if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; +} + + +/*** Edit trackpoint ****/ + +static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp) +{ + tool_ed_t *t = g_new(tool_ed_t, 1); + t->vvp = vvp; + t->holding = FALSE; + return t; +} + +static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + TPSearchParams params; + /* OUTDATED DOCUMENTATION: + find 5 pixel range on each side. then put these UTM, and a pointer + to the winning track name (and maybe the winning track itself), and a + pointer to the winning trackpoint, inside an array or struct. pass + this along, do a foreach on the tracks which will do a foreach on the + trackpoints. */ + params.vvp = vvp; + params.x = event->x; + params.y = event->y; + params.closest_track_name = NULL; + /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ + params.closest_tp = NULL; + + if ( event->button != 1 ) + return FALSE; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( vtl->current_tpl ) + { + /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */ + VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data); + VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name)); + gint x, y; + g_assert ( current_tr ); + + vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y ); + + if ( current_tr->visible && + abs(x - event->x) < TRACKPOINT_SIZE_APPROX && + abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) { + marker_begin_move ( t, event->x, event->y ); + return TRUE; + } + + vtl->last_tpl = vtl->current_tpl; + vtl->last_tp_track_name = vtl->current_tp_track_name; + } + + g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms); + + if ( params.closest_tp ) + { + vtl->current_tpl = params.closest_tpl; + vtl->current_tp_track_name = params.closest_track_name; + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ) ); + trw_layer_tpwin_init ( vtl ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + + /* these aren't the droids you're looking for */ + return FALSE; +} + +static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding ) + { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp && tp != vtl->current_tpl->data ) + new_coord = tp->coord; + } + // VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; + { + gint x, y; + vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y ); + marker_moveto ( t, x, y ); + } + + return TRUE; + } + return FALSE; +} + +static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + if ( event->button != 1) + return FALSE; + + if ( t->holding ) { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp && tp != vtl->current_tpl->data ) + new_coord = tp->coord; + } + + VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; + + marker_end_move ( t ); + + /* diff dist is diff from orig */ + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name ); + /* can't join with itself! */ + trw_layer_cancel_last_tp ( vtl ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + return FALSE; +} + + +/*** Magic Scissors ***/ +static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + VikCoord tmp; + if ( !vtl ) return FALSE; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp ); + if ( event->button == 3 && vtl->magic_scissors_current_track ) { + VikCoord *new_end; + new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track ); + if ( new_end ) { + vtl->magic_scissors_coord = *new_end; + g_free ( new_end ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); + /* remove last ' to:...' */ + if ( vtl->magic_scissors_current_track->comment ) { + gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' ); + if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) { + gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment, + last_to - vtl->magic_scissors_current_track->comment - 1); + vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment ); + } + } + } + } + else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) { + struct LatLon start, end; + gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE]; + gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE]; + gchar *url; + + vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start ); + vik_coord_to_latlon ( &(tmp), &end ); + vtl->magic_scissors_coord = tmp; /* for continuations */ + + /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */ + if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) { + vtl->magic_scissors_append = TRUE; // merge tracks. keep started true. + } else { + vtl->magic_scissors_check_added_track = TRUE; + vtl->magic_scissors_started = FALSE; + } + + url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, + g_ascii_dtostr (startlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lat), + g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon), + g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat), + g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon)); + a_babel_convert_from_url ( vtl, url, "google", NULL, NULL ); + g_free ( url ); + + /* see if anything was done -- a track was added or appended to */ + if ( vtl->magic_scissors_check_added_track && vtl->magic_scissors_added_track_name ) { + VikTrack *tr; + + tr = g_hash_table_lookup ( vtl->tracks, vtl->magic_scissors_added_track_name ); + + if ( tr ) + vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f%f", start.lat, start.lon, end.lat, end.lon ) ); + + vtl->magic_scissors_current_track = tr; + + g_free ( vtl->magic_scissors_added_track_name ); + vtl->magic_scissors_added_track_name = NULL; + } else if ( vtl->magic_scissors_append == FALSE && vtl->magic_scissors_current_track ) { + /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */ + gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->magic_scissors_current_track->comment, end.lat, end.lon ); + vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment ); + } + vtl->magic_scissors_check_added_track = FALSE; + vtl->magic_scissors_append = FALSE; + + vik_layer_emit_update ( VIK_LAYER(vtl) ); + } else { + vtl->magic_scissors_started = TRUE; + vtl->magic_scissors_coord = tmp; + vtl->magic_scissors_current_track = NULL; + } + return TRUE; +} + +/*** Show picture ****/ + +static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +/* Params are: vvp, event, last match found or NULL */ +static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] ) +{ + if ( wp->image && wp->visible ) + { + gint x, y, slackx, slacky; + GdkEventButton *event = (GdkEventButton *) params[1]; + + vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y ); + slackx = wp->image_width / 2; + slacky = wp->image_height / 2; + if ( x <= event->x + slackx && x >= event->x - slackx + && y <= event->y + slacky && y >= event->y - slacky ) + { + params[2] = wp->image; /* we've found a match. however continue searching + * since we want to find the last match -- that + * is, the match that was drawn last. */ + } + } +} + +static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + gpointer params[3] = { vvp, event, NULL }; + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params ); + if ( params[2] ) + { + /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */ +#ifdef WINDOWS + ShellExecute(NULL, NULL, (char *) params[2], NULL, ".\\", 0); +#else /* WINDOWS */ + GError *err = NULL; + gchar *quoted_file = g_shell_quote ( (gchar *) params[2] ); + gchar *cmd = g_strdup_printf ( "eog %s", quoted_file ); + 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.") ); + g_error_free ( err ); + } + g_free ( cmd ); +#endif /* WINDOWS */ + return TRUE; /* found a match */ + } + else + return FALSE; /* go through other layers, searching for a match */ +} + +/*************************************************************************** + ** End tool code + ***************************************************************************/ + + + + + static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics ) { if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) ) @@ -2760,7 +3587,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 ); } @@ -2803,3 +3630,291 @@ VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, gchar *name ) { return g_hash_table_lookup ( vtl->tracks, name ); } + +static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection) +{ + vtl->menu_selection = selection; +} + +static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl) +{ + return(vtl->menu_selection); +} + +/* ----------- Downloading maps along tracks --------------- */ + +static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh) +{ + /* TODO: calculating based on current size of viewport */ + const gdouble w_at_zoom_0_125 = 0.0013; + const gdouble h_at_zoom_0_125 = 0.0011; + gdouble zoom_factor = zoom_level/0.125; + + wh->lat = h_at_zoom_0_125 * zoom_factor; + wh->lon = w_at_zoom_0_125 * zoom_factor; + + return 0; /* all OK */ +} + +static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient) +{ + if ((dist->lon >= ABS(to->east_west - from->east_west)) && + (dist->lat >= ABS(to->north_south - from->north_south))) + return NULL; + + VikCoord *coord = g_malloc(sizeof(VikCoord)); + coord->mode = VIK_COORD_LATLON; + + if (ABS(gradient) < 1) { + if (from->east_west > to->east_west) + coord->east_west = from->east_west - dist->lon; + else + coord->east_west = from->east_west + dist->lon; + coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south; + } else { + if (from->north_south > to->north_south) + coord->north_south = from->north_south - dist->lat; + else + coord->north_south = from->north_south + dist->lat; + coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south; + } + + return coord; +} + +static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist) +{ + /* TODO: handle virtical track (to->east_west - from->east_west == 0) */ + gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west); + + VikCoord *next = from; + while (TRUE) { + if ((next = get_next_coord(next, to, dist, gradient)) == NULL) + break; + list = g_list_prepend(list, next); + } + + return list; +} + +void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level) +{ + typedef struct _Rect { + VikCoord tl; + VikCoord br; + VikCoord center; + } Rect; +#define GLRECT(iter) ((Rect *)((iter)->data)) + + struct LatLon wh; + GList *rects_to_download = NULL; + GList *rect_iter; + + if (get_download_area_width(vvp, zoom_level, &wh)) + return; + + GList *iter = tr->trackpoints; + if (!iter) + return; + + gboolean new_map = TRUE; + VikCoord *cur_coord, tl, br; + Rect *rect; + while (iter) { + cur_coord = &(VIK_TRACKPOINT(iter->data))->coord; + if (new_map) { + vik_coord_set_area(cur_coord, &wh, &tl, &br); + rect = g_malloc(sizeof(Rect)); + rect->tl = tl; + rect->br = br; + rect->center = *cur_coord; + rects_to_download = g_list_prepend(rects_to_download, rect); + new_map = FALSE; + iter = iter->next; + continue; + } + gboolean found = FALSE; + for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) { + if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) { + found = TRUE; + break; + } + } + if (found) + iter = iter->next; + else + 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); + } + } + + if (fillins) { + GList *iter = fillins; + while (iter) { + cur_coord = (VikCoord *)(iter->data); + vik_coord_set_area(cur_coord, &wh, &tl, &br); + rect = g_malloc(sizeof(Rect)); + rect->tl = tl; + rect->br = br; + rect->center = *cur_coord; + rects_to_download = g_list_prepend(rects_to_download, rect); + iter = iter->next; + } + } + + for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) { + maps_layer_download_section_without_redraw(vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level); + } + + if (fillins) { + for (iter = fillins; iter; iter = iter->next) + g_free(iter->data); + g_list_free(fillins); + } + if (rects_to_download) { + for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) + g_free(rect_iter->data); + g_list_free(rects_to_download); + } +} + +static void trw_layer_download_map_along_track_cb(gpointer pass_along[6]) +{ + VikMapsLayer *vml; + gint selected_map, default_map; + gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL }; + gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}; + gint selected_zoom, default_zoom; + int i,j; + + + VikTrwLayer *vtl = pass_along[0]; + VikLayersPanel *vlp = pass_along[1]; + VikTrack *tr = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ); + VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl))); + + GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS); + 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); + return; + } + + gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer)); + VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer)); + + gchar **np = map_names; + VikMapsLayer **lp = map_layers; + for (i = 0; i < num_maps; i++) { + gboolean dup = FALSE; + vml = (VikMapsLayer *)(vmls->data); + for (j = 0; j < i; j++) { /* no duplicate allowed */ + if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) { + dup = TRUE; + break; + } + } + if (!dup) { + *lp++ = vml; + *np++ = vik_maps_layer_get_map_label(vml); + } + vmls = vmls->next; + } + *lp = NULL; + *np = NULL; + num_maps = lp - map_layers; + + for (default_map = 0; default_map < num_maps; default_map++) { + /* TODO: check for parent layer's visibility */ + if (VIK_LAYER(map_layers[default_map])->visible) + break; + } + default_map = (default_map == num_maps) ? 0 : default_map; + + gdouble cur_zoom = vik_viewport_get_zoom(vvp); + for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) { + if (cur_zoom == zoom_vals[default_zoom]) + break; + } + default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom; + + if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom)) + goto done; + + vik_track_download_map(tr, map_layers[selected_map], vvp, zoom_vals[selected_zoom]); + +done: + for (i = 0; i < num_maps; i++) + g_free(map_names[i]); + g_free(map_names); + g_free(map_layers); + + g_list_free(vmls); + +} + +/**** 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); +}