1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-12 14:11:10 +02:00

Remove many uses of GetLink in TrackPanel

This commit is contained in:
Paul Licameli 2017-01-03 17:07:12 -05:00
parent 0c0c2c0d1e
commit 669054b4f4
13 changed files with 184 additions and 220 deletions

View File

@ -1846,14 +1846,12 @@ void TrackPanel::UpdateTrackVRuler(const Track *t)
wxRect rect(GetVRulerOffset(),
kTopMargin,
GetVRulerWidth(),
t->GetHeight() - (kTopMargin + kBottomMargin));
0);
mTrackArtist->UpdateVRuler(t, rect);
const Track *l = t->GetLink();
if (l)
{
rect.height = l->GetHeight() - (kTopMargin + kBottomMargin);
mTrackArtist->UpdateVRuler(l, rect);
for (auto channel : TrackList::Channels(t)) {
rect.height = channel->GetHeight() - (kTopMargin + kBottomMargin);
mTrackArtist->UpdateVRuler(channel, rect);
}
}
@ -2079,30 +2077,29 @@ wxRect TrackPanel::FindTrackRect( const Track * target, bool label )
return { 0, 0, 0, 0 };
}
wxRect rect{
0,
target->GetY() - mViewInfo->vpos,
GetSize().GetWidth(),
target->GetHeight()
};
// PRL: I think the following very old comment misused the term "race
// condition" for a bug that happened with only a single thread. I think the
// real problem referred to, was that this function could be reached, via
// TrackPanelAx callbacks, during low-level operations while the TrackList
// was not in a consistent state. Therefore GetLinked() did not imply
// that GetLink() was not null.
// was not in a consistent state.
// Now the problem is fixed by delaying the handling of events generated
// by TrackList.
// by TrackList. And besides that, we use Channels() instead of looking
// directly at the links.
// Old comment:
// The check for a null linked track is necessary because there's
// a possible race condition between the time the 2 linked tracks
// are added and when wxAccessible methods are called. This is
// most evident when using Jaws.
if (target->GetLinked() && target->GetLink()) {
rect.height += target->GetLink()->GetHeight();
}
auto height = TrackList::Channels( target ).sum( &Track::GetHeight );
wxRect rect{
0,
target->GetY() - mViewInfo->vpos,
GetSize().GetWidth(),
height
};
rect.x += kLeftMargin;
if (label)
@ -2150,8 +2147,7 @@ void TrackPanel::SetFocusedCell()
void TrackPanel::SetFocusedTrack( Track *t )
{
// Make sure we always have the first linked track of a stereo track
if (t && !t->GetLinked() && t->GetLink())
t = (WaveTrack*)t->GetLink();
t = *GetTracks()->FindLeader(t);
auto cell = mAx->SetFocus( Track::Pointer( t ) ).get();
@ -2656,7 +2652,7 @@ TrackPanelCellIterator &TrackPanelCellIterator::operator++ ()
}
if ( mpTrack ) {
if ( mType == CellType::Label &&
mpTrack->GetLink() && !mpTrack->GetLinked() )
!mpTrack->IsLeader() )
// Visit label of stereo track only once
++mType;
switch ( mType ) {
@ -2722,10 +2718,10 @@ void TrackPanelCellIterator::UpdateRect()
mRect.x = kLeftMargin;
mRect.width = kTrackInfoWidth - mRect.x;
mRect.y += kTopMargin;
mRect.height =
TrackList::Channels(mpTrack.get())
.sum( &Track::GetHeight );
mRect.height -= (kBottomMargin + kTopMargin);
auto partner = mpTrack->GetLink();
if ( partner && mpTrack->GetLinked() )
mRect.height += partner->GetHeight();
break;
}
case CellType::VRuler:
@ -2741,11 +2737,12 @@ void TrackPanelCellIterator::UpdateRect()
// The resizer region encompasses the bottom margin proper to this
// track, plus the top margin of the next track (or, an equally
// tall zone below, in case there is no next track)
auto partner = mpTrack->GetLink();
if ( partner && mpTrack->GetLinked() )
mRect.x = kTrackInfoWidth;
else
if ( mpTrack.get() ==
*TrackList::Channels(mpTrack.get()).rbegin() )
// Last channel has a resizer extending farther leftward
mRect.x = kLeftMargin;
else
mRect.x = kTrackInfoWidth;
mRect.width -= (mRect.x + kRightMargin);
mRect.y += (mRect.height - kBottomMargin);
mRect.height = (kBottomMargin + kTopMargin);

View File

@ -144,13 +144,9 @@ bool TrackPanelAx::IsFocused( const Track *track )
if (origTrack)
track = origTrack;
if( ( track == focusedTrack.get() ) ||
( focusedTrack && track == focusedTrack->GetLink() ) )
{
return true;
}
return false;
return focusedTrack
? TrackList::Channels(focusedTrack.get()).contains(track)
: !track;
}
int TrackPanelAx::TrackNum( const std::shared_ptr<Track> &target )

View File

@ -143,8 +143,6 @@ UIHandle::Result CutlineHandle::Click
// 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*>(mpTrack->GetLink());
if (event.LeftDown())
{
@ -156,26 +154,30 @@ UIHandle::Result CutlineHandle::Click
// When user presses left button on cut line, expand the line again
double cutlineStart = 0, cutlineEnd = 0;
double *pCutlineStart = &cutlineStart, *pCutlineEnd = &cutlineEnd;
mpTrack->ExpandCutLine(mLocation.pos, &cutlineStart, &cutlineEnd);
if (linked)
// Expand the cutline in the opposite channel if it is present.
linked->ExpandCutLine(mLocation.pos);
for (auto channel :
TrackList::Channels(mpTrack.get())) {
channel->ExpandCutLine(
mLocation.pos, pCutlineStart, pCutlineEnd);
if ( channel == mpTrack.get() )
pCutlineStart = pCutlineEnd = nullptr;
}
viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
result |= UpdateSelection;
}
else if (mLocation.typ == WaveTrackLocation::locationMergePoint) {
const double pos = mLocation.pos;
mpTrack->MergeClips(mLocation.clipidx1, mLocation.clipidx2);
if (linked) {
for (auto channel :
TrackList::Channels(mpTrack.get())) {
// Don't assume correspondence of merge points across channels!
int idx = FindMergeLine(linked, pos);
int idx = FindMergeLine(channel, pos);
if (idx >= 0) {
WaveTrack::Location location = linked->GetCachedLocations()[idx];
linked->MergeClips(location.clipidx1, location.clipidx2);
WaveTrack::Location location =
channel->GetCachedLocations()[idx];
channel->MergeClips(
location.clipidx1, location.clipidx2);
}
}
@ -184,10 +186,10 @@ UIHandle::Result CutlineHandle::Click
}
else if (event.RightDown())
{
bool removed = mpTrack->RemoveCutLine(mLocation.pos);
if (linked)
removed = linked->RemoveCutLine(mLocation.pos) || removed;
bool removed = false;
for (auto channel :
TrackList::Channels(mpTrack.get()))
removed = channel->RemoveCutLine(mLocation.pos) || removed;
if (!removed)
// Nothing happened, make no Undo item

View File

@ -213,14 +213,9 @@ void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
int newWaveColor = id - OnInstrument1ID;
AudacityProject *const project = ::GetActiveProject();
// TrackList *const tracks = project->GetTracks();
pTrack->SetWaveColorIndex(newWaveColor);
// Assume partner is wave or null
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
if (partner)
partner->SetWaveColorIndex(newWaveColor);
for (auto channel : TrackList::Channels(pTrack))
channel->SetWaveColorIndex(newWaveColor);
project->PushState(wxString::Format(_("Changed '%s' to %s"),
pTrack->GetName(),
@ -336,12 +331,9 @@ void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
return; // Nothing to do.
AudacityProject *const project = ::GetActiveProject();
pTrack->ConvertToSampleFormat(newFormat);
// Assume partner is wave or null
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
if (partner)
partner->ConvertToSampleFormat(newFormat);
for (auto channel : TrackList::Channels(pTrack))
channel->ConvertToSampleFormat(newFormat);
/* i18n-hint: The strings name a track and a format */
project->PushState(wxString::Format(_("Changed '%s' to %s"),
@ -439,11 +431,9 @@ int RateMenuTable::IdOfRate(int rate)
void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
{
AudacityProject *const project = ::GetActiveProject();
pTrack->SetRate(rate);
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
if (partner)
partner->SetRate(rate);
for (auto channel : TrackList::Channels(pTrack))
channel->SetRate(rate);
// Separate conversion of "rate" enables changing the decimals without affecting i18n
wxString rateString = wxString::Format(wxT("%.3f"), rate);
/* i18n-hint: The string names a track */
@ -733,22 +723,13 @@ void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
(id == WaveTrack::Waveform &&
pTrack->GetWaveformSettings().isLinear() != linear);
if (wrongType || wrongScale) {
pTrack->SetLastScaleType();
pTrack->SetDisplay(WaveTrack::WaveTrackDisplay(id));
if (wrongScale)
pTrack->GetIndependentWaveformSettings().scaleType = linear
? WaveformSettings::stLinear
: WaveformSettings::stLogarithmic;
// Assume partner is wave or null
auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
if (partner) {
partner->SetLastScaleType();
partner->SetDisplay(WaveTrack::WaveTrackDisplay(id));
for (auto channel : TrackList::Channels(pTrack)) {
channel->SetLastScaleType();
channel->SetDisplay(WaveTrack::WaveTrackDisplay(id));
if (wrongScale)
partner->GetIndependentWaveformSettings().scaleType = linear
? WaveformSettings::stLinear
: WaveformSettings::stLogarithmic;
channel->GetIndependentWaveformSettings().scaleType = linear
? WaveformSettings::stLinear
: WaveformSettings::stLogarithmic;
}
AudacityProject *const project = ::GetActiveProject();

View File

@ -47,12 +47,9 @@ UIHandle::Result GainSliderHandle::SetValue
auto pTrack = GetWaveTrack();
if (pTrack) {
pTrack->SetGain(newValue);
// Assume linked track is wave or null
const auto link = static_cast<WaveTrack*>(mpTrack.lock()->GetLink());
if (link)
link->SetGain(newValue);
for (auto channel :
TrackList::Channels(pTrack.get()))
channel->SetGain(newValue);
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
if (pMixerBoard)
@ -131,12 +128,9 @@ UIHandle::Result PanSliderHandle::SetValue(AudacityProject *pProject, float newV
auto pTrack = GetWaveTrack();
if (pTrack) {
pTrack->SetPan(newValue);
// Assume linked track is wave or null
const auto link = static_cast<WaveTrack*>(pTrack->GetLink());
if (link)
link->SetPan(newValue);
for (auto channel :
TrackList::Channels(pTrack.get()))
channel->SetPan(newValue);
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
if (pMixerBoard)

View File

@ -58,13 +58,12 @@ void WaveTrackVRulerControls::DoZoomPreset( int i)
const auto wt = static_cast<WaveTrack*>(pTrack.get());
// Don't pass the partner, that causes problems when updating display
// Don't do all channels, that causes problems when updating display
// during recording and there are special pending tracks.
// This function implements WaveTrack::DoSetMinimized which is always
// called in a context that loops over linked tracks too and reinvokes.
auto partner = nullptr;
WaveTrackVZoomHandle::DoZoom(
NULL, wt, partner, (i==1)?kZoomHalfWave: kZoom1to1,
NULL, wt, false, (i==1)?kZoomHalfWave: kZoom1to1,
wxRect(0,0,0,0), 0,0, true);
}
@ -88,9 +87,7 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
wxASSERT(pTrack->GetKind() == Track::Wave);
auto steps = evt.steps;
const auto wt = static_cast<WaveTrack*>(pTrack.get());
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
WaveTrack *const wt = static_cast<WaveTrack*>(pTrack.get());
const bool isDB =
wt->GetDisplay() == WaveTrack::Waveform &&
wt->GetWaveformSettings().scaleType == WaveformSettings::stLogarithmic;
@ -102,24 +99,20 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
if (!(min < 0.0 && max > 0.0))
return RefreshNone;
WaveformSettings &settings = wt->GetIndependentWaveformSettings();
WaveformSettings &settings =
wt->GetIndependentWaveformSettings();
float olddBRange = settings.dBRange;
if (steps < 0)
// Zoom out
settings.NextLowerDBRange();
else
settings.NextHigherDBRange();
float newdBRange = settings.dBRange;
if (partner) {
WaveformSettings &settings = partner->GetIndependentWaveformSettings();
for (auto channel : TrackList::Channels(wt)) {
WaveformSettings &channelSettings =
channel->GetIndependentWaveformSettings();
if (steps < 0)
// Zoom out
settings.NextLowerDBRange();
channelSettings.NextLowerDBRange();
else
settings.NextHigherDBRange();
channelSettings.NextHigherDBRange();
}
float newdBRange = settings.dBRange;
// Is y coordinate within the rectangle half-height centered about
// the zero level?
@ -135,19 +128,16 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
const float extreme = (LINEAR_TO_DB(2) + newdBRange) / newdBRange;
max = std::min(extreme, max * olddBRange / newdBRange);
min = std::max(-extreme, min * olddBRange / newdBRange);
wt->SetLastdBRange();
wt->SetDisplayBounds(min, max);
if (partner) {
partner->SetLastdBRange();
partner->SetDisplayBounds(min, max);
for (auto channel : TrackList::Channels(wt)) {
channel->SetLastdBRange();
channel->SetDisplayBounds(min, max);
}
}
}
else if (event.CmdDown() && !event.ShiftDown()) {
const int yy = event.m_y;
const auto partner = static_cast<WaveTrack *>(wt);
WaveTrackVZoomHandle::DoZoom(
pProject, wt, partner, (steps < 0)?kZoomOut:kZoomIn,
pProject, wt, true, (steps < 0)?kZoomOut:kZoomIn,
evt.rect, yy, yy, true);
}
else if (!event.CmdDown() && event.ShiftDown()) {
@ -173,9 +163,8 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
std::min(bound,
numberScale.PositionToValue(numberScale.ValueToPosition(newBottom) + 1.0f));
wt->SetSpectrumBounds(newBottom, newTop);
if (partner)
partner->SetSpectrumBounds(newBottom, newTop);
for (auto channel : TrackList::Channels(wt))
channel->SetSpectrumBounds(newBottom, newTop);
}
else {
float topLimit = 2.0;
@ -191,9 +180,8 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
float newTop = std::min(topLimit, top + delta);
const float newBottom = std::max(bottomLimit, newTop - range);
newTop = std::min(topLimit, newBottom + range);
wt->SetDisplayBounds(newBottom, newTop);
if (partner)
partner->SetDisplayBounds(newBottom, newTop);
for (auto channel : TrackList::Channels(wt))
channel->SetDisplayBounds(newBottom, newTop);
}
}
else

View File

@ -65,11 +65,12 @@ void WaveTrackVZoomHandle::Enter(bool)
// the zoomKind and cause a drag-zoom-in.
void WaveTrackVZoomHandle::DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, WaveTrack *partner, int ZoomKind,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint)
{
static const float ZOOMLIMIT = 0.001f;
int height = rect.height;
int ypos = rect.y;
@ -318,15 +319,13 @@ void WaveTrackVZoomHandle::DoZoom
}
// Now actually apply the zoom.
if (spectral) {
pTrack->SetSpectrumBounds(min, max);
if (partner)
partner->SetSpectrumBounds(min, max);
}
else {
pTrack->SetDisplayBounds(min, max);
if (partner)
partner->SetDisplayBounds(min, max);
for (auto channel : TrackList::Channels(pTrack)) {
if (!allChannels && channel != pTrack)
continue;
if (spectral)
channel->SetSpectrumBounds(min, max);
else
channel->SetDisplayBounds(min, max);
}
zoomEnd = zoomStart = 0;
@ -389,10 +388,8 @@ void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData)
void WaveTrackVRulerMenuTable::OnZoom( int iZoomCode )
{
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack *>(mpData->pTrack->GetLink());
WaveTrackVZoomHandle::DoZoom
(::GetActiveProject(), mpData->pTrack, partner,
(::GetActiveProject(), mpData->pTrack, true,
iZoomCode, mpData->rect, mpData->yy, mpData->yy, false);
using namespace RefreshCode;
@ -467,17 +464,17 @@ void WaveformVRulerMenuTable::OnWaveformScaleType(wxCommandEvent &evt)
{
WaveTrack *const wt = mpData->pTrack;
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
const WaveformSettings::ScaleType newScaleType =
WaveformSettings::ScaleType(
std::max(0,
std::min((int)(WaveformSettings::stNumScaleTypes) - 1,
evt.GetId() - OnFirstWaveformScaleID
)));
if (wt->GetWaveformSettings().scaleType != newScaleType) {
wt->GetIndependentWaveformSettings().scaleType = newScaleType;
if (partner)
partner->GetIndependentWaveformSettings().scaleType = newScaleType;
for (auto channel : TrackList::Channels(wt)) {
channel->GetIndependentWaveformSettings().scaleType = newScaleType;
}
::GetActiveProject()->ModifyState(true);
@ -540,8 +537,7 @@ END_POPUP_MENU()
void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
{
WaveTrack *const wt = mpData->pTrack;
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
const SpectrogramSettings::ScaleType newScaleType =
SpectrogramSettings::ScaleType(
std::max(0,
@ -549,9 +545,8 @@ void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
evt.GetId() - OnFirstSpectrumScaleID
)));
if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
wt->GetIndependentSpectrogramSettings().scaleType = newScaleType;
if (partner)
partner->GetIndependentSpectrogramSettings().scaleType = newScaleType;
for (auto channel : TrackList::Channels(wt))
channel->GetIndependentSpectrogramSettings().scaleType = newScaleType;
::GetActiveProject()->ModifyState(true);
@ -678,8 +673,7 @@ UIHandle::Result WaveTrackVZoomHandle::Release
if( bVZoom ){
if( shiftDown )
mZoomStart=mZoomEnd;
const auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
DoZoom(pProject, pTrack.get(), partner,
DoZoom(pProject, pTrack.get(), true,
shiftDown ? (rightUp ? kZoom1to1 : kZoomOut) : kZoomIn,
mRect, mZoomStart, mZoomEnd, !shiftDown);
}

View File

@ -42,7 +42,7 @@ public:
static void DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, WaveTrack *partner, int ZoomKind,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint);

View File

@ -178,6 +178,8 @@ UIHandle::Result EnvelopeHandle::Click
const ViewInfo &viewInfo = pProject->GetViewInfo();
const auto pTrack = static_cast<Track*>(evt.pCell.get());
mEnvelopeEditors.clear();
unsigned result = Cancelled;
if (pTrack)
result = pTrack->TypeSwitch< decltype(RefreshNone) >(
@ -191,18 +193,21 @@ UIHandle::Result EnvelopeHandle::Click
mLog = !wt->GetWaveformSettings().isLinear();
wt->GetDisplayBounds(&mLower, &mUpper);
mdBRange = wt->GetWaveformSettings().dBRange;
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *mEnvelope, true );
mEnvelopeEditorRight.reset();
// Assume linked track is wave or null
auto partner = static_cast<WaveTrack*>(wt->GetLink());
if (partner)
{
auto clickedEnvelope = partner->GetEnvelopeAtX(event.GetX());
if (clickedEnvelope)
mEnvelopeEditorRight =
std::make_unique< EnvelopeEditor >( *clickedEnvelope, true );
auto channels = TrackList::Channels( wt );
for ( auto channel : channels ) {
if (channel == wt)
mEnvelopeEditors.push_back(
std::make_unique< EnvelopeEditor >( *mEnvelope, true ) );
else {
auto e2 = channel->GetEnvelopeAtX(event.GetX());
if (e2)
mEnvelopeEditors.push_back(
std::make_unique< EnvelopeEditor >( *e2, true ) );
else {
// There isn't necessarily an envelope there; no guarantee a
// linked track has the same WaveClip structure...
}
}
}
return RefreshNone;
@ -211,9 +216,9 @@ UIHandle::Result EnvelopeHandle::Click
if (!mEnvelope)
return Cancelled;
GetTimeTrackData( *pProject, *tt, mdBRange, mLog, mLower, mUpper);
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *mEnvelope, false );
mEnvelopeEditorRight.reset();
mEnvelopeEditors.push_back(
std::make_unique< EnvelopeEditor >( *mEnvelope, false )
);
return RefreshNone;
},
@ -289,8 +294,7 @@ UIHandle::Result EnvelopeHandle::Release
_("Envelope")
);
mEnvelopeEditor.reset();
mEnvelopeEditorRight.reset();
mEnvelopeEditors.clear();
using namespace RefreshCode;
return needUpdate ? RefreshCell : RefreshNone;
@ -299,8 +303,7 @@ UIHandle::Result EnvelopeHandle::Release
UIHandle::Result EnvelopeHandle::Cancel(AudacityProject *pProject)
{
pProject->RollbackState();
mEnvelopeEditor.reset();
mEnvelopeEditorRight.reset();
mEnvelopeEditors.clear();
return RefreshCode::RefreshCell;
}
@ -313,14 +316,13 @@ bool EnvelopeHandle::ForwardEventToEnvelopes
// AS: I'm not sure why we can't let the Envelope take care of
// redrawing itself. ?
bool needUpdate =
mEnvelopeEditor->MouseEvent(
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper);
if (mEnvelopeEditorRight)
needUpdate |=
mEnvelopeEditorRight->MouseEvent(
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper);
bool needUpdate = false;
for (const auto &pEditor : mEnvelopeEditors) {
needUpdate =
pEditor->MouseEvent(
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper)
|| needUpdate;
}
return needUpdate;
}

View File

@ -14,6 +14,8 @@ Paul Licameli split from TrackPanel.cpp
#include "../../UIHandle.h"
#include "../../MemoryX.h"
#include <vector>
class wxMouseEvent;
class wxMouseState;
#include <wx/gdicmn.h>
@ -85,8 +87,7 @@ private:
double mdBRange{};
Envelope *mEnvelope{};
std::unique_ptr<EnvelopeEditor> mEnvelopeEditor;
std::unique_ptr<EnvelopeEditor> mEnvelopeEditorRight;
std::vector< std::unique_ptr<EnvelopeEditor> > mEnvelopeEditors;
bool mTimeTrack{};
};

View File

@ -152,6 +152,21 @@ namespace
AddClipsToCaptured( state, t, t->GetStartTime(), t->GetEndTime() );
}
WaveTrack *NthChannel(WaveTrack &leader, int nn)
{
if (nn < 0)
return nullptr;
return *TrackList::Channels( &leader ).begin().advance(nn);
}
int ChannelPosition(const Track *pChannel)
{
return static_cast<int>(
TrackList::Channels( pChannel )
.EndingAfter( pChannel ).size()
) - 1;
}
// Don't count right channels.
WaveTrack *NthAudioTrack(TrackList &list, int nn)
{
@ -206,15 +221,10 @@ namespace
clip.track->Offset( offset );
}
}
else if ( pTrack ) {
else if ( pTrack )
// Was a shift-click
for (auto channel =
pTrack->GetLink() && !pTrack->GetLinked()
? pTrack->GetLink() : pTrack;
channel;
channel = channel->GetLinked() ? channel->GetLink() : nullptr)
for (auto channel : TrackList::Channels( pTrack ))
channel->Offset( offset );
}
}
}
@ -236,16 +246,12 @@ void TimeShiftHandle::CreateListOfCapturedClips
state.capturedClipArray.push_back
(TrackClip( &capturedTrack, state.capturedClip ));
// Check for stereo partner
Track *partner = capturedTrack.GetLink();
WaveTrack *wt;
if (state.capturedClip &&
// Assume linked track is wave or null
nullptr != (wt = static_cast<WaveTrack*>(partner))) {
WaveClip *const clip = FindClipAtTime(wt, clickTime);
if (clip)
state.capturedClipArray.push_back(TrackClip(partner, clip));
if (state.capturedClip) {
// Check for other channels
auto wt = static_cast<WaveTrack*>(&capturedTrack);
for ( auto channel : TrackList::Channels( wt ).Excluding( wt ) )
if (WaveClip *const clip = FindClipAtTime(channel, clickTime))
state.capturedClipArray.push_back(TrackClip(channel, clip));
}
}
@ -493,22 +499,28 @@ namespace {
for ( auto &trackClip : state.capturedClipArray ) {
if (trackClip.clip) {
// Move all clips up or down by an equal count of audio tracks.
// Can only move between tracks with equal numbers of channels,
// and among corresponding channels.
Track *const pSrcTrack = trackClip.track;
auto pDstTrack = NthAudioTrack(trackList,
diff + TrackPosition(trackList, pSrcTrack));
// Can only move mono to mono, or left to left, or right to right
// And that must be so for each captured clip
bool stereo = (pSrcTrack->GetLink() != 0);
if (pDstTrack && stereo && !pSrcTrack->GetLinked())
// Assume linked track is wave or null
pDstTrack = static_cast<WaveTrack*>(pDstTrack->GetLink());
bool ok = pDstTrack &&
(stereo == (pDstTrack->GetLink() != 0)) &&
(!stereo || (pSrcTrack->GetLinked() == pDstTrack->GetLinked()));
if (ok)
trackClip.dstTrack = pDstTrack;
else
if (!pDstTrack)
return false;
if (TrackList::Channels(pSrcTrack).size() !=
TrackList::Channels(pDstTrack).size())
return false;
auto pDstChannel = NthChannel(
*pDstTrack, ChannelPosition(pSrcTrack));
if (!pDstChannel) {
wxASSERT(false);
return false;
}
trackClip.dstTrack = pDstChannel;
}
}
return true;

View File

@ -34,9 +34,9 @@ UIHandle::Result MinimizeButtonHandle::CommitChanges
auto pTrack = mpTrack.lock();
if (pTrack)
{
pTrack->SetMinimized(!pTrack->GetMinimized());
if (pTrack->GetLink())
pTrack->GetLink()->SetMinimized(pTrack->GetMinimized());
bool wasMinimized = pTrack->GetMinimized();
for (auto channel : TrackList::Channels(pTrack.get()))
channel->SetMinimized(!wasMinimized);
pProject->ModifyState(true);
// Redraw all tracks when any one of them expands or contracts

View File

@ -209,11 +209,8 @@ void TrackMenuTable::OnSetName(wxCommandEvent &)
if (bResult)
{
wxString newName = Command.mName;
pTrack->SetName(newName);
// if we have a linked channel this name should change as well
// (otherwise sort by name and time will crash).
if (pTrack->GetLinked())
pTrack->GetLink()->SetName(newName);
for (auto channel : TrackList::Channels(pTrack))
channel->SetName(newName);
MixerBoard *const pMixerBoard = proj->GetMixerBoard();
auto pt = dynamic_cast<PlayableTrack*>(pTrack);