mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-21 14:50:06 +02:00
More rewrites of iterations over channels...
... that can generalize to more than stereo
This commit is contained in:
commit
3561154311
@ -2051,25 +2051,6 @@ void AudacityProject::FixScrollbars()
|
|||||||
GetTrackPanel()->HandleCursorForPresentMouseState(); } );
|
GetTrackPanel()->HandleCursorForPresentMouseState(); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Track> AudacityProject::GetFirstVisible()
|
|
||||||
{
|
|
||||||
std::shared_ptr<Track> pTrack;
|
|
||||||
if (GetTracks()) {
|
|
||||||
TrackListIterator iter(GetTracks());
|
|
||||||
for (Track *t = iter.First(); t; t = iter.Next()) {
|
|
||||||
int y = t->GetY();
|
|
||||||
int h = t->GetHeight();
|
|
||||||
if (y + h - 1 >= mViewInfo.vpos) {
|
|
||||||
// At least the bottom row of pixels is not scrolled away above
|
|
||||||
pTrack = Track::Pointer(t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudacityProject::UpdateLayout()
|
void AudacityProject::UpdateLayout()
|
||||||
{
|
{
|
||||||
if (!mTrackPanel)
|
if (!mTrackPanel)
|
||||||
@ -4232,23 +4213,35 @@ AudacityProject::AddImportedTracks(const wxString &fileName,
|
|||||||
bool initiallyEmpty = mTracks->empty();
|
bool initiallyEmpty = mTracks->empty();
|
||||||
double newRate = 0;
|
double newRate = 0;
|
||||||
wxString trackNameBase = fileName.AfterLast(wxFILE_SEP_PATH).BeforeLast('.');
|
wxString trackNameBase = fileName.AfterLast(wxFILE_SEP_PATH).BeforeLast('.');
|
||||||
bool isLinked = false;
|
|
||||||
int i = -1;
|
int i = -1;
|
||||||
for (auto &uNewTrack : newTracks) {
|
|
||||||
++i;
|
|
||||||
|
|
||||||
|
// Must add all tracks first (before using Track::IsLeader)
|
||||||
|
for (auto &uNewTrack : newTracks) {
|
||||||
auto newTrack = mTracks->Add(std::move(uNewTrack));
|
auto newTrack = mTracks->Add(std::move(uNewTrack));
|
||||||
results.push_back(Track::Pointer(newTrack));
|
results.push_back(Track::Pointer(newTrack));
|
||||||
|
}
|
||||||
|
newTracks.clear();
|
||||||
|
|
||||||
|
// Now name them
|
||||||
|
|
||||||
|
// Add numbers to track names only if there is more than one (mono or stereo)
|
||||||
|
// track (not necessarily, more than one channel)
|
||||||
|
const bool useSuffix =
|
||||||
|
make_iterator_range( results.begin() + 1, results.end() )
|
||||||
|
.any_of( []( decltype(*results.begin()) &pTrack )
|
||||||
|
{ return pTrack->IsLeader(); } );
|
||||||
|
|
||||||
|
for (const auto &newTrack : results) {
|
||||||
|
if ( newTrack->IsLeader() )
|
||||||
|
// Count groups only
|
||||||
|
++i;
|
||||||
|
|
||||||
newTrack->SetSelected(true);
|
newTrack->SetSelected(true);
|
||||||
//we need to check link status based on the first channel only.
|
|
||||||
if(0==i)
|
if ( useSuffix )
|
||||||
isLinked = newTrack->GetLinked();
|
|
||||||
if (numTracks > 2 || (numTracks > 1 && !isLinked) ) {
|
|
||||||
newTrack->SetName(trackNameBase + wxString::Format(wxT(" %d" ), i + 1));
|
newTrack->SetName(trackNameBase + wxString::Format(wxT(" %d" ), i + 1));
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
newTrack->SetName(trackNameBase);
|
newTrack->SetName(trackNameBase);
|
||||||
}
|
|
||||||
|
|
||||||
newTrack->TypeSwitch( [&](WaveTrack *wt) {
|
newTrack->TypeSwitch( [&](WaveTrack *wt) {
|
||||||
if (newRate == 0)
|
if (newRate == 0)
|
||||||
@ -4299,8 +4292,6 @@ AudacityProject::AddImportedTracks(const wxString &fileName,
|
|||||||
// Moved this call to higher levels to prevent flicker redrawing everything on each file.
|
// Moved this call to higher levels to prevent flicker redrawing everything on each file.
|
||||||
// HandleResize();
|
// HandleResize();
|
||||||
|
|
||||||
newTracks.clear();
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,8 +213,6 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame,
|
|||||||
const ViewInfo &GetViewInfo() const { return mViewInfo; }
|
const ViewInfo &GetViewInfo() const { return mViewInfo; }
|
||||||
ViewInfo &GetViewInfo() { return mViewInfo; }
|
ViewInfo &GetViewInfo() { return mViewInfo; }
|
||||||
|
|
||||||
std::shared_ptr<Track> GetFirstVisible();
|
|
||||||
|
|
||||||
void GetPlayRegion(double* playRegionStart, double *playRegionEnd);
|
void GetPlayRegion(double* playRegionStart, double *playRegionEnd);
|
||||||
bool IsPlayRegionLocked() { return mLockPlayRegion; }
|
bool IsPlayRegionLocked() { return mLockPlayRegion; }
|
||||||
void SetPlayRegionLocked(bool value) { mLockPlayRegion = value; }
|
void SetPlayRegionLocked(bool value) { mLockPlayRegion = value; }
|
||||||
|
@ -341,7 +341,6 @@ void TrackArtist::SetMargins(int left, int top, int right, int bottom)
|
|||||||
|
|
||||||
void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
||||||
const TrackList * tracks,
|
const TrackList * tracks,
|
||||||
Track * start,
|
|
||||||
const wxRegion & reg,
|
const wxRegion & reg,
|
||||||
const wxRect & rect,
|
const wxRect & rect,
|
||||||
const wxRect & clip,
|
const wxRect & clip,
|
||||||
@ -351,13 +350,11 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
|||||||
bool bigPoints,
|
bool bigPoints,
|
||||||
bool drawSliders)
|
bool drawSliders)
|
||||||
{
|
{
|
||||||
|
// Copy the horizontal extent of rect; will later change only the vertical.
|
||||||
wxRect trackRect = rect;
|
wxRect trackRect = rect;
|
||||||
wxRect stereoTrackRect;
|
|
||||||
TrackListConstIterator iter(tracks);
|
|
||||||
const Track *t;
|
|
||||||
|
|
||||||
bool hasSolo = false;
|
bool hasSolo = false;
|
||||||
for (t = iter.First(); t; t = iter.Next()) {
|
for (const Track *t : *tracks) {
|
||||||
t = t->SubstitutePendingChangedTrack().get();
|
t = t->SubstitutePendingChangedTrack().get();
|
||||||
auto pt = dynamic_cast<const PlayableTrack *>(t);
|
auto pt = dynamic_cast<const PlayableTrack *>(t);
|
||||||
if (pt && pt->GetSolo()) {
|
if (pt && pt->GetSolo()) {
|
||||||
@ -381,15 +378,23 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
|||||||
|
|
||||||
gPrefs->Read(wxT("/GUI/ShowTrackNameInWaveform"), &mbShowTrackNameInWaveform, false);
|
gPrefs->Read(wxT("/GUI/ShowTrackNameInWaveform"), &mbShowTrackNameInWaveform, false);
|
||||||
|
|
||||||
t = iter.StartWith(start);
|
for(auto leader : tracks->Leaders()) {
|
||||||
while (t) {
|
auto group = TrackList::Channels( leader );
|
||||||
t = t->SubstitutePendingChangedTrack().get();
|
leader = leader->SubstitutePendingChangedTrack().get();
|
||||||
trackRect.y = t->GetY() - zoomInfo.vpos;
|
|
||||||
trackRect.height = t->GetHeight();
|
|
||||||
|
|
||||||
if (trackRect.y > clip.GetBottom() && !t->GetLinked()) {
|
trackRect.y = leader->GetY() - zoomInfo.vpos;
|
||||||
|
trackRect.height = group.sum( [&] (const Track *channel) {
|
||||||
|
channel = channel->SubstitutePendingChangedTrack().get();
|
||||||
|
return channel->GetHeight();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (trackRect.GetBottom() < clip.GetTop())
|
||||||
|
continue;
|
||||||
|
else if (trackRect.GetTop() > clip.GetBottom())
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
for (auto t : group) {
|
||||||
|
t = t->SubstitutePendingChangedTrack().get();
|
||||||
|
|
||||||
#if defined(DEBUG_CLIENT_AREA)
|
#if defined(DEBUG_CLIENT_AREA)
|
||||||
// Filled rectangle to show the interior of the client area
|
// Filled rectangle to show the interior of the client area
|
||||||
@ -400,8 +405,6 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
|||||||
dc.DrawRectangle(zr);
|
dc.DrawRectangle(zr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stereoTrackRect = trackRect;
|
|
||||||
|
|
||||||
// For various reasons, the code will break if we display one
|
// For various reasons, the code will break if we display one
|
||||||
// of a stereo pair of tracks but not the other - for example,
|
// of a stereo pair of tracks but not the other - for example,
|
||||||
// if you try to edit the envelope of one track when its linked
|
// if you try to edit the envelope of one track when its linked
|
||||||
@ -410,20 +413,7 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
|||||||
// its linked partner, and see if any part of that rect is on-screen.
|
// its linked partner, and see if any part of that rect is on-screen.
|
||||||
// If so, we draw both. Otherwise, we can safely draw neither.
|
// If so, we draw both. Otherwise, we can safely draw neither.
|
||||||
|
|
||||||
Track *link = t->GetLink();
|
if (trackRect.Intersects(clip) && reg.Contains(trackRect)) {
|
||||||
if (link) {
|
|
||||||
if (t->GetLinked()) {
|
|
||||||
// If we're the first track
|
|
||||||
stereoTrackRect.height += link->GetHeight();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We're the second of two
|
|
||||||
stereoTrackRect.y -= link->GetHeight();
|
|
||||||
stereoTrackRect.height += link->GetHeight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stereoTrackRect.Intersects(clip) && reg.Contains(stereoTrackRect)) {
|
|
||||||
wxRect rr = trackRect;
|
wxRect rr = trackRect;
|
||||||
rr.x += mMarginLeft;
|
rr.x += mMarginLeft;
|
||||||
rr.y += mMarginTop;
|
rr.y += mMarginTop;
|
||||||
@ -433,8 +423,7 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
|
|||||||
selectedRegion, zoomInfo,
|
selectedRegion, zoomInfo,
|
||||||
drawEnvelope, bigPoints, drawSliders, hasSolo);
|
drawEnvelope, bigPoints, drawSliders, hasSolo);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
t = iter.Next();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,8 +469,7 @@ void TrackArtist::DrawTrack(TrackPanelDrawingContext &context,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mbShowTrackNameInWaveform &&
|
if (mbShowTrackNameInWaveform &&
|
||||||
// Exclude right channel of stereo track
|
wt->IsLeader() &&
|
||||||
!(!wt->GetLinked() && wt->GetLink()) &&
|
|
||||||
// Exclude empty name.
|
// Exclude empty name.
|
||||||
!wt->GetName().IsEmpty()) {
|
!wt->GetName().IsEmpty()) {
|
||||||
wxBrush Brush;
|
wxBrush Brush;
|
||||||
|
@ -55,7 +55,7 @@ class AUDACITY_DLL_API TrackArtist {
|
|||||||
|
|
||||||
void SetColours(int iColorIndex);
|
void SetColours(int iColorIndex);
|
||||||
void DrawTracks(TrackPanelDrawingContext &context,
|
void DrawTracks(TrackPanelDrawingContext &context,
|
||||||
const TrackList *tracks, Track *start,
|
const TrackList *tracks,
|
||||||
const wxRegion & reg,
|
const wxRegion & reg,
|
||||||
const wxRect & rect, const wxRect & clip,
|
const wxRect & rect, const wxRect & clip,
|
||||||
const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo,
|
const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo,
|
||||||
|
@ -1156,8 +1156,7 @@ void TrackPanel::DrawTracks(wxDC * dc)
|
|||||||
TrackPanelDrawingContext context{ *dc, Target(), mLastMouseState };
|
TrackPanelDrawingContext context{ *dc, Target(), mLastMouseState };
|
||||||
|
|
||||||
// The track artist actually draws the stuff inside each track
|
// The track artist actually draws the stuff inside each track
|
||||||
auto first = GetProject()->GetFirstVisible();
|
mTrackArtist->DrawTracks(context, GetTracks(),
|
||||||
mTrackArtist->DrawTracks(context, GetTracks(), first.get(),
|
|
||||||
region, tracksRect, clip,
|
region, tracksRect, clip,
|
||||||
mViewInfo->selectedRegion, *mViewInfo,
|
mViewInfo->selectedRegion, *mViewInfo,
|
||||||
envelopeFlag, bigPointsFlag, sliderFlag);
|
envelopeFlag, bigPointsFlag, sliderFlag);
|
||||||
@ -1847,14 +1846,12 @@ void TrackPanel::UpdateTrackVRuler(const Track *t)
|
|||||||
wxRect rect(GetVRulerOffset(),
|
wxRect rect(GetVRulerOffset(),
|
||||||
kTopMargin,
|
kTopMargin,
|
||||||
GetVRulerWidth(),
|
GetVRulerWidth(),
|
||||||
t->GetHeight() - (kTopMargin + kBottomMargin));
|
0);
|
||||||
|
|
||||||
mTrackArtist->UpdateVRuler(t, rect);
|
|
||||||
const Track *l = t->GetLink();
|
for (auto channel : TrackList::Channels(t)) {
|
||||||
if (l)
|
rect.height = channel->GetHeight() - (kTopMargin + kBottomMargin);
|
||||||
{
|
mTrackArtist->UpdateVRuler(channel, rect);
|
||||||
rect.height = l->GetHeight() - (kTopMargin + kBottomMargin);
|
|
||||||
mTrackArtist->UpdateVRuler(l, rect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2080,30 +2077,29 @@ wxRect TrackPanel::FindTrackRect( const Track * target, bool label )
|
|||||||
return { 0, 0, 0, 0 };
|
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
|
// 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
|
// 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
|
// real problem referred to, was that this function could be reached, via
|
||||||
// TrackPanelAx callbacks, during low-level operations while the TrackList
|
// TrackPanelAx callbacks, during low-level operations while the TrackList
|
||||||
// was not in a consistent state. Therefore GetLinked() did not imply
|
// was not in a consistent state.
|
||||||
// that GetLink() was not null.
|
|
||||||
// Now the problem is fixed by delaying the handling of events generated
|
// 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:
|
// Old comment:
|
||||||
// The check for a null linked track is necessary because there's
|
// The check for a null linked track is necessary because there's
|
||||||
// a possible race condition between the time the 2 linked tracks
|
// a possible race condition between the time the 2 linked tracks
|
||||||
// are added and when wxAccessible methods are called. This is
|
// are added and when wxAccessible methods are called. This is
|
||||||
// most evident when using Jaws.
|
// most evident when using Jaws.
|
||||||
if (target->GetLinked() && target->GetLink()) {
|
auto height = TrackList::Channels( target ).sum( &Track::GetHeight );
|
||||||
rect.height += target->GetLink()->GetHeight();
|
|
||||||
}
|
wxRect rect{
|
||||||
|
0,
|
||||||
|
target->GetY() - mViewInfo->vpos,
|
||||||
|
GetSize().GetWidth(),
|
||||||
|
height
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
rect.x += kLeftMargin;
|
rect.x += kLeftMargin;
|
||||||
if (label)
|
if (label)
|
||||||
@ -2151,8 +2147,7 @@ void TrackPanel::SetFocusedCell()
|
|||||||
void TrackPanel::SetFocusedTrack( Track *t )
|
void TrackPanel::SetFocusedTrack( Track *t )
|
||||||
{
|
{
|
||||||
// Make sure we always have the first linked track of a stereo track
|
// Make sure we always have the first linked track of a stereo track
|
||||||
if (t && !t->GetLinked() && t->GetLink())
|
t = *GetTracks()->FindLeader(t);
|
||||||
t = (WaveTrack*)t->GetLink();
|
|
||||||
|
|
||||||
auto cell = mAx->SetFocus( Track::Pointer( t ) ).get();
|
auto cell = mAx->SetFocus( Track::Pointer( t ) ).get();
|
||||||
|
|
||||||
@ -2657,7 +2652,7 @@ TrackPanelCellIterator &TrackPanelCellIterator::operator++ ()
|
|||||||
}
|
}
|
||||||
if ( mpTrack ) {
|
if ( mpTrack ) {
|
||||||
if ( mType == CellType::Label &&
|
if ( mType == CellType::Label &&
|
||||||
mpTrack->GetLink() && !mpTrack->GetLinked() )
|
!mpTrack->IsLeader() )
|
||||||
// Visit label of stereo track only once
|
// Visit label of stereo track only once
|
||||||
++mType;
|
++mType;
|
||||||
switch ( mType ) {
|
switch ( mType ) {
|
||||||
@ -2723,10 +2718,10 @@ void TrackPanelCellIterator::UpdateRect()
|
|||||||
mRect.x = kLeftMargin;
|
mRect.x = kLeftMargin;
|
||||||
mRect.width = kTrackInfoWidth - mRect.x;
|
mRect.width = kTrackInfoWidth - mRect.x;
|
||||||
mRect.y += kTopMargin;
|
mRect.y += kTopMargin;
|
||||||
|
mRect.height =
|
||||||
|
TrackList::Channels(mpTrack.get())
|
||||||
|
.sum( &Track::GetHeight );
|
||||||
mRect.height -= (kBottomMargin + kTopMargin);
|
mRect.height -= (kBottomMargin + kTopMargin);
|
||||||
auto partner = mpTrack->GetLink();
|
|
||||||
if ( partner && mpTrack->GetLinked() )
|
|
||||||
mRect.height += partner->GetHeight();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CellType::VRuler:
|
case CellType::VRuler:
|
||||||
@ -2742,11 +2737,12 @@ void TrackPanelCellIterator::UpdateRect()
|
|||||||
// The resizer region encompasses the bottom margin proper to this
|
// The resizer region encompasses the bottom margin proper to this
|
||||||
// track, plus the top margin of the next track (or, an equally
|
// track, plus the top margin of the next track (or, an equally
|
||||||
// tall zone below, in case there is no next track)
|
// tall zone below, in case there is no next track)
|
||||||
auto partner = mpTrack->GetLink();
|
if ( mpTrack.get() ==
|
||||||
if ( partner && mpTrack->GetLinked() )
|
*TrackList::Channels(mpTrack.get()).rbegin() )
|
||||||
mRect.x = kTrackInfoWidth;
|
// Last channel has a resizer extending farther leftward
|
||||||
else
|
|
||||||
mRect.x = kLeftMargin;
|
mRect.x = kLeftMargin;
|
||||||
|
else
|
||||||
|
mRect.x = kTrackInfoWidth;
|
||||||
mRect.width -= (mRect.x + kRightMargin);
|
mRect.width -= (mRect.x + kRightMargin);
|
||||||
mRect.y += (mRect.height - kBottomMargin);
|
mRect.y += (mRect.height - kBottomMargin);
|
||||||
mRect.height = (kBottomMargin + kTopMargin);
|
mRect.height = (kBottomMargin + kTopMargin);
|
||||||
|
@ -144,13 +144,9 @@ bool TrackPanelAx::IsFocused( const Track *track )
|
|||||||
if (origTrack)
|
if (origTrack)
|
||||||
track = origTrack;
|
track = origTrack;
|
||||||
|
|
||||||
if( ( track == focusedTrack.get() ) ||
|
return focusedTrack
|
||||||
( focusedTrack && track == focusedTrack->GetLink() ) )
|
? TrackList::Channels(focusedTrack.get()).contains(track)
|
||||||
{
|
: !track;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int TrackPanelAx::TrackNum( const std::shared_ptr<Track> &target )
|
int TrackPanelAx::TrackNum( const std::shared_ptr<Track> &target )
|
||||||
|
@ -143,8 +143,6 @@ UIHandle::Result CutlineHandle::Click
|
|||||||
|
|
||||||
// Cutline data changed on either branch, so refresh the track display.
|
// Cutline data changed on either branch, so refresh the track display.
|
||||||
UIHandle::Result result = RefreshCell;
|
UIHandle::Result result = RefreshCell;
|
||||||
// Assume linked track is wave or null
|
|
||||||
const auto linked = static_cast<WaveTrack*>(mpTrack->GetLink());
|
|
||||||
|
|
||||||
if (event.LeftDown())
|
if (event.LeftDown())
|
||||||
{
|
{
|
||||||
@ -156,26 +154,30 @@ UIHandle::Result CutlineHandle::Click
|
|||||||
|
|
||||||
// When user presses left button on cut line, expand the line again
|
// When user presses left button on cut line, expand the line again
|
||||||
double cutlineStart = 0, cutlineEnd = 0;
|
double cutlineStart = 0, cutlineEnd = 0;
|
||||||
|
double *pCutlineStart = &cutlineStart, *pCutlineEnd = &cutlineEnd;
|
||||||
|
|
||||||
mpTrack->ExpandCutLine(mLocation.pos, &cutlineStart, &cutlineEnd);
|
for (auto channel :
|
||||||
|
TrackList::Channels(mpTrack.get())) {
|
||||||
if (linked)
|
channel->ExpandCutLine(
|
||||||
// Expand the cutline in the opposite channel if it is present.
|
mLocation.pos, pCutlineStart, pCutlineEnd);
|
||||||
linked->ExpandCutLine(mLocation.pos);
|
if ( channel == mpTrack.get() )
|
||||||
|
pCutlineStart = pCutlineEnd = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
|
viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
|
||||||
result |= UpdateSelection;
|
result |= UpdateSelection;
|
||||||
}
|
}
|
||||||
else if (mLocation.typ == WaveTrackLocation::locationMergePoint) {
|
else if (mLocation.typ == WaveTrackLocation::locationMergePoint) {
|
||||||
const double pos = mLocation.pos;
|
const double pos = mLocation.pos;
|
||||||
mpTrack->MergeClips(mLocation.clipidx1, mLocation.clipidx2);
|
for (auto channel :
|
||||||
|
TrackList::Channels(mpTrack.get())) {
|
||||||
if (linked) {
|
|
||||||
// Don't assume correspondence of merge points across channels!
|
// Don't assume correspondence of merge points across channels!
|
||||||
int idx = FindMergeLine(linked, pos);
|
int idx = FindMergeLine(channel, pos);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
WaveTrack::Location location = linked->GetCachedLocations()[idx];
|
WaveTrack::Location location =
|
||||||
linked->MergeClips(location.clipidx1, location.clipidx2);
|
channel->GetCachedLocations()[idx];
|
||||||
|
channel->MergeClips(
|
||||||
|
location.clipidx1, location.clipidx2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,10 +186,10 @@ UIHandle::Result CutlineHandle::Click
|
|||||||
}
|
}
|
||||||
else if (event.RightDown())
|
else if (event.RightDown())
|
||||||
{
|
{
|
||||||
bool removed = mpTrack->RemoveCutLine(mLocation.pos);
|
bool removed = false;
|
||||||
|
for (auto channel :
|
||||||
if (linked)
|
TrackList::Channels(mpTrack.get()))
|
||||||
removed = linked->RemoveCutLine(mLocation.pos) || removed;
|
removed = channel->RemoveCutLine(mLocation.pos) || removed;
|
||||||
|
|
||||||
if (!removed)
|
if (!removed)
|
||||||
// Nothing happened, make no Undo item
|
// Nothing happened, make no Undo item
|
||||||
|
@ -213,14 +213,9 @@ void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
|
|||||||
int newWaveColor = id - OnInstrument1ID;
|
int newWaveColor = id - OnInstrument1ID;
|
||||||
|
|
||||||
AudacityProject *const project = ::GetActiveProject();
|
AudacityProject *const project = ::GetActiveProject();
|
||||||
// TrackList *const tracks = project->GetTracks();
|
|
||||||
|
|
||||||
pTrack->SetWaveColorIndex(newWaveColor);
|
for (auto channel : TrackList::Channels(pTrack))
|
||||||
|
channel->SetWaveColorIndex(newWaveColor);
|
||||||
// Assume partner is wave or null
|
|
||||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
|
||||||
if (partner)
|
|
||||||
partner->SetWaveColorIndex(newWaveColor);
|
|
||||||
|
|
||||||
project->PushState(wxString::Format(_("Changed '%s' to %s"),
|
project->PushState(wxString::Format(_("Changed '%s' to %s"),
|
||||||
pTrack->GetName(),
|
pTrack->GetName(),
|
||||||
@ -336,12 +331,9 @@ void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
|
|||||||
return; // Nothing to do.
|
return; // Nothing to do.
|
||||||
|
|
||||||
AudacityProject *const project = ::GetActiveProject();
|
AudacityProject *const project = ::GetActiveProject();
|
||||||
pTrack->ConvertToSampleFormat(newFormat);
|
|
||||||
|
|
||||||
// Assume partner is wave or null
|
for (auto channel : TrackList::Channels(pTrack))
|
||||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
channel->ConvertToSampleFormat(newFormat);
|
||||||
if (partner)
|
|
||||||
partner->ConvertToSampleFormat(newFormat);
|
|
||||||
|
|
||||||
/* i18n-hint: The strings name a track and a format */
|
/* i18n-hint: The strings name a track and a format */
|
||||||
project->PushState(wxString::Format(_("Changed '%s' to %s"),
|
project->PushState(wxString::Format(_("Changed '%s' to %s"),
|
||||||
@ -439,11 +431,9 @@ int RateMenuTable::IdOfRate(int rate)
|
|||||||
void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
|
void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
|
||||||
{
|
{
|
||||||
AudacityProject *const project = ::GetActiveProject();
|
AudacityProject *const project = ::GetActiveProject();
|
||||||
pTrack->SetRate(rate);
|
for (auto channel : TrackList::Channels(pTrack))
|
||||||
// Assume linked track is wave or null
|
channel->SetRate(rate);
|
||||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
|
||||||
if (partner)
|
|
||||||
partner->SetRate(rate);
|
|
||||||
// Separate conversion of "rate" enables changing the decimals without affecting i18n
|
// Separate conversion of "rate" enables changing the decimals without affecting i18n
|
||||||
wxString rateString = wxString::Format(wxT("%.3f"), rate);
|
wxString rateString = wxString::Format(wxT("%.3f"), rate);
|
||||||
/* i18n-hint: The string names a track */
|
/* i18n-hint: The string names a track */
|
||||||
@ -733,20 +723,11 @@ void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
|
|||||||
(id == WaveTrack::Waveform &&
|
(id == WaveTrack::Waveform &&
|
||||||
pTrack->GetWaveformSettings().isLinear() != linear);
|
pTrack->GetWaveformSettings().isLinear() != linear);
|
||||||
if (wrongType || wrongScale) {
|
if (wrongType || wrongScale) {
|
||||||
pTrack->SetLastScaleType();
|
for (auto channel : TrackList::Channels(pTrack)) {
|
||||||
pTrack->SetDisplay(WaveTrack::WaveTrackDisplay(id));
|
channel->SetLastScaleType();
|
||||||
|
channel->SetDisplay(WaveTrack::WaveTrackDisplay(id));
|
||||||
if (wrongScale)
|
if (wrongScale)
|
||||||
pTrack->GetIndependentWaveformSettings().scaleType = linear
|
channel->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));
|
|
||||||
if (wrongScale)
|
|
||||||
partner->GetIndependentWaveformSettings().scaleType = linear
|
|
||||||
? WaveformSettings::stLinear
|
? WaveformSettings::stLinear
|
||||||
: WaveformSettings::stLogarithmic;
|
: WaveformSettings::stLogarithmic;
|
||||||
}
|
}
|
||||||
|
@ -47,12 +47,9 @@ UIHandle::Result GainSliderHandle::SetValue
|
|||||||
auto pTrack = GetWaveTrack();
|
auto pTrack = GetWaveTrack();
|
||||||
|
|
||||||
if (pTrack) {
|
if (pTrack) {
|
||||||
pTrack->SetGain(newValue);
|
for (auto channel :
|
||||||
|
TrackList::Channels(pTrack.get()))
|
||||||
// Assume linked track is wave or null
|
channel->SetGain(newValue);
|
||||||
const auto link = static_cast<WaveTrack*>(mpTrack.lock()->GetLink());
|
|
||||||
if (link)
|
|
||||||
link->SetGain(newValue);
|
|
||||||
|
|
||||||
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
|
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
|
||||||
if (pMixerBoard)
|
if (pMixerBoard)
|
||||||
@ -131,12 +128,9 @@ UIHandle::Result PanSliderHandle::SetValue(AudacityProject *pProject, float newV
|
|||||||
auto pTrack = GetWaveTrack();
|
auto pTrack = GetWaveTrack();
|
||||||
|
|
||||||
if (pTrack) {
|
if (pTrack) {
|
||||||
pTrack->SetPan(newValue);
|
for (auto channel :
|
||||||
|
TrackList::Channels(pTrack.get()))
|
||||||
// Assume linked track is wave or null
|
channel->SetPan(newValue);
|
||||||
const auto link = static_cast<WaveTrack*>(pTrack->GetLink());
|
|
||||||
if (link)
|
|
||||||
link->SetPan(newValue);
|
|
||||||
|
|
||||||
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
|
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
|
||||||
if (pMixerBoard)
|
if (pMixerBoard)
|
||||||
|
@ -58,13 +58,12 @@ void WaveTrackVRulerControls::DoZoomPreset( int i)
|
|||||||
|
|
||||||
const auto wt = static_cast<WaveTrack*>(pTrack.get());
|
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.
|
// during recording and there are special pending tracks.
|
||||||
// This function implements WaveTrack::DoSetMinimized which is always
|
// This function implements WaveTrack::DoSetMinimized which is always
|
||||||
// called in a context that loops over linked tracks too and reinvokes.
|
// called in a context that loops over linked tracks too and reinvokes.
|
||||||
auto partner = nullptr;
|
|
||||||
WaveTrackVZoomHandle::DoZoom(
|
WaveTrackVZoomHandle::DoZoom(
|
||||||
NULL, wt, partner, (i==1)?kZoomHalfWave: kZoom1to1,
|
NULL, wt, false, (i==1)?kZoomHalfWave: kZoom1to1,
|
||||||
wxRect(0,0,0,0), 0,0, true);
|
wxRect(0,0,0,0), 0,0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,9 +87,7 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
|
|||||||
wxASSERT(pTrack->GetKind() == Track::Wave);
|
wxASSERT(pTrack->GetKind() == Track::Wave);
|
||||||
auto steps = evt.steps;
|
auto steps = evt.steps;
|
||||||
|
|
||||||
const auto wt = static_cast<WaveTrack*>(pTrack.get());
|
WaveTrack *const wt = static_cast<WaveTrack*>(pTrack.get());
|
||||||
// Assume linked track is wave or null
|
|
||||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
|
||||||
const bool isDB =
|
const bool isDB =
|
||||||
wt->GetDisplay() == WaveTrack::Waveform &&
|
wt->GetDisplay() == WaveTrack::Waveform &&
|
||||||
wt->GetWaveformSettings().scaleType == WaveformSettings::stLogarithmic;
|
wt->GetWaveformSettings().scaleType == WaveformSettings::stLogarithmic;
|
||||||
@ -102,24 +99,20 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
|
|||||||
if (!(min < 0.0 && max > 0.0))
|
if (!(min < 0.0 && max > 0.0))
|
||||||
return RefreshNone;
|
return RefreshNone;
|
||||||
|
|
||||||
WaveformSettings &settings = wt->GetIndependentWaveformSettings();
|
WaveformSettings &settings =
|
||||||
|
wt->GetIndependentWaveformSettings();
|
||||||
float olddBRange = settings.dBRange;
|
float olddBRange = settings.dBRange;
|
||||||
|
for (auto channel : TrackList::Channels(wt)) {
|
||||||
|
WaveformSettings &channelSettings =
|
||||||
|
channel->GetIndependentWaveformSettings();
|
||||||
if (steps < 0)
|
if (steps < 0)
|
||||||
// Zoom out
|
// Zoom out
|
||||||
settings.NextLowerDBRange();
|
channelSettings.NextLowerDBRange();
|
||||||
else
|
else
|
||||||
settings.NextHigherDBRange();
|
channelSettings.NextHigherDBRange();
|
||||||
float newdBRange = settings.dBRange;
|
|
||||||
|
|
||||||
if (partner) {
|
|
||||||
WaveformSettings &settings = partner->GetIndependentWaveformSettings();
|
|
||||||
if (steps < 0)
|
|
||||||
// Zoom out
|
|
||||||
settings.NextLowerDBRange();
|
|
||||||
else
|
|
||||||
settings.NextHigherDBRange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float newdBRange = settings.dBRange;
|
||||||
|
|
||||||
// Is y coordinate within the rectangle half-height centered about
|
// Is y coordinate within the rectangle half-height centered about
|
||||||
// the zero level?
|
// the zero level?
|
||||||
@ -135,19 +128,16 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
|
|||||||
const float extreme = (LINEAR_TO_DB(2) + newdBRange) / newdBRange;
|
const float extreme = (LINEAR_TO_DB(2) + newdBRange) / newdBRange;
|
||||||
max = std::min(extreme, max * olddBRange / newdBRange);
|
max = std::min(extreme, max * olddBRange / newdBRange);
|
||||||
min = std::max(-extreme, min * olddBRange / newdBRange);
|
min = std::max(-extreme, min * olddBRange / newdBRange);
|
||||||
wt->SetLastdBRange();
|
for (auto channel : TrackList::Channels(wt)) {
|
||||||
wt->SetDisplayBounds(min, max);
|
channel->SetLastdBRange();
|
||||||
if (partner) {
|
channel->SetDisplayBounds(min, max);
|
||||||
partner->SetLastdBRange();
|
|
||||||
partner->SetDisplayBounds(min, max);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event.CmdDown() && !event.ShiftDown()) {
|
else if (event.CmdDown() && !event.ShiftDown()) {
|
||||||
const int yy = event.m_y;
|
const int yy = event.m_y;
|
||||||
const auto partner = static_cast<WaveTrack *>(wt);
|
|
||||||
WaveTrackVZoomHandle::DoZoom(
|
WaveTrackVZoomHandle::DoZoom(
|
||||||
pProject, wt, partner, (steps < 0)?kZoomOut:kZoomIn,
|
pProject, wt, true, (steps < 0)?kZoomOut:kZoomIn,
|
||||||
evt.rect, yy, yy, true);
|
evt.rect, yy, yy, true);
|
||||||
}
|
}
|
||||||
else if (!event.CmdDown() && event.ShiftDown()) {
|
else if (!event.CmdDown() && event.ShiftDown()) {
|
||||||
@ -173,9 +163,8 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
|
|||||||
std::min(bound,
|
std::min(bound,
|
||||||
numberScale.PositionToValue(numberScale.ValueToPosition(newBottom) + 1.0f));
|
numberScale.PositionToValue(numberScale.ValueToPosition(newBottom) + 1.0f));
|
||||||
|
|
||||||
wt->SetSpectrumBounds(newBottom, newTop);
|
for (auto channel : TrackList::Channels(wt))
|
||||||
if (partner)
|
channel->SetSpectrumBounds(newBottom, newTop);
|
||||||
partner->SetSpectrumBounds(newBottom, newTop);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
float topLimit = 2.0;
|
float topLimit = 2.0;
|
||||||
@ -191,9 +180,8 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
|
|||||||
float newTop = std::min(topLimit, top + delta);
|
float newTop = std::min(topLimit, top + delta);
|
||||||
const float newBottom = std::max(bottomLimit, newTop - range);
|
const float newBottom = std::max(bottomLimit, newTop - range);
|
||||||
newTop = std::min(topLimit, newBottom + range);
|
newTop = std::min(topLimit, newBottom + range);
|
||||||
wt->SetDisplayBounds(newBottom, newTop);
|
for (auto channel : TrackList::Channels(wt))
|
||||||
if (partner)
|
channel->SetDisplayBounds(newBottom, newTop);
|
||||||
partner->SetDisplayBounds(newBottom, newTop);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -65,11 +65,12 @@ void WaveTrackVZoomHandle::Enter(bool)
|
|||||||
// the zoomKind and cause a drag-zoom-in.
|
// the zoomKind and cause a drag-zoom-in.
|
||||||
void WaveTrackVZoomHandle::DoZoom
|
void WaveTrackVZoomHandle::DoZoom
|
||||||
(AudacityProject *pProject,
|
(AudacityProject *pProject,
|
||||||
WaveTrack *pTrack, WaveTrack *partner, int ZoomKind,
|
WaveTrack *pTrack, bool allChannels, int ZoomKind,
|
||||||
const wxRect &rect, int zoomStart, int zoomEnd,
|
const wxRect &rect, int zoomStart, int zoomEnd,
|
||||||
bool fixedMousePoint)
|
bool fixedMousePoint)
|
||||||
{
|
{
|
||||||
static const float ZOOMLIMIT = 0.001f;
|
static const float ZOOMLIMIT = 0.001f;
|
||||||
|
|
||||||
int height = rect.height;
|
int height = rect.height;
|
||||||
int ypos = rect.y;
|
int ypos = rect.y;
|
||||||
|
|
||||||
@ -318,15 +319,13 @@ void WaveTrackVZoomHandle::DoZoom
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now actually apply the zoom.
|
// Now actually apply the zoom.
|
||||||
if (spectral) {
|
for (auto channel : TrackList::Channels(pTrack)) {
|
||||||
pTrack->SetSpectrumBounds(min, max);
|
if (!allChannels && channel != pTrack)
|
||||||
if (partner)
|
continue;
|
||||||
partner->SetSpectrumBounds(min, max);
|
if (spectral)
|
||||||
}
|
channel->SetSpectrumBounds(min, max);
|
||||||
else {
|
else
|
||||||
pTrack->SetDisplayBounds(min, max);
|
channel->SetDisplayBounds(min, max);
|
||||||
if (partner)
|
|
||||||
partner->SetDisplayBounds(min, max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomEnd = zoomStart = 0;
|
zoomEnd = zoomStart = 0;
|
||||||
@ -389,10 +388,8 @@ void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData)
|
|||||||
|
|
||||||
void WaveTrackVRulerMenuTable::OnZoom( int iZoomCode )
|
void WaveTrackVRulerMenuTable::OnZoom( int iZoomCode )
|
||||||
{
|
{
|
||||||
// Assume linked track is wave or null
|
|
||||||
const auto partner = static_cast<WaveTrack *>(mpData->pTrack->GetLink());
|
|
||||||
WaveTrackVZoomHandle::DoZoom
|
WaveTrackVZoomHandle::DoZoom
|
||||||
(::GetActiveProject(), mpData->pTrack, partner,
|
(::GetActiveProject(), mpData->pTrack, true,
|
||||||
iZoomCode, mpData->rect, mpData->yy, mpData->yy, false);
|
iZoomCode, mpData->rect, mpData->yy, mpData->yy, false);
|
||||||
|
|
||||||
using namespace RefreshCode;
|
using namespace RefreshCode;
|
||||||
@ -467,17 +464,17 @@ void WaveformVRulerMenuTable::OnWaveformScaleType(wxCommandEvent &evt)
|
|||||||
{
|
{
|
||||||
WaveTrack *const wt = mpData->pTrack;
|
WaveTrack *const wt = mpData->pTrack;
|
||||||
// Assume linked track is wave or null
|
// Assume linked track is wave or null
|
||||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
|
||||||
const WaveformSettings::ScaleType newScaleType =
|
const WaveformSettings::ScaleType newScaleType =
|
||||||
WaveformSettings::ScaleType(
|
WaveformSettings::ScaleType(
|
||||||
std::max(0,
|
std::max(0,
|
||||||
std::min((int)(WaveformSettings::stNumScaleTypes) - 1,
|
std::min((int)(WaveformSettings::stNumScaleTypes) - 1,
|
||||||
evt.GetId() - OnFirstWaveformScaleID
|
evt.GetId() - OnFirstWaveformScaleID
|
||||||
)));
|
)));
|
||||||
|
|
||||||
if (wt->GetWaveformSettings().scaleType != newScaleType) {
|
if (wt->GetWaveformSettings().scaleType != newScaleType) {
|
||||||
wt->GetIndependentWaveformSettings().scaleType = newScaleType;
|
for (auto channel : TrackList::Channels(wt)) {
|
||||||
if (partner)
|
channel->GetIndependentWaveformSettings().scaleType = newScaleType;
|
||||||
partner->GetIndependentWaveformSettings().scaleType = newScaleType;
|
}
|
||||||
|
|
||||||
::GetActiveProject()->ModifyState(true);
|
::GetActiveProject()->ModifyState(true);
|
||||||
|
|
||||||
@ -540,8 +537,7 @@ END_POPUP_MENU()
|
|||||||
void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
|
void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
|
||||||
{
|
{
|
||||||
WaveTrack *const wt = mpData->pTrack;
|
WaveTrack *const wt = mpData->pTrack;
|
||||||
// Assume linked track is wave or null
|
|
||||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
|
||||||
const SpectrogramSettings::ScaleType newScaleType =
|
const SpectrogramSettings::ScaleType newScaleType =
|
||||||
SpectrogramSettings::ScaleType(
|
SpectrogramSettings::ScaleType(
|
||||||
std::max(0,
|
std::max(0,
|
||||||
@ -549,9 +545,8 @@ void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
|
|||||||
evt.GetId() - OnFirstSpectrumScaleID
|
evt.GetId() - OnFirstSpectrumScaleID
|
||||||
)));
|
)));
|
||||||
if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
|
if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
|
||||||
wt->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
for (auto channel : TrackList::Channels(wt))
|
||||||
if (partner)
|
channel->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
||||||
partner->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
|
||||||
|
|
||||||
::GetActiveProject()->ModifyState(true);
|
::GetActiveProject()->ModifyState(true);
|
||||||
|
|
||||||
@ -678,8 +673,7 @@ UIHandle::Result WaveTrackVZoomHandle::Release
|
|||||||
if( bVZoom ){
|
if( bVZoom ){
|
||||||
if( shiftDown )
|
if( shiftDown )
|
||||||
mZoomStart=mZoomEnd;
|
mZoomStart=mZoomEnd;
|
||||||
const auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
|
DoZoom(pProject, pTrack.get(), true,
|
||||||
DoZoom(pProject, pTrack.get(), partner,
|
|
||||||
shiftDown ? (rightUp ? kZoom1to1 : kZoomOut) : kZoomIn,
|
shiftDown ? (rightUp ? kZoom1to1 : kZoomOut) : kZoomIn,
|
||||||
mRect, mZoomStart, mZoomEnd, !shiftDown);
|
mRect, mZoomStart, mZoomEnd, !shiftDown);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
static void DoZoom
|
static void DoZoom
|
||||||
(AudacityProject *pProject,
|
(AudacityProject *pProject,
|
||||||
WaveTrack *pTrack, WaveTrack *partner, int ZoomKind,
|
WaveTrack *pTrack, bool allChannels, int ZoomKind,
|
||||||
const wxRect &rect, int zoomStart, int zoomEnd,
|
const wxRect &rect, int zoomStart, int zoomEnd,
|
||||||
bool fixedMousePoint);
|
bool fixedMousePoint);
|
||||||
|
|
||||||
|
@ -178,6 +178,8 @@ UIHandle::Result EnvelopeHandle::Click
|
|||||||
const ViewInfo &viewInfo = pProject->GetViewInfo();
|
const ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||||
const auto pTrack = static_cast<Track*>(evt.pCell.get());
|
const auto pTrack = static_cast<Track*>(evt.pCell.get());
|
||||||
|
|
||||||
|
mEnvelopeEditors.clear();
|
||||||
|
|
||||||
unsigned result = Cancelled;
|
unsigned result = Cancelled;
|
||||||
if (pTrack)
|
if (pTrack)
|
||||||
result = pTrack->TypeSwitch< decltype(RefreshNone) >(
|
result = pTrack->TypeSwitch< decltype(RefreshNone) >(
|
||||||
@ -191,18 +193,21 @@ UIHandle::Result EnvelopeHandle::Click
|
|||||||
mLog = !wt->GetWaveformSettings().isLinear();
|
mLog = !wt->GetWaveformSettings().isLinear();
|
||||||
wt->GetDisplayBounds(&mLower, &mUpper);
|
wt->GetDisplayBounds(&mLower, &mUpper);
|
||||||
mdBRange = wt->GetWaveformSettings().dBRange;
|
mdBRange = wt->GetWaveformSettings().dBRange;
|
||||||
mEnvelopeEditor =
|
auto channels = TrackList::Channels( wt );
|
||||||
std::make_unique< EnvelopeEditor >( *mEnvelope, true );
|
for ( auto channel : channels ) {
|
||||||
mEnvelopeEditorRight.reset();
|
if (channel == wt)
|
||||||
|
mEnvelopeEditors.push_back(
|
||||||
// Assume linked track is wave or null
|
std::make_unique< EnvelopeEditor >( *mEnvelope, true ) );
|
||||||
auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
else {
|
||||||
if (partner)
|
auto e2 = channel->GetEnvelopeAtX(event.GetX());
|
||||||
{
|
if (e2)
|
||||||
auto clickedEnvelope = partner->GetEnvelopeAtX(event.GetX());
|
mEnvelopeEditors.push_back(
|
||||||
if (clickedEnvelope)
|
std::make_unique< EnvelopeEditor >( *e2, true ) );
|
||||||
mEnvelopeEditorRight =
|
else {
|
||||||
std::make_unique< EnvelopeEditor >( *clickedEnvelope, true );
|
// There isn't necessarily an envelope there; no guarantee a
|
||||||
|
// linked track has the same WaveClip structure...
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RefreshNone;
|
return RefreshNone;
|
||||||
@ -211,9 +216,9 @@ UIHandle::Result EnvelopeHandle::Click
|
|||||||
if (!mEnvelope)
|
if (!mEnvelope)
|
||||||
return Cancelled;
|
return Cancelled;
|
||||||
GetTimeTrackData( *pProject, *tt, mdBRange, mLog, mLower, mUpper);
|
GetTimeTrackData( *pProject, *tt, mdBRange, mLog, mLower, mUpper);
|
||||||
mEnvelopeEditor =
|
mEnvelopeEditors.push_back(
|
||||||
std::make_unique< EnvelopeEditor >( *mEnvelope, false );
|
std::make_unique< EnvelopeEditor >( *mEnvelope, false )
|
||||||
mEnvelopeEditorRight.reset();
|
);
|
||||||
|
|
||||||
return RefreshNone;
|
return RefreshNone;
|
||||||
},
|
},
|
||||||
@ -289,8 +294,7 @@ UIHandle::Result EnvelopeHandle::Release
|
|||||||
_("Envelope")
|
_("Envelope")
|
||||||
);
|
);
|
||||||
|
|
||||||
mEnvelopeEditor.reset();
|
mEnvelopeEditors.clear();
|
||||||
mEnvelopeEditorRight.reset();
|
|
||||||
|
|
||||||
using namespace RefreshCode;
|
using namespace RefreshCode;
|
||||||
return needUpdate ? RefreshCell : RefreshNone;
|
return needUpdate ? RefreshCell : RefreshNone;
|
||||||
@ -299,8 +303,7 @@ UIHandle::Result EnvelopeHandle::Release
|
|||||||
UIHandle::Result EnvelopeHandle::Cancel(AudacityProject *pProject)
|
UIHandle::Result EnvelopeHandle::Cancel(AudacityProject *pProject)
|
||||||
{
|
{
|
||||||
pProject->RollbackState();
|
pProject->RollbackState();
|
||||||
mEnvelopeEditor.reset();
|
mEnvelopeEditors.clear();
|
||||||
mEnvelopeEditorRight.reset();
|
|
||||||
return RefreshCode::RefreshCell;
|
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
|
// AS: I'm not sure why we can't let the Envelope take care of
|
||||||
// redrawing itself. ?
|
// redrawing itself. ?
|
||||||
bool needUpdate =
|
bool needUpdate = false;
|
||||||
mEnvelopeEditor->MouseEvent(
|
for (const auto &pEditor : mEnvelopeEditors) {
|
||||||
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper);
|
needUpdate =
|
||||||
|
pEditor->MouseEvent(
|
||||||
if (mEnvelopeEditorRight)
|
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper)
|
||||||
needUpdate |=
|
|| needUpdate;
|
||||||
mEnvelopeEditorRight->MouseEvent(
|
}
|
||||||
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper);
|
|
||||||
|
|
||||||
return needUpdate;
|
return needUpdate;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ Paul Licameli split from TrackPanel.cpp
|
|||||||
#include "../../UIHandle.h"
|
#include "../../UIHandle.h"
|
||||||
#include "../../MemoryX.h"
|
#include "../../MemoryX.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class wxMouseEvent;
|
class wxMouseEvent;
|
||||||
class wxMouseState;
|
class wxMouseState;
|
||||||
#include <wx/gdicmn.h>
|
#include <wx/gdicmn.h>
|
||||||
@ -85,8 +87,7 @@ private:
|
|||||||
double mdBRange{};
|
double mdBRange{};
|
||||||
|
|
||||||
Envelope *mEnvelope{};
|
Envelope *mEnvelope{};
|
||||||
std::unique_ptr<EnvelopeEditor> mEnvelopeEditor;
|
std::vector< std::unique_ptr<EnvelopeEditor> > mEnvelopeEditors;
|
||||||
std::unique_ptr<EnvelopeEditor> mEnvelopeEditorRight;
|
|
||||||
|
|
||||||
bool mTimeTrack{};
|
bool mTimeTrack{};
|
||||||
};
|
};
|
||||||
|
@ -152,6 +152,21 @@ namespace
|
|||||||
AddClipsToCaptured( state, t, t->GetStartTime(), t->GetEndTime() );
|
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.
|
// Don't count right channels.
|
||||||
WaveTrack *NthAudioTrack(TrackList &list, int nn)
|
WaveTrack *NthAudioTrack(TrackList &list, int nn)
|
||||||
{
|
{
|
||||||
@ -206,16 +221,11 @@ namespace
|
|||||||
clip.track->Offset( offset );
|
clip.track->Offset( offset );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( pTrack ) {
|
else if ( pTrack )
|
||||||
// Was a shift-click
|
// Was a shift-click
|
||||||
for (auto channel =
|
for (auto channel : TrackList::Channels( pTrack ))
|
||||||
pTrack->GetLink() && !pTrack->GetLinked()
|
|
||||||
? pTrack->GetLink() : pTrack;
|
|
||||||
channel;
|
|
||||||
channel = channel->GetLinked() ? channel->GetLink() : nullptr)
|
|
||||||
channel->Offset( offset );
|
channel->Offset( offset );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeShiftHandle::CreateListOfCapturedClips
|
void TimeShiftHandle::CreateListOfCapturedClips
|
||||||
@ -236,16 +246,12 @@ void TimeShiftHandle::CreateListOfCapturedClips
|
|||||||
state.capturedClipArray.push_back
|
state.capturedClipArray.push_back
|
||||||
(TrackClip( &capturedTrack, state.capturedClip ));
|
(TrackClip( &capturedTrack, state.capturedClip ));
|
||||||
|
|
||||||
// Check for stereo partner
|
if (state.capturedClip) {
|
||||||
Track *partner = capturedTrack.GetLink();
|
// Check for other channels
|
||||||
WaveTrack *wt;
|
auto wt = static_cast<WaveTrack*>(&capturedTrack);
|
||||||
if (state.capturedClip &&
|
for ( auto channel : TrackList::Channels( wt ).Excluding( wt ) )
|
||||||
// Assume linked track is wave or null
|
if (WaveClip *const clip = FindClipAtTime(channel, clickTime))
|
||||||
nullptr != (wt = static_cast<WaveTrack*>(partner))) {
|
state.capturedClipArray.push_back(TrackClip(channel, clip));
|
||||||
WaveClip *const clip = FindClipAtTime(wt, clickTime);
|
|
||||||
|
|
||||||
if (clip)
|
|
||||||
state.capturedClipArray.push_back(TrackClip(partner, clip));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,22 +499,28 @@ namespace {
|
|||||||
for ( auto &trackClip : state.capturedClipArray ) {
|
for ( auto &trackClip : state.capturedClipArray ) {
|
||||||
if (trackClip.clip) {
|
if (trackClip.clip) {
|
||||||
// Move all clips up or down by an equal count of audio tracks.
|
// 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;
|
Track *const pSrcTrack = trackClip.track;
|
||||||
auto pDstTrack = NthAudioTrack(trackList,
|
auto pDstTrack = NthAudioTrack(trackList,
|
||||||
diff + TrackPosition(trackList, pSrcTrack));
|
diff + TrackPosition(trackList, pSrcTrack));
|
||||||
// Can only move mono to mono, or left to left, or right to right
|
if (!pDstTrack)
|
||||||
// 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
|
|
||||||
return false;
|
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;
|
return true;
|
||||||
|
@ -34,9 +34,9 @@ UIHandle::Result MinimizeButtonHandle::CommitChanges
|
|||||||
auto pTrack = mpTrack.lock();
|
auto pTrack = mpTrack.lock();
|
||||||
if (pTrack)
|
if (pTrack)
|
||||||
{
|
{
|
||||||
pTrack->SetMinimized(!pTrack->GetMinimized());
|
bool wasMinimized = pTrack->GetMinimized();
|
||||||
if (pTrack->GetLink())
|
for (auto channel : TrackList::Channels(pTrack.get()))
|
||||||
pTrack->GetLink()->SetMinimized(pTrack->GetMinimized());
|
channel->SetMinimized(!wasMinimized);
|
||||||
pProject->ModifyState(true);
|
pProject->ModifyState(true);
|
||||||
|
|
||||||
// Redraw all tracks when any one of them expands or contracts
|
// Redraw all tracks when any one of them expands or contracts
|
||||||
|
@ -209,11 +209,8 @@ void TrackMenuTable::OnSetName(wxCommandEvent &)
|
|||||||
if (bResult)
|
if (bResult)
|
||||||
{
|
{
|
||||||
wxString newName = Command.mName;
|
wxString newName = Command.mName;
|
||||||
pTrack->SetName(newName);
|
for (auto channel : TrackList::Channels(pTrack))
|
||||||
// if we have a linked channel this name should change as well
|
channel->SetName(newName);
|
||||||
// (otherwise sort by name and time will crash).
|
|
||||||
if (pTrack->GetLinked())
|
|
||||||
pTrack->GetLink()->SetName(newName);
|
|
||||||
|
|
||||||
MixerBoard *const pMixerBoard = proj->GetMixerBoard();
|
MixerBoard *const pMixerBoard = proj->GetMixerBoard();
|
||||||
auto pt = dynamic_cast<PlayableTrack*>(pTrack);
|
auto pt = dynamic_cast<PlayableTrack*>(pTrack);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user