From 702d9d75e5a89b09795f93ef2686805da2013a12 Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Fri, 17 Apr 2015 17:52:13 +0100 Subject: [PATCH] Timeline Quick Play bug fixes and enhancements --- src/AudioIO.cpp | 2 +- src/TrackPanel.cpp | 31 +++ src/TrackPanel.h | 5 + src/toolbars/ControlToolBar.cpp | 57 ++--- src/toolbars/ControlToolBar.h | 4 +- src/widgets/Ruler.cpp | 387 ++++++++++++++++++++++++++++---- src/widgets/Ruler.h | 27 ++- 7 files changed, 427 insertions(+), 86 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 8dbede16d..4b1d0e785 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -1554,7 +1554,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks, else mWarpedLength = mT1 - mT0; // PRL allow backwards play - mWarpedLength = abs(mWarpedLength); + mWarpedLength = fabs(mWarpedLength); } // diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 73c26548b..64f79ec1e 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -564,6 +564,7 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, mLastCursor = -1; mLastIndicator = -1; + mOldQPIndicatorPos = -1; // Register for tracklist updates mTracks->Connect(EVT_TRACKLIST_RESIZED, @@ -1119,6 +1120,36 @@ void TrackPanel::DrawIndicator() DoDrawIndicator( dc ); } +void TrackPanel::DrawQuickPlayIndicator(wxDC & dc, double pos) +{ + // Erase the old indicator. + if( mOldQPIndicatorPos != -1 ) { + dc.Blit( mOldQPIndicatorPos, 0, 1, mBacking->GetHeight(), &mBackingDC, mOldQPIndicatorPos, 0 ); + mOldQPIndicatorPos = -1; + } + + if (pos >= 0) { + + (mRuler->mIsSnapped)? AColor::SnapGuidePen( &dc) : AColor::Light( &dc, false); + + // Draw indicator in all visible tracks + VisibleTrackIterator iter( GetProject() ); + for( Track *t = iter.First(); t; t = iter.Next() ) + { + // Convert virtual coordinate to physical + int y = t->GetY() - mViewInfo->vpos; + + // Draw the new indicator in its new location + AColor::Line(dc, + pos, + y + kTopInset + 1, + pos, + y + t->GetHeight() - 3 ); + } + mOldQPIndicatorPos = pos; + } +} + /// Second level DrawIndicator() void TrackPanel::DoDrawIndicator(wxDC & dc, bool repairOld /* = false */) { diff --git a/src/TrackPanel.h b/src/TrackPanel.h index e21c38e0a..f8edede0b 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -253,6 +253,8 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel { virtual void UpdateTrackVRuler(Track *t); virtual void UpdateVRulerSize(); + virtual void DrawQuickPlayIndicator(wxDC & dc, double pos); + protected: virtual MixerBoard* GetMixerBoard(); /** @brief Populates the track pop-down menu with the common set of @@ -561,6 +563,9 @@ protected: double mLastIndicator; double mLastCursor; + // Quick Play indicator postion + double mOldQPIndicatorPos; + int mTimeCount; wxMemoryDC mBackingDC; diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index ec11310e9..55a0b2621 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -422,7 +422,6 @@ void ControlToolBar::EnableDisableButtons() void ControlToolBar::SetPlay(bool down, bool looped, bool cutPreview) { - AudacityProject *p = GetActiveProject(); if (down) { mPlay->SetShift(looped); mPlay->SetControl(cutPreview); @@ -471,7 +470,8 @@ bool ControlToolBar::IsRecordDown() int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, bool cutpreview, /* = false */ - bool backwards /* = false */) + bool backwards, /* = false */ + bool playWhiteSpace /* = false */) { // Uncomment this for laughs! // backwards = true; @@ -522,23 +522,32 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, } } + double latestEnd = (playWhiteSpace)? t1 : t->GetEndTime(); + if (!hasaudio) { SetPlay(false); return -1; // No need to continue without audio tracks } - double maxofmins,minofmaxs; #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) double init_seek = 0.0; #endif - // JS: clarified how the final play region is computed; if (t1 == t0) { - // msmeyer: When playing looped, we play the whole file, if - // no range is selected. Otherwise, we play from t0 to end if (looped) { - // msmeyer: always play from start - t0 = t->GetStartTime(); + // play selection if there is one, otherwise + // set start of play region to project start, + // and loop the project from current play position. + + if ((t0 > p->GetSel0()) && (t0 < p->GetSel1())) { + t0 = p->GetSel0(); + t1 = p->GetSel1(); + } + else { + // loop the entire project + t0 = t->GetStartTime(); + t1 = t->GetEndTime(); + } } else { // move t0 to valid range if (t0 < 0) { @@ -554,8 +563,6 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, } #endif } - - // always play to end t1 = t->GetEndTime(); } else { @@ -563,39 +570,13 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, if (backwards) std::swap(t0, t1); - // the set intersection between the play region and the - // valid range maximum of lower bounds - if (t0 < t->GetStartTime()) - maxofmins = t->GetStartTime(); - else - maxofmins = t0; - - // minimum of upper bounds - if (t1 > t->GetEndTime()) - minofmaxs = t->GetEndTime(); - else - minofmaxs = t1; - - // we test if the intersection has no volume - if (minofmaxs <= maxofmins) { - // no volume; play nothing - return -1; - } - else { - t0 = maxofmins; - t1 = minofmaxs; - } + t0 = wxMax(t0, 0.0); + t1 = wxMin(t1, latestEnd); if (backwards) std::swap(t0, t1); } - // Can't play before 0...either shifted or latency corrected tracks - if (t0 < 0.0) - t0 = 0.0; - if (t1 < 0.0) - t1 = 0.0; - int token = -1; bool success = false; if (t1 != t0) { diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index 847752cf1..d4706df74 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -70,7 +70,9 @@ class ControlToolBar:public ToolBar { // Return the Audio IO token or -1 for failure int PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, - bool cutpreview = false, bool backwards = false); + bool cutpreview = false, bool backwards = false, + // Allow t0 and t1 to be beyond end of tracks + bool playWhiteSpace = false); void PlayDefault(); // Stop playing diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index d5cd00b6e..10b928ac3 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -61,6 +61,9 @@ array of Ruler::Label. #include #include #include +#include +#include +#include #include "../AudioIO.h" #include "../Internat.h" @@ -71,17 +74,22 @@ array of Ruler::Label. #include "../AllThemeResources.h" #include "../Experimental.h" #include "../TimeTrack.h" -#include +#include "../TrackPanel.h" +#include "../Menus.h" +#include "../Prefs.h" #define max(a,b) ( (aDrawLine(mLeft, mTop, mLeft, mBottom+1); else { - // These calculations tappear to be wrong, and to never have been used (so not tested) prior to MixerBoard. + // These calculations appear to be wrong, and to never have been used (so not tested) prior to MixerBoard. // mDC->DrawLine(mRect.x-mRect.width, mTop, mRect.x-mRect.width, mBottom+1); const int nLineX = mRight - 1; mDC->DrawLine(nLineX, mTop, nLineX, mBottom+1); @@ -1591,12 +1599,23 @@ void RulerPanel::DoSetSize(int x, int y, #include "../ViewInfo.h" #include "../AColor.h" +enum { + OnSyncQuickPlaySelID = 7000, + OnTimelineToolTipID, + OnAutoScrollID, + OnLockPlayRegionID +}; + BEGIN_EVENT_TABLE(AdornedRulerPanel, wxPanel) EVT_ERASE_BACKGROUND(AdornedRulerPanel::OnErase) EVT_PAINT(AdornedRulerPanel::OnPaint) EVT_SIZE(AdornedRulerPanel::OnSize) EVT_MOUSE_EVENTS(AdornedRulerPanel::OnMouseEvents) EVT_MOUSE_CAPTURE_LOST(AdornedRulerPanel::OnCaptureLost) + EVT_MENU(OnSyncQuickPlaySelID, AdornedRulerPanel::OnSyncSelToQuickPlay) + EVT_MENU(OnTimelineToolTipID, AdornedRulerPanel::OnTimelineToolTips) + EVT_MENU(OnAutoScrollID, AdornedRulerPanel::OnAutoScroll) + EVT_MENU(OnLockPlayRegionID, AdornedRulerPanel::OnLockPlayRegion) END_EVENT_TABLE() AdornedRulerPanel::AdornedRulerPanel(wxWindow* parent, @@ -1613,8 +1632,12 @@ AdornedRulerPanel::AdornedRulerPanel(wxWindow* parent, mCurPos = -1; mIndPos = -1; mIndType = -1; + mQuickPlayInd = false; mPlayRegionStart = -1; + mPlayRegionLock = false; mPlayRegionEnd = -1; + mOldPlayRegionStart = -1; + mOldPlayRegionEnd = -1; mMouseEventState = mesNone; mBuffer = new wxBitmap( 1, 1 ); @@ -1635,8 +1658,14 @@ AdornedRulerPanel::AdornedRulerPanel(wxWindow* parent, ruler.SetLabelEdges( false ); ruler.SetFormat( Ruler::TimeFormat ); + mSnapManager = NULL; + mIsSnapped = false; + mIsRecording = false; + mTimelineToolTip = gPrefs->Read(wxT("/QuickPlay/ToolTips"), wxT("Enabled")) == wxT("Enabled"); + mPlayRegionDragsSelection = gPrefs->Read(wxT("/QuickPlay/DragLoopSelection"), wxT("Enabled")) == wxT("Enabled"); + #if wxUSE_TOOLTIPS RegenerateTooltips(); wxToolTip::Enable(true); @@ -1655,15 +1684,25 @@ AdornedRulerPanel::~AdornedRulerPanel() NULL, this); delete mBuffer; + + if (mSnapManager) + delete mSnapManager; } void AdornedRulerPanel::RegenerateTooltips() { #if wxUSE_TOOLTIPS - if (mIsRecording) - this->SetToolTip(_("Timeline actions disabled during recording")); - else - this->SetToolTip(_("Timeline - Quick Play enabled")); + if (mTimelineToolTip) { + if (mIsRecording) { + this->SetToolTip(_("Timeline actions disabled during recording")); + } + else { + this->SetToolTip(_("Timeline - Quick Play enabled")); + } + } + else { + this->SetToolTip(NULL); + } #endif } @@ -1710,6 +1749,11 @@ void AdornedRulerPanel::OnPaint(wxPaintEvent & WXUNUSED(evt)) DoDrawIndicator(&dc); } + if (mQuickPlayInd) + { + DrawQuickPlayIndicator(&dc, false); + } + DoDrawMarks(&dc, true); if (mViewInfo->selectedRegion.isPoint()) @@ -1752,9 +1796,15 @@ double AdornedRulerPanel::Pos2Time(int p) int AdornedRulerPanel::Time2Pos(double t) { - return mLeftOffset + (int)((t-mViewInfo->h) * mViewInfo->zoom + 0.5); + return mLeftOffset + Seconds2Pixels(t-mViewInfo->h); } +int AdornedRulerPanel::Seconds2Pixels(double t) +{ + return (int)(t * mViewInfo->zoom + 0.5); +} + + bool AdornedRulerPanel::IsWithinMarker(int mousePosX, double markerTime) { if (markerTime < 0) @@ -1773,42 +1823,86 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt) if (mIsRecording) return; + bool isLocked = mProject->IsPlayRegionLocked(); + + if (isLocked && evt.LeftDown()) { + mPlayRegionLock = true; + mOldPlayRegionStart = mPlayRegionStart; + mOldPlayRegionEnd = mPlayRegionEnd; + mProject->OnUnlockPlayRegion(); + } + + bool isWithinStart = IsWithinMarker(evt.GetX(), mPlayRegionStart); bool isWithinEnd = IsWithinMarker(evt.GetX(), mPlayRegionEnd); + bool canDragLoopSel = !mPlayRegionLock && mPlayRegionDragsSelection; mLastMouseX = evt.GetX(); - if (evt.Leaving()) - { + mQuickPlayPos = Pos2Time(evt.GetX()); + + double t0 = mProject->GetTracks()->GetStartTime(); + double t1 = mProject->GetTracks()->GetEndTime(); + double sel0 = mProject->GetSel0(); + double sel1 = mProject->GetSel1(); + + // Restrict Quick Play region to where there is something to play or is selected. + mQuickPlayPos = wxMax(0.0, mQuickPlayPos); + + // If not looping, restrict selection to end of project + if (!evt.ShiftDown()) mQuickPlayPos = wxMin(t1, mQuickPlayPos); + + + if (evt.Leaving()) { #if defined(__WXMAC__) // We must install the cursor ourselves since the window under // the mouse is no longer this one and wx2.8.12 makes that check. // Should re-evaluate with wx3. wxSTANDARD_CURSOR->MacInstall(); #endif - } - else if (isWithinStart || isWithinEnd) - SetCursor(wxCursor(wxCURSOR_SIZEWE)); - else - SetCursor(wxCursor(wxCURSOR_HAND)); - double mouseTime = Pos2Time(evt.GetX()); - if (mouseTime < 0.0) { - mouseTime = 0.0; + mQuickPlayInd = false; + wxClientDC cdc(this); + DrawQuickPlayIndicator(&cdc, true); + + + Refresh(false); } + else { + mQuickPlayInd = true; + Refresh(false); + + if (isWithinStart || isWithinEnd) { + SetCursor(wxCursor(wxCURSOR_SIZEWE)); + } + else { + SetCursor(wxCursor(wxCURSOR_HAND)); + } + } + + if (mSnapManager) { + // Create a new snap manager in case any snap-points have changed + delete mSnapManager; + } + mSnapManager = new SnapManager(mProject->GetTracks(), NULL, + mViewInfo->zoom, + QUICK_PLAY_SNAP_PIXEL); + bool snappedPoint, snappedTime; + mIsSnapped = (mSnapManager->Snap(NULL, mQuickPlayPos, false, + &mQuickPlayPos, &snappedPoint, &snappedTime)); if (evt.LeftDown()) { mButtonDownMousePos = evt.GetX(); - if (isWithinStart && isWithinEnd) - { + if (isWithinStart && isWithinEnd) { // Both could be selected, check which marker is nearer - if (fabs(mouseTime-mPlayRegionStart) < fabs(mouseTime-mPlayRegionEnd)) + if (fabs(mQuickPlayPos - mPlayRegionStart) < fabs(mQuickPlayPos - mPlayRegionEnd)) mMouseEventState = mesDraggingPlayRegionStart; else mMouseEventState = mesDraggingPlayRegionEnd; - } else if (isWithinStart) + } + else if (isWithinStart) mMouseEventState = mesDraggingPlayRegionStart; else if (isWithinEnd) mMouseEventState = mesDraggingPlayRegionEnd; @@ -1816,25 +1910,35 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt) // First, we enter "click" mode to avoid selecting a small range // accidentially mMouseEventState = mesSelectingPlayRegionClick; - mPlayRegionStart = mouseTime; - mPlayRegionEnd = mouseTime; + mPlayRegionStart = mQuickPlayPos; + mPlayRegionEnd = mQuickPlayPos; Refresh(); } - CaptureMouse(); } + if (evt.RightDown()) + { + ShowMenu(evt.GetPosition()); + } + switch (mMouseEventState) { case mesNone: // do nothing break; case mesDraggingPlayRegionStart: - mPlayRegionStart = mouseTime; + mPlayRegionStart = mQuickPlayPos; + if (canDragLoopSel) { + DragLoopSelection(); + } Refresh(); break; case mesDraggingPlayRegionEnd: - mPlayRegionEnd = mouseTime; + mPlayRegionEnd = mQuickPlayPos; + if (canDragLoopSel) { + DragLoopSelection(); + } Refresh(); break; case mesSelectingPlayRegionClick: @@ -1843,58 +1947,219 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt) // User moved mouse at least SELECT_TOLERANCE_PIXEL, so change // from "click" mode to "range" mode to allow selecting a range mMouseEventState = mesSelectingPlayRegionRange; - mPlayRegionEnd = mouseTime; + mPlayRegionEnd = mQuickPlayPos; Refresh(); } break; case mesSelectingPlayRegionRange: - mPlayRegionEnd = mouseTime; + mPlayRegionEnd = mQuickPlayPos; Refresh(); break; } if (evt.LeftUp()) { + mQuickPlayInd = false; + wxClientDC cdc(this); + DrawQuickPlayIndicator(&cdc, true); + if (HasCapture()) ReleaseMouse(); - if (mPlayRegionStart < 0 && mPlayRegionEnd >= 0) - { - // This makes no sense, remove play region - mPlayRegionStart = -1; - mPlayRegionEnd = -1; + int playlength = Seconds2Pixels(fabs(mPlayRegionEnd - mPlayRegionStart)); + if (playlength < SELECT_TOLERANCE_PIXEL) { + // Mouse has slipped back within tolerance range. + // We have been dragging mPlayRegionEnd, so snap it back to mPlayRegionStart. + mPlayRegionEnd = mPlayRegionStart; } - - if (mPlayRegionEnd < mPlayRegionStart) - { - // Swap values to make sure mPlayRegionStart > mPlayRegionEnd + else if (mPlayRegionEnd < mPlayRegionStart) { + // Swap values to ensure mPlayRegionStart < mPlayRegionEnd double tmp = mPlayRegionStart; mPlayRegionStart = mPlayRegionEnd; mPlayRegionEnd = tmp; } - bool startPlaying = mPlayRegionStart >= 0 && - (mMouseEventState == mesSelectingPlayRegionClick || - mMouseEventState == mesSelectingPlayRegionRange); + // We want some audio in the selection, but we allow a dragged + // region to include selected white-space and space before audio start. + if (evt.ShiftDown() && (mPlayRegionStart == mPlayRegionEnd)) { + // Looping the selection or project. + // Disable if track selection is in white-space beyond end of tracks and + // play position is outside of track contents. + if (((sel1 < t0) || (sel0 > t1)) && + ((mPlayRegionStart < t0) || (mPlayRegionStart > t1))) { + ClearPlayRegion(); + } + } + // Disable if beyond end. + else if (mPlayRegionStart >= t1) { + ClearPlayRegion(); + } + // Disable if empty selection before start. + // (allow Quick Play region to include 'pre-roll' white space) + else if (((mPlayRegionEnd - mPlayRegionStart) > 0.0) && (mPlayRegionEnd < t0)) { + ClearPlayRegion(); + } + + // Start / Restart playback on left click. + bool startPlaying = (mPlayRegionStart >= 0); mMouseEventState = mesNone; - if (startPlaying) - { + if (startPlaying) { ControlToolBar* ctb = mProject->GetControlToolBar(); ctb->StopPlaying(); - ctb->PlayCurrentRegion(evt.ShiftDown(), evt.ControlDown() ); + + bool loopEnabled = true; + double start, end; + + if ((mPlayRegionEnd - mPlayRegionStart == 0.0) && evt.ShiftDown()) { + // Loop play a point will loop either a selection or the project. + if ((mPlayRegionStart > sel0) && (mPlayRegionStart < sel1)) { + // we are in a selection, so use the selection + start = sel0; + end = sel1; + } // not in a selection, so use the project + else { + start = t0; + end = t1; + } + } + else { + start = mPlayRegionStart; + end = mPlayRegionEnd; + } + // Looping a tiny selection may freeze, so just play it once. + loopEnabled = ((end - start) > 0.001)? true : false; + + AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions()); + options.playLooped = (loopEnabled && evt.ShiftDown()); + + ctb->PlayPlayRegion((SelectedRegion(mPlayRegionStart, mPlayRegionEnd)), + options, + evt.ControlDown(), + false, + true); + + mPlayRegionStart = start; + mPlayRegionEnd = end; + DoDrawPlayRegion(&cdc); + } + + if (mPlayRegionLock) { + // Restore Locked Play region + SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd); + mProject->OnLockPlayRegion(); + // and release local lock + mPlayRegionLock = false; } } } void AdornedRulerPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(evt)) { + wxClientDC cdc(this); + DrawQuickPlayIndicator(&cdc, true); + wxMouseEvent e(wxEVT_LEFT_UP); e.m_x = mLastMouseX; OnMouseEvents(e); } + +// Pop-up menu + +void AdornedRulerPanel::ShowMenu(const wxPoint & pos) +{ + wxMenu *rulerMenu = new wxMenu(); + + wxMenuItem *dragitem; + if (mPlayRegionDragsSelection && !mProject->IsPlayRegionLocked()) + dragitem = rulerMenu->Append(OnSyncQuickPlaySelID, _("Disable dragging selection")); + else + dragitem = rulerMenu->Append(OnSyncQuickPlaySelID, _("Enable dragging selection")); + dragitem->Enable(!mProject->IsPlayRegionLocked()); + +#if wxUSE_TOOLTIPS + if (mTimelineToolTip) + rulerMenu->Append(OnTimelineToolTipID, _("Disable Timeline Tooltips")); + else + rulerMenu->Append(OnTimelineToolTipID, _("Enable Timeline Tooltips")); +#endif + + if (mViewInfo->bUpdateTrackIndicator) + rulerMenu->Append(OnAutoScrollID, _("Do not scroll while playing")); + else + rulerMenu->Append(OnAutoScrollID, _("Update display while playing")); + + wxMenuItem *prlitem; + if (!mProject->IsPlayRegionLocked()) + prlitem = rulerMenu->Append(OnLockPlayRegionID, _("Lock Play Region")); + else + prlitem = rulerMenu->Append(OnLockPlayRegionID, _("Unlock Play Region")); + prlitem->Enable(mProject->GetSel0() != mProject->GetSel1()); + + PopupMenu(rulerMenu, pos); + + delete rulerMenu; + // dismiss and clear Quick Play indicator + mQuickPlayInd = false; + wxClientDC cdc(this); + DrawQuickPlayIndicator(&cdc, true); +} + +void AdornedRulerPanel::OnSyncSelToQuickPlay(wxCommandEvent& evt) +{ + mPlayRegionDragsSelection = (mPlayRegionDragsSelection)? false : true; + gPrefs->Write(wxT("/QuickPlay/DragLoopSelection"), mPlayRegionDragsSelection ? wxT("Enabled") : wxT("Disabled")); + gPrefs->Flush(); +} + +void AdornedRulerPanel::DragLoopSelection() +{ + if (mPlayRegionStart < mPlayRegionEnd) { + mProject->SetSel0(mPlayRegionStart); + mProject->SetSel1(mPlayRegionEnd); + } + else { + mProject->SetSel0(mPlayRegionEnd); + mProject->SetSel1(mPlayRegionStart); + } + mProject->GetTrackPanel()->TrackPanel::DisplaySelection(); + mProject->GetTrackPanel()->TrackPanel::Refresh(false); +} + +void AdornedRulerPanel::OnTimelineToolTips(wxCommandEvent& evt) +{ + mTimelineToolTip = (mTimelineToolTip)? false : true; + gPrefs->Write(wxT("/QuickPlay/ToolTips"), mTimelineToolTip ? wxT("Enabled") : wxT("Disabled")); + gPrefs->Flush(); +#if wxUSE_TOOLTIPS + RegenerateTooltips(); +#endif +} + + +void AdornedRulerPanel::OnAutoScroll(wxCommandEvent& evt) +{ + if (mViewInfo->bUpdateTrackIndicator) + gPrefs->Write(wxT("/GUI/AutoScroll"), false); + else + gPrefs->Write(wxT("/GUI/AutoScroll"), true); + mProject->UpdatePrefs(); + gPrefs->Flush(); +} + + +void AdornedRulerPanel::OnLockPlayRegion(wxCommandEvent& evt) +{ + if (mProject->IsPlayRegionLocked()) + mProject->OnUnlockPlayRegion(); + else + mProject->OnLockPlayRegion(); +} + + +// Draws the horizontal <===> void AdornedRulerPanel::DoDrawPlayRegion(wxDC * dc) { double start, end; @@ -2056,8 +2321,7 @@ void AdornedRulerPanel::DrawIndicator( double pos, bool rec ) void AdornedRulerPanel::DoDrawIndicator(wxDC * dc) { - if( mIndType < 0 ) - { + if (mIndType < 0) { return; } @@ -2076,6 +2340,35 @@ void AdornedRulerPanel::DoDrawIndicator(wxDC * dc) dc->DrawPolygon( 3, tri ); } +// Draws the vertical line and green triangle indicating the Qick Play cursor position. +void AdornedRulerPanel::DrawQuickPlayIndicator(wxDC * dc, bool clear) +{ + TrackPanel *tp = mProject->GetTrackPanel(); + wxClientDC cdc(tp); + + double latestEnd = wxMax(mProject->GetTracks()->GetEndTime(), mProject->GetSel1()); + if (clear || (mQuickPlayPos >= latestEnd)) { + tp->TrackPanel::DrawQuickPlayIndicator(cdc, -1); + return; + } + + int indsize = 4; + int x = mLeftOffset + int((mQuickPlayPos - mViewInfo->h) * mViewInfo->zoom); + + wxPoint tri[3]; + tri[0].x = -indsize; + tri[0].y = 1; + tri[1].x = indsize; + tri[1].y = 1; + tri[2].x = 0; + tri[2].y = ( indsize * 3 ) / 2 + 1; + + AColor::IndicatorColor( dc, true); + dc->DrawPolygon( 3, tri, x ); + + tp->TrackPanel::DrawQuickPlayIndicator(cdc, x); +} + void AdornedRulerPanel::SetPlayRegion(double playRegionStart, double playRegionEnd) { @@ -2092,8 +2385,12 @@ void AdornedRulerPanel::SetPlayRegion(double playRegionStart, void AdornedRulerPanel::ClearPlayRegion() { + ControlToolBar* ctb = mProject->GetControlToolBar(); + ctb->StopPlaying(); + mPlayRegionStart = -1; mPlayRegionEnd = -1; + mQuickPlayInd = false; Refresh(); } diff --git a/src/widgets/Ruler.h b/src/widgets/Ruler.h index 49d87e02c..a83dfe92e 100644 --- a/src/widgets/Ruler.h +++ b/src/widgets/Ruler.h @@ -18,6 +18,7 @@ #include #include "../Envelope.h" #include "../Experimental.h" +#include "../Snap.h" struct ViewInfo; class AudacityProject; @@ -270,6 +271,8 @@ public: void RegenerateTooltips(); + bool mIsSnapped; + private: void OnCapture(wxCommandEvent & evt); void OnErase(wxEraseEvent &evt); @@ -283,10 +286,12 @@ private: void DoDrawCursor(wxDC * dc); void DoDrawSelection(wxDC * dc); void DoDrawIndicator(wxDC * dc); + void DrawQuickPlayIndicator(wxDC * dc, bool clear /*delete old only*/); void DoDrawPlayRegion(wxDC * dc); double Pos2Time(int p); int Time2Pos(double t); + int Seconds2Pixels(double t); bool IsWithinMarker(int mousePosX, double markerTime); @@ -303,14 +308,34 @@ private: double mCurPos; - int mIndType; // -1 = No indicator, 0 = Play, 1 = Record + int mIndType; // -1 = No indicator, 0 = Play, 1 = Record double mIndPos; + bool mQuickPlayInd; + double mQuickPlayPos; + SnapManager *mSnapManager; + bool mPlayRegionLock; double mPlayRegionStart; double mPlayRegionEnd; + double mOldPlayRegionStart; + double mOldPlayRegionEnd; bool mIsRecording; + // + // Pop-up menu + // + void ShowMenu(const wxPoint & pos); + void DragLoopSelection(); + void OnSyncSelToQuickPlay(wxCommandEvent &evt); + void OnTimelineToolTips(wxCommandEvent &evt); + void OnAutoScroll(wxCommandEvent &evt); + void OnLockPlayRegion(wxCommandEvent &evt); + + bool mPlayRegionDragsSelection; + bool mTimelineToolTip; + + enum MouseEventState { mesNone, mesDraggingPlayRegionStart,