mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-22 23:30:07 +02:00
More restructuring of Ruler update code
This commit is contained in:
commit
c56a10c5bb
@ -24,6 +24,7 @@ enum NumberScaleType {
|
||||
nstPeriod,
|
||||
|
||||
nstNumScaleTypes,
|
||||
nstNone,
|
||||
};
|
||||
|
||||
|
||||
@ -31,7 +32,7 @@ class NumberScale
|
||||
{
|
||||
public:
|
||||
NumberScale()
|
||||
: mType(nstLinear), mValue0(0), mValue1(1)
|
||||
: mType(nstNone), mValue0(0), mValue1(1)
|
||||
{}
|
||||
|
||||
NumberScale(NumberScaleType type, float value0, float value1)
|
||||
@ -39,6 +40,7 @@ public:
|
||||
{
|
||||
switch (mType) {
|
||||
case nstLinear:
|
||||
case nstNone:
|
||||
{
|
||||
mValue0 = value0;
|
||||
mValue1 = value1;
|
||||
@ -156,6 +158,7 @@ public:
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
case nstNone:
|
||||
return mValue0 + pp * (mValue1 - mValue0);
|
||||
case nstLogarithmic:
|
||||
return exp(mValue0 + pp * (mValue1 - mValue0));
|
||||
@ -186,6 +189,7 @@ public:
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
case nstNone:
|
||||
case nstLogarithmic:
|
||||
return mValue;
|
||||
case nstMel:
|
||||
@ -203,6 +207,7 @@ public:
|
||||
{
|
||||
switch (mType) {
|
||||
case nstLinear:
|
||||
case nstNone:
|
||||
case nstMel:
|
||||
case nstBark:
|
||||
case nstErb:
|
||||
@ -230,6 +235,7 @@ public:
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
case nstNone:
|
||||
case nstMel:
|
||||
case nstBark:
|
||||
case nstErb:
|
||||
@ -253,6 +259,7 @@ public:
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
case nstNone:
|
||||
return ((val - mValue0) / (mValue1 - mValue0));
|
||||
case nstLogarithmic:
|
||||
return ((log(val) - mValue0) / (mValue1 - mValue0));
|
||||
|
@ -193,7 +193,7 @@ void SpectrumVRulerControls::DoUpdateVRuler(
|
||||
NumberScale scale(
|
||||
wt->GetSpectrogramSettings().GetScale( minFreq, maxFreq )
|
||||
.Reversal() );
|
||||
vruler->SetNumberScale(&scale);
|
||||
vruler->SetNumberScale(scale);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -120,7 +120,6 @@ void WaveformVZoomHandle::DoZoom(
|
||||
const float halfrate = rate / 2;
|
||||
float maxFreq = 8000.0;
|
||||
const SpectrogramSettings &specSettings = pTrack->GetSpectrogramSettings();
|
||||
NumberScale scale;
|
||||
|
||||
bool bDragZoom = WaveTrackVZoomHandle::IsDragZooming(zoomStart, zoomEnd);
|
||||
// Add 100 if spectral to separate the kinds of zoom.
|
||||
|
@ -78,7 +78,6 @@ using std::max;
|
||||
//
|
||||
|
||||
Ruler::Ruler()
|
||||
: mpNumberScale{}
|
||||
{
|
||||
mMin = mHiddenMin = 0.0;
|
||||
mMax = mHiddenMax = 100.0;
|
||||
@ -110,19 +109,11 @@ Ruler::Ruler()
|
||||
fontSize = 8;
|
||||
#endif
|
||||
|
||||
mUserFonts = false;
|
||||
|
||||
mLength = 0;
|
||||
|
||||
mValid = false;
|
||||
|
||||
mCustom = false;
|
||||
mbMinor = true;
|
||||
|
||||
mGridLineLength = 0;
|
||||
mMajorGrid = false;
|
||||
mMinorGrid = false;
|
||||
|
||||
mTwoTone = false;
|
||||
|
||||
mUseZoomInfo = NULL;
|
||||
@ -266,48 +257,47 @@ void Ruler::SetMinor(bool value)
|
||||
|
||||
namespace {
|
||||
void FindFontHeights(
|
||||
wxCoord &height, wxCoord &lead,
|
||||
wxDC &dc, int fontSize, wxFontWeight weight = wxFONTWEIGHT_NORMAL )
|
||||
wxCoord &height, wxCoord &lead, wxDC &dc, const wxFont &font )
|
||||
{
|
||||
wxCoord strW, strH, strD, strL;
|
||||
static const wxString exampleText = wxT("0.9"); //ignored for height calcs on all platforms
|
||||
dc.SetFont(wxFont(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, weight));
|
||||
dc.SetFont( font );
|
||||
dc.GetTextExtent(exampleText, &strW, &strH, &strD, &strL);
|
||||
height = strH - strD - strL;
|
||||
lead = strL;
|
||||
}
|
||||
|
||||
void FindFontHeights(
|
||||
wxCoord &height, wxCoord &lead,
|
||||
wxDC &dc, int fontSize, wxFontWeight weight = wxFONTWEIGHT_NORMAL )
|
||||
{
|
||||
const wxFont font{ fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, weight };
|
||||
FindFontHeights( height, lead, dc, font );
|
||||
}
|
||||
}
|
||||
|
||||
void Ruler::SetFonts(const wxFont &minorFont, const wxFont &majorFont, const wxFont &minorMinorFont)
|
||||
{
|
||||
mFonts.minorMinor = minorMinorFont;
|
||||
mFonts.minor = minorFont;
|
||||
mFonts.major = majorFont;
|
||||
|
||||
// Won't override these fonts
|
||||
mUserFonts = true;
|
||||
|
||||
mpUserFonts = std::make_unique<Fonts>(
|
||||
Fonts{ majorFont, minorFont, minorMinorFont, 0 } );
|
||||
|
||||
wxScreenDC dc;
|
||||
wxCoord height;
|
||||
FindFontHeights( height, mFonts.lead, dc, majorFont.GetPointSize() );
|
||||
FindFontHeights( height, mpUserFonts->lead, dc, majorFont );
|
||||
|
||||
mpFonts.reset();
|
||||
mpFonts.reset();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void Ruler::SetNumberScale(const NumberScale *pScale)
|
||||
void Ruler::SetNumberScale(const NumberScale &scale)
|
||||
{
|
||||
if (!pScale) {
|
||||
if (mpNumberScale) {
|
||||
mpNumberScale.reset();
|
||||
if ( mNumberScale != scale ) {
|
||||
mNumberScale = scale;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!mpNumberScale || *mpNumberScale != *pScale) {
|
||||
mpNumberScale = std::make_unique<NumberScale>(*pScale);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ruler::OfflimitsPixels(int start, int end)
|
||||
@ -355,14 +345,12 @@ void Ruler::SetBounds(int left, int top, int right, int bottom)
|
||||
|
||||
void Ruler::Invalidate()
|
||||
{
|
||||
mValid = false;
|
||||
|
||||
if (mOrientation == wxHORIZONTAL)
|
||||
mLength = mRight-mLeft;
|
||||
else
|
||||
mLength = mBottom-mTop;
|
||||
|
||||
mBits.clear();
|
||||
mpCache.reset();
|
||||
mUserBits.clear();
|
||||
}
|
||||
|
||||
@ -858,24 +846,41 @@ auto Ruler::MakeTick(
|
||||
return { { strLeft, strTop, strW, strH }, lab };
|
||||
}
|
||||
|
||||
struct Ruler::TickOutputs{ Labels &labels; Bits &bits; wxRect &box; };
|
||||
struct Ruler::Updater {
|
||||
const Ruler &mRuler;
|
||||
const ZoomInfo *zoomInfo;
|
||||
|
||||
explicit Updater( const Ruler &ruler, const ZoomInfo *z )
|
||||
: mRuler{ ruler }
|
||||
, zoomInfo{ z }
|
||||
{}
|
||||
|
||||
const double mDbMirrorValue = mRuler.mDbMirrorValue;
|
||||
const int mLength = mRuler.mLength;
|
||||
const RulerFormat mFormat = mRuler.mFormat;
|
||||
const TranslatableString mUnits = mRuler.mUnits;
|
||||
|
||||
const int mLeft = mRuler.mLeft;
|
||||
const int mTop = mRuler.mTop;
|
||||
const int mBottom = mRuler.mBottom;
|
||||
const int mRight = mRuler.mRight;
|
||||
|
||||
const int mSpacing = mRuler.mSpacing;
|
||||
const int mOrientation = mRuler.mOrientation;
|
||||
const int mLead = mRuler.mFonts.lead;
|
||||
const bool mFlip = mRuler.mFlip;
|
||||
|
||||
explicit Updater( const Ruler &ruler )
|
||||
: mRuler( ruler )
|
||||
{}
|
||||
const bool mCustom = mRuler.mCustom;
|
||||
const Fonts &mFonts = *mRuler.mpFonts;
|
||||
const bool mLog = mRuler.mLog;
|
||||
const double mHiddenMin = mRuler.mHiddenMin;
|
||||
const double mHiddenMax = mRuler.mHiddenMax;
|
||||
const bool mLabelEdges = mRuler.mLabelEdges;
|
||||
const double mMin = mRuler.mMin;
|
||||
const double mMax = mRuler.mMax;
|
||||
const int mLeftOffset = mRuler.mLeftOffset;
|
||||
const NumberScale mNumberScale = mRuler.mNumberScale;
|
||||
|
||||
struct TickOutputs;
|
||||
|
||||
bool Tick( wxDC &dc,
|
||||
int pos, double d, const TickSizes &tickSizes, wxFont font,
|
||||
@ -886,6 +891,36 @@ struct Ruler::Updater {
|
||||
bool TickCustom( wxDC &dc, int labelIdx, wxFont font,
|
||||
TickOutputs outputs
|
||||
) const;
|
||||
|
||||
static void ChooseFonts(
|
||||
std::unique_ptr<Fonts> &pFonts, const Fonts *pUserFonts,
|
||||
wxDC &dc, int desiredPixelHeight );
|
||||
|
||||
struct UpdateOutputs;
|
||||
|
||||
void Update(
|
||||
wxDC &dc, const Envelope* envelope,
|
||||
UpdateOutputs &allOutputs
|
||||
)// Envelope *speedEnv, long minSpeed, long maxSpeed )
|
||||
const;
|
||||
|
||||
void UpdateCustom( wxDC &dc, UpdateOutputs &allOutputs ) const;
|
||||
void UpdateLinear(
|
||||
wxDC &dc, const Envelope *envelope, UpdateOutputs &allOutputs ) const;
|
||||
void UpdateNonlinear( wxDC &dc, UpdateOutputs &allOutputs ) 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::UpdateOutputs {
|
||||
Labels &majorLabels, &minorLabels, &minorMinorLabels;
|
||||
Bits &bits;
|
||||
wxRect &box;
|
||||
};
|
||||
|
||||
bool Ruler::Updater::Tick( wxDC &dc,
|
||||
@ -911,7 +946,7 @@ bool Ruler::Updater::Tick( wxDC &dc,
|
||||
lab,
|
||||
dc, font,
|
||||
outputs.bits,
|
||||
mLeft, mTop, mSpacing, mLead,
|
||||
mLeft, mTop, mSpacing, mFonts.lead,
|
||||
mFlip,
|
||||
mOrientation );
|
||||
|
||||
@ -940,7 +975,7 @@ bool Ruler::Updater::TickCustom( wxDC &dc, int labelIdx, wxFont font,
|
||||
|
||||
dc, font,
|
||||
outputs.bits,
|
||||
mLeft, mTop, mSpacing, mLead,
|
||||
mLeft, mTop, mSpacing, mFonts.lead,
|
||||
mFlip,
|
||||
mOrientation );
|
||||
|
||||
@ -971,8 +1006,21 @@ static constexpr int MaxPixelHeight =
|
||||
#endif
|
||||
;
|
||||
|
||||
void Ruler::ChooseFonts( Fonts &fonts, wxDC &dc, int desiredPixelHeight )
|
||||
void Ruler::Updater::ChooseFonts(
|
||||
std::unique_ptr<Fonts> &pFonts, const Fonts *pUserFonts,
|
||||
wxDC &dc, int desiredPixelHeight )
|
||||
{
|
||||
if ( pFonts )
|
||||
return;
|
||||
|
||||
if ( pUserFonts ) {
|
||||
pFonts = std::make_unique<Fonts>( *pUserFonts );
|
||||
return;
|
||||
}
|
||||
|
||||
pFonts = std::make_unique<Fonts>( Fonts{ {}, {}, {}, 0 } );
|
||||
auto &fonts = *pFonts;
|
||||
|
||||
int fontSize = 4;
|
||||
|
||||
desiredPixelHeight =
|
||||
@ -993,69 +1041,25 @@ void Ruler::ChooseFonts( Fonts &fonts, wxDC &dc, int desiredPixelHeight )
|
||||
fonts.minorMinor = wxFont{ fontSize - 1, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL };
|
||||
}
|
||||
|
||||
void Ruler::Update(
|
||||
wxDC &dc, const Envelope* envelope )// Envelope *speedEnv, long minSpeed, long maxSpeed )
|
||||
void Ruler::Updater::UpdateCustom( wxDC &dc, UpdateOutputs &allOutputs ) const
|
||||
{
|
||||
const ZoomInfo *zoomInfo = NULL;
|
||||
if (!mLog && mOrientation == wxHORIZONTAL)
|
||||
zoomInfo = mUseZoomInfo;
|
||||
|
||||
// This gets called when something has been changed
|
||||
// (i.e. we've been invalidated). Recompute all
|
||||
// tick positions and font size.
|
||||
|
||||
if (!mUserFonts) {
|
||||
ChooseFonts( mFonts, dc,
|
||||
mOrientation == wxHORIZONTAL
|
||||
? mBottom - mTop - 5 // height less ticks and 1px gap
|
||||
: MaxPixelHeight
|
||||
);
|
||||
}
|
||||
|
||||
// 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
|
||||
// division by zero. So...
|
||||
// IF too small THEN bail out and don't draw.
|
||||
if( mLength <= 0 )
|
||||
return;
|
||||
|
||||
if (mOrientation == wxHORIZONTAL)
|
||||
mRect = wxRect(0,0, mLength,0);
|
||||
else
|
||||
mRect = wxRect(0,0, 0,mLength);
|
||||
|
||||
// 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
|
||||
// mCustom is false!!!!
|
||||
|
||||
if(!mCustom) {
|
||||
mMajorLabels.clear();
|
||||
mMinorLabels.clear();
|
||||
mMinorMinorLabels.clear();
|
||||
}
|
||||
|
||||
mBits = mUserBits;
|
||||
mBits.resize( static_cast<size_t>(mLength + 1), false );
|
||||
|
||||
// Keep Updater const! We want no hidden state changes affecting its
|
||||
// computations.
|
||||
const Updater updater{ *this };
|
||||
|
||||
TickOutputs majorOutputs{ mMajorLabels, mBits, mRect };
|
||||
|
||||
// *************** Label calculation routine **************
|
||||
if( mCustom ) {
|
||||
TickOutputs majorOutputs{
|
||||
allOutputs.majorLabels, allOutputs.bits, allOutputs.box };
|
||||
|
||||
// SET PARAMETER IN MCUSTOM CASE
|
||||
// Works only with major labels
|
||||
|
||||
int numLabel = mMajorLabels.size();
|
||||
int numLabel = allOutputs.majorLabels.size();
|
||||
|
||||
for( int i = 0; (i<numLabel) && (i<=mLength); ++i )
|
||||
updater.TickCustom( dc, i, mFonts.major, majorOutputs );
|
||||
TickCustom( dc, i, mFonts.major, majorOutputs );
|
||||
}
|
||||
|
||||
}
|
||||
else if( !mLog ) {
|
||||
void Ruler::Updater::UpdateLinear(
|
||||
wxDC &dc, const Envelope *envelope, UpdateOutputs &allOutputs ) const
|
||||
{
|
||||
TickOutputs majorOutputs{
|
||||
allOutputs.majorLabels, allOutputs.bits, allOutputs.box };
|
||||
|
||||
// Use the "hidden" min and max to determine the tick size.
|
||||
// That may make a difference with fisheye.
|
||||
@ -1065,7 +1069,7 @@ void Ruler::Update(
|
||||
TickSizes tickSizes{ UPP, mOrientation, mFormat, false };
|
||||
|
||||
auto TickAtValue =
|
||||
[this, zoomInfo, &tickSizes, &dc, &updater, &majorOutputs]
|
||||
[this, &tickSizes, &dc, &majorOutputs]
|
||||
( double value ) -> int {
|
||||
// Make a tick only if the value is strictly between the bounds
|
||||
if ( value <= std::min( mMin, mMax ) )
|
||||
@ -1085,7 +1089,7 @@ void Ruler::Update(
|
||||
|
||||
const int iMaxPos = (mOrientation == wxHORIZONTAL) ? mRight : mBottom - 5;
|
||||
if (mid >= 0 && mid < iMaxPos)
|
||||
updater.Tick( dc, mid, value, tickSizes, mFonts.major, majorOutputs );
|
||||
Tick( dc, mid, value, tickSizes, mFonts.major, majorOutputs );
|
||||
else
|
||||
return -1;
|
||||
|
||||
@ -1108,8 +1112,8 @@ void Ruler::Update(
|
||||
|
||||
// Extreme values
|
||||
if (mLabelEdges) {
|
||||
updater.Tick( dc, 0, mMin, tickSizes, mFonts.major, majorOutputs );
|
||||
updater.Tick( dc, mLength, mMax, tickSizes, mFonts.major, majorOutputs );
|
||||
Tick( dc, 0, mMin, tickSizes, mFonts.major, majorOutputs );
|
||||
Tick( dc, mLength, mMax, tickSizes, mFonts.major, majorOutputs );
|
||||
}
|
||||
|
||||
if ( !mDbMirrorValue ) {
|
||||
@ -1125,8 +1129,8 @@ void Ruler::Update(
|
||||
const double denom = jj == 0 ? tickSizes.mMajor : tickSizes.mMinor;
|
||||
auto font = jj == 0 ? mFonts.major : mFonts.minor;
|
||||
TickOutputs outputs{
|
||||
(jj == 0 ? mMajorLabels : mMinorLabels),
|
||||
mBits, mRect
|
||||
(jj == 0 ? allOutputs.majorLabels : allOutputs.minorLabels),
|
||||
allOutputs.bits, allOutputs.box
|
||||
};
|
||||
int ii = -1, j = 0;
|
||||
double d, warpedD, nextD;
|
||||
@ -1168,7 +1172,7 @@ void Ruler::Update(
|
||||
step = floor(sg * warpedD / denom);
|
||||
bool major = jj == 0;
|
||||
tickSizes.useMajor = major;
|
||||
bool ticked = updater.Tick( dc, ii, sg * step * denom, tickSizes,
|
||||
bool ticked = Tick( dc, ii, sg * step * denom, tickSizes,
|
||||
font, outputs );
|
||||
if( !major && !ticked ){
|
||||
nDroppedMinorLabels++;
|
||||
@ -1182,27 +1186,31 @@ void Ruler::Update(
|
||||
// If we've dropped minor labels through overcrowding, then don't show
|
||||
// any of them. We're allowed though to drop ones which correspond to the
|
||||
// major numbers.
|
||||
if( nDroppedMinorLabels > (mMajorLabels.size() + (mLabelEdges ? 2:0)) ){
|
||||
if( nDroppedMinorLabels >
|
||||
(allOutputs.majorLabels.size() + (mLabelEdges ? 2:0)) ){
|
||||
// Old code dropped the labels AND their ticks, like so:
|
||||
// mMinorLabels.clear();
|
||||
// Nowadays we just drop the labels.
|
||||
for( auto &label : mMinorLabels )
|
||||
for( auto &label : allOutputs.minorLabels )
|
||||
label.text = {};
|
||||
}
|
||||
|
||||
// Left and Right Edges
|
||||
if (mLabelEdges) {
|
||||
updater.Tick( dc, 0, mMin, tickSizes, mFonts.major, majorOutputs );
|
||||
updater.Tick( dc, mLength, mMax, tickSizes, mFonts.major, majorOutputs );
|
||||
Tick( dc, 0, mMin, tickSizes, mFonts.major, majorOutputs );
|
||||
Tick( dc, mLength, mMax, tickSizes, mFonts.major, majorOutputs );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// log case
|
||||
}
|
||||
|
||||
NumberScale numberScale(mpNumberScale
|
||||
? *mpNumberScale
|
||||
: NumberScale(nstLogarithmic, mMin, mMax)
|
||||
);
|
||||
void Ruler::Updater::UpdateNonlinear(
|
||||
wxDC &dc, UpdateOutputs &allOutputs ) const
|
||||
{
|
||||
TickOutputs majorOutputs{
|
||||
allOutputs.majorLabels, allOutputs.bits, allOutputs.box };
|
||||
|
||||
auto numberScale = ( mNumberScale == NumberScale{} )
|
||||
? NumberScale( nstLogarithmic, mMin, mMax )
|
||||
: mNumberScale;
|
||||
|
||||
double UPP = (mHiddenMax-mHiddenMin)/mLength; // Units per pixel
|
||||
TickSizes tickSizes{ UPP, mOrientation, mFormat, true };
|
||||
@ -1226,7 +1234,7 @@ void Ruler::Update(
|
||||
{ val = decade;
|
||||
if(val >= rMin && val < rMax) {
|
||||
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
|
||||
updater.Tick( dc, pos, val, tickSizes, mFonts.major, majorOutputs );
|
||||
Tick( dc, pos, val, tickSizes, mFonts.major, majorOutputs );
|
||||
}
|
||||
}
|
||||
decade *= step;
|
||||
@ -1242,13 +1250,14 @@ void Ruler::Update(
|
||||
}
|
||||
steps++;
|
||||
tickSizes.useMajor = false;
|
||||
TickOutputs minorOutputs{ mMinorLabels, mBits, mRect };
|
||||
TickOutputs minorOutputs{
|
||||
allOutputs.minorLabels, allOutputs.bits, allOutputs.box };
|
||||
for(int i=0; i<=steps; i++) {
|
||||
for(int j=start; j!=end; j+=mstep) {
|
||||
val = decade * j;
|
||||
if(val >= rMin && val < rMax) {
|
||||
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
|
||||
updater.Tick( dc, pos, val, tickSizes, mFonts.minor, minorOutputs );
|
||||
Tick( dc, pos, val, tickSizes, mFonts.minor, minorOutputs );
|
||||
}
|
||||
}
|
||||
decade *= step;
|
||||
@ -1262,7 +1271,8 @@ void Ruler::Update(
|
||||
{ start=100; end= 10; mstep=-1;
|
||||
}
|
||||
steps++;
|
||||
TickOutputs minorMinorOutputs{ mMinorMinorLabels, mBits, mRect };
|
||||
TickOutputs minorMinorOutputs{
|
||||
allOutputs.minorMinorLabels, allOutputs.bits, allOutputs.box };
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
// PRL: Bug1038. Don't label 1.6, rounded, as a duplicate tick for "2"
|
||||
if (!(mFormat == IntFormat && decade < 10.0)) {
|
||||
@ -1271,7 +1281,7 @@ void Ruler::Update(
|
||||
val = decade * f / 10;
|
||||
if (val >= rMin && val < rMax) {
|
||||
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
|
||||
updater.Tick( dc, pos, val, tickSizes,
|
||||
Tick( dc, pos, val, tickSizes,
|
||||
mFonts.minorMinor, minorMinorOutputs );
|
||||
}
|
||||
}
|
||||
@ -1279,28 +1289,45 @@ void Ruler::Update(
|
||||
}
|
||||
decade *= step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ruler::Updater::Update(
|
||||
wxDC &dc, const Envelope* envelope,
|
||||
UpdateOutputs &allOutputs
|
||||
)// Envelope *speedEnv, long minSpeed, long maxSpeed )
|
||||
const
|
||||
{
|
||||
TickOutputs majorOutputs{
|
||||
allOutputs.majorLabels, allOutputs.bits, allOutputs.box };
|
||||
|
||||
if ( mCustom )
|
||||
UpdateCustom( dc, allOutputs );
|
||||
else if ( !mLog )
|
||||
UpdateLinear( dc, envelope, allOutputs );
|
||||
else
|
||||
UpdateNonlinear( dc, allOutputs );
|
||||
|
||||
int displacementx=0, displacementy=0;
|
||||
auto &box = allOutputs.box;
|
||||
if (!mFlip) {
|
||||
if (mOrientation==wxHORIZONTAL) {
|
||||
int d=mTop+mRect.GetHeight()+5;
|
||||
mRect.Offset(0,d);
|
||||
mRect.Inflate(0,5);
|
||||
int d = mTop + box.GetHeight() + 5;
|
||||
box.Offset(0,d);
|
||||
box.Inflate(0,5);
|
||||
displacementx=0;
|
||||
displacementy=d;
|
||||
}
|
||||
else {
|
||||
int d=mLeft-mRect.GetLeft()+5;
|
||||
mRect.Offset(d,0);
|
||||
mRect.Inflate(5,0);
|
||||
int d = mLeft - box.GetLeft() + 5;
|
||||
box.Offset(d,0);
|
||||
box.Inflate(5,0);
|
||||
displacementx=d;
|
||||
displacementy=0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mOrientation==wxHORIZONTAL) {
|
||||
mRect.Inflate(0,5);
|
||||
box.Inflate(0,5);
|
||||
displacementx=0;
|
||||
displacementy=0;
|
||||
}
|
||||
@ -1309,28 +1336,99 @@ void Ruler::Update(
|
||||
label.lx += displacementx;
|
||||
label.ly += displacementy;
|
||||
};
|
||||
for( auto &label : mMajorLabels )
|
||||
for( auto &label : allOutputs.majorLabels )
|
||||
update( label );
|
||||
for( auto &label : mMinorLabels )
|
||||
for( auto &label : allOutputs.minorLabels )
|
||||
update( label );
|
||||
for( auto &label : mMinorMinorLabels )
|
||||
for( auto &label : allOutputs.minorMinorLabels )
|
||||
update( label );
|
||||
|
||||
mValid = true;
|
||||
}
|
||||
|
||||
void Ruler::Draw(wxDC& dc)
|
||||
void Ruler::ChooseFonts( wxDC &dc ) const
|
||||
{
|
||||
Updater::ChooseFonts( mpFonts, mpUserFonts.get(), dc,
|
||||
mOrientation == wxHORIZONTAL
|
||||
? mBottom - mTop - 5 // height less ticks and 1px gap
|
||||
: MaxPixelHeight
|
||||
);
|
||||
}
|
||||
|
||||
void Ruler::UpdateCache(
|
||||
wxDC &dc, const Envelope* envelope )
|
||||
const // Envelope *speedEnv, long minSpeed, long maxSpeed )
|
||||
{
|
||||
if ( mpCache )
|
||||
return;
|
||||
|
||||
const ZoomInfo *zoomInfo = NULL;
|
||||
if (!mLog && mOrientation == wxHORIZONTAL)
|
||||
zoomInfo = mUseZoomInfo;
|
||||
|
||||
// This gets called when something has been changed
|
||||
// (i.e. we've been invalidated). Recompute all
|
||||
// tick positions and font size.
|
||||
|
||||
ChooseFonts( dc );
|
||||
mpCache = std::make_unique< Cache >();
|
||||
auto &cache = *mpCache;
|
||||
|
||||
// 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
|
||||
// division by zero. So...
|
||||
// IF too small THEN bail out and don't draw.
|
||||
if( mLength <= 0 )
|
||||
return;
|
||||
|
||||
if (mOrientation == wxHORIZONTAL)
|
||||
cache.mRect = { 0, 0, mLength, 0 };
|
||||
else
|
||||
cache.mRect = { 0, 0, 0, mLength };
|
||||
|
||||
// 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
|
||||
// mCustom is false!!!!
|
||||
|
||||
if(!mCustom) {
|
||||
cache.mMajorLabels.clear();
|
||||
cache.mMinorLabels.clear();
|
||||
cache.mMinorMinorLabels.clear();
|
||||
}
|
||||
|
||||
cache.mBits = mUserBits;
|
||||
cache.mBits.resize( static_cast<size_t>(mLength + 1), false );
|
||||
|
||||
// Keep Updater const! We want no hidden state changes affecting its
|
||||
// computations.
|
||||
const Updater updater{ *this, zoomInfo };
|
||||
Updater::UpdateOutputs allOutputs{
|
||||
cache.mMajorLabels, cache.mMinorLabels, cache.mMinorMinorLabels,
|
||||
cache.mBits, cache.mRect
|
||||
};
|
||||
updater.Update(dc, envelope, allOutputs);
|
||||
}
|
||||
|
||||
auto Ruler::GetFonts() const -> Fonts
|
||||
{
|
||||
if ( !mpFonts ) {
|
||||
wxScreenDC dc;
|
||||
ChooseFonts( dc );
|
||||
}
|
||||
|
||||
return *mpFonts;
|
||||
}
|
||||
|
||||
void Ruler::Draw(wxDC& dc) const
|
||||
{
|
||||
Draw( dc, NULL);
|
||||
}
|
||||
|
||||
void Ruler::Draw(wxDC& dc, const Envelope* envelope)
|
||||
void Ruler::Draw(wxDC& dc, const Envelope* envelope) const
|
||||
{
|
||||
if( mLength <=0 )
|
||||
return;
|
||||
|
||||
if (!mValid)
|
||||
Update( dc, envelope );
|
||||
UpdateCache( dc, envelope );
|
||||
auto &cache = *mpCache;
|
||||
|
||||
dc.SetTextForeground( mTickColour );
|
||||
#ifdef EXPERIMENTAL_THEMING
|
||||
@ -1361,7 +1459,7 @@ void Ruler::Draw(wxDC& dc, const Envelope* envelope)
|
||||
}
|
||||
}
|
||||
|
||||
dc.SetFont(mFonts.major);
|
||||
dc.SetFont( mpFonts->major );
|
||||
|
||||
// We may want to not show the ticks at the extremes,
|
||||
// though still showing the labels.
|
||||
@ -1395,63 +1493,62 @@ void Ruler::Draw(wxDC& dc, const Envelope* envelope)
|
||||
label.Draw(dc, mTwoTone, mTickColour);
|
||||
};
|
||||
|
||||
for( const auto &label : mMajorLabels )
|
||||
for( const auto &label : cache.mMajorLabels )
|
||||
drawLabel( label, 4 );
|
||||
|
||||
if( mbMinor ) {
|
||||
dc.SetFont(mFonts.minor);
|
||||
for( const auto &label : mMinorLabels )
|
||||
dc.SetFont( mpFonts->minor );
|
||||
for( const auto &label : cache.mMinorLabels )
|
||||
drawLabel( label, 2 );
|
||||
}
|
||||
|
||||
dc.SetFont(mFonts.minorMinor);
|
||||
dc.SetFont( mpFonts->minorMinor );
|
||||
|
||||
for( const auto &label : mMinorMinorLabels )
|
||||
for( const auto &label : cache.mMinorMinorLabels )
|
||||
if ( !label.text.empty() )
|
||||
drawLabel( label, 2 );
|
||||
}
|
||||
|
||||
// ********** Draw grid ***************************
|
||||
void Ruler::DrawGrid(wxDC& dc, int length, bool minor, bool major, int xOffset, int yOffset)
|
||||
void Ruler::DrawGrid(wxDC& dc,
|
||||
const int gridLineLength,
|
||||
const bool minorGrid, const bool majorGrid, int xOffset, int yOffset)
|
||||
const
|
||||
{
|
||||
mGridLineLength = length;
|
||||
mMajorGrid = major;
|
||||
mMinorGrid = minor;
|
||||
|
||||
if ( !mValid )
|
||||
Update( dc, nullptr );
|
||||
UpdateCache( dc, nullptr );
|
||||
auto &cache = *mpCache;
|
||||
|
||||
int gridPos;
|
||||
wxPen gridPen;
|
||||
|
||||
if(mbMinor && (mMinorGrid && (mGridLineLength != 0 ))) {
|
||||
if(mbMinor && (minorGrid && (gridLineLength != 0 ))) {
|
||||
gridPen.SetColour(178, 178, 178); // very light grey
|
||||
dc.SetPen(gridPen);
|
||||
for( const auto &label : mMinorLabels ) {
|
||||
for( const auto &label : cache.mMinorLabels ) {
|
||||
gridPos = label.pos;
|
||||
if(mOrientation == wxHORIZONTAL) {
|
||||
if((gridPos != 0) && (gridPos != mGridLineLength))
|
||||
AColor::Line(dc, gridPos+xOffset, yOffset, gridPos+xOffset, mGridLineLength-1+yOffset);
|
||||
if((gridPos != 0) && (gridPos != gridLineLength))
|
||||
AColor::Line(dc, gridPos+xOffset, yOffset, gridPos+xOffset, gridLineLength-1+yOffset);
|
||||
}
|
||||
else {
|
||||
if((gridPos != 0) && (gridPos != mGridLineLength))
|
||||
AColor::Line(dc, xOffset, gridPos+yOffset, mGridLineLength-1+xOffset, gridPos+yOffset);
|
||||
if((gridPos != 0) && (gridPos != gridLineLength))
|
||||
AColor::Line(dc, xOffset, gridPos+yOffset, gridLineLength-1+xOffset, gridPos+yOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mMajorGrid && (mGridLineLength != 0 )) {
|
||||
if(majorGrid && (gridLineLength != 0 )) {
|
||||
gridPen.SetColour(127, 127, 127); // light grey
|
||||
dc.SetPen(gridPen);
|
||||
for( const auto &label : mMajorLabels ) {
|
||||
for( const auto &label : cache.mMajorLabels ) {
|
||||
gridPos = label.pos;
|
||||
if(mOrientation == wxHORIZONTAL) {
|
||||
if((gridPos != 0) && (gridPos != mGridLineLength))
|
||||
AColor::Line(dc, gridPos+xOffset, yOffset, gridPos+xOffset, mGridLineLength-1+yOffset);
|
||||
if((gridPos != 0) && (gridPos != gridLineLength))
|
||||
AColor::Line(dc, gridPos+xOffset, yOffset, gridPos+xOffset, gridLineLength-1+yOffset);
|
||||
}
|
||||
else {
|
||||
if((gridPos != 0) && (gridPos != mGridLineLength))
|
||||
AColor::Line(dc, xOffset, gridPos+yOffset, mGridLineLength-1+xOffset, gridPos+yOffset);
|
||||
if((gridPos != 0) && (gridPos != gridLineLength))
|
||||
AColor::Line(dc, xOffset, gridPos+yOffset, gridLineLength-1+xOffset, gridPos+yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1460,18 +1557,18 @@ void Ruler::DrawGrid(wxDC& dc, int length, bool minor, bool major, int xOffset,
|
||||
// Draw 'zero' grid line in black
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
if(mOrientation == wxHORIZONTAL) {
|
||||
if(zeroPosition != mGridLineLength)
|
||||
AColor::Line(dc, zeroPosition+xOffset, yOffset, zeroPosition+xOffset, mGridLineLength-1+yOffset);
|
||||
if(zeroPosition != gridLineLength)
|
||||
AColor::Line(dc, zeroPosition+xOffset, yOffset, zeroPosition+xOffset, gridLineLength-1+yOffset);
|
||||
}
|
||||
else {
|
||||
if(zeroPosition != mGridLineLength)
|
||||
AColor::Line(dc, xOffset, zeroPosition+yOffset, mGridLineLength-1+xOffset, zeroPosition+yOffset);
|
||||
if(zeroPosition != gridLineLength)
|
||||
AColor::Line(dc, xOffset, zeroPosition+yOffset, gridLineLength-1+xOffset, zeroPosition+yOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Ruler::FindZero( const Labels &labels )
|
||||
int Ruler::FindZero( const Labels &labels ) const
|
||||
{
|
||||
auto begin = labels.begin(), end = labels.end(),
|
||||
iter = std::find_if( begin, end, []( const Label &label ){
|
||||
@ -1484,35 +1581,52 @@ int Ruler::FindZero( const Labels &labels )
|
||||
return iter->pos;
|
||||
}
|
||||
|
||||
int Ruler::GetZeroPosition()
|
||||
int Ruler::GetZeroPosition() const
|
||||
{
|
||||
wxASSERT( mpCache );
|
||||
auto &cache = *mpCache;
|
||||
int zero;
|
||||
if( (zero = FindZero( mMajorLabels ) ) < 0)
|
||||
zero = FindZero( mMinorLabels );
|
||||
if( (zero = FindZero( cache.mMajorLabels ) ) < 0)
|
||||
zero = FindZero( cache.mMinorLabels );
|
||||
// PRL: don't consult minor minor??
|
||||
return zero;
|
||||
}
|
||||
|
||||
void Ruler::GetMaxSize(wxCoord *width, wxCoord *height)
|
||||
{
|
||||
if (!mValid) {
|
||||
if ( !mpCache ) {
|
||||
wxScreenDC sdc;
|
||||
Update( sdc, nullptr );
|
||||
UpdateCache( sdc, nullptr );
|
||||
}
|
||||
|
||||
auto &cache = *mpCache;
|
||||
if (width)
|
||||
*width = mRect.GetWidth();
|
||||
*width = cache.mRect.GetWidth();
|
||||
|
||||
if (height)
|
||||
*height = mRect.GetHeight();
|
||||
*height = cache.mRect.GetHeight();
|
||||
}
|
||||
|
||||
|
||||
void Ruler::SetCustomMode(bool value) { mCustom = value; }
|
||||
void Ruler::SetCustomMode(bool value)
|
||||
{
|
||||
if ( mCustom != value ) {
|
||||
mCustom = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// These two unused functions need reconsideration of their interactions with
|
||||
// the cache and update
|
||||
void Ruler::SetCustomMajorLabels(
|
||||
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();
|
||||
mMajorLabels.resize( numLabel );
|
||||
|
||||
@ -1520,12 +1634,16 @@ void Ruler::SetCustomMajorLabels(
|
||||
mMajorLabels[i].text = labels[i];
|
||||
mMajorLabels[i].pos = start + i*step;
|
||||
}
|
||||
//Remember: DELETE majorlabels....
|
||||
}
|
||||
|
||||
void Ruler::SetCustomMinorLabels(
|
||||
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();
|
||||
mMinorLabels.resize( numLabel );
|
||||
|
||||
@ -1533,8 +1651,8 @@ void Ruler::SetCustomMinorLabels(
|
||||
mMinorLabels[i].text = labels[i];
|
||||
mMinorLabels[i].pos = start + i*step;
|
||||
}
|
||||
//Remember: DELETE majorlabels....
|
||||
}
|
||||
#endif
|
||||
|
||||
void Ruler::Label::Draw(wxDC&dc, bool twoTone, wxColour c) const
|
||||
{
|
||||
@ -1553,8 +1671,15 @@ void Ruler::Label::Draw(wxDC&dc, bool twoTone, wxColour c) const
|
||||
|
||||
void Ruler::SetUseZoomInfo(int leftOffset, const ZoomInfo *zoomInfo)
|
||||
{
|
||||
|
||||
if ( mLeftOffset != leftOffset ||
|
||||
// Hm, is this invalidation sufficient? What if *zoomInfo changes under us?
|
||||
mUseZoomInfo != zoomInfo
|
||||
) {
|
||||
mLeftOffset = leftOffset;
|
||||
mUseZoomInfo = zoomInfo;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define __AUDACITY_RULER__
|
||||
|
||||
#include "wxPanelWrapper.h" // to inherit
|
||||
#include "../NumberScale.h" // member variable
|
||||
|
||||
#include <wx/colour.h> // member variable
|
||||
#include <wx/pen.h> // member variable
|
||||
@ -20,7 +21,6 @@ class wxArrayString;
|
||||
class wxDC;
|
||||
class wxFont;
|
||||
|
||||
class NumberScale;
|
||||
class Envelope;
|
||||
class ZoomInfo;
|
||||
|
||||
@ -102,11 +102,9 @@ class AUDACITY_DLL_API Ruler {
|
||||
wxFont major, minor, minorMinor;
|
||||
int lead;
|
||||
};
|
||||
Fonts GetFonts() const
|
||||
{ return mFonts; }
|
||||
Fonts GetFonts() const;
|
||||
|
||||
// Copies *pScale if it is not NULL
|
||||
void SetNumberScale(const NumberScale *pScale);
|
||||
void SetNumberScale(const NumberScale &scale);
|
||||
|
||||
// The ruler will not draw text within this (pixel) range.
|
||||
// Use this if you have another graphic object obscuring part
|
||||
@ -140,12 +138,12 @@ class AUDACITY_DLL_API Ruler {
|
||||
//
|
||||
|
||||
// Note that it will not erase for you...
|
||||
void Draw(wxDC& dc);
|
||||
void Draw(wxDC& dc, const Envelope* envelope);
|
||||
void Draw(wxDC& dc) const;
|
||||
void Draw(wxDC& dc, const Envelope* envelope) const;
|
||||
// If length <> 0, draws lines perpendiculars to ruler corresponding
|
||||
// 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.
|
||||
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...
|
||||
void SetTickColour( const wxColour & colour)
|
||||
@ -170,16 +168,15 @@ class AUDACITY_DLL_API Ruler {
|
||||
|
||||
using Bits = std::vector< bool >;
|
||||
|
||||
static void ChooseFonts( Fonts &fonts, wxDC &dc, int desiredPixelHeight );
|
||||
void Update( wxDC &dc, const Envelope* envelope );
|
||||
void ChooseFonts( wxDC &dc ) const;
|
||||
|
||||
void UpdateCache( wxDC &dc, const Envelope* envelope ) const;
|
||||
|
||||
struct TickOutputs;
|
||||
struct Updater;
|
||||
|
||||
public:
|
||||
bool mbTicksOnly; // true => no line the length of the ruler
|
||||
bool mbTicksAtExtremes;
|
||||
wxRect mRect;
|
||||
|
||||
private:
|
||||
wxColour mTickColour;
|
||||
@ -188,16 +185,13 @@ private:
|
||||
int mLeft, mTop, mRight, mBottom;
|
||||
int mLength;
|
||||
|
||||
Fonts mFonts;
|
||||
bool mUserFonts;
|
||||
std::unique_ptr<Fonts> mpUserFonts;
|
||||
mutable std::unique_ptr<Fonts> mpFonts;
|
||||
|
||||
double mMin, mMax;
|
||||
double mHiddenMin, mHiddenMax;
|
||||
|
||||
Bits mUserBits;
|
||||
Bits mBits;
|
||||
|
||||
bool mValid;
|
||||
|
||||
static std::pair< wxRect, Label > MakeTick(
|
||||
Label lab,
|
||||
@ -206,17 +200,14 @@ private:
|
||||
int left, int top, int spacing, int lead,
|
||||
bool flip, int orientation );
|
||||
|
||||
Labels mMajorLabels;
|
||||
Labels mMinorLabels;
|
||||
Labels mMinorMinorLabels;
|
||||
struct Cache;
|
||||
mutable std::unique_ptr<Cache> mpCache;
|
||||
|
||||
// Returns 'zero' label coordinate (for grid drawing)
|
||||
int FindZero( const Labels &labels );
|
||||
int FindZero( const Labels &labels ) const;
|
||||
|
||||
public:
|
||||
int GetZeroPosition();
|
||||
int GetZeroPosition() const;
|
||||
|
||||
private:
|
||||
int mOrientation;
|
||||
int mSpacing;
|
||||
double mDbMirrorValue;
|
||||
@ -227,15 +218,12 @@ private:
|
||||
bool mFlip;
|
||||
bool mCustom;
|
||||
bool mbMinor;
|
||||
bool mMajorGrid; // for grid drawing
|
||||
bool mMinorGrid; // .
|
||||
int mGridLineLength; // end
|
||||
TranslatableString mUnits;
|
||||
bool mTwoTone;
|
||||
const ZoomInfo *mUseZoomInfo;
|
||||
int mLeftOffset;
|
||||
|
||||
std::unique_ptr<NumberScale> mpNumberScale;
|
||||
NumberScale mNumberScale;
|
||||
};
|
||||
|
||||
class AUDACITY_DLL_API RulerPanel final : public wxPanelWrapper {
|
||||
|
Loading…
x
Reference in New Issue
Block a user