mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-15 16:17:41 +02:00
Implement TAB key rotation among hit targets...
... The old effect of TAB -- to rotate the selected label, when a Label track has focus -- is still available, but only when the pointer is not on a text box or a label glyph. Some of the cases where this might make a difference: Alternate the note track stretch cursor, or label glyph, or text box, with selection. Rotate among envelope, draw, and selection in WaveTrack and multi tool.
This commit is contained in:
commit
c1cd324848
@ -1386,7 +1386,7 @@ void AudacityProject::RedrawProject(const bool bForceWaveTracks /*= false*/)
|
||||
|
||||
void AudacityProject::RefreshCursor()
|
||||
{
|
||||
mTrackPanel->HandleCursorForLastMouseState();
|
||||
mTrackPanel->HandleCursorForPresentMouseState();
|
||||
}
|
||||
|
||||
void AudacityProject::SetSel0(double newSel0)
|
||||
|
@ -757,7 +757,7 @@ void TrackPanel::Uncapture(wxMouseEvent *pEvent)
|
||||
{
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
HandleMotion( pEvent );
|
||||
HandleMotion( *pEvent );
|
||||
}
|
||||
|
||||
void TrackPanel::CancelDragging()
|
||||
@ -812,14 +812,9 @@ void TrackPanel::UpdateMouseState(const wxMouseState &state)
|
||||
|
||||
void TrackPanel::HandleModifierKey()
|
||||
{
|
||||
// Get the button and key states
|
||||
auto state = ::wxGetMouseState();
|
||||
// Remap the position
|
||||
state.SetPosition(this->ScreenToClient(state.GetPosition()));
|
||||
|
||||
UpdateMouseState(state);
|
||||
HandleCursorForLastMouseState();
|
||||
HandleCursorForPresentMouseState();
|
||||
}
|
||||
|
||||
void TrackPanel::HandlePageUpKey()
|
||||
{
|
||||
mListener->TP_ScrollWindow(2 * mViewInfo->h - GetScreenEndTime());
|
||||
@ -830,12 +825,19 @@ void TrackPanel::HandlePageDownKey()
|
||||
mListener->TP_ScrollWindow(GetScreenEndTime());
|
||||
}
|
||||
|
||||
void TrackPanel::HandleCursorForLastMouseState()
|
||||
void TrackPanel::HandleCursorForPresentMouseState(bool doHit)
|
||||
{
|
||||
// Come here on modifier key or mouse button transitions,
|
||||
// or on starting or stopping of play or record,
|
||||
// or change of toolbar button,
|
||||
// and change the cursor appropriately.
|
||||
HandleMotion( &mLastMouseState );
|
||||
|
||||
// Get the button and key states
|
||||
auto state = ::wxGetMouseState();
|
||||
// Remap the position
|
||||
state.SetPosition(this->ScreenToClient(state.GetPosition()));
|
||||
|
||||
HandleMotion( state, doHit );
|
||||
}
|
||||
|
||||
bool TrackPanel::IsAudioActive()
|
||||
@ -852,45 +854,51 @@ bool TrackPanel::IsAudioActive()
|
||||
/// may cause the appropriate cursor and message to change.
|
||||
/// As this procedure checks which region the mouse is over, it is
|
||||
/// appropriate to establish the message in the status bar.
|
||||
void TrackPanel::HandleMotion( wxMouseState *pState )
|
||||
void TrackPanel::HandleMotion( wxMouseState &inState, bool doHit )
|
||||
{
|
||||
wxMouseState dummy;
|
||||
if (!pState)
|
||||
pState = &dummy;
|
||||
else
|
||||
UpdateMouseState( *pState ), pState = &mLastMouseState;
|
||||
auto &state = *pState;
|
||||
UpdateMouseState( inState );
|
||||
|
||||
const auto foundCell = FindCell( state.m_x, state.m_y );
|
||||
const auto foundCell = FindCell( inState.m_x, inState.m_y );
|
||||
auto &track = foundCell.pTrack;
|
||||
auto &rect = foundCell.rect;
|
||||
auto &pCell = foundCell.pCell;
|
||||
const TrackPanelMouseState tpmState{ state, rect, pCell };
|
||||
HandleMotion( tpmState );
|
||||
const TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
|
||||
HandleMotion( tpmState, doHit );
|
||||
}
|
||||
|
||||
void TrackPanel::HandleMotion( const TrackPanelMouseState &tpmState )
|
||||
void TrackPanel::HandleMotion
|
||||
( const TrackPanelMouseState &tpmState, bool doHit )
|
||||
{
|
||||
auto handle = mUIHandle;
|
||||
|
||||
auto oldHandle = mLastHitTest;
|
||||
auto oldCell = mLastCell.lock();
|
||||
auto newCell = tpmState.pCell;
|
||||
|
||||
std::shared_ptr<Track> newTrack;
|
||||
if ( newCell )
|
||||
newTrack = static_cast<CommonTrackPanelCell*>( newCell.get() )->FindTrack();
|
||||
|
||||
std::shared_ptr<Track> oldTrack;
|
||||
if ( oldCell )
|
||||
oldTrack = static_cast<CommonTrackPanelCell*>( oldCell.get() )->FindTrack();
|
||||
newTrack = static_cast<CommonTrackPanelCell*>( newCell.get() )->
|
||||
FindTrack();
|
||||
|
||||
wxString tip{};
|
||||
wxCursor *pCursor{};
|
||||
unsigned refreshCode = 0;
|
||||
|
||||
if ( !mUIHandle ) {
|
||||
if ( ! doHit ) {
|
||||
// Dragging or not
|
||||
handle = Target();
|
||||
|
||||
// Assume cell does not change but target does
|
||||
refreshCode = mMouseOverUpdateFlags;
|
||||
mMouseOverUpdateFlags = 0;
|
||||
}
|
||||
else if ( !mUIHandle ) {
|
||||
// Not yet dragging.
|
||||
|
||||
auto oldCell = mLastCell.lock();
|
||||
std::shared_ptr<Track> oldTrack;
|
||||
if ( oldCell )
|
||||
oldTrack = static_cast<CommonTrackPanelCell*>( oldCell.get() )->
|
||||
FindTrack();
|
||||
|
||||
unsigned updateFlags = mMouseOverUpdateFlags;
|
||||
|
||||
// First check whether crossing cell to cell
|
||||
@ -906,19 +914,32 @@ void TrackPanel::HandleMotion( const TrackPanelMouseState &tpmState )
|
||||
}
|
||||
}
|
||||
|
||||
auto oldHandle = Target();
|
||||
|
||||
// Now do the
|
||||
// UIHANDLE HIT TEST !
|
||||
auto targets = newCell->HitTest(tpmState, GetProject());
|
||||
mTargets = newCell->HitTest(tpmState, GetProject());
|
||||
|
||||
// No use, yet, of any but the first target
|
||||
handle = targets.empty() ? UIHandlePtr{} : targets[0];
|
||||
mTarget = 0;
|
||||
|
||||
// Find the old target's new place if we can
|
||||
if (oldHandle) {
|
||||
auto begin = mTargets.begin(), end = mTargets.end(),
|
||||
iter = std::find(begin, end, oldHandle);
|
||||
if (iter != end)
|
||||
mTarget = iter - begin;
|
||||
}
|
||||
|
||||
handle = Target();
|
||||
|
||||
mLastCell = newCell;
|
||||
mLastHitTest = handle;
|
||||
|
||||
if (!oldCell && oldHandle != handle)
|
||||
// Did not move cell to cell, but did change the target
|
||||
refreshCode = updateFlags;
|
||||
|
||||
if (handle)
|
||||
handle->Enter();
|
||||
}
|
||||
|
||||
// UIHANDLE PREVIEW
|
||||
@ -944,6 +965,21 @@ void TrackPanel::HandleMotion( const TrackPanelMouseState &tpmState )
|
||||
this, GetRuler(), newTrack.get(), newTrack.get(), refreshCode);
|
||||
}
|
||||
|
||||
bool TrackPanel::HasRotation() const
|
||||
{
|
||||
// Is there a nontrivial TAB key rotation?
|
||||
return !mUIHandle && mTargets.size() > 1;
|
||||
}
|
||||
|
||||
void TrackPanel::RotateTarget()
|
||||
{
|
||||
auto size = mTargets.size();
|
||||
if (size > 1) {
|
||||
mTarget = (mTarget + 1) % size;
|
||||
Target()->Enter();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackPanel::UpdateSelectionDisplay()
|
||||
{
|
||||
// Full refresh since the label area may need to indicate
|
||||
@ -1036,7 +1072,7 @@ void TrackPanel::OnPlayback(wxCommandEvent &e)
|
||||
// Starting or stopping of play or record affects some cursors.
|
||||
// Start or stop is in progress now, not completed; so delay the cursor
|
||||
// change until next idle time.
|
||||
CallAfter( [this] { HandleCursorForLastMouseState(); } );
|
||||
CallAfter( [this] { HandleCursorForPresentMouseState(); } );
|
||||
}
|
||||
|
||||
// The tracks positions within the list have changed, so update the vertical
|
||||
@ -1292,13 +1328,20 @@ void TrackPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
|
||||
this, mRuler, pTrack.get(), pTrack.get(), result);
|
||||
}
|
||||
|
||||
/// Filter captured keys typed into LabelTracks.
|
||||
void TrackPanel::OnCaptureKey(wxCommandEvent & event)
|
||||
{
|
||||
wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
|
||||
if ( WXK_ESCAPE != kevent->GetKeyCode() )
|
||||
const auto code = kevent->GetKeyCode();
|
||||
if ( WXK_ESCAPE != code )
|
||||
HandleInterruptedDrag();
|
||||
|
||||
if ( WXK_TAB == code && HasRotation() ) {
|
||||
// Override what the cell might do, don't call its CaptureKey;
|
||||
// Also override TAB navigation in wxWidgets, by not skipping
|
||||
event.Skip(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Track * const t = GetFocusedTrack();
|
||||
if (t) {
|
||||
const unsigned refreshResult =
|
||||
@ -1340,6 +1383,15 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
||||
case WXK_PAGEDOWN:
|
||||
HandlePageDownKey();
|
||||
return;
|
||||
|
||||
case WXK_TAB:
|
||||
if ( HasRotation() ) {
|
||||
RotateTarget();
|
||||
HandleCursorForPresentMouseState(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
Track *const t = GetFocusedTrack();
|
||||
@ -1554,7 +1606,7 @@ try
|
||||
// consider it not a drag, even if button is down during motion, if
|
||||
// mUIHandle is null, as it becomes during interrupted drag
|
||||
// (e.g. by hitting space to play while dragging an envelope point)
|
||||
HandleMotion( &event );
|
||||
HandleMotion( event );
|
||||
else if ( event.ButtonDown() || event.ButtonDClick() )
|
||||
HandleClick( tpmEvent );
|
||||
|
||||
|
@ -334,7 +334,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
||||
Track *GetFocusedTrack();
|
||||
void SetFocusedTrack(Track *t);
|
||||
|
||||
void HandleCursorForLastMouseState();
|
||||
void HandleCursorForPresentMouseState(bool doHit = true);
|
||||
|
||||
void UpdateVRulers();
|
||||
void UpdateVRuler(Track *t);
|
||||
@ -377,8 +377,9 @@ protected:
|
||||
};
|
||||
FoundCell FindCell(int mouseX, int mouseY);
|
||||
|
||||
void HandleMotion( wxMouseState *pState );
|
||||
void HandleMotion( const TrackPanelMouseState &tpmState );
|
||||
void HandleMotion( wxMouseState &state, bool doHit = true );
|
||||
void HandleMotion
|
||||
( const TrackPanelMouseState &tpmState, bool doHit = true );
|
||||
|
||||
// If label, rectangle includes track control panel only.
|
||||
// If !label, rectangle includes all of that, and the vertical ruler, and
|
||||
@ -524,13 +525,17 @@ protected:
|
||||
|
||||
protected:
|
||||
std::weak_ptr<TrackPanelCell> mLastCell;
|
||||
UIHandlePtr mLastHitTest;
|
||||
std::vector<UIHandlePtr> mTargets;
|
||||
size_t mTarget {};
|
||||
unsigned mMouseOverUpdateFlags{};
|
||||
|
||||
public:
|
||||
UIHandlePtr Target()
|
||||
{
|
||||
return mLastHitTest;
|
||||
if (mTargets.size())
|
||||
return mTargets[mTarget];
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -539,10 +544,15 @@ protected:
|
||||
// Forget the rotation of hit test candidates when the mouse moves from
|
||||
// cell to cell or outside of the TrackPanel entirely.
|
||||
mLastCell.reset();
|
||||
mLastHitTest = {};
|
||||
mTargets.clear();
|
||||
mTarget = 0;
|
||||
mMouseOverUpdateFlags = 0;
|
||||
}
|
||||
|
||||
bool HasRotation() const;
|
||||
|
||||
void RotateTarget();
|
||||
|
||||
std::weak_ptr<Track> mpClickedTrack;
|
||||
UIHandlePtr mUIHandle;
|
||||
|
||||
|
@ -15,6 +15,10 @@ UIHandle::~UIHandle()
|
||||
{
|
||||
}
|
||||
|
||||
void UIHandle::Enter()
|
||||
{
|
||||
}
|
||||
|
||||
void UIHandle::DrawExtras
|
||||
(DrawingPass, wxDC *, const wxRegion &, const wxRect &)
|
||||
{
|
||||
|
@ -47,6 +47,10 @@ public:
|
||||
|
||||
virtual ~UIHandle() = 0;
|
||||
|
||||
// Before clicking, the handle is notified that it has been "hit"
|
||||
// Default does nothing.
|
||||
virtual void Enter();
|
||||
|
||||
// Assume hit test (implemented in other classes) was positive.
|
||||
// May return Cancelled, overriding the hit test decision and stopping drag.
|
||||
// Otherwise the framework will later call Release or Cancel after
|
||||
|
@ -29,6 +29,10 @@ LabelGlyphHandle::LabelGlyphHandle
|
||||
: mpLT{ pLT }
|
||||
, mRect{ rect }
|
||||
, mHit{ hit }
|
||||
{
|
||||
}
|
||||
|
||||
void LabelGlyphHandle::Enter()
|
||||
{
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
|
||||
virtual ~LabelGlyphHandle();
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -24,6 +24,10 @@ LabelTextHandle::LabelTextHandle
|
||||
: mpLT{ pLT }
|
||||
, mLabelNum{ labelNum }
|
||||
{
|
||||
}
|
||||
|
||||
void LabelTextHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -38,6 +38,8 @@ public:
|
||||
std::shared_ptr<LabelTrack> GetTrack() const { return mpLT.lock(); }
|
||||
int GetLabelNum() const { return mLabelNum; }
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -24,6 +24,10 @@ NoteTrackButtonHandle::NoteTrackButtonHandle
|
||||
: mpTrack{ pTrack }
|
||||
, mChannel{ channel }
|
||||
, mRect{ rect }
|
||||
{
|
||||
}
|
||||
|
||||
void NoteTrackButtonHandle::Enter()
|
||||
{
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ public:
|
||||
const NoteTrackButtonHandle &newState);
|
||||
|
||||
protected:
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -40,6 +40,10 @@ NoteTrackVZoomHandle::NoteTrackVZoomHandle
|
||||
: mZoomStart(y), mZoomEnd(y), mRect(rect)
|
||||
, mpTrack{ pTrack }
|
||||
{
|
||||
}
|
||||
|
||||
void NoteTrackVZoomHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -38,6 +38,8 @@ public:
|
||||
|
||||
std::shared_ptr<NoteTrack> GetTrack() const { return mpTrack.lock(); }
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -71,20 +71,21 @@ public:
|
||||
|
||||
virtual ~StretchHandle();
|
||||
|
||||
virtual Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
virtual Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
virtual HitTestPreview Preview
|
||||
(const TrackPanelMouseState &state, const AudacityProject *pProject);
|
||||
HitTestPreview Preview
|
||||
(const TrackPanelMouseState &state, const AudacityProject *pProject)
|
||||
override;
|
||||
|
||||
virtual Result Release
|
||||
Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent);
|
||||
wxWindow *pParent) override;
|
||||
|
||||
virtual Result Cancel(AudacityProject *pProject);
|
||||
Result Cancel(AudacityProject *pProject) override;
|
||||
|
||||
bool StopsOnKeystroke() override { return true; }
|
||||
|
||||
|
@ -28,6 +28,10 @@ CutlineHandle::CutlineHandle
|
||||
: mpTrack{ pTrack }
|
||||
, mLocation{ location }
|
||||
{
|
||||
}
|
||||
|
||||
void CutlineHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
const WaveTrackLocation &GetLocation() { return mLocation; }
|
||||
std::shared_ptr<WaveTrack> GetTrack() { return mpTrack; }
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -38,6 +38,10 @@ static const double SMOOTHING_PROPORTION_MIN = 0.0;
|
||||
SampleHandle::SampleHandle( const std::shared_ptr<WaveTrack> &pTrack )
|
||||
: mClickedTrack{ pTrack }
|
||||
{
|
||||
}
|
||||
|
||||
void SampleHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
|
||||
std::shared_ptr<WaveTrack> GetTrack() const { return mClickedTrack; }
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -49,6 +49,10 @@ WaveTrackVZoomHandle::WaveTrackVZoomHandle
|
||||
: mZoomStart(y), mZoomEnd(y), mRect(rect)
|
||||
, mpTrack{ pTrack }
|
||||
{
|
||||
}
|
||||
|
||||
void WaveTrackVZoomHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -38,6 +38,8 @@ public:
|
||||
|
||||
std::shared_ptr<WaveTrack> GetTrack() const { return mpTrack.lock(); }
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -25,13 +25,17 @@ ButtonHandle::ButtonHandle
|
||||
: mpTrack{ pTrack }
|
||||
, mRect{ rect }
|
||||
{
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
}
|
||||
|
||||
ButtonHandle::~ButtonHandle()
|
||||
{
|
||||
}
|
||||
|
||||
void ButtonHandle::Enter()
|
||||
{
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
}
|
||||
|
||||
UIHandle::Result ButtonHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
|
@ -42,6 +42,8 @@ protected:
|
||||
virtual Result CommitChanges
|
||||
(const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) = 0;
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -30,6 +30,10 @@ Paul Licameli split from TrackPanel.cpp
|
||||
EnvelopeHandle::EnvelopeHandle( Envelope *pEnvelope )
|
||||
: mEnvelope{ pEnvelope }
|
||||
{
|
||||
}
|
||||
|
||||
void EnvelopeHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -56,6 +56,8 @@ public:
|
||||
|
||||
Envelope *GetEnvelope() const { return mEnvelope; }
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -32,6 +32,8 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../toolbars/ToolsToolBar.h"
|
||||
#include "../../../images/Cursors.h"
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
// Only for definition of SonifyBeginModifyState:
|
||||
//#include "../../NoteTrack.h"
|
||||
|
||||
@ -423,21 +425,21 @@ UIHandlePtr SelectHandle::HitTest
|
||||
const TrackPanelMouseState &st, const AudacityProject *pProject,
|
||||
const std::shared_ptr<Track> &pTrack)
|
||||
{
|
||||
// This handle is a little special, not following the pattern of calling
|
||||
// AssignUIHandlePtr(); there may be some state to preserve during movement
|
||||
// before the click.
|
||||
// This handle is a little special because there may be some state to
|
||||
// preserve during movement before the click.
|
||||
auto old = holder.lock();
|
||||
std::unique_ptr<SnapManager> oldSnapManager;
|
||||
std::shared_ptr<SnapManager> oldSnapManager;
|
||||
wxInt64 oldSnapLeft = -1, oldSnapRight = -1;
|
||||
if (old) {
|
||||
// It should not have started listening to timer events
|
||||
wxASSERT( !old->mConnectedProject );
|
||||
wxASSERT( !old->mTimerHandler );
|
||||
oldSnapManager = std::move(old->mSnapManager);
|
||||
oldSnapLeft = old->mSnapLeft;
|
||||
oldSnapRight = old->mSnapRight;
|
||||
}
|
||||
|
||||
auto result = std::make_shared<SelectHandle>( pTrack );
|
||||
result = AssignUIHandlePtr(holder, result);
|
||||
|
||||
// Copy the pre-dragging state
|
||||
result->mSnapManager = std::move( oldSnapManager );
|
||||
@ -561,14 +563,14 @@ UIHandle::Result SelectHandle::Click
|
||||
mInitialSelection = viewInfo.selectedRegion;
|
||||
|
||||
TrackList *const trackList = pProject->GetTracks();
|
||||
mSelectionStateChanger = std::make_unique< SelectionStateChanger >
|
||||
mSelectionStateChanger = std::make_shared< SelectionStateChanger >
|
||||
( selectionState, *trackList );
|
||||
|
||||
mSelectionBoundary = 0;
|
||||
|
||||
if (!mSnapManager) {
|
||||
// We create a NEW snap manager in case any snap-points have changed
|
||||
mSnapManager = std::make_unique<SnapManager>(trackList, &viewInfo);
|
||||
mSnapManager = std::make_shared<SnapManager>(trackList, &viewInfo);
|
||||
mSnapLeft = -1;
|
||||
mSnapRight = -1;
|
||||
}
|
||||
@ -954,7 +956,6 @@ UIHandle::Result SelectHandle::Release
|
||||
wxWindow *)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
Disconnect();
|
||||
pProject->ModifyState(false);
|
||||
mFrequencySnapper.reset();
|
||||
mSnapManager.reset();
|
||||
@ -971,8 +972,6 @@ UIHandle::Result SelectHandle::Release
|
||||
|
||||
UIHandle::Result SelectHandle::Cancel(AudacityProject *pProject)
|
||||
{
|
||||
Disconnect();
|
||||
|
||||
mSelectionStateChanger.reset();
|
||||
pProject->GetViewInfo().selectedRegion = mInitialSelection;
|
||||
|
||||
@ -995,31 +994,41 @@ void SelectHandle::DrawExtras
|
||||
|
||||
void SelectHandle::Connect(AudacityProject *pProject)
|
||||
{
|
||||
mConnectedProject = pProject;
|
||||
mConnectedProject->Connect(EVT_TRACK_PANEL_TIMER,
|
||||
wxCommandEventHandler(SelectHandle::OnTimer),
|
||||
NULL,
|
||||
this);
|
||||
mTimerHandler = std::make_shared<TimerHandler>( this, pProject );
|
||||
}
|
||||
|
||||
void SelectHandle::Disconnect()
|
||||
class SelectHandle::TimerHandler : public wxEvtHandler
|
||||
{
|
||||
if (mConnectedProject)
|
||||
mConnectedProject->Disconnect(EVT_TRACK_PANEL_TIMER,
|
||||
wxCommandEventHandler(SelectHandle::OnTimer),
|
||||
NULL,
|
||||
this);
|
||||
mConnectedProject = NULL;
|
||||
public:
|
||||
TimerHandler( SelectHandle *pParent, AudacityProject *pProject )
|
||||
: mParent{ pParent }
|
||||
, mConnectedProject{ pProject }
|
||||
{
|
||||
if (mConnectedProject)
|
||||
mConnectedProject->Connect(EVT_TRACK_PANEL_TIMER,
|
||||
wxCommandEventHandler(SelectHandle::TimerHandler::OnTimer),
|
||||
NULL,
|
||||
this);
|
||||
}
|
||||
|
||||
mpTrack.reset();
|
||||
mFreqSelTrack.reset();
|
||||
~TimerHandler()
|
||||
{
|
||||
if (mConnectedProject)
|
||||
mConnectedProject->Disconnect(EVT_TRACK_PANEL_TIMER,
|
||||
wxCommandEventHandler(SelectHandle::TimerHandler::OnTimer),
|
||||
NULL,
|
||||
this);
|
||||
}
|
||||
|
||||
mSnapManager.reset(NULL);
|
||||
// Receives timer event notifications, to implement auto-scroll
|
||||
void OnTimer(wxCommandEvent &event);
|
||||
|
||||
mFreqSelMode = FREQ_SEL_INVALID;
|
||||
}
|
||||
private:
|
||||
SelectHandle *mParent;
|
||||
AudacityProject *mConnectedProject;
|
||||
};
|
||||
|
||||
void SelectHandle::OnTimer(wxCommandEvent &event)
|
||||
void SelectHandle::TimerHandler::OnTimer(wxCommandEvent &event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
@ -1042,12 +1051,12 @@ void SelectHandle::OnTimer(wxCommandEvent &event)
|
||||
|
||||
const auto project = mConnectedProject;
|
||||
const auto trackPanel = project->GetTrackPanel();
|
||||
if (mMostRecentX >= mRect.x + mRect.width) {
|
||||
mAutoScrolling = true;
|
||||
if (mParent->mMostRecentX >= mParent->mRect.x + mParent->mRect.width) {
|
||||
mParent->mAutoScrolling = true;
|
||||
project->TP_ScrollRight();
|
||||
}
|
||||
else if (mMostRecentX < mRect.x) {
|
||||
mAutoScrolling = true;
|
||||
else if (mParent->mMostRecentX < mParent->mRect.x) {
|
||||
mParent->mAutoScrolling = true;
|
||||
project->TP_ScrollLeft();
|
||||
}
|
||||
else {
|
||||
@ -1055,24 +1064,24 @@ void SelectHandle::OnTimer(wxCommandEvent &event)
|
||||
// extreme x coordinate of the screen, even if that is still within the
|
||||
// track area.
|
||||
|
||||
int xx = mMostRecentX, yy = 0;
|
||||
int xx = mParent->mMostRecentX, yy = 0;
|
||||
trackPanel->ClientToScreen(&xx, &yy);
|
||||
if (xx == 0) {
|
||||
mAutoScrolling = true;
|
||||
mParent->mAutoScrolling = true;
|
||||
project->TP_ScrollLeft();
|
||||
}
|
||||
else {
|
||||
int width, height;
|
||||
::wxDisplaySize(&width, &height);
|
||||
if (xx == width - 1) {
|
||||
mAutoScrolling = true;
|
||||
mParent->mAutoScrolling = true;
|
||||
project->TP_ScrollRight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto pTrack = mpTrack.lock(); // TrackList::Lock() ?
|
||||
if (mAutoScrolling && pTrack) {
|
||||
auto pTrack = mParent->mpTrack.lock(); // TrackList::Lock() ?
|
||||
if (mParent->mAutoScrolling && pTrack) {
|
||||
// AS: To keep the selection working properly as we scroll,
|
||||
// we fake a mouse event (remember, this method is called
|
||||
// from a timer tick).
|
||||
@ -1080,8 +1089,8 @@ void SelectHandle::OnTimer(wxCommandEvent &event)
|
||||
// AS: For some reason, GCC won't let us pass this directly.
|
||||
wxMouseEvent evt(wxEVT_MOTION);
|
||||
const auto size = trackPanel->GetSize();
|
||||
Drag(TrackPanelMouseEvent{ evt, mRect, size, pTrack }, project);
|
||||
mAutoScrolling = false;
|
||||
mParent->Drag(TrackPanelMouseEvent{ evt, mParent->mRect, size, pTrack }, project);
|
||||
mParent->mAutoScrolling = false;
|
||||
mConnectedProject->GetTrackPanel()->Refresh(false);
|
||||
}
|
||||
}
|
||||
@ -1304,7 +1313,7 @@ void SelectHandle::HandleCenterFrequencyClick
|
||||
mFreqSelMode = FREQ_SEL_SNAPPING_CENTER;
|
||||
// Disable time selection
|
||||
mSelStartValid = false;
|
||||
mFrequencySnapper = std::make_unique<SpectrumAnalyst>();
|
||||
mFrequencySnapper = std::make_shared<SpectrumAnalyst>();
|
||||
StartSnappingFreqSelection(*mFrequencySnapper, viewInfo, pTrack);
|
||||
#endif
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../MemoryX.h"
|
||||
#include <vector>
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/gdicmn.h>
|
||||
|
||||
class SelectionStateChanger;
|
||||
@ -27,10 +26,9 @@ class Track;
|
||||
class ViewInfo;
|
||||
class WaveTrack;
|
||||
|
||||
class SelectHandle : public wxEvtHandler, public UIHandle
|
||||
class SelectHandle : public UIHandle
|
||||
{
|
||||
SelectHandle(const SelectHandle&);
|
||||
SelectHandle &operator=(const SelectHandle&);
|
||||
|
||||
public:
|
||||
explicit SelectHandle( const std::shared_ptr<Track> &pTrack );
|
||||
@ -42,35 +40,35 @@ public:
|
||||
const TrackPanelMouseState &state, const AudacityProject *pProject,
|
||||
const std::shared_ptr<Track> &pTrack);
|
||||
|
||||
SelectHandle &operator=(const SelectHandle&) = default;
|
||||
|
||||
virtual ~SelectHandle();
|
||||
|
||||
bool IsClicked() const;
|
||||
|
||||
virtual Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
virtual Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
virtual HitTestPreview Preview
|
||||
(const TrackPanelMouseState &state, const AudacityProject *pProject);
|
||||
HitTestPreview Preview
|
||||
(const TrackPanelMouseState &state, const AudacityProject *pProject)
|
||||
override;
|
||||
|
||||
virtual Result Release
|
||||
Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent);
|
||||
wxWindow *pParent) override;
|
||||
|
||||
virtual Result Cancel(AudacityProject*);
|
||||
Result Cancel(AudacityProject*) override;
|
||||
|
||||
virtual void DrawExtras
|
||||
void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
|
||||
|
||||
// Receives timer event notifications, to implement auto-scroll
|
||||
void OnTimer(wxCommandEvent &event);
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
|
||||
override;
|
||||
|
||||
private:
|
||||
void Connect(AudacityProject *pProject);
|
||||
void Disconnect();
|
||||
|
||||
void StartSelection
|
||||
(AudacityProject *pProject, int mouseXCoordinate, int trackLeftEdge);
|
||||
@ -115,7 +113,7 @@ private:
|
||||
// line up with existing tracks or labels. mSnapLeft and mSnapRight
|
||||
// are the horizontal index of pixels to display user feedback
|
||||
// guidelines so the user knows when such snapping is taking place.
|
||||
std::unique_ptr<SnapManager> mSnapManager;
|
||||
std::shared_ptr<SnapManager> mSnapManager;
|
||||
wxInt64 mSnapLeft{ -1 };
|
||||
wxInt64 mSnapRight{ -1 };
|
||||
|
||||
@ -143,14 +141,16 @@ private:
|
||||
// FREQ_SEL_BOTTOM_FREE,
|
||||
// and is ignored otherwise.
|
||||
double mFreqSelPin{ -1.0 };
|
||||
std::unique_ptr<SpectrumAnalyst> mFrequencySnapper;
|
||||
std::shared_ptr<SpectrumAnalyst> mFrequencySnapper;
|
||||
|
||||
int mMostRecentX{ -1 }, mMostRecentY{ -1 };
|
||||
|
||||
bool mAutoScrolling{};
|
||||
|
||||
AudacityProject *mConnectedProject{};
|
||||
std::shared_ptr<SelectionStateChanger> mSelectionStateChanger;
|
||||
|
||||
std::unique_ptr<SelectionStateChanger> mSelectionStateChanger;
|
||||
class TimerHandler;
|
||||
friend TimerHandler;
|
||||
std::shared_ptr<TimerHandler> mTimerHandler;
|
||||
};
|
||||
#endif
|
||||
|
@ -21,6 +21,10 @@ SliderHandle::SliderHandle
|
||||
: mSliderFn{ sliderFn }
|
||||
, mRect{ rect }
|
||||
, mpTrack{ pTrack }
|
||||
{
|
||||
}
|
||||
|
||||
void SliderHandle::Enter()
|
||||
{
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ protected:
|
||||
virtual Result CommitChanges
|
||||
(const wxMouseEvent &event, AudacityProject *pProject) = 0;
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
@ -29,6 +29,10 @@ TimeShiftHandle::TimeShiftHandle
|
||||
: mCapturedTrack{ pTrack }
|
||||
, mGripHit{ gripHit }
|
||||
{
|
||||
}
|
||||
|
||||
void TimeShiftHandle::Enter()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
mChangeHighlight = RefreshCode::RefreshCell;
|
||||
#endif
|
||||
|
@ -75,6 +75,8 @@ public:
|
||||
|
||||
virtual ~TimeShiftHandle();
|
||||
|
||||
void Enter() override;
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user