diff --git a/src/Menus.cpp b/src/Menus.cpp index 760e4164a..f4b6a582f 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -751,14 +751,7 @@ void AudacityProject::CreateMenusAndCommands() WaveTracksExistFlag | AudioIONotBusyFlag | CanStopAudioStreamFlag); // Scrubbing sub-menu - { - c->BeginSubMenu(_("Scru&bbing")); - c->AddItem(wxT("Scrub"), _("&Scrub"), FN(OnScrub)); - c->AddItem(wxT("ScrollScrub"), _("Sc&rolling Scrub"), FN(OnScrollScrub)); - c->AddItem(wxT("Seek"), _("See&k"), FN(OnSeek)); - c->AddItem(wxT("ScrollSeek"), _("Scrollin&g Seek"), FN(OnScrollSeek)); - c->EndSubMenu(); - } + GetScrubber().AddMenuItems(); c->AddItem(wxT("Pause"), _("&Pause"), FN(OnPause), wxT("P"), c->GetDefaultFlags() | AudioStreamNotScrubbingFlag, @@ -2195,36 +2188,6 @@ void AudacityProject::OnPlayCutPreview() GetControlToolBar()->PlayCurrentRegion(false, true); } -namespace { - inline void DoScrub(AudacityProject *project, bool scroll, bool seek) - { - auto tp = project->GetTrackPanel(); - wxCoord xx = tp->ScreenToClient(::wxGetMouseState().GetPosition()).x; - wxMouseEvent evt; - project->GetScrubber().MarkScrubStart(evt, scroll, seek); - } -} - -void AudacityProject::OnScrub() -{ - DoScrub(this, false, false); -} - -void AudacityProject::OnScrollScrub() -{ - DoScrub(this, true, false); -} - -void AudacityProject::OnSeek() -{ - DoScrub(this, false, true); -} - -void AudacityProject::OnScrollSeek() -{ - DoScrub(this, true, true); -} - void AudacityProject::OnPlayStop() { ControlToolBar *toolbar = GetControlToolBar(); diff --git a/src/Menus.h b/src/Menus.h index e1e6d897b..f8cc32084 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -88,11 +88,6 @@ void OnPlayBeforeAndAfterSelectionEnd(); void OnPlayLooped(); void OnPlayCutPreview(); -void OnScrub(); -void OnScrollScrub(); -void OnSeek(); -void OnScrollSeek(); - // Wave track control void OnTrackPan(); diff --git a/src/Project.cpp b/src/Project.cpp index 06a419655..9492224e3 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -839,8 +839,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mIsSyncLocked = false; gPrefs->Read(wxT("/GUI/SyncLockTracks"), &mIsSyncLocked, false); - CreateMenusAndCommands(); - // LLL: Read this!!! // // Until the time (and cpu) required to refresh the track panel is @@ -955,6 +953,8 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mTrackPanel->AddOverlay(mScrubOverlay.get()); #endif + CreateMenusAndCommands(); + // LLL: When Audacity starts or becomes active after returning from // another application, the first window that can accept focus // will be given the focus even if we try to SetFocus(). By diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index bf04b9ba2..5610bc413 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -16,6 +16,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../TrackPanel.h" #include "../../TrackPanelCell.h" #include "../../TrackPanelCellIterator.h" +#include "../../commands/CommandFunctors.h" #include "../../toolbars/ControlToolBar.h" #include @@ -134,6 +135,28 @@ Scrubber::~Scrubber() wxActivateEventHandler(Scrubber::OnActivateOrDeactivateApp), NULL, this); } +namespace { + const struct MenuItem { + wxString name; + wxString label; + void (Scrubber::*memFn)(); + bool scroll; + bool seek; + } menuItems[] = { + /* i18n-hint: These commands assist the user in finding a sound by ear. ... + "Scrubbing" is variable-speed playback, ... + "Seeking" is normal speed playback but with skips, ... + "Scrolling" keeps the playback position at a fixed place on screen while the waveform moves + */ + { wxT("Scrub"), XO("&Scrub"), &Scrubber::OnScrub, false, false }, + { wxT("ScrollScrub"), XO("Sc&rolling Scrub"), &Scrubber::OnScrollScrub, true, false }, + { wxT("Seek"), XO("See&k"), &Scrubber::OnSeek, false, true }, + { wxT("ScrollSeek"), XO("Scrollin&g Seek"), &Scrubber::OnScrollSeek, true, true }, + }; + + enum { nMenuItems = sizeof(menuItems) / sizeof(*menuItems) }; +} + void Scrubber::MarkScrubStart( const wxMouseEvent &event #ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL @@ -142,6 +165,8 @@ void Scrubber::MarkScrubStart( , bool alwaysSeeking ) { + UncheckAllMenuItems(); + const wxCoord xx = event.m_x; // Don't actually start scrubbing, but collect some information @@ -158,6 +183,8 @@ void Scrubber::MarkScrubStart( ctb->SetPlay(true, ControlToolBar::PlayAppearance::Scrub); ctb->UpdateStatusBar(mProject); mProject->GetTrackPanel()->HandleCursor(event); + + CheckMenuItem(); } #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT @@ -311,6 +338,8 @@ void Scrubber::ContinueScrubbing() void Scrubber::StopScrubbing() { + UncheckAllMenuItems(); + mScrubStartPosition = -1; mSmoothScrollingScrub = false; const auto ctb = mProject->GetControlToolBar(); @@ -550,4 +579,82 @@ bool Scrubber::PollIsSeeking() return mAlwaysSeeking || ::wxGetMouseState().LeftIsDown(); } +void Scrubber::DoScrub(bool scroll, bool seek) +{ + const bool wasScrubbing = IsScrubbing(); + const bool match = (scroll == mSmoothScrollingScrub && seek == mAlwaysSeeking); + if (!wasScrubbing) { + auto tp = mProject->GetTrackPanel(); + wxCoord xx = tp->ScreenToClient(::wxGetMouseState().GetPosition()).x; + wxMouseEvent evt; + evt.SetX(xx); + MarkScrubStart(evt, scroll, seek); + } + else if(!match) { + mSmoothScrollingScrub = scroll; + mAlwaysSeeking = seek; + UncheckAllMenuItems(); + CheckMenuItem(); + } + else + // unchecks items + StopScrubbing(); +} + +void Scrubber::OnScrub() +{ + DoScrub(false, false); +} + +void Scrubber::OnScrollScrub() +{ + DoScrub(true, false); +} + +void Scrubber::OnSeek() +{ + DoScrub(false, true); +} + +void Scrubber::OnScrollSeek() +{ + DoScrub(true, true); +} + +void Scrubber::AddMenuItems() +{ + auto cm = mProject->GetCommandManager(); + + cm->BeginSubMenu(_("Scru&bbing")); + for (const auto &item : menuItems) { + cm->AddCheck(item.name, wxGetTranslation(item.label), + FNT(Scrubber, this, item.memFn), + false, + WaveTracksExistFlag, WaveTracksExistFlag); + } + cm->EndSubMenu(); + CheckMenuItem(); +} + +void Scrubber::UncheckAllMenuItems() +{ + auto cm = mProject->GetCommandManager(); + for (const auto &item : menuItems) + cm->Check(item.name, false); +} + +void Scrubber::CheckMenuItem() +{ + if(HasStartedScrubbing()) { + auto &item = *std::find_if(menuItems, menuItems + nMenuItems, + [=](const MenuItem &item) { + return mSmoothScrollingScrub == item.scroll && + mAlwaysSeeking == item.seek; + } + ); + auto cm = mProject->GetCommandManager(); + cm->Check(item.name, true); + } +} + #endif diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 2edd2cdd0..d4347c691 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -59,8 +59,18 @@ public: void SetSeeking() { mScrubSeekPress = true; } bool PollIsSeeking(); + void AddMenuItems(); + + void OnScrub(); + void OnScrollScrub(); + void OnSeek(); + void OnScrollSeek(); + private: + void DoScrub(bool scroll, bool seek); void OnActivateOrDeactivateApp(wxActivateEvent & event); + void UncheckAllMenuItems(); + void CheckMenuItem(); private: int mScrubToken;