X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/e46f259a9f067d626de3bbe90215ff29e33262de..c3092f0f56a7d416da8c506ae6d222d5d67e5379:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index ee6f7ebb..202a8266 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -239,7 +239,10 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ); static void trw_layer_merge_with_other ( gpointer pass_along[6] ); static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ); static void trw_layer_split_by_n_points ( gpointer pass_along[6] ); -static void trw_layer_download_map_along_track_cb (gpointer pass_along[6]); +static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ); +static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ); +static void trw_layer_show_picture ( gpointer pass_along[6] ); + static void trw_layer_centerize ( gpointer layer_and_vlp[2] ); static void trw_layer_auto_view ( gpointer layer_and_vlp[2] ); static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, const gchar* trackname, guint file_type ); @@ -247,6 +250,10 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ); static void trw_layer_new_wp ( gpointer lav[2] ); static void trw_layer_auto_waypoints_view ( gpointer lav[2] ); static void trw_layer_auto_tracks_view ( gpointer lav[2] ); +static void trw_layer_delete_all_tracks ( gpointer lav[2] ); +static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ); +static void trw_layer_delete_all_waypoints ( gpointer lav[2] ); +static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] ); static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] ); static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] ); @@ -274,7 +281,9 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i static void trw_layer_free_copied_item ( gint subtype, gpointer item ); static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path ); -static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t ); +static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t ); +static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t ); static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl ); @@ -348,8 +357,8 @@ static VikToolInterface trw_layer_tools[] = { { 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 }, + { N_("Route Finder"), (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf }, }; enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS }; @@ -473,6 +482,8 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncDragDropRequest) trw_layer_drag_drop_request, (VikLayerFuncSelectClick) trw_layer_select_click, + (VikLayerFuncSelectMove) trw_layer_select_move, + (VikLayerFuncSelectRelease) trw_layer_select_release, (VikLayerFuncSelectedViewportMenu) trw_layer_show_selected_viewport_menu, }; @@ -519,7 +530,7 @@ static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublay pass_along[1] = NULL; pass_along[2] = GINT_TO_POINTER (subtype); pass_along[3] = sublayer; - pass_along[4] = NULL; + pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request pass_along[5] = NULL; trw_layer_delete_item ( pass_along ); @@ -536,7 +547,7 @@ static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublay pass_along[1] = NULL; pass_along[2] = GINT_TO_POINTER (subtype); pass_along[3] = sublayer; - pass_along[4] = NULL; + pass_along[4] = GINT_TO_POINTER (0); // No delete confirmation needed for auto delete pass_along[5] = NULL; trw_layer_copy_item_cb(pass_along); @@ -562,6 +573,7 @@ static void trw_layer_copy_item_cb ( gpointer pass_along[6]) static void trw_layer_cut_item_cb ( gpointer pass_along[6]) { trw_layer_copy_item_cb(pass_along); + pass_along[4] = GINT_TO_POINTER (0); // Never need to confirm automatic delete trw_layer_delete_item(pass_along); } @@ -1791,6 +1803,11 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g */ gboolean vik_trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp ) { + // Reset + l->current_wp = NULL; + l->current_wp_name = NULL; + trw_layer_cancel_current_tp ( l, FALSE ); + switch ( type ) { case VIK_TREEVIEW_TYPE_LAYER: @@ -2073,6 +2090,18 @@ static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] ) trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPX ); } +static void trw_layer_export_kml ( gpointer layer_and_vlp[2] ) +{ + /* Auto append '.kml' to the name (providing it's not already there) for the default filename */ + gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) ); + if ( ! check_file_ext ( auto_save_name, ".kml" ) ) + auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL ); + + trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML ); + + g_free ( auto_save_name ); +} + static void trw_layer_export_gpx_track ( gpointer pass_along[6] ) { gpointer layer_and_vlp[2]; @@ -2285,7 +2314,7 @@ 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_mnemonic ( _("Goto _Waypoint") ); + item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); @@ -2296,22 +2325,27 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl gtk_widget_show ( item ); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu ); - item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point") ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper") ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX") ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint") ); + item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); @@ -2335,12 +2369,38 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl #endif #ifdef VIK_CONFIG_OPENSTREETMAP - item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM") ); + item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); #endif + GtkWidget *delete_submenu = gtk_menu_new (); + item = gtk_menu_item_new_with_mnemonic ( _("De_lete") ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu ); + + item = gtk_menu_item_new_with_mnemonic ( _("Delete All _Tracks") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Delete Tracks _From Selection...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Delete Waypoints From _Selection...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item ); + gtk_widget_show ( item ); + 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 ) { @@ -2374,7 +2434,6 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp #endif // Actual setting of visibility dependent on the waypoint vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible ); - vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter, TRUE ); g_hash_table_insert ( vtl->waypoints_iters, name, iter ); } } @@ -2402,7 +2461,6 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) #endif // Actual setting of visibility dependent on the track vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible ); - vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter, TRUE ); g_hash_table_insert ( vtl->tracks_iters, name, iter ); } } @@ -2607,16 +2665,49 @@ void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) vik_layer_emit_update ( VIK_LAYER(vtl) ); } +static void trw_layer_delete_all_tracks ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + // Get confirmation from the user + if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Are you sure you want to delete all tracks in %s?"), + vik_layer_get_name ( VIK_LAYER(vtl) ) ) ) + vik_trw_layer_delete_all_tracks (vtl); +} + +static void trw_layer_delete_all_waypoints ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + // Get confirmation from the user + if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Are you sure you want to delete all waypoints in %s?"), + vik_layer_get_name ( VIK_LAYER(vtl) ) ) ) + vik_trw_layer_delete_all_waypoints (vtl); +} + static void trw_layer_delete_item ( gpointer pass_along[6] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); gboolean was_visible = FALSE; if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + if ( GPOINTER_TO_INT ( pass_along[4]) ) + // Get confirmation from the user + // Maybe this Waypoint Delete should be optional as is it could get annoying... + if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Are you sure you want to delete the waypoint \"%s\""), + pass_along[3] ) ) + return; was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] ); } else { + if ( GPOINTER_TO_INT ( pass_along[4]) ) + // Get confirmation from the user + if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + _("Are you sure you want to delete the track \"%s\""), + pass_along[3] ) ) + return; was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] ); } if ( was_visible ) @@ -2787,6 +2878,12 @@ static void trw_layer_auto_track_view ( gpointer pass_along[5] ) } } +static void trw_layer_edit_trackpoint ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + trw_layer_tpwin_init ( vtl ); +} + /************************************* * merge/split by time routines *************************************/ @@ -2871,6 +2968,7 @@ static void find_nearby_track(gpointer key, gpointer value, gpointer user_data) } /* comparison function used to sort tracks; a and b are hash table keys */ +/* Not actively used - can be restored if needed static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data) { GHashTable *tracks = user_data; @@ -2883,6 +2981,7 @@ static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data) if (t1 > t2) return 1; return 0; } +*/ /* comparison function used to sort trackpoints */ static gint trackpoint_compare(gconstpointer a, gconstpointer b) @@ -2973,7 +3072,7 @@ 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; + //time_t t1, t2; GList *nearby_tracks; VikTrack *track; GList *trps; @@ -3004,8 +3103,8 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) nearby_tracks = NULL; } - t1 = ((VikTrackpoint *)trps->data)->timestamp; - t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp; + //t1 = ((VikTrackpoint *)trps->data)->timestamp; + //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp; /* g_print("Original track times: %d and %d\n", t1, t2); */ params[0] = &nearby_tracks; @@ -3092,7 +3191,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) } if (ts - prev_ts > thr*60) { /* flush accumulated trackpoints into new list */ - newlists = g_list_prepend(newlists, g_list_reverse(newtps)); + newlists = g_list_append(newlists, g_list_reverse(newtps)); newtps = NULL; } @@ -3102,30 +3201,33 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) iter = g_list_next(iter); } if (newtps) { - newlists = g_list_prepend(newlists, g_list_reverse(newtps)); + newlists = g_list_append(newlists, g_list_reverse(newtps)); } /* put lists of trackpoints into tracks */ iter = newlists; i = 1; - while (iter) { - gchar *new_tr_name; - VikTrack *tr; + // Only bother updating if the split results in new tracks + if (g_list_length (newlists) > 1) { + while (iter) { + gchar *new_tr_name; + VikTrack *tr; - tr = vik_track_new(); - tr->visible = track->visible; - tr->trackpoints = (GList *)(iter->data); + tr = vik_track_new(); + tr->visible = track->visible; + tr->trackpoints = (GList *)(iter->data); - new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++); - vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr); - /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp, + 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); + /* 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); + iter = g_list_next(iter); + } + vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]); + vik_layer_emit_update(VIK_LAYER(pass_along[0])); } g_list_free(newlists); - vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]); - vik_layer_emit_update(VIK_LAYER(pass_along[0])); } /** @@ -3205,6 +3307,89 @@ static void trw_layer_split_by_n_points ( gpointer pass_along[6] ) /* end of split/merge routines */ +/** + * Similar to trw_layer_enum_item, but this uses a sorted method + */ +static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata) +{ + GList **list = (GList**)udata; + //*list = g_list_prepend(*all, key); //unsorted method + // Sort named list alphabetically + *list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL); +} + +/** + * + */ +static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + GList *all = NULL; + // Sort list alphabetically for better presentation + g_hash_table_foreach(vtl->tracks, trw_layer_sorted_name_list, &all); + + if ( ! all ) { + a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No tracks found")); + return; + } + + // Get list of items to delete from the user + GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), + all, + TRUE, + _("Delete Selection"), + _("Select tracks to delete")); + g_list_free(all); + + // Delete requested tracks + // since specificly requested, IMHO no need for extra confirmation + if ( delete_list ) { + GList *l; + for (l = delete_list; l != NULL; l = g_list_next(l)) { + vik_trw_layer_delete_track(vtl, l->data); + } + g_list_free(delete_list); + vik_layer_emit_update( VIK_LAYER(vtl) ); + } +} + +/** + * + */ +static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]); + GList *all = NULL; + + // Sort list alphabetically for better presentation + g_hash_table_foreach ( vtl->waypoints, trw_layer_sorted_name_list, &all); + if ( ! all ) { + a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found")); + return; + } + + all = g_list_sort_with_data(all, sort_alphabetically, NULL); + + // Get list of items to delete from the user + GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl), + all, + TRUE, + _("Delete Selection"), + _("Select waypoints to delete")); + g_list_free(all); + + // Delete requested waypoints + // since specificly requested, IMHO no need for extra confirmation + if ( delete_list ) { + GList *l; + for (l = delete_list; l != NULL; l = g_list_next(l)) { + vik_trw_layer_delete_waypoint(vtl, l->data); + } + g_list_free(delete_list); + vik_layer_emit_update( VIK_LAYER(vtl) ); + } + +} static void trw_layer_goto_waypoint ( gpointer pass_along[6] ) { @@ -3350,7 +3535,6 @@ static void trw_layer_track_google_route_webpage ( gpointer pass_along[6] ) /* viewpoint is now available instead */ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp ) { - static GtkTreeIter staticiter; static gpointer pass_along[6]; GtkWidget *item; gboolean rv = FALSE; @@ -3359,10 +3543,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, pass_along[1] = vlp; pass_along[2] = GINT_TO_POINTER (subtype); pass_along[3] = sublayer; - if ( iter ) { - staticiter = *iter; /* will exist after function has ended */ - pass_along[4] = &staticiter; - } + pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request pass_along[5] = vvp; if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) @@ -3420,6 +3601,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, item = gtk_menu_item_new (); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + separator_created = TRUE; } item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") ); @@ -3428,18 +3610,81 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_widget_show ( item ); } + VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer ); + + if ( wp && wp->image ) + { + if ( !separator_created ) { + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + separator_created = TRUE; + } + + // Set up image paramater + pass_along[5] = wp->image; + + item = gtk_menu_item_new_with_mnemonic ( _("_Show Picture...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + } } if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) { rv = TRUE; - item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint") ); + item = gtk_menu_item_new_with_mnemonic ( _("_New Waypoint...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) + { + item = gtk_menu_item_new_with_mnemonic ( _("_View All Waypoints") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("_Delete Waypoints From Selection...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS ) + { + rv = TRUE; + + item = gtk_menu_item_new_with_mnemonic ( _("_View All Tracks") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("Delete _All Tracks") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + + item = gtk_menu_item_new_with_mnemonic ( _("_Delete Tracks From Selection...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) { GtkWidget *goto_submenu; @@ -3488,7 +3733,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time") ); + item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -3498,12 +3743,12 @@ 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_mnemonic ( _("_Split By Time") ); + item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points") ); + item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -3521,7 +3766,7 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Export Trac_k as GPX") ); + item = gtk_menu_item_new_with_mnemonic ( _("Export Trac_k as GPX...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -3531,13 +3776,13 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); - item = gtk_menu_item_new_with_mnemonic ( _("Extend _Using Magic Scissors") ); + item = gtk_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_ms), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); #ifdef VIK_CONFIG_OPENSTREETMAP - item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM") ); + item = gtk_menu_item_new_with_mnemonic ( _("Upload to _OSM...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); @@ -3566,6 +3811,21 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_widget_show ( item ); } } + + // Only show on viewport popmenu when a trackpoint is selected + if ( ! vlp && l->current_tpl ) { + // Add separator + item = gtk_menu_item_new (); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_with_mnemonic ( _("_Edit Trackpoint") ); + gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU) ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_edit_trackpoint), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + } + } return rv; @@ -3658,7 +3918,11 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) g_assert ( vtl->tpwin != NULL ); if ( response == VIK_TRW_LAYER_TPWIN_CLOSE ) trw_layer_cancel_current_tp ( vtl, TRUE ); - else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev ) + + if ( vtl->current_tpl == NULL ) + return; + + if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev ) { gchar *name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, vtl->current_tp_track_name); if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks, name ) ) ) @@ -3822,16 +4086,30 @@ static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchP return; vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y ); - - if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX && - ((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */ - abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) - { - params->closest_wp_name = name; - params->closest_wp = wp; - params->closest_x = x; - params->closest_y = y; + + // If waypoint has an image then use the image size to select + if ( wp->image ) { + gint slackx, slacky; + slackx = wp->image_width / 2; + slacky = wp->image_height / 2; + + if ( x <= params->x + slackx && x >= params->x - slackx + && y <= params->y + slacky && y >= params->y - slacky ) { + params->closest_wp_name = name; + params->closest_wp = wp; + params->closest_x = x; + params->closest_y = y; + } } + else if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX && + ((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */ + abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) + { + params->closest_wp_name = name; + params->closest_wp = wp; + params->closest_x = x; + params->closest_y = y; + } } static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params ) @@ -3887,12 +4165,106 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie return params.closest_wp; } +// Some forward declarations +static void marker_begin_move ( tool_ed_t *t, gint x, gint y ); +static void marker_moveto ( tool_ed_t *t, gint x, gint y ); +static void marker_end_move ( tool_ed_t *t ); +// + +static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t ) +{ + if ( t->holding ) { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + // Here always allow snapping back to the original location + // this is useful when one decides not to move the thing afterall + // If one wants to move the item only a little bit then don't hold down the 'snap' key! + + // 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 ) + 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 trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t ) +{ + 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 ) + new_coord = wp->coord; + } + + marker_end_move ( t ); + + // Determine if working on a waypoint or a trackpoint + if ( t->is_waypoint ) + vtl->current_wp->coord = new_coord; + else { + if ( vtl->current_tpl ) { + VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; + + if ( vtl->tpwin ) + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name ); + + // Don't really know what this is for but seems like it might be handy... + /* can't join with itself! */ + trw_layer_cancel_last_tp ( vtl ); + } + } + + // Reset + vtl->current_wp = NULL; + vtl->current_wp_name = NULL; + trw_layer_cancel_current_tp ( vtl, FALSE ); + + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + return FALSE; +} + /* Returns true if a waypoint or track is found near the requested event position for this particular layer The item found is automatically selected This is a tool like feature but routed via the layer interface, since it's instigated by a 'global' layer tool in vikwindow.c */ -static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* tet ) { if ( event->button != 1 ) return FALSE; @@ -3903,7 +4275,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event if ( !vtl->tracks_visible && !vtl->waypoints_visible ) return FALSE; - /* Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track */ + // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track if (vtl->waypoints_visible) { WPSearchParams wp_params; @@ -3916,8 +4288,27 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params); if ( wp_params.closest_wp ) { + + // Select vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_name ), TRUE ); + + // Too easy to move it so must be holding shift to start immediately moving it + // or otherwise be previously selected + if ( event->state & GDK_SHIFT_MASK || + vtl->current_wp == wp_params.closest_wp ) { + // Put into 'move buffer' + // NB vvp & vw already set in tet + tet->vtl = (gpointer)vtl; + tet->is_waypoint = TRUE; + + marker_begin_move (tet, event->x, event->y); + } + + vtl->current_wp = wp_params.closest_wp; + vtl->current_wp_name = wp_params.closest_wp_name; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; } } @@ -3933,13 +4324,38 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params); if ( tp_params.closest_tp ) { + + // Always select + highlight the track vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, tp_params.closest_track_name ), TRUE ); + + tet->is_waypoint = FALSE; + + // Select the Trackpoint + // Can move it immediately when control held or it's the previously selected tp + if ( event->state & GDK_CONTROL_MASK || + vtl->current_tpl == tp_params.closest_tpl ) { + // Put into 'move buffer' + // NB vvp & vw already set in tet + tet->vtl = (gpointer)vtl; + marker_begin_move (tet, event->x, event->y); + } + + vtl->current_tpl = tp_params.closest_tpl; + vtl->current_tp_track_name = tp_params.closest_track_name; + + if ( vtl->tpwin ) + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name ); + vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } } /* these aren't the droids you're looking for */ + vtl->current_wp = NULL; + vtl->current_wp_name = NULL; + trw_layer_cancel_current_tp ( vtl, FALSE ); + return FALSE; } @@ -4019,13 +4435,6 @@ static gboolean tool_sync(gpointer data) 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; @@ -4668,6 +5077,25 @@ static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[ } } +static void trw_layer_show_picture ( gpointer pass_along[6] ) +{ + /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */ +#ifdef WINDOWS + ShellExecute(NULL, NULL, (char *) pass_along[2], NULL, ".\\", 0); +#else /* WINDOWS */ + GError *err = NULL; + gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] ); + 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( pass_along[0]), _("Could not launch eog to open file.") ); + g_error_free ( err ); + } + g_free ( cmd ); +#endif /* WINDOWS */ +} + static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) { gpointer params[3] = { vvp, event, NULL }; @@ -4676,21 +5104,10 @@ static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *even g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params ); if ( params[2] ) { - /* 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 */ + static gpointer pass_along[6]; + pass_along[0] = vtl; + pass_along[5] = params[2]; + trw_layer_show_picture ( pass_along ); return TRUE; /* found a match */ } else @@ -4988,7 +5405,7 @@ static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] ) 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); + GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types int num_maps = g_list_length(vmls); if (!num_maps) {