1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-18 17:10:55 +02:00

Simplify label track hit tests

This commit is contained in:
Paul Licameli 2017-06-18 13:34:34 -04:00
parent 34da6e6ad3
commit 828d9c3ccd
7 changed files with 55 additions and 136 deletions

View File

@ -21,12 +21,6 @@ LabelDefaultClickHandle::LabelDefaultClickHandle()
{ {
} }
LabelDefaultClickHandle &LabelDefaultClickHandle::Instance()
{
static LabelDefaultClickHandle instance;
return instance;
}
LabelDefaultClickHandle::~LabelDefaultClickHandle() LabelDefaultClickHandle::~LabelDefaultClickHandle()
{ {
} }
@ -65,12 +59,16 @@ void LabelDefaultClickHandle::RestoreState( AudacityProject *pProject )
} }
} }
void LabelDefaultClickHandle::DoClick UIHandle::Result LabelDefaultClickHandle::Click
(const wxMouseEvent &event, AudacityProject *pProject, TrackPanelCell *pCell) (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{ {
LabelTrack *pLT = static_cast<LabelTrack*>(pCell); using namespace RefreshCode;
// Redraw to show the change of text box selection status
UIHandle::Result result = RefreshAll;
if (event.LeftDown()) LabelTrack *pLT = static_cast<LabelTrack*>(evt.pCell);
if (evt.event.LeftDown())
{ {
SaveState( pProject ); SaveState( pProject );
@ -79,7 +77,7 @@ void LabelDefaultClickHandle::DoClick
Track *n = iter.First(); Track *n = iter.First();
while (n) { while (n) {
if (n->GetKind() == Track::Label && pCell != n) { if (n->GetKind() == Track::Label && evt.pCell != n) {
LabelTrack *const lt = static_cast<LabelTrack*>(n); LabelTrack *const lt = static_cast<LabelTrack*>(n);
lt->ResetFlags(); lt->ResetFlags();
lt->Unselect(); lt->Unselect();
@ -87,22 +85,6 @@ void LabelDefaultClickHandle::DoClick
n = iter.Next(); n = iter.Next();
} }
} }
}
UIHandle::Result LabelDefaultClickHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
// Redraw to show the change of text box selection status
UIHandle::Result result = RefreshAll;
DoClick(evt.event, pProject, evt.pCell);
if (mpForward)
result |= mpForward->Click(evt, pProject);
else
// No drag or release follows
result |= Cancelled;
return result; return result;
} }
@ -110,19 +92,7 @@ UIHandle::Result LabelDefaultClickHandle::Click
UIHandle::Result LabelDefaultClickHandle::Drag UIHandle::Result LabelDefaultClickHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{ {
if (mpForward) return RefreshCode::RefreshNone;
return mpForward->Drag(evt, pProject);
else
return RefreshCode::RefreshNone;
}
HitTestPreview LabelDefaultClickHandle::Preview
(const TrackPanelMouseEvent &evt, const AudacityProject *pProject)
{
if (mpForward)
return mpForward->Preview(evt, pProject);
else
return {};
} }
UIHandle::Result LabelDefaultClickHandle::Release UIHandle::Result LabelDefaultClickHandle::Release
@ -130,40 +100,12 @@ UIHandle::Result LabelDefaultClickHandle::Release
wxWindow *pParent) wxWindow *pParent)
{ {
mLabelState.reset(); mLabelState.reset();
if (mpForward) return RefreshCode::RefreshNone;
return mpForward->Release(evt, pProject, pParent);
else
return RefreshCode::RefreshNone;
} }
UIHandle::Result LabelDefaultClickHandle::Cancel(AudacityProject *pProject) UIHandle::Result LabelDefaultClickHandle::Cancel(AudacityProject *pProject)
{ {
UIHandle::Result result = RefreshCode::RefreshNone; UIHandle::Result result = RefreshCode::RefreshNone;
if (mpForward)
result |= mpForward->Cancel(pProject);
RestoreState( pProject ); RestoreState( pProject );
return result; return result;
} }
void LabelDefaultClickHandle::DrawExtras
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
{
UIHandle::DrawExtras(pass, dc, updateRegion, panelRect);
if (mpForward)
mpForward->DrawExtras(pass, dc, updateRegion, panelRect);
}
bool LabelDefaultClickHandle::StopsOnKeystroke()
{
return
(mpForward && mpForward->StopsOnKeystroke()) ||
UIHandle::StopsOnKeystroke();
}
void LabelDefaultClickHandle::OnProjectChange(AudacityProject *pProject)
{
if (mpForward)
return mpForward->OnProjectChange(pProject);
UIHandle::OnProjectChange(pProject);
}

View File

@ -18,29 +18,24 @@ class wxMouseEvent;
struct HitTestResult; struct HitTestResult;
class LabelTrack; class LabelTrack;
// Adds some behavior to click, then calls through to other mouse handling. // Used as a base class.
class LabelDefaultClickHandle final : public UIHandle // Adds some behavior to clicks.
class LabelDefaultClickHandle /* not final */ : public UIHandle
{ {
LabelDefaultClickHandle();
LabelDefaultClickHandle(const LabelDefaultClickHandle&) = delete; LabelDefaultClickHandle(const LabelDefaultClickHandle&) = delete;
LabelDefaultClickHandle &operator=(const LabelDefaultClickHandle&) = delete; LabelDefaultClickHandle &operator=(const LabelDefaultClickHandle&) = delete;
public: public:
static LabelDefaultClickHandle& Instance(); LabelDefaultClickHandle();
virtual ~LabelDefaultClickHandle(); virtual ~LabelDefaultClickHandle();
void DoClick
(const wxMouseEvent &event, AudacityProject *pProject, TrackPanelCell *pCell);
Result Click Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override; (const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
Result Drag Result Drag
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override; (const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
HitTestPreview Preview // does not override Preview()
(const TrackPanelMouseEvent &event, const AudacityProject *pProject)
override;
Result Release Result Release
(const TrackPanelMouseEvent &event, AudacityProject *pProject, (const TrackPanelMouseEvent &event, AudacityProject *pProject,
@ -48,17 +43,6 @@ public:
Result Cancel(AudacityProject *pProject) override; Result Cancel(AudacityProject *pProject) override;
void DrawExtras
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
override;
bool StopsOnKeystroke() override;
void OnProjectChange(AudacityProject *pProject) override;
UIHandle *mpForward {};
private: private:
struct LabelState; struct LabelState;
std::unique_ptr< LabelState > mLabelState; std::unique_ptr< LabelState > mLabelState;

View File

@ -8,6 +8,7 @@ Paul Licameli split from TrackPanel.cpp
**********************************************************************/ **********************************************************************/
#include "../../../Audacity.h"
#include "LabelGlyphHandle.h" #include "LabelGlyphHandle.h"
#include "../../../HitTestResult.h" #include "../../../HitTestResult.h"
#include "../../../LabelTrack.h" #include "../../../LabelTrack.h"
@ -90,6 +91,8 @@ LabelGlyphHandle::~LabelGlyphHandle()
UIHandle::Result LabelGlyphHandle::Click UIHandle::Result LabelGlyphHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{ {
auto result = LabelDefaultClickHandle::Click( evt, pProject );
TrackPanelCell *const pCell = evt.pCell; TrackPanelCell *const pCell = evt.pCell;
const wxMouseEvent &event = evt.event; const wxMouseEvent &event = evt.event;
const wxRect &rect = evt.rect; const wxRect &rect = evt.rect;
@ -104,11 +107,11 @@ UIHandle::Result LabelGlyphHandle::Click
{ {
// The positive hit test should have ensured otherwise // The positive hit test should have ensured otherwise
//wxASSERT(false); //wxASSERT(false);
return RefreshCode::Cancelled; result |= RefreshCode::Cancelled;
} }
else
// redraw the track. // redraw the track.
return RefreshCode::RefreshCell; result |= RefreshCode::RefreshCell;
// handle shift+ctrl down // handle shift+ctrl down
/*if (event.ShiftDown()) { // && event.ControlDown()) { /*if (event.ShiftDown()) { // && event.ControlDown()) {
@ -117,19 +120,20 @@ UIHandle::Result LabelGlyphHandle::Click
return; return;
}*/ }*/
return result;
return RefreshCode::RefreshNone;
} }
UIHandle::Result LabelGlyphHandle::Drag UIHandle::Result LabelGlyphHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{ {
auto result = LabelDefaultClickHandle::Drag( evt, pProject );
const wxMouseEvent &event = evt.event; const wxMouseEvent &event = evt.event;
ViewInfo &viewInfo = pProject->GetViewInfo(); ViewInfo &viewInfo = pProject->GetViewInfo();
mpLT->HandleGlyphDragRelease(event, mRect, viewInfo, &viewInfo.selectedRegion); mpLT->HandleGlyphDragRelease(event, mRect, viewInfo, &viewInfo.selectedRegion);
// Refresh all so that the change of selection is redrawn in all tracks // Refresh all so that the change of selection is redrawn in all tracks
return RefreshCode::RefreshAll | RefreshCode::DrawOverlays; return result | RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
} }
HitTestPreview LabelGlyphHandle::Preview HitTestPreview LabelGlyphHandle::Preview
@ -142,6 +146,7 @@ UIHandle::Result LabelGlyphHandle::Release
(const TrackPanelMouseEvent &evt, AudacityProject *pProject, (const TrackPanelMouseEvent &evt, AudacityProject *pProject,
wxWindow *pParent) wxWindow *pParent)
{ {
auto result = LabelDefaultClickHandle::Release( evt, pProject, pParent );
mpLT->mOldEdge = 0; mpLT->mOldEdge = 0;
const wxMouseEvent &event = evt.event; const wxMouseEvent &event = evt.event;
@ -153,12 +158,13 @@ UIHandle::Result LabelGlyphHandle::Release
} }
// Refresh all so that the change of selection is redrawn in all tracks // Refresh all so that the change of selection is redrawn in all tracks
return RefreshCode::RefreshAll | RefreshCode::DrawOverlays; return result | RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
} }
UIHandle::Result LabelGlyphHandle::Cancel(AudacityProject *pProject) UIHandle::Result LabelGlyphHandle::Cancel(AudacityProject *pProject)
{ {
mpLT->mOldEdge = 0; mpLT->mOldEdge = 0;
pProject->RollbackState(); pProject->RollbackState();
return RefreshCode::RefreshAll; auto result = LabelDefaultClickHandle::Cancel( pProject );
return result | RefreshCode::RefreshAll;
} }

View File

@ -11,14 +11,14 @@ Paul Licameli split from TrackPanel.cpp
#ifndef __AUDACITY_LABEL_GLYPH_HANDLE__ #ifndef __AUDACITY_LABEL_GLYPH_HANDLE__
#define __AUDACITY_LABEL_GLYPH_HANDLE__ #define __AUDACITY_LABEL_GLYPH_HANDLE__
#include "../../../UIHandle.h" #include "LabelDefaultClickHandle.h"
#include <wx/gdicmn.h> #include <wx/gdicmn.h>
class wxMouseEvent; class wxMouseEvent;
struct HitTestResult; struct HitTestResult;
class LabelTrack; class LabelTrack;
class LabelGlyphHandle final : public UIHandle class LabelGlyphHandle final : public LabelDefaultClickHandle
{ {
LabelGlyphHandle(); LabelGlyphHandle();
LabelGlyphHandle(const LabelGlyphHandle&) = delete; LabelGlyphHandle(const LabelGlyphHandle&) = delete;

View File

@ -45,6 +45,8 @@ LabelTextHandle::~LabelTextHandle()
UIHandle::Result LabelTextHandle::Click UIHandle::Result LabelTextHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{ {
auto result = LabelDefaultClickHandle::Click( evt, pProject );
auto &selectionState = pProject->GetSelectionState(); auto &selectionState = pProject->GetSelectionState();
TrackList *const tracks = pProject->GetTracks(); TrackList *const tracks = pProject->GetTracks();
mChanger = mChanger =
@ -98,14 +100,14 @@ UIHandle::Result LabelTextHandle::Click
if (!unsafe) if (!unsafe)
pProject->ModifyState(false); pProject->ModifyState(false);
return RefreshCode::RefreshCell | RefreshCode::UpdateSelection; return result | RefreshCode::RefreshCell | RefreshCode::UpdateSelection;
} }
UIHandle::Result LabelTextHandle::Drag UIHandle::Result LabelTextHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{ {
using namespace RefreshCode; using namespace RefreshCode;
Result result = RefreshNone; auto result = LabelDefaultClickHandle::Drag( evt, pProject );
const wxMouseEvent &event = evt.event; const wxMouseEvent &event = evt.event;
auto pLT = mpLT.lock(); auto pLT = mpLT.lock();
@ -145,6 +147,8 @@ UIHandle::Result LabelTextHandle::Release
(const TrackPanelMouseEvent &evt, AudacityProject *pProject, (const TrackPanelMouseEvent &evt, AudacityProject *pProject,
wxWindow *pParent) wxWindow *pParent)
{ {
auto result = LabelDefaultClickHandle::Release( evt, pProject, pParent );
// Only selected a part of a text string and changed track selectedness. // Only selected a part of a text string and changed track selectedness.
// No undoable effects. // No undoable effects.
@ -162,7 +166,7 @@ UIHandle::Result LabelTextHandle::Release
if (event.LeftUp()) if (event.LeftUp())
mLabelTrackStartXPos = -1; mLabelTrackStartXPos = -1;
return RefreshCode::RefreshNone; return result | RefreshCode::RefreshNone;
} }
UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject ) UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject )
@ -173,5 +177,6 @@ UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject )
mChanger.release(); mChanger.release();
ViewInfo &viewInfo = pProject->GetViewInfo(); ViewInfo &viewInfo = pProject->GetViewInfo();
viewInfo.selectedRegion = mSelectedRegion; viewInfo.selectedRegion = mSelectedRegion;
return RefreshCode::RefreshAll; auto result = LabelDefaultClickHandle::Cancel( pProject );
return result | RefreshCode::RefreshAll;
} }

View File

@ -11,7 +11,7 @@ Paul Licameli split from TrackPanel.cpp
#ifndef __AUDACITY_LABEL_TEXT_HANDLE__ #ifndef __AUDACITY_LABEL_TEXT_HANDLE__
#define __AUDACITY_LABEL_TEXT_HANDLE__ #define __AUDACITY_LABEL_TEXT_HANDLE__
#include "../../../UIHandle.h" #include "LabelDefaultClickHandle.h"
#include "../../../MemoryX.h" #include "../../../MemoryX.h"
#include "../../../SelectedRegion.h" #include "../../../SelectedRegion.h"
#include <wx/gdicmn.h> #include <wx/gdicmn.h>
@ -21,7 +21,7 @@ struct HitTestResult;
class LabelTrack; class LabelTrack;
class SelectionStateChanger; class SelectionStateChanger;
class LabelTextHandle final : public UIHandle class LabelTextHandle final : public LabelDefaultClickHandle
{ {
LabelTextHandle(); LabelTextHandle();
LabelTextHandle(const LabelTextHandle&) = delete; LabelTextHandle(const LabelTextHandle&) = delete;

View File

@ -26,44 +26,26 @@ HitTestResult LabelTrack::HitTest
(const TrackPanelMouseEvent &evt, (const TrackPanelMouseEvent &evt,
const AudacityProject *pProject) const AudacityProject *pProject)
{ {
// PRL: Maybe I did too much work to preserve old behavior, but anyway,
// this unusually combines parts of two or more hit test results.
HitTestResult result; HitTestResult result;
const wxMouseEvent &event = evt.event; const wxMouseEvent &event = evt.event;
// Try label movement handles first // Try label movement handles first
result = LabelGlyphHandle::HitTest(event, this); result = LabelGlyphHandle::HitTest(event, this);
// Hit test may request refresh even if a miss
auto refreshResult = result.preview.refreshCode; if ( !result.handle )
// Missed glyph, try text box
result = LabelTextHandle::HitTest(event, this);
if ( !result.handle )
result = Track::HitTest(evt, pProject);
if ( !result.handle ) { if ( !result.handle ) {
// Missed glyph, try text box // In case of multi tool, default to selection.
// This hit test does not define its own messages or cursor const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
HitTestResult defaultResult = Track::HitTest(evt, pProject); if (pTtb->IsDown(multiTool))
if (!defaultResult.handle) { result = SelectHandle::HitTest(evt, pProject, this);
// In case of multi tool, default to selection.
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
if (pTtb->IsDown(multiTool))
defaultResult = SelectHandle::HitTest(evt, pProject, this);
}
result = LabelTextHandle::HitTest(event, this);
if (result.handle)
// Use any cursor or status message change from catchall,
// But let the text ui handle pass
result.preview = defaultResult.preview;
else
result = defaultResult;
} }
// Now attach some common extra work to the click action
LabelDefaultClickHandle::Instance().mpForward = result.handle;
result.handle = &LabelDefaultClickHandle::Instance();
// Don't lose the refresh result side effect of the glyph
// hit test
result.preview.refreshCode |= refreshResult;
return result; return result;
} }