Change DoGetPreferredSize() to use a callback function

Instead of taking an array of scales, call GetNextAvailableScale() to
get them.

This allows centralising the logic for returning the available scales in
a single place, where it will be reused in the upcoming commits.
This commit is contained in:
Vadim Zeitlin 2022-06-01 23:41:34 +01:00
parent 66d4f75c86
commit 36abfe973a
4 changed files with 107 additions and 63 deletions

View file

@ -227,10 +227,19 @@ protected:
// Standard implementation of GetPreferredBitmapSizeAtScale(): choose the
// scale closest to the given one from the available bitmap scales.
//
// Note that scales *must* be sorted in increasing scale order and there
// must be at least 1 of them.
wxSize
DoGetPreferredSize(double scale, size_t n, const double *availableScales) const;
// If this function is used, GetNextAvailableScale() must be overridden!
wxSize DoGetPreferredSize(double scale) const;
// Override this function if DoGetPreferredSize() is used: it can use the
// provided parameter as an internal index, it's guaranteed to be 0 when
// calling this function for the first time. When there are no more scales,
// return 0.
//
// This function is not pure virtual because it doesn't need to be
// implemented if DoGetPreferredSize() is never used, but it will assert if
// it's called.
virtual double GetNextAvailableScale(size_t& i) const;
virtual ~wxBitmapBundleImpl();

View file

@ -500,25 +500,28 @@ protected:
trying to choose one of the available scales, to avoid actually
rescaling the bitmaps.
Typically this function is used in the derived classes implementation,
e.g.
It relies on GetNextAvailableScale() to get information about the
available bitmaps, so that function must be overridden if this one is
used.
Typically this function is used in the derived classes implementation
to forward GetPreferredBitmapSizeAtScale() to it, e.g.
@code
class MyCustomBitmapBundleImpl : public wxBitmapBundleImpl
{
public:
wxSize GetPreferredBitmapSizeAtScale(double scale) const wxOVERRIDE
{
std::vector<double> vec;
vec.push_back(1);
return DoGetPreferredSize(scale);
}
// Note that the vector must be sorted, so we must add this
// scale before adding 2 below.
if ( MyIntermediateBitmapIsAvailable() )
vec.push_back(1.5);
protected:
double GetNextAvailableScale(size_t& i) const wxOVERRIDE
{
const double availableScales[] = { 1, 1.5, 2, 0 };
vec.push_back(2);
return DoGetPreferredSize(scale, vec.size(), vec.data());
// We can rely on not being called again once we return 0.
return availableScales[i++];
}
...
@ -527,17 +530,29 @@ protected:
@param scale The required scale, typically the same one as passed to
GetPreferredBitmapSizeAtScale().
@param n The number of elements in @a availableScales, must be strictly
positive (i.e. there must always be at least one available scale).
@param availableScales The scales in which bitmaps are available, i.e.
scales such that GetBitmap() wouldn't need to scale the bitmap if
it were called with them. This array @e must be in sorted order,
with 1 being its first element.
@since 3.1.7
*/
wxSize
DoGetPreferredSize(double scale, size_t n, const double *availableScales) const;
wxSize DoGetPreferredSize(double scale) const;
/**
Return information about the available bitmaps.
Overriding this function is optional and only needs to be done if
DoGetPreferredSize() is called. If you do override it, this function
must return the next available scale or 0.0 if there are no more.
The returned scales must be in ascending order and the first returned
scale, for the initial @a i value of 0, should be 1. The function must
change @a i, but the values of this index don't have to be consecutive
and it's only used by this function itself, the caller only initializes
it to 0 before the first call.
See DoGetPreferredSize() for an example of implementing this function.
@since 3.1.7
*/
virtual double GetNextAvailableScale(size_t& i) const;
};
/**

View file

@ -133,6 +133,9 @@ public:
virtual wxSize GetPreferredBitmapSizeAtScale(double scale) const wxOVERRIDE;
virtual wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE;
protected:
virtual double GetNextAvailableScale(size_t& i) const wxOVERRIDE;
private:
// Struct containing bitmap itself as well as a flag indicating whether we
// generated it by rescaling the existing bitmap or not.
@ -236,22 +239,24 @@ wxSize wxBitmapBundleImplSet::GetDefaultSize() const
return m_sizeDefault;
}
wxSize wxBitmapBundleImplSet::GetPreferredBitmapSizeAtScale(double scale) const
double wxBitmapBundleImplSet::GetNextAvailableScale(size_t& i) const
{
const double baseY = GetDefaultSize().y;
const size_t n = m_entries.size();
wxVector<double> scales;
scales.reserve(n);
for ( size_t i = 0; i < n; ++i )
while ( i < m_entries.size() )
{
if ( m_entries[i].generated )
const Entry& entry = m_entries[i++];
if ( entry.generated )
continue;
scales.push_back(m_entries[i].bitmap.GetSize().y / baseY);
return static_cast<double>(entry.bitmap.GetSize().y) / GetDefaultSize().y;
}
return DoGetPreferredSize(scale, scales.size(), &scales[0]);
return 0.0;
}
wxSize wxBitmapBundleImplSet::GetPreferredBitmapSizeAtScale(double scale) const
{
return DoGetPreferredSize(scale);
}
wxBitmap wxBitmapBundleImplSet::GetBitmap(const wxSize& size)
@ -703,19 +708,47 @@ wxBitmapBundle::CreateImageList(wxWindow* win,
// wxBitmapBundleImpl implementation
// ============================================================================
wxSize
wxBitmapBundleImpl::DoGetPreferredSize(double scaleTarget,
size_t n,
const double* availableScales) const
double
wxBitmapBundleImpl::GetNextAvailableScale(size_t& WXUNUSED(i)) const
{
wxCHECK_MSG( n > 0, wxSize(), wxS("must have at least one scale") );
wxFAIL_MSG( wxS("must be overridden if called") );
return 0.0;
}
wxSize
wxBitmapBundleImpl::DoGetPreferredSize(double scaleTarget) const
{
double scaleBest = 0.0;
double scaleLast = 0.0;
for ( size_t i = 0; i < n; ++i )
for ( size_t i = 0;; )
{
const double scaleThis = availableScales[i];
const double scaleThis = GetNextAvailableScale(i);
if ( scaleThis == 0.0 )
{
// We only get here if the target scale is bigger than all the
// available scales, in which case we have no choice but to use the
// biggest bitmap, which corresponds to the last used scale that we
// should have by now.
wxASSERT_MSG( scaleLast != 0.0, "must have some available scales" );
// But check how far is it from the requested scale: if it's more than
// 1.5 times larger, we should still scale it, notably to ensure that
// bitmaps of standard size are scaled when 2x DPI scaling is used.
if ( scaleTarget > 1.5*scaleLast )
{
// However scaling by non-integer scales doesn't work well at all, so
// round it to the closest integer in this case.
scaleBest = wxRound(scaleTarget);
}
else // Target scale is not much greater than the biggest one we have.
{
scaleBest = scaleLast;
}
break;
}
// Ensure we remember the last used scale value.
wxON_BLOCK_EXIT_SET(scaleLast, scaleThis);
@ -735,7 +768,7 @@ wxBitmapBundleImpl::DoGetPreferredSize(double scaleTarget,
// We've found the closest bigger bitmap.
// If there is no smaller bitmap, we have no choice but to use this one.
if ( i == 0 )
if ( scaleLast == 0.0 )
{
scaleBest = scaleThis;
break;
@ -751,27 +784,6 @@ wxBitmapBundleImpl::DoGetPreferredSize(double scaleTarget,
break;
}
if ( scaleBest == 0.0 )
{
// We only get here if the target scale is bigger than all the
// available scales, in which case we have no choice but to use the
// biggest bitmap, which corresponds to the last used scale.
// But check how far is it from the requested scale: if it's more than
// 1.5 times larger, we should still scale it, notably to ensure that
// bitmaps of standard size are scaled when 2x DPI scaling is used.
if ( scaleTarget > 1.5*scaleLast )
{
// However scaling by non-integer scales doesn't work well at all, so
// round it to the closest integer in this case.
scaleBest = wxRound(scaleTarget);
}
else // Target scale is not much greater than the biggest one we have.
{
scaleBest = scaleLast;
}
}
return GetDefaultSize()*scaleBest;
}

View file

@ -144,6 +144,9 @@ public:
virtual wxSize GetPreferredBitmapSizeAtScale(double scale) const wxOVERRIDE;
virtual wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE;
protected:
virtual double GetNextAvailableScale(size_t& i) const wxOVERRIDE;
private:
// Load the bitmap from the given resource and add it m_bitmaps, after
// rescaling it to the given size if necessary, i.e. if the needed size is
@ -189,6 +192,11 @@ wxSize wxBitmapBundleImplRC::GetDefaultSize() const
return m_bitmaps[0].GetSize();
}
double wxBitmapBundleImplRC::GetNextAvailableScale(size_t& i) const
{
return i < m_resourceInfos.size() ? m_resourceInfos[i++].scale : 0.0;
}
wxSize wxBitmapBundleImplRC::GetPreferredBitmapSizeAtScale(double scale) const
{
const size_t n = m_resourceInfos.size();
@ -198,7 +206,7 @@ wxSize wxBitmapBundleImplRC::GetPreferredBitmapSizeAtScale(double scale) const
scales[i] = m_resourceInfos[i].scale;
}
return DoGetPreferredSize(scale, n, &scales[0]);
return DoGetPreferredSize(scale);
}
wxBitmap