From 8a0c34e96be0c805e38e6b9221c17b4acbd1fd29 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 17 Jun 2016 10:06:16 -0400 Subject: [PATCH 1/2] Eliminate the special case of dragging scrub/seek --- src/tracks/ui/Scrubbing.cpp | 47 +++++++++++++++++++++++++++---------- src/tracks/ui/Scrubbing.h | 1 + src/widgets/Ruler.cpp | 8 +++++++ 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index 08b419c50..19d31fa65 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -35,6 +35,10 @@ Paul Licameli split from TrackPanel.cpp #include +// Yet another experimental scrub would drag the track under a +// stationary play head +#undef DRAG_SCRUB + enum { // PRL: // Mouse must move at least this far to distinguish ctrl-drag to scrub @@ -328,6 +332,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) mScrubStartPosition = position; } +#ifdef DRAG_SCRUB if (mDragging && mSmoothScrollingScrub) { auto delta = time0 - time1; time0 = std::max(0.0, std::min(maxTime, @@ -335,6 +340,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) )); time1 = time0 + delta; } +#endif AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions()); options.pScrubbingOptions = &mOptions; @@ -351,13 +357,21 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) #else // That idea seems unpopular... just make it one for move-scrub, // but big for drag-scrub +#ifdef DRAG_SCRUB mMaxSpeed = mOptions.maxSpeed = mDragging ? MaxDragSpeed : 1.0; +#else + mMaxSpeed = mOptions.maxSpeed = 1.0; +#endif + #endif mOptions.minSample = 0; mOptions.maxSample = lrint(std::max(0.0, mProject->GetTracks()->GetEndTime()) * options.rate); mOptions.minStutter = - mDragging ? 0.0 : lrint(std::max(0.0, MinStutter) * options.rate); +#ifdef DRAG_SCRUB + mDragging ? 0.0 : +#endif + lrint(std::max(0.0, MinStutter) * options.rate); ControlToolBar::PlayAppearance appearance = mSeeking ? ControlToolBar::PlayAppearance::Seek @@ -425,6 +439,7 @@ void Scrubber::ContinueScrubbingPoll() const auto trackPanel = mProject->GetTrackPanel(); const wxPoint position = trackPanel->ScreenToClient(state.GetPosition()); const auto &viewInfo = mProject->GetViewInfo(); +#ifdef DRAG_SCRUB if (mDragging && mSmoothScrollingScrub) { const auto lastTime = gAudioIO->GetLastTimeInScrubQueue(); const auto delta = mLastScrubPosition - position.x; @@ -436,11 +451,13 @@ void Scrubber::ContinueScrubbingPoll() result = gAudioIO->EnqueueScrub(time, mOptions); mLastScrubPosition = position.x; } - else { + else +#endif + { const double time = viewInfo.PositionToTime(position.x, trackPanel->GetLeftOffset()); mOptions.adjustStart = seek; - mOptions.minSpeed = (mDragging || !seek) ? 0.0 : 1.0; - mOptions.maxSpeed = (mDragging || !seek) ? mMaxSpeed : 1.0; + mOptions.minSpeed = seek ? 1.0 : 0.0; + mOptions.maxSpeed = seek ? 1.0 : mMaxSpeed; if (mSmoothScrollingScrub) { const double speed = FindScrubSpeed(seek, time); @@ -460,6 +477,7 @@ void Scrubber::ContinueScrubbingUI() const wxMouseState state(::wxGetMouseState()); if (mDragging && !state.LeftIsDown()) { + // Dragging scrub can stop with mouse up // Stop and set cursor mProject->DoPlayStopSelect(true, state.ShiftDown()); wxCommandEvent evt; @@ -541,21 +559,28 @@ bool Scrubber::IsScrubbing() const } } +bool Scrubber::ChoseSeeking() const +{ + return +#if !defined(DRAG_SCRUB) + // Drag always seeks + mDragging || +#endif + mSeeking; +} + bool Scrubber::Seeks() const { - return (HasStartedScrubbing() || IsScrubbing()) && mSeeking; + return (HasStartedScrubbing() || IsScrubbing()) && ChoseSeeking(); } bool Scrubber::Scrubs() const { - return (HasStartedScrubbing() || IsScrubbing()) && !mSeeking; + return (HasStartedScrubbing() || IsScrubbing()) && !ChoseSeeking(); } bool Scrubber::ShouldDrawScrubSpeed() { - if (mDragging) - return false; - return IsScrubbing() && !mPaused && ( // Draw for (non-scroll) scrub, sometimes, but never for seek @@ -575,10 +600,6 @@ double Scrubber::FindScrubSpeed(bool seeking, double time) const void Scrubber::HandleScrollWheel(int steps) { - if (mDragging) - // Not likely you would spin it with the left button down, but... - return; - if (steps == 0) return; diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 760847837..256ee321e 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -97,6 +97,7 @@ public: void SetScrollScrubbing(bool value) { mSmoothScrollingScrub = value; } + bool ChoseSeeking() const; bool Seeks() const; bool Scrubs() const; bool ShowsBar() const; diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index ca334a299..cea6653e0 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -2112,10 +2112,14 @@ namespace { "Scrubbing" is variable-speed playback, ... "Seeking" is normal speed playback but with skips */ +#if 0 if(scrubber.Seeks()) return _("Click or drag to begin seeking"); else return _("Click or drag to begin scrubbing"); +#else + return _("Click to scrub, drag to seek"); +#endif } const wxString ContinueScrubbingMessage(const Scrubber &scrubber) @@ -2124,10 +2128,14 @@ namespace { "Scrubbing" is variable-speed playback, ... "Seeking" is normal speed playback but with skips */ +#if 0 if(scrubber.Seeks()) return _("Move to seek"); else return _("Move to scrub"); +#else + return _("Move to scrub, drag to seek"); +#endif } const wxString ScrubbingMessage(const Scrubber &scrubber) From 4fb51cad079b3d671dab73cc09224a6264f1747b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 16 Jun 2016 23:44:00 -0400 Subject: [PATCH 2/2] Click to switch to seek works again, but only in ruler or track panel --- src/tracks/ui/Scrubbing.cpp | 65 +++++++++++++++++++++++++++++-------- src/tracks/ui/Scrubbing.h | 7 ++-- src/widgets/Ruler.cpp | 5 +-- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index 19d31fa65..a16e38e21 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -263,7 +263,7 @@ namespace { void Scrubber::MarkScrubStart( // Assume xx is relative to the left edge of TrackPanel! - wxCoord xx, bool smoothScrolling + wxCoord xx, bool smoothScrolling, bool seek ) { // Don't actually start scrubbing, but collect some information @@ -280,6 +280,8 @@ void Scrubber::MarkScrubStart( // scrubber state mProject->SetAudioIOToken(0); + mSeeking = seek; + ctb->SetPlay(true, mSeeking ? ControlToolBar::PlayAppearance::Seek : ControlToolBar::PlayAppearance::Scrub); @@ -418,12 +420,12 @@ void Scrubber::ContinueScrubbingPoll() { // Thus scrubbing relies mostly on periodic polling of mouse and keys, // not event notifications. But there are a few event handlers that - // leave messages for this routine, in mPaused. + // leave messages for this routine, in mScrubSeekPress and in mPaused. // Decide whether to skip play, because either mouse is down now, // or there was a left click event. (This is then a delayed reaction, in a // timer callback, to a left click event detected elsewhere.) - const bool seek = Seeks(); + const bool seek = TemporarilySeeks() || Seeks(); bool result = false; if (mPaused) { @@ -470,6 +472,12 @@ void Scrubber::ContinueScrubbingPoll() } } } + + if (result) + mScrubSeekPress = false; + + // else, if seek requested, try again at a later time when we might + // enqueue a long enough stutter } void Scrubber::ContinueScrubbingUI() @@ -527,6 +535,7 @@ void Scrubber::StopScrubbing() mScrubStartPosition = -1; mDragging = false; + mSeeking = false; if (!IsScrubbing()) { @@ -569,6 +578,32 @@ bool Scrubber::ChoseSeeking() const mSeeking; } +bool Scrubber::MayDragToSeek() const +{ + // Return true only if the pointer is in the + // ruler or the track panel + const auto &state = ::wxGetMouseState(); + const auto &position = state.GetPosition(); + + auto ruler = mProject->GetRulerPanel(); + if (ruler && + ruler->GetScreenRect().Contains(position)) + return true; + + auto trackPanel = mProject->GetTrackPanel(); + if (trackPanel && + trackPanel->GetScreenRect().Contains(position)) + return true; + + return false; +} + +bool Scrubber::TemporarilySeeks() const +{ + return mScrubSeekPress || + (::wxGetMouseState().LeftIsDown() && MayDragToSeek()); +} + bool Scrubber::Seeks() const { return (HasStartedScrubbing() || IsScrubbing()) && ChoseSeeking(); @@ -642,7 +677,12 @@ void Scrubber::Forwarder::OnMouse(wxMouseEvent &event) auto ruler = scrubber.mProject->GetRulerPanel(); auto isScrubbing = scrubber.IsScrubbing(); if (isScrubbing && !event.HasAnyModifiers()) { - if (event.m_wheelRotation) { + if(event.LeftDown() && scrubber.MayDragToSeek()) { + // This event handler may catch mouse transitions that are missed + // by the polling of mouse state by the timer. + scrubber.mScrubSeekPress = true; + } + else if (event.m_wheelRotation) { double steps = event.m_wheelRotation / (event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0); scrubber.HandleScrollWheel(steps); @@ -807,7 +847,7 @@ Scrubber &ScrubbingOverlay::GetScrubber() return mProject->GetScrubber(); } -void Scrubber::DoScrub() +void Scrubber::DoScrub(bool seek) { const bool wasScrubbing = HasStartedScrubbing() || IsScrubbing(); const bool scroll = PlaybackPrefs::GetPinnedHeadPreference(); @@ -821,7 +861,10 @@ void Scrubber::DoScrub() const auto offset = tp->GetLeftOffset(); xx = (std::max(offset, std::min(offset + width - 1, xx))); - MarkScrubStart(xx, scroll); + MarkScrubStart(xx, scroll, seek); + } + else if (mSeeking != seek) { + // just switching mode } else mProject->GetControlToolBar()->StopPlaying(); @@ -829,10 +872,9 @@ void Scrubber::DoScrub() void Scrubber::OnScrubOrSeek(bool seek) { - bool skip = false; + DoScrub(seek); if (HasStartedScrubbing()) { - skip = (mSeeking != seek); // just switching mode // Show the correct status. const auto ctb = mProject->GetControlToolBar(); ctb->UpdateStatusBar(mProject); @@ -848,11 +890,6 @@ void Scrubber::OnScrubOrSeek(bool seek) auto scrubbingToolBar = mProject->GetScrubbingToolBar(); scrubbingToolBar->EnableDisableButtons(); scrubbingToolBar->RegenerateTooltips(); - - if (!skip) - DoScrub(); - - CheckMenuItems(); } void Scrubber::OnScrub(wxCommandEvent&) @@ -892,7 +929,7 @@ const wxString &Scrubber::GetUntranslatedStateString() const static wxString empty; if (HasStartedScrubbing()) { - auto &item = FindMenuItem(mSeeking); + auto &item = FindMenuItem(Seeks() || TemporarilySeeks()); return item.status; } else diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 256ee321e..6507f7a61 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -71,7 +71,7 @@ public: ~Scrubber(); // Assume xx is relative to the left edge of TrackPanel! - void MarkScrubStart(wxCoord xx, bool smoothScrolling); + void MarkScrubStart(wxCoord xx, bool smoothScrolling, bool seek); // Returns true iff the event should be considered consumed by this: // Assume xx is relative to the left edge of TrackPanel! @@ -98,6 +98,8 @@ public: { mSmoothScrollingScrub = value; } bool ChoseSeeking() const; + bool MayDragToSeek() const; + bool TemporarilySeeks() const; bool Seeks() const; bool Scrubs() const; bool ShowsBar() const; @@ -135,7 +137,7 @@ public: bool IsPaused() const; private: - void DoScrub(); + void DoScrub(bool seek); void OnActivateOrDeactivateApp(wxActivateEvent & event); void CheckMenuItems(); @@ -157,6 +159,7 @@ private: int mScrubSpeedDisplayCountdown; wxCoord mScrubStartPosition; wxCoord mLastScrubPosition {}; + bool mScrubSeekPress {}; bool mSmoothScrollingScrub; bool mSeeking {}; diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index cea6653e0..6f7eee4f0 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -1819,7 +1819,7 @@ void QuickPlayRulerOverlay::Draw(OverlayPanel &panel, wxDC &dc) ruler->mMouseEventState == AdornedRulerPanel::mesNone && (ruler->mPrevZone == AdornedRulerPanel::StatusChoice::EnteringScrubZone || (scrubber.HasStartedScrubbing())); - auto seek = scrub && scrubber.Seeks(); + auto seek = scrub && (scrubber.Seeks() || scrubber.TemporarilySeeks()); auto width = scrub ? IndicatorBigWidth() : IndicatorSmallWidth; ruler->DoDrawIndicator(&dc, mOldQPIndicatorPos, true, width, scrub, seek); } @@ -2450,7 +2450,8 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt) } else if (!HasCapture() && inScrubZone) { if (evt.LeftDown()) { - scrubber.MarkScrubStart(evt.m_x, PlaybackPrefs::GetPinnedHeadPreference()); + scrubber.MarkScrubStart(evt.m_x, + PlaybackPrefs::GetPinnedHeadPreference(), false); UpdateStatusBarAndTooltips(StatusChoice::EnteringScrubZone); } ShowQuickPlayIndicator();