From efdb9889b14e88a4aab73e270aaafc47e3622cec Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 17 Aug 2015 17:49:00 -0400 Subject: [PATCH] TrackPanel no longer implements label keystrokes, drags, text selection... ... also implemented ESC key for those drags ... temporarily loses the special CTRL click handling --- mac/Audacity.xcodeproj/project.pbxproj | 18 + src/LabelTrack.cpp | 88 ++++- src/LabelTrack.h | 32 +- src/Makefile.am | 6 + src/TrackPanel.cpp | 310 +----------------- src/TrackPanel.h | 11 - .../labeltrack/ui/LabelDefaultClickHandle.cpp | 181 ++++++++++ .../labeltrack/ui/LabelDefaultClickHandle.h | 70 ++++ src/tracks/labeltrack/ui/LabelGlyphHandle.cpp | 164 +++++++++ src/tracks/labeltrack/ui/LabelGlyphHandle.h | 58 ++++ src/tracks/labeltrack/ui/LabelTextHandle.cpp | 184 +++++++++++ src/tracks/labeltrack/ui/LabelTextHandle.h | 63 ++++ src/tracks/labeltrack/ui/LabelTrackUI.cpp | 40 ++- win/Projects/Audacity/Audacity.vcxproj | 6 + .../Audacity/Audacity.vcxproj.filters | 18 + 15 files changed, 923 insertions(+), 326 deletions(-) create mode 100644 src/tracks/labeltrack/ui/LabelDefaultClickHandle.cpp create mode 100644 src/tracks/labeltrack/ui/LabelDefaultClickHandle.h create mode 100644 src/tracks/labeltrack/ui/LabelGlyphHandle.cpp create mode 100644 src/tracks/labeltrack/ui/LabelGlyphHandle.h create mode 100644 src/tracks/labeltrack/ui/LabelTextHandle.cpp create mode 100644 src/tracks/labeltrack/ui/LabelTextHandle.h diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 9a6cd7cad..5a2a59fdf 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1235,6 +1235,9 @@ 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 */; }; + 5E7396691DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396631DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp */; }; + 5E73966A1DAFDB5600BA0A4D /* LabelGlyphHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396651DAFDB5600BA0A4D /* LabelGlyphHandle.cpp */; }; + 5E73966B1DAFDB5600BA0A4D /* LabelTextHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396671DAFDB5600BA0A4D /* LabelTextHandle.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 */; }; @@ -3076,6 +3079,12 @@ 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 = ""; }; + 5E7396631DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LabelDefaultClickHandle.cpp; sourceTree = ""; }; + 5E7396641DAFDB5600BA0A4D /* LabelDefaultClickHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelDefaultClickHandle.h; sourceTree = ""; }; + 5E7396651DAFDB5600BA0A4D /* LabelGlyphHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LabelGlyphHandle.cpp; sourceTree = ""; }; + 5E7396661DAFDB5600BA0A4D /* LabelGlyphHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelGlyphHandle.h; sourceTree = ""; }; + 5E7396671DAFDB5600BA0A4D /* LabelTextHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LabelTextHandle.cpp; sourceTree = ""; }; + 5E7396681DAFDB5600BA0A4D /* LabelTextHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelTextHandle.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 = ""; }; @@ -5732,9 +5741,15 @@ 5E15123F1DB000DC00702E29 /* ui */ = { isa = PBXGroup; children = ( + 5E7396631DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp */, + 5E7396651DAFDB5600BA0A4D /* LabelGlyphHandle.cpp */, + 5E7396671DAFDB5600BA0A4D /* LabelTextHandle.cpp */, 5E1512401DB000DC00702E29 /* LabelTrackControls.cpp */, 5E1512421DB000DC00702E29 /* LabelTrackUI.cpp */, 5E1512431DB000DC00702E29 /* LabelTrackVRulerControls.cpp */, + 5E7396641DAFDB5600BA0A4D /* LabelDefaultClickHandle.h */, + 5E7396661DAFDB5600BA0A4D /* LabelGlyphHandle.h */, + 5E7396681DAFDB5600BA0A4D /* LabelTextHandle.h */, 5E1512411DB000DC00702E29 /* LabelTrackControls.h */, 5E1512441DB000DC00702E29 /* LabelTrackVRulerControls.h */, ); @@ -7652,6 +7667,7 @@ 1790B15E09883BFD008A330A /* ExportMultiple.cpp in Sources */, 1790B15F09883BFD008A330A /* ExportOGG.cpp in Sources */, 1790B16009883BFD008A330A /* ExportPCM.cpp in Sources */, + 5E7396691DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp in Sources */, 1790B16109883BFD008A330A /* FFT.cpp in Sources */, 1790B16209883BFD008A330A /* FileFormats.cpp in Sources */, 1790B16309883BFD008A330A /* FreqWindow.cpp in Sources */, @@ -7824,6 +7840,7 @@ 284B279E0FC66864005EAC96 /* ProjectsPrefs.cpp in Sources */, 5E78388E1DE4995F003270C0 /* AudacityException.cpp in Sources */, 284B279F0FC66864005EAC96 /* RecordingPrefs.cpp in Sources */, + 5E73966B1DAFDB5600BA0A4D /* LabelTextHandle.cpp in Sources */, 284B27E40FC66CCD005EAC96 /* TracksPrefs.cpp in Sources */, 284B27E50FC66CCD005EAC96 /* WarningsPrefs.cpp in Sources */, 5E15125B1DB000DC00702E29 /* LabelTrackUI.cpp in Sources */, @@ -7921,6 +7938,7 @@ ED87F50A1986424100AC520B /* ta.po in Sources */, 2888496E131B6CF600B59735 /* tg.po in Sources */, 5E7396441DAFD8C600BA0A4D /* TimeShiftHandle.cpp in Sources */, + 5E73966A1DAFDB5600BA0A4D /* LabelGlyphHandle.cpp in Sources */, 2888496F131B6CF600B59735 /* tr.po in Sources */, 28884970131B6CF600B59735 /* uk.po in Sources */, 28884971131B6CF600B59735 /* vi.po in Sources */, diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index 163f516e2..7cb560623 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -30,6 +30,7 @@ for drawing different aspects of the label and its text box. #include "Audacity.h" #include "LabelTrack.h" +#include "TrackPanel.h" #include #include @@ -55,6 +56,7 @@ for drawing different aspects of the label and its text box. #include "DirManager.h" #include "Internat.h" #include "Prefs.h" +#include "RefreshCode.h" #include "Theme.h" #include "AllThemeResources.h" #include "AColor.h" @@ -280,6 +282,15 @@ void LabelTrack::ResetFlags() mDrawCursor = false; } +void LabelTrack::RestoreFlags( const Flags& flags ) +{ + mInitialCursorPos = flags.mInitialCursorPos; + mCurrentCursorPos = flags.mCurrentCursorPos; + mSelIndex = flags.mSelIndex; + mRightDragging = flags.mRightDragging; + mDrawCursor = flags.mDrawCursor; +} + wxFont LabelTrack::GetFont(const wxString &faceName, int size) { wxFontEncoding encoding; @@ -1545,7 +1556,7 @@ void LabelTrack::HandleTextDragRelease(const wxMouseEvent & evt) return; } -void LabelTrack::HandleClick(const wxMouseEvent & evt, +void LabelTrack::HandleGlyphClick(const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo, SelectedRegion *newSel) { @@ -1596,6 +1607,15 @@ void LabelTrack::HandleClick(const wxMouseEvent & evt, mxMouseDisplacement = zoomInfo.TimeToPosition(t, r.x) - evt.m_x; return; } + } +} + +void LabelTrack::HandleTextClick(const wxMouseEvent & evt, + const wxRect & r, const ZoomInfo &zoomInfo, + SelectedRegion *newSel) +{ + if (evt.ButtonDown()) + { mSelIndex = OverATextBox(evt.m_x, evt.m_y); if (mSelIndex != -1) { @@ -1660,7 +1680,6 @@ void LabelTrack::HandleClick(const wxMouseEvent & evt, } #endif } - #if defined(__WXGTK__) && (HAVE_GTK) if (evt.MiddleDown()) { // Paste text, making a NEW label if none is selected. @@ -1673,7 +1692,7 @@ void LabelTrack::HandleClick(const wxMouseEvent & evt, } // Check for keys that we will process -bool LabelTrack::CaptureKey(wxKeyEvent & event) +bool LabelTrack::DoCaptureKey(wxKeyEvent & event) { // Check for modifiers and only allow shift int mods = event.GetModifiers(); @@ -1725,6 +1744,69 @@ bool LabelTrack::CaptureKey(wxKeyEvent & event) return false; } +unsigned LabelTrack::CaptureKey(wxKeyEvent & event, ViewInfo &, wxWindow *) +{ + event.Skip(!DoCaptureKey(event)); + return RefreshCode::RefreshNone; +} + +unsigned LabelTrack::KeyDown(wxKeyEvent & event, ViewInfo &viewInfo, wxWindow *pParent) +{ + double bkpSel0 = viewInfo.selectedRegion.t0(), + bkpSel1 = viewInfo.selectedRegion.t1(); + + AudacityProject *const pProj = GetActiveProject(); + + // Pass keystroke to labeltrack's handler and add to history if any + // updates were done + if (OnKeyDown(viewInfo.selectedRegion, event)) { + pProj->PushState(_("Modified Label"), + _("Label Edit"), + UndoPush::CONSOLIDATE); + } + + // Make sure caret is in view + int x; + if (CalcCursorX(&x)) { + pProj->GetTrackPanel()->ScrollIntoView(x); + } + + // If selection modified, refresh + // Otherwise, refresh track display if the keystroke was handled + if (bkpSel0 != viewInfo.selectedRegion.t0() || + bkpSel1 != viewInfo.selectedRegion.t1()) + return RefreshCode::RefreshAll; + else if (!event.GetSkipped()) + return RefreshCode::RefreshCell; + + return RefreshCode::RefreshNone; +} + +unsigned LabelTrack::Char(wxKeyEvent & event, ViewInfo &viewInfo, wxWindow *) +{ + double bkpSel0 = viewInfo.selectedRegion.t0(), + bkpSel1 = viewInfo.selectedRegion.t1(); + // Pass keystroke to labeltrack's handler and add to history if any + // updates were done + + AudacityProject *const pProj = GetActiveProject(); + + if (OnChar(viewInfo.selectedRegion, event)) + pProj->PushState(_("Modified Label"), + _("Label Edit"), + UndoPush::CONSOLIDATE); + + // If selection modified, refresh + // Otherwise, refresh track display if the keystroke was handled + if (bkpSel0 != viewInfo.selectedRegion.t0() || + bkpSel1 != viewInfo.selectedRegion.t1()) + return RefreshCode::RefreshAll; + else if (!event.GetSkipped()) + return RefreshCode::RefreshCell; + + return RefreshCode::RefreshNone; +} + /// KeyEvent is called for every keypress when over the label track. bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event) { diff --git a/src/LabelTrack.h b/src/LabelTrack.h index 60d79b846..c2a300947 100644 --- a/src/LabelTrack.h +++ b/src/LabelTrack.h @@ -125,6 +125,16 @@ class AUDACITY_DLL_API LabelTrack final : public Track (const TrackPanelMouseEvent &event, const AudacityProject *pProject) override; + bool DoCaptureKey(wxKeyEvent &event); + unsigned CaptureKey + (wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent) override; + + unsigned KeyDown + (wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent) override; + + unsigned Char + (wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent) override; + void SetOffset(double dOffset) override; static const int DefaultFontSize = 12; @@ -171,7 +181,20 @@ class AUDACITY_DLL_API LabelTrack final : public Track static wxBitmap & GetGlyph( int i); + struct Flags { + int mInitialCursorPos, mCurrentCursorPos, mSelIndex; + bool mRightDragging, mDrawCursor; + }; void ResetFlags(); + Flags SaveFlags() const + { + return { + mInitialCursorPos, mCurrentCursorPos, mSelIndex, + mRightDragging, mDrawCursor + }; + } + void RestoreFlags( const Flags& flags ); + int OverATextBox(int xx, int yy) const; bool OverTextBox(const LabelStruct *pLabel, int x, int y) const; bool CutSelectedText(); @@ -179,13 +202,16 @@ class AUDACITY_DLL_API LabelTrack final : public Track bool PasteSelectedText(double sel0, double sel1); static bool IsTextClipSupported(); - void HandleClick(const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo, - SelectedRegion *newSel); + void HandleGlyphClick + (const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo, + SelectedRegion *newSel); + void HandleTextClick + (const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo, + SelectedRegion *newSel); bool HandleGlyphDragRelease(const wxMouseEvent & evt, wxRect & r, const ZoomInfo &zoomInfo, SelectedRegion *newSel); void HandleTextDragRelease(const wxMouseEvent & evt); - bool CaptureKey(wxKeyEvent & event); bool OnKeyDown(SelectedRegion &sel, wxKeyEvent & event); bool OnChar(SelectedRegion &sel, wxKeyEvent & event); diff --git a/src/Makefile.am b/src/Makefile.am index a3764b167..9575b36b5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -551,6 +551,12 @@ audacity_SOURCES = \ toolbars/ToolsToolBar.h \ toolbars/TranscriptionToolBar.cpp \ toolbars/TranscriptionToolBar.h \ + tracks/labeltrack/ui/LabelDefaultClickHandle.cpp \ + tracks/labeltrack/ui/LabelDefaultClickHandle.h \ + tracks/labeltrack/ui/LabelGlyphHandle.cpp \ + tracks/labeltrack/ui/LabelGlyphHandle.h \ + tracks/labeltrack/ui/LabelTextHandle.cpp \ + tracks/labeltrack/ui/LabelTextHandle.h \ tracks/labeltrack/ui/LabelTrackControls.cpp \ tracks/labeltrack/ui/LabelTrackControls.h \ tracks/labeltrack/ui/LabelTrackUI.cpp \ diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index b2777878e..480b9c413 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -166,7 +166,6 @@ is time to refresh some aspect of the screen. #include "AllThemeResources.h" #include "AudioIO.h" #include "float_cast.h" -#include "LabelTrack.h" #include "MixerBoard.h" #include "NoteTrack.h" @@ -356,8 +355,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, } mMouseCapture = IsUncaptured; - mLabelTrackStartXPos=-1; - mRedrawAfterStop = false; @@ -553,28 +550,6 @@ void TrackPanel::SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture mMouseCapture = MouseCapture; } -/// Select all tracks marked by the label track lt -void TrackPanel::SelectTracksByLabel( LabelTrack *lt ) -{ - TrackListIterator iter(GetTracks()); - Track *t = iter.First(); - - //do nothing if at least one other track is selected - while (t) { - if( t->GetSelected() && t != lt ) - return; - t = iter.Next(); - } - - //otherwise, select all tracks - t = iter.First(); - while( t ) - { - GetSelectionState().SelectTrack( *mTracks, *t, true, true, GetMixerBoard() ); - t = iter.Next(); - } -} - void TrackPanel::GetTracksUsableArea(int *width, int *height) const { GetSize(width, height); @@ -859,7 +834,6 @@ void TrackPanel::HandleInterruptedDrag() { case IsUncaptured: case IsSelecting: - case IsSelectingLabelText: sendEvent = false; default: @@ -867,9 +841,8 @@ void TrackPanel::HandleInterruptedDrag() } /* - So this includes the cases: + So this includes the case: - IsAdjustingLabel, IsStretching */ @@ -1087,9 +1060,6 @@ bool TrackPanel::SetCursorByActivity( ) case IsSelecting: SetCursor(*mSelectCursor); return true; - case IsAdjustingLabel: - case IsSelectingLabelText: - return true; #if 0 case IsStretching: SetCursor( unsafe @@ -1103,37 +1073,6 @@ bool TrackPanel::SetCursorByActivity( ) return false; } -/// When in a label track, find out if we've hit anything that -/// would cause a cursor change. -void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, - const wxMouseEvent & event, wxString &tip ) -{ - int edge=pLT->OverGlyph(event.m_x, event.m_y); - if(edge !=0) - { - SetCursor(*mArrowCursor); - } - - //KLUDGE: We refresh the whole Label track when the icon hovered over - //changes colouration. As well as being inefficient we are also - //doing stuff that should be delegated to the label track itself. - edge += pLT->mbHitCenter ? 4:0; - if( edge != pLT->mOldEdge ) - { - pLT->mOldEdge = edge; - RefreshTrack( pLT ); - } - // IF edge!=0 THEN we've set the cursor and we're done. - // signal this by setting the tip. - if( edge != 0 ) - { - tip = - (pLT->mbHitCenter ) ? - _("Drag one or more label boundaries.") : - _("Drag label boundary."); - } -} - namespace { // This returns true if we're a spectral editing track. @@ -1415,16 +1354,6 @@ void TrackPanel::HandleCursor(wxMouseEvent & event) SetCursor(*pCursor); } - // Is it a label track? - if (track && - pCursor == NULL && tip == wxString() && track->GetKind() == Track::Label) - { - // We are over a label track - SetCursorAndTipWhenInLabelTrack( static_cast(track), event, tip ); - // ..and if we haven't yet determined the cursor, - // we go on to do all the standard track hit tests. - } - if( pCursor == NULL && tip == wxString() ) { ToolsToolBar * ttb = mListener->TP_GetToolsToolBar(); @@ -3038,9 +2967,6 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event) HandleInterruptedDrag(); Track * const t = GetFocusedTrack(); - if (t && t->GetKind() == Track::Label) - event.Skip(!((LabelTrack *)t)->CaptureKey(*kevent)); - else if (t) { const unsigned refreshResult = ((TrackPanelCell*)t)->CaptureKey(*kevent, *mViewInfo, this); @@ -3087,33 +3013,6 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event) Track *const t = GetFocusedTrack(); - if (t && t->GetKind() == Track::Label) { - LabelTrack *lt = (LabelTrack *)t; - double bkpSel0 = mViewInfo->selectedRegion.t0(), - bkpSel1 = mViewInfo->selectedRegion.t1(); - - // Pass keystroke to labeltrack's handler and add to history if any - // updates were done - if (lt->OnKeyDown(mViewInfo->selectedRegion, event)) - MakeParentPushState(_("Modified Label"), - _("Label Edit"), - UndoPush::CONSOLIDATE); - - // Make sure caret is in view - int x; - if (lt->CalcCursorX(&x)) { - ScrollIntoView(x); - } - - // If selection modified, refresh - // Otherwise, refresh track display if the keystroke was handled - if (bkpSel0 != mViewInfo->selectedRegion.t0() || - bkpSel1 != mViewInfo->selectedRegion.t1()) - Refresh(false); - else if (!event.GetSkipped()) - RefreshTrack(t); - } - else if (t) { const unsigned refreshResult = ((TrackPanelCell*)t)->KeyDown(event, *mViewInfo, this); @@ -3137,25 +3036,6 @@ void TrackPanel::OnChar(wxKeyEvent & event) } Track *const t = GetFocusedTrack(); - if (t && t->GetKind() == Track::Label) { - double bkpSel0 = mViewInfo->selectedRegion.t0(), - bkpSel1 = mViewInfo->selectedRegion.t1(); - // Pass keystroke to labeltrack's handler and add to history if any - // updates were done - if (((LabelTrack *)t)->OnChar(mViewInfo->selectedRegion, event)) - MakeParentPushState(_("Modified Label"), - _("Label Edit"), - UndoPush::CONSOLIDATE); - - // If selection modified, refresh - // Otherwise, refresh track display if the keystroke was handled - if (bkpSel0 != mViewInfo->selectedRegion.t0() || - bkpSel1 != mViewInfo->selectedRegion.t1()) - Refresh(false); - else if (!event.GetSkipped()) - RefreshTrack(t); - } - else if (t) { const unsigned refreshResult = ((TrackPanelCell*)t)->Char(event, *mViewInfo, this); @@ -3341,19 +3221,10 @@ try // HandleCursor(event); } } - else switch( mMouseCapture ) { - case IsAdjustingLabel: - // Reach this case only when the captured track was label - HandleGlyphDragRelease(static_cast(mCapturedTrack), event); - break; - case IsSelectingLabelText: - // Reach this case only when the captured track was label - HandleTextDragRelease(static_cast(mCapturedTrack), event); - break; - default: //includes case of IsUncaptured + else { + // includes case of IsUncaptured // This is where most button-downs are detected HandleTrackSpecificMouseEvent(event); - break; } if (event.ButtonDown() && IsMouseCaptured()) { @@ -3390,171 +3261,6 @@ catch( ... ) throw; } -/// Event has happened on a track and it has been determined to be a label track. -bool TrackPanel::HandleLabelTrackClick(LabelTrack * lTrack, const wxRect &rect, wxMouseEvent & event) -{ - if (!event.ButtonDown()) - return false; - - if(event.LeftDown()) - { - /// \todo This method is one of a large number of methods in - /// TrackPanel which suitably modified belong in other classes. - TrackListIterator iter(GetTracks()); - Track *n = iter.First(); - - while (n) { - if (n->GetKind() == Track::Label && lTrack != n) { - ((LabelTrack *)n)->ResetFlags(); - ((LabelTrack *)n)->Unselect(); - } - n = iter.Next(); - } - } - - mCapturedRect = rect; - - lTrack->HandleClick(event, mCapturedRect, *mViewInfo, &mViewInfo->selectedRegion); - - if (lTrack->IsAdjustingLabel()) - { - SetCapturedTrack(lTrack, IsAdjustingLabel); - - //If we are adjusting a label on a labeltrack, do not do anything - //that follows. Instead, redraw the track. - RefreshTrack(lTrack); - return true; - } - - if( event.LeftDown() ){ - bool bShift = event.ShiftDown(); - bool bCtrlDown = event.ControlDown(); - bool unsafe = IsUnsafe(); - - if( /*bShift ||*/ bCtrlDown ){ - - GetProject()->HandleListSelection(lTrack, bShift, bCtrlDown, !unsafe); - return true; - } - } - - - // IF the user clicked a label, THEN select all other tracks by Label - if (lTrack->IsSelected()) { - SelectTracksByLabel(lTrack); - // Do this after, for the effect on mLastPickedTrack: - GetSelectionState().SelectTrack - ( *mTracks, *lTrack, true, true, GetMixerBoard() ); - DisplaySelection(); - - // Not starting a drag - SetCapturedTrack(NULL, IsUncaptured); - - if(mCapturedTrack == NULL) - SetCapturedTrack(lTrack, IsSelectingLabelText); - - RefreshTrack(lTrack); - - // PRL: bug1659 -- make selection change undo correctly - if (!IsUnsafe()) - MakeParentModifyState(false); - - return true; - } - - // handle shift+ctrl down - /*if (event.ShiftDown()) { // && event.ControlDown()) { - lTrack->SetHighlightedByKey(true); - Refresh(false); - return; - }*/ - - - - - // return false, there is more to do... - return false; -} - -/// Event has happened on a track and it has been determined to be a label track. -void TrackPanel::HandleGlyphDragRelease(LabelTrack * lTrack, wxMouseEvent & event) -{ - if (!lTrack) - return; - - /// \todo This method is one of a large number of methods in - /// TrackPanel which suitably modified belong in other classes. - if (event.Dragging()) { - ; - } - else if (event.LeftUp()) - SetCapturedTrack(NULL); - - if (lTrack->HandleGlyphDragRelease(event, mCapturedRect, - *mViewInfo, &mViewInfo->selectedRegion)) { - MakeParentPushState(_("Modified Label"), - _("Label Edit"), - UndoPush::CONSOLIDATE); - } - - // Update cursor on the screen if it is a point. - DrawOverlays(false); - mRuler->DrawOverlays(false); - - //If we are adjusting a label on a labeltrack, do not do anything - //that follows. Instead, redraw the track. - RefreshTrack(lTrack); - return; -} - -/// Event has happened on a track and it has been determined to be a label track. -void TrackPanel::HandleTextDragRelease(LabelTrack * lTrack, wxMouseEvent & event) -{ - if (!lTrack) - return; - - lTrack->HandleTextDragRelease(event); - - /// \todo This method is one of a large number of methods in - /// TrackPanel which suitably modified belong in other classes. - if (event.Dragging()) { - ; - } - else if (event.ButtonUp()) - SetCapturedTrack(NULL); - - // handle dragging - if (event.Dragging()) { - // locate the initial mouse position - if (event.LeftIsDown()) { - if (mLabelTrackStartXPos == -1) { - mLabelTrackStartXPos = event.m_x; - mLabelTrackStartYPos = event.m_y; - - if ((lTrack->getSelectedIndex() != -1) && - lTrack->OverTextBox( - lTrack->GetLabel(lTrack->getSelectedIndex()), - mLabelTrackStartXPos, - mLabelTrackStartYPos)) - { - mLabelTrackStartYPos = -1; - } - } - // if initial mouse position in the text box - // then only drag text - if (mLabelTrackStartYPos == -1) { - RefreshTrack(lTrack); - return; - } - } - } - - // handle mouse left button up - if (event.LeftUp()) { - mLabelTrackStartXPos = -1; - } -} - // AS: I don't really understand why this code is sectioned off // from the other OnMouseEvent code. void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event) @@ -3605,16 +3311,6 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event) // To do: remove the following special things // so that we can coalesce the code for track and non-track clicks - //Determine if user clicked on a label track. - //If so, use MouseDown handler for the label track. - if (!mUIHandle && - pTrack && foundCell.type == CellType::Track && - (pTrack->GetKind() == Track::Label)) - { - if (HandleLabelTrackClick((LabelTrack *)pTrack, rect, event)) - return; - } - bool handled = false; ToolsToolBar * pTtb = mListener->TP_GetToolsToolBar(); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index c4a1805b1..a9a416323 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -337,9 +337,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel { virtual bool IsAudioActive(); virtual bool IsUnsafe(); - virtual bool HandleLabelTrackClick(LabelTrack * lTrack, const wxRect &rect, wxMouseEvent & event); - virtual void HandleGlyphDragRelease(LabelTrack * lTrack, wxMouseEvent & event); - virtual void HandleTextDragRelease(LabelTrack * lTrack, wxMouseEvent & event); virtual void HandleTrackSpecificMouseEvent(wxMouseEvent & event); virtual void ScrollDuringDrag(); @@ -424,12 +421,9 @@ protected: #endif - virtual void SelectTracksByLabel( LabelTrack *t ); - protected: // AS: Cursor handling virtual bool SetCursorByActivity( ); - 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 ); virtual void SetCursorAndTipByTool( int tool, const wxMouseEvent & event, wxString &tip ); @@ -520,9 +514,6 @@ public: static bool HasSoloButton(){ return gSoloPref!=wxT("None");} protected: - //JKC: These two belong in the label track. - int mLabelTrackStartXPos; - int mLabelTrackStartYPos; TrackInfo mTrackInfo; @@ -676,8 +667,6 @@ public: IsUncaptured=0, // This is the normal state for the mouse IsClosing, IsSelecting, - IsAdjustingLabel, - IsSelectingLabelText, IsMuting, IsSoloing, IsMinimizing, diff --git a/src/tracks/labeltrack/ui/LabelDefaultClickHandle.cpp b/src/tracks/labeltrack/ui/LabelDefaultClickHandle.cpp new file mode 100644 index 000000000..684bafac9 --- /dev/null +++ b/src/tracks/labeltrack/ui/LabelDefaultClickHandle.cpp @@ -0,0 +1,181 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +LabelDefaultClickHandle.cpp + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#include "../../../Audacity.h" +#include "LabelDefaultClickHandle.h" +#include "../../../HitTestResult.h" +#include "../../../LabelTrack.h" +#include "../../../Project.h" +#include "../../../RefreshCode.h" +#include "../../../TrackPanelMouseEvent.h" +#include "../../../ViewInfo.h" + +LabelDefaultClickHandle::LabelDefaultClickHandle() +{ +} + +LabelDefaultClickHandle &LabelDefaultClickHandle::Instance() +{ + static LabelDefaultClickHandle instance; + return instance; +} + +LabelDefaultClickHandle::~LabelDefaultClickHandle() +{ +} + +struct LabelDefaultClickHandle::LabelState { + std::vector< std::pair< LabelTrack*, LabelTrack::Flags > > mPairs; +}; + +void LabelDefaultClickHandle::SaveState( AudacityProject *pProject ) +{ + mLabelState = std::make_unique(); + auto &pairs = mLabelState->mPairs; + TrackList *const tracks = pProject->GetTracks(); + TrackListIterator iter(tracks); + Track *n = iter.First(); + + while (n) { + if (n->GetKind() == Track::Label) { + LabelTrack *const lt = static_cast(n); + pairs.push_back( std::make_pair( lt, lt->SaveFlags() ) ); + } + n = iter.Next(); + } +} + +void LabelDefaultClickHandle::UpdateState( AudacityProject *pProject ) +{ + if ( mLabelState ) { + auto trackList = pProject->GetTracks(); + auto &pairs = mLabelState->mPairs; + auto it = pairs.begin(); + while ( it != pairs.end() ) { + if ( trackList->Contains( it->first ) ) + ++it; + else + it = pairs.erase( it ); + } + } +} + +void LabelDefaultClickHandle::RestoreState( AudacityProject *pProject ) +{ + if ( mLabelState ) { + for ( const auto &pair : mLabelState->mPairs ) + pair.first->RestoreFlags( pair.second ); + mLabelState.reset(); + } +} + +void LabelDefaultClickHandle::DoClick +(const wxMouseEvent &event, AudacityProject *pProject, TrackPanelCell *pCell) +{ + LabelTrack *pLT = static_cast(pCell); + + if (event.LeftDown()) + { + SaveState( pProject ); + + TrackList *const tracks = pProject->GetTracks(); + TrackListIterator iter(tracks); + Track *n = iter.First(); + + while (n) { + if (n->GetKind() == Track::Label && pCell != n) { + LabelTrack *const lt = static_cast(n); + lt->ResetFlags(); + lt->Unselect(); + } + n = iter.Next(); + } + } +} + +UIHandle::Result LabelDefaultClickHandle::Click +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + using namespace RefreshCode; + // Redraw to show the change of text box selection status + UIHandle::Result result = RefreshAll; + + DoClick(evt.event, pProject, evt.pCell); + + if (mpForward) + result |= mpForward->Click(evt, pProject); + else + // No drag or release follows + result |= Cancelled; + + return result; +} + +UIHandle::Result LabelDefaultClickHandle::Drag +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + if (mpForward) + return mpForward->Drag(evt, pProject); + else + return RefreshCode::RefreshNone; +} + +HitTestPreview LabelDefaultClickHandle::Preview +(const TrackPanelMouseEvent &evt, const AudacityProject *pProject) +{ + if (mpForward) + return mpForward->Preview(evt, pProject); + else + return {}; +} + +UIHandle::Result LabelDefaultClickHandle::Release +(const TrackPanelMouseEvent &evt, AudacityProject *pProject, + wxWindow *pParent) +{ + mLabelState.reset(); + if (mpForward) + return mpForward->Release(evt, pProject, pParent); + else + return RefreshCode::RefreshNone; +} + +UIHandle::Result LabelDefaultClickHandle::Cancel(AudacityProject *pProject) +{ + UIHandle::Result result = RefreshCode::RefreshNone; + if (mpForward) + result |= mpForward->Cancel(pProject); + RestoreState( pProject ); + return result; +} + +void LabelDefaultClickHandle::DrawExtras +(DrawingPass pass, + wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect) +{ + UIHandle::DrawExtras(pass, dc, updateRegion, panelRect); + if (mpForward) + mpForward->DrawExtras(pass, dc, updateRegion, panelRect); +} + +bool LabelDefaultClickHandle::StopsOnKeystroke() +{ + return + (mpForward && mpForward->StopsOnKeystroke()) || + UIHandle::StopsOnKeystroke(); +} + +void LabelDefaultClickHandle::OnProjectChange(AudacityProject *pProject) +{ + UpdateState( pProject ); + if (mpForward) + return mpForward->OnProjectChange(pProject); + UIHandle::OnProjectChange(pProject); +} diff --git a/src/tracks/labeltrack/ui/LabelDefaultClickHandle.h b/src/tracks/labeltrack/ui/LabelDefaultClickHandle.h new file mode 100644 index 000000000..91162dd2d --- /dev/null +++ b/src/tracks/labeltrack/ui/LabelDefaultClickHandle.h @@ -0,0 +1,70 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +LabelDefaultClickHandle.h + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#ifndef __AUDACITY_LABEL_DEFAULT_CLICK_HANDLE__ +#define __AUDACITY_LABEL_DEFAULT_CLICK_HANDLE__ + +#include "../../../UIHandle.h" +#include "../../../MemoryX.h" + +class wxMouseEvent; +struct HitTestResult; +class LabelTrack; + +// Adds some behavior to click, then calls through to other mouse handling. +class LabelDefaultClickHandle final : public UIHandle +{ + LabelDefaultClickHandle(); + LabelDefaultClickHandle(const LabelDefaultClickHandle&) = delete; + LabelDefaultClickHandle &operator=(const LabelDefaultClickHandle&) = delete; + +public: + static LabelDefaultClickHandle& Instance(); + virtual ~LabelDefaultClickHandle(); + + void DoClick + (const wxMouseEvent &event, AudacityProject *pProject, TrackPanelCell *pCell); + + 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 DrawExtras + (DrawingPass pass, + wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect) + override; + + bool StopsOnKeystroke() override; + + void OnProjectChange(AudacityProject *pProject) override; + + UIHandle *mpForward {}; + +private: + struct LabelState; + std::unique_ptr< LabelState > mLabelState; + void SaveState( AudacityProject *pProject ); + void UpdateState( AudacityProject *pProject ); + void RestoreState( AudacityProject *pProject ); +}; + +#endif diff --git a/src/tracks/labeltrack/ui/LabelGlyphHandle.cpp b/src/tracks/labeltrack/ui/LabelGlyphHandle.cpp new file mode 100644 index 000000000..ba79405ea --- /dev/null +++ b/src/tracks/labeltrack/ui/LabelGlyphHandle.cpp @@ -0,0 +1,164 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +LabelGlyphHandle.cpp + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#include "LabelGlyphHandle.h" +#include "../../../HitTestResult.h" +#include "../../../LabelTrack.h" +#include "../../../Project.h" +#include "../../../RefreshCode.h" +#include "../../../TrackPanelMouseEvent.h" +#include "../../../UndoManager.h" +#include "../../../ViewInfo.h" + +#include "../../../MemoryX.h" + +#include +#include + +LabelGlyphHandle::LabelGlyphHandle() +{ +} + +LabelGlyphHandle &LabelGlyphHandle::Instance() +{ + static LabelGlyphHandle instance; + return instance; +} + +HitTestPreview LabelGlyphHandle::HitPreview + (bool hitCenter, unsigned refreshResult) +{ + static wxCursor arrowCursor{ wxCURSOR_ARROW }; + return { + (hitCenter + ? _("Drag one or more label boundaries.") + : _("Drag label boundary.")), + &arrowCursor, + // Unusually, can have a non-zero third member of HitTestPreview, so that + // mouse-over highlights it. + refreshResult + }; +} + +HitTestResult LabelGlyphHandle::HitTest +(const wxMouseEvent &event, LabelTrack *pLT) +{ + using namespace RefreshCode; + unsigned refreshResult = RefreshNone; + + // Note: this has side effects on pLT! + int edge = pLT->OverGlyph(event.m_x, event.m_y); + + //KLUDGE: We refresh the whole Label track when the icon hovered over + //changes colouration. Inefficient. + edge += pLT->mbHitCenter ? 4 : 0; + if (edge != pLT->mOldEdge) + { + pLT->mOldEdge = edge; + refreshResult |= RefreshCell; + } + + // IF edge!=0 THEN we've set the cursor and we're done. + // signal this by setting the tip. + if (edge != 0) + { + return { + HitPreview(pLT->mbHitCenter, refreshResult), + &Instance() + }; + } + else { + // An empty result, except maybe, unusually, the refresh + return { + { wxString{}, nullptr, refreshResult }, + nullptr + }; + } +} + +LabelGlyphHandle::~LabelGlyphHandle() +{ +} + +UIHandle::Result LabelGlyphHandle::Click +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + TrackPanelCell *const pCell = evt.pCell; + const wxMouseEvent &event = evt.event; + const wxRect &rect = evt.rect; + + mpLT = static_cast(pCell); + mRect = rect; + + ViewInfo &viewInfo = pProject->GetViewInfo(); + mpLT->HandleGlyphClick(event, rect, viewInfo, &viewInfo.selectedRegion); + + if (! mpLT->IsAdjustingLabel() ) + { + // The positive hit test should have ensured otherwise + //wxASSERT(false); + return RefreshCode::Cancelled; + } + + // redraw the track. + return RefreshCode::RefreshCell; + + // handle shift+ctrl down + /*if (event.ShiftDown()) { // && event.ControlDown()) { + lTrack->SetHighlightedByKey(true); + Refresh(false); + return; + }*/ + + + return RefreshCode::RefreshNone; +} + +UIHandle::Result LabelGlyphHandle::Drag +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + const wxMouseEvent &event = evt.event; + ViewInfo &viewInfo = pProject->GetViewInfo(); + mpLT->HandleGlyphDragRelease(event, mRect, viewInfo, &viewInfo.selectedRegion); + + // Refresh all so that the change of selection is redrawn in all tracks + return RefreshCode::RefreshAll | RefreshCode::DrawOverlays; +} + +HitTestPreview LabelGlyphHandle::Preview +(const TrackPanelMouseEvent &evt, const AudacityProject *pProject) +{ + return HitPreview(mpLT->mbHitCenter, 0); +} + +UIHandle::Result LabelGlyphHandle::Release +(const TrackPanelMouseEvent &evt, AudacityProject *pProject, + wxWindow *pParent) +{ + mpLT->mOldEdge = 0; + + const wxMouseEvent &event = evt.event; + ViewInfo &viewInfo = pProject->GetViewInfo(); + if (mpLT->HandleGlyphDragRelease(event, mRect, viewInfo, &viewInfo.selectedRegion)) { + pProject->PushState(_("Modified Label"), + _("Label Edit"), + UndoPush::CONSOLIDATE); + } + + // Refresh all so that the change of selection is redrawn in all tracks + return RefreshCode::RefreshAll | RefreshCode::DrawOverlays; +} + +UIHandle::Result LabelGlyphHandle::Cancel(AudacityProject *pProject) +{ + mpLT->mOldEdge = 0; + pProject->RollbackState(); + return RefreshCode::RefreshAll; +} diff --git a/src/tracks/labeltrack/ui/LabelGlyphHandle.h b/src/tracks/labeltrack/ui/LabelGlyphHandle.h new file mode 100644 index 000000000..f2f5baf48 --- /dev/null +++ b/src/tracks/labeltrack/ui/LabelGlyphHandle.h @@ -0,0 +1,58 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +LabelGlyphHandle.h + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#ifndef __AUDACITY_LABEL_GLYPH_HANDLE__ +#define __AUDACITY_LABEL_GLYPH_HANDLE__ + +#include "../../../UIHandle.h" +#include + +class wxMouseEvent; +struct HitTestResult; +class LabelTrack; + +class LabelGlyphHandle final : public UIHandle +{ + LabelGlyphHandle(); + LabelGlyphHandle(const LabelGlyphHandle&) = delete; + LabelGlyphHandle &operator=(const LabelGlyphHandle&) = delete; + static LabelGlyphHandle& Instance(); + static HitTestPreview HitPreview(bool hitCenter, unsigned refreshResult); + +public: + static HitTestResult HitTest + (const wxMouseEvent &event, LabelTrack *pLT); + + virtual ~LabelGlyphHandle(); + + 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; + + bool StopsOnKeystroke() override { return true; } + +private: + LabelTrack *mpLT {}; + wxRect mRect {}; +}; + +#endif diff --git a/src/tracks/labeltrack/ui/LabelTextHandle.cpp b/src/tracks/labeltrack/ui/LabelTextHandle.cpp new file mode 100644 index 000000000..badbfd723 --- /dev/null +++ b/src/tracks/labeltrack/ui/LabelTextHandle.cpp @@ -0,0 +1,184 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +LabelTextHandle.cpp + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#include "../../../Audacity.h" +#include "LabelTextHandle.h" +#include "../../../HitTestResult.h" +#include "../../../LabelTrack.h" +#include "../../../Project.h" +#include "../../../RefreshCode.h" +#include "../../../TrackPanelMouseEvent.h" +#include "../../../ViewInfo.h" + +LabelTextHandle::LabelTextHandle() +{ +} + +LabelTextHandle &LabelTextHandle::Instance() +{ + static LabelTextHandle instance; + return instance; +} + +HitTestResult LabelTextHandle::HitTest(const wxMouseEvent &event, LabelTrack *pLT) +{ + // If Control is down, let the select handle be hit instead + if (!event.ControlDown() && + pLT->OverATextBox(event.m_x, event.m_y) >= 0) + // There was no cursor change or status message for mousing over a label text box + return { {}, &Instance() }; + + return {}; +} + +LabelTextHandle::~LabelTextHandle() +{ +} + +UIHandle::Result LabelTextHandle::Click +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + auto &selectionState = pProject->GetSelectionState(); + TrackList *const tracks = pProject->GetTracks(); + mChanger = + std::make_unique< SelectionStateChanger >( selectionState, *tracks ); + + TrackPanelCell *const pCell = evt.pCell; + const wxMouseEvent &event = evt.event; + ViewInfo &viewInfo = pProject->GetViewInfo(); + + mpLT = static_cast(pCell); + mSelectedRegion = viewInfo.selectedRegion; + mpLT->HandleTextClick( event, evt.rect, viewInfo, &viewInfo.selectedRegion ); + wxASSERT(mpLT->IsSelected()); + + { + // IF the user clicked a label, THEN select all other tracks by Label + + TrackListIterator iter(tracks); + Track *t = iter.First(); + + //do nothing if at least one other track is selected + bool done = false; + while (!done && t) { + if (t->GetSelected() && t != mpLT) + done = true; + t = iter.Next(); + } + + if (!done) { + //otherwise, select all tracks + t = iter.First(); + while (t) + { + selectionState.SelectTrack + ( *pProject->GetTracks(), *t, true, true, + pProject->GetMixerBoard() ); + t = iter.Next(); + } + } + + // Do this after, for its effect on TrackPanel's memory of last selected + // track (which affects shift-click actions) + selectionState.SelectTrack + ( *pProject->GetTracks(), *mpLT, true, true, + pProject->GetMixerBoard() ); + } + + // PRL: bug1659 -- make selection change undo correctly + const bool unsafe = pProject->IsAudioActive(); + if (!unsafe) + pProject->ModifyState(false); + + return RefreshCode::RefreshCell | RefreshCode::UpdateSelection; +} + +UIHandle::Result LabelTextHandle::Drag +(const TrackPanelMouseEvent &evt, AudacityProject *pProject) +{ + using namespace RefreshCode; + Result result = RefreshNone; + + const wxMouseEvent &event = evt.event; + if(mpLT) + mpLT->HandleTextDragRelease(event); + + // locate the initial mouse position + if (event.LeftIsDown()) { + if (mLabelTrackStartXPos == -1) { + mLabelTrackStartXPos = event.m_x; + mLabelTrackStartYPos = event.m_y; + + if (mpLT && + (mpLT->getSelectedIndex() != -1) && + mpLT->OverTextBox( + mpLT->GetLabel(mpLT->getSelectedIndex()), + mLabelTrackStartXPos, + mLabelTrackStartYPos)) + mLabelTrackStartYPos = -1; + } + // if initial mouse position in the text box + // then only drag text + if (mLabelTrackStartYPos == -1) + result |= RefreshCell; + } + + return result; +} + +HitTestPreview LabelTextHandle::Preview +(const TrackPanelMouseEvent &evt, const AudacityProject *pProject) +{ + return {}; +} + +UIHandle::Result LabelTextHandle::Release +(const TrackPanelMouseEvent &evt, AudacityProject *pProject, + wxWindow *pParent) +{ + // Only selected a part of a text string and changed track selectedness. + // No undoable effects. + + if (mChanger) { + mChanger->Commit(); + mChanger.release(); + } + + const wxMouseEvent &event = evt.event; + if (mpLT) + mpLT->HandleTextDragRelease(event); + + // handle mouse left button up + if (event.LeftUp()) + mLabelTrackStartXPos = -1; + + return RefreshCode::RefreshNone; +} + +UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject ) +{ + // Restore the selection states of tracks + // Note that we are also relying on LabelDefaultClickHandle::Cancel + // to restore the selection state of the labels in the tracks. + mChanger.release(); + ViewInfo &viewInfo = pProject->GetViewInfo(); + viewInfo.selectedRegion = mSelectedRegion; + return RefreshCode::RefreshAll; +} + +void LabelTextHandle::OnProjectChange(AudacityProject *pProject) +{ + if (! pProject->GetTracks()->Contains(mpLT)) { + mpLT = nullptr; + mRect = {}; + } + + UIHandle::OnProjectChange(pProject); +} diff --git a/src/tracks/labeltrack/ui/LabelTextHandle.h b/src/tracks/labeltrack/ui/LabelTextHandle.h new file mode 100644 index 000000000..53bf990a0 --- /dev/null +++ b/src/tracks/labeltrack/ui/LabelTextHandle.h @@ -0,0 +1,63 @@ +/********************************************************************** + +Audacity: A Digital Audio Editor + +LabelTextHandle.h + +Paul Licameli split from TrackPanel.cpp + +**********************************************************************/ + +#ifndef __AUDACITY_LABEL_TEXT_HANDLE__ +#define __AUDACITY_LABEL_TEXT_HANDLE__ + +#include "../../../UIHandle.h" +#include "../../../MemoryX.h" +#include "../../../SelectedRegion.h" +#include + +class wxMouseEvent; +struct HitTestResult; +class LabelTrack; +class SelectionStateChanger; + +class LabelTextHandle final : public UIHandle +{ + LabelTextHandle(); + LabelTextHandle(const LabelTextHandle&) = delete; + LabelTextHandle &operator=(const LabelTextHandle&) = delete; + static LabelTextHandle& Instance(); + +public: + static HitTestResult HitTest(const wxMouseEvent &event, LabelTrack *pLT); + + virtual ~LabelTextHandle(); + + 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: + LabelTrack *mpLT {}; + wxRect mRect {}; + int mLabelTrackStartXPos { -1 }; + int mLabelTrackStartYPos { -1 }; + SelectedRegion mSelectedRegion{}; + std::unique_ptr mChanger; +}; + +#endif diff --git a/src/tracks/labeltrack/ui/LabelTrackUI.cpp b/src/tracks/labeltrack/ui/LabelTrackUI.cpp index 63fe1ea4d..abf39aac4 100644 --- a/src/tracks/labeltrack/ui/LabelTrackUI.cpp +++ b/src/tracks/labeltrack/ui/LabelTrackUI.cpp @@ -10,15 +10,51 @@ Paul Licameli split from TrackPanel.cpp #include "../../../LabelTrack.h" #include "LabelTrackControls.h" +#include "LabelDefaultClickHandle.h" #include "LabelTrackVRulerControls.h" +#include "LabelGlyphHandle.h" +#include "LabelTextHandle.h" #include "../../../HitTestResult.h" +#include "../../../TrackPanelMouseEvent.h" HitTestResult LabelTrack::HitTest -(const TrackPanelMouseEvent &event, +(const TrackPanelMouseEvent &evt, const AudacityProject *pProject) { - return Track::HitTest(event, pProject); + // PRL: Maybe I did too much work to preserve old behavior, but anyway, + // this unusually combines parts of two or more hit test results. + + HitTestResult result; + const wxMouseEvent &event = evt.event; + + // Try label movement handles first + result = LabelGlyphHandle::HitTest(event, this); + // Hit test may request refresh even if a miss + auto refreshResult = result.preview.refreshCode; + + if ( !result.handle ) { + // Missed glyph, try text box + // This hit test does not define its own messages or cursor + HitTestResult defaultResult = Track::HitTest(evt, pProject); + result = LabelTextHandle::HitTest(event, this); + if (result.handle) + // Use any cursor or status message change from catchall, + // But let the text ui handle pass + result.preview = defaultResult.preview; + else + result = defaultResult; + } + + // Now attach some common extra work to the click action + LabelDefaultClickHandle::Instance().mpForward = result.handle; + result.handle = &LabelDefaultClickHandle::Instance(); + + // Don't lose the refresh result side effect of the glyph + // hit test + result.preview.refreshCode |= refreshResult; + + return result; } TrackControls *LabelTrack::GetControls() diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index b465e2e73..6df39ea4d 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -225,6 +225,9 @@ + + + @@ -509,6 +512,9 @@ + + + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index c69fa769f..92b356aab 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -1031,6 +1031,15 @@ src + + src\tracks\labeltrack\ui + + + src\tracks\labeltrack\ui + + + src\tracks\labeltrack\ui + @@ -2053,6 +2062,15 @@ src + + src\tracks\labeltrack\ui + + + src\tracks\labeltrack\ui + + + src\tracks\labeltrack\ui +