1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-29 08:43:56 +01:00

Rename TrackPanel::HandleCursor as HandleMotion...

Call HitTest in just one place

Can now preserve repeatedly hit UIHandle objects during pre-click motion

Fields of HitTestResult besides the handle pointer are now unused

The need to repaint a track during mouse movement can be indicated when
constructing a UIHandle or when updating it for move; HitPreview no longer
does this

And the last allows simplifications of LabelTrack glyph highlighting

Also move the temporary state for label glyph dragging out of LabelTrack
This commit is contained in:
Paul Licameli
2017-06-17 21:37:41 -04:00
parent 2c1a16f593
commit f5b0afc2fc
10 changed files with 336 additions and 210 deletions

View File

@@ -758,7 +758,7 @@ void TrackPanel::Uncapture(wxMouseEvent *pEvent)
{
if (HasCapture())
ReleaseMouse();
HandleCursor( pEvent );
HandleMotion( pEvent );
}
void TrackPanel::CancelDragging()
@@ -768,9 +768,10 @@ void TrackPanel::CancelDragging()
auto pTrack = GetTracks()->Lock(mpClickedTrack);
if (pTrack)
ProcessUIHandleResult(
this, mRuler, pTrack.get(), NULL, refreshResult);
this, mRuler, pTrack.get(), NULL,
refreshResult | mMouseOverUpdateFlags );
mpClickedTrack.reset();
mUIHandle.reset();
mUIHandle.reset(), ClearTargets();
Uncapture();
}
}
@@ -830,7 +831,7 @@ void TrackPanel::HandleCursorForLastMouseState()
// Come here on modifier key or mouse button transitions,
// or on starting or stopping of play or record,
// and change the cursor appropriately.
HandleCursor( &mLastMouseState );
HandleMotion( &mLastMouseState );
}
bool TrackPanel::IsAudioActive()
@@ -840,10 +841,14 @@ bool TrackPanel::IsAudioActive()
}
/// TrackPanel::HandleCursor( ) sets the cursor drawn at the mouse location.
/// TrackPanel::HandleMotion( ) sets the cursor drawn at the mouse location,
/// and updates the status bar message.
/// We treat certain other changes of mouse button and key state as "motions"
/// too, and also starting and stopping of playback or recording, all of which
/// 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::HandleCursor( wxMouseState *pState )
void TrackPanel::HandleMotion( wxMouseState *pState )
{
wxMouseState dummy;
if (!pState)
@@ -857,39 +862,78 @@ void TrackPanel::HandleCursor( wxMouseState *pState )
auto &rect = foundCell.rect;
auto &pCell = foundCell.pCell;
const TrackPanelMouseState tpmState{ state, rect, pCell };
HandleCursor( tpmState );
HandleMotion( tpmState );
}
void TrackPanel::HandleCursor( const TrackPanelMouseState &tpmState )
void TrackPanel::HandleMotion( const TrackPanelMouseState &tpmState )
{
if ( mUIHandle ) {
// UIHANDLE PREVIEW
// Update status message and cursor during drag
HitTestPreview preview = mUIHandle->Preview( tpmState, GetProject() );
mListener->TP_DisplayStatusMessage( preview.message );
if ( preview.cursor )
SetCursor( *preview.cursor );
}
else {
wxCursor *pCursor = NULL;
HitTestResult result;
auto handle = mUIHandle;
wxString tip;
auto oldHandle = mLastHitTest.handle;
auto oldCell = mLastCell.lock();
auto newCell = tpmState.pCell;
auto pCell = tpmState.pCell;
auto track = static_cast<CommonTrackPanelCell*>( pCell.get() )->FindTrack();
if (pCell && pCursor == NULL && tip == wxString()) {
HitTestResult hitTest( pCell->HitTest(tpmState, GetProject()) );
tip = hitTest.preview.message;
ProcessUIHandleResult
(this, mRuler, track.get(), track.get(), hitTest.preview.refreshCode);
pCursor = hitTest.preview.cursor;
if (pCursor)
SetCursor(*pCursor);
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();
wxString tip{};
wxCursor *pCursor{};
unsigned refreshCode = 0;
if ( !mUIHandle ) {
// Not yet dragging.
unsigned updateFlags = mMouseOverUpdateFlags;
// First check whether crossing cell to cell
if ( newCell == oldCell )
oldCell.reset();
else {
// Forget old targets
ClearTargets();
// Re-draw any highlighting
if (oldCell) {
ProcessUIHandleResult(
this, GetRuler(), oldTrack.get(), oldTrack.get(), updateFlags);
}
}
if (pCursor != NULL || tip != wxString())
mListener->TP_DisplayStatusMessage(tip);
// Now do the
// UIHANDLE HIT TEST !
result = newCell->HitTest(tpmState, GetProject());
handle = result.handle;
mLastCell = newCell;
mLastHitTestValid = true;
mLastHitTest = result;
if (!oldCell && oldHandle != handle)
// Did not move cell to cell, but did change the target
refreshCode = updateFlags;
}
// UIHANDLE PREVIEW
// Update status message and cursor, whether dragging or not
if (handle) {
auto preview = handle->Preview( tpmState, GetProject() );
tip = preview.message;
pCursor = preview.cursor;
auto code = handle->GetChangeHighlight();
handle->SetChangeHighlight(RefreshCode::RefreshNone);
refreshCode |= code;
mMouseOverUpdateFlags |= code;
}
mListener->TP_DisplayStatusMessage(tip);
if (pCursor)
SetCursor( *pCursor );
ProcessUIHandleResult(
this, GetRuler(), newTrack.get(), newTrack.get(), refreshCode);
}
void TrackPanel::UpdateSelectionDisplay()
@@ -1238,7 +1282,8 @@ void TrackPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
unsigned result =
pCell->HandleWheelRotation( tpmEvent, GetProject() );
auto pTrack = static_cast<CommonTrackPanelCell*>(pCell.get())->FindTrack();
ProcessUIHandleResult(this, mRuler, pTrack.get(), pTrack.get(), result);
ProcessUIHandleResult(
this, mRuler, pTrack.get(), pTrack.get(), result);
}
/// Filter captured keys typed into LabelTracks.
@@ -1361,6 +1406,8 @@ void TrackPanel::OnKeyUp(wxKeyEvent & event)
/// Should handle the case when the mouse capture is lost.
void TrackPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
{
ClearTargets();
wxMouseEvent e(wxEVT_LEFT_UP);
e.m_x = mMouseMostRecentX;
@@ -1436,6 +1483,9 @@ try
if (event.Leaving())
{
if ( !mUIHandle )
ClearTargets();
auto buttons =
// Bug 1325: button state in Leaving events is unreliable on Mac.
// Poll the global state instead.
@@ -1463,32 +1513,32 @@ try
mUIHandle->Drag( tpmEvent, GetProject() );
ProcessUIHandleResult
(this, mRuler, pClickedTrack.get(), pTrack.get(), refreshResult);
mMouseOverUpdateFlags |= refreshResult;
if (refreshResult & RefreshCode::Cancelled) {
// Drag decided to abort itself
mUIHandle.reset();
mUIHandle.reset(), ClearTargets();
mpClickedTrack.reset();
Uncapture( &event );
}
else {
TrackPanelMouseState tpmState{
tpmEvent.event,
tpmEvent.rect,
tpmEvent.pCell
};
HandleCursor( tpmState );
UpdateMouseState(event);
TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
HandleMotion( tpmState );
}
}
else if (event.ButtonUp()) {
// UIHANDLE RELEASE
auto uiHandle = mUIHandle;
// Null this pointer out first before calling Release -- because on Windows, we can
// Null mUIHandle out first before calling Release -- because on Windows, we can
// come back recursively to this place during handling of the context menu,
// because of a capture lost event.
mUIHandle.reset();
unsigned moreFlags = mMouseOverUpdateFlags;
mUIHandle.reset(), ClearTargets();
UIHandle::Result refreshResult =
uiHandle->Release( tpmEvent, GetProject(), this );
ProcessUIHandleResult
(this, mRuler, pClickedTrack.get(), pTrack.get(), refreshResult);
(this, mRuler, pClickedTrack.get(), pTrack.get(),
refreshResult | moreFlags);
mpClickedTrack.reset();
// will also Uncapture() below
}
@@ -1498,7 +1548,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)
HandleCursor( &event );
HandleMotion( &event );
else if ( event.ButtonDown() || event.ButtonDClick() )
HandleClick( tpmEvent );
@@ -1538,32 +1588,44 @@ void TrackPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
const auto &rect = tpmEvent.rect;
auto pTrack = static_cast<CommonTrackPanelCell *>( pCell.get() )->FindTrack();
if ( !mUIHandle && pCell ) {
// Do hit test once more, in case the button really pressed was not the
// one "anticipated."
{
TrackPanelMouseState tpmState{
tpmEvent.event,
tpmEvent.rect,
tpmEvent.pCell
};
mUIHandle =
pCell->HitTest( tpmState, GetProject() ).handle;
HandleMotion( tpmState );
}
auto target = Target();
if (target)
mUIHandle = target->handle;
else
mUIHandle = {};
if (mUIHandle) {
// UIHANDLE CLICK
UIHandle::Result refreshResult =
mUIHandle->Click( tpmEvent, GetProject() );
if (refreshResult & RefreshCode::Cancelled)
mUIHandle.reset();
else
mUIHandle.reset(), ClearTargets();
else {
mpClickedTrack = pTrack;
ProcessUIHandleResult
(this, mRuler, pTrack.get(), pTrack.get(), refreshResult);
TrackPanelMouseState tpmState{
tpmEvent.event,
tpmEvent.rect,
tpmEvent.pCell
};
HandleCursor( tpmState );
// Perhaps the clicked handle wants to update cursor and state message
// after a click.
TrackPanelMouseState tpmState{
tpmEvent.event,
tpmEvent.rect,
tpmEvent.pCell
};
HandleMotion( tpmState );
}
ProcessUIHandleResult(
this, mRuler, pTrack.get(), pTrack.get(), refreshResult);
mMouseOverUpdateFlags |= refreshResult;
}
}
@@ -1574,6 +1636,9 @@ double TrackPanel::GetMostRecentXPos()
void TrackPanel::RefreshTrack(Track *trk, bool refreshbacking)
{
if (!trk)
return;
Track *link = trk->GetLink();
if (link && !trk->GetLinked()) {