mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-04 17:49:45 +02:00
Control scrub with motion, click, drag, wheel almost anywhere in main window...
... if the event is not handled and skipped by sub-windows first, such as for toolbar button clicks. (But track panel clicks are skipped even after doing something, so they may also cause seeking besides other responses. So click can seek AND set cursor.) This is meant to make drag to seek and wheel for change of speed easier, without needing to keep the mouse in the narrow time ruler. Also lets you click in the ruler, then move in any direction, and not miss the motion event that should start the scrub playback. The event handling is a bit of a hack, using propagation. It does not use capture.
This commit is contained in:
parent
3d222bcd87
commit
9ab0e42f29
@ -1613,7 +1613,7 @@ void AudacityProject::TP_ScrollWindow(double scrollto)
|
||||
// handler in Track Panel. A positive argument makes the window
|
||||
// scroll down, while a negative argument scrolls up.
|
||||
//
|
||||
void AudacityProject::TP_ScrollUpDown(int delta)
|
||||
bool AudacityProject::TP_ScrollUpDown(int delta)
|
||||
{
|
||||
int oldPos = mVsbar->GetThumbPosition();
|
||||
int pos = oldPos + delta;
|
||||
@ -1634,7 +1634,10 @@ void AudacityProject::TP_ScrollUpDown(int delta)
|
||||
|
||||
wxScrollEvent dummy;
|
||||
OnScroll(dummy);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudacityProject::FixScrollbars()
|
||||
|
@ -430,7 +430,7 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame,
|
||||
void TP_ScrollLeft() override;
|
||||
void TP_ScrollRight() override;
|
||||
void TP_ScrollWindow(double scrollto) override;
|
||||
void TP_ScrollUpDown(int delta) override;
|
||||
bool TP_ScrollUpDown(int delta) override;
|
||||
void TP_HandleResize() override;
|
||||
|
||||
// ToolBar
|
||||
|
@ -5473,6 +5473,13 @@ void TrackPanel::HandleResize(wxMouseEvent & event)
|
||||
/// Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling)
|
||||
void TrackPanel::HandleWheelRotation(wxMouseEvent & event)
|
||||
{
|
||||
if(!event.HasAnyModifiers()) {
|
||||
// We will later un-skip if we do anything, but if we don't,
|
||||
// propagate the event up for the sake of the scrubber
|
||||
event.Skip();
|
||||
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||
}
|
||||
|
||||
if (GetTracks()->IsEmpty())
|
||||
// Scrolling and Zoom in and out commands are disabled when there are no tracks.
|
||||
// This should be disabled too for consistency. Otherwise
|
||||
@ -5485,6 +5492,9 @@ void TrackPanel::HandleWheelRotation(wxMouseEvent & event)
|
||||
Track *const pTrack = FindTrack(event.m_x, event.m_y, true, false, &rect);
|
||||
if (pTrack && event.m_x >= GetVRulerOffset()) {
|
||||
HandleWheelRotationInVRuler(event, pTrack, rect);
|
||||
// Always stop propagation even if the ruler didn't change. The ruler
|
||||
// is a narrow enough target.
|
||||
event.Skip(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -5574,7 +5584,8 @@ void TrackPanel::HandleWheelRotation(wxMouseEvent & event)
|
||||
double lines = steps * 4 + mVertScrollRemainder;
|
||||
mVertScrollRemainder = lines - floor(lines);
|
||||
lines = floor(lines);
|
||||
mListener->TP_ScrollUpDown((int)-lines);
|
||||
const bool didSomething = mListener->TP_ScrollUpDown((int)-lines);
|
||||
event.Skip(!didSomething);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5862,6 +5873,13 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
|
||||
if (event.m_wheelRotation != 0)
|
||||
HandleWheelRotation(event);
|
||||
|
||||
if (event.LeftDown() || event.LeftIsDown() || event.Moving()) {
|
||||
// Skip, even if we do something, so that the left click or drag
|
||||
// may have an additional effect in the scrubber.
|
||||
event.Skip();
|
||||
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||
}
|
||||
|
||||
if (!mAutoScrolling) {
|
||||
mMouseMostRecentX = event.m_x;
|
||||
mMouseMostRecentY = event.m_y;
|
||||
|
@ -34,7 +34,7 @@ class AUDACITY_DLL_API TrackPanelListener /* not final */ {
|
||||
virtual void TP_ScrollLeft() = 0;
|
||||
virtual void TP_ScrollRight() = 0;
|
||||
virtual void TP_ScrollWindow(double scrollto) = 0;
|
||||
virtual void TP_ScrollUpDown(int delta) = 0;
|
||||
virtual bool TP_ScrollUpDown(int delta) = 0;
|
||||
virtual void TP_HandleResize() = 0;
|
||||
};
|
||||
|
||||
|
@ -276,6 +276,7 @@ DEFINE_EVENT_TYPE(EVT_TOOLBAR_UPDATED)
|
||||
BEGIN_EVENT_TABLE( ToolBar, wxPanel )
|
||||
EVT_PAINT( ToolBar::OnPaint )
|
||||
EVT_ERASE_BACKGROUND( ToolBar::OnErase )
|
||||
EVT_MOUSE_EVENTS( ToolBar::OnMouseEvents )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
//
|
||||
@ -841,6 +842,13 @@ void ToolBar::OnPaint( wxPaintEvent & event )
|
||||
#endif
|
||||
}
|
||||
|
||||
void ToolBar::OnMouseEvents(wxMouseEvent &event)
|
||||
{
|
||||
// Do this hack so scrubber can detect mouse drags anywhere
|
||||
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
int ToolBar::GetResizeGrabberWidth()
|
||||
{
|
||||
return RWIDTH;
|
||||
|
@ -188,6 +188,7 @@ class ToolBar /* not final */ : public wxPanel
|
||||
|
||||
void OnErase(wxEraseEvent & event);
|
||||
void OnPaint(wxPaintEvent & event);
|
||||
void OnMouseEvents(wxMouseEvent &event);
|
||||
|
||||
protected:
|
||||
wxString mLabel;
|
||||
|
@ -64,6 +64,7 @@ BEGIN_EVENT_TABLE( ToolDock, wxPanel )
|
||||
EVT_ERASE_BACKGROUND( ToolDock::OnErase )
|
||||
EVT_PAINT( ToolDock::OnPaint )
|
||||
EVT_SIZE( ToolDock::OnSize )
|
||||
EVT_MOUSE_EVENTS( ToolDock::OnMouseEvents )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
//
|
||||
@ -556,3 +557,10 @@ void ToolDock::OnPaint( wxPaintEvent & WXUNUSED(event) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToolDock::OnMouseEvents(wxMouseEvent &event)
|
||||
{
|
||||
// Do this hack so scrubber can detect mouse drags anywhere
|
||||
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||
event.Skip();
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ class ToolDock final : public wxPanel
|
||||
void OnSize( wxSizeEvent & event );
|
||||
void OnPaint( wxPaintEvent & event );
|
||||
void OnGrabber( GrabberEvent & event );
|
||||
void OnMouseEvents(wxMouseEvent &event);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -19,6 +19,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../TrackPanelCellIterator.h"
|
||||
#include "../../commands/CommandFunctors.h"
|
||||
#include "../../toolbars/ControlToolBar.h"
|
||||
#include "../../widgets/Ruler.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -126,10 +127,12 @@ Scrubber::Scrubber(AudacityProject *project)
|
||||
wxTheApp->Connect
|
||||
(wxEVT_ACTIVATE_APP,
|
||||
wxActivateEventHandler(Scrubber::OnActivateOrDeactivateApp), NULL, this);
|
||||
mProject->PushEventHandler(this);
|
||||
}
|
||||
|
||||
Scrubber::~Scrubber()
|
||||
{
|
||||
mProject->PopEventHandler();
|
||||
if (wxTheApp)
|
||||
wxTheApp->Disconnect
|
||||
(wxEVT_ACTIVATE_APP,
|
||||
@ -180,6 +183,7 @@ namespace {
|
||||
}
|
||||
|
||||
void Scrubber::MarkScrubStart(
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
wxCoord xx
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||
, bool smoothScrolling
|
||||
@ -207,7 +211,8 @@ void Scrubber::MarkScrubStart(
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
bool Scrubber::MaybeStartScrubbing(const wxMouseEvent &event)
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
bool Scrubber::MaybeStartScrubbing(wxCoord xx)
|
||||
{
|
||||
if (mScrubStartPosition < 0)
|
||||
return false;
|
||||
@ -222,7 +227,7 @@ bool Scrubber::MaybeStartScrubbing(const wxMouseEvent &event)
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCoord position = event.m_x;
|
||||
wxCoord position = xx;
|
||||
if (abs(mScrubStartPosition - position) >= SCRUBBING_PIXEL_TOLERANCE) {
|
||||
const ViewInfo &viewInfo = mProject->GetViewInfo();
|
||||
TrackPanel *const trackPanel = mProject->GetTrackPanel();
|
||||
@ -450,6 +455,40 @@ void Scrubber::OnActivateOrDeactivateApp(wxActivateEvent &event)
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void Scrubber::OnMouse(wxMouseEvent &event)
|
||||
{
|
||||
auto isScrubbing = IsScrubbing();
|
||||
if (!isScrubbing && HasStartedScrubbing()) {
|
||||
if (!event.HasAnyModifiers() &&
|
||||
event.GetEventType() == wxEVT_MOTION) {
|
||||
|
||||
// Really start scrub if motion is far enough
|
||||
auto ruler = mProject->GetRulerPanel();
|
||||
auto xx = ruler->ScreenToClient(::wxGetMousePosition()).x;
|
||||
MaybeStartScrubbing(xx
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (isScrubbing && !event.HasAnyModifiers()) {
|
||||
if(event.LeftDown() ||
|
||||
(event.LeftIsDown() && event.Dragging())) {
|
||||
mScrubSeekPress = true;
|
||||
auto ruler = mProject->GetRulerPanel();
|
||||
auto xx = ruler->ScreenToClient(::wxGetMousePosition()).x;
|
||||
ruler->UpdateQuickPlayPos(xx);
|
||||
}
|
||||
else if (event.m_wheelRotation) {
|
||||
double steps = event.m_wheelRotation /
|
||||
(event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
|
||||
HandleScrollWheel(steps);
|
||||
}
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// class ScrubbingOverlay is responsible for drawing the speed numbers
|
||||
|
||||
@ -661,6 +700,9 @@ BEGIN_EVENT_TABLE(Scrubber, wxEvtHandler)
|
||||
EVT_MENU(CMD_ID + 1, Scrubber::OnScrollScrub)
|
||||
EVT_MENU(CMD_ID + 2, Scrubber::OnSeek)
|
||||
EVT_MENU(CMD_ID + 3, Scrubber::OnScrollSeek)
|
||||
|
||||
EVT_MOUSE_EVENTS(Scrubber::OnMouse)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
static_assert(nMenuItems == 4, "wrong number of items");
|
||||
|
@ -27,6 +27,7 @@ public:
|
||||
Scrubber(AudacityProject *project);
|
||||
~Scrubber();
|
||||
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
void MarkScrubStart(
|
||||
wxCoord xx
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||
@ -35,8 +36,11 @@ public:
|
||||
, bool alwaysSeeking // if false, can switch seeking or scrubbing
|
||||
// by mouse button state
|
||||
);
|
||||
|
||||
// Returns true iff the event should be considered consumed by this:
|
||||
bool MaybeStartScrubbing(const wxMouseEvent &event);
|
||||
// Assume xx is relative to the left edge of TrackPanel!
|
||||
bool MaybeStartScrubbing(wxCoord xx);
|
||||
|
||||
void ContinueScrubbing();
|
||||
|
||||
// This is meant to be called only from ControlToolBar
|
||||
@ -61,7 +65,6 @@ public:
|
||||
|
||||
void HandleScrollWheel(int steps);
|
||||
|
||||
void SetSeeking() { mScrubSeekPress = true; }
|
||||
bool PollIsSeeking();
|
||||
|
||||
// This returns the same as the enabled state of the menu items:
|
||||
@ -88,6 +91,7 @@ private:
|
||||
void OnActivateOrDeactivateApp(wxActivateEvent & event);
|
||||
void UncheckAllMenuItems();
|
||||
void CheckMenuItem();
|
||||
void OnMouse(wxMouseEvent &event);
|
||||
|
||||
private:
|
||||
int mScrubToken;
|
||||
|
@ -452,6 +452,8 @@ void AButton::OnMouseEvent(wxMouseEvent & event)
|
||||
GetActiveProject()->TP_DisplayStatusMessage(wxT(""));
|
||||
}
|
||||
}
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void AButton::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
|
||||
|
@ -2080,20 +2080,15 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
||||
: StatusChoice::NoChange
|
||||
);
|
||||
|
||||
// Keep Quick-Play within usable track area.
|
||||
TrackPanel *tp = mProject->GetTrackPanel();
|
||||
int mousePosX, width;
|
||||
tp->GetTracksUsableArea(&width, NULL);
|
||||
mousePosX = std::max(evt.GetX(), tp->GetLeftOffset());
|
||||
mousePosX = std::min(mousePosX, tp->GetLeftOffset() + width - 1);
|
||||
|
||||
double t0 = mTracks->GetStartTime();
|
||||
double t1 = mTracks->GetEndTime();
|
||||
double sel0 = mProject->GetSel0();
|
||||
double sel1 = mProject->GetSel1();
|
||||
|
||||
mLastMouseX = mousePosX;
|
||||
mQuickPlayPos = Pos2Time(mousePosX);
|
||||
wxCoord mousePosX = evt.GetX();
|
||||
UpdateQuickPlayPos(mousePosX);
|
||||
|
||||
// If not looping, restrict selection to end of project
|
||||
if (!inScrubZone && !evt.ShiftDown()) {
|
||||
mQuickPlayPos = std::min(t1, mQuickPlayPos);
|
||||
@ -2103,18 +2098,16 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
||||
// If already clicked for scrub, preempt the usual event handling,
|
||||
// no matter what the y coordinate.
|
||||
|
||||
if (scrubber.IsScrubbing()) {
|
||||
if(evt.LeftDown() || evt.Dragging())
|
||||
// Cause scrub in progress to jump
|
||||
scrubber.SetSeeking();
|
||||
}
|
||||
// Do this hack so scrubber can detect mouse drags anywhere
|
||||
evt.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||
|
||||
if (scrubber.IsScrubbing())
|
||||
evt.Skip();
|
||||
else if (evt.LeftDClick())
|
||||
// On the second button down, switch the pending scrub to scrolling
|
||||
scrubber.MarkScrubStart(evt.m_x, true, false);
|
||||
else if (!evt.Button(wxMOUSE_BTN_ANY)) {
|
||||
// Really start scrub if motion is far enough
|
||||
scrubber.MaybeStartScrubbing(evt);
|
||||
}
|
||||
else
|
||||
evt.Skip();
|
||||
|
||||
mQuickPlayInd = true;
|
||||
wxClientDC dc(this);
|
||||
@ -2478,6 +2471,19 @@ void AdornedRulerPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(evt))
|
||||
OnMouseEvents(e);
|
||||
}
|
||||
|
||||
void AdornedRulerPanel::UpdateQuickPlayPos(wxCoord &mousePosX)
|
||||
{
|
||||
// Keep Quick-Play within usable track area.
|
||||
TrackPanel *tp = mProject->GetTrackPanel();
|
||||
int width;
|
||||
tp->GetTracksUsableArea(&width, NULL);
|
||||
mousePosX = std::max(mousePosX, tp->GetLeftOffset());
|
||||
mousePosX = std::min(mousePosX, tp->GetLeftOffset() + width - 1);
|
||||
|
||||
mLastMouseX = mousePosX;
|
||||
mQuickPlayPos = Pos2Time(mousePosX);
|
||||
}
|
||||
|
||||
// Pop-up menus
|
||||
|
||||
void AdornedRulerPanel::ShowMenu(const wxPoint & pos)
|
||||
|
@ -312,6 +312,8 @@ public:
|
||||
void RegenerateTooltips();
|
||||
void HideQuickPlayIndicator();
|
||||
|
||||
void UpdateQuickPlayPos(wxCoord &mousPosX);
|
||||
|
||||
private:
|
||||
void OnCapture(wxCommandEvent & evt);
|
||||
void OnPaint(wxPaintEvent &evt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user