1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-05 14:18:53 +02:00

Implement selection snap lines before click, and TAB to cancel them

This commit is contained in:
Paul Licameli 2017-07-12 12:09:35 -04:00
parent b7ae012ece
commit 2150bde578
2 changed files with 100 additions and 16 deletions

View File

@ -428,14 +428,17 @@ UIHandlePtr SelectHandle::HitTest
// This handle is a little special because there may be some state to
// preserve during movement before the click.
auto old = holder.lock();
bool oldUseSnap = true;
if (old) {
// It should not have started listening to timer events
wxASSERT( !old->mTimerHandler );
oldUseSnap = old->mUseSnap;
}
const ViewInfo &viewInfo = pProject->GetViewInfo();
auto result = std::make_shared<SelectHandle>(
pTrack, *pProject->GetTracks(), st, viewInfo );
pTrack, oldUseSnap, *pProject->GetTracks(), st, viewInfo );
result = AssignUIHandlePtr(holder, result);
//Make sure we are within the selected track
@ -457,8 +460,28 @@ UIHandlePtr SelectHandle::HitTest
return result;
}
UIHandle::Result SelectHandle::NeedChangeHighlight
(const SelectHandle &oldState, const SelectHandle &newState)
{
auto useSnap = oldState.mUseSnap;
// This is guaranteed when constructing the new handle:
wxASSERT( useSnap == newState.mUseSnap );
if (!useSnap)
return 0;
auto &oldSnapState = oldState.mSnapStart;
auto &newSnapState = newState.mSnapStart;
if ( oldSnapState.Snapped() == newSnapState.Snapped() &&
(!oldSnapState.Snapped() ||
oldSnapState.outCoord == newSnapState.outCoord) )
return 0;
return RefreshCode::RefreshAll;
}
SelectHandle::SelectHandle
( const std::shared_ptr<Track> &pTrack, const TrackList &trackList,
( const std::shared_ptr<Track> &pTrack, bool useSnap,
const TrackList &trackList,
const TrackPanelMouseState &st, const ViewInfo &viewInfo )
: mpTrack{ pTrack }
, mSnapManager{ std::make_shared<SnapManager>(&trackList, &viewInfo) }
@ -472,6 +495,8 @@ SelectHandle::SelectHandle
mSnapStart.outCoord += rect.x;
else
mSnapStart.outCoord = -1;
mUseSnap = useSnap;
}
SelectHandle::~SelectHandle()
@ -497,6 +522,40 @@ namespace {
}
}
void SelectHandle::Enter(bool forward)
{
mUseSnap = forward;
bool hasSnap = HasRotation();
if (hasSnap)
// Repaint to turn the snap lines on or off
mChangeHighlight = RefreshCode::RefreshAll;
if (hasSnap && IsClicked())
// Readjust the moving selection end
AssignSelection(
::GetActiveProject()->GetViewInfo(),
mUseSnap ? mSnapEnd.outTime : mSnapEnd.timeSnappedTime,
nullptr);
}
bool SelectHandle::HasRotation() const
{
return
mSnapStart.snappedPoint || (IsClicked() && mSnapEnd.snappedPoint);
}
bool SelectHandle::Rotate(bool forward)
{
if (SelectHandle::HasRotation()) {
if (mUseSnap == forward) {
Enter(!forward);
return true;
}
}
return false;
}
UIHandle::Result SelectHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
@ -574,7 +633,8 @@ UIHandle::Result SelectHandle::Click
auto pMixerBoard = pProject->GetMixerBoard();
mSelStart = mSnapStart.outTime;
mSelStart = mUseSnap ? mSnapStart.outTime : mSnapStart.timeSnappedTime;
auto xx = viewInfo.TimeToPosition(mSelStart, mRect.x);
// I. Shift-click adjusts an existing selection
if (bShiftDown || bCtrlDown) {
@ -595,7 +655,7 @@ UIHandle::Result SelectHandle::Click
double value;
// Shift-click, choose closest boundary
SelectionBoundary boundary =
ChooseBoundary(viewInfo, event.m_x, event.m_y, pTrack, mRect, false, false, &value);
ChooseBoundary(viewInfo, xx, event.m_y, pTrack, mRect, false, false, &value);
mSelectionBoundary = boundary;
switch (boundary) {
case SBLeft:
@ -607,7 +667,7 @@ UIHandle::Result SelectHandle::Click
mFreqSelMode = FREQ_SEL_INVALID;
#endif
mSelStartValid = true;
if (!mSnapStart.Snapped())
if (!(mUseSnap && mSnapStart.Snapped()))
mSelStart = value;
AdjustSelection(pProject, viewInfo, event.m_x, mRect.x, pTrack);
break;
@ -689,7 +749,7 @@ UIHandle::Result SelectHandle::Click
// Not shift-down, choose boundary only within snapping
double value;
SelectionBoundary boundary =
ChooseBoundary(viewInfo, event.m_x, event.m_y, pTrack, mRect, true, true, &value);
ChooseBoundary(viewInfo, xx, event.m_y, pTrack, mRect, true, true, &value);
mSelectionBoundary = boundary;
switch (boundary) {
case SBNone:
@ -703,7 +763,7 @@ UIHandle::Result SelectHandle::Click
mFreqSelMode = FREQ_SEL_INVALID;
#endif
mSelStartValid = true;
if (!mSnapStart.Snapped())
if (!(mUseSnap && mSnapStart.Snapped()))
mSelStart = value;
break;
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
@ -854,6 +914,9 @@ UIHandle::Result SelectHandle::Drag
HitTestPreview SelectHandle::Preview
(const TrackPanelMouseState &st, const AudacityProject *pProject)
{
if (!HasRotation())
mUseSnap = true;
auto pTrack = mpTrack.lock();
if (!pTrack)
return {};
@ -871,6 +934,10 @@ HitTestPreview SelectHandle::Preview
const ViewInfo &viewInfo = pProject->GetViewInfo();
auto &state = st.state;
auto time = mUseSnap ? mSnapStart.outTime : mSnapStart.timeSnappedTime;
auto xx = viewInfo.TimeToPosition(time, mRect.x);
const bool bMultiToolMode =
pProject->GetToolsToolBar()->IsDown(multiTool);
@ -895,7 +962,6 @@ HitTestPreview SelectHandle::Preview
!viewInfo.bAdjustSelectionEdges)
;
else {
const auto &state = st.state;
const wxRect &rect = st.rect;
const bool bShiftDown = state.ShiftDown();
const bool bCtrlDown = state.ControlDown();
@ -905,7 +971,7 @@ HitTestPreview SelectHandle::Preview
// choose boundaries only in snapping tolerance,
// and may choose center.
SelectionBoundary boundary =
ChooseBoundary(viewInfo, state.m_x, state.m_y, pTrack.get(), rect, !bModifierDown, !bModifierDown);
ChooseBoundary(viewInfo, xx, state.m_y, pTrack.get(), rect, !bModifierDown, !bModifierDown);
SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor);
}
@ -929,13 +995,12 @@ HitTestPreview SelectHandle::Preview
if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges)
;
else {
const auto &state = st.state;
const wxRect &rect = st.rect;
const bool bShiftDown = state.ShiftDown();
const bool bCtrlDown = state.ControlDown();
const bool bModifierDown = bShiftDown || bCtrlDown;
SelectionBoundary boundary = ChooseBoundary(
viewInfo, state.m_x, state.m_y, pTrack.get(), rect, !bModifierDown, !bModifierDown);
viewInfo, xx, state.m_y, pTrack.get(), rect, !bModifierDown, !bModifierDown);
SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor);
}
@ -962,7 +1027,7 @@ UIHandle::Result SelectHandle::Release
mSelectionStateChanger.reset();
}
if (mSnapStart.outCoord != -1 || mSnapEnd.outCoord != -1)
if (mUseSnap && (mSnapStart.outCoord != -1 || mSnapEnd.outCoord != -1))
return RefreshAll;
else
return RefreshNone;
@ -985,7 +1050,7 @@ void SelectHandle::DrawExtras
{
if (pass == Panel) {
// Draw snap guidelines if we have any
if ( mSnapManager )
if ( mUseSnap && mSnapManager )
mSnapManager->Draw( dc, mSnapStart.outCoord, mSnapEnd.outCoord );
}
}
@ -1130,7 +1195,8 @@ void SelectHandle::AdjustSelection
bool rightEdge = (selend > mSelStart);
mSnapEnd = mSnapManager->Snap(pTrack.get(), selend, rightEdge);
if (mSnapEnd.Snapped()) {
selend = mSnapEnd.outTime;
if (mUseSnap)
selend = mSnapEnd.outTime;
if (mSnapEnd.snappedPoint)
mSnapEnd.outCoord += trackLeftEdge;
}
@ -1147,7 +1213,12 @@ void SelectHandle::AdjustSelection
mSnapEnd.outCoord = -1;
}
}
AssignSelection(viewInfo, selend, pTrack.get());
}
void SelectHandle::AssignSelection
(ViewInfo &viewInfo, double selend, Track *pTrack)
{
double sel0, sel1;
if (mSelStart < selend) {
sel0 = mSelStart;
@ -1163,7 +1234,7 @@ void SelectHandle::AdjustSelection
//On-Demand: check to see if there is an OD thing associated with this track. If so we want to update the focal point for the task.
if (pTrack && (pTrack->GetKind() == Track::Wave) && ODManager::IsInstanceCreated())
ODManager::Instance()->DemandTrackUpdate
(static_cast<WaveTrack*>(pTrack.get()),sel0); //sel0 is sometimes less than mSelStart
(static_cast<WaveTrack*>(pTrack),sel0); //sel0 is sometimes less than mSelStart
}
void SelectHandle::StartFreqSelection(ViewInfo &viewInfo,

View File

@ -35,7 +35,8 @@ class SelectHandle : public UIHandle
public:
explicit SelectHandle
(const std::shared_ptr<Track> &pTrack, const TrackList &trackList,
(const std::shared_ptr<Track> &pTrack, bool useSnap,
const TrackList &trackList,
const TrackPanelMouseState &st, const ViewInfo &viewInfo);
// This always hits, but details of the hit vary with mouse position and
@ -51,6 +52,12 @@ public:
bool IsClicked() const;
void Enter(bool forward) override;
bool HasRotation() const override;
bool Rotate(bool forward) override;
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
@ -72,6 +79,10 @@ public:
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
override;
static UIHandle::Result NeedChangeHighlight
(const SelectHandle &oldState,
const SelectHandle &newState);
private:
void Connect(AudacityProject *pProject);
@ -80,6 +91,7 @@ private:
(AudacityProject *pProject,
ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge,
Track *pTrack);
void AssignSelection(ViewInfo &viewInfo, double selend, Track *pTrack);
void StartFreqSelection
(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge,
@ -115,6 +127,7 @@ private:
std::shared_ptr<SnapManager> mSnapManager;
SnapResults mSnapStart, mSnapEnd;
bool mUseSnap{ true };
bool mSelStartValid{};
double mSelStart{ 0.0 };