From 703abe87bceb830daeedab37318df66fe1b2229f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 9 Aug 2015 13:48:27 -0400 Subject: [PATCH] TrackPanel no longer implements track selection click or rearrange drag... ... also implement ESC key for the drag --- mac/Audacity.xcodeproj/project.pbxproj | 6 + src/Makefile.am | 2 + src/TrackPanel.cpp | 178 +------------- src/TrackPanel.h | 28 +-- src/tracks/ui/TrackControls.cpp | 6 +- src/tracks/ui/TrackSelectHandle.cpp | 227 ++++++++++++++++++ src/tracks/ui/TrackSelectHandle.h | 63 +++++ win/Projects/Audacity/Audacity.vcxproj | 2 + .../Audacity/Audacity.vcxproj.filters | 8 +- 9 files changed, 330 insertions(+), 190 deletions(-) create mode 100644 src/tracks/ui/TrackSelectHandle.cpp create mode 100644 src/tracks/ui/TrackSelectHandle.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 8f286e1aa..7ca7446e3 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1233,6 +1233,7 @@ 5E7396561DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396541DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp */; }; 5E7396591DAFDA3600BA0A4D /* TrackButtonHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */; }; 5E73965C1DAFDAA400BA0A4D /* BackgroundCell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73965A1DAFDAA400BA0A4D /* BackgroundCell.cpp */; }; + 5E73965F1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73965D1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp */; }; 5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; }; 5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; }; 5E74D2E51CC4429700D88B0B /* Scrubbing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */; }; @@ -3070,6 +3071,8 @@ 5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackButtonHandles.h; sourceTree = ""; }; 5E73965A1DAFDAA400BA0A4D /* BackgroundCell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackgroundCell.cpp; sourceTree = ""; }; 5E73965B1DAFDAA400BA0A4D /* BackgroundCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackgroundCell.h; sourceTree = ""; }; + 5E73965D1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackSelectHandle.cpp; sourceTree = ""; }; + 5E73965E1DAFDAEC00BA0A4D /* TrackSelectHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackSelectHandle.h; sourceTree = ""; }; 5E74D2D91CC4427B00D88B0B /* TrackPanelCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCell.h; sourceTree = ""; }; 5E74D2DA1CC4427B00D88B0B /* TrackPanelCellIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCellIterator.h; sourceTree = ""; }; 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditCursorOverlay.cpp; sourceTree = ""; }; @@ -5778,6 +5781,7 @@ 5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */, 5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */, 5E1512681DB0010C00702E29 /* TrackControls.cpp */, + 5E73965D1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp */, 5E15126A1DB0010C00702E29 /* TrackUI.cpp */, 5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */, 5E73963C1DAFD86000BA0A4D /* ZoomHandle.cpp */, @@ -5792,6 +5796,7 @@ 5E7396431DAFD8C600BA0A4D /* TimeShiftHandle.h */, 5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */, 5E1512691DB0010C00702E29 /* TrackControls.h */, + 5E73965E1DAFDAEC00BA0A4D /* TrackSelectHandle.h */, 5E15126C1DB0010C00702E29 /* TrackVRulerControls.h */, 5E73963D1DAFD86000BA0A4D /* ZoomHandle.h */, ); @@ -7893,6 +7898,7 @@ 2888495E131B6CF600B59735 /* km.po in Sources */, 2888495F131B6CF600B59735 /* ko.po in Sources */, 28884960131B6CF600B59735 /* lt.po in Sources */, + 5E73965F1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp in Sources */, 28884961131B6CF600B59735 /* mk.po in Sources */, 28884962131B6CF600B59735 /* my.po in Sources */, 28884963131B6CF600B59735 /* nb.po in Sources */, diff --git a/src/Makefile.am b/src/Makefile.am index 1f65420d0..7337393df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -601,6 +601,8 @@ audacity_SOURCES = \ tracks/ui/TrackButtonHandles.h \ tracks/ui/TrackControls.cpp \ tracks/ui/TrackControls.h \ + tracks/ui/TrackSelectHandle.cpp \ + tracks/ui/TrackSelectHandle.h \ tracks/ui/TrackUI.cpp \ tracks/ui/TrackVRulerControls.cpp \ tracks/ui/TrackVRulerControls.h \ diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 4727c6fda..8208d13f8 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -195,6 +195,8 @@ is time to refresh some aspect of the screen. //This loads the appropriate set of cursors, depending on platform. #include "../images/Cursors.h" +#include "widgets/ASlider.h" + DEFINE_EVENT_TYPE(EVT_TRACK_PANEL_TIMER) /* @@ -381,7 +383,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, mArrowCursor = std::make_unique(wxCURSOR_ARROW); mResizeCursor = std::make_unique(wxCURSOR_SIZENS); - mRearrangeCursor = std::make_unique(wxCURSOR_HAND); mAdjustLeftSelectionCursor = std::make_unique(wxCURSOR_POINT_LEFT); mAdjustRightSelectionCursor = std::make_unique(wxCURSOR_POINT_RIGHT); @@ -873,7 +874,6 @@ void TrackPanel::HandleInterruptedDrag() So this includes the cases: IsAdjustingLabel, - IsRearranging, IsStretching */ @@ -1123,9 +1123,6 @@ bool TrackPanel::SetCursorByActivity( ) case IsSelecting: SetCursor(*mSelectCursor); return true; - case IsRearranging: - SetCursor( unsafe ? *mDisabledCursor : *mRearrangeCursor); - return true; case IsAdjustingLabel: case IsSelectingLabelText: return true; @@ -1142,36 +1139,6 @@ bool TrackPanel::SetCursorByActivity( ) return false; } -#if defined(__WXMAC__) -/* i18n-hint: Command names a modifier key on Macintosh keyboards */ -#define CTRL_CLICK _("Command-Click") -#else -/* i18n-hint: Ctrl names a modifier key on Windows or Linux keyboards */ -#define CTRL_CLICK _("Ctrl-Click") -#endif - -/// When in the "label" (TrackInfo or vertical ruler), we can either vertical zoom or re-order tracks. -/// Dont't change cursor/tip to zoom if display is not waveform (either linear of dB) or Spectrum -void TrackPanel::SetCursorAndTipWhenInLabel( Track * , - const wxMouseEvent &, wxString &tip ) -{ - if( GetTrackCount() > 1 ) { - // Set a status message if over TrackInfo. - //tip = _("Drag the track vertically to change the order of the tracks."); - // i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac - tip = wxString::Format( _("%s to select or deselect track. Drag up or down to change track order."), - CTRL_CLICK ); - SetCursor( *mArrowCursor ); - } - else { - // Set a status message if over TrackInfo. - // i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac - tip = wxString::Format( _("%s to select or deselect track."), - CTRL_CLICK ); - SetCursor(*mArrowCursor); - } -} - /// When in the resize area we can adjust size or relative size. void TrackPanel::SetCursorAndTipWhenInVResizeArea( bool bLinked, wxString &tip ) { @@ -1492,9 +1459,6 @@ void TrackPanel::HandleCursor(wxMouseEvent & event) pCursor = hitTest.preview.cursor; if (pCursor) SetCursor(*pCursor); - else if (foundCell.type == CellType::Label || - foundCell.type == CellType::VRuler) - SetCursorAndTipWhenInLabel(track, event, tip); } // Is it a label track? @@ -1671,11 +1635,12 @@ void TrackPanel::HandleSelect(wxMouseEvent & event) } // Counts tracks, counting stereo tracks as one track. -size_t TrackPanel::GetTrackCount(){ +size_t TrackPanel::GetTrackCount() const +{ size_t count = 0; - TrackListIterator iter(GetTracks()); - for (Track *t = iter.First(); t; t = iter.Next()) { + TrackListConstIterator iter(GetTracks()); + for (auto t = iter.First(); t; t = iter.Next()) { count += 1; if( t->GetLinked() ){ t = iter.Next(); @@ -1687,11 +1652,12 @@ size_t TrackPanel::GetTrackCount(){ } // Counts selected tracks, counting stereo tracks as one track. -size_t TrackPanel::GetSelectedTrackCount(){ +size_t TrackPanel::GetSelectedTrackCount() const +{ size_t count = 0; - TrackListIterator iter(GetTracks()); - for (Track *t = iter.First(); t; t = iter.Next()) { + TrackListConstIterator iter(GetTracks()); + for (auto t = iter.First(); t; t = iter.Next()) { count += t->GetSelected() ? 1:0; if( t->GetLinked() ){ t = iter.Next(); @@ -3062,120 +3028,6 @@ bool TrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect, return subRect.y + subRect.height - allowance >= rect.y + limit; } -/// This handles when the user clicks on the "Label" area -/// of a track, ie the part with all the buttons and the drop -/// down menu, etc. -// That is, TrackInfo and vertical ruler rect. -void TrackPanel::HandleLabelClick(wxMouseEvent & event) -{ - // AS: If not a click, ignore the mouse event. - if (!event.ButtonDown() && !event.ButtonDClick()) { - return; - } - - // MIDI tracks use the right mouse button, but other tracks get confused - // if they see anything other than a left click. - bool isleft = event.Button(wxMOUSE_BTN_LEFT); - - bool unsafe = IsUnsafe(); - - const auto foundCell = FindCell(event.m_x, event.m_y); - auto &t = foundCell.pTrack; - auto &rect = foundCell.rect; - - if (!isleft) { - return; - } - - // DM: If they weren't clicking on a particular part of a track label, - // deselect other tracks and select this one. - - // JH: also, capture the current track for rearranging, so the user - // can drag the track up or down to swap it with others - if (!unsafe) { - mRearrangeCount = 0; - SetCapturedTrack(t, IsRearranging); - TrackPanel::CalculateRearrangingThresholds(event); - } - - GetProject()->HandleListSelection(t, event.ShiftDown(), event.ControlDown(), !unsafe); -} - -/// The user is dragging one of the tracks: change the track order -/// accordingly -void TrackPanel::HandleRearrange(wxMouseEvent & event) -{ - // are we finishing the drag? - if (event.LeftUp()) { - if (mRearrangeCount != 0) { - wxString dir; - /* i18n-hint: a direction as in up or down.*/ - dir = mRearrangeCount < 0 ? _("up") : _("down"); -/* i18n-hint: will substitute name of track for first %s, "up" or "down" for the other.*/ - MakeParentPushState(wxString::Format(_("Moved '%s' %s"), - mCapturedTrack->GetName().c_str(), - dir.c_str()), - _("Move Track")); - } - - SetCapturedTrack(NULL); - SetCursor(*mArrowCursor); - return; - } - - // probably harmless during play? However, we do disallow the click, so check this too. - bool unsafe = IsUnsafe(); - if (unsafe) - return; - - MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too. - if (event.m_y < mMoveUpThreshold || event.m_y < 0) { - mTracks->MoveUp(mCapturedTrack); - --mRearrangeCount; - if (pMixerBoard) - if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack )) - pMixerBoard->MoveTrackCluster(pPlayable, true /* up */); - } - else if (event.m_y > mMoveDownThreshold || event.m_y > GetRect().GetHeight()) { - mTracks->MoveDown(mCapturedTrack); - ++mRearrangeCount; - if (pMixerBoard) - if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack )) - pMixerBoard->MoveTrackCluster(pPlayable, false /* down */); - } - else - { - return; - } - - // JH: if we moved up or down, recalculate the thresholds and make sure the - // track is fully on-screen. - TrackPanel::CalculateRearrangingThresholds(event); - EnsureVisible(mCapturedTrack); -} - -/// Figure out how far the user must drag the mouse up or down -/// before the track will swap with the one above or below -void TrackPanel::CalculateRearrangingThresholds(wxMouseEvent & event) -{ - wxASSERT(mCapturedTrack); - - // JH: this will probably need to be tweaked a bit, I'm just - // not sure what formula will have the best feel for the - // user. - if (mTracks->CanMoveUp(mCapturedTrack)) - mMoveUpThreshold = - event.m_y - mTracks->GetGroupHeight( mTracks->GetPrev(mCapturedTrack,true) ); - else - mMoveUpThreshold = INT_MIN; - - if (mTracks->CanMoveDown(mCapturedTrack)) - mMoveDownThreshold = - event.m_y + mTracks->GetGroupHeight( mTracks->GetNext(mCapturedTrack,true) ); - else - mMoveDownThreshold = INT_MAX; -} - /// ButtonDown means they just clicked and haven't released yet. /// We use this opportunity to save which track they clicked on, /// and the initial height of the track, so as they drag we can @@ -3811,9 +3663,6 @@ try HandleResize(event); HandleCursor(event); break; - case IsRearranging: - HandleRearrange(event); - break; case IsAdjustingLabel: // Reach this case only when the captured track was label HandleGlyphDragRelease(static_cast(mCapturedTrack), event); @@ -4069,13 +3918,6 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event) ProcessUIHandleResult(this, mRuler, pTrack, pTrack, refreshResult); } - else { - if (foundCell.type == CellType::VRuler) { - } - else if (foundCell.type == CellType::Label) - HandleLabelClick(event); - } - HandleCursor(event); return; } diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 7d40385d3..77f7a8211 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -388,12 +388,14 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel { #endif // AS: Selection handling - size_t GetTrackCount(); - size_t GetSelectedTrackCount(); - virtual void HandleSelect(wxMouseEvent & event); - virtual void SelectionHandleDrag(wxMouseEvent &event, Track *pTrack); + +public: + size_t GetTrackCount() const; + size_t GetSelectedTrackCount() const; protected: + virtual void HandleSelect(wxMouseEvent & event); + virtual void SelectionHandleDrag(wxMouseEvent &event, Track *pTrack); virtual void SelectionHandleClick(wxMouseEvent &event, Track* pTrack, wxRect rect); @@ -424,9 +426,9 @@ protected: virtual void SelectTracksByLabel( LabelTrack *t ); +protected: // AS: Cursor handling virtual bool SetCursorByActivity( ); - virtual void SetCursorAndTipWhenInLabel( Track * t, const wxMouseEvent &event, wxString &tip ); virtual void SetCursorAndTipWhenInVResizeArea( bool blinked, wxString &tip ); virtual void SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, const wxMouseEvent & event, wxString &tip ); virtual void SetCursorAndTipWhenSelectTool @@ -448,11 +450,6 @@ protected: virtual void HandleResizeButtonUp(wxMouseEvent & event); virtual void HandleResize(wxMouseEvent & event); - virtual void HandleLabelClick(wxMouseEvent & event); - - virtual void HandleRearrange(wxMouseEvent & event); - virtual void CalculateRearrangingThresholds(wxMouseEvent & event); - public: virtual void MakeParentRedrawScrollbars(); @@ -487,7 +484,8 @@ protected: // JKC Nov-2011: These four functions only used from within a dll such as mod-track-panel // They work around some messy problems with constructors. public: - TrackList * GetTracks(){ return mTracks.get(); } + const TrackList * GetTracks() const { return mTracks.get(); } + TrackList * GetTracks() { return mTracks.get(); } ViewInfo * GetViewInfo(){ return mViewInfo;} TrackPanelListener * GetListener(){ return mListener;} AdornedRulerPanel * GetRuler(){ return mRuler;} @@ -697,7 +695,6 @@ public: IsResizing, IsResizingBetweenLinkedTracks, IsResizingBelowLinkedTracks, - IsRearranging, IsMuting, IsSoloing, IsMinimizing, @@ -709,17 +706,10 @@ protected: virtual void SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture=IsUncaptured ); - // JH: if the user is dragging a track, at what y - // coordinate should the dragging track move up or down? - int mMoveUpThreshold; - int mMoveDownThreshold; - int mRearrangeCount; - std::unique_ptr mArrowCursor, mSelectCursor, mResizeCursor, mEnvelopeCursor, // doubles as the center frequency cursor // for spectral selection - mRearrangeCursor, mDisabledCursor, mAdjustLeftSelectionCursor, mAdjustRightSelectionCursor; #ifdef EXPERIMENTAL_SPECTRAL_EDITING std::unique_ptr diff --git a/src/tracks/ui/TrackControls.cpp b/src/tracks/ui/TrackControls.cpp index deea704f2..6e7faaf0b 100644 --- a/src/tracks/ui/TrackControls.cpp +++ b/src/tracks/ui/TrackControls.cpp @@ -11,6 +11,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../Audacity.h" #include "TrackControls.h" #include "TrackButtonHandles.h" +#include "TrackSelectHandle.h" #include "../../HitTestResult.h" #include "../../RefreshCode.h" #include "../../MixerBoard.h" @@ -28,7 +29,7 @@ TrackControls::~TrackControls() HitTestResult TrackControls::HitTest (const TrackPanelMouseEvent &evt, - const AudacityProject *) + const AudacityProject *project) { const wxMouseEvent &event = evt.event; const wxRect &rect = evt.rect; @@ -43,7 +44,8 @@ HitTestResult TrackControls::HitTest if (NULL != (result = MinimizeButtonHandle::HitTest(event, rect)).handle) return result; - return result; + return TrackSelectHandle::HitAnywhere + (project->GetTrackPanel()->GetTrackCount()); } Track *TrackControls::FindTrack() diff --git a/src/tracks/ui/TrackSelectHandle.cpp b/src/tracks/ui/TrackSelectHandle.cpp new file mode 100644 index 000000000..5a8161fff --- /dev/null +++ b/src/tracks/ui/TrackSelectHandle.cpp @@ -0,0 +1,227 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +TrackSelectHandle.cpp + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#include "../../Audacity.h" +#include "TrackSelectHandle.h" +#include "TrackControls.h" +#include "../../Experimental.h" +#include "../../HitTestResult.h" +#include "../../MixerBoard.h" +#include "../../Project.h" +#include "../../RefreshCode.h" +#include "../../TrackPanel.h" +#include "../../TrackPanelMouseEvent.h" +#include "../../WaveTrack.h" + +#include "../../MemoryX.h" +#include +#include + +#include "../../../images/Cursors.h" + +TrackSelectHandle::TrackSelectHandle() +{ +} + +TrackSelectHandle &TrackSelectHandle::Instance() +{ + static TrackSelectHandle instance; + return instance; +} + +#if defined(__WXMAC__) +/* i18n-hint: Command names a modifier key on Macintosh keyboards */ +#define CTRL_CLICK _("Command-Click") +#else +/* i18n-hint: Ctrl names a modifier key on Windows or Linux keyboards */ +#define CTRL_CLICK _("Ctrl-Click") +#endif + +namespace { + wxString Message(unsigned trackCount) { + if (trackCount > 1) + // i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac + return wxString::Format( + _("%s to select or deselect track. Drag up or down to change track order."), + CTRL_CLICK ); + else + // i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac + return wxString::Format( + _("%s to select or deselect track."), + CTRL_CLICK ); + } +} + +HitTestPreview TrackSelectHandle::HitPreview(unsigned trackCount) +{ + static wxCursor arrowCursor{ wxCURSOR_ARROW }; + return { + Message(trackCount), + &arrowCursor + }; +} + +HitTestResult TrackSelectHandle::HitAnywhere(unsigned trackCount) +{ + return { + HitPreview(trackCount), + &Instance() + }; +} + +TrackSelectHandle::~TrackSelectHandle() +{ +} + +UIHandle::Result TrackSelectHandle::Click +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + using namespace RefreshCode; + Result result = RefreshNone; + + const wxMouseEvent &event = evt.event; + + // AS: If not a click, ignore the mouse event. + if (!event.ButtonDown() && !event.ButtonDClick()) + return Cancelled; + if (!event.Button(wxMOUSE_BTN_LEFT)) + return Cancelled; + + TrackControls *const pControls = static_cast(evt.pCell); + Track *const pTrack = pControls->GetTrack(); + TrackPanel *const trackPanel = pProject->GetTrackPanel(); + const bool unsafe = pProject->IsAudioActive(); + + // DM: If they weren't clicking on a particular part of a track label, + // deselect other tracks and select this one. + + // JH: also, capture the current track for rearranging, so the user + // can drag the track up or down to swap it with others + if (unsafe) + result |= Cancelled; + else { + mRearrangeCount = 0; + mpTrack = pTrack; + CalculateRearrangingThresholds(event); + } + + pProject->HandleListSelection + (pTrack, event.ShiftDown(), event.ControlDown(), !unsafe); + + return result; +} + +UIHandle::Result TrackSelectHandle::Drag +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + using namespace RefreshCode; + Result result = RefreshNone; + + const wxMouseEvent &event = evt.event; + + TrackList *const tracks = pProject->GetTracks(); + + // probably harmless during play? However, we do disallow the click, so check this too. + bool unsafe = pProject->IsAudioActive(); + if (unsafe) + return result; + + MixerBoard* pMixerBoard = pProject->GetMixerBoard(); // Update mixer board, too. + if (event.m_y < mMoveUpThreshold || event.m_y < 0) { + tracks->MoveUp(mpTrack); + --mRearrangeCount; + if (pMixerBoard) + if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mpTrack )) + pMixerBoard->MoveTrackCluster(pPlayable, true /* up */); + } + else if ( event.m_y > mMoveDownThreshold + || event.m_y > evt.whole.GetHeight() ) { + tracks->MoveDown(mpTrack); + ++mRearrangeCount; + if (pMixerBoard) + if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mpTrack )) + pMixerBoard->MoveTrackCluster(pPlayable, false /* down */); + } + else + return result; + + // JH: if we moved up or down, recalculate the thresholds and make sure the + // track is fully on-screen. + CalculateRearrangingThresholds(event); + + result |= EnsureVisible; + return result; +} + +HitTestPreview TrackSelectHandle::Preview +(const TrackPanelMouseEvent &, const AudacityProject *project) +{ + // Note that this differs from HitPreview. + + static auto disabledCursor = + ::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16); + static wxCursor rearrangeCursor{ wxCURSOR_HAND }; + + const bool unsafe = GetActiveProject()->IsAudioActive(); + return { + Message(project->GetTrackPanel()->GetTrackCount()), + (unsafe + ? &*disabledCursor + : &rearrangeCursor) + }; +} + +UIHandle::Result TrackSelectHandle::Release +(const TrackPanelMouseEvent &, AudacityProject *, wxWindow *) +{ + if (mRearrangeCount != 0) { + AudacityProject *const project = ::GetActiveProject(); + wxString dir; + /* i18n-hint: a direction as in up or down.*/ + dir = mRearrangeCount < 0 ? _("up") : _("down"); +/* i18n-hint: will substitute name of track for first %s, "up" or "down" for the other.*/ + project->PushState(wxString::Format(_("Moved '%s' %s"), + mpTrack->GetName().c_str(), + dir.c_str()), + _("Move Track")); + } + // No need to redraw, that was done when drag moved the track + return RefreshCode::RefreshNone; +} + +UIHandle::Result TrackSelectHandle::Cancel(AudacityProject *pProject) +{ + pProject->RollbackState(); + return RefreshCode::RefreshAll; +} + +/// Figure out how far the user must drag the mouse up or down +/// before the track will swap with the one above or below +void TrackSelectHandle::CalculateRearrangingThresholds(const wxMouseEvent & event) +{ + // JH: this will probably need to be tweaked a bit, I'm just + // not sure what formula will have the best feel for the + // user. + + AudacityProject *const project = ::GetActiveProject(); + TrackList *const tracks = project->GetTracks(); + + if (tracks->CanMoveUp(mpTrack)) + mMoveUpThreshold = + event.m_y - tracks->GetGroupHeight(tracks->GetPrev(mpTrack, true)); + else + mMoveUpThreshold = INT_MIN; + + if (tracks->CanMoveDown(mpTrack)) + mMoveDownThreshold = + event.m_y + tracks->GetGroupHeight(tracks->GetNext(mpTrack, true)); + else + mMoveDownThreshold = INT_MAX; +} diff --git a/src/tracks/ui/TrackSelectHandle.h b/src/tracks/ui/TrackSelectHandle.h new file mode 100644 index 000000000..5b5b26b53 --- /dev/null +++ b/src/tracks/ui/TrackSelectHandle.h @@ -0,0 +1,63 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +TrackSelectHandle.h + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#ifndef __AUDACITY_TRACK_SELECT_HANDLE__ +#define __AUDACITY_TRACK_SELECT_HANDLE__ + +#include "../../UIHandle.h" + +class wxMouseEvent; +struct HitTestResult; +class Track; + +class TrackSelectHandle final : public UIHandle +{ + TrackSelectHandle(); + TrackSelectHandle(const TrackSelectHandle&) = delete; + TrackSelectHandle &operator=(const TrackSelectHandle&) = delete; + static TrackSelectHandle& Instance(); + static HitTestPreview HitPreview(unsigned trackCount); + +public: + static HitTestResult HitAnywhere(unsigned trackCount); + + virtual ~TrackSelectHandle(); + + Result Click + (const TrackPanelMouseEvent &event, AudacityProject *pProject) override; + + Result Drag + (const TrackPanelMouseEvent &event, AudacityProject *pProject) override; + + HitTestPreview Preview + (const TrackPanelMouseEvent &event, const AudacityProject *pProject) + override; + + Result Release + (const TrackPanelMouseEvent &event, AudacityProject *pProject, + wxWindow *pParent) override; + + Result Cancel(AudacityProject *) override; + + bool StopsOnKeystroke() override { return true; } + +private: + Track *mpTrack {}; + + // JH: if the user is dragging a track, at what y + // coordinate should the dragging track move up or down? + int mMoveUpThreshold {}; + int mMoveDownThreshold {}; + int mRearrangeCount {}; + + void CalculateRearrangingThresholds(const wxMouseEvent & event); +}; + +#endif diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index e6fe01ef8..da5288e61 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -251,6 +251,7 @@ + @@ -522,6 +523,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 154cf63b8..243aba899 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -1025,6 +1025,9 @@ src\tracks\ui + + src\tracks\ui + @@ -2041,6 +2044,9 @@ src\tracks\ui + + src\tracks\ui +