1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-11-05 08:33:53 +01:00

weak_ptr not events to avoid dangling track pointers in UIHandles

This commit is contained in:
Paul Licameli
2017-06-24 17:04:07 -04:00
parent 321919301e
commit fa5a742e22
16 changed files with 182 additions and 236 deletions

View File

@@ -82,7 +82,7 @@ UIHandle::Result TrackPanelResizeHandle::Click
if (!track)
return RefreshCode::Cancelled;
mpTrack = track;
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,
@@ -153,7 +153,8 @@ UIHandle::Result TrackPanelResizeHandle::Click
UIHandle::Result TrackPanelResizeHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
if ( !mpTrack )
auto pTrack = mpTrack.lock();
if ( !pTrack )
return RefreshCode::Cancelled;
const wxMouseEvent &event = evt.event;
@@ -166,11 +167,11 @@ UIHandle::Result TrackPanelResizeHandle::Drag
//
// This used to be in HandleResizeClick(), but simply clicking
// on a resize border would switch the minimized state.
if (mpTrack->GetMinimized()) {
Track *link = mpTrack->GetLink();
if (pTrack->GetMinimized()) {
Track *link = pTrack->GetLink();
mpTrack->SetHeight(mpTrack->GetHeight());
mpTrack->SetMinimized(false);
pTrack->SetHeight(pTrack->GetHeight());
pTrack->SetMinimized(false);
if (link) {
link->SetHeight(link->GetHeight());
@@ -178,7 +179,7 @@ UIHandle::Result TrackPanelResizeHandle::Drag
// Initial values must be reset since they weren't based on the
// minimized heights.
mInitialUpperTrackHeight = link->GetHeight();
mInitialTrackHeight = mpTrack->GetHeight();
mInitialTrackHeight = pTrack->GetHeight();
}
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
else if (MONO_WAVE_PAN(mpTrack)){
@@ -201,12 +202,12 @@ UIHandle::Result TrackPanelResizeHandle::Drag
(mInitialUpperTrackHeight + delta * (1.0 - proportion));
//make sure neither track is smaller than its minimum height
if (newTrackHeight < mpTrack->GetMinimizedHeight())
newTrackHeight = mpTrack->GetMinimizedHeight();
if (newTrackHeight < pTrack->GetMinimizedHeight())
newTrackHeight = pTrack->GetMinimizedHeight();
if (newUpperTrackHeight < prev->GetMinimizedHeight())
newUpperTrackHeight = prev->GetMinimizedHeight();
mpTrack->SetHeight(newTrackHeight
pTrack->SetHeight(newTrackHeight
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
, vStereo
#endif
@@ -224,10 +225,10 @@ UIHandle::Result TrackPanelResizeHandle::Drag
newUpperTrackHeight =
mInitialUpperTrackHeight + mInitialTrackHeight - next->GetMinimizedHeight();
}
if (newUpperTrackHeight < mpTrack->GetMinimizedHeight()) {
newUpperTrackHeight = mpTrack->GetMinimizedHeight();
if (newUpperTrackHeight < pTrack->GetMinimizedHeight()) {
newUpperTrackHeight = pTrack->GetMinimizedHeight();
newTrackHeight =
mInitialUpperTrackHeight + mInitialTrackHeight - mpTrack->GetMinimizedHeight();
mInitialUpperTrackHeight + mInitialTrackHeight - pTrack->GetMinimizedHeight();
}
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
@@ -239,7 +240,7 @@ UIHandle::Result TrackPanelResizeHandle::Drag
}
#endif
mpTrack->SetHeight(newUpperTrackHeight);
pTrack->SetHeight(newUpperTrackHeight);
next->SetHeight(newTrackHeight
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
, vStereo
@@ -249,9 +250,9 @@ UIHandle::Result TrackPanelResizeHandle::Drag
auto doResize = [&] {
int newTrackHeight = mInitialTrackHeight + delta;
if (newTrackHeight < mpTrack->GetMinimizedHeight())
newTrackHeight = mpTrack->GetMinimizedHeight();
mpTrack->SetHeight(newTrackHeight);
if (newTrackHeight < pTrack->GetMinimizedHeight())
newTrackHeight = pTrack->GetMinimizedHeight();
pTrack->SetHeight(newTrackHeight);
};
//STM: We may be dragging one or two (stereo) tracks.
@@ -291,13 +292,13 @@ UIHandle::Result TrackPanelResizeHandle::Drag
{
case IsResizingBelowLinkedTracks:
{
Track *prev = tracks->GetPrev(mpTrack);
Track *prev = tracks->GetPrev(pTrack.get());
doResizeBelow(prev, false);
break;
}
case IsResizingBetweenLinkedTracks:
{
Track *next = tracks->GetNext(mpTrack);
Track *next = tracks->GetNext(pTrack.get());
doResizeBetween(next, false);
break;
}
@@ -337,7 +338,8 @@ UIHandle::Result TrackPanelResizeHandle::Release
UIHandle::Result TrackPanelResizeHandle::Cancel(AudacityProject *pProject)
{
if ( !mpTrack )
auto pTrack = mpTrack.lock();
if ( !pTrack )
return RefreshCode::Cancelled;
TrackList *const tracks = pProject->GetTracks();
@@ -345,15 +347,15 @@ UIHandle::Result TrackPanelResizeHandle::Cancel(AudacityProject *pProject)
switch (mMode) {
case IsResizing:
{
mpTrack->SetHeight(mInitialActualHeight);
mpTrack->SetMinimized(mInitialMinimized);
pTrack->SetHeight(mInitialActualHeight);
pTrack->SetMinimized(mInitialMinimized);
}
break;
case IsResizingBetweenLinkedTracks:
{
Track *const next = tracks->GetNext(mpTrack);
mpTrack->SetHeight(mInitialUpperActualHeight);
mpTrack->SetMinimized(mInitialMinimized);
Track *const next = tracks->GetNext(pTrack.get());
pTrack->SetHeight(mInitialUpperActualHeight);
pTrack->SetMinimized(mInitialMinimized);
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
if( !MONO_WAVE_PAN(mpTrack) )
#endif
@@ -365,9 +367,9 @@ UIHandle::Result TrackPanelResizeHandle::Cancel(AudacityProject *pProject)
break;
case IsResizingBelowLinkedTracks:
{
Track *const prev = tracks->GetPrev(mpTrack);
mpTrack->SetHeight(mInitialActualHeight);
mpTrack->SetMinimized(mInitialMinimized);
Track *const prev = tracks->GetPrev(pTrack.get());
pTrack->SetHeight(mInitialActualHeight);
pTrack->SetMinimized(mInitialMinimized);
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
if( !MONO_WAVE_PAN(mpTrack) )
#endif
@@ -382,15 +384,6 @@ UIHandle::Result TrackPanelResizeHandle::Cancel(AudacityProject *pProject)
return RefreshCode::RefreshAll;
}
void TrackPanelResizeHandle::OnProjectChange(AudacityProject *pProject)
{
if (! ::GetActiveProject()->GetTracks()->Contains(mpTrack)) {
mpTrack = nullptr;
}
UIHandle::OnProjectChange(pProject);
}
TrackPanelResizerCell &TrackPanelResizerCell::Instance()
{
static TrackPanelResizerCell instance;

View File

@@ -12,6 +12,7 @@ Paul Licameli split from TrackPanel.cpp
#define __AUDACITY_TRACK_PANEL_RESIZE_HANDLE__
#include "tracks/ui/CommonTrackPanelCell.h"
#include "MemoryX.h"
#include "UIHandle.h"
struct HitTestResult;
@@ -46,8 +47,6 @@ public:
Result Cancel(AudacityProject *pProject) override;
void OnProjectChange(AudacityProject *pProject) override;
private:
enum Mode {
IsResizing,
@@ -56,7 +55,7 @@ private:
};
Mode mMode{ IsResizing };
Track *mpTrack{};
std::weak_ptr<Track> mpTrack;
bool mInitialMinimized{};
int mInitialTrackHeight{};

View File

@@ -85,11 +85,16 @@ public:
// Whether to force Release (not Cancel!) of the drag when a
// keystroke command is about to be dispatched. Default is always false.
// When default is false, any remembered pointers to tracks should be
// weak_ptrs.
virtual bool StopsOnKeystroke();
// Notification after a command is dispatched; generally, it will need to
// be overridden only in case StopsOnKeystroke() returns false. Default
// does nothing.
// PRL: all former uses of this are now accomplished with weak_ptr instead
// to avoid dangling pointers to tracks. But maybe there will be a future
// use?
virtual void OnProjectChange(AudacityProject *pProject);
};

View File

@@ -32,7 +32,7 @@ LabelDefaultClickHandle::~LabelDefaultClickHandle()
}
struct LabelDefaultClickHandle::LabelState {
std::vector< std::pair< LabelTrack*, LabelTrack::Flags > > mPairs;
std::vector< std::pair< std::weak_ptr<LabelTrack>, LabelTrack::Flags > > mPairs;
};
void LabelDefaultClickHandle::SaveState( AudacityProject *pProject )
@@ -46,32 +46,21 @@ void LabelDefaultClickHandle::SaveState( AudacityProject *pProject )
while (n) {
if (n->GetKind() == Track::Label) {
LabelTrack *const lt = static_cast<LabelTrack*>(n);
pairs.push_back( std::make_pair( lt, lt->SaveFlags() ) );
pairs.push_back( std::make_pair(
Track::Pointer<LabelTrack>( lt ),
lt->SaveFlags() )
);
}
n = iter.Next();
}
}
void LabelDefaultClickHandle::UpdateState( AudacityProject *pProject )
{
if ( mLabelState ) {
auto trackList = pProject->GetTracks();
auto &pairs = mLabelState->mPairs;
auto it = pairs.begin();
while ( it != pairs.end() ) {
if ( trackList->Contains( it->first ) )
++it;
else
it = pairs.erase( it );
}
}
}
void LabelDefaultClickHandle::RestoreState( AudacityProject *pProject )
{
if ( mLabelState ) {
for ( const auto &pair : mLabelState->mPairs )
pair.first->RestoreFlags( pair.second );
if (auto pLt = pair.first.lock())
pLt->RestoreFlags( pair.second );
mLabelState.reset();
}
}
@@ -174,7 +163,6 @@ bool LabelDefaultClickHandle::StopsOnKeystroke()
void LabelDefaultClickHandle::OnProjectChange(AudacityProject *pProject)
{
UpdateState( pProject );
if (mpForward)
return mpForward->OnProjectChange(pProject);
UIHandle::OnProjectChange(pProject);

View File

@@ -63,7 +63,6 @@ private:
struct LabelState;
std::unique_ptr< LabelState > mLabelState;
void SaveState( AudacityProject *pProject );
void UpdateState( AudacityProject *pProject );
void RestoreState( AudacityProject *pProject );
};

View File

@@ -54,10 +54,11 @@ UIHandle::Result LabelTextHandle::Click
const wxMouseEvent &event = evt.event;
ViewInfo &viewInfo = pProject->GetViewInfo();
mpLT = static_cast<LabelTrack*>(pCell);
auto pLT = Track::Pointer<LabelTrack>( static_cast<Track*>(pCell) );
mpLT = pLT;
mSelectedRegion = viewInfo.selectedRegion;
mpLT->HandleTextClick( event, evt.rect, viewInfo, &viewInfo.selectedRegion );
wxASSERT(mpLT->IsSelected());
pLT->HandleTextClick( event, evt.rect, viewInfo, &viewInfo.selectedRegion );
wxASSERT(pLT->IsSelected());
{
// IF the user clicked a label, THEN select all other tracks by Label
@@ -68,7 +69,7 @@ UIHandle::Result LabelTextHandle::Click
//do nothing if at least one other track is selected
bool done = false;
while (!done && t) {
if (t->GetSelected() && t != mpLT)
if (t->GetSelected() && t != pLT.get())
done = true;
t = iter.Next();
}
@@ -88,7 +89,7 @@ UIHandle::Result LabelTextHandle::Click
// Do this after, for its effect on TrackPanel's memory of last selected
// track (which affects shift-click actions)
selectionState.SelectTrack
( *pProject->GetTracks(), *mpLT, true, true,
( *pProject->GetTracks(), *pLT, true, true,
pProject->GetMixerBoard() );
}
@@ -107,8 +108,9 @@ UIHandle::Result LabelTextHandle::Drag
Result result = RefreshNone;
const wxMouseEvent &event = evt.event;
if(mpLT)
mpLT->HandleTextDragRelease(event);
auto pLT = mpLT.lock();
if(pLT)
pLT->HandleTextDragRelease(event);
// locate the initial mouse position
if (event.LeftIsDown()) {
@@ -116,10 +118,10 @@ UIHandle::Result LabelTextHandle::Drag
mLabelTrackStartXPos = event.m_x;
mLabelTrackStartYPos = event.m_y;
if (mpLT &&
(mpLT->getSelectedIndex() != -1) &&
mpLT->OverTextBox(
mpLT->GetLabel(mpLT->getSelectedIndex()),
if (pLT &&
(pLT->getSelectedIndex() != -1) &&
pLT->OverTextBox(
pLT->GetLabel(pLT->getSelectedIndex()),
mLabelTrackStartXPos,
mLabelTrackStartYPos))
mLabelTrackStartYPos = -1;
@@ -152,8 +154,9 @@ UIHandle::Result LabelTextHandle::Release
}
const wxMouseEvent &event = evt.event;
if (mpLT)
mpLT->HandleTextDragRelease(event);
auto pLT = mpLT.lock();
if (pLT)
pLT->HandleTextDragRelease(event);
// handle mouse left button up
if (event.LeftUp())
@@ -172,13 +175,3 @@ UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject )
viewInfo.selectedRegion = mSelectedRegion;
return RefreshCode::RefreshAll;
}
void LabelTextHandle::OnProjectChange(AudacityProject *pProject)
{
if (! pProject->GetTracks()->Contains(mpLT)) {
mpLT = nullptr;
mRect = {};
}
UIHandle::OnProjectChange(pProject);
}

View File

@@ -49,11 +49,8 @@ public:
Result Cancel(AudacityProject *pProject) override;
void OnProjectChange(AudacityProject *pProject) override;
private:
LabelTrack *mpLT {};
wxRect mRect {};
std::weak_ptr<LabelTrack> mpLT {};
int mLabelTrackStartXPos { -1 };
int mLabelTrackStartYPos { -1 };
SelectedRegion mSelectedRegion{};

View File

@@ -57,9 +57,7 @@ protected:
virtual Result Cancel(AudacityProject *pProject);
void OnProjectChange(AudacityProject *pProject) override;
NoteTrack *mpTrack{};
std::weak_ptr<NoteTrack> mpTrack;
wxRect mRect{};
};
@@ -86,7 +84,7 @@ HitTestResult NoteTrackClickHandle::HitTest
return {};
if (pTrack->GetKind() == Track::Note &&
midiRect.Contains(event.m_x, event.m_y)) {
Instance().mpTrack = static_cast<NoteTrack*>(pTrack);
Instance().mpTrack = Track::Pointer<NoteTrack>( pTrack );
Instance().mRect = midiRect;
return {
HitTestPreview(),
@@ -121,11 +119,12 @@ UIHandle::Result NoteTrackClickHandle::Release
{
using namespace RefreshCode;
if (!mpTrack)
return RefreshNone;
auto pTrack = mpTrack.lock();
if (!pTrack)
return Cancelled;
const wxMouseEvent &event = evt.event;
if (mpTrack->LabelClick(mRect, event.m_x, event.m_y,
if (pTrack->LabelClick(mRect, event.m_x, event.m_y,
event.Button(wxMOUSE_BTN_RIGHT))) {
// No undo items needed??
pProject->ModifyState(false);
@@ -139,16 +138,6 @@ UIHandle::Result NoteTrackClickHandle::Cancel(AudacityProject *)
return RefreshCode::RefreshNone;
}
void NoteTrackClickHandle::OnProjectChange(AudacityProject *pProject)
{
if (! pProject->GetTracks()->Contains(mpTrack)) {
mpTrack = nullptr;
mRect = {};
}
UIHandle::OnProjectChange(pProject);
}
///////////////////////////////////////////////////////////////////////////////
NoteTrackControls::NoteTrackControls()
{

View File

@@ -67,17 +67,15 @@ public:
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
void OnProjectChange(AudacityProject *pProject) override;
private:
NoteTrack *mpTrack;
std::weak_ptr<NoteTrack> mpTrack;
int mZoomStart, mZoomEnd;
wxRect mRect;
};
NoteTrackVZoomHandle::NoteTrackVZoomHandle()
: mpTrack(NULL), mZoomStart(0), mZoomEnd(0), mRect()
: mZoomStart(0), mZoomEnd(0), mRect()
{
}
@@ -111,9 +109,8 @@ NoteTrackVZoomHandle::~NoteTrackVZoomHandle()
UIHandle::Result NoteTrackVZoomHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
mpTrack = static_cast<NoteTrack*>(
static_cast<NoteTrackVRulerControls*>(evt.pCell)->GetTrack()
);
mpTrack = Track::Pointer<NoteTrack>(
static_cast<NoteTrackVRulerControls*>(evt.pCell)->GetTrack() );
mRect = evt.rect;
const wxMouseEvent &event = evt.event;
@@ -129,9 +126,12 @@ UIHandle::Result NoteTrackVZoomHandle::Click
UIHandle::Result NoteTrackVZoomHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
if (!mpTrack.lock())
return Cancelled;
const wxMouseEvent &event = evt.event;
mZoomEnd = event.m_y;
using namespace RefreshCode;
if (IsDragZooming(mZoomStart, mZoomEnd)) {
// changed Note track to work like audio track
// mpTrack->VScroll(mZoomStart, mZoomEnd);
@@ -151,18 +151,19 @@ UIHandle::Result NoteTrackVZoomHandle::Release
wxWindow *pParent)
{
using namespace RefreshCode;
if (!mpTrack)
auto pTrack = mpTrack.lock();
if (!pTrack)
return RefreshNone;
const wxMouseEvent &event = evt.event;
if (IsDragZooming(mZoomStart, mZoomEnd)) {
mpTrack->ZoomTo(evt.rect, mZoomStart, mZoomEnd);
pTrack->ZoomTo(evt.rect, mZoomStart, mZoomEnd);
}
else if (event.ShiftDown() || event.RightUp()) {
mpTrack->ZoomOut(evt.rect, mZoomEnd);
pTrack->ZoomOut(evt.rect, mZoomEnd);
}
else {
mpTrack->ZoomIn(evt.rect, mZoomEnd);
pTrack->ZoomIn(evt.rect, mZoomEnd);
}
// TODO: shift-right click as in audio track?
@@ -183,22 +184,15 @@ UIHandle::Result NoteTrackVZoomHandle::Cancel(AudacityProject *pProject)
void NoteTrackVZoomHandle::DrawExtras
(DrawingPass pass, wxDC * dc, const wxRegion &, const wxRect &panelRect)
{
if (!mpTrack.lock())
return;
if ( pass == UIHandle::Cells &&
IsDragZooming( mZoomStart, mZoomEnd ) )
TrackVRulerControls::DrawZooming
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
}
void NoteTrackVZoomHandle::OnProjectChange(AudacityProject *pProject)
{
if (! pProject->GetTracks()->Contains(mpTrack)) {
mpTrack = nullptr;
mRect = {};
}
UIHandle::OnProjectChange(pProject);
}
///////////////////////////////////////////////////////////////////////////////
NoteTrackVRulerControls::NoteTrackVRulerControls()
: TrackVRulerControls()

View File

@@ -8,6 +8,7 @@ Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#include "../../../Audacity.h"
#include "PlayableTrackButtonHandles.h"
#include "../../../HitTestResult.h"
@@ -35,8 +36,9 @@ MuteButtonHandle &MuteButtonHandle::Instance()
UIHandle::Result MuteButtonHandle::CommitChanges
(const wxMouseEvent &event, AudacityProject *pProject, wxWindow *)
{
if ( dynamic_cast< PlayableTrack* >( mpTrack ) )
pProject->DoTrackMute(mpTrack, event.ShiftDown());
auto pTrack = mpTrack.lock();
if ( dynamic_cast< PlayableTrack* >( pTrack.get() ) )
pProject->DoTrackMute(pTrack.get(), event.ShiftDown());
return RefreshCode::RefreshNone;
}
@@ -83,8 +85,9 @@ SoloButtonHandle &SoloButtonHandle::Instance()
UIHandle::Result SoloButtonHandle::CommitChanges
(const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent)
{
if ( dynamic_cast< PlayableTrack* >( mpTrack ) )
pProject->DoTrackSolo(mpTrack, event.ShiftDown());
auto pTrack = mpTrack.lock();
if ( dynamic_cast< PlayableTrack* >( pTrack.get() ) )
pProject->DoTrackSolo(pTrack.get(), event.ShiftDown());
return RefreshCode::RefreshNone;
}

View File

@@ -518,10 +518,8 @@ public:
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
void OnProjectChange(AudacityProject *pProject) override;
private:
WaveTrack *mpTrack{};
std::weak_ptr<WaveTrack> mpTrack;
int mZoomStart{}, mZoomEnd{};
wxRect mRect{};
@@ -561,9 +559,8 @@ WaveTrackVZoomHandle::~WaveTrackVZoomHandle()
UIHandle::Result WaveTrackVZoomHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *)
{
mpTrack = static_cast<WaveTrack*>(
static_cast<WaveTrackVRulerControls*>(evt.pCell)->GetTrack()
);
mpTrack = Track::Pointer<WaveTrack>(
static_cast<WaveTrackVRulerControls*>(evt.pCell)->GetTrack() );
mRect = evt.rect;
const wxMouseEvent &event = evt.event;
@@ -576,9 +573,12 @@ UIHandle::Result WaveTrackVZoomHandle::Click
UIHandle::Result WaveTrackVZoomHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *)
{
using namespace RefreshCode;
if (!mpTrack.lock())
return Cancelled;
const wxMouseEvent &event = evt.event;
mZoomEnd = event.m_y;
using namespace RefreshCode;
if (IsDragZooming(mZoomStart, mZoomEnd))
return RefreshAll;
return RefreshNone;
@@ -595,7 +595,8 @@ UIHandle::Result WaveTrackVZoomHandle::Release
wxWindow *pParent)
{
using namespace RefreshCode;
if (!mpTrack)
auto pTrack = mpTrack.lock();
if (!pTrack)
return RefreshNone;
const wxMouseEvent &event = evt.event;
@@ -608,11 +609,11 @@ UIHandle::Result WaveTrackVZoomHandle::Release
!(event.ShiftDown() || event.CmdDown()))
{
InitMenuData data {
mpTrack, mRect, RefreshCode::RefreshNone, event.m_y
pTrack.get(), mRect, RefreshCode::RefreshNone, event.m_y
};
PopupMenuTable *const pTable =
(mpTrack->GetDisplay() == WaveTrack::Spectrum)
(pTrack->GetDisplay() == WaveTrack::Spectrum)
? (PopupMenuTable *) &SpectrumVRulerMenuTable::Instance()
: (PopupMenuTable *) &WaveformVRulerMenuTable::Instance();
std::unique_ptr<PopupMenuTable::Menu>
@@ -623,7 +624,7 @@ UIHandle::Result WaveTrackVZoomHandle::Release
return data.result;
}
else
HandleWaveTrackVZoom(pProject, mpTrack, shiftDown, rightUp,
HandleWaveTrackVZoom(pProject, pTrack.get(), shiftDown, rightUp,
mRect, mZoomStart, mZoomEnd, false);
return UpdateVRuler | RefreshAll;
@@ -639,22 +640,15 @@ UIHandle::Result WaveTrackVZoomHandle::Cancel(AudacityProject*)
void WaveTrackVZoomHandle::DrawExtras
(DrawingPass pass, wxDC * dc, const wxRegion &, const wxRect &panelRect)
{
if (!mpTrack.lock())
return;
if ( pass == UIHandle::Cells &&
IsDragZooming( mZoomStart, mZoomEnd ) )
TrackVRulerControls::DrawZooming
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
}
void WaveTrackVZoomHandle::OnProjectChange(AudacityProject *pProject)
{
if (! pProject->GetTracks()->Contains(mpTrack)) {
mpTrack = nullptr;
mRect = {};
}
UIHandle::OnProjectChange(pProject);
}
///////////////////////////////////////////////////////////////////////////////
WaveTrackVRulerControls::WaveTrackVRulerControls()
: TrackVRulerControls()

View File

@@ -45,7 +45,8 @@ UIHandle::Result ButtonHandle::Click
// Come here for left click or double click
if (mRect.Contains(event.m_x, event.m_y)) {
mpTrack = static_cast<TrackControls*>(evt.pCell)->GetTrack();
mpTrack = Track::Pointer(
static_cast<TrackControls*>(evt.pCell)->GetTrack() );
TrackControls::gCaptureState = mDragCode;
// Toggle visible button state
return RefreshCell;
@@ -59,6 +60,9 @@ UIHandle::Result ButtonHandle::Drag
{
const wxMouseEvent &event = evt.event;
using namespace RefreshCode;
if (!mpTrack.lock())
return Cancelled;
const int newState =
mRect.Contains(event.m_x, event.m_y) ? mDragCode : 0;
if (TrackControls::gCaptureState == newState)
@@ -81,13 +85,17 @@ UIHandle::Result ButtonHandle::Release
wxWindow *pParent)
{
using namespace RefreshCode;
auto pTrack = mpTrack.lock();
if (!pTrack)
return Cancelled;
Result result = RefreshNone;
const wxMouseEvent &event = evt.event;
if (TrackControls::gCaptureState) {
TrackControls::gCaptureState = 0;
result = RefreshCell;
}
if (mpTrack && mRect.Contains(event.m_x, event.m_y))
if (pTrack && mRect.Contains(event.m_x, event.m_y))
result |= CommitChanges(event, pProject, pParent);
return result;
}
@@ -102,14 +110,3 @@ UIHandle::Result ButtonHandle::Cancel(AudacityProject *pProject)
else
return RefreshNone;
}
void ButtonHandle::OnProjectChange(AudacityProject *pProject)
{
if (! pProject->GetTracks()->Contains(mpTrack)) {
mpTrack = nullptr;
mRect = {};
}
UIHandle::OnProjectChange(pProject);
}

View File

@@ -12,6 +12,7 @@ Paul Licameli
#define __AUDACITY_BUTTON_HANDLE__
#include "../../UIHandle.h"
#include "../../MemoryX.h"
class wxMouseEvent;
#include <wx/gdicmn.h>
@@ -53,10 +54,8 @@ protected:
Result Cancel(AudacityProject *pProject) override;
void OnProjectChange(AudacityProject *pProject) override;
wxRect mRect {};
Track *mpTrack {};
std::weak_ptr<Track> mpTrack;
const int mDragCode;
};

View File

@@ -50,8 +50,7 @@ enum {
// #define SPECTRAL_EDITING_ESC_KEY
SelectHandle::SelectHandle()
: mpTrack(0)
, mRect()
: mRect()
, mInitialSelection()
, mSnapManager()
@@ -64,7 +63,6 @@ SelectHandle::SelectHandle()
, mSelectionBoundary(0)
, mFreqSelMode(FREQ_SEL_INVALID)
, mFreqSelTrack(NULL)
, mFreqSelPin(-1.0)
, mFrequencySnapper(new SpectrumAnalyst)
@@ -559,7 +557,7 @@ UIHandle::Result SelectHandle::Click
else if (!event.LeftDown())
return Cancelled;
mpTrack = pTrack;
mpTrack = Track::Pointer( pTrack );
mRect = evt.rect;
mInitialSelection = viewInfo.selectedRegion;
@@ -599,7 +597,7 @@ UIHandle::Result SelectHandle::Click
double value;
// Shift-click, choose closest boundary
SelectionBoundary boundary =
ChooseBoundary(viewInfo, event, mpTrack, mRect, false, false, &value);
ChooseBoundary(viewInfo, event, pTrack, mRect, false, false, &value);
mSelectionBoundary = boundary;
switch (boundary) {
case SBLeft:
@@ -612,14 +610,14 @@ UIHandle::Result SelectHandle::Click
#endif
mSelStartValid = true;
mSelStart = value;
AdjustSelection(viewInfo, event.m_x, mRect.x, mpTrack);
AdjustSelection(viewInfo, event.m_x, mRect.x, pTrack);
break;
}
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
case SBBottom:
case SBTop:
{
mFreqSelTrack = static_cast<const WaveTrack*>(mpTrack);
mFreqSelTrack = Track::Pointer<const WaveTrack>( pTrack );
mFreqSelPin = value;
mFreqSelMode =
(boundary == SBBottom)
@@ -627,7 +625,9 @@ UIHandle::Result SelectHandle::Click
// Drag frequency only, not time:
mSelStartValid = false;
AdjustFreqSelection(viewInfo, event.m_y, mRect.y, mRect.height);
AdjustFreqSelection(
static_cast<WaveTrack*>(pTrack),
viewInfo, event.m_y, mRect.y, mRect.height);
break;
}
case SBCenter:
@@ -656,13 +656,13 @@ UIHandle::Result SelectHandle::Click
//Make sure you are within the selected track
bool startNewSelection = true;
if (mpTrack && mpTrack->GetSelected()) {
if (pTrack && pTrack->GetSelected()) {
// Adjusting selection edges can be turned off in the
// preferences now
if (viewInfo.bAdjustSelectionEdges) {
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
isSpectralSelectionTrack(mpTrack)) {
isSpectralSelectionTrack(pTrack)) {
// This code is no longer reachable, but it had a place in the
// spectral selection prototype. It used to be that you could be
// in a center-frequency-snapping mode that was not a mouse drag
@@ -672,11 +672,13 @@ UIHandle::Result SelectHandle::Click
// Ignore whether we are inside the time selection.
// Exit center-snapping, start dragging the width.
mFreqSelMode = FREQ_SEL_PINNED_CENTER;
mFreqSelTrack = static_cast<WaveTrack*>(mpTrack);
mFreqSelTrack = Track::Pointer<const WaveTrack>( pTrack );
mFreqSelPin = viewInfo.selectedRegion.fc();
// Do not adjust time boundaries
mSelStartValid = false;
AdjustFreqSelection(viewInfo, event.m_y, mRect.y, mRect.height);
AdjustFreqSelection(
static_cast<WaveTrack*>(pTrack),
viewInfo, event.m_y, mRect.y, mRect.height);
// For persistence of the selection change:
pProject->ModifyState(false);
mSelectionBoundary = SBWidth;
@@ -688,7 +690,7 @@ UIHandle::Result SelectHandle::Click
// Not shift-down, choose boundary only within snapping
double value;
SelectionBoundary boundary =
ChooseBoundary(viewInfo, event, mpTrack, mRect, true, true, &value);
ChooseBoundary(viewInfo, event, pTrack, mRect, true, true, &value);
mSelectionBoundary = boundary;
switch (boundary) {
case SBNone:
@@ -711,7 +713,7 @@ UIHandle::Result SelectHandle::Click
startNewSelection = false;
// Disable time selection
mSelStartValid = false;
mFreqSelTrack = static_cast<const WaveTrack*>(mpTrack);
mFreqSelTrack = Track::Pointer<const WaveTrack>( pTrack );
mFreqSelPin = value;
mFreqSelMode =
(boundary == SBWidth) ? FREQ_SEL_PINNED_CENTER :
@@ -739,17 +741,17 @@ UIHandle::Result SelectHandle::Click
// If we didn't move a selection boundary, start a NEW selection
selectionState.SelectNone( *trackList, pMixerBoard );
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
StartFreqSelection (viewInfo, event.m_y, mRect.y, mRect.height, mpTrack);
StartFreqSelection (viewInfo, event.m_y, mRect.y, mRect.height, pTrack);
#endif
StartSelection(pProject, event.m_x, mRect.x);
selectionState.SelectTrack
( *trackList, *mpTrack, true, true, pMixerBoard );
trackPanel->SetFocusedTrack(mpTrack);
( *trackList, *pTrack, true, true, pMixerBoard );
trackPanel->SetFocusedTrack(pTrack);
//On-Demand: check to see if there is an OD thing associated with this track.
if (mpTrack->GetKind() == Track::Wave) {
if (pTrack->GetKind() == Track::Wave) {
if(ODManager::IsInstanceCreated())
ODManager::Instance()->DemandTrackUpdate
(static_cast<WaveTrack*>(mpTrack),mSelStart);
(static_cast<WaveTrack*>(pTrack),mSelStart);
}
Connect(pProject);
@@ -787,7 +789,8 @@ UIHandle::Result SelectHandle::Drag
}
// Also fuhggeddaboudit if not in a track.
if (!mpTrack)
auto pTrack = mpTrack.lock();
if (!pTrack)
return RefreshNone;
// JKC: Logic to prevent a selection smaller than 5 pixels to
@@ -809,7 +812,7 @@ UIHandle::Result SelectHandle::Drag
static_cast<CommonTrackPanelCell*>(evt.pCell)->FindTrack();
// Handle which tracks are selected
Track *sTrack = mpTrack;
Track *sTrack = pTrack.get();
Track *eTrack = clickedTrack;
auto trackList = pProject->GetTracks();
auto pMixerBoard = pProject->GetMixerBoard();
@@ -824,11 +827,13 @@ UIHandle::Result SelectHandle::Drag
if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
!viewInfo.selectedRegion.isPoint())
MoveSnappingFreqSelection
(pProject, viewInfo, y, mRect.y, mRect.height, mpTrack);
(pProject, viewInfo, y, mRect.y, mRect.height, pTrack.get());
else
#endif
if (mFreqSelTrack == mpTrack)
AdjustFreqSelection(viewInfo, y, mRect.y, mRect.height);
if (mFreqSelTrack.lock() == pTrack)
AdjustFreqSelection(
static_cast<WaveTrack*>(pTrack.get()),
viewInfo, y, mRect.y, mRect.height);
#endif
AdjustSelection(viewInfo, x, mRect.x, clickedTrack);
@@ -902,20 +907,6 @@ void SelectHandle::DrawExtras
}
}
void SelectHandle::OnProjectChange(AudacityProject *pProject)
{
if (! pProject->GetTracks()->Contains(mpTrack)) {
mpTrack = nullptr;
mRect = {};
}
if (! pProject->GetTracks()->Contains(mFreqSelTrack)) {
mFreqSelTrack = nullptr;
}
UIHandle::OnProjectChange(pProject);
}
void SelectHandle::Connect(AudacityProject *pProject)
{
mConnectedProject = pProject;
@@ -934,8 +925,8 @@ void SelectHandle::Disconnect()
this);
mConnectedProject = NULL;
mpTrack = 0;
mFreqSelTrack = nullptr;
mpTrack.reset();
mFreqSelTrack.reset();
mSnapManager.reset(NULL);
@@ -994,7 +985,8 @@ void SelectHandle::OnTimer(wxCommandEvent &event)
}
}
if (mAutoScrolling && mpTrack) {
auto pTrack = mpTrack.lock();
if (mAutoScrolling && pTrack) {
// AS: To keep the selection working properly as we scroll,
// we fake a mouse event (remember, this method is called
// from a timer tick).
@@ -1002,7 +994,7 @@ void SelectHandle::OnTimer(wxCommandEvent &event)
// AS: For some reason, GCC won't let us pass this directly.
wxMouseEvent evt(wxEVT_MOTION);
const auto size = trackPanel->GetSize();
Drag(TrackPanelMouseEvent{ evt, mRect, size, mpTrack }, project);
Drag(TrackPanelMouseEvent{ evt, mRect, size, pTrack.get() }, project);
mAutoScrolling = false;
mConnectedProject->GetTrackPanel()->Refresh(false);
}
@@ -1022,7 +1014,8 @@ void SelectHandle::StartSelection
mSnapLeft = -1;
mSnapRight = -1;
bool snappedPoint, snappedTime;
if (mSnapManager->Snap(mpTrack, mSelStart, false,
auto pTrack = mpTrack.lock();
if (mSnapManager->Snap(pTrack.get(), mSelStart, false,
&s, &snappedPoint, &snappedTime)) {
if (snappedPoint)
mSnapLeft = viewInfo.TimeToPosition(s, trackLeftEdge);
@@ -1041,7 +1034,7 @@ void SelectHandle::StartSelection
/// Extend or contract the existing selection
void SelectHandle::AdjustSelection
(ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge,
Track *pTrack)
Track *track)
{
if (!mSelStartValid)
// Must be dragging frequency bounds only.
@@ -1052,8 +1045,9 @@ void SelectHandle::AdjustSelection
double origSel0, origSel1;
double sel0, sel1;
if (pTrack == NULL && mpTrack != NULL)
pTrack = mpTrack;
auto pTrack = Track::Pointer( track );
if (!pTrack)
pTrack = mpTrack.lock();
if (mSelStart < selend) {
sel0 = mSelStart;
@@ -1071,14 +1065,14 @@ void SelectHandle::AdjustSelection
mSnapLeft = -1;
mSnapRight = -1;
bool snappedPoint, snappedTime;
if (mpTrack &&
mSnapManager->Snap(mpTrack, sel0, false,
if (pTrack &&
mSnapManager->Snap(pTrack.get(), sel0, false,
&sel0, &snappedPoint, &snappedTime)) {
if (snappedPoint)
mSnapLeft = viewInfo.TimeToPosition(sel0, trackLeftEdge);
}
if (mpTrack &&
mSnapManager->Snap(mpTrack, sel1, true,
if (pTrack &&
mSnapManager->Snap(pTrack.get(), sel1, true,
&sel1, &snappedPoint, &snappedTime)) {
if (snappedPoint)
mSnapRight = viewInfo.TimeToPosition(sel1, trackLeftEdge);
@@ -1100,29 +1094,31 @@ void SelectHandle::AdjustSelection
//On-Demand: check to see if there is an OD thing associated with this track. If so we want to update the focal point for the task.
if (pTrack && (pTrack->GetKind() == Track::Wave) && ODManager::IsInstanceCreated())
ODManager::Instance()->DemandTrackUpdate
(static_cast<WaveTrack*>(pTrack),sel0); //sel0 is sometimes less than mSelStart
(static_cast<WaveTrack*>(pTrack.get()),sel0); //sel0 is sometimes less than mSelStart
}
void SelectHandle::StartFreqSelection(ViewInfo &viewInfo,
int mouseYCoordinate, int trackTopEdge,
int trackHeight, Track *pTrack)
{
mFreqSelTrack = NULL;
mFreqSelTrack.reset();
mFreqSelMode = FREQ_SEL_INVALID;
mFreqSelPin = SelectedRegion::UndefinedFrequency;
if (isSpectralSelectionTrack(pTrack)) {
// Spectral selection track is always wave
mFreqSelTrack = static_cast<WaveTrack*>(pTrack);
auto shTrack = Track::Pointer<const WaveTrack>( pTrack );
mFreqSelTrack = shTrack;
mFreqSelMode = FREQ_SEL_FREE;
mFreqSelPin =
PositionToFrequency(mFreqSelTrack, false, mouseYCoordinate,
PositionToFrequency(shTrack.get(), false, mouseYCoordinate,
trackTopEdge, trackHeight);
viewInfo.selectedRegion.setFrequencies(mFreqSelPin, mFreqSelPin);
}
}
void SelectHandle::AdjustFreqSelection(ViewInfo &viewInfo,
void SelectHandle::AdjustFreqSelection(
const WaveTrack *wt, ViewInfo &viewInfo,
int mouseYCoordinate, int trackTopEdge,
int trackHeight)
{
@@ -1133,7 +1129,6 @@ void SelectHandle::AdjustFreqSelection(ViewInfo &viewInfo,
// Extension happens only when dragging in the same track in which we
// started, and that is of a spectrogram display type.
const WaveTrack *const wt = mFreqSelTrack;
const double rate = wt->GetRate();
const double frequency =
PositionToFrequency(wt, true, mouseYCoordinate,
@@ -1211,7 +1206,7 @@ void SelectHandle::HandleCenterFrequencyClick
if (shiftDown) {
// Disable time selection
mSelStartValid = false;
mFreqSelTrack = pTrack;
mFreqSelTrack = Track::Pointer<const WaveTrack>( pTrack );
mFreqSelPin = value;
mFreqSelMode = FREQ_SEL_DRAG_CENTER;
}
@@ -1310,7 +1305,7 @@ void SelectHandle::MoveSnappingFreqSelection
// A change here would affect what AdjustFreqSelection() does
// in the prototype version where you switch from moving center to
// dragging width with a click. No effect now.
mFreqSelTrack = wt;
mFreqSelTrack = Track::Pointer<const WaveTrack>( wt );
// SelectNone();
// SelectTrack(pTrack, true);

View File

@@ -63,8 +63,6 @@ public:
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
void OnProjectChange(AudacityProject *pProject) override;
// Receives timer event notifications, to implement auto-scroll
void OnTimer(wxCommandEvent &event);
@@ -82,7 +80,8 @@ private:
(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge,
int trackHeight, Track *pTrack);
void AdjustFreqSelection
(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge,
(const WaveTrack *wt,
ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge,
int trackHeight);
void HandleCenterFrequencyClick
@@ -103,7 +102,7 @@ private:
// (const ViewInfo &viewInfo, double hintFrequency, bool logF);
Track *mpTrack;
std::weak_ptr<Track> mpTrack;
wxRect mRect;
SelectedRegion mInitialSelection;
@@ -131,7 +130,7 @@ private:
FREQ_SEL_TOP_FREE,
FREQ_SEL_BOTTOM_FREE,
} mFreqSelMode;
const WaveTrack *mFreqSelTrack {};
std::weak_ptr<const WaveTrack> mFreqSelTrack;
// Following holds:
// the center for FREQ_SEL_PINNED_CENTER,
// the ratio of top to center (== center to bottom) for FREQ_SEL_DRAG_CENTER,

View File

@@ -37,11 +37,12 @@ UIHandle::Result MinimizeButtonHandle::CommitChanges
{
using namespace RefreshCode;
if (mpTrack)
auto pTrack = mpTrack.lock();
if (pTrack)
{
mpTrack->SetMinimized(!mpTrack->GetMinimized());
if (mpTrack->GetLink())
mpTrack->GetLink()->SetMinimized(mpTrack->GetMinimized());
pTrack->SetMinimized(!pTrack->GetMinimized());
if (pTrack->GetLink())
pTrack->GetLink()->SetMinimized(pTrack->GetMinimized());
pProject->ModifyState(true);
// Redraw all tracks when any one of them expands or contracts
@@ -93,12 +94,13 @@ UIHandle::Result CloseButtonHandle::CommitChanges
using namespace RefreshCode;
Result result = RefreshNone;
if (mpTrack)
auto pTrack = mpTrack.lock();
if (pTrack)
{
pProject->StopIfPaused();
if (!pProject->IsAudioActive()) {
// This pushes an undo item:
pProject->RemoveTrack(mpTrack);
pProject->RemoveTrack(pTrack.get());
// Redraw all tracks when any one of them closes
// (Could we invent a return code that draws only those at or below
// the affected track?)