diff --git a/src/prefs/PlaybackPrefs.cpp b/src/prefs/PlaybackPrefs.cpp index 38ca66e11..3ec6faeab 100644 --- a/src/prefs/PlaybackPrefs.cpp +++ b/src/prefs/PlaybackPrefs.cpp @@ -49,6 +49,18 @@ void PlaybackPrefs::Populate() // ----------------------- End of main section -------------- } +namespace { + const char *UnpinnedScrubbingPreferenceKey() + { + return "/AudioIO/UnpinnedScrubbing"; + } + bool UnpinnedScrubbingPreferenceDefault() + { + return true; + } + int iPreferenceUnpinned = -1; +} + void PlaybackPrefs::PopulateOrExchange(ShuttleGui & S) { wxTextCtrl *w; @@ -126,7 +138,9 @@ void PlaybackPrefs::PopulateOrExchange(ShuttleGui & S) S.StartTwoColumn(); { - S.TieCheckBox(_("Always scrub un&pinned"), "/AudioIO/UnpinnedScrubbing", true); + S.TieCheckBox(_("Always scrub un&pinned"), + UnpinnedScrubbingPreferenceKey(), + UnpinnedScrubbingPreferenceDefault()); } S.EndTwoColumn(); } @@ -137,8 +151,21 @@ void PlaybackPrefs::PopulateOrExchange(ShuttleGui & S) } +bool PlaybackPrefs::GetUnpinnedScrubbingPreference() +{ + if ( iPreferenceUnpinned >= 0 ) + return iPreferenceUnpinned == 1; + bool bResult = gPrefs->ReadBool( + UnpinnedScrubbingPreferenceKey(), + UnpinnedScrubbingPreferenceDefault()); + iPreferenceUnpinned = bResult ? 1: 0; + return bResult; +} + bool PlaybackPrefs::Commit() { + iPreferenceUnpinned = -1; + ShuttleGui S(this, eIsSavingToPrefs); PopulateOrExchange(S); diff --git a/src/prefs/PlaybackPrefs.h b/src/prefs/PlaybackPrefs.h index 1a8b68caa..ffc4c4e76 100644 --- a/src/prefs/PlaybackPrefs.h +++ b/src/prefs/PlaybackPrefs.h @@ -28,6 +28,8 @@ class PlaybackPrefs final : public PrefsPanel bool Commit() override; wxString HelpPageName() override; void PopulateOrExchange(ShuttleGui & S) override; + + static bool GetUnpinnedScrubbingPreference(); private: void Populate(); diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 7c756a9c5..658807c93 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1505,9 +1505,20 @@ void ControlToolBar::UpdateStatusBar(AudacityProject *pProject) pProject->GetStatusBar()->SetStatusText(StateForStatusBar(), stateStatusBarField); } +bool ControlToolBar::IsTransportingPinned() +{ + if (!TracksPrefs::GetPinnedHeadPreference()) + return false; + const auto &scrubber = ::GetActiveProject()->GetScrubber(); + return + !(scrubber.HasMark() && + !scrubber.WasSpeedPlaying() && + !Scrubber::ShouldScrubPinned()); +} + void ControlToolBar::StartScrollingIfPreferred() { - if (TracksPrefs::GetPinnedHeadPreference()) + if (IsTransportingPinned()) StartScrolling(); #ifdef __WXMAC__ else if (::GetActiveProject()->GetScrubber().HasMark()) { diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index 26ab61ec2..d791007bc 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -51,6 +51,8 @@ class ControlToolBar final : public ToolBar { ControlToolBar(); virtual ~ControlToolBar(); + static bool IsTransportingPinned(); + void Create(wxWindow *parent) override; void UpdatePrefs() override; diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index 1fe77ae11..296dc8e43 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -17,6 +17,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../Project.h" #include "../../TrackPanel.h" #include "../../TrackPanelCell.h" +#include "../../prefs/PlaybackPrefs.h" #include "../../prefs/TracksPrefs.h" #include "../../toolbars/ControlToolBar.h" #include "../../toolbars/ScrubbingToolBar.h" @@ -162,6 +163,12 @@ auto Scrubber::ScrubPollerThread::Entry() -> ExitCode #endif +bool Scrubber::ShouldScrubPinned() +{ + return TracksPrefs::GetPinnedHeadPreference() && + !PlaybackPrefs::GetUnpinnedScrubbingPreference(); +} + class Scrubber::ScrubPoller : public wxTimer { public: @@ -997,7 +1004,7 @@ void Scrubber::DoScrub(bool seek) if( !CanScrub() ) return; const bool wasScrubbing = HasMark() || IsScrubbing(); - const bool scroll = TracksPrefs::GetPinnedHeadPreference(); + const bool scroll = ShouldScrubPinned(); if (!wasScrubbing) { auto tp = mProject->GetTrackPanel(); wxCoord xx = tp->ScreenToClient(::wxGetMouseState().GetPosition()).x; diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 2d1d2bef7..73b0dc3d0 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -72,6 +72,8 @@ public: Scrubber(AudacityProject *project); ~Scrubber(); + + static bool ShouldScrubPinned(); // Assume xx is relative to the left edge of TrackPanel! void MarkScrubStart(wxCoord xx, bool smoothScrolling, bool seek); diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index 464766518..952adaaf0 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -2210,7 +2210,7 @@ public: static std::shared_ptr HitTest( const AudacityProject *pProject, wxCoord xx ) { - if( TracksPrefs::GetPinnedHeadPreference() && + if( ControlToolBar::IsTransportingPinned() && pProject->IsAudioActive() ) { const auto targetX = GetPlayHeadX( pProject ); @@ -2373,7 +2373,7 @@ private: if (!scrubber.HasMark()) { // Asynchronous scrub poller gets activated here scrubber.MarkScrubStart( - event.event.m_x, TracksPrefs::GetPinnedHeadPreference(), false); + event.event.m_x, Scrubber::ShouldScrubPinned(), false); } } } @@ -3287,6 +3287,8 @@ void AdornedRulerPanel::UpdateButtonStates() }; { + // The button always reflects the pinned head preference, even though + // there is also a Playback preference that may overrule it for scrubbing bool state = TracksPrefs::GetPinnedHeadPreference(); auto pinButton = static_cast(FindWindow(OnTogglePinnedStateID)); if( !state ) @@ -3664,7 +3666,7 @@ void AdornedRulerPanel::DoDrawIndicator dc->DrawPolygon( 3, tri ); } else { - bool pinned = TracksPrefs::GetPinnedHeadPreference(); + bool pinned = ControlToolBar::IsTransportingPinned(); wxBitmap & bmp = theTheme.Bitmap( pinned ? (playing ? bmpPlayPointerPinned : bmpRecordPointerPinned) : (playing ? bmpPlayPointer : bmpRecordPointer)