From bbfa57479071908d7a079e5e48853085a60353ce Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 9 Aug 2015 23:41:08 -0400 Subject: [PATCH] Move track resizing code out of TrackPanel.cpp, though it still... ... cooperates more closely with TrackPanel than the other UIHandle subclasses do. --- mac/Audacity.xcodeproj/project.pbxproj | 6 + src/Makefile.am | 2 + src/TrackPanel.cpp | 362 +--------------- src/TrackPanel.h | 19 +- src/TrackPanelResizeHandle.cpp | 393 ++++++++++++++++++ src/TrackPanelResizeHandle.h | 68 +++ win/Projects/Audacity/Audacity.vcxproj | 2 + .../Audacity/Audacity.vcxproj.filters | 6 + 8 files changed, 499 insertions(+), 359 deletions(-) create mode 100644 src/TrackPanelResizeHandle.cpp create mode 100644 src/TrackPanelResizeHandle.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 7ca7446e3..9a6cd7cad 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1234,6 +1234,7 @@ 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 */; }; + 5E7396621DAFDB1E00BA0A4D /* TrackPanelResizeHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396601DAFDB1E00BA0A4D /* TrackPanelResizeHandle.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 */; }; @@ -3073,6 +3074,8 @@ 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 = ""; }; + 5E7396601DAFDB1E00BA0A4D /* TrackPanelResizeHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackPanelResizeHandle.cpp; sourceTree = ""; }; + 5E7396611DAFDB1E00BA0A4D /* TrackPanelResizeHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelResizeHandle.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 = ""; }; @@ -4022,6 +4025,7 @@ 1790B0EA09883BFD008A330A /* TrackArtist.cpp */, 1790B0EC09883BFD008A330A /* TrackPanel.cpp */, 1790B0EE09883BFD008A330A /* TrackPanelAx.cpp */, + 5E7396601DAFDB1E00BA0A4D /* TrackPanelResizeHandle.cpp */, 5E15123B1DB000C000702E29 /* UIHandle.cpp */, 1790B0F209883BFD008A330A /* UndoManager.cpp */, 5E07842F1DF1E4F400CA76EA /* UserException.cpp */, @@ -4127,6 +4131,7 @@ 5E74D2DA1CC4427B00D88B0B /* TrackPanelCellIterator.h */, 2803C8B619F35AA000278526 /* TrackPanelListener.h */, 5E15123A1DB000C000702E29 /* TrackPanelMouseEvent.h */, + 5E7396611DAFDB1E00BA0A4D /* TrackPanelResizeHandle.h */, 284416391B82D6BC0000574D /* TranslatableStringArray.h */, 5E15123C1DB000C000702E29 /* UIHandle.h */, 1790B0F309883BFD008A330A /* UndoManager.h */, @@ -7933,6 +7938,7 @@ 28F2CED4181867BB00573D61 /* numformatter.cpp in Sources */, 28F2CED5181867BB00573D61 /* valnum.cpp in Sources */, EDFCEB9C18894AE600C98E51 /* OpenSaveCommands.cpp in Sources */, + 5E7396621DAFDB1E00BA0A4D /* TrackPanelResizeHandle.cpp in Sources */, EDFCEBA618894B2A00C98E51 /* RealFFTf48x.cpp in Sources */, EDFCEBA718894B2A00C98E51 /* SseMathFuncs.cpp in Sources */, EDFCEBB518894B9E00C98E51 /* Equalization48x.cpp in Sources */, diff --git a/src/Makefile.am b/src/Makefile.am index 7337393df..a3764b167 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -249,6 +249,8 @@ audacity_SOURCES = \ TrackPanelCellIterator.h \ TrackPanelListener.h \ TrackPanelMouseEvent.h \ + TrackPanelResizeHandle.cpp \ + TrackPanelResizeHandle.h \ TranslatableStringArray.h \ UIHandle.h \ UIHandle.cpp \ diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 8208d13f8..b2777878e 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -156,7 +156,7 @@ is time to refresh some aspect of the screen. #include "TrackPanel.h" #include "TrackPanelCellIterator.h" #include "TrackPanelMouseEvent.h" - +#include "TrackPanelResizeHandle.h" //#define DEBUG_DRAW_TIMING 1 // #define SPECTRAL_EDITING_ESC_KEY @@ -382,7 +382,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, #endif mArrowCursor = std::make_unique(wxCURSOR_ARROW); - mResizeCursor = std::make_unique(wxCURSOR_SIZENS); mAdjustLeftSelectionCursor = std::make_unique(wxCURSOR_POINT_LEFT); mAdjustRightSelectionCursor = std::make_unique(wxCURSOR_POINT_RIGHT); @@ -861,9 +860,6 @@ void TrackPanel::HandleInterruptedDrag() case IsUncaptured: case IsSelecting: case IsSelectingLabelText: - case IsResizing: - case IsResizingBetweenLinkedTracks: - case IsResizingBelowLinkedTracks: sendEvent = false; default: @@ -1006,38 +1002,6 @@ bool TrackPanel::HandleEscapeKey(bool down) pMixerBoard->Refresh(); } break; - case IsResizing: - mCapturedTrack->SetHeight(mInitialActualHeight); - mCapturedTrack->SetMinimized(mInitialMinimized); - break; - case IsResizingBetweenLinkedTracks: - { - Track *const next = mTracks->GetNext(mCapturedTrack); - mCapturedTrack->SetHeight(mInitialUpperActualHeight); - mCapturedTrack->SetMinimized(mInitialMinimized); -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - if( !MONO_WAVE_PAN(mCapturedTrack) ) -#endif - { - next->SetHeight(mInitialActualHeight); - next->SetMinimized(mInitialMinimized); - } - } - break; - case IsResizingBelowLinkedTracks: - { - Track *const prev = mTracks->GetPrev(mCapturedTrack); - mCapturedTrack->SetHeight(mInitialActualHeight); - mCapturedTrack->SetMinimized(mInitialMinimized); -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - if( !MONO_WAVE_PAN(mCapturedTrack) ) -#endif - { - prev->SetHeight(mInitialUpperActualHeight); - prev->SetMinimized(mInitialMinimized); - } - } - break; default: { // Not escaping from a mouse drag @@ -1139,23 +1103,6 @@ bool TrackPanel::SetCursorByActivity( ) return false; } -/// When in the resize area we can adjust size or relative size. -void TrackPanel::SetCursorAndTipWhenInVResizeArea( bool bLinked, wxString &tip ) -{ - // Check to see whether it is the first channel of a stereo track - if (bLinked) { - // If we are in the label we got here 'by mistake' and we're - // not actually in the resize area at all. (The resize area - // is shorter when it is between stereo tracks). - - tip = _("Click and drag to adjust relative size of stereo tracks."); - SetCursor(*mResizeCursor); - } else { - tip = _("Click and drag to resize the track."); - SetCursor(*mResizeCursor); - } -} - /// When in a label track, find out if we've hit anything that /// would cause a cursor change. void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, @@ -1440,15 +1387,22 @@ void TrackPanel::HandleCursor(wxMouseEvent & event) wxString tip; + // tip may still be NULL at this point, in which case we go on looking. + // Are we within the vertical resize area? // (Add margin back to bottom of the rectangle) if (within(event.m_y, (rect.GetBottom() + (kBottomMargin + kTopMargin) / 2), TRACK_RESIZE_REGION)) - SetCursorAndTipWhenInVResizeArea( - track->GetLinked() && foundCell.type != CellType::Label, tip); - - // tip may still be NULL at this point, in which case we go on looking. + { + HitTestPreview preview + (TrackPanelResizeHandle::HitPreview( + (foundCell.type != CellType::Label) && track->GetLinked())); + tip = preview.message; + wxCursor *const pCursor = preview.cursor; + if (pCursor) + SetCursor(*pCursor); + } if (pCell && pCursor == NULL && tip == wxString()) { const auto size = GetSize(); @@ -3028,275 +2982,6 @@ bool TrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect, return subRect.y + subRect.height - allowance >= rect.y + limit; } -/// 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 -/// update the track size. -void TrackPanel::HandleResizeClick( wxMouseEvent & event ) -{ - // Get here only if the click was near the bottom of the cell rectangle. - // DM: Figure out what track is about to be resized - const auto foundCell = FindCell(event.m_x, event.m_y); - auto track = foundCell.pTrack; - - if (foundCell.type == CellType::Label && track && track->GetLinked()) - // Click was at the bottom of a stereo track. - track = track->GetLink(); - - if (!track) { - return; - } - - mMouseClickY = event.m_y; - -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - // To do: escape key - if(MONO_WAVE_PAN(track)){ - //STM: Determine whether we should rescale one or two tracks - if (track->GetVirtualStereo()) { - // mCapturedTrack is the lower track - mInitialTrackHeight = track->GetHeight(true); - mInitialActualHeight = mInitialUpperActualHeight = track->GetActualHeight(); - mInitialMinimized = track->GetMinimized(); - mInitialUpperTrackHeight = track->GetHeight(); - SetCapturedTrack(track, IsResizingBelowLinkedTracks); - } - else { - // mCapturedTrack is the upper track - mInitialTrackHeight = track->GetHeight(true); - mInitialActualHeight = mInitialUpperActualHeight = track->GetActualHeight(); - mInitialMinimized = track->GetMinimized(); - mInitialUpperTrackHeight = track->GetHeight(); - SetCapturedTrack(track, IsResizingBetweenLinkedTracks); - } - } - else -#endif - { - Track *prev = mTracks->GetPrev(track); - Track *next = mTracks->GetNext(track); - - //STM: Determine whether we should rescale one or two tracks - if (prev && prev->GetLink() == track) { - // mCapturedTrack is the lower track - mInitialTrackHeight = track->GetHeight(); - mInitialActualHeight = track->GetActualHeight(); - mInitialMinimized = track->GetMinimized(); - mInitialUpperTrackHeight = prev->GetHeight(); - mInitialUpperActualHeight = prev->GetActualHeight(); - SetCapturedTrack(track, IsResizingBelowLinkedTracks); - } - else if (next && track->GetLink() == next) { - // mCapturedTrack is the upper track - mInitialTrackHeight = next->GetHeight(); - mInitialActualHeight = next->GetActualHeight(); - mInitialMinimized = next->GetMinimized(); - mInitialUpperTrackHeight = track->GetHeight(); - mInitialUpperActualHeight = track->GetActualHeight(); - SetCapturedTrack(track, IsResizingBetweenLinkedTracks); - } - else { - // DM: Save the initial mouse location and the initial height - mInitialTrackHeight = track->GetHeight(); - mInitialActualHeight = track->GetActualHeight(); - mInitialMinimized = track->GetMinimized(); - SetCapturedTrack(track, IsResizing); - } - } -} - -/// This happens when the button is released from a drag. -/// Since we actually took care of resizing the track when -/// we got drag events, all we have to do here is clean up. -/// We also modify the undo state (the action doesn't become -/// undo-able, but it gets merged with the previous undo-able -/// event). -void TrackPanel::HandleResizeButtonUp(wxMouseEvent & WXUNUSED(event)) -{ - SetCapturedTrack( NULL ); - MakeParentRedrawScrollbars(); - MakeParentModifyState(false); -} - -/// Resize dragging means that the mouse button IS down and has moved -/// from its initial location. By the time we get here, we -/// have already received a ButtonDown() event and saved the -/// track being resized in mCapturedTrack. -void TrackPanel::HandleResizeDrag(wxMouseEvent & event) -{ - int delta = (event.m_y - mMouseClickY); - - // On first drag, jump out of minimized mode. Initial height - // will be height of minimized track. - // - // This used to be in HandleResizeClick(), but simply clicking - // on a resize border would switch the minimized state. - if (mCapturedTrack->GetMinimized()) { - Track *link = mCapturedTrack->GetLink(); - - mCapturedTrack->SetHeight(mCapturedTrack->GetHeight()); - mCapturedTrack->SetMinimized(false); - - if (link) { - link->SetHeight(link->GetHeight()); - link->SetMinimized(false); - // Initial values must be reset since they weren't based on the - // minimized heights. - mInitialUpperTrackHeight = link->GetHeight(); - mInitialTrackHeight = mCapturedTrack->GetHeight(); - } -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - else if(MONO_WAVE_PAN(mCapturedTrack)){ - mCapturedTrack->SetMinimized(false); - mInitialUpperTrackHeight = mCapturedTrack->GetHeight(); - mInitialTrackHeight = mCapturedTrack->GetHeight(true); - } -#endif - } - - // Common pieces of code for MONO_WAVE_PAN and otherwise. - auto doResizeBelow = [&] (Track *prev, bool vStereo) { - double proportion = static_cast < double >(mInitialTrackHeight) - / (mInitialTrackHeight + mInitialUpperTrackHeight); - - int newTrackHeight = static_cast < int > - (mInitialTrackHeight + delta * proportion); - - int newUpperTrackHeight = static_cast < int > - (mInitialUpperTrackHeight + delta * (1.0 - proportion)); - - //make sure neither track is smaller than its minimum height - if (newTrackHeight < mCapturedTrack->GetMinimizedHeight()) - newTrackHeight = mCapturedTrack->GetMinimizedHeight(); - if (newUpperTrackHeight < prev->GetMinimizedHeight()) - newUpperTrackHeight = prev->GetMinimizedHeight(); - - mCapturedTrack->SetHeight(newTrackHeight -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - , vStereo -#endif - ); - prev->SetHeight(newUpperTrackHeight); - }; - - auto doResizeBetween = [&] (Track *next, bool vStereo) { - int newUpperTrackHeight = mInitialUpperTrackHeight + delta; - int newTrackHeight = mInitialTrackHeight - delta; - - // make sure neither track is smaller than its minimum height - if (newTrackHeight < next->GetMinimizedHeight()) { - newTrackHeight = next->GetMinimizedHeight(); - newUpperTrackHeight = - mInitialUpperTrackHeight + mInitialTrackHeight - next->GetMinimizedHeight(); - } - if (newUpperTrackHeight < mCapturedTrack->GetMinimizedHeight()) { - newUpperTrackHeight = mCapturedTrack->GetMinimizedHeight(); - newTrackHeight = - mInitialUpperTrackHeight + mInitialTrackHeight - mCapturedTrack->GetMinimizedHeight(); - } - -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - if (vStereo) { - float temp = 1.0f; - if(newUpperTrackHeight != 0.0f) - temp = (float)newUpperTrackHeight/(float)(newUpperTrackHeight + newTrackHeight); - mCapturedTrack->SetVirtualTrackPercentage(temp); - } -#endif - - mCapturedTrack->SetHeight(newUpperTrackHeight); - next->SetHeight(newTrackHeight -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - , vStereo -#endif - ); - }; - - auto doResize = [&] { - int newTrackHeight = mInitialTrackHeight + delta; - if (newTrackHeight < mCapturedTrack->GetMinimizedHeight()) - newTrackHeight = mCapturedTrack->GetMinimizedHeight(); - mCapturedTrack->SetHeight(newTrackHeight); - }; - - //STM: We may be dragging one or two (stereo) tracks. - // If two, resize proportionally if we are dragging the lower track, and - // adjust compensatively if we are dragging the upper track. -#ifdef EXPERIMENTAL_OUTPUT_DISPLAY - if(MONO_WAVE_PAN(mCapturedTrack)) { - switch( mMouseCapture ) - { - case IsResizingBelowLinkedTracks: - { - doResizeBelow( mCapturedTrack, true ); - break; - } - case IsResizingBetweenLinkedTracks: - { - doResizeBetween( mCapturedTrack, true ); - break; - } - case IsResizing: - { - // Should imply !MONO_WAVE_PAN(mCapturedTrack), - // so impossible, but anyway: - doResize(); - break; - } - default: - // don't refresh in this case. - return; - } - } - else -#endif - { - switch( mMouseCapture ) - { - case IsResizingBelowLinkedTracks: - { - Track *prev = mTracks->GetPrev(mCapturedTrack); - doResizeBelow(prev, false); - break; - } - case IsResizingBetweenLinkedTracks: - { - Track *next = mTracks->GetNext(mCapturedTrack); - doResizeBetween(next, false); - break; - } - case IsResizing: - { - doResize(); - break; - } - default: - // don't refresh in this case. - return; - } - } - Refresh(false); -} - -/// HandleResize gets called when: -/// - A mouse-down event occurs in the "resize region" of a track, -/// i.e. to change its vertical height. -/// - A mouse event occurs and mIsResizing==true (i.e. while -/// the resize is going on) -void TrackPanel::HandleResize(wxMouseEvent & event) -{ - if (event.LeftDown()) { - HandleResizeClick( event ); - } - else if (event.LeftUp()) - { - HandleResizeButtonUp( event ); - } - else if (event.Dragging()) { - HandleResizeDrag( event ); - } -} - /// Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling) void TrackPanel::HandleWheelRotation(wxMouseEvent & event) { @@ -3657,12 +3342,6 @@ try } } else switch( mMouseCapture ) { - case IsResizing: - case IsResizingBetweenLinkedTracks: - case IsResizingBelowLinkedTracks: - HandleResize(event); - HandleCursor(event); - break; case IsAdjustingLabel: // Reach this case only when the captured track was label HandleGlyphDragRelease(static_cast(mCapturedTrack), event); @@ -3885,16 +3564,17 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event) auto &pCell = foundCell.pCell; auto &rect = foundCell.rect; - //call HandleResize if I'm over the border area - // (Add margin back to bottom of the rectangle) - if (event.LeftDown() && - pTrack && + // see if I'm over the border area. + // TrackPanelResizeHandle is the UIHandle subclass that TrackPanel knows + // and uses directly, because allocating area to cells is TrackPanel's business, + // and we implement a "hit test" directly here. + if (mUIHandle == NULL && + event.LeftDown()) { + if (pCell && (within(event.m_y, (rect.GetBottom() + (kBottomMargin + kTopMargin) / 2), - TRACK_RESIZE_REGION))) { - HandleResize(event); - HandleCursor(event); - return; + TRACK_RESIZE_REGION))) + mUIHandle = &TrackPanelResizeHandle::Instance(); } //Determine if user clicked on the track's left-hand label or ruler diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 77f7a8211..c4a1805b1 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -429,7 +429,6 @@ protected: protected: // AS: Cursor handling virtual bool SetCursorByActivity( ); - virtual void SetCursorAndTipWhenInVResizeArea( bool blinked, wxString &tip ); virtual void SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, const wxMouseEvent & event, wxString &tip ); virtual void SetCursorAndTipWhenSelectTool ( Track * t, const wxMouseEvent & event, const wxRect &rect, bool bMultiToolMode, wxString &tip, const wxCursor ** ppCursor ); @@ -444,12 +443,6 @@ protected: // MM: Handle mouse wheel rotation virtual void HandleWheelRotation(wxMouseEvent & event); - // Handle resizing. - virtual void HandleResizeClick(wxMouseEvent & event); - virtual void HandleResizeDrag(wxMouseEvent & event); - virtual void HandleResizeButtonUp(wxMouseEvent & event); - virtual void HandleResize(wxMouseEvent & event); - public: virtual void MakeParentRedrawScrollbars(); @@ -614,8 +607,6 @@ protected: wxMouseEvent mLastMouseEvent; - int mMouseClickY; - int mMouseMostRecentX; int mMouseMostRecentY; @@ -675,11 +666,6 @@ protected: bool onlyWithinSnapDistance, double *pPinValue = NULL) const; - bool mInitialMinimized; - int mInitialTrackHeight; - int mInitialActualHeight; - int mInitialUpperTrackHeight; - int mInitialUpperActualHeight; bool mAutoScrolling; public: @@ -692,9 +678,6 @@ public: IsSelecting, IsAdjustingLabel, IsSelectingLabelText, - IsResizing, - IsResizingBetweenLinkedTracks, - IsResizingBelowLinkedTracks, IsMuting, IsSoloing, IsMinimizing, @@ -708,7 +691,7 @@ protected: std::unique_ptr mArrowCursor, mSelectCursor, - mResizeCursor, mEnvelopeCursor, // doubles as the center frequency cursor + mEnvelopeCursor, // doubles as the center frequency cursor // for spectral selection mDisabledCursor, mAdjustLeftSelectionCursor, mAdjustRightSelectionCursor; #ifdef EXPERIMENTAL_SPECTRAL_EDITING diff --git a/src/TrackPanelResizeHandle.cpp b/src/TrackPanelResizeHandle.cpp new file mode 100644 index 000000000..90aab974e --- /dev/null +++ b/src/TrackPanelResizeHandle.cpp @@ -0,0 +1,393 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +TrackPanelResizeHandle.cpp + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#include "Audacity.h" +#include "TrackPanelResizeHandle.h" +#include "Experimental.h" + +#include "MemoryX.h" + +#include +#include + +#include "HitTestResult.h" +#include "Project.h" +#include "RefreshCode.h" +#include "Track.h" +#include "TrackPanelMouseEvent.h" +#include "tracks/ui/TrackControls.h" + +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY +#include "WaveTrack.h" +#endif + +TrackPanelResizeHandle::TrackPanelResizeHandle() +{ +} + +TrackPanelResizeHandle &TrackPanelResizeHandle::Instance() +{ + static TrackPanelResizeHandle instance; + return instance; +} + +HitTestPreview TrackPanelResizeHandle::HitPreview(bool bLinked) +{ + static wxCursor resizeCursor{ wxCURSOR_SIZENS }; + + /// When in the resize area we can adjust size or relative size. + // Check to see whether it is the first channel of a stereo track + if (bLinked) { + // If we are in the label we got here 'by mistake' and we're + // not actually in the resize area at all. (The resize area + // is shorter when it is between stereo tracks). + + return { + _("Click and drag to adjust relative size of stereo tracks."), + &resizeCursor + }; + } + else { + return { + _("Click and drag to resize the track."), + &resizeCursor + }; + } +} + +TrackPanelResizeHandle::~TrackPanelResizeHandle() +{ +} + +UIHandle::Result TrackPanelResizeHandle::Click +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + const wxMouseEvent &event = evt.event; + CommonTrackPanelCell *const pCell = + static_cast(evt.pCell); + Track *track = track = pCell->FindTrack(); + if (track && dynamic_cast< TrackControls * >( pCell )) { + // Clicked under a label; + // if stereo, replace left channel with the right: + if (track && track->GetLinked()) + track = track->GetLink(); + } + if (!track) + return RefreshCode::Cancelled; + + mpTrack = track; + + /// 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 + /// update the track size. + + mMouseClickY = event.m_y; + + TrackList *const tracks = pProject->GetTracks(); + +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + if (MONO_WAVE_PAN(track)){ + //STM: Determine whether we should rescale one or two tracks + if (track->GetVirtualStereo()) { + // mpTrack is the lower track + mInitialTrackHeight = track->GetHeight(true); + mInitialActualHeight = mInitialUpperActualHeight = track->GetActualHeight(); + mInitialMinimized = track->GetMinimized(); + mInitialUpperTrackHeight = track->GetHeight(); + mMode = IsResizingBelowLinkedTracks; + } + else { + // mpTrack is the upper track + mInitialTrackHeight = track->GetHeight(true); + mInitialActualHeight = mInitialUpperActualHeight = track->GetActualHeight(); + mInitialMinimized = track->GetMinimized(); + mInitialUpperTrackHeight = track->GetHeight(); + mMode = IsResizingBetweenLinkedTracks; + } + } + else +#endif + { + Track *prev = tracks->GetPrev(track); + Track *next = tracks->GetNext(track); + + //STM: Determine whether we should rescale one or two tracks + if (prev && prev->GetLink() == track) { + // mpTrack is the lower track + mInitialTrackHeight = track->GetHeight(); + mInitialActualHeight = track->GetActualHeight(); + mInitialMinimized = track->GetMinimized(); + mInitialUpperTrackHeight = prev->GetHeight(); + mInitialUpperActualHeight = prev->GetActualHeight(); + mMode = IsResizingBelowLinkedTracks; + } + else if (next && track->GetLink() == next) { + // mpTrack is the upper track + mInitialTrackHeight = next->GetHeight(); + mInitialActualHeight = next->GetActualHeight(); + mInitialMinimized = next->GetMinimized(); + mInitialUpperTrackHeight = track->GetHeight(); + mInitialUpperActualHeight = track->GetActualHeight(); + mMode = IsResizingBetweenLinkedTracks; + } + else { + // DM: Save the initial mouse location and the initial height + mInitialTrackHeight = track->GetHeight(); + mInitialActualHeight = track->GetActualHeight(); + mInitialMinimized = track->GetMinimized(); + mMode = IsResizing; + } + } + + return RefreshCode::RefreshNone; +} + +UIHandle::Result TrackPanelResizeHandle::Drag +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + if ( !mpTrack ) + return RefreshCode::Cancelled; + + const wxMouseEvent &event = evt.event; + TrackList *const tracks = pProject->GetTracks(); + + int delta = (event.m_y - mMouseClickY); + + // On first drag, jump out of minimized mode. Initial height + // will be height of minimized track. + // + // This used to be in HandleResizeClick(), but simply clicking + // on a resize border would switch the minimized state. + if (mpTrack->GetMinimized()) { + Track *link = mpTrack->GetLink(); + + mpTrack->SetHeight(mpTrack->GetHeight()); + mpTrack->SetMinimized(false); + + if (link) { + link->SetHeight(link->GetHeight()); + link->SetMinimized(false); + // Initial values must be reset since they weren't based on the + // minimized heights. + mInitialUpperTrackHeight = link->GetHeight(); + mInitialTrackHeight = mpTrack->GetHeight(); + } +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + else if (MONO_WAVE_PAN(mpTrack)){ + mpTrack->SetMinimized(false); + mInitialUpperTrackHeight = mpTrack->GetHeight(); + mInitialTrackHeight = mpTrack->GetHeight(true); + } +#endif + } + + // Common pieces of code for MONO_WAVE_PAN and otherwise. + auto doResizeBelow = [&] (Track *prev, bool vStereo) { + double proportion = static_cast < double >(mInitialTrackHeight) + / (mInitialTrackHeight + mInitialUpperTrackHeight); + + int newTrackHeight = static_cast < int > + (mInitialTrackHeight + delta * proportion); + + int newUpperTrackHeight = static_cast < int > + (mInitialUpperTrackHeight + delta * (1.0 - proportion)); + + //make sure neither track is smaller than its minimum height + if (newTrackHeight < mpTrack->GetMinimizedHeight()) + newTrackHeight = mpTrack->GetMinimizedHeight(); + if (newUpperTrackHeight < prev->GetMinimizedHeight()) + newUpperTrackHeight = prev->GetMinimizedHeight(); + + mpTrack->SetHeight(newTrackHeight +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + , vStereo +#endif + ); + prev->SetHeight(newUpperTrackHeight); + }; + + auto doResizeBetween = [&] (Track *next, bool vStereo) { + int newUpperTrackHeight = mInitialUpperTrackHeight + delta; + int newTrackHeight = mInitialTrackHeight - delta; + + // make sure neither track is smaller than its minimum height + if (newTrackHeight < next->GetMinimizedHeight()) { + newTrackHeight = next->GetMinimizedHeight(); + newUpperTrackHeight = + mInitialUpperTrackHeight + mInitialTrackHeight - next->GetMinimizedHeight(); + } + if (newUpperTrackHeight < mpTrack->GetMinimizedHeight()) { + newUpperTrackHeight = mpTrack->GetMinimizedHeight(); + newTrackHeight = + mInitialUpperTrackHeight + mInitialTrackHeight - mpTrack->GetMinimizedHeight(); + } + +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + if (vStereo) { + float temp = 1.0f; + if(newUpperTrackHeight != 0.0f) + temp = (float)newUpperTrackHeight/(float)(newUpperTrackHeight + newTrackHeight); + mpTrack->SetVirtualTrackPercentage(temp); + } +#endif + + mpTrack->SetHeight(newUpperTrackHeight); + next->SetHeight(newTrackHeight +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + , vStereo +#endif + ); + }; + + auto doResize = [&] { + int newTrackHeight = mInitialTrackHeight + delta; + if (newTrackHeight < mpTrack->GetMinimizedHeight()) + newTrackHeight = mpTrack->GetMinimizedHeight(); + mpTrack->SetHeight(newTrackHeight); + }; + + //STM: We may be dragging one or two (stereo) tracks. + // If two, resize proportionally if we are dragging the lower track, and + // adjust compensatively if we are dragging the upper track. + +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + if(MONO_WAVE_PAN(mpTrack)) { + switch( mMode ) + { + case IsResizingBelowLinkedTracks: + { + doResizeBelow( mpTrack, true ); + break; + } + case IsResizingBetweenLinkedTracks: + { + doResizeBetween( mpTrack, true ); + break; + } + case IsResizing: + { + // Should imply !MONO_WAVE_PAN(mCapturedTrack), + // so impossible, but anyway: + doResize(); + break; + } + default: + // don't refresh in this case. + return RefreshCode::RefreshNone; + } + } + else +#endif + { + switch( mMode ) + { + case IsResizingBelowLinkedTracks: + { + Track *prev = tracks->GetPrev(mpTrack); + doResizeBelow(prev, false); + break; + } + case IsResizingBetweenLinkedTracks: + { + Track *next = tracks->GetNext(mpTrack); + doResizeBetween(next, false); + break; + } + case IsResizing: + { + doResize(); + break; + } + default: + // don't refresh in this case. + return RefreshCode::RefreshNone; + } + } + + return RefreshCode::RefreshAll; +} + +HitTestPreview TrackPanelResizeHandle::Preview +(const TrackPanelMouseEvent &, const AudacityProject *) +{ + return HitPreview(mMode == IsResizingBetweenLinkedTracks); +} + +UIHandle::Result TrackPanelResizeHandle::Release +(const TrackPanelMouseEvent &, AudacityProject *pProject, + wxWindow *) +{ + /// This happens when the button is released from a drag. + /// Since we actually took care of resizing the track when + /// we got drag events, all we have to do here is clean up. + /// We also modify the undo state (the action doesn't become + /// undo-able, but it gets merged with the previous undo-able + /// event). + pProject->ModifyState(false); + return RefreshCode::FixScrollbars; +} + +UIHandle::Result TrackPanelResizeHandle::Cancel(AudacityProject *pProject) +{ + if ( !mpTrack ) + return RefreshCode::Cancelled; + + TrackList *const tracks = pProject->GetTracks(); + + switch (mMode) { + case IsResizing: + { + mpTrack->SetHeight(mInitialActualHeight); + mpTrack->SetMinimized(mInitialMinimized); + } + break; + case IsResizingBetweenLinkedTracks: + { + Track *const next = tracks->GetNext(mpTrack); + mpTrack->SetHeight(mInitialUpperActualHeight); + mpTrack->SetMinimized(mInitialMinimized); +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + if( !MONO_WAVE_PAN(mpTrack) ) +#endif + { + next->SetHeight(mInitialActualHeight); + next->SetMinimized(mInitialMinimized); + } + } + break; + case IsResizingBelowLinkedTracks: + { + Track *const prev = tracks->GetPrev(mpTrack); + mpTrack->SetHeight(mInitialActualHeight); + mpTrack->SetMinimized(mInitialMinimized); +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + if( !MONO_WAVE_PAN(mpTrack) ) +#endif + { + prev->SetHeight(mInitialUpperActualHeight); + prev->SetMinimized(mInitialMinimized); + } + } + break; + } + + return RefreshCode::RefreshAll; +} + +void TrackPanelResizeHandle::OnProjectChange(AudacityProject *pProject) +{ + if (! ::GetActiveProject()->GetTracks()->Contains(mpTrack)) { + mpTrack = nullptr; + } + + UIHandle::OnProjectChange(pProject); +} + diff --git a/src/TrackPanelResizeHandle.h b/src/TrackPanelResizeHandle.h new file mode 100644 index 000000000..aa5cb5906 --- /dev/null +++ b/src/TrackPanelResizeHandle.h @@ -0,0 +1,68 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +TrackPanelResizeHandle.h + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#ifndef __AUDACITY_TRACK_PANEL_RESIZE_HANDLE__ +#define __AUDACITY_TRACK_PANEL_RESIZE_HANDLE__ + +#include "UIHandle.h" + +struct HitTestResult; +class Track; + +class TrackPanelResizeHandle final : public UIHandle +{ + TrackPanelResizeHandle(); + TrackPanelResizeHandle(const TrackPanelResizeHandle&) = delete; + TrackPanelResizeHandle &operator=(const TrackPanelResizeHandle&) = delete; + +public: + static TrackPanelResizeHandle& Instance(); + static HitTestPreview HitPreview(bool bLinked); + + virtual ~TrackPanelResizeHandle(); + + 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 *pProject) override; + + void OnProjectChange(AudacityProject *pProject) override; + +private: + enum Mode { + IsResizing, + IsResizingBetweenLinkedTracks, + IsResizingBelowLinkedTracks, + }; + Mode mMode{ IsResizing }; + + Track *mpTrack{}; + + bool mInitialMinimized{}; + int mInitialTrackHeight{}; + int mInitialActualHeight{}; + int mInitialUpperTrackHeight{}; + int mInitialUpperActualHeight{}; + + int mMouseClickY{}; +}; + +#endif diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index da5288e61..b465e2e73 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -224,6 +224,7 @@ + @@ -507,6 +508,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 243aba899..c69fa769f 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -1028,6 +1028,9 @@ src\tracks\ui + + src + @@ -2047,6 +2050,9 @@ src\tracks\ui + + src +