From 36abfe973a8f412ad6b17596020749661db18276 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 1 Jun 2022 23:41:34 +0100 Subject: [PATCH] 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. --- include/wx/bmpbndl.h | 17 ++++++-- interface/wx/bmpbndl.h | 53 ++++++++++++++++--------- src/common/bmpbndl.cpp | 90 ++++++++++++++++++++++++------------------ src/msw/bmpbndl.cpp | 10 ++++- 4 files changed, 107 insertions(+), 63 deletions(-) diff --git a/include/wx/bmpbndl.h b/include/wx/bmpbndl.h index db07bea47f..3bf8e0b88d 100644 --- a/include/wx/bmpbndl.h +++ b/include/wx/bmpbndl.h @@ -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(); diff --git a/interface/wx/bmpbndl.h b/interface/wx/bmpbndl.h index 06ce457999..795dd649f8 100644 --- a/interface/wx/bmpbndl.h +++ b/interface/wx/bmpbndl.h @@ -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 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; }; /** diff --git a/src/common/bmpbndl.cpp b/src/common/bmpbndl.cpp index 8ef96d135a..8af75ec2a9 100644 --- a/src/common/bmpbndl.cpp +++ b/src/common/bmpbndl.cpp @@ -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 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(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; } diff --git a/src/msw/bmpbndl.cpp b/src/msw/bmpbndl.cpp index fbd707f040..e9eaf87a09 100644 --- a/src/msw/bmpbndl.cpp +++ b/src/msw/bmpbndl.cpp @@ -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