1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-11-22 00:47:13 +01:00

Mutable cache for ruler updates, so Draw functions can be const

This commit is contained in:
Paul Licameli
2020-01-23 11:32:49 -05:00
parent a2babc646f
commit 580ad8221e
2 changed files with 67 additions and 50 deletions

View File

@@ -111,8 +111,6 @@ Ruler::Ruler()
mLength = 0; mLength = 0;
mValid = false;
mCustom = false; mCustom = false;
mbMinor = true; mbMinor = true;
@@ -289,6 +287,7 @@ void Ruler::SetFonts(const wxFont &minorFont, const wxFont &majorFont, const wxF
wxCoord height; wxCoord height;
FindFontHeights( height, mpUserFonts->lead, dc, majorFont ); FindFontHeights( height, mpUserFonts->lead, dc, majorFont );
mpFonts.reset();
mpFonts.reset(); mpFonts.reset();
Invalidate(); Invalidate();
} }
@@ -346,14 +345,12 @@ void Ruler::SetBounds(int left, int top, int right, int bottom)
void Ruler::Invalidate() void Ruler::Invalidate()
{ {
mValid = false;
if (mOrientation == wxHORIZONTAL) if (mOrientation == wxHORIZONTAL)
mLength = mRight-mLeft; mLength = mRight-mLeft;
else else
mLength = mBottom-mTop; mLength = mBottom-mTop;
mBits.clear(); mpCache.reset();
mUserBits.clear(); mUserBits.clear();
} }
@@ -908,6 +905,12 @@ struct Ruler::Updater {
const; const;
}; };
struct Ruler::Cache {
Bits mBits;
Labels mMajorLabels, mMinorLabels, mMinorMinorLabels;
wxRect mRect;
};
struct Ruler::Updater::TickOutputs{ Labels &labels; Bits &bits; wxRect &box; }; struct Ruler::Updater::TickOutputs{ Labels &labels; Bits &bits; wxRect &box; };
struct Ruler::Updater::UpdateOutputs { struct Ruler::Updater::UpdateOutputs {
Labels &majorLabels, &minorLabels, &minorMinorLabels; Labels &majorLabels, &minorLabels, &minorMinorLabels;
@@ -1328,9 +1331,13 @@ void Ruler::ChooseFonts( wxDC &dc ) const
); );
} }
void Ruler::Update( void Ruler::UpdateCache(
wxDC &dc, const Envelope* envelope )// Envelope *speedEnv, long minSpeed, long maxSpeed ) wxDC &dc, const Envelope* envelope )
const // Envelope *speedEnv, long minSpeed, long maxSpeed )
{ {
if ( mpCache )
return;
const ZoomInfo *zoomInfo = NULL; const ZoomInfo *zoomInfo = NULL;
if (!mLog && mOrientation == wxHORIZONTAL) if (!mLog && mOrientation == wxHORIZONTAL)
zoomInfo = mUseZoomInfo; zoomInfo = mUseZoomInfo;
@@ -1340,6 +1347,8 @@ void Ruler::Update(
// tick positions and font size. // tick positions and font size.
ChooseFonts( dc ); ChooseFonts( dc );
mpCache = std::make_unique< Cache >();
auto &cache = *mpCache;
// If ruler is being resized, we could end up with it being too small. // If ruler is being resized, we could end up with it being too small.
// Values of mLength of zero or below cause bad array allocations and // Values of mLength of zero or below cause bad array allocations and
@@ -1349,33 +1358,31 @@ void Ruler::Update(
return; return;
if (mOrientation == wxHORIZONTAL) if (mOrientation == wxHORIZONTAL)
mRect = wxRect(0,0, mLength,0); cache.mRect = { 0, 0, mLength, 0 };
else else
mRect = wxRect(0,0, 0,mLength); cache.mRect = { 0, 0, 0, mLength };
// FIXME: Surely we do not need to allocate storage for the labels? // FIXME: Surely we do not need to allocate storage for the labels?
// We can just recompute them as we need them? Yes, but only if // We can just recompute them as we need them? Yes, but only if
// mCustom is false!!!! // mCustom is false!!!!
if(!mCustom) { if(!mCustom) {
mMajorLabels.clear(); cache.mMajorLabels.clear();
mMinorLabels.clear(); cache.mMinorLabels.clear();
mMinorMinorLabels.clear(); cache.mMinorMinorLabels.clear();
} }
mBits = mUserBits; cache.mBits = mUserBits;
mBits.resize( static_cast<size_t>(mLength + 1), false ); cache.mBits.resize( static_cast<size_t>(mLength + 1), false );
// Keep Updater const! We want no hidden state changes affecting its // Keep Updater const! We want no hidden state changes affecting its
// computations. // computations.
const Updater updater{ *this, zoomInfo }; const Updater updater{ *this, zoomInfo };
Updater::UpdateOutputs allOutputs{ Updater::UpdateOutputs allOutputs{
mMajorLabels, mMinorLabels, mMinorMinorLabels, cache.mMajorLabels, cache.mMinorLabels, cache.mMinorMinorLabels,
mBits, mRect cache.mBits, cache.mRect
}; };
updater.Update(dc, envelope, allOutputs); updater.Update(dc, envelope, allOutputs);
mValid = true;
} }
auto Ruler::GetFonts() const -> Fonts auto Ruler::GetFonts() const -> Fonts
@@ -1388,18 +1395,18 @@ auto Ruler::GetFonts() const -> Fonts
return *mpFonts; return *mpFonts;
} }
void Ruler::Draw(wxDC& dc) void Ruler::Draw(wxDC& dc) const
{ {
Draw( dc, NULL); Draw( dc, NULL);
} }
void Ruler::Draw(wxDC& dc, const Envelope* envelope) void Ruler::Draw(wxDC& dc, const Envelope* envelope) const
{ {
if( mLength <=0 ) if( mLength <=0 )
return; return;
if (!mValid) UpdateCache( dc, envelope );
Update( dc, envelope ); auto &cache = *mpCache;
dc.SetTextForeground( mTickColour ); dc.SetTextForeground( mTickColour );
#ifdef EXPERIMENTAL_THEMING #ifdef EXPERIMENTAL_THEMING
@@ -1464,18 +1471,18 @@ void Ruler::Draw(wxDC& dc, const Envelope* envelope)
label.Draw(dc, mTwoTone, mTickColour); label.Draw(dc, mTwoTone, mTickColour);
}; };
for( const auto &label : mMajorLabels ) for( const auto &label : cache.mMajorLabels )
drawLabel( label, 4 ); drawLabel( label, 4 );
if( mbMinor ) { if( mbMinor ) {
dc.SetFont( mpFonts->minor ); dc.SetFont( mpFonts->minor );
for( const auto &label : mMinorLabels ) for( const auto &label : cache.mMinorLabels )
drawLabel( label, 2 ); drawLabel( label, 2 );
} }
dc.SetFont( mpFonts->minorMinor ); dc.SetFont( mpFonts->minorMinor );
for( const auto &label : mMinorMinorLabels ) for( const auto &label : cache.mMinorMinorLabels )
if ( !label.text.empty() ) if ( !label.text.empty() )
drawLabel( label, 2 ); drawLabel( label, 2 );
} }
@@ -1484,9 +1491,10 @@ void Ruler::Draw(wxDC& dc, const Envelope* envelope)
void Ruler::DrawGrid(wxDC& dc, void Ruler::DrawGrid(wxDC& dc,
const int gridLineLength, const int gridLineLength,
const bool minorGrid, const bool majorGrid, int xOffset, int yOffset) const bool minorGrid, const bool majorGrid, int xOffset, int yOffset)
const
{ {
if ( !mValid ) UpdateCache( dc, nullptr );
Update( dc, nullptr ); auto &cache = *mpCache;
int gridPos; int gridPos;
wxPen gridPen; wxPen gridPen;
@@ -1494,7 +1502,7 @@ void Ruler::DrawGrid(wxDC& dc,
if(mbMinor && (minorGrid && (gridLineLength != 0 ))) { if(mbMinor && (minorGrid && (gridLineLength != 0 ))) {
gridPen.SetColour(178, 178, 178); // very light grey gridPen.SetColour(178, 178, 178); // very light grey
dc.SetPen(gridPen); dc.SetPen(gridPen);
for( const auto &label : mMinorLabels ) { for( const auto &label : cache.mMinorLabels ) {
gridPos = label.pos; gridPos = label.pos;
if(mOrientation == wxHORIZONTAL) { if(mOrientation == wxHORIZONTAL) {
if((gridPos != 0) && (gridPos != gridLineLength)) if((gridPos != 0) && (gridPos != gridLineLength))
@@ -1510,7 +1518,7 @@ void Ruler::DrawGrid(wxDC& dc,
if(majorGrid && (gridLineLength != 0 )) { if(majorGrid && (gridLineLength != 0 )) {
gridPen.SetColour(127, 127, 127); // light grey gridPen.SetColour(127, 127, 127); // light grey
dc.SetPen(gridPen); dc.SetPen(gridPen);
for( const auto &label : mMajorLabels ) { for( const auto &label : cache.mMajorLabels ) {
gridPos = label.pos; gridPos = label.pos;
if(mOrientation == wxHORIZONTAL) { if(mOrientation == wxHORIZONTAL) {
if((gridPos != 0) && (gridPos != gridLineLength)) if((gridPos != 0) && (gridPos != gridLineLength))
@@ -1553,25 +1561,28 @@ int Ruler::FindZero( const Labels &labels ) const
int Ruler::GetZeroPosition() const int Ruler::GetZeroPosition() const
{ {
wxASSERT( mpCache );
auto &cache = *mpCache;
int zero; int zero;
if( (zero = FindZero( mMajorLabels ) ) < 0) if( (zero = FindZero( cache.mMajorLabels ) ) < 0)
zero = FindZero( mMinorLabels ); zero = FindZero( cache.mMinorLabels );
// PRL: don't consult minor minor?? // PRL: don't consult minor minor??
return zero; return zero;
} }
void Ruler::GetMaxSize(wxCoord *width, wxCoord *height) void Ruler::GetMaxSize(wxCoord *width, wxCoord *height)
{ {
if (!mValid) { if ( !mpCache ) {
wxScreenDC sdc; wxScreenDC sdc;
Update( sdc, nullptr ); UpdateCache( sdc, nullptr );
} }
auto &cache = *mpCache;
if (width) if (width)
*width = mRect.GetWidth(); *width = cache.mRect.GetWidth();
if (height) if (height)
*height = mRect.GetHeight(); *height = cache.mRect.GetHeight();
} }
@@ -1583,9 +1594,17 @@ void Ruler::SetCustomMode(bool value)
} }
} }
#if 0
// These two unused functions need reconsideration of their interactions with
// the cache and update
void Ruler::SetCustomMajorLabels( void Ruler::SetCustomMajorLabels(
const TranslatableStrings &labels, int start, int step) const TranslatableStrings &labels, int start, int step)
{ {
SetCustomMode( true );
mpCache = std::make_unique<Cache>();
auto &cache = *mpCache;
auto &mMajorLabels = cache.mMajorLabels;
const auto numLabel = labels.size(); const auto numLabel = labels.size();
mMajorLabels.resize( numLabel ); mMajorLabels.resize( numLabel );
@@ -1593,12 +1612,16 @@ void Ruler::SetCustomMajorLabels(
mMajorLabels[i].text = labels[i]; mMajorLabels[i].text = labels[i];
mMajorLabels[i].pos = start + i*step; mMajorLabels[i].pos = start + i*step;
} }
//Remember: DELETE majorlabels....
} }
void Ruler::SetCustomMinorLabels( void Ruler::SetCustomMinorLabels(
const TranslatableStrings &labels, int start, int step) const TranslatableStrings &labels, int start, int step)
{ {
SetCustomMode( true );
mpCache = std::make_unique<Cache>();
auto &cache = *mpCache;
auto &mMinorLabels = cache.mMinorLabels;
const auto numLabel = labels.size(); const auto numLabel = labels.size();
mMinorLabels.resize( numLabel ); mMinorLabels.resize( numLabel );
@@ -1606,8 +1629,8 @@ void Ruler::SetCustomMinorLabels(
mMinorLabels[i].text = labels[i]; mMinorLabels[i].text = labels[i];
mMinorLabels[i].pos = start + i*step; mMinorLabels[i].pos = start + i*step;
} }
//Remember: DELETE majorlabels....
} }
#endif
void Ruler::Label::Draw(wxDC&dc, bool twoTone, wxColour c) const void Ruler::Label::Draw(wxDC&dc, bool twoTone, wxColour c) const
{ {

View File

@@ -138,12 +138,12 @@ class AUDACITY_DLL_API Ruler {
// //
// Note that it will not erase for you... // Note that it will not erase for you...
void Draw(wxDC& dc); void Draw(wxDC& dc) const;
void Draw(wxDC& dc, const Envelope* envelope); void Draw(wxDC& dc, const Envelope* envelope) const;
// If length <> 0, draws lines perpendiculars to ruler corresponding // If length <> 0, draws lines perpendiculars to ruler corresponding
// to selected ticks (major, minor, or both), in an adjacent window. // to selected ticks (major, minor, or both), in an adjacent window.
// You may need to use the offsets if you are using part of the dc for rulers, borders etc. // You may need to use the offsets if you are using part of the dc for rulers, borders etc.
void DrawGrid(wxDC& dc, int length, bool minor = true, bool major = true, int xOffset = 0, int yOffset = 0); void DrawGrid(wxDC& dc, int length, bool minor = true, bool major = true, int xOffset = 0, int yOffset = 0) const;
// So we can have white ticks on black... // So we can have white ticks on black...
void SetTickColour( const wxColour & colour) void SetTickColour( const wxColour & colour)
@@ -169,14 +169,14 @@ class AUDACITY_DLL_API Ruler {
using Bits = std::vector< bool >; using Bits = std::vector< bool >;
void ChooseFonts( wxDC &dc ) const; void ChooseFonts( wxDC &dc ) const;
void Update( wxDC &dc, const Envelope* envelope );
void UpdateCache( wxDC &dc, const Envelope* envelope ) const;
struct Updater; struct Updater;
public: public:
bool mbTicksOnly; // true => no line the length of the ruler bool mbTicksOnly; // true => no line the length of the ruler
bool mbTicksAtExtremes; bool mbTicksAtExtremes;
wxRect mRect;
private: private:
wxColour mTickColour; wxColour mTickColour;
@@ -192,9 +192,6 @@ private:
double mHiddenMin, mHiddenMax; double mHiddenMin, mHiddenMax;
Bits mUserBits; Bits mUserBits;
Bits mBits;
bool mValid;
static std::pair< wxRect, Label > MakeTick( static std::pair< wxRect, Label > MakeTick(
Label lab, Label lab,
@@ -203,17 +200,14 @@ private:
int left, int top, int spacing, int lead, int left, int top, int spacing, int lead,
bool flip, int orientation ); bool flip, int orientation );
Labels mMajorLabels; struct Cache;
Labels mMinorLabels; mutable std::unique_ptr<Cache> mpCache;
Labels mMinorMinorLabels;
// Returns 'zero' label coordinate (for grid drawing) // Returns 'zero' label coordinate (for grid drawing)
int FindZero( const Labels &labels ) const; int FindZero( const Labels &labels ) const;
public:
int GetZeroPosition() const; int GetZeroPosition() const;
private:
int mOrientation; int mOrientation;
int mSpacing; int mSpacing;
double mDbMirrorValue; double mDbMirrorValue;