diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 6253e730d..c6d1a103a 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -767,11 +767,12 @@ void TrackPanel::Uncapture(wxMouseState *pState) HandleMotion( *pState ); } -void TrackPanel::CancelDragging() +bool TrackPanel::CancelDragging() { if (mUIHandle) { // copy shared_ptr for safety, as in HandleClick auto handle = mUIHandle; + // UIHANDLE CANCEL UIHandle::Result refreshResult = handle->Cancel(GetProject()); auto pTrack = GetTracks()->Lock(mpClickedTrack); if (pTrack) @@ -781,7 +782,9 @@ void TrackPanel::CancelDragging() mpClickedTrack.reset(); mUIHandle.reset(), handle.reset(), ClearTargets(); Uncapture(); + return true; } + return false; } bool TrackPanel::HandleEscapeKey(bool down) @@ -789,13 +792,22 @@ bool TrackPanel::HandleEscapeKey(bool down) if (!down) return false; + auto target = Target(); + if (target && target->HasEscape() && target->Escape()) { + HandleCursorForPresentMouseState(false); + return true; + } + if (mUIHandle) { - // UIHANDLE CANCEL CancelDragging(); return true; } - // Not escaping from a mouse drag + if (ChangeTarget(true, false)) { + HandleCursorForPresentMouseState(false); + return true; + } + return false; } @@ -972,9 +984,9 @@ void TrackPanel::HandleMotion pCursor = &defaultCursor; } - if (HasRotation()) + if (HasEscape()) /* i18n-hint TAB is a key on the keyboard */ - tip += wxT(" "), tip += _("(Tab for more choices)"); + tip += wxT(" "), tip += _("(Esc to cancel)"); this->SetToolTip(tip); mListener->TP_DisplayStatusMessage(tip); if (pCursor) @@ -993,21 +1005,39 @@ bool TrackPanel::HasRotation() return target && target->HasRotation(); } -void TrackPanel::RotateTarget(bool forward) +bool TrackPanel::HasEscape() +{ + if (HasCapture()) + return true; + + if (mTarget + 1 == mTargets.size() && + Target() && + !Target()->HasEscape()) + return false; + + return true; +} + +bool TrackPanel::ChangeTarget(bool forward, bool cycle) { auto size = mTargets.size(); auto target = Target(); if (target && target->HasRotation()) { if(target->Rotate(forward)) - return; - else if (size == 1 || IsMouseCaptured()) { + return true; + else if (cycle && (size == 1 || IsMouseCaptured())) { // Rotate through the states of this target only. target->Enter(forward); - return; + return true; } } + if (!cycle && + ((forward && mTarget + 1 == size) || + (!forward && mTarget == 0))) + return false; + if (size > 1) { if (forward) ++mTarget; @@ -1016,7 +1046,10 @@ void TrackPanel::RotateTarget(bool forward) mTarget %= size; if (Target()) Target()->Enter(forward); + return true; } + + return false; } void TrackPanel::UpdateSelectionDisplay() @@ -1401,6 +1434,7 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event) event.Skip(kevent->GetSkipped()); } +#if 0 // Special TAB key handling, but only if the track didn't capture it if ( !(t && !kevent->GetSkipped()) && WXK_TAB == code && HasRotation() ) { @@ -1409,7 +1443,9 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event) mEnableTab = true; return; } - else if (!t) + else +#endif + if (!t) event.Skip(); } @@ -1444,14 +1480,16 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event) HandlePageDownKey(); return; +#if 0 case WXK_TAB: if ( mEnableTab && HasRotation() ) { - RotateTarget( !event.ShiftDown() ); + ChangeTarget( !event.ShiftDown(), true ); HandleCursorForPresentMouseState(false); return; } else break; +#endif } Track *const t = GetFocusedTrack(); @@ -1611,7 +1649,7 @@ try ::wxGetMouseState().ButtonIsDown(wxMOUSE_BTN_ANY); if(!buttons) { - HandleEscapeKey( true ); + CancelDragging(); #if defined(__WXMAC__) @@ -1692,7 +1730,7 @@ try catch( ... ) { // Abort any dragging, as if by hitting Esc - if ( HandleEscapeKey( true ) ) + if ( CancelDragging() ) ; else { Uncapture(); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 99ce8ade4..7eab87961 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -316,7 +316,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel { void HandleInterruptedDrag(); void Uncapture( wxMouseState *pState = nullptr ); - void CancelDragging(); + bool CancelDragging(); bool HandleEscapeKey(bool down); void UpdateMouseState(const wxMouseState &state); void HandleModifierKey(); @@ -552,8 +552,9 @@ protected: } bool HasRotation(); + bool HasEscape(); - void RotateTarget(bool forward); + bool ChangeTarget(bool forward, bool cycle); std::weak_ptr mpClickedTrack; UIHandlePtr mUIHandle; diff --git a/src/UIHandle.cpp b/src/UIHandle.cpp index f5a7db581..b8c3ef499 100644 --- a/src/UIHandle.cpp +++ b/src/UIHandle.cpp @@ -10,6 +10,7 @@ Paul Licameli #include "Audacity.h" #include "UIHandle.h" +#include "RefreshCode.h" UIHandle::~UIHandle() { @@ -29,6 +30,16 @@ bool UIHandle::Rotate(bool) return false; } +bool UIHandle::HasEscape() const +{ + return false; +} + +bool UIHandle::Escape() +{ + return false; +} + void UIHandle::DrawExtras (DrawingPass, wxDC *, const wxRegion &, const wxRect &) { diff --git a/src/UIHandle.h b/src/UIHandle.h index ea6cddaf9..ff8074962 100644 --- a/src/UIHandle.h +++ b/src/UIHandle.h @@ -62,6 +62,15 @@ public: // Default does nothing and returns false virtual bool Rotate(bool forward); + // Tell whether the handle has its own escape action. In case it is already + // clicked, it will not cancel on Escape key if true. + // Default is always false. + virtual bool HasEscape() const; + + // The handle may change state and mark itself for highlight change. + // Default does nothing and returns false + virtual bool Escape(); + // Assume hit test (implemented in other classes) was positive. // May return Cancelled, overriding the hit test decision and stopping drag. // Otherwise the framework will later call Release or Cancel after diff --git a/src/tracks/ui/SelectHandle.cpp b/src/tracks/ui/SelectHandle.cpp index 854663e87..672bf8661 100644 --- a/src/tracks/ui/SelectHandle.cpp +++ b/src/tracks/ui/SelectHandle.cpp @@ -474,11 +474,16 @@ namespace { } } -void SelectHandle::Enter(bool forward) +void SelectHandle::Enter(bool) { - mUseSnap = forward; + SetUseSnap(true); +} - bool hasSnap = HasRotation(); +void SelectHandle::SetUseSnap(bool use) +{ + mUseSnap = use; + + bool hasSnap = HasSnap(); if (hasSnap) // Repaint to turn the snap lines on or off mChangeHighlight = RefreshCode::RefreshAll; @@ -491,19 +496,22 @@ void SelectHandle::Enter(bool forward) nullptr); } -bool SelectHandle::HasRotation() const +bool SelectHandle::HasSnap() const { return - mSnapStart.snappedPoint || (IsClicked() && mSnapEnd.snappedPoint); + (IsClicked() ? mSnapEnd : mSnapStart).snappedPoint; } -bool SelectHandle::Rotate(bool forward) +bool SelectHandle::HasEscape() const { - if (SelectHandle::HasRotation()) { - if (mUseSnap == forward) { - Enter(!forward); - return true; - } + return HasSnap() && mUseSnap; +} + +bool SelectHandle::Escape() +{ + if (SelectHandle::HasEscape()) { + SetUseSnap(false); + return true; } return false; } @@ -866,7 +874,8 @@ UIHandle::Result SelectHandle::Drag HitTestPreview SelectHandle::Preview (const TrackPanelMouseState &st, const AudacityProject *pProject) { - if (!HasRotation()) + if (!HasSnap() && !mUseSnap) + // Moved out of snapping; revert to un-escaped state mUseSnap = true; auto pTrack = mpTrack.lock(); @@ -963,13 +972,10 @@ HitTestPreview SelectHandle::Preview if (ttb) tip = ttb->GetMessageForTool(selectTool); } - if (HasRotation()) { - tip += wxT(" ") + (mUseSnap + if (HasEscape() && mUseSnap) { + tip += wxT(" ") + /* i18n-hint: "Snapping" means automatic alignment of selection edges to any nearby label or clip boundaries */ - ? _("(snapping)") -/* i18n-hint: "Snapping" means automatic alignment of selection edges to any nearby label or clip boundaries */ - : _("(not snapping)") - ); + _("(snapping)"); } return { tip, pCursor }; } @@ -1010,8 +1016,11 @@ void SelectHandle::DrawExtras { if (pass == Panel) { // Draw snap guidelines if we have any - if ( mUseSnap && mSnapManager ) - mSnapManager->Draw( dc, mSnapStart.outCoord, mSnapEnd.outCoord ); + if ( mSnapManager ) { + auto coord1 = (mUseSnap || IsClicked()) ? mSnapStart.outCoord : -1; + auto coord2 = (!mUseSnap || !IsClicked()) ? -1 : mSnapEnd.outCoord; + mSnapManager->Draw( dc, coord1, coord2 ); + } } } diff --git a/src/tracks/ui/SelectHandle.h b/src/tracks/ui/SelectHandle.h index 9ebec38a6..0a729cb2b 100644 --- a/src/tracks/ui/SelectHandle.h +++ b/src/tracks/ui/SelectHandle.h @@ -52,11 +52,13 @@ public: bool IsClicked() const; + void SetUseSnap(bool use); void Enter(bool forward) override; - bool HasRotation() const override; + bool HasSnap() const; + bool HasEscape() const override; - bool Rotate(bool forward) override; + bool Escape() override; Result Click (const TrackPanelMouseEvent &event, AudacityProject *pProject) override;