1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-19 09:01:15 +02:00

Improve selection handling in Quick-Play

This commit is contained in:
Steve Daulton
2015-05-05 12:55:59 +01:00
parent 1ad878771f
commit c487b920ca
2 changed files with 108 additions and 68 deletions

View File

@@ -1640,7 +1640,9 @@ AdornedRulerPanel::AdornedRulerPanel(wxWindow* parent,
mPlayRegionEnd = -1; mPlayRegionEnd = -1;
mOldPlayRegionStart = -1; mOldPlayRegionStart = -1;
mOldPlayRegionEnd = -1; mOldPlayRegionEnd = -1;
mLeftDownClick = -1;
mMouseEventState = mesNone; mMouseEventState = mesNone;
mIsDragging = false;
mBuffer = new wxBitmap( 1, 1 ); mBuffer = new wxBitmap( 1, 1 );
mViewInfo = viewinfo; mViewInfo = viewinfo;
@@ -1666,7 +1668,7 @@ AdornedRulerPanel::AdornedRulerPanel(wxWindow* parent,
mIsRecording = false; mIsRecording = false;
mTimelineToolTip = gPrefs->Read(wxT("/QuickPlay/ToolTips"), wxT("Enabled")) == wxT("Enabled"); mTimelineToolTip = gPrefs->Read(wxT("/QuickPlay/ToolTips"), wxT("Enabled")) == wxT("Enabled");
mPlayRegionDragsSelection = gPrefs->Read(wxT("/QuickPlay/DragLoopSelection"), wxT("Enabled")) == wxT("Enabled"); mPlayRegionDragsSelection = gPrefs->Read(wxT("/QuickPlay/DragSelection"), wxT("Enabled")) == wxT("Enabled");
mQuickPlayEnabled = gPrefs->Read(wxT("/QuickPlay/QuickPlayEnabled"), wxT("Enabled")) == wxT("Enabled"); mQuickPlayEnabled = gPrefs->Read(wxT("/QuickPlay/QuickPlayEnabled"), wxT("Enabled")) == wxT("Enabled");
#if wxUSE_TOOLTIPS #if wxUSE_TOOLTIPS
@@ -1829,13 +1831,11 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
if (mIsRecording) if (mIsRecording)
return; return;
bool isLocked = mProject->IsPlayRegionLocked(); // Store the initial play region state
if(mMouseEventState == mesNone) {
if (isLocked && evt.LeftDown()) {
mPlayRegionLock = true;
mOldPlayRegionStart = mPlayRegionStart; mOldPlayRegionStart = mPlayRegionStart;
mOldPlayRegionEnd = mPlayRegionEnd; mOldPlayRegionEnd = mPlayRegionEnd;
mProject->OnUnlockPlayRegion(); mPlayRegionLock = mProject->IsPlayRegionLocked();
} }
// Keep Quick-Play within usable track area. // Keep Quick-Play within usable track area.
@@ -1845,22 +1845,18 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
mousePosX = wxMax(evt.GetX(), tp->GetLeftOffset()); mousePosX = wxMax(evt.GetX(), tp->GetLeftOffset());
mousePosX = wxMin(mousePosX, tp->GetLeftOffset() + width - 1); mousePosX = wxMin(mousePosX, tp->GetLeftOffset() + width - 1);
bool isWithinStart = IsWithinMarker(mousePosX, mPlayRegionStart); bool isWithinStart = IsWithinMarker(mousePosX, mOldPlayRegionStart);
bool isWithinEnd = IsWithinMarker(mousePosX, mPlayRegionEnd); bool isWithinEnd = IsWithinMarker(mousePosX, mOldPlayRegionEnd);
bool isWithinClick = (mLeftDownClick >= 0) && IsWithinMarker(mousePosX, mLeftDownClick);
bool canDragSel = !mPlayRegionLock && mPlayRegionDragsSelection; bool canDragSel = !mPlayRegionLock && mPlayRegionDragsSelection;
mLastMouseX = mousePosX;
mQuickPlayPos = Pos2Time(mousePosX);
double t0 = mProject->GetTracks()->GetStartTime(); double t0 = mProject->GetTracks()->GetStartTime();
double t1 = mProject->GetTracks()->GetEndTime(); double t1 = mProject->GetTracks()->GetEndTime();
double sel0 = mProject->GetSel0(); double sel0 = mProject->GetSel0();
double sel1 = mProject->GetSel1(); double sel1 = mProject->GetSel1();
// Restrict Quick-Play region to where there is something to play or is selected. mLastMouseX = mousePosX;
mQuickPlayPos = wxMax(0.0, mQuickPlayPos); mQuickPlayPos = Pos2Time(mousePosX);
// If not looping, restrict selection to end of project // If not looping, restrict selection to end of project
if (!evt.ShiftDown()) mQuickPlayPos = wxMin(t1, mQuickPlayPos); if (!evt.ShiftDown()) mQuickPlayPos = wxMin(t1, mQuickPlayPos);
@@ -1876,8 +1872,6 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
mQuickPlayInd = false; mQuickPlayInd = false;
wxClientDC cdc(this); wxClientDC cdc(this);
DrawQuickPlayIndicator(&cdc, true); DrawQuickPlayIndicator(&cdc, true);
Refresh(false); Refresh(false);
} }
else if (mQuickPlayEnabled) { else if (mQuickPlayEnabled) {
@@ -1895,6 +1889,7 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
SetCursor(wxCursor(wxCURSOR_HAND)); SetCursor(wxCursor(wxCURSOR_HAND));
} }
if (evt.RightDown()) { if (evt.RightDown()) {
ShowMenu(evt.GetPosition()); ShowMenu(evt.GetPosition());
} }
@@ -1902,78 +1897,109 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
if (!mQuickPlayEnabled) if (!mQuickPlayEnabled)
return; return;
if (mSnapManager) {
// Create a new snap manager in case any snap-points have changed HandleSnapping();
delete mSnapManager;
}
mSnapManager = new SnapManager(mProject->GetTracks(), NULL,
mViewInfo->zoom,
QUICK_PLAY_SNAP_PIXEL);
bool snappedPoint, snappedTime;
mIsSnapped = (mSnapManager->Snap(NULL, mQuickPlayPos, false,
&mQuickPlayPos, &snappedPoint, &snappedTime));
if (evt.LeftDown()) if (evt.LeftDown())
{ {
mButtonDownMousePos = mousePosX; // Temporarily unlock locked play region
if (mPlayRegionLock && evt.LeftDown()) {
//mPlayRegionLock = true;
mProject->OnUnlockPlayRegion();
}
if (isWithinStart && isWithinEnd) { mLeftDownClick = mQuickPlayPos;
// Both could be selected, check which marker is nearer isWithinClick = IsWithinMarker(mousePosX, mLeftDownClick);
if (fabs(mQuickPlayPos - mPlayRegionStart) < fabs(mQuickPlayPos - mPlayRegionEnd))
mMouseEventState = mesDraggingPlayRegionStart; if (isWithinStart || isWithinEnd) {
else // If Quick-Play is playing from a point, we need to treat it as a click
mMouseEventState = mesDraggingPlayRegionEnd; // not as dragging.
if (mOldPlayRegionStart == mOldPlayRegionEnd)
mMouseEventState = mesSelectingPlayRegionClick;
// otherwise check which marker is nearer
else {
if (fabs(mQuickPlayPos - mOldPlayRegionStart) < fabs(mQuickPlayPos - mOldPlayRegionEnd))
mMouseEventState = mesDraggingPlayRegionStart;
else
mMouseEventState = mesDraggingPlayRegionEnd;
}
} }
else if (isWithinStart)
mMouseEventState = mesDraggingPlayRegionStart;
else if (isWithinEnd)
mMouseEventState = mesDraggingPlayRegionEnd;
else { else {
// First, we enter "click" mode to avoid selecting a small range // Clicked but not yet dragging
// accidentially
mMouseEventState = mesSelectingPlayRegionClick; mMouseEventState = mesSelectingPlayRegionClick;
mPlayRegionStart = mQuickPlayPos;
mPlayRegionEnd = mQuickPlayPos;
Refresh();
} }
// Check if we are dragging BEFORE CaptureMouse. // Check if we are dragging BEFORE CaptureMouse.
if (mMouseEventState != mesNone) if (mMouseEventState != mesNone)
SetCursor(wxCursor(wxCURSOR_SIZEWE)); SetCursor(wxCursor(wxCURSOR_SIZEWE));
CaptureMouse(); CaptureMouse();
} }
switch (mMouseEventState) switch (mMouseEventState)
{ {
case mesNone: case mesNone:
// do nothing // If close to either end of play region, snap to closest
if (isWithinStart || isWithinEnd) {
if (fabs(mQuickPlayPos - mOldPlayRegionStart) < fabs(mQuickPlayPos - mOldPlayRegionEnd))
mQuickPlayPos = mOldPlayRegionStart;
else
mQuickPlayPos = mOldPlayRegionEnd;
}
break; break;
case mesDraggingPlayRegionStart: case mesDraggingPlayRegionStart:
// Don't start dragging until beyond tollerance initial playback start
if (!mIsDragging && isWithinStart)
mQuickPlayPos = mOldPlayRegionStart;
else
mIsDragging = true;
// avoid accidental tiny selection
if (isWithinEnd)
mQuickPlayPos = mOldPlayRegionEnd;
mPlayRegionStart = mQuickPlayPos; mPlayRegionStart = mQuickPlayPos;
if (canDragSel) { if (canDragSel) {
DragSelection(); DragSelection();
} }
Refresh();
break; break;
case mesDraggingPlayRegionEnd: case mesDraggingPlayRegionEnd:
if (!mIsDragging && isWithinEnd)
mQuickPlayPos = mOldPlayRegionEnd;
else
mIsDragging = true;
if (isWithinStart)
mQuickPlayPos = mOldPlayRegionStart;
mPlayRegionEnd = mQuickPlayPos; mPlayRegionEnd = mQuickPlayPos;
if (canDragSel) { if (canDragSel) {
DragSelection(); DragSelection();
} }
Refresh();
break; break;
case mesSelectingPlayRegionClick: case mesSelectingPlayRegionClick:
if (abs(mousePosX - mButtonDownMousePos) > SELECT_TOLERANCE_PIXEL) // Don't start dragging until mouse is beyond tollerance of initial click.
{ if (isWithinClick || mLeftDownClick == -1) {
// User moved mouse at least SELECT_TOLERANCE_PIXEL, so change mQuickPlayPos = mLeftDownClick;
// from "click" mode to "range" mode to allow selecting a range mPlayRegionStart = mLeftDownClick;
mPlayRegionEnd = mLeftDownClick;
}
else {
mMouseEventState = mesSelectingPlayRegionRange; mMouseEventState = mesSelectingPlayRegionRange;
mPlayRegionEnd = mQuickPlayPos;
Refresh();
} }
break; break;
case mesSelectingPlayRegionRange: case mesSelectingPlayRegionRange:
mPlayRegionEnd = mQuickPlayPos; if (isWithinClick) {
Refresh(); mQuickPlayPos = mLeftDownClick;
}
if (mQuickPlayPos < mLeftDownClick) {
mPlayRegionStart = mQuickPlayPos;
mPlayRegionEnd = mLeftDownClick;
}
else {
mPlayRegionEnd = mQuickPlayPos;
mPlayRegionStart = mLeftDownClick;
}
if (canDragSel) {
DragSelection();
}
break; break;
} }
@@ -1986,13 +2012,7 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
if (HasCapture()) if (HasCapture())
ReleaseMouse(); ReleaseMouse();
int playlength = Seconds2Pixels(fabs(mPlayRegionEnd - mPlayRegionStart)); if (mPlayRegionEnd < mPlayRegionStart) {
if (playlength < SELECT_TOLERANCE_PIXEL) {
// Mouse has slipped back within tolerance range.
// We have been dragging mPlayRegionEnd, so snap it back to mPlayRegionStart.
mPlayRegionEnd = mPlayRegionStart;
}
else if (mPlayRegionEnd < mPlayRegionStart) {
// Swap values to ensure mPlayRegionStart < mPlayRegionEnd // Swap values to ensure mPlayRegionStart < mPlayRegionEnd
double tmp = mPlayRegionStart; double tmp = mPlayRegionStart;
mPlayRegionStart = mPlayRegionEnd; mPlayRegionStart = mPlayRegionEnd;
@@ -2023,8 +2043,6 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
// Start / Restart playback on left click. // Start / Restart playback on left click.
bool startPlaying = (mPlayRegionStart >= 0); bool startPlaying = (mPlayRegionStart >= 0);
mMouseEventState = mesNone;
if (startPlaying) { if (startPlaying) {
ControlToolBar* ctb = mProject->GetControlToolBar(); ControlToolBar* ctb = mProject->GetControlToolBar();
ctb->StopPlaying(); ctb->StopPlaying();
@@ -2054,14 +2072,14 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions()); AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
options.playLooped = (loopEnabled && evt.ShiftDown()); options.playLooped = (loopEnabled && evt.ShiftDown());
if (!evt.ControlDown()) if (!evt.CmdDown()) // Use CmdDown rather than ControlDown. See bug 746
options.pStartTime = &mPlayRegionStart; options.pStartTime = &mPlayRegionStart;
else else
options.timeTrack = NULL; options.timeTrack = NULL;
ctb->PlayPlayRegion((SelectedRegion(start, end)), ctb->PlayPlayRegion((SelectedRegion(start, end)),
options, options,
evt.ControlDown(), evt.CmdDown(),
false, false,
true); true);
@@ -2070,6 +2088,10 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
DoDrawPlayRegion(&cdc); DoDrawPlayRegion(&cdc);
} }
mMouseEventState = mesNone;
mIsDragging = false;
mLeftDownClick = -1;
if (mPlayRegionLock) { if (mPlayRegionLock) {
// Restore Locked Play region // Restore Locked Play region
SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd); SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd);
@@ -2148,7 +2170,7 @@ void AdornedRulerPanel::OnToggleQuickPlay(wxCommandEvent& evt)
void AdornedRulerPanel::OnSyncSelToQuickPlay(wxCommandEvent& evt) void AdornedRulerPanel::OnSyncSelToQuickPlay(wxCommandEvent& evt)
{ {
mPlayRegionDragsSelection = (mPlayRegionDragsSelection)? false : true; mPlayRegionDragsSelection = (mPlayRegionDragsSelection)? false : true;
gPrefs->Write(wxT("/QuickPlay/DragLoopSelection"), mPlayRegionDragsSelection ? wxT("Enabled") : wxT("Disabled")); gPrefs->Write(wxT("/QuickPlay/DragSelection"), mPlayRegionDragsSelection ? wxT("Enabled") : wxT("Disabled"));
gPrefs->Flush(); gPrefs->Flush();
} }
@@ -2166,6 +2188,22 @@ void AdornedRulerPanel::DragSelection()
mProject->GetTrackPanel()->TrackPanel::Refresh(false); mProject->GetTrackPanel()->TrackPanel::Refresh(false);
} }
void AdornedRulerPanel::HandleSnapping()
{
if (mSnapManager) {
// Create a new snap manager in case any snap-points have changed
delete mSnapManager;
}
mSnapManager = new SnapManager(mProject->GetTracks(), NULL,
mViewInfo->zoom,
QUICK_PLAY_SNAP_PIXEL);
bool snappedPoint, snappedTime;
mIsSnapped = (mSnapManager->Snap(NULL, mQuickPlayPos, false,
&mQuickPlayPos, &snappedPoint, &snappedTime));
}
void AdornedRulerPanel::OnTimelineToolTips(wxCommandEvent& evt) void AdornedRulerPanel::OnTimelineToolTips(wxCommandEvent& evt)
{ {
mTimelineToolTip = (mTimelineToolTip)? false : true; mTimelineToolTip = (mTimelineToolTip)? false : true;

View File

@@ -327,6 +327,7 @@ private:
// //
void ShowMenu(const wxPoint & pos); void ShowMenu(const wxPoint & pos);
void DragSelection(); void DragSelection();
void HandleSnapping();
void OnToggleQuickPlay(wxCommandEvent &evt); void OnToggleQuickPlay(wxCommandEvent &evt);
void OnSyncSelToQuickPlay(wxCommandEvent &evt); void OnSyncSelToQuickPlay(wxCommandEvent &evt);
void OnTimelineToolTips(wxCommandEvent &evt); void OnTimelineToolTips(wxCommandEvent &evt);
@@ -347,8 +348,9 @@ private:
}; };
MouseEventState mMouseEventState; MouseEventState mMouseEventState;
int mButtonDownMousePos; double mLeftDownClick; // click position in seconds
int mLastMouseX; int mLastMouseX; // Pixel position
bool mIsDragging;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };