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

Iterate over the pending tracks for drawing

This commit is contained in:
Paul Licameli 2018-01-10 16:02:51 -05:00
parent 7d57a17ff4
commit ce5a67a9e9
7 changed files with 141 additions and 37 deletions

View File

@ -2019,25 +2019,6 @@ void AudacityProject::FixScrollbars()
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()
{
if (!mTrackPanel)

View File

@ -192,8 +192,6 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame,
const ViewInfo &GetViewInfo() const { return mViewInfo; }
ViewInfo &GetViewInfo() { return mViewInfo; }
std::shared_ptr<Track> GetFirstVisible();
void GetPlayRegion(double* playRegionStart, double *playRegionEnd);
bool IsPlayRegionLocked() { return mLockPlayRegion; }

View File

@ -1560,3 +1560,69 @@ std::shared_ptr<Track> TrackList::FindPendingChangedTrack(TrackId id) const
return {};
return *it;
}
// Make begin iterator
PendingTrackIterator::PendingTrackIterator
(TrackList *list, const std::shared_ptr<TrackListIterator> &pIter)
: mList{ list }
, mpIter{ pIter }
{
auto &pending = mList->FindPendingNewTracks();
// Assume no invalidation of these iterators happens during the lifetime
// of this!
mpPendingIt = pending.begin(), mpPendingEnd = pending.end();
mpTrack = Track::Pointer( mpIter->First() );
SubstituteTrack();
mDoingExtras = !mpTrack;
FindExtraTrack();
}
// Make end iterator; the only important thing is to define operators == and
// != with other iterators
PendingTrackIterator::PendingTrackIterator()
: mList{ nullptr }
, mpIter{ }
{
mDoingExtras = true;
}
PendingTrackIterator &PendingTrackIterator::operator++()
{
if (!mDoingExtras) {
Track *next = mpIter->Next();
if (next) {
mpTrack = Track::Pointer( next );
SubstituteTrack();
}
else
mDoingExtras = true;
}
FindExtraTrack();
return *this;
}
void PendingTrackIterator::SubstituteTrack()
{
if (mpTrack) {
auto sub = mList->FindPendingChangedTrack( mpTrack->GetId() );
if (sub)
mpTrack = sub;
}
}
void PendingTrackIterator::FindExtraTrack()
{
if (mDoingExtras) {
auto pCondIter = dynamic_cast<TrackListCondIterator*>(mpIter.get());
while(
mpTrack.reset(),
mpPendingIt != mpPendingEnd &&
(mpTrack = *mpPendingIt++,
pCondIter &&
!pCondIter->Condition(mpTrack.get())))
{}
}
}

View File

@ -501,7 +501,6 @@ class AUDACITY_DLL_API TrackListCondIterator /* not final */ : public TrackListI
Track *Prev(bool skiplinked = false) override;
Track *Last(bool skiplinked = false) override;
protected:
// NEW virtual
virtual bool Condition(Track *t) = 0;
};
@ -579,6 +578,52 @@ class AUDACITY_DLL_API SyncLockedTracksIterator final : public TrackListIterator
};
// Iterates over the tracks, substituting any pending replacement tracks
// for the actual, and always appending the added tracks, but then
// also filtering all tracks according to the criterion in the
// TrackListIterator given to the constructor.
// Iterator may be invalidated if the project's TrackList is mutated during
// the iterator's lifetime (though not in case of RegisterPendingChangedTrack()).
class PendingTrackIterator {
public:
// Construct a begin iterator
PendingTrackIterator
(TrackList *list,
// Track iterator that can include a condition
const std::shared_ptr<TrackListIterator> &pIter);
// Construct an end iterator
PendingTrackIterator();
PendingTrackIterator &operator++();
const std::shared_ptr<Track> &operator* () const { return mpTrack; }
bool operator == (const PendingTrackIterator &other) const
// Test for identity of the tracks pointed to should be a sufficient
// test of iterator equality, assuming no track is ever duplicated in the
// sequence, which should be the case, and that an end iterator stores a
// null pointer.
{ return mpTrack == other.mpTrack; }
bool operator != (const PendingTrackIterator &other) const
{ return !(*this == other); }
protected:
std::shared_ptr<Track> mpTrack;
private:
void SubstituteTrack();
void FindExtraTrack();
TrackList *mList;
std::shared_ptr<TrackListIterator> mpIter;
bool mDoingExtras{ false };
ListOfTracks::const_iterator mpPendingIt, mpPendingEnd;
};
/** \brief TrackList is a flat linked list of tracks supporting Add, Remove,
* Clear, and Contains, plus serialization of the list of tracks.
*/

View File

@ -339,8 +339,7 @@ void TrackArtist::SetMargins(int left, int top, int right, int bottom)
}
void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
TrackList * tracks,
Track * start,
const std::function< Range() > &range,
const wxRegion & reg,
const wxRect & rect,
const wxRect & clip,
@ -352,11 +351,10 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
{
wxRect trackRect = rect;
wxRect stereoTrackRect;
TrackListIterator iter(tracks);
Track *t;
bool hasSolo = false;
for (t = iter.First(); t; t = iter.Next()) {
for (auto &track : range()) {
auto t = track.get();
auto pt = dynamic_cast<const PlayableTrack *>(t);
if (pt && pt->GetSolo()) {
hasSolo = true;
@ -379,8 +377,8 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
gPrefs->Read(wxT("/GUI/ShowTrackNameInWaveform"), &mbShowTrackNameInWaveform, false);
t = iter.StartWith(start);
while (t) {
for (auto &track : range()) {
auto t = track.get();
trackRect.y = t->GetY() - zoomInfo.vpos;
trackRect.height = t->GetHeight();
@ -430,8 +428,6 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
selectedRegion, zoomInfo,
drawEnvelope, bigPoints, drawSliders, hasSolo);
}
t = iter.Next();
}
}

View File

@ -24,6 +24,8 @@
#include "Experimental.h"
#include "audacity/Types.h"
#include <functional>
class wxDC;
class wxRect;
class wxHashTable;
@ -36,10 +38,10 @@ class WaveClip;
class NoteTrack;
class LabelTrack;
class TimeTrack;
class TrackList;
class Ruler;
class SelectedRegion;
class ZoomInfo;
class PendingTrackIterator;
struct TrackPanelDrawingContext;
@ -54,8 +56,10 @@ class AUDACITY_DLL_API TrackArtist {
~TrackArtist();
void SetColours(int iColorIndex);
using Range = IteratorRange< PendingTrackIterator >;
void DrawTracks(TrackPanelDrawingContext &context,
TrackList *tracks, Track *start,
const std::function< Range() > &range,
const wxRegion & reg,
const wxRect & rect, const wxRect & clip,
const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo,

View File

@ -1846,8 +1846,17 @@ void TrackPanel::DrawTracks(wxDC * dc)
TrackPanelDrawingContext context{ *dc, Target(), mLastMouseState };
// The track artist actually draws the stuff inside each track
auto first = GetProject()->GetFirstVisible();
mTrackArtist->DrawTracks(context, GetTracks(), first.get(),
auto project = GetProject();
// Make a function that reproduces the range, because, quirkily, the range
// can't be copied and iterated twice. Fix that later.
auto range = [&]{
return make_iterator_range(
PendingTrackIterator{ project->GetTracks(),
std::make_shared<VisibleTrackIterator>( project ) },
PendingTrackIterator{}
);
};
mTrackArtist->DrawTracks(context, range,
region, tracksRect, clip,
mViewInfo->selectedRegion, *mViewInfo,
envelopeFlag, bigPointsFlag, sliderFlag);
@ -1869,8 +1878,13 @@ void TrackPanel::DrawEverythingElse(TrackPanelDrawingContext &context,
wxRect trackRect = clip;
trackRect.height = 0; // for drawing background in no tracks case.
VisibleTrackIterator iter(GetProject());
for (Track *t = iter.First(); t; t = iter.Next()) {
auto project = GetProject();
PendingTrackIterator
begin{ project->GetTracks(),
std::make_shared<VisibleTrackIterator>( project ) },
end;
for (const auto &track : make_iterator_range(begin, end)) {
auto t = track.get();
trackRect.y = t->GetY() - mViewInfo->vpos;
trackRect.height = t->GetHeight();