Changed lifetime management of UIHandle objects, no singletons...

... Rather, construct them during hit tests (also capturing more state sooner
rather than at Click time, and adding some accessors for later use)

This also fixes bug 1677 by other means and avoids similar problems.

A cell may be implemented to re-use a previously hit handle object, not yet
clicked, in a later hit test, by remembering a weak pointer, but TrackPanel
holds the strong pointers that determine when the object is destroyed.

And the objects will surely be destroyed after drag-release, or ESC key.

For now they are also destroyed whenever not dragging, and hit-testing is
re-invoked; that will be changed later, so that the re-use mentioned above
becomes effective, but still they will be destroyed when the pointer moves
from one cell to another.
This commit is contained in:
Paul Licameli 2017-07-05 16:45:55 -04:00
parent d2fbca83b2
commit 2c1a16f593
75 changed files with 891 additions and 678 deletions

View File

@ -12,10 +12,13 @@ Paul Licameli
#define __AUDACITY_HIT_TEST_RESULT__
#include <wx/string.h>
#include "MemoryX.h"
class UIHandle;
class wxCursor;
using UIHandlePtr = std::shared_ptr<UIHandle>;
struct HitTestPreview
{
HitTestPreview()
@ -39,12 +42,12 @@ struct HitTestResult
HitTestResult()
{}
HitTestResult(HitTestPreview preview_, UIHandle *handle_)
HitTestResult(HitTestPreview preview_, UIHandlePtr handle_)
: preview(preview_), handle(handle_)
{}
HitTestPreview preview {};
UIHandle *handle {};
UIHandlePtr handle {};
};
#endif

View File

@ -105,6 +105,8 @@ const int NUM_GLYPH_CONFIGS = 3;
const int NUM_GLYPH_HIGHLIGHTS = 4;
const int MAX_NUM_ROWS =80;
class LabelGlyphHandle;
class LabelTextHandle;
class AUDACITY_DLL_API LabelTrack final : public Track
{
@ -317,6 +319,9 @@ private:
static wxFont msFont;
std::weak_ptr<LabelGlyphHandle> mGlyphHandle;
std::weak_ptr<LabelTextHandle> mTextHandle;
protected:
std::shared_ptr<TrackControls> GetControls() override;
std::shared_ptr<TrackVRulerControls> GetVRulerControls() override;

View File

@ -336,11 +336,7 @@ void NoteTrack::DrawLabelControls
AColor::MIDIChannel(&dc, 0); // always return with gray color selected
}
// Handles clicking within the midi controls rect (same as DrawLabelControls).
// This is somewhat oddly written, as these aren't real buttons - they act
// when the mouse goes down; you can't hold it pressed and move off of it.
// Left-clicking toggles a single channel; right-clicking turns off all other channels.
bool NoteTrack::LabelClick(const wxRect &rect, int mx, int my, bool right)
int NoteTrack::FindChannel(const wxRect &rect, int mx, int my)
{
wxASSERT_MSG(rect.width % 4 == 0, "Midi channel control rect width must be divisible by 4");
wxASSERT_MSG(rect.height % 4 == 0, "Midi channel control rect height must be divisible by 4");
@ -351,8 +347,17 @@ bool NoteTrack::LabelClick(const wxRect &rect, int mx, int my, bool right)
int col = (mx - rect.x) / cellWidth;
int row = (my - rect.y) / cellHeight;
int channel = row * 4 + col;
return row * 4 + col;
}
// Handles clicking within the midi controls rect (same as DrawLabelControls).
// This is somewhat oddly written, as these aren't real buttons - they act
// when the mouse goes down; you can't hold it pressed and move off of it.
// Left-clicking toggles a single channel; right-clicking turns off all other channels.
bool NoteTrack::LabelClick(const wxRect &rect, int mx, int my, bool right)
{
auto channel = FindChannel(rect, mx, my);
if (right)
SoloVisibleChan(channel);
else

View File

@ -61,6 +61,8 @@ using NoteTrackBase =
using QuantizedTimeAndBeat = std::pair< double, double >;
class StretchHandle;
class AUDACITY_DLL_API NoteTrack final
: public NoteTrackBase
{
@ -89,6 +91,7 @@ class AUDACITY_DLL_API NoteTrack final
static void DrawLabelControls
( const NoteTrack *pTrack, wxDC & dc, const wxRect &rect );
int FindChannel(const wxRect &rect, int mx, int my);
bool LabelClick(const wxRect &rect, int x, int y, bool right);
void SetSequence(std::unique_ptr<Alg_seq> &&seq);
@ -242,6 +245,8 @@ class AUDACITY_DLL_API NoteTrack final
int mVisibleChannels; // bit set of visible channels
int mLastMidiPosition;
std::weak_ptr<StretchHandle> mStretchHandle;
protected:
std::shared_ptr<TrackControls> GetControls() override;
std::shared_ptr<TrackVRulerControls> GetVRulerControls() override;

View File

@ -806,6 +806,8 @@ public:
public:
PlaybackScroller &GetPlaybackScroller() { return *mPlaybackScroller; }
std::shared_ptr<BackgroundCell> GetBackgroundCell() const
{ return mBackgroundCell; }
DECLARE_EVENT_TABLE()
};

View File

@ -23,6 +23,8 @@ class Envelope;
class Ruler;
class ZoomInfo;
class EnvelopeHandle;
class TimeTrack final : public Track {
public:
@ -141,6 +143,8 @@ class TimeTrack final : public Track {
bool mDisplayLog;
bool mRescaleXMLValues; // needed for backward-compatibility with older project files
std::weak_ptr<EnvelopeHandle> mEnvelopeHandle;
/** @brief Copy the metadata from another track but not the points
*
* Copies the Name, DefaultName, Range and Display data from the source track

View File

@ -44,6 +44,9 @@ class NoteTrack;
class AudacityProject;
class ZoomInfo;
class SelectHandle;
class TimeShiftHandle;
WX_DEFINE_USER_EXPORTED_ARRAY(Track*, TrackArray, class AUDACITY_DLL_API);
using WaveTrackArray = std::vector < WaveTrack* > ;
@ -318,6 +321,9 @@ protected:
std::shared_ptr<TrackControls> mpControls;
std::shared_ptr<TrackVRulerControls> mpVRulerContols;
std::shared_ptr<TrackPanelResizerCell> mpResizer;
std::weak_ptr<SelectHandle> mSelectHandle;
std::weak_ptr<TimeShiftHandle> mTimeShiftHandle;
};
class AUDACITY_DLL_API AudioTrack /* not final */ : public Track

View File

@ -770,7 +770,7 @@ void TrackPanel::CancelDragging()
ProcessUIHandleResult(
this, mRuler, pTrack.get(), NULL, refreshResult);
mpClickedTrack.reset();
mUIHandle = NULL;
mUIHandle.reset();
Uncapture();
}
}
@ -1465,7 +1465,7 @@ try
(this, mRuler, pClickedTrack.get(), pTrack.get(), refreshResult);
if (refreshResult & RefreshCode::Cancelled) {
// Drag decided to abort itself
mUIHandle = NULL;
mUIHandle.reset();
mpClickedTrack.reset();
Uncapture( &event );
}
@ -1484,7 +1484,7 @@ try
// Null this pointer 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 = nullptr;
mUIHandle.reset();
UIHandle::Result refreshResult =
uiHandle->Release( tpmEvent, GetProject(), this );
ProcessUIHandleResult
@ -1553,7 +1553,7 @@ void TrackPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
UIHandle::Result refreshResult =
mUIHandle->Click( tpmEvent, GetProject() );
if (refreshResult & RefreshCode::Cancelled)
mUIHandle = NULL;
mUIHandle.reset();
else
mpClickedTrack = pTrack;
ProcessUIHandleResult
@ -3113,7 +3113,7 @@ TrackPanelCellIterator::TrackPanelCellIterator(TrackPanel *trackPanel, bool begi
mpCell = mpTrack;
else
mpCell = trackPanel->GetBackgroundCell();
}
}
const auto size = mPanel->GetSize();
mRect = { 0, 0, size.x, size.y };

View File

@ -54,6 +54,7 @@ class NoteTrack;
class WaveTrack;
class WaveClip;
class UIHandle;
using UIHandlePtr = std::shared_ptr<UIHandle>;
// Declared elsewhere, to reduce compilation dependencies
class TrackPanelListener;
@ -528,8 +529,7 @@ protected:
protected:
std::weak_ptr<Track> mpClickedTrack;
// TrackPanel is not responsible for memory management:
UIHandle *mUIHandle {};
UIHandlePtr mUIHandle;
std::shared_ptr<TrackPanelCell> mpBackground;

View File

@ -32,7 +32,6 @@ public:
// appropriate to the mouse position, modifier keys, and button-down state.
// The button-down state passed to the function is as it will be at click
// time -- not necessarily as it is now.
// TrackPanel is not responsible for memory management of the handler.
virtual HitTestResult HitTest
(const TrackPanelMouseState &state,
const AudacityProject *pProject) = 0;

View File

@ -28,16 +28,6 @@ Paul Licameli split from TrackPanel.cpp
#include "WaveTrack.h"
#endif
TrackPanelResizeHandle::TrackPanelResizeHandle()
{
}
TrackPanelResizeHandle &TrackPanelResizeHandle::Instance()
{
static TrackPanelResizeHandle instance;
return instance;
}
HitTestPreview TrackPanelResizeHandle::HitPreview(bool bLinked)
{
static wxCursor resizeCursor{ wxCURSOR_SIZENS };
@ -69,30 +59,14 @@ TrackPanelResizeHandle::~TrackPanelResizeHandle()
UIHandle::Result TrackPanelResizeHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
const wxMouseEvent &event = evt.event;
const auto pCell =
static_cast<CommonTrackPanelCell*>(evt.pCell.get());
auto track = pCell->FindTrack().get();
if (track && dynamic_cast< TrackControls * >( pCell )) {
// Clicked under a label;
// if stereo, replace left channel with the right:
if (track && track->GetLinked())
track = track->GetLink();
}
if (!track)
return RefreshCode::Cancelled;
mpTrack = Track::Pointer( track );
/// ButtonDown means they just clicked and haven't released yet.
/// We use this opportunity to save which track they clicked on,
/// and the initial height of the track, so as they drag we can
/// update the track size.
mMouseClickY = event.m_y;
TrackList *const tracks = pProject->GetTracks();
return RefreshCode::RefreshNone;
}
TrackPanelResizeHandle::TrackPanelResizeHandle
( const std::shared_ptr<Track> &track, int y, const AudacityProject *pProject )
: mpTrack{ track }
, mMouseClickY( y )
{
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
if (MONO_WAVE_PAN(track)){
//STM: Determine whether we should rescale one or two tracks
@ -116,11 +90,12 @@ UIHandle::Result TrackPanelResizeHandle::Click
else
#endif
{
Track *prev = tracks->GetPrev(track);
Track *next = tracks->GetNext(track);
auto tracks = pProject->GetTracks();
Track *prev = tracks->GetPrev(track.get());
Track *next = tracks->GetNext(track.get());
//STM: Determine whether we should rescale one or two tracks
if (prev && prev->GetLink() == track) {
if (prev && prev->GetLink() == track.get()) {
// mpTrack is the lower track
mInitialTrackHeight = track->GetHeight();
mInitialActualHeight = track->GetActualHeight();
@ -146,8 +121,6 @@ UIHandle::Result TrackPanelResizeHandle::Click
mMode = IsResizing;
}
}
return RefreshCode::RefreshNone;
}
UIHandle::Result TrackPanelResizeHandle::Drag

View File

@ -20,16 +20,21 @@ class TrackPanelCellIterator;
class TrackPanelResizeHandle final : public UIHandle
{
TrackPanelResizeHandle();
TrackPanelResizeHandle(const TrackPanelResizeHandle&) = delete;
TrackPanelResizeHandle &operator=(const TrackPanelResizeHandle&) = delete;
public:
static TrackPanelResizeHandle& Instance();
explicit TrackPanelResizeHandle
( const std::shared_ptr<Track> &pTrack, int y,
const AudacityProject *pProject );
TrackPanelResizeHandle &operator=(const TrackPanelResizeHandle&) = default;
static HitTestPreview HitPreview(bool bLinked);
virtual ~TrackPanelResizeHandle();
std::shared_ptr<Track> GetTrack() const { return mpTrack.lock(); }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;

View File

@ -10,18 +10,29 @@ Paul Licameli split from TrackPanel.cpp
#include "Audacity.h"
#include "TrackPanelResizerCell.h"
#include "TrackPanelResizeHandle.h"
#include "TrackPanelMouseEvent.h"
#include "HitTestResult.h"
#include <wx/mousestate.h>
TrackPanelResizerCell::TrackPanelResizerCell( std::shared_ptr<Track> pTrack )
: mpTrack{ pTrack }
{}
HitTestResult TrackPanelResizerCell::HitTest
(const TrackPanelMouseState &, const AudacityProject *)
(const TrackPanelMouseState &st, const AudacityProject *pProject)
{
return {
TrackPanelResizeHandle::HitPreview( mBetweenTracks ),
&TrackPanelResizeHandle::Instance()
};
auto pTrack = mpTrack.lock();
if (pTrack) {
auto result = std::make_shared<TrackPanelResizeHandle>(
pTrack, st.state.m_y, pProject );
result = AssignUIHandlePtr(mResizeHandle, result);
return {
result->Preview(st, pProject),
result
};
}
return {};
}

View File

@ -13,6 +13,8 @@
#include "tracks/ui/CommonTrackPanelCell.h"
class TrackPanelResizeHandle;
class TrackPanelResizerCell : public CommonTrackPanelCell
{
TrackPanelResizerCell(const TrackPanelResizerCell&) = delete;
@ -29,7 +31,8 @@ public:
private:
friend class TrackPanelCellIterator;
std::weak_ptr<Track> mpTrack;
bool mBetweenTracks {};
std::weak_ptr<TrackPanelResizeHandle> mResizeHandle;
};
#endif

View File

@ -8,6 +8,7 @@ Paul Licameli
**********************************************************************/
#include "Audacity.h"
#include "UIHandle.h"
UIHandle::~UIHandle()

View File

@ -24,6 +24,8 @@ class TrackPanelCell;
struct TrackPanelMouseEvent;
struct TrackPanelMouseState;
#include "MemoryX.h"
// A TrackPanelCell reports a handle object of some subclass, in response to a
// hit test at a mouse position; then this handle processes certain events,
// and maintains necessary state through click-drag-release event sequences.
@ -99,4 +101,26 @@ public:
virtual void OnProjectChange(AudacityProject *pProject);
};
using UIHandlePtr = std::shared_ptr<UIHandle>;
// A frequent convenience
template<typename Subclass>
std::shared_ptr<Subclass> AssignUIHandlePtr
( std::weak_ptr<Subclass> &holder, const std::shared_ptr<Subclass> &pNew )
{
// Either assign to a null weak_ptr, or else rewrite what the weak_ptr
// points at. Thus a handle already pointed at changes its state but not its
// identity. This may matter for the framework that holds the strong
// pointers.
auto ptr = holder.lock();
if (!ptr) {
holder = pNew;
return pNew;
}
else {
*ptr = std::move(*pNew);
return ptr;
}
}
#endif

View File

@ -28,6 +28,10 @@ class SpectrogramSettings;
class WaveformSettings;
class TimeWarper;
class CutlineHandle;
class SampleHandle;
class EnvelopeHandle;
//
// Tolerance for merging wave tracks (in seconds)
//
@ -636,6 +640,10 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
std::unique_ptr<SpectrogramSettings> mpSpectrumSettings;
std::unique_ptr<WaveformSettings> mpWaveformSettings;
std::weak_ptr<CutlineHandle> mCutlineHandle;
std::weak_ptr<SampleHandle> mSampleHandle;
std::weak_ptr<EnvelopeHandle> mEnvelopeHandle;
protected:
std::shared_ptr<TrackControls> GetControls() override;
std::shared_ptr<TrackVRulerControls> GetVRulerControls() override;

View File

@ -31,7 +31,7 @@ struct LabelDefaultClickHandle::LabelState {
void LabelDefaultClickHandle::SaveState( AudacityProject *pProject )
{
mLabelState = std::make_unique<LabelState>();
mLabelState = std::make_shared<LabelState>();
auto &pairs = mLabelState->mPairs;
TrackList *const tracks = pProject->GetTracks();
TrackListIterator iter(tracks);

View File

@ -23,12 +23,13 @@ class LabelTrack;
class LabelDefaultClickHandle /* not final */ : public UIHandle
{
LabelDefaultClickHandle(const LabelDefaultClickHandle&) = delete;
LabelDefaultClickHandle &operator=(const LabelDefaultClickHandle&) = delete;
public:
LabelDefaultClickHandle();
virtual ~LabelDefaultClickHandle();
LabelDefaultClickHandle &operator=(LabelDefaultClickHandle&&) = default;
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
@ -45,7 +46,7 @@ public:
private:
struct LabelState;
std::unique_ptr< LabelState > mLabelState;
std::shared_ptr< LabelState > mLabelState;
void SaveState( AudacityProject *pProject );
void RestoreState( AudacityProject *pProject );
};

View File

@ -23,18 +23,14 @@ Paul Licameli split from TrackPanel.cpp
#include <wx/cursor.h>
#include <wx/translation.h>
LabelGlyphHandle::LabelGlyphHandle()
{
}
LabelGlyphHandle &LabelGlyphHandle::Instance()
{
static LabelGlyphHandle instance;
return instance;
}
LabelGlyphHandle::LabelGlyphHandle
(const std::shared_ptr<LabelTrack> &pLT, const wxRect &rect)
: mpLT{ pLT }
, mRect{ rect }
{}
HitTestPreview LabelGlyphHandle::HitPreview
(bool hitCenter, unsigned refreshResult)
(bool hitCenter, unsigned refreshResult)
{
static wxCursor arrowCursor{ wxCURSOR_ARROW };
return {
@ -49,7 +45,9 @@ HitTestPreview LabelGlyphHandle::HitPreview
}
HitTestResult LabelGlyphHandle::HitTest
(const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT)
(std::weak_ptr<LabelGlyphHandle> &holder,
const wxMouseState &state,
const std::shared_ptr<LabelTrack> &pLT, const wxRect &rect)
{
using namespace RefreshCode;
unsigned refreshResult = RefreshNone;
@ -70,16 +68,18 @@ HitTestResult LabelGlyphHandle::HitTest
// signal this by setting the tip.
if (edge != 0)
{
auto result = std::make_shared<LabelGlyphHandle>( pLT, rect );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(pLT->mbHitCenter, refreshResult),
&Instance()
result
};
}
else {
// An empty result, except maybe, unusually, the refresh
return {
{ wxString{}, nullptr, refreshResult },
nullptr
{}
};
}
}
@ -93,15 +93,10 @@ UIHandle::Result LabelGlyphHandle::Click
{
auto result = LabelDefaultClickHandle::Click( evt, pProject );
const auto pCell = evt.pCell;
const wxMouseEvent &event = evt.event;
const wxRect &rect = evt.rect;
mpLT = std::static_pointer_cast<LabelTrack>(pCell);
mRect = rect;
ViewInfo &viewInfo = pProject->GetViewInfo();
mpLT->HandleGlyphClick(event, rect, viewInfo, &viewInfo.selectedRegion);
mpLT->HandleGlyphClick(event, mRect, viewInfo, &viewInfo.selectedRegion);
if (! mpLT->IsAdjustingLabel() )
{

View File

@ -21,15 +21,19 @@ class LabelTrack;
class LabelGlyphHandle final : public LabelDefaultClickHandle
{
LabelGlyphHandle();
LabelGlyphHandle(const LabelGlyphHandle&) = delete;
LabelGlyphHandle &operator=(const LabelGlyphHandle&) = delete;
static LabelGlyphHandle& Instance();
static HitTestPreview HitPreview(bool hitCenter, unsigned refreshResult);
public:
explicit LabelGlyphHandle
(const std::shared_ptr<LabelTrack> &pLT, const wxRect &rect);
LabelGlyphHandle &operator=(LabelGlyphHandle&&) = default;
static HitTestResult HitTest
(const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT);
(std::weak_ptr<LabelGlyphHandle> &holder,
const wxMouseState &state,
const std::shared_ptr<LabelTrack> &pLT, const wxRect &rect);
virtual ~LabelGlyphHandle();

View File

@ -18,15 +18,11 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ViewInfo.h"
#include "../../../images/Cursors.h"
LabelTextHandle::LabelTextHandle()
{
}
LabelTextHandle &LabelTextHandle::Instance()
{
static LabelTextHandle instance;
return instance;
}
LabelTextHandle::LabelTextHandle
( const std::shared_ptr<LabelTrack> &pLT, int labelNum )
: mpLT{ pLT }
, mLabelNum{ labelNum }
{}
HitTestPreview LabelTextHandle::HitPreview()
{
@ -39,13 +35,18 @@ HitTestPreview LabelTextHandle::HitPreview()
}
HitTestResult LabelTextHandle::HitTest
(const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT)
(std::weak_ptr<LabelTextHandle> &holder,
const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT)
{
// If Control is down, let the select handle be hit instead
int labelNum;
if (!state.ControlDown() &&
pLT->OverATextBox(state.m_x, state.m_y) >= 0)
(labelNum = pLT->OverATextBox(state.m_x, state.m_y) ) >= 0) {
auto result = std::make_shared<LabelTextHandle>( pLT, labelNum );
result = AssignUIHandlePtr(holder, result);
// There was no cursor change or status message for mousing over a label text box
return { HitPreview(), &Instance() };
return { HitPreview(), result };
}
return {};
}
@ -57,6 +58,10 @@ LabelTextHandle::~LabelTextHandle()
UIHandle::Result LabelTextHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
auto pLT = mpLT.lock();
if (!pLT)
return RefreshCode::Cancelled;
auto result = LabelDefaultClickHandle::Click( evt, pProject );
auto &selectionState = pProject->GetSelectionState();
@ -64,12 +69,9 @@ UIHandle::Result LabelTextHandle::Click
mChanger =
std::make_unique< SelectionStateChanger >( selectionState, *tracks );
const auto pCell = evt.pCell;
const wxMouseEvent &event = evt.event;
ViewInfo &viewInfo = pProject->GetViewInfo();
auto pLT = std::static_pointer_cast<LabelTrack>(pCell);
mpLT = pLT;
mSelectedRegion = viewInfo.selectedRegion;
pLT->HandleTextClick( event, evt.rect, viewInfo, &viewInfo.selectedRegion );
wxASSERT(pLT->IsSelected());

View File

@ -23,19 +23,24 @@ class SelectionStateChanger;
class LabelTextHandle final : public LabelDefaultClickHandle
{
LabelTextHandle();
LabelTextHandle(const LabelTextHandle&) = delete;
LabelTextHandle &operator=(const LabelTextHandle&) = delete;
static LabelTextHandle& Instance();
static HitTestPreview HitPreview();
public:
static HitTestResult HitTest(
const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT);
static HitTestResult HitTest
(std::weak_ptr<LabelTextHandle> &holder,
const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT);
LabelTextHandle &operator=(LabelTextHandle&&) = default;
explicit LabelTextHandle
( const std::shared_ptr<LabelTrack> &pLT, int labelNum );
virtual ~LabelTextHandle();
std::shared_ptr<LabelTrack> GetTrack() const { return mpLT.lock(); }
int GetLabelNum() const { return mLabelNum; }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
@ -54,6 +59,7 @@ public:
private:
std::weak_ptr<LabelTrack> mpLT {};
int mLabelNum{ -1 };
int mLabelTrackStartXPos { -1 };
int mLabelTrackStartYPos { -1 };
SelectedRegion mSelectedRegion{};

View File

@ -29,12 +29,14 @@ HitTestResult LabelTrack::DetailedHitTest
const wxMouseState &state = st.state;
// Try label movement handles first
result = LabelGlyphHandle::HitTest(state, Pointer<LabelTrack>(this));
result = LabelGlyphHandle::HitTest(
mGlyphHandle, state, Pointer<LabelTrack>(this), st.rect);
auto refresh = result.preview.refreshCode; // kludge
if ( !result.handle ) {
// Missed glyph, try text box
result = LabelTextHandle::HitTest(state, Pointer<LabelTrack>(this));
result = LabelTextHandle::HitTest(
mTextHandle, state, Pointer<LabelTrack>(this));
result.preview.refreshCode |= refresh; // kludge
}

View File

@ -18,22 +18,21 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../../RefreshCode.h"
#include "../../../../TrackPanel.h"
NoteTrackButtonHandle::NoteTrackButtonHandle()
{
}
NoteTrackButtonHandle::NoteTrackButtonHandle
( const std::shared_ptr<NoteTrack> &pTrack,
int channel, const wxRect &rect )
: mpTrack{ pTrack }
, mChannel{ channel }
, mRect{ rect }
{}
NoteTrackButtonHandle::~NoteTrackButtonHandle()
{
}
NoteTrackButtonHandle &NoteTrackButtonHandle::Instance()
{
static NoteTrackButtonHandle instance;
return instance;
}
HitTestResult NoteTrackButtonHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<NoteTrackButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const std::shared_ptr<NoteTrack> &pTrack)
{
wxRect midiRect;
@ -42,12 +41,14 @@ HitTestResult NoteTrackButtonHandle::HitTest
return {};
if (pTrack->GetKind() == Track::Note &&
midiRect.Contains(state.m_x, state.m_y)) {
Instance().mpTrack = pTrack;
Instance().mRect = midiRect;
return {
HitTestPreview(),
&Instance()
};
auto channel = pTrack->FindChannel(midiRect, state.m_x, state.m_y);
auto result = std::make_shared<NoteTrackButtonHandle>(
pTrack, channel, midiRect );
result = AssignUIHandlePtr(holder, result);
return {
HitTestPreview(),
result
};
}
else
return {};
@ -68,6 +69,10 @@ UIHandle::Result NoteTrackButtonHandle::Drag
HitTestPreview NoteTrackButtonHandle::Preview
(const TrackPanelMouseState &, const AudacityProject *)
{
// auto pTrack = pProject->GetTracks()->Lock(mpTrack);
auto pTrack = mpTrack.lock();
if ( !pTrack )
return {};
// No special message or cursor
return {};
}

View File

@ -24,15 +24,24 @@ struct HitTestResult;
class NoteTrackButtonHandle : public UIHandle
{
NoteTrackButtonHandle(const NoteTrackButtonHandle&);
NoteTrackButtonHandle &operator=(const NoteTrackButtonHandle&);
NoteTrackButtonHandle();
virtual ~NoteTrackButtonHandle();
static NoteTrackButtonHandle& Instance();
public:
explicit NoteTrackButtonHandle
( const std::shared_ptr<NoteTrack> &pTrack,
int channel, const wxRect &rect );
NoteTrackButtonHandle &operator=(const NoteTrackButtonHandle&) = default;
virtual ~NoteTrackButtonHandle();
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
const std::shared_ptr<NoteTrack> &pTrack);
(std::weak_ptr<NoteTrackButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const std::shared_ptr<NoteTrack> &pTrack);
int GetChannel() const { return mChannel; }
protected:
Result Click
@ -52,6 +61,7 @@ protected:
Result Cancel(AudacityProject *pProject) override;
std::weak_ptr<NoteTrack> mpTrack;
int mChannel{ -1 };
wxRect mRect{};
};

View File

@ -40,21 +40,19 @@ HitTestResult NoteTrackControls::HitTest
auto track = std::static_pointer_cast<NoteTrack>(FindTrack());
if (track && track->GetKind() == Track::Note) {
HitTestResult result;
if (NULL !=
(result = MuteButtonHandle::HitTest
(state, rect, pProject, track)).handle)
if (NULL != (result = MuteButtonHandle::HitTest(
mMuteHandle, state, rect, pProject, track)).handle)
return result;
if (NULL !=
(result = SoloButtonHandle::HitTest
(state, rect, pProject, track)).handle)
if (NULL != (result = SoloButtonHandle::HitTest(
mSoloHandle, state, rect, pProject, track)).handle)
return result;
#ifdef EXPERIMENTAL_MIDI_OUT
if (NULL != (result =
VelocitySliderHandle::HitTest(state, rect, pProject, track)).handle)
if (NULL != (result = VelocitySliderHandle::HitTest(
mVelocityHandle, state, rect, pProject, track)).handle)
return result;
if (NULL != (result =
NoteTrackButtonHandle::HitTest(state, rect, track)).handle)
if (NULL != (result = NoteTrackButtonHandle::HitTest(
mClickHandle, state, rect, track)).handle)
return result;
#endif
}

View File

@ -12,12 +12,23 @@ Paul Licameli split from TrackPanel.cpp
#define __AUDACITY_NOTE_TRACK_CONTROLS__
#include "../../../ui/TrackControls.h"
#include "../../../../MemoryX.h"
class MuteButtonHandle;
class SoloButtonHandle;
class NoteTrackButtonHandle;
class VelocitySliderHandle;
///////////////////////////////////////////////////////////////////////////////
class NoteTrackControls : public TrackControls
{
NoteTrackControls(const NoteTrackControls&) = delete;
NoteTrackControls &operator=(const NoteTrackControls&) = delete;
std::weak_ptr<MuteButtonHandle> mMuteHandle;
std::weak_ptr<SoloButtonHandle> mSoloHandle;
std::weak_ptr<NoteTrackButtonHandle> mClickHandle;
std::weak_ptr<VelocitySliderHandle> mVelocityHandle;
public:
explicit
NoteTrackControls( std::shared_ptr<Track> pTrack )

View File

@ -21,21 +21,16 @@
#include "../../../../UndoManager.h"
#include "../../../../NoteTrack.h"
VelocitySliderHandle::VelocitySliderHandle()
: SliderHandle()
{
}
VelocitySliderHandle::VelocitySliderHandle
( SliderFn sliderFn, const wxRect &rect,
const std::shared_ptr<Track> &pTrack )
: SliderHandle{ sliderFn, rect, pTrack }
{}
VelocitySliderHandle::~VelocitySliderHandle()
{
}
VelocitySliderHandle &VelocitySliderHandle::Instance()
{
static VelocitySliderHandle instance;
return instance;
}
std::shared_ptr<NoteTrack> VelocitySliderHandle::GetNoteTrack()
{
return std::static_pointer_cast<NoteTrack>(mpTrack.lock());
@ -69,7 +64,8 @@ UIHandle::Result VelocitySliderHandle::CommitChanges
HitTestResult VelocitySliderHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<VelocitySliderHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack)
{
if (!state.ButtonIsDown(wxMOUSE_BTN_LEFT))
@ -80,16 +76,17 @@ HitTestResult VelocitySliderHandle::HitTest
if ( TrackInfo::HideTopItem( rect, sliderRect, kTrackInfoSliderAllowance ) )
return {};
if (sliderRect.Contains(state.m_x, state.m_y)) {
Instance().mSliderFn =
auto sliderFn =
[]( AudacityProject *pProject, const wxRect &sliderRect, Track *pTrack ) {
return TrackInfo::VelocitySlider
(sliderRect, static_cast<NoteTrack*>( pTrack ), true,
const_cast<TrackPanel*>(pProject->GetTrackPanel()));
};
Instance().mRect = sliderRect;
Instance().mpTrack = pTrack;
auto result = std::make_shared<VelocitySliderHandle>(
sliderFn, sliderRect, pTrack );
result = AssignUIHandlePtr(holder, result);
return { HitPreview(), &Instance() };
return { HitPreview(), result };
}
else
return {};

View File

@ -25,14 +25,18 @@ struct HitTestResult;
class VelocitySliderHandle final : public SliderHandle
{
VelocitySliderHandle(const VelocitySliderHandle&) = delete;
VelocitySliderHandle &operator=(const VelocitySliderHandle&) = delete;
VelocitySliderHandle();
virtual ~VelocitySliderHandle();
static VelocitySliderHandle& Instance();
std::shared_ptr<NoteTrack> GetNoteTrack();
public:
explicit VelocitySliderHandle
( SliderFn sliderFn, const wxRect &rect,
const std::shared_ptr<Track> &pTrack );
VelocitySliderHandle &operator=(const VelocitySliderHandle&) = default;
virtual ~VelocitySliderHandle();
protected:
float GetValue() override;
Result SetValue
@ -44,7 +48,8 @@ protected:
public:
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<VelocitySliderHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack);
};

View File

@ -29,8 +29,8 @@ HitTestResult NoteTrack::DetailedHitTest
// Eligible for stretch?
HitTestResult result;
#ifdef USE_MIDI
StretchHandle::StretchState stretchState;
result = StretchHandle::HitTest( state, pProject, Pointer<NoteTrack>(this), stretchState );
result = StretchHandle::HitTest(
mStretchHandle, state, pProject, Pointer<NoteTrack>(this) );
#endif
return result;

View File

@ -31,7 +31,10 @@ HitTestResult NoteTrackVRulerControls::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *)
{
return NoteTrackVZoomHandle::HitTest(st.state);
UIHandlePtr result;
auto track = std::static_pointer_cast<NoteTrack>(FindTrack());
return NoteTrackVZoomHandle::HitTest(
mVZoomHandle, st.state, track, st.rect);
}
unsigned NoteTrackVRulerControls::HandleWheelRotation

View File

@ -13,6 +13,8 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ui/TrackVRulerControls.h"
class NoteTrackVZoomHandle;
class NoteTrackVRulerControls final : public TrackVRulerControls
{
NoteTrackVRulerControls(const NoteTrackVRulerControls&) = delete;
@ -31,6 +33,9 @@ public:
unsigned HandleWheelRotation
(const TrackPanelMouseEvent &event,
AudacityProject *pProject) override;
private:
std::weak_ptr<NoteTrackVZoomHandle> mVZoomHandle;
};
#endif

View File

@ -34,16 +34,11 @@ namespace
///////////////////////////////////////////////////////////////////////////////
NoteTrackVZoomHandle::NoteTrackVZoomHandle()
: mZoomStart(0), mZoomEnd(0), mRect()
{
}
NoteTrackVZoomHandle &NoteTrackVZoomHandle::Instance()
{
static NoteTrackVZoomHandle instance;
return instance;
}
NoteTrackVZoomHandle::NoteTrackVZoomHandle
(const std::shared_ptr<NoteTrack> &pTrack, const wxRect &rect, int y)
: mZoomStart(y), mZoomEnd(y), mRect(rect)
, mpTrack{ pTrack }
{}
HitTestPreview NoteTrackVZoomHandle::HitPreview(const wxMouseState &state)
{
@ -57,9 +52,18 @@ HitTestPreview NoteTrackVZoomHandle::HitPreview(const wxMouseState &state)
};
}
HitTestResult NoteTrackVZoomHandle::HitTest(const wxMouseState &state)
HitTestResult NoteTrackVZoomHandle::HitTest
(std::weak_ptr<NoteTrackVZoomHandle> &holder,
const wxMouseState &state,
const std::shared_ptr<NoteTrack> &pTrack, const wxRect &rect)
{
return HitTestResult(HitPreview(state), &Instance());
if (pTrack) {
auto result = std::make_shared<NoteTrackVZoomHandle>(
pTrack, rect, state.m_y);
result = AssignUIHandlePtr(holder, result);
return HitTestResult(HitPreview(state), result);
}
return {};
}
NoteTrackVZoomHandle::~NoteTrackVZoomHandle()
@ -67,16 +71,8 @@ NoteTrackVZoomHandle::~NoteTrackVZoomHandle()
}
UIHandle::Result NoteTrackVZoomHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
(const TrackPanelMouseEvent &, AudacityProject *)
{
mpTrack = std::static_pointer_cast<NoteTrack>(
static_cast<NoteTrackVRulerControls*>(evt.pCell.get())->FindTrack() );
mRect = evt.rect;
const wxMouseEvent &event = evt.event;
mZoomStart = event.m_y;
mZoomEnd = event.m_y;
// change note track to zoom like audio track
// mpTrack->StartVScroll();

View File

@ -21,17 +21,24 @@ class NoteTrack;
class NoteTrackVZoomHandle : public UIHandle
{
NoteTrackVZoomHandle();
NoteTrackVZoomHandle(const NoteTrackVZoomHandle&);
NoteTrackVZoomHandle &operator=(const NoteTrackVZoomHandle&);
static NoteTrackVZoomHandle& Instance();
static HitTestPreview HitPreview(const wxMouseState &state);
public:
static HitTestResult HitTest(const wxMouseState &state);
explicit NoteTrackVZoomHandle
(const std::shared_ptr<NoteTrack> &pTrack, const wxRect &rect, int y);
NoteTrackVZoomHandle &operator=(const NoteTrackVZoomHandle&) = default;
static HitTestResult HitTest
(std::weak_ptr<NoteTrackVZoomHandle> &holder,
const wxMouseState &state,
const std::shared_ptr<NoteTrack> &pTrack, const wxRect &rect);
virtual ~NoteTrackVZoomHandle();
std::shared_ptr<NoteTrack> GetTrack() const { return mpTrack.lock(); }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;

View File

@ -24,15 +24,11 @@ Paul Licameli split from TrackPanel.cpp
#include <algorithm>
StretchHandle::StretchHandle()
{
}
StretchHandle &StretchHandle::Instance()
{
static StretchHandle instance;
return instance;
}
StretchHandle::StretchHandle
( const std::shared_ptr<NoteTrack> &pTrack, const StretchState &stretchState )
: mpTrack{ pTrack }
, mStretchState{ stretchState }
{}
HitTestPreview StretchHandle::HitPreview( StretchEnum stretchMode, bool unsafe )
{
@ -68,9 +64,11 @@ HitTestPreview StretchHandle::HitPreview( StretchEnum stretchMode, bool unsafe )
}
HitTestResult StretchHandle::HitTest
( const TrackPanelMouseState &st, const AudacityProject *pProject,
const std::shared_ptr<NoteTrack> &pTrack, StretchState &stretchState)
(std::weak_ptr<StretchHandle> &holder,
const TrackPanelMouseState &st, const AudacityProject *pProject,
const std::shared_ptr<NoteTrack> &pTrack)
{
StretchState stretchState;
const wxMouseState &state = st.state;
// later, we may want a different policy, but for now, stretch is
@ -140,9 +138,11 @@ HitTestResult StretchHandle::HitTest
stretchState.mBeatCenter.second - stretchState.mBeat0.second;
}
auto result = std::make_shared<StretchHandle>( pTrack, stretchState );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview( stretchState.mMode, unsafe ),
&Instance()
result
};
}
@ -167,14 +167,8 @@ UIHandle::Result StretchHandle::Click
mLeftEdge = evt.rect.GetLeft();
mpTrack = std::static_pointer_cast<NoteTrack>(evt.pCell);
ViewInfo &viewInfo = pProject->GetViewInfo();
// We must have hit if we got here, but repeat some
// calculations that set members
TrackPanelMouseState tpmState{ evt.event, evt.rect, evt.pCell };
HitTest( tpmState, pProject, mpTrack, mStretchState );
viewInfo.selectedRegion.setTimes
( mStretchState.mBeat0.first, mStretchState.mBeat1.first );

View File

@ -55,16 +55,20 @@ public:
};
private:
StretchHandle();
StretchHandle(const StretchHandle&);
StretchHandle &operator=(const StretchHandle&);
static StretchHandle& Instance();
static HitTestPreview HitPreview(StretchEnum stretchMode, bool unsafe);
public:
explicit StretchHandle
( const std::shared_ptr<NoteTrack> &pTrack,
const StretchState &stretchState );
StretchHandle &operator=(const StretchHandle&) = default;
static HitTestResult HitTest
( const TrackPanelMouseState &state, const AudacityProject *pProject,
const std::shared_ptr<NoteTrack> &pTrack, StretchState &stretchState );
(std::weak_ptr<StretchHandle> &holder,
const TrackPanelMouseState &state, const AudacityProject *pProject,
const std::shared_ptr<NoteTrack> &pTrack );
virtual ~StretchHandle();

View File

@ -18,21 +18,15 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../TrackPanel.h"
#include "../../../TrackPanelMouseEvent.h"
MuteButtonHandle::MuteButtonHandle()
: ButtonHandle{ TrackPanel::IsMuting }
{
}
MuteButtonHandle::MuteButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect )
: ButtonHandle{ pTrack, rect, TrackPanel::IsMuting }
{}
MuteButtonHandle::~MuteButtonHandle()
{
}
MuteButtonHandle &MuteButtonHandle::Instance()
{
static MuteButtonHandle instance;
return instance;
}
UIHandle::Result MuteButtonHandle::CommitChanges
(const wxMouseEvent &event, AudacityProject *pProject, wxWindow *)
{
@ -44,7 +38,8 @@ UIHandle::Result MuteButtonHandle::CommitChanges
}
HitTestResult MuteButtonHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<MuteButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack)
{
wxRect buttonRect;
@ -55,10 +50,11 @@ HitTestResult MuteButtonHandle::HitTest
return {};
if ( pTrack && buttonRect.Contains(state.m_x, state.m_y) ) {
Instance().mRect = buttonRect;
auto result = std::make_shared<MuteButtonHandle>(pTrack, buttonRect);
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(),
&Instance()
result
};
}
else
@ -67,21 +63,15 @@ HitTestResult MuteButtonHandle::HitTest
////////////////////////////////////////////////////////////////////////////////
SoloButtonHandle::SoloButtonHandle()
: ButtonHandle{ TrackPanel::IsSoloing }
{
}
SoloButtonHandle::SoloButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect )
: ButtonHandle{ pTrack, rect, TrackPanel::IsSoloing }
{}
SoloButtonHandle::~SoloButtonHandle()
{
}
SoloButtonHandle &SoloButtonHandle::Instance()
{
static SoloButtonHandle instance;
return instance;
}
UIHandle::Result SoloButtonHandle::CommitChanges
(const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent)
{
@ -93,7 +83,8 @@ UIHandle::Result SoloButtonHandle::CommitChanges
}
HitTestResult SoloButtonHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<SoloButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack)
{
wxRect buttonRect;
@ -105,10 +96,11 @@ HitTestResult SoloButtonHandle::HitTest
return {};
if ( pTrack && buttonRect.Contains(state.m_x, state.m_y) ) {
Instance().mRect = buttonRect;
auto result = std::make_shared<SoloButtonHandle>( pTrack, buttonRect );
result = AssignUIHandlePtr(holder, result);
return HitTestResult(
HitPreview(),
&Instance()
result
);
}
else

View File

@ -12,18 +12,23 @@ Paul Licameli split from TrackPanel.cpp
#define __AUDACITY_PLAYABLE_TRACK_BUTTON_HANDLES__
#include "../../ui/ButtonHandle.h"
#include "../../../TrackPanel.h"
struct HitTestResult;
class wxMouseState;
class MuteButtonHandle final : public ButtonHandle
{
MuteButtonHandle(const MuteButtonHandle&) = delete;
MuteButtonHandle &operator=(const MuteButtonHandle&) = delete;
MuteButtonHandle();
public:
explicit MuteButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect );
MuteButtonHandle &operator=(const MuteButtonHandle&) = default;
virtual ~MuteButtonHandle();
static MuteButtonHandle& Instance();
protected:
Result CommitChanges
@ -34,7 +39,8 @@ protected:
public:
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<MuteButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack);
};
@ -43,11 +49,14 @@ public:
class SoloButtonHandle final : public ButtonHandle
{
SoloButtonHandle(const SoloButtonHandle&) = delete;
SoloButtonHandle &operator=(const SoloButtonHandle&) = delete;
SoloButtonHandle();
public:
explicit SoloButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect );
SoloButtonHandle &operator=(const SoloButtonHandle&) = default;
virtual ~SoloButtonHandle();
static SoloButtonHandle& Instance();
protected:
Result CommitChanges
@ -58,7 +67,8 @@ protected:
public:
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<SoloButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack);
};

View File

@ -22,15 +22,11 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../../WaveTrackLocation.h"
#include "../../../../../images/Cursors.h"
CutlineHandle::CutlineHandle()
{
}
CutlineHandle &CutlineHandle::Instance()
{
static CutlineHandle instance;
return instance;
}
CutlineHandle::CutlineHandle
( const std::shared_ptr<WaveTrack> &pTrack, WaveTrackLocation location )
: mpTrack{ pTrack }
, mLocation{ location }
{}
HitTestPreview CutlineHandle::HitPreview(bool cutline, bool unsafe)
{
@ -47,10 +43,11 @@ HitTestPreview CutlineHandle::HitPreview(bool cutline, bool unsafe)
};
}
HitTestResult CutlineHandle::HitAnywhere(const AudacityProject *pProject, bool cutline)
HitTestResult CutlineHandle::HitAnywhere
(const AudacityProject *pProject, bool cutline, UIHandlePtr ptr)
{
const bool unsafe = pProject->IsAudioActive();
return { HitPreview(cutline, unsafe), &Instance() };
return { HitPreview(cutline, unsafe), ptr };
}
namespace
@ -71,7 +68,7 @@ namespace
bool IsOverCutline
(const ViewInfo &viewInfo, WaveTrack * track,
const wxRect &rect, const wxMouseState &state,
WaveTrackLocation *pCapturedTrackLocation)
WaveTrackLocation *pmLocation)
{
for (auto loc: track->GetCachedLocations())
{
@ -90,8 +87,8 @@ namespace
}
if (locRect.Contains(state.m_x, state.m_y))
{
if (pCapturedTrackLocation)
*pCapturedTrackLocation = loc;
if (pmLocation)
*pmLocation = loc;
return true;
}
}
@ -102,7 +99,8 @@ namespace
}
HitTestResult CutlineHandle::HitTest
(const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject,
(std::weak_ptr<CutlineHandle> &holder,
const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject,
const std::shared_ptr<WaveTrack> &pTrack)
{
const ViewInfo &viewInfo = pProject->GetViewInfo();
@ -116,7 +114,9 @@ HitTestResult CutlineHandle::HitTest
if (!IsOverCutline(viewInfo, wavetrack, rect, state, &location))
return {};
return HitAnywhere(pProject, location.typ == WaveTrackLocation::locationCutLine);
auto result = std::make_shared<CutlineHandle>( pTrack, location );
result = AssignUIHandlePtr( holder, result );
return HitAnywhere(pProject, location.typ == WaveTrackLocation::locationCutLine, result);
}
CutlineHandle::~CutlineHandle()
@ -133,7 +133,6 @@ UIHandle::Result CutlineHandle::Click
const wxMouseEvent &event = evt.event;
ViewInfo &viewInfo = pProject->GetViewInfo();
const auto pTrack = static_cast<Track*>(evt.pCell.get());
// Can affect the track by merging clips, expanding a cutline, or
// deleting a cutline.
@ -141,24 +140,17 @@ UIHandle::Result CutlineHandle::Click
/// Someone has just clicked the mouse. What do we do?
WaveTrackLocation capturedTrackLocation;
WaveTrack *wavetrack = static_cast<WaveTrack*>(pTrack);
if (!IsOverCutline(viewInfo, wavetrack, evt.rect, event, &capturedTrackLocation))
return Cancelled;
mbCutline = (capturedTrackLocation.typ == WaveTrackLocation::locationCutLine);
// FIXME: Disable this and return true when CutLines aren't showing?
// (Don't use gPrefs-> for the fix as registry access is slow).
// Cutline data changed on either branch, so refresh the track display.
UIHandle::Result result = RefreshCell;
// Assume linked track is wave or null
const auto linked = static_cast<WaveTrack*>(wavetrack->GetLink());
const auto linked = static_cast<WaveTrack*>(mpTrack->GetLink());
if (event.LeftDown())
{
if (capturedTrackLocation.typ == WaveTrackLocation::locationCutLine)
if (mLocation.typ == WaveTrackLocation::locationCutLine)
{
mOperation = Expand;
mStartTime = viewInfo.selectedRegion.t0();
@ -167,18 +159,18 @@ UIHandle::Result CutlineHandle::Click
// When user presses left button on cut line, expand the line again
double cutlineStart = 0, cutlineEnd = 0;
wavetrack->ExpandCutLine(capturedTrackLocation.pos, &cutlineStart, &cutlineEnd);
mpTrack->ExpandCutLine(mLocation.pos, &cutlineStart, &cutlineEnd);
if (linked)
// Expand the cutline in the opposite channel if it is present.
linked->ExpandCutLine(capturedTrackLocation.pos);
linked->ExpandCutLine(mLocation.pos);
viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
result |= UpdateSelection;
}
else if (capturedTrackLocation.typ == WaveTrackLocation::locationMergePoint) {
const double pos = capturedTrackLocation.pos;
wavetrack->MergeClips(capturedTrackLocation.clipidx1, capturedTrackLocation.clipidx2);
else if (mLocation.typ == WaveTrackLocation::locationMergePoint) {
const double pos = mLocation.pos;
mpTrack->MergeClips(mLocation.clipidx1, mLocation.clipidx2);
if (linked) {
// Don't assume correspondence of merge points across channels!
@ -194,10 +186,10 @@ UIHandle::Result CutlineHandle::Click
}
else if (event.RightDown())
{
bool removed = wavetrack->RemoveCutLine(capturedTrackLocation.pos);
bool removed = mpTrack->RemoveCutLine(mLocation.pos);
if (linked)
removed = linked->RemoveCutLine(capturedTrackLocation.pos) || removed;
removed = linked->RemoveCutLine(mLocation.pos) || removed;
if (!removed)
// Nothing happened, make no Undo item
@ -221,7 +213,8 @@ HitTestPreview CutlineHandle::Preview
(const TrackPanelMouseState &, const AudacityProject *pProject)
{
const bool unsafe = pProject->IsAudioActive();
return HitPreview( mbCutline, unsafe );
auto bCutline = (mLocation.typ == WaveTrackLocation::locationCutLine);
return HitPreview( bCutline, unsafe );
}
UIHandle::Result CutlineHandle::Release

View File

@ -11,30 +11,43 @@ Paul Licameli
#ifndef __AUDACITY_CUTLINE_HANDLE__
#define __AUDACITY_CUTLINE_HANDLE__
#include "../../../../MemoryX.h"
#include "../../../../UIHandle.h"
#include "../../../../MemoryX.h"
#include "../../../../WaveTrackLocation.h"
class wxMouseEvent;
class wxMouseState;
struct HitTestResult;
class WaveTrack;
using UIHandlePtr = std::shared_ptr<UIHandle>;
class CutlineHandle final : public UIHandle
{
CutlineHandle();
CutlineHandle(const CutlineHandle&) = delete;
CutlineHandle &operator=(const CutlineHandle&) = delete;
static CutlineHandle& Instance();
static HitTestPreview HitPreview(bool cutline, bool unsafe);
public:
static HitTestResult HitAnywhere(const AudacityProject *pProject, bool cutline);
explicit CutlineHandle
( const std::shared_ptr<WaveTrack> &pTrack,
WaveTrackLocation location );
CutlineHandle &operator=(const CutlineHandle&) = default;
static HitTestResult HitAnywhere
(const AudacityProject *pProject, bool cutline, UIHandlePtr ptr);
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<WaveTrack> &pTrack);
(std::weak_ptr<CutlineHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject,
const std::shared_ptr<WaveTrack> &pTrack);
virtual ~CutlineHandle();
const WaveTrackLocation &GetLocation() { return mLocation; }
std::shared_ptr<WaveTrack> GetTrack() { return mpTrack; }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
@ -57,7 +70,8 @@ private:
enum Operation { Merge, Expand, Remove };
Operation mOperation{ Merge };
double mStartTime{}, mEndTime{};
bool mbCutline{};
WaveTrackLocation mLocation {};
std::shared_ptr<WaveTrack> mpTrack{};
};
#endif

View File

@ -34,15 +34,9 @@ static const int SMOOTHING_BRUSH_RADIUS = 5;
static const double SMOOTHING_PROPORTION_MAX = 0.7;
static const double SMOOTHING_PROPORTION_MIN = 0.0;
SampleHandle::SampleHandle()
{
}
SampleHandle &SampleHandle::Instance()
{
static SampleHandle instance;
return instance;
}
SampleHandle::SampleHandle( const std::shared_ptr<WaveTrack> &pTrack )
: mClickedTrack{ pTrack }
{}
HitTestPreview SampleHandle::HitPreview
(const wxMouseState &state, const AudacityProject *pProject, bool unsafe)
@ -64,10 +58,14 @@ HitTestPreview SampleHandle::HitPreview
}
HitTestResult SampleHandle::HitAnywhere
(const wxMouseState &state, const AudacityProject *pProject)
(std::weak_ptr<SampleHandle> &holder,
const wxMouseState &state, const AudacityProject *pProject,
const std::shared_ptr<WaveTrack> &pTrack)
{
auto result = std::make_shared<SampleHandle>( pTrack );
result = AssignUIHandlePtr(holder, result);
const bool unsafe = pProject->IsAudioActive();
return { HitPreview(state, pProject, unsafe), &Instance() };
return { HitPreview(state, pProject, unsafe), result };
}
namespace {
@ -100,16 +98,12 @@ namespace {
}
HitTestResult SampleHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<SampleHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<WaveTrack> &pTrack)
{
const ViewInfo &viewInfo = pProject->GetViewInfo();
/// method that tells us if the mouse event landed on an
/// editable sample
if (pTrack->GetKind() != Track::Wave)
return {};
WaveTrack *wavetrack = pTrack.get();
const int displayType = wavetrack->GetDisplay();
@ -155,7 +149,7 @@ HitTestResult SampleHandle::HitTest
if (abs(yValue - yMouse) >= yTolerance)
return {};
return HitAnywhere(state, pProject);
return HitAnywhere(holder, state, pProject, pTrack);
}
SampleHandle::~SampleHandle()
@ -209,15 +203,14 @@ UIHandle::Result SampleHandle::Click
const wxMouseEvent &event = evt.event;
const wxRect &rect = evt.rect;
const ViewInfo &viewInfo = pProject->GetViewInfo();
const auto pTrack = std::static_pointer_cast<WaveTrack>(evt.pCell);
const auto pTrack = mClickedTrack.get();
/// Someone has just clicked the mouse. What do we do?
if (!IsSampleEditingPossible(
event, rect, viewInfo, pTrack.get(), rect.width))
event, rect, viewInfo, pTrack, rect.width))
return Cancelled;
/// We're in a track view and zoomed enough to see the samples.
mClickedTrack = pTrack;
mRect = rect;
//If we are still around, we are drawing in earnest. Set some member data structures up:

View File

@ -26,22 +26,28 @@ class WaveTrack;
class SampleHandle final : public UIHandle
{
SampleHandle();
SampleHandle(const SampleHandle&) = delete;
SampleHandle &operator=(const SampleHandle&) = delete;
static SampleHandle& Instance();
static HitTestPreview HitPreview
(const wxMouseState &state, const AudacityProject *pProject, bool unsafe);
public:
explicit SampleHandle( const std::shared_ptr<WaveTrack> &pTrack );
SampleHandle &operator=(const SampleHandle&) = default;
static HitTestResult HitAnywhere
(const wxMouseState &state, const AudacityProject *pProject);
(std::weak_ptr<SampleHandle> &holder,
const wxMouseState &state, const AudacityProject *pProject,
const std::shared_ptr<WaveTrack> &pTrack);
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<SampleHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<WaveTrack> &pTrack);
virtual ~SampleHandle();
std::shared_ptr<WaveTrack> GetTrack() const { return mClickedTrack; }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;

View File

@ -63,22 +63,20 @@ HitTestResult WaveTrackControls::HitTest
auto track = FindTrack();
if (track && track->GetKind() == Track::Wave) {
HitTestResult result;
if (NULL !=
(result = MuteButtonHandle::HitTest
(state, rect, pProject, track)).handle)
if (NULL != (result = MuteButtonHandle::HitTest(
mMuteHandle, state, rect, pProject, track)).handle)
return result;
if (NULL !=
(result = SoloButtonHandle::HitTest
(state, rect, pProject, track)).handle)
if (NULL != (result = SoloButtonHandle::HitTest(
mSoloHandle, state, rect, pProject, track)).handle)
return result;
if (NULL != (result =
GainSliderHandle::HitTest(state, rect, pProject, track)).handle)
if (NULL != (result = GainSliderHandle::HitTest(
mGainHandle, state, rect, pProject, track)).handle)
return result;
if (NULL != (result =
PanSliderHandle::HitTest(state, rect, pProject, track)).handle)
if (NULL != (result = PanSliderHandle::HitTest(
mPanHandle, state, rect, pProject, track)).handle)
return result;
}
}

View File

@ -13,6 +13,11 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ui/TrackControls.h"
class MuteButtonHandle;
class SoloButtonHandle;
class GainSliderHandle;
class PanSliderHandle;
class WaveTrackControls final : public TrackControls
{
WaveTrackControls(const WaveTrackControls&) = delete;
@ -29,6 +34,12 @@ public:
const AudacityProject *pProject) override;
PopupMenuTable *GetMenuExtension(Track *pTrack) override;
private:
std::weak_ptr<MuteButtonHandle> mMuteHandle;
std::weak_ptr<SoloButtonHandle> mSoloHandle;
std::weak_ptr<GainSliderHandle> mGainHandle;
std::weak_ptr<PanSliderHandle> mPanHandle;
};
#endif

View File

@ -19,21 +19,15 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../../UndoManager.h"
#include "../../../../WaveTrack.h"
GainSliderHandle::GainSliderHandle()
: SliderHandle()
{
}
GainSliderHandle::GainSliderHandle
( SliderFn sliderFn, const wxRect &rect, const std::shared_ptr<Track> &pTrack )
: SliderHandle{ sliderFn, rect, pTrack }
{}
GainSliderHandle::~GainSliderHandle()
{
}
GainSliderHandle &GainSliderHandle::Instance()
{
static GainSliderHandle instance;
return instance;
}
std::shared_ptr<WaveTrack> GainSliderHandle::GetWaveTrack()
{
return std::static_pointer_cast<WaveTrack>(mpTrack.lock());
@ -70,7 +64,8 @@ UIHandle::Result GainSliderHandle::CommitChanges
}
HitTestResult GainSliderHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<GainSliderHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *, const std::shared_ptr<Track> &pTrack)
{
if (!state.ButtonIsDown(wxMOUSE_BTN_LEFT))
@ -83,19 +78,19 @@ HitTestResult GainSliderHandle::HitTest
if (sliderRect.Contains(state.m_x, state.m_y)) {
wxRect sliderRect;
TrackInfo::GetGainRect(rect.GetTopLeft(), sliderRect);
Instance().mSliderFn =
auto sliderFn =
[]( AudacityProject *pProject, const wxRect &sliderRect, Track *pTrack ) {
return TrackInfo::GainSlider
(sliderRect, static_cast<WaveTrack*>( pTrack ), true,
const_cast<TrackPanel*>(pProject->GetTrackPanel()));
};
Instance().mRect = sliderRect;
Instance().mpTrack = pTrack;
auto result =
std::make_shared<GainSliderHandle>( sliderFn, sliderRect, pTrack );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(),
&Instance()
result
};
}
else
@ -104,21 +99,15 @@ HitTestResult GainSliderHandle::HitTest
////////////////////////////////////////////////////////////////////////////////
PanSliderHandle::PanSliderHandle()
: SliderHandle()
{
}
PanSliderHandle::PanSliderHandle
( SliderFn sliderFn, const wxRect &rect, const std::shared_ptr<Track> &pTrack )
: SliderHandle{ sliderFn, rect, pTrack }
{}
PanSliderHandle::~PanSliderHandle()
{
}
PanSliderHandle &PanSliderHandle::Instance()
{
static PanSliderHandle instance;
return instance;
}
std::shared_ptr<WaveTrack> PanSliderHandle::GetWaveTrack()
{
return std::static_pointer_cast<WaveTrack>(mpTrack.lock());
@ -167,7 +156,8 @@ UIHandle::Result PanSliderHandle::CommitChanges
}
HitTestResult PanSliderHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<PanSliderHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack)
{
if (!state.ButtonIsDown(wxMOUSE_BTN_LEFT))
@ -178,18 +168,19 @@ HitTestResult PanSliderHandle::HitTest
if ( TrackInfo::HideTopItem( rect, sliderRect, kTrackInfoSliderAllowance ) )
return {};
if (sliderRect.Contains(state.m_x, state.m_y)) {
Instance().mSliderFn =
auto sliderFn =
[]( AudacityProject *pProject, const wxRect &sliderRect, Track *pTrack ) {
return TrackInfo::PanSlider
(sliderRect, static_cast<WaveTrack*>( pTrack ), true,
const_cast<TrackPanel*>(pProject->GetTrackPanel()));
};
Instance().mRect = sliderRect;
Instance().mpTrack = pTrack;
auto result = std::make_shared<PanSliderHandle>(
sliderFn, sliderRect, pTrack );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(),
&Instance()
result
};
}
else

View File

@ -21,14 +21,18 @@ struct HitTestResult;
class GainSliderHandle final : public SliderHandle
{
GainSliderHandle(const GainSliderHandle&) = delete;
GainSliderHandle &operator=(const GainSliderHandle&) = delete;
GainSliderHandle();
virtual ~GainSliderHandle();
static GainSliderHandle& Instance();
std::shared_ptr<WaveTrack> GetWaveTrack();
public:
explicit GainSliderHandle
( SliderFn sliderFn, const wxRect &rect,
const std::shared_ptr<Track> &pTrack );
GainSliderHandle &operator=(const GainSliderHandle&) = default;
virtual ~GainSliderHandle();
protected:
float GetValue() override;
Result SetValue
@ -40,7 +44,8 @@ protected:
public:
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<GainSliderHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack);
};
@ -49,14 +54,18 @@ public:
class PanSliderHandle final : public SliderHandle
{
PanSliderHandle(const PanSliderHandle&) = delete;
PanSliderHandle &operator=(const PanSliderHandle&) = delete;
PanSliderHandle();
virtual ~PanSliderHandle();
static PanSliderHandle& Instance();
std::shared_ptr<WaveTrack> GetWaveTrack();
public:
explicit PanSliderHandle
( SliderFn sliderFn, const wxRect &rect,
const std::shared_ptr<Track> &pTrack );
PanSliderHandle &operator=(const PanSliderHandle&) = default;
virtual ~PanSliderHandle();
protected:
float GetValue() override;
Result SetValue(AudacityProject *pProject, float newValue) override;
@ -67,7 +76,8 @@ protected:
public:
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<PanSliderHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<Track> &pTrack);
};

View File

@ -39,44 +39,51 @@ HitTestResult WaveTrack::DetailedHitTest
// 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(pProject);
return TimeShiftHandle::HitAnywhere(
mTimeShiftHandle, pProject, Pointer(this), false);
// Some special targets are not drawn in spectrogram,
// so don't hit them in such views.
else if (isWaveform) {
HitTestResult result;
if (NULL !=
(result = CutlineHandle::HitTest
(st.state, st.rect, pProject, Pointer<WaveTrack>(this)))
.preview.cursor)
// This overriding test applies in all tools
return result;
if (NULL != (result = CutlineHandle::HitTest(
mCutlineHandle, st.state, st.rect,
pProject, Pointer<WaveTrack>(this))).preview.cursor)
// This overriding test applies in all tools
return result;
else 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
// point, seems arbitrary
if (NULL != (result = EnvelopeHandle::WaveTrackHitTest
(st.state, st.rect, pProject, Pointer<WaveTrack>(this)))
.preview.cursor)
if (NULL != (result = EnvelopeHandle::WaveTrackHitTest(
mEnvelopeHandle, st.state, st.rect,
pProject, Pointer<WaveTrack>(this)))
.preview.cursor)
;
else if (NULL != (result = TimeShiftHandle::HitTest
(st.state, st.rect, pProject)).preview.cursor)
else if (NULL != (result = TimeShiftHandle::HitTest(
mTimeShiftHandle, st.state, st.rect,
pProject, Pointer(this))).preview.cursor)
// This is the hit test on the "grips" drawn left and
// right in Multi only
;
else if (NULL != (result = SampleHandle::HitTest
(st.state, st.rect, pProject, Pointer<WaveTrack>(this))).preview.cursor)
else if (NULL != (result = SampleHandle::HitTest(
mSampleHandle, st.state, st.rect,
pProject, Pointer<WaveTrack>(this))).preview.cursor)
;
return result;
}
else switch ( currentTool ) {
// Unconditional hits appropriate to the tool
// If tools toolbar were eliminated, we would eliminate these
case envelopeTool:
return EnvelopeHandle::HitAnywhere(pProject);
case envelopeTool: {
auto envelope = GetEnvelopeAtX( st.state.m_x );
return EnvelopeHandle::HitAnywhere(
mEnvelopeHandle, pProject, envelope);
}
case drawTool:
return SampleHandle::HitAnywhere(st.state, pProject);
return SampleHandle::HitAnywhere(
mSampleHandle, st.state, pProject, Pointer<WaveTrack>(this));
default:
break;
}

View File

@ -33,7 +33,14 @@ HitTestResult WaveTrackVRulerControls::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *)
{
return WaveTrackVZoomHandle::HitTest(st.state);
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 WaveTrackVZoomHandle::HitTest(st.state, result);
}
return {};
}
unsigned WaveTrackVRulerControls::HandleWheelRotation

View File

@ -13,6 +13,8 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ui/TrackVRulerControls.h"
class WaveTrackVZoomHandle;
class WaveTrackVRulerControls final : public TrackVRulerControls
{
WaveTrackVRulerControls(const WaveTrackVRulerControls&) = delete;
@ -31,6 +33,9 @@ public:
unsigned HandleWheelRotation
(const TrackPanelMouseEvent &event,
AudacityProject *pProject) override;
private:
std::weak_ptr<WaveTrackVZoomHandle> mVZoomHandle;
};
#endif

View File

@ -43,6 +43,12 @@ bool IsDragZooming(int zoomStart, int zoomEnd)
}
WaveTrackVZoomHandle::WaveTrackVZoomHandle
(const std::shared_ptr<WaveTrack> &pTrack, const wxRect &rect, int y)
: mZoomStart(y), mZoomEnd(y), mRect(rect)
, mpTrack{ pTrack }
{}
void WaveTrackVZoomHandle::DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, bool shiftDown, bool rightUp,
@ -480,16 +486,6 @@ void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
///////////////////////////////////////////////////////////////////////////////
WaveTrackVZoomHandle::WaveTrackVZoomHandle()
{
}
WaveTrackVZoomHandle &WaveTrackVZoomHandle::Instance()
{
static WaveTrackVZoomHandle instance;
return instance;
}
HitTestPreview WaveTrackVZoomHandle::HitPreview(const wxMouseState &state)
{
static auto zoomInCursor =
@ -502,9 +498,10 @@ HitTestPreview WaveTrackVZoomHandle::HitPreview(const wxMouseState &state)
};
}
HitTestResult WaveTrackVZoomHandle::HitTest(const wxMouseState &state)
HitTestResult WaveTrackVZoomHandle::HitTest
(const wxMouseState &state, UIHandlePtr result)
{
return { HitPreview(state), &Instance() };
return { HitPreview(state), result };
}
WaveTrackVZoomHandle::~WaveTrackVZoomHandle()
@ -512,16 +509,8 @@ WaveTrackVZoomHandle::~WaveTrackVZoomHandle()
}
UIHandle::Result WaveTrackVZoomHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *)
(const TrackPanelMouseEvent &, AudacityProject *)
{
mpTrack = std::static_pointer_cast<WaveTrack>(
static_cast<WaveTrackVRulerControls*>(evt.pCell.get())->FindTrack() );
mRect = evt.rect;
const wxMouseEvent &event = evt.event;
mZoomStart = event.m_y;
mZoomEnd = event.m_y;
return RefreshCode::RefreshNone;
}

View File

@ -21,14 +21,16 @@ struct HitTestResult;
class WaveTrackVZoomHandle : public UIHandle
{
WaveTrackVZoomHandle();
WaveTrackVZoomHandle(const WaveTrackVZoomHandle&);
WaveTrackVZoomHandle &operator=(const WaveTrackVZoomHandle&);
static WaveTrackVZoomHandle& Instance();
static HitTestPreview HitPreview(const wxMouseState &state);
public:
static HitTestResult HitTest(const wxMouseState &state);
explicit WaveTrackVZoomHandle
(const std::shared_ptr<WaveTrack> &pTrack, const wxRect &rect, int y);
WaveTrackVZoomHandle &operator=(const WaveTrackVZoomHandle&) = default;
static HitTestResult HitTest(const wxMouseState &state, UIHandlePtr result);
static void DoZoom
(AudacityProject *pProject,
@ -38,6 +40,8 @@ public:
virtual ~WaveTrackVZoomHandle();
std::shared_ptr<WaveTrack> GetTrack() const { return mpTrack.lock(); }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;

View File

@ -23,7 +23,7 @@ HitTestResult TimeTrack::DetailedHitTest
const AudacityProject *pProject, int, bool)
{
return EnvelopeHandle::TimeTrackHitTest
( st.state, st.rect, pProject, Pointer<TimeTrack>(this) );
( mEnvelopeHandle, st.state, st.rect, pProject, Pointer<TimeTrack>(this) );
}
std::shared_ptr<TrackControls> TimeTrack::GetControls()

View File

@ -20,76 +20,68 @@ Paul Licameli split from TrackPanel.cpp
#include <wx/cursor.h>
#include <wx/event.h>
namespace
// Define this, just so the click to deselect can dispatch here
// This handle class, unlike most, doesn't associate with any particular cell.
class BackgroundHandle : public UIHandle
{
// Define this, just so the click to deselect can dispatch here
class BackgroundHandle : public UIHandle
BackgroundHandle(const BackgroundHandle&) = delete;
BackgroundHandle &operator=(const BackgroundHandle&) = delete;
public:
BackgroundHandle() {}
static HitTestPreview HitPreview()
{
BackgroundHandle() {}
BackgroundHandle(const BackgroundHandle&) = delete;
BackgroundHandle &operator=(const BackgroundHandle&) = delete;
static wxCursor arrowCursor{ wxCURSOR_ARROW };
return { {}, &arrowCursor };
}
public:
static HitTestResult HitAnywhere(UIHandlePtr result)
{
return {
HitPreview(),
result
};
}
static BackgroundHandle& Instance()
{
static BackgroundHandle instance;
return instance;
virtual ~BackgroundHandle()
{}
Result Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) override
{
using namespace RefreshCode;
const wxMouseEvent &event = evt.event;
// Do not start a drag
Result result = Cancelled;
// AS: If the user clicked outside all tracks, make nothing
// selected.
if ((event.ButtonDown() || event.ButtonDClick())) {
pProject->GetSelectionState().SelectNone
( *pProject->GetTracks(), pProject->GetMixerBoard() );
result |= RefreshAll;
}
static HitTestPreview HitPreview()
{
static wxCursor arrowCursor{ wxCURSOR_ARROW };
return { {}, &arrowCursor };
}
return result;
}
static HitTestResult HitAnywhere()
{
return {
HitPreview(),
&BackgroundHandle::Instance()
};
}
Result Drag
(const TrackPanelMouseEvent &, AudacityProject *) override
{ return RefreshCode::RefreshNone; }
virtual ~BackgroundHandle()
{}
HitTestPreview Preview
(const TrackPanelMouseState &, const AudacityProject *) override
{ return HitPreview(); }
Result Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject) override
{
using namespace RefreshCode;
const wxMouseEvent &event = evt.event;
// Do not start a drag
Result result = Cancelled;
Result Release
(const TrackPanelMouseEvent &, AudacityProject *,
wxWindow *) override
{ return RefreshCode::RefreshNone; }
// AS: If the user clicked outside all tracks, make nothing
// selected.
if ((event.ButtonDown() || event.ButtonDClick())) {
pProject->GetSelectionState().SelectNone
( *pProject->GetTracks(), pProject->GetMixerBoard() );
result |= RefreshAll;
}
return result;
}
Result Drag
(const TrackPanelMouseEvent &, AudacityProject *) override
{ return RefreshCode::RefreshNone; }
HitTestPreview Preview
(const TrackPanelMouseState &, const AudacityProject *) override
{ return HitPreview(); }
Result Release
(const TrackPanelMouseEvent &, AudacityProject *,
wxWindow *) override
{ return RefreshCode::RefreshNone; }
Result Cancel(AudacityProject *) override
{ return RefreshCode::RefreshNone; }
};
}
Result Cancel(AudacityProject *) override
{ return RefreshCode::RefreshNone; }
};
BackgroundCell::~BackgroundCell()
{
@ -99,7 +91,10 @@ HitTestResult BackgroundCell::HitTest
(const TrackPanelMouseState &,
const AudacityProject *)
{
return BackgroundHandle::HitAnywhere();
auto result = mHandle.lock();
if (!result)
result = std::make_shared<BackgroundHandle>();
return BackgroundHandle::HitAnywhere(result);
}
std::shared_ptr<Track> BackgroundCell::FindTrack()

View File

@ -12,9 +12,13 @@ Paul Licameli split from TrackPanel.cpp
#define __AUDACITY_BACKGROUND_CELL__
#include "CommonTrackPanelCell.h"
#include "../../MemoryX.h"
class AudacityProject;
class BackgroundHandle;
class ZoomHandle;
class BackgroundCell final : public CommonTrackPanelCell
{
public:
@ -33,6 +37,12 @@ protected:
private:
AudacityProject *mpProject;
std::weak_ptr<BackgroundHandle> mHandle;
public:
// For want of a better place...
std::weak_ptr<ZoomHandle> mZoomHandle;
};
#endif

View File

@ -20,10 +20,12 @@ Paul Licameli
#include "../../TrackPanelMouseEvent.h"
#include "../ui/TrackControls.h"
ButtonHandle::ButtonHandle(int dragCode)
: mDragCode(dragCode)
{
}
ButtonHandle::ButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect, int dragCode )
: mpTrack{ pTrack }
, mRect{ rect }
, mDragCode{ dragCode }
{}
ButtonHandle::~ButtonHandle()
{
@ -36,10 +38,10 @@ HitTestPreview ButtonHandle::HitPreview()
}
UIHandle::Result ButtonHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *)
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
auto pTrack = static_cast<TrackControls*>(evt.pCell.get())->FindTrack();
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
if ( !pTrack )
return Cancelled;
@ -49,7 +51,6 @@ UIHandle::Result ButtonHandle::Click
// Come here for left click or double click
if (mRect.Contains(event.m_x, event.m_y)) {
mpTrack = pTrack;
TrackControls::gCaptureState = mDragCode;
// Toggle visible button state
return RefreshCell;

View File

@ -22,10 +22,13 @@ class Track;
class ButtonHandle /* not final */ : public UIHandle
{
ButtonHandle(const ButtonHandle&) = delete;
ButtonHandle &operator=(const ButtonHandle&) = delete;
protected:
explicit ButtonHandle(int dragCode);
explicit ButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect, int dragCode );
ButtonHandle &operator=(const ButtonHandle&) = default;
virtual ~ButtonHandle();
// This new abstract virtual simplifies the duties of further subclasses.
@ -54,9 +57,9 @@ protected:
Result Cancel(AudacityProject *pProject) override;
wxRect mRect {};
std::weak_ptr<Track> mpTrack;
const int mDragCode;
wxRect mRect;
int mDragCode;
};
#endif

View File

@ -26,15 +26,12 @@ Paul Licameli split from TrackPanel.cpp
#include "../../WaveTrack.h"
#include "../../../images/Cursors.h"
EnvelopeHandle::EnvelopeHandle()
{
}
EnvelopeHandle::EnvelopeHandle( Envelope *pEnvelope )
: mEnvelope{ pEnvelope }
{}
EnvelopeHandle &EnvelopeHandle::Instance()
{
static EnvelopeHandle instance;
return instance;
}
EnvelopeHandle::~EnvelopeHandle()
{}
HitTestPreview EnvelopeHandle::HitPreview(const AudacityProject *pProject, bool unsafe)
{
@ -51,10 +48,13 @@ HitTestPreview EnvelopeHandle::HitPreview(const AudacityProject *pProject, bool
};
}
HitTestResult EnvelopeHandle::HitAnywhere(const AudacityProject *pProject)
HitTestResult EnvelopeHandle::HitAnywhere
(std::weak_ptr<EnvelopeHandle> &holder,
const AudacityProject *pProject, Envelope *envelope)
{
const bool unsafe = pProject->IsAudioActive();
return { HitPreview(pProject, unsafe), &Instance() };
UIHandlePtr result = std::make_shared<EnvelopeHandle>( envelope );
return { HitPreview(pProject, unsafe), result };
}
namespace {
@ -75,7 +75,8 @@ namespace {
}
HitTestResult EnvelopeHandle::TimeTrackHitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<EnvelopeHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<TimeTrack> &tt)
{
auto envelope = tt->GetEnvelope();
@ -86,16 +87,17 @@ HitTestResult EnvelopeHandle::TimeTrackHitTest
float zoomMin, zoomMax;
GetTimeTrackData( *pProject, *tt, dBRange, dB, zoomMin, zoomMax);
return EnvelopeHandle::HitEnvelope
(state, rect, pProject, envelope, zoomMin, zoomMax, dB, dBRange);
(holder, state, rect, pProject, envelope, zoomMin, zoomMax, dB, dBRange);
}
HitTestResult EnvelopeHandle::WaveTrackHitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<EnvelopeHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<WaveTrack> &wt)
{
/// method that tells us if the mouse event landed on an
/// envelope boundary.
const Envelope *const envelope = wt->GetEnvelopeAtX(state.GetX());
Envelope *const envelope = wt->GetEnvelopeAtX(state.GetX());
if (!envelope)
return {};
@ -115,12 +117,13 @@ HitTestResult EnvelopeHandle::WaveTrackHitTest
const float dBRange = wt->GetWaveformSettings().dBRange;
return EnvelopeHandle::HitEnvelope
(state, rect, pProject, envelope, zoomMin, zoomMax, dB, dBRange);
(holder, state, rect, pProject, envelope, zoomMin, zoomMax, dB, dBRange);
}
HitTestResult EnvelopeHandle::HitEnvelope
(const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject,
const Envelope *envelope, float zoomMin, float zoomMax,
(std::weak_ptr<EnvelopeHandle> &holder,
const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject,
Envelope *envelope, float zoomMin, float zoomMax,
bool dB, float dBRange)
{
const ViewInfo &viewInfo = pProject->GetViewInfo();
@ -167,11 +170,7 @@ HitTestResult EnvelopeHandle::HitEnvelope
if (distance >= yTolerance)
return {};
return HitAnywhere(pProject);
}
EnvelopeHandle::~EnvelopeHandle()
{
return HitAnywhere(holder, pProject, envelope);
}
UIHandle::Result EnvelopeHandle::Click
@ -191,23 +190,21 @@ UIHandle::Result EnvelopeHandle::Click
if (wt->GetDisplay() != WaveTrack::Waveform)
return Cancelled;
auto clickedEnvelope =
wt->GetEnvelopeAtX(event.GetX());
if (!clickedEnvelope)
if (!mEnvelope)
return Cancelled;
mLog = !wt->GetWaveformSettings().isLinear();
wt->GetDisplayBounds(&mLower, &mUpper);
mdBRange = wt->GetWaveformSettings().dBRange;
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *clickedEnvelope, true );
std::make_unique< EnvelopeEditor >( *mEnvelope, true );
mEnvelopeEditorRight.reset();
// Assume linked track is wave or null
auto partner = static_cast<WaveTrack*>(wt->GetLink());
if (partner)
{
clickedEnvelope = partner->GetEnvelopeAtX(event.GetX());
auto clickedEnvelope = partner->GetEnvelopeAtX(event.GetX());
if (clickedEnvelope)
mEnvelopeEditorRight =
std::make_unique< EnvelopeEditor >( *clickedEnvelope, true );
@ -216,12 +213,11 @@ UIHandle::Result EnvelopeHandle::Click
else if (pTrack->GetKind() == Track::Time)
{
TimeTrack *const tt = static_cast<TimeTrack*>(pTrack);
auto clickedEnvelope = tt->GetEnvelope();
if (!clickedEnvelope)
if (!mEnvelope)
return Cancelled;
GetTimeTrackData( *pProject, *tt, mdBRange, mLog, mLower, mUpper);
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *clickedEnvelope, false );
std::make_unique< EnvelopeEditor >( *mEnvelope, false );
mEnvelopeEditorRight.reset();
}
else

View File

@ -27,29 +27,36 @@ class WaveTrack;
class EnvelopeHandle final : public UIHandle
{
EnvelopeHandle();
EnvelopeHandle(const EnvelopeHandle&) = delete;
EnvelopeHandle &operator=(const EnvelopeHandle&) = delete;
static EnvelopeHandle& Instance();
static HitTestPreview HitPreview(const AudacityProject *pProject, bool unsafe);
static HitTestResult HitEnvelope
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<EnvelopeHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject,
const Envelope *envelope, float zoomMin, float zoomMax,
Envelope *envelope, float zoomMin, float zoomMax,
bool dB, float dBRange);
public:
static HitTestResult HitAnywhere(const AudacityProject *pProject);
static HitTestResult TimeTrackHitTest
(const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<TimeTrack> &tt);
static HitTestResult WaveTrackHitTest
(const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<WaveTrack> &wt);
explicit EnvelopeHandle( Envelope *pEnvelope );
virtual ~EnvelopeHandle();
static HitTestResult HitAnywhere
(std::weak_ptr<EnvelopeHandle> &holder,
const AudacityProject *pProject, Envelope *envelope);
static HitTestResult TimeTrackHitTest
(std::weak_ptr<EnvelopeHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<TimeTrack> &tt);
static HitTestResult WaveTrackHitTest
(std::weak_ptr<EnvelopeHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject, const std::shared_ptr<WaveTrack> &wt);
Envelope *GetEnvelope() const { return mEnvelope; }
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
@ -77,6 +84,7 @@ private:
float mLower{}, mUpper{};
double mdBRange{};
Envelope *mEnvelope{};
std::unique_ptr<EnvelopeEditor> mEnvelopeEditor;
std::unique_ptr<EnvelopeEditor> mEnvelopeEditorRight;
};

View File

@ -8,6 +8,7 @@ Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#include "../../Audacity.h"
#include "SelectHandle.h"
#include "Scrubbing.h"
@ -54,16 +55,6 @@ bool SelectHandle::IsClicked() const
return mSelectionStateChanger.get();
}
SelectHandle::SelectHandle()
{
}
SelectHandle &SelectHandle::Instance()
{
static SelectHandle instance;
return instance;
}
namespace
{
// If we're in OnDemand mode, we may change the tip.
@ -428,9 +419,31 @@ namespace
}
HitTestResult SelectHandle::HitTest
(const TrackPanelMouseState &st, const AudacityProject *pProject,
(std::weak_ptr<SelectHandle> &holder,
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.
auto old = holder.lock();
std::unique_ptr<SnapManager> oldSnapManager;
wxInt64 oldSnapLeft = -1, oldSnapRight = -1;
if (old) {
// It should not have started listening to timer events
wxASSERT( !old->mConnectedProject );
oldSnapManager = std::move(old->mSnapManager);
oldSnapLeft = old->mSnapLeft;
oldSnapRight = old->mSnapRight;
}
auto result = std::make_shared<SelectHandle>( pTrack );
// Copy the pre-dragging state
result->mSnapManager = std::move( oldSnapManager );
result->mSnapLeft = oldSnapLeft;
result->mSnapRight = oldSnapRight;
const wxMouseState &state = st.state;
const wxRect &rect = st.rect;
@ -465,7 +478,7 @@ HitTestResult SelectHandle::HitTest
if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges)
{
MaySetOnDemandTip(pTrack.get(), tip);
return { { tip, pCursor }, &Instance() };
return { { tip, pCursor }, result };
}
{
@ -510,9 +523,13 @@ HitTestResult SelectHandle::HitTest
tip = ttb->GetMessageForTool(selectTool);
}
return HitTestResult{ { tip, pCursor }, &Instance() };
return HitTestResult{ { tip, pCursor }, result };
}
SelectHandle::SelectHandle( const std::shared_ptr<Track> &pTrack )
: mpTrack{ pTrack }
{}
SelectHandle::~SelectHandle()
{
}
@ -545,7 +562,8 @@ UIHandle::Result SelectHandle::Click
using namespace RefreshCode;
wxMouseEvent &event = evt.event;
const auto pTrack = static_cast<Track*>(evt.pCell.get());
const auto sTrack = pProject->GetTracks()->Lock(mpTrack);
const auto pTrack = sTrack.get();
ViewInfo &viewInfo = pProject->GetViewInfo();
mMostRecentX = event.m_x;
@ -598,7 +616,6 @@ UIHandle::Result SelectHandle::Click
else if (!event.LeftDown())
return Cancelled;
mpTrack = Track::Pointer( pTrack );
mRect = evt.rect;
mInitialSelection = viewInfo.selectedRegion;
@ -608,11 +625,12 @@ UIHandle::Result SelectHandle::Click
mSelectionBoundary = 0;
// We create a NEW snap manager in case any snap-points have changed
mSnapManager = std::make_unique<SnapManager>(trackList, &viewInfo);
mSnapLeft = -1;
mSnapRight = -1;
if (!mSnapManager) {
// We create a NEW snap manager in case any snap-points have changed
mSnapManager = std::make_unique<SnapManager>(trackList, &viewInfo);
mSnapLeft = -1;
mSnapRight = -1;
}
bool bShiftDown = event.ShiftDown();
bool bCtrlDown = event.ControlDown();

View File

@ -30,17 +30,17 @@ class WaveTrack;
class SelectHandle : public wxEvtHandler, public UIHandle
{
SelectHandle();
SelectHandle(const SelectHandle&);
SelectHandle &operator=(const SelectHandle&);
public:
static SelectHandle& Instance();
explicit SelectHandle( const std::shared_ptr<Track> &pTrack );
// This always hits, but details of the hit vary with mouse position and
// key state.
static HitTestResult HitTest
(const TrackPanelMouseState &state, const AudacityProject *pProject,
(std::weak_ptr<SelectHandle> &holder,
const TrackPanelMouseState &state, const AudacityProject *pProject,
const std::shared_ptr<Track> &pTrack);
virtual ~SelectHandle();

View File

@ -16,9 +16,12 @@ Paul Licameli
#include "../../RefreshCode.h"
#include "../../TrackPanelMouseEvent.h"
SliderHandle::SliderHandle()
{
}
SliderHandle::SliderHandle
( SliderFn sliderFn, const wxRect &rect, const std::shared_ptr<Track> &pTrack )
: mSliderFn{ sliderFn }
, mRect{ rect }
, mpTrack{ pTrack }
{}
SliderHandle::~SliderHandle()
{

View File

@ -22,10 +22,17 @@ class Track;
class SliderHandle /* not final */ : public UIHandle
{
SliderHandle(const SliderHandle&) = delete;
SliderHandle &operator=(const SliderHandle&) = delete;
public:
using SliderFn = LWSlider *(*)( AudacityProject*, const wxRect&, Track* );
explicit SliderHandle
( SliderFn sliderFn, const wxRect &rect,
const std::shared_ptr<Track> &pTrack );
SliderHandle &operator=(const SliderHandle&) = default;
protected:
SliderHandle();
virtual ~SliderHandle();
// These new abstract virtuals simplify the duties of further subclasses.
@ -59,7 +66,6 @@ protected:
// Derived class is expected to set these two before Click():
std::weak_ptr<Track> mpTrack;
wxRect mRect{};
using SliderFn = LWSlider *(*)( AudacityProject*, const wxRect&, Track* );
SliderFn mSliderFn;
LWSlider *GetSlider( AudacityProject *pProject );

View File

@ -23,15 +23,11 @@ Paul Licameli split from TrackPanel.cpp
#include "../../WaveTrack.h"
#include "../../../images/Cursors.h"
TimeShiftHandle::TimeShiftHandle()
{
}
TimeShiftHandle &TimeShiftHandle::Instance()
{
static TimeShiftHandle instance;
return instance;
}
TimeShiftHandle::TimeShiftHandle
( const std::shared_ptr<Track> &pTrack, bool gripHit )
: mCapturedTrack{ pTrack }
, mGripHit{ gripHit }
{}
HitTestPreview TimeShiftHandle::HitPreview
(const AudacityProject *pProject, bool unsafe)
@ -49,16 +45,24 @@ HitTestPreview TimeShiftHandle::HitPreview
};
}
HitTestResult TimeShiftHandle::HitAnywhere(const AudacityProject *pProject)
HitTestResult TimeShiftHandle::HitAnywhere
(std::weak_ptr<TimeShiftHandle> &holder,
const AudacityProject *pProject,
const std::shared_ptr<Track> &pTrack, bool gripHit)
{
// After all that, it still may be unsafe to drag.
// Even if so, make an informative cursor change from default to "banned."
const bool unsafe = pProject->IsAudioActive();
return { HitPreview(pProject, unsafe), &Instance() };
auto result = std::make_shared<TimeShiftHandle>( pTrack, gripHit );
result = AssignUIHandlePtr(holder, result);
return { HitPreview(pProject, unsafe), result };
}
HitTestResult TimeShiftHandle::HitTest
(const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject)
(std::weak_ptr<TimeShiftHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject,
const std::shared_ptr<Track> &pTrack)
{
/// method that tells us if the mouse event landed on a
/// time-slider that allows us to time shift the sequence.
@ -77,7 +81,7 @@ HitTestResult TimeShiftHandle::HitTest
state.m_x + hotspotOffset >= rect.x + rect.width - adjustedDragHandleWidth))
return {};
return HitAnywhere(pProject);
return HitAnywhere( holder, pProject, pTrack, true );
}
TimeShiftHandle::~TimeShiftHandle()
@ -465,7 +469,6 @@ UIHandle::Result TimeShiftHandle::Click
}
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
mCapturedTrack = pTrack;
mRect = rect;
mMouseClickX = event.m_x;
const double selStart = viewInfo.PositionToTime(event.m_x, mRect.x);
@ -506,6 +509,7 @@ UIHandle::Result TimeShiftHandle::Drag
track = mCapturedTrack.get();
}
// May need a shared_ptr to reassign mCapturedTrack below
auto pTrack = Track::Pointer( track );
if (!pTrack)
return RefreshCode::RefreshNone;

View File

@ -21,6 +21,8 @@ Paul Licameli
struct HitTestResult;
class WaveClip;
using UIHandlePtr = std::shared_ptr<UIHandle>;
struct ClipMoveState {
// non-NULL only if click was in a WaveTrack and without Shift key:
WaveClip *capturedClip {};
@ -44,14 +46,19 @@ struct ClipMoveState {
class TimeShiftHandle final : public UIHandle
{
TimeShiftHandle();
TimeShiftHandle(const TimeShiftHandle&) = delete;
TimeShiftHandle &operator=(const TimeShiftHandle&) = delete;
static TimeShiftHandle& Instance();
static HitTestPreview HitPreview
(const AudacityProject *pProject, bool unsafe);
public:
explicit TimeShiftHandle
( const std::shared_ptr<Track> &pTrack, bool gripHit );
TimeShiftHandle &operator=(TimeShiftHandle&&) = default;
bool IsGripHit() const { return mGripHit; }
std::shared_ptr<Track> GetTrack() const { return mCapturedTrack; }
// A utility function also used by menu commands
static void CreateListOfCapturedClips
( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack,
@ -61,9 +68,15 @@ public:
static void DoSlideHorizontal
( ClipMoveState &state, TrackList &trackList, Track &capturedTrack );
static HitTestResult HitAnywhere(const AudacityProject *pProject);
static HitTestResult HitAnywhere
(std::weak_ptr<TimeShiftHandle> &holder,
const AudacityProject *pProject,
const std::shared_ptr<Track> &pTrack, bool gripHit);
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject);
(std::weak_ptr<TimeShiftHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const AudacityProject *pProject,
const std::shared_ptr<Track> &pTrack);
virtual ~TimeShiftHandle();
@ -107,6 +120,7 @@ private:
std::unique_ptr<SnapManager> mSnapManager{};
ClipMoveState mClipMoveState{};
bool mGripHit {};
};
#endif

View File

@ -17,21 +17,15 @@ Paul Licameli split from TrackPanel.cpp
#include "../../Track.h"
#include "../../TrackPanel.h"
MinimizeButtonHandle::MinimizeButtonHandle()
: ButtonHandle{ TrackPanel::IsMinimizing }
{
}
MinimizeButtonHandle::MinimizeButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect )
: ButtonHandle{ pTrack, rect, TrackPanel::IsMinimizing }
{}
MinimizeButtonHandle::~MinimizeButtonHandle()
{
}
MinimizeButtonHandle &MinimizeButtonHandle::Instance()
{
static MinimizeButtonHandle instance;
return instance;
}
UIHandle::Result MinimizeButtonHandle::CommitChanges
(const wxMouseEvent &, AudacityProject *pProject, wxWindow*)
{
@ -55,16 +49,19 @@ UIHandle::Result MinimizeButtonHandle::CommitChanges
}
HitTestResult MinimizeButtonHandle::HitTest
(const wxMouseState &state, const wxRect &rect)
(std::weak_ptr<MinimizeButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell)
{
wxRect buttonRect;
TrackInfo::GetMinimizeRect(rect, buttonRect);
if (buttonRect.Contains(state.m_x, state.m_y)) {
Instance().mRect = buttonRect;
auto pTrack = static_cast<CommonTrackPanelCell*>(pCell)->FindTrack();
auto result = std::make_shared<MinimizeButtonHandle>( pTrack, buttonRect );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(),
&Instance()
result
};
}
else
@ -73,21 +70,15 @@ HitTestResult MinimizeButtonHandle::HitTest
////////////////////////////////////////////////////////////////////////////////
CloseButtonHandle::CloseButtonHandle()
: ButtonHandle{ TrackPanel::IsClosing }
{
}
CloseButtonHandle::CloseButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect )
: ButtonHandle{ pTrack, rect, TrackPanel::IsClosing }
{}
CloseButtonHandle::~CloseButtonHandle()
{
}
CloseButtonHandle &CloseButtonHandle::Instance()
{
static CloseButtonHandle instance;
return instance;
}
UIHandle::Result CloseButtonHandle::CommitChanges
(const wxMouseEvent &, AudacityProject *pProject, wxWindow*)
{
@ -112,16 +103,19 @@ UIHandle::Result CloseButtonHandle::CommitChanges
}
HitTestResult CloseButtonHandle::HitTest
(const wxMouseState &state, const wxRect &rect)
(std::weak_ptr<CloseButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell)
{
wxRect buttonRect;
TrackInfo::GetCloseBoxRect(rect, buttonRect);
if (buttonRect.Contains(state.m_x, state.m_y)) {
Instance().mRect = buttonRect;
auto pTrack = static_cast<CommonTrackPanelCell*>(pCell)->FindTrack();
auto result = std::make_shared<CloseButtonHandle>( pTrack, buttonRect );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(),
&Instance()
result
};
}
else
@ -130,21 +124,17 @@ HitTestResult CloseButtonHandle::HitTest
////////////////////////////////////////////////////////////////////////////////
MenuButtonHandle::MenuButtonHandle()
: ButtonHandle{ TrackPanel::IsPopping }
{
}
MenuButtonHandle::MenuButtonHandle
( const std::shared_ptr<TrackPanelCell> &pCell,
const std::shared_ptr<Track> &pTrack, const wxRect &rect )
: ButtonHandle{ pTrack, rect, TrackPanel::IsPopping }
, mpCell{ pCell }
{}
MenuButtonHandle::~MenuButtonHandle()
{
}
MenuButtonHandle &MenuButtonHandle::Instance()
{
static MenuButtonHandle instance;
return instance;
}
UIHandle::Result MenuButtonHandle::CommitChanges
(const wxMouseEvent &, AudacityProject *, wxWindow *pParent)
{
@ -155,18 +145,20 @@ UIHandle::Result MenuButtonHandle::CommitChanges
}
HitTestResult MenuButtonHandle::HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<MenuButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const std::shared_ptr<TrackPanelCell> &pCell)
{
wxRect buttonRect;
TrackInfo::GetTitleBarRect(rect, buttonRect);
if (buttonRect.Contains(state.m_x, state.m_y)) {
Instance().mpCell = pCell;
Instance().mRect = buttonRect;
auto pTrack = static_cast<CommonTrackPanelCell*>(pCell.get())->FindTrack();
auto result = std::make_shared<MenuButtonHandle>( pCell, pTrack, buttonRect );
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(),
&Instance()
result
};
}
else

View File

@ -12,6 +12,7 @@ Paul Licameli split from TrackPanel.cpp
#define __AUDACITY_TRACK_BUTTON_HANDLES__
#include "../ui/ButtonHandle.h"
#include "../../TrackPanel.h"
class wxMouseState;
struct HitTestResult;
@ -19,11 +20,6 @@ struct HitTestResult;
class MinimizeButtonHandle final : public ButtonHandle
{
MinimizeButtonHandle(const MinimizeButtonHandle&) = delete;
MinimizeButtonHandle &operator=(const MinimizeButtonHandle&) = delete;
MinimizeButtonHandle();
virtual ~MinimizeButtonHandle();
static MinimizeButtonHandle& Instance();
protected:
Result CommitChanges
@ -31,7 +27,16 @@ protected:
override;
public:
static HitTestResult HitTest(const wxMouseState &state, const wxRect &rect);
explicit MinimizeButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect );
MinimizeButtonHandle &operator=(const MinimizeButtonHandle&) = default;
virtual ~MinimizeButtonHandle();
static HitTestResult HitTest
(std::weak_ptr<MinimizeButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell);
};
////////////////////////////////////////////////////////////////////////////////
@ -39,11 +44,6 @@ public:
class CloseButtonHandle final : public ButtonHandle
{
CloseButtonHandle(const CloseButtonHandle&) = delete;
CloseButtonHandle &operator=(const CloseButtonHandle&) = delete;
CloseButtonHandle();
virtual ~CloseButtonHandle();
static CloseButtonHandle& Instance();
protected:
Result CommitChanges
@ -53,7 +53,16 @@ protected:
bool StopsOnKeystroke () override { return true; }
public:
static HitTestResult HitTest(const wxMouseState &state, const wxRect &rect);
explicit CloseButtonHandle
( const std::shared_ptr<Track> &pTrack, const wxRect &rect );
CloseButtonHandle &operator=(const CloseButtonHandle&) = default;
virtual ~CloseButtonHandle();
static HitTestResult HitTest
(std::weak_ptr<CloseButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell);
};
////////////////////////////////////////////////////////////////////////////////
@ -64,11 +73,6 @@ public:
class MenuButtonHandle final : public ButtonHandle
{
MenuButtonHandle(const MenuButtonHandle&) = delete;
MenuButtonHandle &operator=(const MenuButtonHandle&) = delete;
MenuButtonHandle();
virtual ~MenuButtonHandle();
static MenuButtonHandle& Instance();
protected:
Result CommitChanges
@ -76,8 +80,17 @@ protected:
override;
public:
explicit MenuButtonHandle
( const std::shared_ptr<TrackPanelCell> &pCell,
const std::shared_ptr<Track> &pTrack, const wxRect &rect );
MenuButtonHandle &operator=(const MenuButtonHandle&) = default;
virtual ~MenuButtonHandle();
static HitTestResult HitTest
(const wxMouseState &state, const wxRect &rect,
(std::weak_ptr<MenuButtonHandle> &holder,
const wxMouseState &state, const wxRect &rect,
const std::shared_ptr<TrackPanelCell> &pCell);
private:

View File

@ -45,18 +45,24 @@ HitTestResult TrackControls::HitTest
const wxRect &rect = st.rect;
HitTestResult result;
if (NULL != (result = CloseButtonHandle::HitTest(state, rect)).handle)
auto pTrack = FindTrack();
// shared pointer to this:
auto sThis = pTrack->GetTrackControl();
if (NULL != (result = CloseButtonHandle::HitTest(
mCloseHandle, state, rect, this)).handle)
return result;
if (NULL != (result = MenuButtonHandle::HitTest(state, rect,
this->FindTrack()->GetTrackControl())).handle)
if (NULL != (result = MenuButtonHandle::HitTest(
mMenuHandle, state, rect, sThis)).handle)
return result;
if (NULL != (result = MinimizeButtonHandle::HitTest(state, rect)).handle)
if (NULL != (result = MinimizeButtonHandle::HitTest(
mMinimizeHandle, state, rect, this)).handle)
return result;
return TrackSelectHandle::HitAnywhere
(project->GetTrackPanel()->GetTrackCount());
return TrackSelectHandle::HitAnywhere(
mSelectHandle, pTrack, project->GetTrackPanel()->GetTrackCount());
}
enum

View File

@ -17,6 +17,11 @@ Paul Licameli split from TrackPanel.cpp
class PopupMenuTable;
class Track;
class CloseButtonHandle;
class MenuButtonHandle;
class MinimizeButtonHandle;
class TrackSelectHandle;
class TrackControls /* not final */ : public CommonTrackPanelCell
{
public:
@ -54,6 +59,11 @@ protected:
Track *GetTrack() const;
std::weak_ptr<Track> mwTrack;
std::weak_ptr<CloseButtonHandle> mCloseHandle;
std::weak_ptr<MenuButtonHandle> mMenuHandle;
std::weak_ptr<MinimizeButtonHandle> mMinimizeHandle;
std::weak_ptr<TrackSelectHandle> mSelectHandle;
};
#endif

View File

@ -26,16 +26,6 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../images/Cursors.h"
TrackSelectHandle::TrackSelectHandle()
{
}
TrackSelectHandle &TrackSelectHandle::Instance()
{
static TrackSelectHandle instance;
return instance;
}
#if defined(__WXMAC__)
/* i18n-hint: Command names a modifier key on Macintosh keyboards */
#define CTRL_CLICK _("Command-Click")
@ -59,6 +49,10 @@ namespace {
}
}
TrackSelectHandle::TrackSelectHandle( const std::shared_ptr<Track> &pTrack )
: mpTrack( pTrack )
{}
HitTestPreview TrackSelectHandle::HitPreview(unsigned trackCount)
{
static wxCursor arrowCursor{ wxCURSOR_ARROW };
@ -68,11 +62,15 @@ HitTestPreview TrackSelectHandle::HitPreview(unsigned trackCount)
};
}
HitTestResult TrackSelectHandle::HitAnywhere(unsigned trackCount)
HitTestResult TrackSelectHandle::HitAnywhere
(std::weak_ptr<TrackSelectHandle> &holder,
const std::shared_ptr<Track> &pTrack, unsigned trackCount)
{
auto result = std::make_shared<TrackSelectHandle>(pTrack);
result = AssignUIHandlePtr(holder, result);
return {
HitPreview(trackCount),
&Instance()
result
};
}
@ -97,8 +95,7 @@ UIHandle::Result TrackSelectHandle::Click
if (!event.Button(wxMOUSE_BTN_LEFT))
return Cancelled;
const auto pControls = static_cast<TrackControls*>(evt.pCell.get());
const auto pTrack = pControls->FindTrack();
const auto pTrack = mpTrack;
if (!pTrack)
return Cancelled;
TrackPanel *const trackPanel = pProject->GetTrackPanel();
@ -113,7 +110,6 @@ UIHandle::Result TrackSelectHandle::Click
result |= Cancelled;
else {
mRearrangeCount = 0;
mpTrack = pTrack;
CalculateRearrangingThresholds(event);
}

View File

@ -20,14 +20,17 @@ class Track;
class TrackSelectHandle final : public UIHandle
{
TrackSelectHandle();
TrackSelectHandle(const TrackSelectHandle&) = delete;
TrackSelectHandle &operator=(const TrackSelectHandle&) = delete;
static TrackSelectHandle& Instance();
static HitTestPreview HitPreview(unsigned trackCount);
public:
static HitTestResult HitAnywhere(unsigned trackCount);
explicit TrackSelectHandle( const std::shared_ptr<Track> &pTrack );
TrackSelectHandle &operator=(const TrackSelectHandle&) = default;
static HitTestResult HitAnywhere
(std::weak_ptr<TrackSelectHandle> &holder,
const std::shared_ptr<Track> &pTrack, unsigned trackCount);
virtual ~TrackSelectHandle();

View File

@ -23,6 +23,7 @@ Paul Licameli split from TrackPanel.cpp
#include "ZoomHandle.h"
#include "TimeShiftHandle.h"
#include "../../TrackPanelResizerCell.h"
#include "BackgroundCell.h"
HitTestResult Track::HitTest
(const TrackPanelMouseState &st,
@ -35,7 +36,8 @@ HitTestResult Track::HitTest
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(st.state, pProject);
return ZoomHandle::HitAnywhere(
pProject->GetBackgroundCell()->mZoomHandle, st.state, pProject);
// In other tools, let subclasses determine detailed hits.
HitTestResult result =
@ -49,16 +51,19 @@ HitTestResult Track::HitTest
// Sliding applies in more than one track type.
if ( !result.handle && !isMultiTool && currentTool == slideTool )
result = TimeShiftHandle::HitAnywhere(pProject);
result = TimeShiftHandle::HitAnywhere(
mTimeShiftHandle, pProject, Pointer(this), false);
// Let the multi-tool right-click handler apply only in default of all
// other detailed hits.
if ( !result.handle && isMultiTool )
result = ZoomHandle::HitTest(st.state, pProject);
result = ZoomHandle::HitTest(
pProject->GetBackgroundCell()->mZoomHandle, st.state, pProject);
// Finally, default of all is adjustment of the selection box.
if ( !result.handle && ( isMultiTool || currentTool == selectTool) )
result = SelectHandle::HitTest(st, pProject, Pointer(this));
result = SelectHandle::HitTest(
mSelectHandle, st, pProject, Pointer(this));
result.preview.refreshCode |= refresh;
return result;

View File

@ -33,11 +33,11 @@ std::shared_ptr<Track> TrackVRulerControls::FindTrack()
}
HitTestResult TrackVRulerControls::HitTest
(const TrackPanelMouseState &, const AudacityProject *)
(const TrackPanelMouseState &, const AudacityProject *)
{
// Use a space for the tip, otherwise we get the default message.
static wxCursor arrowCursor{ wxCURSOR_ARROW };
return { { _(" "), &arrowCursor }, nullptr };
return { { _(" "), &arrowCursor }, {} };
}
void TrackVRulerControls::DrawZooming

View File

@ -38,14 +38,7 @@ Paul Licameli split from TrackPanel.cpp
/// and forcing a refresh.
ZoomHandle::ZoomHandle()
{
}
ZoomHandle &ZoomHandle::Instance()
{
static ZoomHandle instance;
return instance;
}
{}
HitTestPreview ZoomHandle::HitPreview
(const wxMouseState &state, const AudacityProject *pProject)
@ -62,16 +55,20 @@ HitTestPreview ZoomHandle::HitPreview
}
HitTestResult ZoomHandle::HitAnywhere
(const wxMouseState &state, const AudacityProject *pProject)
(std::weak_ptr<ZoomHandle> &holder,
const wxMouseState &state, const AudacityProject *pProject)
{
return { HitPreview(state, pProject), &Instance() };
auto result = std::make_shared<ZoomHandle>();
result = AssignUIHandlePtr(holder, result);
return { HitPreview(state, pProject), result };
}
HitTestResult ZoomHandle::HitTest
(const wxMouseState &state, const AudacityProject *pProject)
(std::weak_ptr<ZoomHandle> &holder,
const wxMouseState &state, const AudacityProject *pProject)
{
if (state.ButtonIsDown(wxMOUSE_BTN_RIGHT))
return HitAnywhere(state, pProject);
return HitAnywhere(holder, state, pProject);
else
return {};
}

View File

@ -18,20 +18,24 @@ class wxMouseState;
struct HitTestResult;
// This handle class, unlike most, doesn't associate with any particular cell.
class ZoomHandle final : public UIHandle
{
ZoomHandle();
ZoomHandle(const ZoomHandle&) = delete;
ZoomHandle &operator=(const ZoomHandle&) = delete;
static ZoomHandle& Instance();
static HitTestPreview HitPreview
(const wxMouseState &state, const AudacityProject *pProject);
public:
ZoomHandle();
ZoomHandle &operator=(const ZoomHandle&) = default;
static HitTestResult HitAnywhere
(const wxMouseState &state, const AudacityProject *pProject);
(std::weak_ptr<ZoomHandle> &holder,
const wxMouseState &state, const AudacityProject *pProject);
static HitTestResult HitTest
(const wxMouseState &state, const AudacityProject *pProject);
(std::weak_ptr<ZoomHandle> &holder,
const wxMouseState &state, const AudacityProject *pProject);
virtual ~ZoomHandle();