From 08f14055b729c70c631eef2113853a8d160c7f33 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 4 Feb 2011 00:15:35 +0000 Subject: [PATCH] Add ability to move selected trackpoint or waypoint by the mouse within the select tool. If you want to move the waypoint immediately press shift whilst selecting the waypoint, otherwise one can move it on the second selection. If you want to move the trackpoint immediately press control whilst selecting the trackpoint, otherwise one can move it on the second selection. The idea is to prevent accidently moving the item upon initial selection. Reuse the core of the existing track/waypoint tool move code. --- src/vikaggregatelayer.c | 2 + src/vikcoordlayer.c | 2 + src/vikdemlayer.c | 2 + src/vikgeoreflayer.c | 2 + src/vikgpslayer.c | 2 + src/viklayer.h | 6 +- src/vikmapslayer.c | 2 + src/viktrwlayer.c | 155 +++++++++++++++++++++++++++++++++++++--- src/vikwindow.c | 64 +++++++++++++---- src/vikwindow.h | 10 +++ 10 files changed, 222 insertions(+), 25 deletions(-) diff --git a/src/vikaggregatelayer.c b/src/vikaggregatelayer.c index 1495d240..66d05a96 100644 --- a/src/vikaggregatelayer.c +++ b/src/vikaggregatelayer.c @@ -83,6 +83,8 @@ VikLayerInterface vik_aggregate_layer_interface = { (VikLayerFuncDragDropRequest) aggregate_layer_drag_drop_request, (VikLayerFuncSelectClick) NULL, + (VikLayerFuncSelectMove) NULL, + (VikLayerFuncSelectRelease) NULL, (VikLayerFuncSelectedViewportMenu) NULL, }; diff --git a/src/vikcoordlayer.c b/src/vikcoordlayer.c index 961716d5..b41669be 100644 --- a/src/vikcoordlayer.c +++ b/src/vikcoordlayer.c @@ -103,6 +103,8 @@ VikLayerInterface vik_coord_layer_interface = { (VikLayerFuncDragDropRequest) NULL, (VikLayerFuncSelectClick) NULL, + (VikLayerFuncSelectMove) NULL, + (VikLayerFuncSelectRelease) NULL, (VikLayerFuncSelectedViewportMenu) NULL, }; diff --git a/src/vikdemlayer.c b/src/vikdemlayer.c index 1c551f43..2d434cf4 100644 --- a/src/vikdemlayer.c +++ b/src/vikdemlayer.c @@ -234,6 +234,8 @@ VikLayerInterface vik_dem_layer_interface = { (VikLayerFuncDragDropRequest) NULL, (VikLayerFuncSelectClick) NULL, + (VikLayerFuncSelectMove) NULL, + (VikLayerFuncSelectRelease) NULL, (VikLayerFuncSelectedViewportMenu) NULL, }; diff --git a/src/vikgeoreflayer.c b/src/vikgeoreflayer.c index 065e26d2..da8a1c61 100644 --- a/src/vikgeoreflayer.c +++ b/src/vikgeoreflayer.c @@ -127,6 +127,8 @@ VikLayerInterface vik_georef_layer_interface = { (VikLayerFuncDragDropRequest) NULL, (VikLayerFuncSelectClick) NULL, + (VikLayerFuncSelectMove) NULL, + (VikLayerFuncSelectRelease) NULL, (VikLayerFuncSelectedViewportMenu) NULL, }; diff --git a/src/vikgpslayer.c b/src/vikgpslayer.c index 526707c6..ebda591c 100644 --- a/src/vikgpslayer.c +++ b/src/vikgpslayer.c @@ -220,6 +220,8 @@ VikLayerInterface vik_gps_layer_interface = { (VikLayerFuncDragDropRequest) gps_layer_drag_drop_request, (VikLayerFuncSelectClick) NULL, + (VikLayerFuncSelectMove) NULL, + (VikLayerFuncSelectRelease) NULL, (VikLayerFuncSelectedViewportMenu) NULL, }; diff --git a/src/viklayer.h b/src/viklayer.h index d1fa70e8..4400d64f 100644 --- a/src/viklayer.h +++ b/src/viklayer.h @@ -183,7 +183,9 @@ typedef void (*VikLayerFuncFreeCopiedItem) (gint, gpointer); */ typedef void (*VikLayerFuncDragDropRequest) (VikLayer *, VikLayer *, GtkTreeIter *, GtkTreePath *); -typedef gboolean (*VikLayerFuncSelectClick) (VikLayer *, GdkEventButton *, VikViewport *); +typedef gboolean (*VikLayerFuncSelectClick) (VikLayer *, GdkEventButton *, VikViewport *, tool_ed_t*); +typedef gboolean (*VikLayerFuncSelectMove) (VikLayer *, GdkEventButton *, VikViewport *, tool_ed_t*); +typedef gboolean (*VikLayerFuncSelectRelease) (VikLayer *, GdkEventButton *, VikViewport *, tool_ed_t*); typedef gboolean (*VikLayerFuncSelectedViewportMenu) (VikLayer *, GdkEventButton *, VikViewport *); typedef enum { @@ -254,6 +256,8 @@ struct _VikLayerInterface { VikLayerFuncDragDropRequest drag_drop_request; VikLayerFuncSelectClick select_click; + VikLayerFuncSelectMove select_move; + VikLayerFuncSelectRelease select_release; VikLayerFuncSelectedViewportMenu show_viewport_menu; }; diff --git a/src/vikmapslayer.c b/src/vikmapslayer.c index ea299f84..7e501fab 100644 --- a/src/vikmapslayer.c +++ b/src/vikmapslayer.c @@ -188,6 +188,8 @@ VikLayerInterface vik_maps_layer_interface = { (VikLayerFuncDragDropRequest) NULL, (VikLayerFuncSelectClick) NULL, + (VikLayerFuncSelectMove) NULL, + (VikLayerFuncSelectRelease) NULL, (VikLayerFuncSelectedViewportMenu) NULL, }; diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index ee6f7ebb..c2cade01 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -274,7 +274,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 ); @@ -473,6 +475,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, }; @@ -3887,12 +3891,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 +4001,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 +4014,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 +4050,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 +4161,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; diff --git a/src/vikwindow.c b/src/vikwindow.c index 5a1ea437..43560284 100644 --- a/src/vikwindow.c +++ b/src/vikwindow.c @@ -1100,13 +1100,24 @@ static VikToolInterface pan_tool = ********************************************************************************/ static gpointer selecttool_create (VikWindow *vw, VikViewport *vvp) { - return vw; + tool_ed_t *t = g_new(tool_ed_t, 1); + t->vw = vw; + t->vvp = vvp; + t->vtl = NULL; + t->is_waypoint = FALSE; + return t; +} + +static void selecttool_destroy (tool_ed_t *t) +{ + g_free(t); } typedef struct { gboolean cont; VikViewport *vvp; GdkEventButton *event; + tool_ed_t *tool_edit; } clicker; static void click_layer_selected (VikLayer *vl, clicker *ck) @@ -1115,28 +1126,29 @@ static void click_layer_selected (VikLayer *vl, clicker *ck) /* i.e. stop on first found item */ if ( ck->cont ) if ( vl->visible ) - if ( vik_layer_get_interface(vl->type)->select_request ) - ck->cont = !vik_layer_get_interface(vl->type)->select_request ( vl, ck->event, ck->vvp ); + if ( vik_layer_get_interface(vl->type)->select_click ) + ck->cont = !vik_layer_get_interface(vl->type)->select_click ( vl, ck->event, ck->vvp, ck->tool_edit ); } -static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *event, VikWindow *vw) +static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *event, tool_ed_t *t) { /* Only allow selection on primary button */ if ( event->button == 1 ) { /* Enable click to apply callback to potentially all track/waypoint layers */ /* Useful as we can find things that aren't necessarily in the currently selected layer */ - GList* gl = vik_layers_panel_get_all_layers_of_type ( vw->viking_vlp, VIK_LAYER_TRW ); + GList* gl = vik_layers_panel_get_all_layers_of_type ( t->vw->viking_vlp, VIK_LAYER_TRW ); clicker ck; ck.cont = TRUE; - ck.vvp = vw->viking_vvp; + ck.vvp = t->vw->viking_vvp; ck.event = event; + ck.tool_edit = t; g_list_foreach ( gl, (GFunc) click_layer_selected, &ck ); g_list_free ( gl ); // If nothing found then deselect & redraw screen if necessary to remove the highlight if ( ck.cont ) { GtkTreeIter iter; - VikTreeview *vtv = vik_layers_panel_get_treeview ( vw->viking_vlp ); + VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp ); if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) { // Only clear if selected thing is a TrackWaypoint layer or a sublayer @@ -1145,8 +1157,8 @@ static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *ev VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) { vik_treeview_item_unselect ( vtv, &iter ); - if ( vik_window_clear_highlight ( vw ) ) - draw_update ( vw ); + if ( vik_window_clear_highlight ( t->vw ) ) + draw_update ( t->vw ); } } } @@ -1154,23 +1166,47 @@ static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *ev else if ( ( event->button == 3 ) && ( vl && ( vl->type == VIK_LAYER_TRW ) ) ) { if ( vl->visible ) /* Act on currently selected item to show menu */ - if ( ( vw->selected_track || vw->selected_waypoint ) && vw->selected_name ) + if ( ( t->vw->selected_track || t->vw->selected_waypoint ) && t->vw->selected_name ) if ( vik_layer_get_interface(vl->type)->show_viewport_menu ) - vik_layer_get_interface(vl->type)->show_viewport_menu ( vl, event, vw->viking_vvp ); + vik_layer_get_interface(vl->type)->show_viewport_menu ( vl, event, t->vw->viking_vvp ); } return VIK_LAYER_TOOL_ACK; } +static VikLayerToolFuncStatus selecttool_move (VikLayer *vl, GdkEventButton *event, tool_ed_t *t) +{ + /* Only allow selection on primary button */ + if ( event->button == 1 ) { + // Don't care about vl here + if ( t->vtl ) + if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_move ) + vik_layer_get_interface(VIK_LAYER_TRW)->select_move ( vl, event, t->vvp, t ); + } + return VIK_LAYER_TOOL_ACK; +} + +static VikLayerToolFuncStatus selecttool_release (VikLayer *vl, GdkEventButton *event, tool_ed_t *t) +{ + /* Only allow selection on primary button */ + if ( event->button == 1 ) { + // Don't care about vl here + if ( t->vtl ) + if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_release ) + vik_layer_get_interface(VIK_LAYER_TRW)->select_release ( (VikLayer*)t->vtl, event, t->vvp, t ); + } + return VIK_LAYER_TOOL_ACK; +} + static VikToolInterface select_tool = { "Select", (VikToolConstructorFunc) selecttool_create, - (VikToolDestructorFunc) NULL, + (VikToolDestructorFunc) selecttool_destroy, (VikToolActivationFunc) NULL, (VikToolActivationFunc) NULL, (VikToolMouseFunc) selecttool_click, - (VikToolMouseMoveFunc) NULL, - (VikToolMouseFunc) NULL, + (VikToolMouseMoveFunc) selecttool_move, + (VikToolMouseFunc) selecttool_release, (VikToolKeyFunc) NULL, GDK_LEFT_PTR, NULL, diff --git a/src/vikwindow.h b/src/vikwindow.h index a0fed725..855e58c0 100644 --- a/src/vikwindow.h +++ b/src/vikwindow.h @@ -77,6 +77,16 @@ gpointer vik_window_get_selected_name ( VikWindow *vw ); /* return indicates if a redraw is necessary */ gboolean vik_window_clear_highlight ( VikWindow *vw ); +typedef struct { + VikWindow *vw; + VikViewport *vvp; + gpointer *vtl; // VikTrwlayer + gboolean holding; + gboolean is_waypoint; // otherwise a track + GdkGC *gc; + int oldx, oldy; +} tool_ed_t; + G_END_DECLS #define VIK_WINDOW_FROM_WIDGET(x) VIK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(x))) -- 2.39.5