diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 0cd394037..c6be212ce 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1231,6 +1231,7 @@ 5E73964D1DAFD95B00BA0A4D /* ButtonHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73964B1DAFD95B00BA0A4D /* ButtonHandle.cpp */; }; 5E7396501DAFD98400BA0A4D /* SliderHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73964E1DAFD98400BA0A4D /* SliderHandle.cpp */; }; 5E7396561DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396541DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp */; }; + 5E7396591DAFDA3600BA0A4D /* TrackButtonHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.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 */; }; @@ -3064,6 +3065,8 @@ 5E73964F1DAFD98400BA0A4D /* SliderHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SliderHandle.h; sourceTree = ""; }; 5E7396541DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaveTrackSliderHandles.cpp; sourceTree = ""; }; 5E7396551DAFDA0000BA0A4D /* WaveTrackSliderHandles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaveTrackSliderHandles.h; sourceTree = ""; }; + 5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackButtonHandles.cpp; sourceTree = ""; }; + 5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackButtonHandles.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 = ""; }; @@ -5769,6 +5772,7 @@ 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */, 5E73964E1DAFD98400BA0A4D /* SliderHandle.cpp */, 5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */, + 5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */, 5E1512681DB0010C00702E29 /* TrackControls.cpp */, 5E15126A1DB0010C00702E29 /* TrackUI.cpp */, 5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */, @@ -5781,6 +5785,7 @@ 5E74D2E21CC4429700D88B0B /* Scrubbing.h */, 5E73964F1DAFD98400BA0A4D /* SliderHandle.h */, 5E7396431DAFD8C600BA0A4D /* TimeShiftHandle.h */, + 5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */, 5E1512691DB0010C00702E29 /* TrackControls.h */, 5E15126C1DB0010C00702E29 /* TrackVRulerControls.h */, 5E73963D1DAFD86000BA0A4D /* ZoomHandle.h */, @@ -7754,6 +7759,7 @@ 2801A6460BF9268700648258 /* ImportQT.cpp in Sources */, 2891B2870C531D2C0044FBE3 /* FindClipping.cpp in Sources */, 283AA0EB0C56ED08002CBD34 /* ErrorDialog.cpp in Sources */, + 5E7396591DAFDA3600BA0A4D /* TrackButtonHandles.cpp in Sources */, 28501EA10CEECEF80029ABAA /* HelpText.cpp in Sources */, 5EF958851DEB121800191280 /* InconsistencyException.cpp in Sources */, 28501EA20CEECEF80029ABAA /* SplashDialog.cpp in Sources */, diff --git a/src/Makefile.am b/src/Makefile.am index da13df0a7..2fa2e72f9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -595,6 +595,8 @@ audacity_SOURCES = \ tracks/ui/SliderHandle.h \ tracks/ui/TimeShiftHandle.cpp \ tracks/ui/TimeShiftHandle.h \ + tracks/ui/TrackButtonHandles.cpp \ + tracks/ui/TrackButtonHandles.h \ tracks/ui/TrackControls.cpp \ tracks/ui/TrackControls.h \ tracks/ui/TrackUI.cpp \ diff --git a/src/Project.h b/src/Project.h index 54744e940..1fb0276a2 100644 --- a/src/Project.h +++ b/src/Project.h @@ -557,8 +557,11 @@ public: void OnCapture(wxCommandEvent & evt); void InitialState(); + + public: void ModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after // a crash, as it can take many seconds for large (eg. 10 track-hours) projects +private: void PopState(const UndoState &state); void UpdateLyrics(); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 3d766e4a1..4e5b3497e 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1133,7 +1133,6 @@ void TrackPanel::HandleInterruptedDrag() case IsResizing: case IsResizingBetweenLinkedTracks: case IsResizingBelowLinkedTracks: - case IsMinimizing: case IsPopping: sendEvent = false; @@ -1144,7 +1143,6 @@ void TrackPanel::HandleInterruptedDrag() /* So this includes the cases: - IsClosing, IsAdjustingLabel, IsRearranging, IsStretching @@ -3459,38 +3457,13 @@ void TrackPanel::HandleWaveTrackVZoom } } -// This is for when a given track gets the x. -void TrackPanel::HandleClosing(wxMouseEvent & event) -{ - Track *t = mCapturedTrack; - wxRect rect = mCapturedRect; - - wxRect closeRect; - mTrackInfo.GetCloseBoxRect(rect, closeRect); - - wxClientDC dc(this); - - if (event.Dragging()) - mTrackInfo.DrawCloseBox(&dc, rect, t, closeRect.Contains(event.m_x, event.m_y)); - else if (event.LeftUp()) { - mTrackInfo.DrawCloseBox(&dc, rect, t, false); - if (closeRect.Contains(event.m_x, event.m_y)) { - AudacityProject *p = GetProject(); - p->StopIfPaused(); - if (!IsUnsafe()) - GetProject()->RemoveTrack(t); - } - SetCapturedTrack( NULL ); - } - - this->UpdateViewIfNoTracks(); - this->Refresh(false); -} - void TrackPanel::UpdateViewIfNoTracks() { if (mTracks->IsEmpty()) { + // Be sure not to keep a dangling pointer + SetCapturedTrack(NULL); + // BG: There are no more tracks on screen //BG: Set zoom to normal mViewInfo->SetZoom(ZoomInfo::GetDefaultZoom()); @@ -3504,6 +3477,7 @@ void TrackPanel::UpdateViewIfNoTracks() mViewInfo->h = 0; mListener->TP_RedrawScrollbars(); + mListener->TP_HandleResize(); mListener->TP_DisplayStatusMessage(wxT("")); //STM: Clear message if all tracks are removed } } @@ -3538,41 +3512,6 @@ void TrackPanel::HandlePopping(wxMouseEvent & event) } } -void TrackPanel::HandleMinimizing(wxMouseEvent & event) -{ - Track *t = mCapturedTrack; - wxRect rect = mCapturedRect; - - if (t == NULL) { - SetCapturedTrack(NULL); - return; - } - - wxRect buttonRect; - mTrackInfo.GetMinimizeRect(rect, buttonRect); - - wxClientDC dc(this); - - if (event.Dragging()) { - mTrackInfo.DrawMinimize(&dc, rect, t, buttonRect.Contains(event.m_x, event.m_y)); - } - else if (event.LeftUp()) { - if (buttonRect.Contains(event.m_x, event.m_y)) { - t->SetMinimized(!t->GetMinimized()); - if (t->GetLink()) - t->GetLink()->SetMinimized(t->GetMinimized()); - MakeParentRedrawScrollbars(); - MakeParentModifyState(true); - } - - SetCapturedTrack(NULL); - - mTrackInfo.DrawMinimize(&dc, rect, t, false); - Refresh(false); - GetActiveProject()->RedrawProject(); - } -} - // The tracks positions within the list have changed, so update the vertical // ruler size for the track that triggered the event. void TrackPanel::OnTrackListResized(wxCommandEvent & e) @@ -3829,23 +3768,14 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event) auto &t = foundCell.pTrack; auto &rect = foundCell.rect; - // LL: Check close box - if (isleft && CloseFunc(t, rect, event.m_x, event.m_y)) - return; - // LL: Check title bar for popup if (isleft && PopupFunc(t, rect, event.m_x, event.m_y)) return; { - // MM: Check minimize buttons on WaveTracks. Must be before - // solo/mute buttons, sliders etc. - if (isleft && MinimizeFunc(t, rect, event.m_x, event.m_y)) - return; - #ifdef USE_MIDI // DM: If it's a NoteTrack, it has special controls - else if (t->GetKind() == Track::Note) + if (t->GetKind() == Track::Note) { #ifdef EXPERIMENTAL_MIDI_OUT wxRect midiRect; @@ -3959,38 +3889,6 @@ void TrackPanel::CalculateRearrangingThresholds(wxMouseEvent & event) mMoveDownThreshold = INT_MAX; } -bool TrackPanel::MinimizeFunc(Track * t, wxRect rect, int x, int y) -{ - wxRect buttonRect; - mTrackInfo.GetMinimizeRect(rect, buttonRect); - if (!buttonRect.Contains(x, y)) - return false; - - SetCapturedTrack(t, IsMinimizing); - mCapturedRect = rect; - - wxClientDC dc(this); - mTrackInfo.DrawMinimize(&dc, rect, t, true); - - return true; -} - -bool TrackPanel::CloseFunc(Track * t, wxRect rect, int x, int y) -{ - wxRect closeRect; - mTrackInfo.GetCloseBoxRect(rect, closeRect); - - if (!closeRect.Contains(x, y)) - return false; - - wxClientDC dc(this); - SetCapturedTrack( t, IsClosing ); - mCapturedRect = rect; - - mTrackInfo.DrawCloseBox(&dc, rect, t, true); - return true; -} - bool TrackPanel::PopupFunc(Track * t, wxRect rect, int x, int y) { wxRect titleRect; @@ -4866,9 +4764,6 @@ try case IsVZooming: HandleVZoom(event); break; - case IsClosing: - HandleClosing(event); - break; case IsPopping: HandlePopping(event); break; @@ -4881,9 +4776,6 @@ try case IsRearranging: HandleRearrange(event); break; - case IsMinimizing: - HandleMinimizing(event); - break; case IsAdjustingLabel: // Reach this case only when the captured track was label HandleGlyphDragRelease(static_cast(mCapturedTrack), event); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 440de1b02..833cebb17 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -491,18 +491,13 @@ protected: virtual void HandleRearrange(wxMouseEvent & event); virtual void CalculateRearrangingThresholds(wxMouseEvent & event); - virtual void HandleClosing(wxMouseEvent & event); virtual void HandlePopping(wxMouseEvent & event); - virtual void HandleMinimizing(wxMouseEvent & event); - // These *Func methods are used in TrackPanel::HandleLabelClick to set up // for actual handling in methods called by TrackPanel::OnMouseEvent, and // to draw button-down states, etc. - virtual bool CloseFunc(Track * t, wxRect rect, int x, int y); virtual bool PopupFunc(Track * t, wxRect rect, int x, int y); - virtual bool MinimizeFunc(Track *t, wxRect rect, int x, int f); public: virtual void MakeParentRedrawScrollbars(); @@ -799,6 +794,7 @@ public: protected: enum MouseCaptureEnum mMouseCapture; + virtual void SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture=IsUncaptured ); // JH: if the user is dragging a track, at what y diff --git a/src/tracks/ui/ButtonHandle.cpp b/src/tracks/ui/ButtonHandle.cpp index 6bec79fa5..8f2695b7f 100644 --- a/src/tracks/ui/ButtonHandle.cpp +++ b/src/tracks/ui/ButtonHandle.cpp @@ -8,7 +8,11 @@ Paul Licameli **********************************************************************/ +#include "../../Audacity.h" #include "ButtonHandle.h" + +#include "../../MemoryX.h" + #include "../../HitTestResult.h" #include "../../Project.h" #include "../../RefreshCode.h" @@ -27,8 +31,8 @@ ButtonHandle::~ButtonHandle() HitTestPreview ButtonHandle::HitPreview() { - // No special message or cursor - return {}; + static wxCursor arrowCursor{ wxCURSOR_ARROW }; + return { {}, &arrowCursor }; } UIHandle::Result ButtonHandle::Click diff --git a/src/tracks/ui/TrackButtonHandles.cpp b/src/tracks/ui/TrackButtonHandles.cpp new file mode 100644 index 000000000..b6916f498 --- /dev/null +++ b/src/tracks/ui/TrackButtonHandles.cpp @@ -0,0 +1,126 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +TrackButtonHandles.cpp + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#include "TrackButtonHandles.h" + +#include "../../HitTestResult.h" +#include "../../Project.h" +#include "../../RefreshCode.h" +#include "../../Track.h" +#include "../../TrackPanel.h" + +MinimizeButtonHandle::MinimizeButtonHandle() + : ButtonHandle{ TrackPanel::IsMinimizing } +{ +} + +MinimizeButtonHandle::~MinimizeButtonHandle() +{ +} + +MinimizeButtonHandle &MinimizeButtonHandle::Instance() +{ + static MinimizeButtonHandle instance; + return instance; +} + +UIHandle::Result MinimizeButtonHandle::CommitChanges +(const wxMouseEvent &, AudacityProject *pProject, wxWindow*) +{ + using namespace RefreshCode; + + if (mpTrack) + { + mpTrack->SetMinimized(!mpTrack->GetMinimized()); + if (mpTrack->GetLink()) + mpTrack->GetLink()->SetMinimized(mpTrack->GetMinimized()); + pProject->ModifyState(true); + + // Redraw all tracks when any one of them expands or contracts + // (Could we invent a return code that draws only those at or below + // the affected track?) + return RefreshAll | FixScrollbars; + } + + return RefreshNone; +} + +HitTestResult MinimizeButtonHandle::HitTest +(const wxMouseEvent &event, const wxRect &rect) +{ + wxRect buttonRect; + TrackInfo::GetMinimizeRect(rect, buttonRect); + + if (buttonRect.Contains(event.m_x, event.m_y)) { + Instance().mRect = buttonRect; + return { + HitPreview(), + &Instance() + }; + } + else + return {}; +} + +//////////////////////////////////////////////////////////////////////////////// + +CloseButtonHandle::CloseButtonHandle() + : ButtonHandle{ TrackPanel::IsClosing } +{ +} + +CloseButtonHandle::~CloseButtonHandle() +{ +} + +CloseButtonHandle &CloseButtonHandle::Instance() +{ + static CloseButtonHandle instance; + return instance; +} + +UIHandle::Result CloseButtonHandle::CommitChanges +(const wxMouseEvent &, AudacityProject *pProject, wxWindow*) +{ + using namespace RefreshCode; + Result result = RefreshNone; + + if (mpTrack) + { + pProject->StopIfPaused(); + if (!pProject->IsAudioActive()) { + // This pushes an undo item: + pProject->RemoveTrack(mpTrack); + // Redraw all tracks when any one of them closes + // (Could we invent a return code that draws only those at or below + // the affected track?) + result |= Resize | RefreshAll | FixScrollbars | DestroyedCell; + } + } + + return result; +} + +HitTestResult CloseButtonHandle::HitTest +(const wxMouseEvent &event, const wxRect &rect) +{ + wxRect buttonRect; + TrackInfo::GetCloseBoxRect(rect, buttonRect); + + if (buttonRect.Contains(event.m_x, event.m_y)) { + Instance().mRect = buttonRect; + return { + HitPreview(), + &Instance() + }; + } + else + return {}; +} diff --git a/src/tracks/ui/TrackButtonHandles.h b/src/tracks/ui/TrackButtonHandles.h new file mode 100644 index 000000000..a03edee7e --- /dev/null +++ b/src/tracks/ui/TrackButtonHandles.h @@ -0,0 +1,58 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +WavelTrackButtonHandles.h + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#ifndef __AUDACITY_TRACK_BUTTON_HANDLES__ +#define __AUDACITY_TRACK_BUTTON_HANDLES__ + +#include "../ui/ButtonHandle.h" + +struct HitTestResult; + +class MinimizeButtonHandle final : public ButtonHandle +{ + MinimizeButtonHandle(const MinimizeButtonHandle&) = delete; + MinimizeButtonHandle &operator=(const MinimizeButtonHandle&) = delete; + + MinimizeButtonHandle(); + virtual ~MinimizeButtonHandle(); + static MinimizeButtonHandle& Instance(); + +protected: + Result CommitChanges + (const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) + override; + +public: + static HitTestResult HitTest(const wxMouseEvent &event, const wxRect &rect); +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CloseButtonHandle final : public ButtonHandle +{ + CloseButtonHandle(const CloseButtonHandle&) = delete; + CloseButtonHandle &operator=(const CloseButtonHandle&) = delete; + + CloseButtonHandle(); + virtual ~CloseButtonHandle(); + static CloseButtonHandle& Instance(); + +protected: + Result CommitChanges + (const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) + override; + + bool StopsOnKeystroke () override { return true; } + +public: + static HitTestResult HitTest(const wxMouseEvent &event, const wxRect &rect); +}; + +#endif diff --git a/src/tracks/ui/TrackControls.cpp b/src/tracks/ui/TrackControls.cpp index f4963f008..ca6c32e84 100644 --- a/src/tracks/ui/TrackControls.cpp +++ b/src/tracks/ui/TrackControls.cpp @@ -10,7 +10,10 @@ Paul Licameli split from TrackPanel.cpp #include "../../Audacity.h" #include "TrackControls.h" +#include "TrackButtonHandles.h" #include "../../HitTestResult.h" +#include "../../TrackPanel.h" +#include "../../TrackPanelMouseEvent.h" int TrackControls::gCaptureState; @@ -19,10 +22,20 @@ TrackControls::~TrackControls() } HitTestResult TrackControls::HitTest -(const TrackPanelMouseEvent &, +(const TrackPanelMouseEvent &evt, const AudacityProject *) { - return {}; + const wxMouseEvent &event = evt.event; + const wxRect &rect = evt.rect; + HitTestResult result; + + if (NULL != (result = CloseButtonHandle::HitTest(event, rect)).handle) + return result; + + if (NULL != (result = MinimizeButtonHandle::HitTest(event, rect)).handle) + return result; + + return result; } Track *TrackControls::FindTrack() diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 6cfa59b3d..060fc1d72 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -248,6 +248,7 @@ + @@ -517,6 +518,7 @@ + @@ -1189,4 +1191,4 @@ - \ No newline at end of file + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index cca3f3f8c..2fd6d201f 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -1019,6 +1019,9 @@ src\tracks\playabletrack\wavetrack\ui + + src\tracks\ui + @@ -2029,6 +2032,9 @@ src\tracks\playabletrack\wavetrack\ui + + src\tracks\ui + @@ -2252,4 +2258,4 @@ plug-ins - \ No newline at end of file +