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

TrackPanelCell hit tests can return multiple results...

.. though only the first is used yet
This commit is contained in:
Paul Licameli 2017-06-29 10:34:57 -04:00
parent b3d62e2ab6
commit 8e44827980
32 changed files with 165 additions and 93 deletions

View File

@ -125,7 +125,7 @@ class AUDACITY_DLL_API LabelTrack final : public Track
virtual ~ LabelTrack();
UIHandlePtr DetailedHitTest
std::vector<UIHandlePtr> DetailedHitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;

View File

@ -70,7 +70,7 @@ class AUDACITY_DLL_API NoteTrack final
NoteTrack(const std::shared_ptr<DirManager> &projDirManager);
virtual ~NoteTrack();
UIHandlePtr DetailedHitTest
std::vector<UIHandlePtr> DetailedHitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;

View File

@ -51,7 +51,7 @@ class TimeTrack final : public Track {
void Silence(double t0, double t1) override;
void InsertSilence(double t, double len) override;
UIHandlePtr DetailedHitTest
std::vector<UIHandlePtr> DetailedHitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;

View File

@ -136,14 +136,14 @@ class AUDACITY_DLL_API Track /* not final */
// Cause certain overriding tool modes (Zoom; future ones?) to behave
// uniformly in all tracks, disregarding track contents.
// Do not further override this...
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &, const AudacityProject *pProject)
final;
public:
// Rather override this for subclasses:
virtual UIHandlePtr DetailedHitTest
virtual std::vector<UIHandlePtr> DetailedHitTest
(const TrackPanelMouseState &,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
= 0;

View File

@ -904,7 +904,10 @@ void TrackPanel::HandleMotion( const TrackPanelMouseState &tpmState )
// Now do the
// UIHANDLE HIT TEST !
handle = newCell->HitTest(tpmState, GetProject());
auto targets = newCell->HitTest(tpmState, GetProject());
// No use, yet, of any but the first target
handle = targets.empty() ? UIHandlePtr{} : targets[0];
mLastCell = newCell;
mLastHitTest = handle;

View File

@ -25,6 +25,8 @@ class wxWindow;
class UIHandle;
using UIHandlePtr = std::shared_ptr<UIHandle>;
#include <vector>
// Abstract base class defining TrackPanel's access to specialist classes that
// implement drawing and user interactions
class AUDACITY_DLL_API TrackPanelCell /* not final */
@ -32,12 +34,12 @@ class AUDACITY_DLL_API TrackPanelCell /* not final */
public:
virtual ~TrackPanelCell () = 0;
// Return null, or a pointer to an object that can be queried for a status
// bar message and cursor appropriate to the point, and that dispatches
// Return pointers to objects that can be queried for a status
// bar message and cursor appropriate to the point, and that dispatch
// mouse button events.
// The button-down state passed to the function is as it will be at click
// time -- not necessarily as it is now.
virtual UIHandlePtr HitTest
virtual std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) = 0;

View File

@ -21,15 +21,16 @@ TrackPanelResizerCell::TrackPanelResizerCell( std::shared_ptr<Track> pTrack )
: mpTrack{ pTrack }
{}
UIHandlePtr TrackPanelResizerCell::HitTest
std::vector<UIHandlePtr> TrackPanelResizerCell::HitTest
(const TrackPanelMouseState &st, const AudacityProject *pProject)
{
std::vector<UIHandlePtr> results;
auto pTrack = mpTrack.lock();
if (pTrack) {
auto result = std::make_shared<TrackPanelResizeHandle>(
pTrack, st.state.m_y, pProject );
result = AssignUIHandlePtr(mResizeHandle, result);
return result;
results.push_back(result);
}
return {};
return results;
}

View File

@ -24,7 +24,7 @@ public:
explicit
TrackPanelResizerCell( std::shared_ptr<Track> pTrack );
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &, const AudacityProject *) override;
std::shared_ptr<Track> FindTrack() override { return mpTrack.lock(); };

View File

@ -107,7 +107,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
virtual ~WaveTrack();
UIHandlePtr DetailedHitTest
std::vector<UIHandlePtr> DetailedHitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;

View File

@ -26,7 +26,7 @@ LabelTrackControls::~LabelTrackControls()
{
}
UIHandlePtr LabelTrackControls::HitTest
std::vector<UIHandlePtr> LabelTrackControls::HitTest
(const TrackPanelMouseState & state,
const AudacityProject *pProject)
{

View File

@ -24,7 +24,7 @@ public:
: TrackControls( pTrack ) {}
~LabelTrackControls();
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) override;

View File

@ -21,23 +21,25 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../Project.h"
#include "../../../TrackPanelMouseEvent.h"
UIHandlePtr LabelTrack::DetailedHitTest
std::vector<UIHandlePtr> LabelTrack::DetailedHitTest
(const TrackPanelMouseState &st,
const AudacityProject *pProject, int, bool)
{
UIHandlePtr result;
std::vector<UIHandlePtr> results;
const wxMouseState &state = st.state;
// Try label movement handles first
UIHandlePtr result;
result = LabelGlyphHandle::HitTest(
mGlyphHandle, state, Pointer<LabelTrack>(this), st.rect);
if (result)
results.push_back(result);
if ( !result )
// Missed glyph, try text box
result = LabelTextHandle::HitTest(
mTextHandle, state, Pointer<LabelTrack>(this));
result = LabelTextHandle::HitTest(
mTextHandle, state, Pointer<LabelTrack>(this));
if (result)
results.push_back(result);
return result;
return results;
}
std::shared_ptr<TrackControls> LabelTrack::GetControls()

View File

@ -30,15 +30,17 @@ NoteTrackControls::~NoteTrackControls()
{
}
UIHandlePtr NoteTrackControls::HitTest
std::vector<UIHandlePtr> NoteTrackControls::HitTest
(const TrackPanelMouseState & st,
const AudacityProject *pProject)
{
// Hits are mutually exclusive, results single
std::vector<UIHandlePtr> results;
const wxMouseState &state = st.state;
const wxRect &rect = st.rect;
if (state.ButtonIsDown(wxMOUSE_BTN_ANY)) {
auto track = std::static_pointer_cast<NoteTrack>(FindTrack());
if (track && track->GetKind() == Track::Note) {
auto result = [&]{
UIHandlePtr result;
if (NULL != (result = MuteButtonHandle::HitTest(
mMuteHandle, state, rect, pProject, track)))
@ -55,6 +57,10 @@ UIHandlePtr NoteTrackControls::HitTest
mClickHandle, state, rect, track)))
return result;
#endif
}();
if (result) {
results.push_back(result);
return results;
}
}

View File

@ -35,7 +35,7 @@ public:
: TrackControls( pTrack ) {}
~NoteTrackControls();
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) override;

View File

@ -22,18 +22,21 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ui/SelectHandle.h"
#include "StretchHandle.h"
UIHandlePtr NoteTrack::DetailedHitTest
std::vector<UIHandlePtr> NoteTrack::DetailedHitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject, int, bool )
{
// Eligible for stretch?
UIHandlePtr result;
std::vector<UIHandlePtr> results;
#ifdef USE_MIDI
result = StretchHandle::HitTest(
mStretchHandle, state, pProject, Pointer<NoteTrack>(this) );
if (result)
results.push_back(result);
#endif
return result;
return results;
}
std::shared_ptr<TrackControls> NoteTrack::GetControls()

View File

@ -27,14 +27,22 @@ NoteTrackVRulerControls::~NoteTrackVRulerControls()
{
}
UIHandlePtr NoteTrackVRulerControls::HitTest
std::vector<UIHandlePtr> NoteTrackVRulerControls::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *pProject)
{
std::vector<UIHandlePtr> results;
UIHandlePtr result;
auto track = std::static_pointer_cast<NoteTrack>(FindTrack());
return NoteTrackVZoomHandle::HitTest(
result = NoteTrackVZoomHandle::HitTest(
mVZoomHandle, st.state, track, st.rect);
if (result)
results.push_back(result);
auto more = TrackVRulerControls::HitTest(st, pProject);
std::copy(more.begin(), more.end(), std::back_inserter(results));
return results;
}
unsigned NoteTrackVRulerControls::HandleWheelRotation

View File

@ -26,7 +26,7 @@ public:
: TrackVRulerControls( pTrack ) {}
~NoteTrackVRulerControls();
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) override;

View File

@ -53,15 +53,17 @@ WaveTrackControls::~WaveTrackControls()
}
UIHandlePtr WaveTrackControls::HitTest
std::vector<UIHandlePtr> WaveTrackControls::HitTest
(const TrackPanelMouseState & st,
const AudacityProject *pProject)
{
// Hits are mutually exclusive, results single
const wxMouseState &state = st.state;
const wxRect &rect = st.rect;
if (state.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
auto track = FindTrack();
if (track && track->GetKind() == Track::Wave) {
std::vector<UIHandlePtr> results;
auto result = [&]{
UIHandlePtr result;
if (NULL != (result = MuteButtonHandle::HitTest(
mMuteHandle, state, rect, pProject, track)))
@ -78,6 +80,10 @@ UIHandlePtr WaveTrackControls::HitTest
if (NULL != (result = PanSliderHandle::HitTest(
mPanHandle, state, rect, track)))
return result;
}();
if (result) {
results.push_back(result);
return results;
}
}

View File

@ -29,7 +29,7 @@ public:
: TrackControls( pTrack ) {}
~WaveTrackControls();
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) override;

View File

@ -23,7 +23,7 @@ Paul Licameli split from TrackPanel.cpp
#include "SampleHandle.h"
#include "../../../ui/TimeShiftHandle.h"
UIHandlePtr WaveTrack::DetailedHitTest
std::vector<UIHandlePtr> WaveTrack::DetailedHitTest
(const TrackPanelMouseState &st,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
{
@ -32,15 +32,20 @@ UIHandlePtr WaveTrack::DetailedHitTest
// If that toolbar were eliminated, this could simplify to a sequence of
// hit test routines describable by a table.
const auto wavetrack = static_cast<WaveTrack*>(st.pCell.get());
bool isWaveform = (wavetrack->GetDisplay() == WaveTrack::Waveform);
UIHandlePtr result;
std::vector<UIHandlePtr> results;
bool isWaveform = (GetDisplay() == WaveTrack::Waveform);
if (bMultiTool && st.state.CmdDown())
if (bMultiTool && st.state.CmdDown()) {
// Ctrl modifier key in multi-tool overrides everything else
// (But this does not do the time shift constrained to the vertical only,
// which is what happens when you hold Ctrl in the Time Shift tool mode)
return TimeShiftHandle::HitAnywhere(
result = TimeShiftHandle::HitAnywhere(
mTimeShiftHandle, Pointer(this), false);
if (result)
results.push_back(result);
return results;
}
// Some special targets are not drawn in spectrogram,
// so don't hit them in such views.
@ -50,8 +55,8 @@ UIHandlePtr WaveTrack::DetailedHitTest
mCutlineHandle, st.state, st.rect,
pProject, Pointer<WaveTrack>(this))))
// This overriding test applies in all tools
return result;
else if (bMultiTool) {
results.push_back(result);
if (bMultiTool) {
// Conditional hit tests
// If Tools toolbar were eliminated, we would keep these
// The priority of these, in case more than one might apply at one
@ -59,35 +64,39 @@ UIHandlePtr WaveTrack::DetailedHitTest
if (NULL != (result = EnvelopeHandle::WaveTrackHitTest(
mEnvelopeHandle, st.state, st.rect,
pProject, Pointer<WaveTrack>(this))))
;
else if (NULL != (result = TimeShiftHandle::HitTest(
results.push_back(result);
if (NULL != (result = TimeShiftHandle::HitTest(
mTimeShiftHandle, st.state, st.rect, Pointer(this))))
// This is the hit test on the "grips" drawn left and
// right in Multi only
;
else if (NULL != (result = SampleHandle::HitTest(
results.push_back(result);
if (NULL != (result = SampleHandle::HitTest(
mSampleHandle, st.state, st.rect,
pProject, Pointer<WaveTrack>(this))))
;
return result;
results.push_back(result);
}
else switch ( currentTool ) {
// Unconditional hits appropriate to the tool
// If tools toolbar were eliminated, we would eliminate these
case envelopeTool: {
auto envelope = GetEnvelopeAtX( st.state.m_x );
return EnvelopeHandle::HitAnywhere(
mEnvelopeHandle, envelope);
else {
switch ( currentTool ) {
// Unconditional hits appropriate to the tool
// If tools toolbar were eliminated, we would eliminate these
case envelopeTool: {
auto envelope = GetEnvelopeAtX( st.state.m_x );
result = EnvelopeHandle::HitAnywhere(
mEnvelopeHandle, envelope);
break;
}
case drawTool:
result = SampleHandle::HitAnywhere(
mSampleHandle, st.state, Pointer<WaveTrack>(this));
default:
break;
}
case drawTool:
return SampleHandle::HitAnywhere(
mSampleHandle, st.state, Pointer<WaveTrack>(this));
default:
break;
if (result)
results.push_back(result);
}
}
return {};
return results;
}
std::shared_ptr<TrackControls> WaveTrack::GetControls()

View File

@ -26,18 +26,23 @@ WaveTrackVRulerControls::~WaveTrackVRulerControls()
{
}
UIHandlePtr WaveTrackVRulerControls::HitTest
std::vector<UIHandlePtr> WaveTrackVRulerControls::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *)
const AudacityProject *pProject)
{
std::vector<UIHandlePtr> results;
auto pTrack = Track::Pointer<WaveTrack>( FindTrack().get() );
if (pTrack) {
auto result = std::make_shared<WaveTrackVZoomHandle>(
pTrack, st.rect, st.state.m_y );
result = AssignUIHandlePtr(mVZoomHandle, result);
return result;
results.push_back(result);
}
return {};
auto more = TrackVRulerControls::HitTest(st, pProject);
std::copy(more.begin(), more.end(), std::back_inserter(results));
return results;
}
unsigned WaveTrackVRulerControls::HandleWheelRotation

View File

@ -26,7 +26,7 @@ public:
: TrackVRulerControls( pTrack ) {}
~WaveTrackVRulerControls();
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *) override;

View File

@ -21,7 +21,7 @@ TimeTrackControls::~TimeTrackControls()
{
}
UIHandlePtr TimeTrackControls::HitTest
std::vector<UIHandlePtr> TimeTrackControls::HitTest
(const TrackPanelMouseState & state,
const AudacityProject *pProject)
{

View File

@ -24,7 +24,7 @@ public:
: TrackControls( pTrack ) {}
~TimeTrackControls();
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) override;

View File

@ -18,12 +18,16 @@ Paul Licameli split from TrackPanel.cpp
#include "../../ui/EnvelopeHandle.h"
UIHandlePtr TimeTrack::DetailedHitTest
std::vector<UIHandlePtr> TimeTrack::DetailedHitTest
(const TrackPanelMouseState &st,
const AudacityProject *pProject, int, bool)
{
return EnvelopeHandle::TimeTrackHitTest
std::vector<UIHandlePtr> results;
auto result = EnvelopeHandle::TimeTrackHitTest
( mEnvelopeHandle, st.state, st.rect, pProject, Pointer<TimeTrack>(this) );
if (result)
results.push_back(result);
return results;
}
std::shared_ptr<TrackControls> TimeTrack::GetControls()

View File

@ -79,14 +79,16 @@ BackgroundCell::~BackgroundCell()
{
}
UIHandlePtr BackgroundCell::HitTest
std::vector<UIHandlePtr> BackgroundCell::HitTest
(const TrackPanelMouseState &,
const AudacityProject *)
{
std::vector<UIHandlePtr> results;
auto result = mHandle.lock();
if (!result)
result = std::make_shared<BackgroundHandle>();
return result;
results.push_back(result);
return results;
}
std::shared_ptr<Track> BackgroundCell::FindTrack()

View File

@ -29,7 +29,7 @@ public:
virtual ~BackgroundCell();
protected:
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *) override;

View File

@ -37,13 +37,16 @@ std::shared_ptr<Track> TrackControls::FindTrack()
return mwTrack.lock();
}
UIHandlePtr TrackControls::HitTest
std::vector<UIHandlePtr> TrackControls::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *project)
{
// Hits are mutually exclusive, results single
const wxMouseState &state = st.state;
const wxRect &rect = st.rect;
UIHandlePtr result;
std::vector<UIHandlePtr> results;
auto pTrack = FindTrack();
// shared pointer to this:
@ -51,18 +54,23 @@ UIHandlePtr TrackControls::HitTest
if (NULL != (result = CloseButtonHandle::HitTest(
mCloseHandle, state, rect, this)))
return result;
results.push_back(result);
if (NULL != (result = MenuButtonHandle::HitTest(
mMenuHandle, state, rect, sThis)))
return result;
results.push_back(result);
if (NULL != (result = MinimizeButtonHandle::HitTest(
mMinimizeHandle, state, rect, this)))
return result;
results.push_back(result);
return TrackSelectHandle::HitAnywhere(
mSelectHandle, pTrack);
if (results.empty()) {
if (NULL != (result = TrackSelectHandle::HitAnywhere(
mSelectHandle, pTrack)))
results.push_back(result);
}
return results;
}
enum

View File

@ -48,7 +48,7 @@ public:
protected:
// An override is supplied for derived classes to call through but it is
// still marked pure virtual
virtual UIHandlePtr HitTest
virtual std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *) override = 0;

View File

@ -25,44 +25,57 @@ Paul Licameli split from TrackPanel.cpp
#include "../../TrackPanelResizerCell.h"
#include "BackgroundCell.h"
UIHandlePtr Track::HitTest
std::vector<UIHandlePtr> Track::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *pProject)
{
UIHandlePtr result;
std::vector<UIHandlePtr> results;
const ToolsToolBar * pTtb = pProject->GetToolsToolBar();
const bool isMultiTool = pTtb->IsDown(multiTool);
const auto currentTool = pTtb->GetCurrentTool();
if ( !isMultiTool && currentTool == zoomTool )
if ( !isMultiTool && currentTool == zoomTool ) {
// Zoom tool is a non-selecting tool that takes precedence in all tracks
// over all other tools, no matter what detail you point at.
return ZoomHandle::HitAnywhere(
result = ZoomHandle::HitAnywhere(
pProject->GetBackgroundCell()->mZoomHandle);
results.push_back(result);
return results;
}
// In other tools, let subclasses determine detailed hits.
auto result =
results =
DetailedHitTest( st, pProject, currentTool, isMultiTool );
// If there is no detailed hit for the subclass, there are still some
// general cases.
// There are still some general cases.
// Sliding applies in more than one track type.
if ( !result && !isMultiTool && currentTool == slideTool )
if ( !isMultiTool && currentTool == slideTool ) {
result = TimeShiftHandle::HitAnywhere(
mTimeShiftHandle, Pointer(this), false);
if (result)
results.push_back(result);
}
// Let the multi-tool right-click handler apply only in default of all
// other detailed hits.
if ( !result && isMultiTool )
if ( isMultiTool ) {
result = ZoomHandle::HitTest(
pProject->GetBackgroundCell()->mZoomHandle, st.state);
if (result)
results.push_back(result);
}
// Finally, default of all is adjustment of the selection box.
if ( !result && ( isMultiTool || currentTool == selectTool) )
if ( isMultiTool || currentTool == selectTool ) {
result = SelectHandle::HitTest(
mSelectHandle, st, pProject, Pointer(this));
if (result)
results.push_back(result);
}
return result;
return results;
}
std::shared_ptr<TrackPanelCell> Track::GetTrackControl()

View File

@ -32,10 +32,10 @@ std::shared_ptr<Track> TrackVRulerControls::FindTrack()
return mwTrack.lock();
}
UIHandlePtr TrackVRulerControls::HitTest
std::vector<UIHandlePtr> TrackVRulerControls::HitTest
(const TrackPanelMouseState &, const AudacityProject *)
{
return {};
return std::vector<UIHandlePtr>{};
}
void TrackVRulerControls::DrawZooming

View File

@ -28,7 +28,7 @@ public:
std::shared_ptr<Track> FindTrack() override;
// Define a default hit test method, just for message and cursor
UIHandlePtr HitTest
std::vector<UIHandlePtr> HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) override;