mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-14 17:14:07 +01:00
Implement scrub and seek buttons on ruler; redo scrub menu items
This commit is contained in:
@@ -33,9 +33,6 @@ Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
#include <wx/dc.h>
|
||||
|
||||
// Conditional compilation switch for making scrub menu items checkable
|
||||
#define CHECKABLE_SCRUB_MENU_ITEMS
|
||||
|
||||
enum {
|
||||
// PRL:
|
||||
// Mouse must move at least this far to distinguish ctrl-drag to scrub
|
||||
@@ -221,24 +218,27 @@ namespace {
|
||||
wxString status;
|
||||
void (Scrubber::*memFn)(wxCommandEvent&);
|
||||
bool seek;
|
||||
bool (Scrubber::*StatusTest)() const;
|
||||
|
||||
const wxString &GetStatus() const { return status; }
|
||||
} 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"), XO("Scrubbing"),
|
||||
&Scrubber::OnScrub, false },
|
||||
&Scrubber::OnScrub, false, &Scrubber::Scrubs },
|
||||
|
||||
{ wxT("Seek"), XO("See&k"), XO("Seeking"),
|
||||
&Scrubber::OnSeek, true },
|
||||
&Scrubber::OnSeek, true, &Scrubber::Seeks },
|
||||
|
||||
{ wxT("StartScrubSeek"), XO("Star&t"), XO(""),
|
||||
&Scrubber::OnStart, true, nullptr },
|
||||
};
|
||||
|
||||
enum { nMenuItems = sizeof(menuItems) / sizeof(*menuItems) };
|
||||
enum { nMenuItems = sizeof(menuItems) / sizeof(*menuItems), StartMenuItem = 2 };
|
||||
|
||||
// This never finds the last item:
|
||||
inline const MenuItem &FindMenuItem(bool seek)
|
||||
{
|
||||
return *std::find_if(menuItems, menuItems + nMenuItems,
|
||||
@@ -252,16 +252,13 @@ namespace {
|
||||
|
||||
void Scrubber::MarkScrubStart(
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
wxCoord xx, bool smoothScrolling, bool alwaysSeeking
|
||||
wxCoord xx, bool smoothScrolling
|
||||
)
|
||||
{
|
||||
UncheckAllMenuItems();
|
||||
|
||||
// Don't actually start scrubbing, but collect some information
|
||||
// needed for the decision to start scrubbing later when handling
|
||||
// drag events.
|
||||
mSmoothScrollingScrub = smoothScrolling;
|
||||
mAlwaysSeeking = alwaysSeeking;
|
||||
|
||||
ControlToolBar * const ctb = mProject->GetControlToolBar();
|
||||
|
||||
@@ -278,8 +275,6 @@ void Scrubber::MarkScrubStart(
|
||||
|
||||
mScrubStartPosition = xx;
|
||||
mOptions.startClockTimeMillis = ::wxGetLocalTimeMillis();
|
||||
|
||||
CheckMenuItem();
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
@@ -468,12 +463,12 @@ void Scrubber::ContinueScrubbingUI()
|
||||
|
||||
{
|
||||
// Show the correct status for seeking.
|
||||
bool backup = mAlwaysSeeking;
|
||||
mAlwaysSeeking = seek;
|
||||
bool backup = mSeeking;
|
||||
mSeeking = seek;
|
||||
const auto ctb = mProject->GetControlToolBar();
|
||||
if (ctb)
|
||||
ctb->UpdateStatusBar(mProject);
|
||||
mAlwaysSeeking = backup;
|
||||
mSeeking = backup;
|
||||
}
|
||||
|
||||
if (seek)
|
||||
@@ -498,8 +493,6 @@ void Scrubber::StopScrubbing()
|
||||
|
||||
mPoller->Stop();
|
||||
|
||||
UncheckAllMenuItems();
|
||||
|
||||
mScrubStartPosition = -1;
|
||||
mDragging = false;
|
||||
|
||||
@@ -770,13 +763,12 @@ Scrubber &ScrubbingOverlay::GetScrubber()
|
||||
|
||||
bool Scrubber::PollIsSeeking()
|
||||
{
|
||||
return mDragging || (mAlwaysSeeking || ::wxGetMouseState().LeftIsDown());
|
||||
return mDragging || (mSeeking || ::wxGetMouseState().LeftIsDown());
|
||||
}
|
||||
|
||||
void Scrubber::DoScrub(bool seek)
|
||||
void Scrubber::DoScrub()
|
||||
{
|
||||
const bool wasScrubbing = IsScrubbing();
|
||||
const bool match = (seek == mAlwaysSeeking);
|
||||
const bool scroll = PlaybackPrefs::GetPinnedHeadPreference();
|
||||
if (!wasScrubbing) {
|
||||
auto tp = mProject->GetTrackPanel();
|
||||
@@ -788,33 +780,43 @@ void Scrubber::DoScrub(bool seek)
|
||||
const auto offset = tp->GetLeftOffset();
|
||||
xx = (std::max(offset, std::min(offset + width - 1, xx)));
|
||||
|
||||
MarkScrubStart(xx, scroll, seek);
|
||||
MarkScrubStart(xx, scroll);
|
||||
}
|
||||
else if(!match) {
|
||||
mSmoothScrollingScrub = scroll;
|
||||
mAlwaysSeeking = seek;
|
||||
UncheckAllMenuItems();
|
||||
CheckMenuItem();
|
||||
}
|
||||
|
||||
void Scrubber::OnScrubOrSeek(bool &toToggle, bool &other)
|
||||
{
|
||||
toToggle = !toToggle;
|
||||
if (toToggle)
|
||||
other = false;
|
||||
|
||||
if (HasStartedScrubbing()) {
|
||||
// Show the correct status.
|
||||
const auto ctb = mProject->GetControlToolBar();
|
||||
ctb->UpdateStatusBar(mProject);
|
||||
}
|
||||
else {
|
||||
// This will call back to Scrubber::StopScrubbing
|
||||
const auto ctb = mProject->GetControlToolBar();
|
||||
ctb->StopPlaying();
|
||||
}
|
||||
|
||||
auto ruler = mProject->GetRulerPanel();
|
||||
if (ruler)
|
||||
// Update button images
|
||||
ruler->UpdateButtonStates();
|
||||
|
||||
CheckMenuItem();
|
||||
}
|
||||
|
||||
void Scrubber::OnScrub(wxCommandEvent&)
|
||||
{
|
||||
DoScrub(false);
|
||||
OnScrubOrSeek(mScrubbing, mSeeking);
|
||||
}
|
||||
|
||||
void Scrubber::OnSeek(wxCommandEvent&)
|
||||
{
|
||||
DoScrub(true);
|
||||
OnScrubOrSeek(mSeeking, mScrubbing);
|
||||
}
|
||||
|
||||
void Scrubber::OnStart(wxCommandEvent&)
|
||||
{
|
||||
DoScrub();
|
||||
}
|
||||
|
||||
enum { CMD_ID = 8000 };
|
||||
@@ -828,14 +830,14 @@ BEGIN_EVENT_TABLE(Scrubber::Forwarder, wxEvtHandler)
|
||||
EVT_MOUSE_EVENTS(Scrubber::Forwarder::OnMouse)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
static_assert(nMenuItems == 2, "wrong number of items");
|
||||
static_assert(nMenuItems == 3, "wrong number of items");
|
||||
|
||||
const wxString &Scrubber::GetUntranslatedStateString() const
|
||||
{
|
||||
static wxString empty;
|
||||
|
||||
if (HasStartedScrubbing()) {
|
||||
auto &item = FindMenuItem(mAlwaysSeeking);
|
||||
auto &item = FindMenuItem(mSeeking);
|
||||
return item.status;
|
||||
}
|
||||
else
|
||||
@@ -846,15 +848,19 @@ std::vector<wxString> Scrubber::GetAllUntranslatedStatusStrings()
|
||||
{
|
||||
using namespace std;
|
||||
vector<wxString> results;
|
||||
transform(menuItems, menuItems + nMenuItems, back_inserter(results),
|
||||
mem_fun_ref(&MenuItem::GetStatus));
|
||||
for (const auto &item : menuItems) {
|
||||
const auto &status = item.GetStatus();
|
||||
if (!status.empty())
|
||||
results.push_back(status);
|
||||
}
|
||||
return move(results);
|
||||
}
|
||||
|
||||
bool Scrubber::CanScrub() const
|
||||
{
|
||||
// Return the enabled state for the menu item that really launches the scrub or seek.
|
||||
auto cm = mProject->GetCommandManager();
|
||||
return cm->GetEnabled(menuItems[0].name);
|
||||
return cm->GetEnabled(menuItems[StartMenuItem].name);
|
||||
}
|
||||
|
||||
void Scrubber::AddMenuItems()
|
||||
@@ -865,15 +871,14 @@ void Scrubber::AddMenuItems()
|
||||
|
||||
cm->BeginSubMenu(_("Scru&bbing"));
|
||||
for (const auto &item : menuItems) {
|
||||
#ifdef CHECKABLE_SCRUB_MENU_ITEMS
|
||||
cm->AddCheck(item.name, wxGetTranslation(item.label),
|
||||
FNT(Scrubber, this, item.memFn),
|
||||
false, flags, mask);
|
||||
#else
|
||||
cm->AddItem(item.name, wxGetTranslation(item.label),
|
||||
FNT(Scrubber, this, item.memFn),
|
||||
flags, mask);
|
||||
#endif
|
||||
if (!item.GetStatus().empty())
|
||||
cm->AddCheck(item.name, wxGetTranslation(item.label),
|
||||
FNT(Scrubber, this, item.memFn),
|
||||
false, flags, mask);
|
||||
else
|
||||
cm->AddItem(item.name, wxGetTranslation(item.label),
|
||||
FNT(Scrubber, this, item.memFn),
|
||||
flags, mask);
|
||||
}
|
||||
cm->EndSubMenu();
|
||||
CheckMenuItem();
|
||||
@@ -885,40 +890,23 @@ void Scrubber::PopulateMenu(wxMenu &menu)
|
||||
auto cm = mProject->GetCommandManager();
|
||||
const MenuItem *checkedItem =
|
||||
HasStartedScrubbing()
|
||||
? &FindMenuItem(mAlwaysSeeking)
|
||||
? &FindMenuItem(mSeeking)
|
||||
: nullptr;
|
||||
for (const auto &item : menuItems) {
|
||||
if (cm->GetEnabled(item.name)) {
|
||||
#ifdef CHECKABLE_SCRUB_MENU_ITEMS
|
||||
menu.AppendCheckItem(id, item.label);
|
||||
if(&item == checkedItem)
|
||||
menu.FindItem(id)->Check();
|
||||
#else
|
||||
menu.Append(id, item.label);
|
||||
#endif
|
||||
}
|
||||
++id;
|
||||
}
|
||||
}
|
||||
|
||||
void Scrubber::UncheckAllMenuItems()
|
||||
{
|
||||
#ifdef CHECKABLE_SCRUB_MENU_ITEMS
|
||||
auto cm = mProject->GetCommandManager();
|
||||
for (const auto &item : menuItems)
|
||||
cm->Check(item.name, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Scrubber::CheckMenuItem()
|
||||
{
|
||||
#ifdef CHECKABLE_SCRUB_MENU_ITEMS
|
||||
if(HasStartedScrubbing()) {
|
||||
auto cm = mProject->GetCommandManager();
|
||||
auto item = FindMenuItem(mAlwaysSeeking);
|
||||
cm->Check(item.name, true);
|
||||
}
|
||||
#endif
|
||||
auto cm = mProject->GetCommandManager();
|
||||
cm->Check(menuItems[0].name, mScrubbing);
|
||||
cm->Check(menuItems[1].name, mSeeking);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -71,11 +71,7 @@ public:
|
||||
~Scrubber();
|
||||
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
void MarkScrubStart(
|
||||
wxCoord xx, bool smoothScrolling,
|
||||
bool alwaysSeeking // if false, can switch seeking or scrubbing
|
||||
// by mouse button state
|
||||
);
|
||||
void MarkScrubStart(wxCoord xx, bool smoothScrolling);
|
||||
|
||||
// Returns true iff the event should be considered consumed by this:
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
@@ -101,8 +97,11 @@ public:
|
||||
void SetScrollScrubbing(bool value)
|
||||
{ mSmoothScrollingScrub = value; }
|
||||
|
||||
bool IsAlwaysSeeking() const
|
||||
{ return mAlwaysSeeking; }
|
||||
bool Seeks() const
|
||||
{ return mSeeking; }
|
||||
|
||||
bool Scrubs() const
|
||||
{ return mScrubbing; }
|
||||
|
||||
bool ShouldDrawScrubSpeed();
|
||||
double FindScrubSpeed(bool seeking, double time) const;
|
||||
@@ -120,10 +119,13 @@ public:
|
||||
// For popup
|
||||
void PopulateMenu(wxMenu &menu);
|
||||
|
||||
void OnScrubOrSeek(bool &toToggle, bool &other);
|
||||
void OnScrub(wxCommandEvent&);
|
||||
void OnSeek(wxCommandEvent&);
|
||||
void OnStart(wxCommandEvent&);
|
||||
|
||||
// A string to put in the leftmost part of the status bar.
|
||||
// A string to put in the leftmost part of the status bar
|
||||
// when scrub or seek is in progress, or else empty.
|
||||
const wxString &GetUntranslatedStateString() const;
|
||||
|
||||
// All possible status strings.
|
||||
@@ -133,9 +135,8 @@ public:
|
||||
bool IsPaused() const;
|
||||
|
||||
private:
|
||||
void DoScrub(bool seek);
|
||||
void DoScrub();
|
||||
void OnActivateOrDeactivateApp(wxActivateEvent & event);
|
||||
void UncheckAllMenuItems();
|
||||
void CheckMenuItem();
|
||||
|
||||
// I need this because I can't push the scrubber as an event handler
|
||||
@@ -158,7 +159,12 @@ private:
|
||||
wxCoord mLastScrubPosition {};
|
||||
bool mScrubSeekPress;
|
||||
bool mSmoothScrollingScrub;
|
||||
bool mAlwaysSeeking {};
|
||||
|
||||
// These hold the three-way choice among click-to-scrub, click-to-seek, or disabled.
|
||||
// Not both true.
|
||||
bool mScrubbing {};
|
||||
bool mSeeking {};
|
||||
|
||||
bool mDragging {};
|
||||
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL
|
||||
|
||||
Reference in New Issue
Block a user