Merge branch 'bmp-bundle-pref-size'
Allow wxBitmapBundle specify its preferred size and use it in wxMSW. See https://github.com/wxWidgets/wxWidgets/pull/2554
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "wx/vector.h"
|
||||
|
||||
class wxBitmapBundleImpl;
|
||||
class WXDLLIMPEXP_FWD_CORE wxWindow;
|
||||
|
||||
// It should be possible to implement SVG rasterizing without raw bitmap
|
||||
// support using wxDC::DrawSpline(), but currently we don't do it and so
|
||||
@@ -96,6 +97,12 @@ public:
|
||||
// default DPI, i.e. 100% scaling. Returns invalid size for empty bundle.
|
||||
wxSize GetDefaultSize() const;
|
||||
|
||||
// Get preferred size, i.e. usually the closest size in which a bitmap is
|
||||
// available to the ideal size determined from the default size and the DPI
|
||||
// scaling, for the given window.
|
||||
wxSize GetPreferredSizeFor(wxWindow* window) const;
|
||||
wxSize GetPreferredSizeAtScale(double scale) const;
|
||||
|
||||
// Get bitmap of the specified size, creating a new bitmap from the closest
|
||||
// available size by rescaling it if necessary.
|
||||
//
|
||||
@@ -177,6 +184,11 @@ public:
|
||||
// Must always return a valid size.
|
||||
virtual wxSize GetDefaultSize() const = 0;
|
||||
|
||||
// Return the preferred size that should be used at the given scale.
|
||||
//
|
||||
// Must always return a valid size.
|
||||
virtual wxSize GetPreferredSizeAtScale(double scale) const = 0;
|
||||
|
||||
// Retrieve the bitmap of exactly the given size.
|
||||
//
|
||||
// Note that this function is non-const because it may generate the bitmap
|
||||
|
@@ -252,6 +252,31 @@ public:
|
||||
*/
|
||||
wxSize GetDefaultSize() const;
|
||||
|
||||
/**
|
||||
Get the size that would be best to use for this bundle at the given DPI
|
||||
scaling factor.
|
||||
|
||||
For bundles containing some number of the fixed-size bitmaps, this
|
||||
function returns the size of an existing bitmap closest to the ideal
|
||||
size at the given scale, i.e. GetDefaultSize() multiplied by @a scale.
|
||||
|
||||
Passing a size returned by this function to GetBitmap() ensures that
|
||||
bitmap doesn't need to be rescaled, which typically significantly
|
||||
lowers its quality.
|
||||
*/
|
||||
wxSize GetPreferredSizeAtScale(double scale) const;
|
||||
|
||||
/**
|
||||
Get the size that would be best to use for this bundle at the DPI
|
||||
scaling factor used by the given window.
|
||||
|
||||
This is just a convenient wrapper for GetPreferredSizeAtScale() calling
|
||||
that function with the result of wxWindow::GetDPIScaleFactor().
|
||||
|
||||
@param window Non-null and fully created window.
|
||||
*/
|
||||
wxSize GetPreferredSizeFor(wxWindow* window) const;
|
||||
|
||||
/**
|
||||
Get bitmap of the specified size, creating a new bitmap from the closest
|
||||
available size by rescaling it if necessary.
|
||||
@@ -285,6 +310,16 @@ public:
|
||||
... determine the minimum/default size for bitmap to use ...
|
||||
}
|
||||
|
||||
wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE
|
||||
{
|
||||
// If it's ok to scale the bitmap, just use the standard size
|
||||
// at the given scale:
|
||||
return GetDefaultSize()*scale;
|
||||
|
||||
... otherwise, an existing bitmap of the size closest to the
|
||||
one above would need to be found and its size returned ...
|
||||
}
|
||||
|
||||
wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE
|
||||
{
|
||||
... get the bitmap of the requested size from somewhere and
|
||||
@@ -314,6 +349,13 @@ public:
|
||||
*/
|
||||
virtual wxSize GetDefaultSize() const = 0;
|
||||
|
||||
/**
|
||||
Return the preferred size that should be used at the given scale.
|
||||
|
||||
Must always return a valid size.
|
||||
*/
|
||||
virtual wxSize GetPreferredSizeAtScale(double scale) const = 0;
|
||||
|
||||
/**
|
||||
Retrieve the bitmap of exactly the given size.
|
||||
|
||||
|
@@ -520,6 +520,13 @@ void MyFrame::PopulateToolbar(wxToolBarBase* toolBar)
|
||||
return m_sizeDef;
|
||||
}
|
||||
|
||||
wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE
|
||||
{
|
||||
// We just scale the bitmap to fit the requested size, so
|
||||
// we don't really have any preferences.
|
||||
return m_sizeDef*scale;
|
||||
}
|
||||
|
||||
wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE
|
||||
{
|
||||
// In this simple implementation we don't bother caching
|
||||
|
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "wx/bmpbndl.h"
|
||||
#include "wx/icon.h"
|
||||
#include "wx/window.h"
|
||||
|
||||
#include "wx/private/bmpbndl.h"
|
||||
|
||||
@@ -64,6 +65,7 @@ public:
|
||||
}
|
||||
|
||||
virtual wxSize GetDefaultSize() const wxOVERRIDE;
|
||||
virtual wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE;
|
||||
virtual wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE;
|
||||
|
||||
#ifdef __WXOSX__
|
||||
@@ -157,6 +159,47 @@ wxSize wxBitmapBundleImplSet::GetDefaultSize() const
|
||||
return m_entries[0].bitmap.GetSize();
|
||||
}
|
||||
|
||||
wxSize wxBitmapBundleImplSet::GetPreferredSizeAtScale(double scale) const
|
||||
{
|
||||
// Target size is the ideal size we'd like the bitmap to have at this scale.
|
||||
const wxSize sizeTarget = GetDefaultSize()*scale;
|
||||
|
||||
const size_t n = m_entries.size();
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
{
|
||||
const wxSize sizeThis = m_entries[i].bitmap.GetSize();
|
||||
|
||||
// Keep looking for the exact match which we still can hope to find
|
||||
// while the current bitmap is smaller.
|
||||
if ( sizeThis.y < sizeTarget.y )
|
||||
continue;
|
||||
|
||||
// If we've found the exact match, just return it.
|
||||
if ( sizeThis.y == sizeTarget.y )
|
||||
return sizeThis;
|
||||
|
||||
// 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 )
|
||||
return sizeThis;
|
||||
|
||||
// Decide whether we should use this one or the previous smaller one
|
||||
// depending on which of them is closer to the target size, breaking
|
||||
// the tie in favour of the bigger size.
|
||||
const wxSize sizeLast = m_entries[i - 1].bitmap.GetSize();
|
||||
|
||||
return sizeThis.y - sizeTarget.y <= sizeTarget.y - sizeLast.y
|
||||
? sizeThis
|
||||
: sizeLast;
|
||||
|
||||
}
|
||||
|
||||
// We only get here if the target size is bigger than all the available
|
||||
// sizes, in which case we have no choice but to use the biggest bitmap.
|
||||
return m_entries.back().bitmap.GetSize();
|
||||
}
|
||||
|
||||
wxBitmap wxBitmapBundleImplSet::GetBitmap(const wxSize& size)
|
||||
{
|
||||
// We use linear search instead if binary one because it's simpler and the
|
||||
@@ -326,6 +369,21 @@ wxSize wxBitmapBundle::GetDefaultSize() const
|
||||
return m_impl->GetDefaultSize();
|
||||
}
|
||||
|
||||
wxSize wxBitmapBundle::GetPreferredSizeFor(wxWindow* window) const
|
||||
{
|
||||
wxCHECK_MSG( window, wxDefaultSize, "window must be valid" );
|
||||
|
||||
return GetPreferredSizeAtScale(window->GetDPIScaleFactor());
|
||||
}
|
||||
|
||||
wxSize wxBitmapBundle::GetPreferredSizeAtScale(double scale) const
|
||||
{
|
||||
if ( !m_impl )
|
||||
return wxDefaultSize;
|
||||
|
||||
return m_impl->GetPreferredSizeAtScale(scale);
|
||||
}
|
||||
|
||||
wxBitmap wxBitmapBundle::GetBitmap(const wxSize& size) const
|
||||
{
|
||||
if ( !m_impl )
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "wx/image.h"
|
||||
#endif // WXWIN_COMPATIBILITY_2_8
|
||||
#include "wx/menu.h"
|
||||
#include "wx/vector.h"
|
||||
#endif
|
||||
|
||||
extern WXDLLEXPORT_DATA(const char) wxToolBarNameStr[] = "toolbar";
|
||||
@@ -432,6 +433,39 @@ void wxToolBarBase::ClearTools()
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Struct containing the number of tools preferring to use the given size.
|
||||
struct SizePrefWithCount
|
||||
{
|
||||
SizePrefWithCount() : count(0) { }
|
||||
|
||||
wxSize size;
|
||||
int count;
|
||||
};
|
||||
|
||||
typedef wxVector<SizePrefWithCount> SizePrefs;
|
||||
|
||||
void RecordSizePref(SizePrefs& prefs, const wxSize& size)
|
||||
{
|
||||
for ( size_t n = 0; n < prefs.size(); ++n )
|
||||
{
|
||||
if ( prefs[n].size == size )
|
||||
{
|
||||
prefs[n].count++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SizePrefWithCount pref;
|
||||
pref.size = size;
|
||||
pref.count++;
|
||||
prefs.push_back(pref);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void wxToolBarBase::AdjustToolBitmapSize()
|
||||
{
|
||||
if ( HasFlag(wxTB_NOICONS) )
|
||||
@@ -442,8 +476,10 @@ void wxToolBarBase::AdjustToolBitmapSize()
|
||||
|
||||
const wxSize sizeOrig(m_defaultWidth, m_defaultHeight);
|
||||
|
||||
wxSize sizeActual(sizeOrig);
|
||||
|
||||
// We want to use preferred bitmap size, but the preferred sizes can be
|
||||
// different for different bitmap bundles, so record all their preferences
|
||||
// first.
|
||||
SizePrefs prefs;
|
||||
const double scale = GetDPIScaleFactor();
|
||||
for ( wxToolBarToolsList::const_iterator i = m_tools.begin();
|
||||
i != m_tools.end();
|
||||
@@ -451,11 +487,48 @@ void wxToolBarBase::AdjustToolBitmapSize()
|
||||
{
|
||||
const wxBitmapBundle& bmp = (*i)->GetNormalBitmapBundle();
|
||||
if ( bmp.IsOk() )
|
||||
sizeActual.IncTo(bmp.GetDefaultSize()*scale);
|
||||
RecordSizePref(prefs, bmp.GetPreferredSizeAtScale(scale));
|
||||
}
|
||||
|
||||
if ( sizeActual != sizeOrig )
|
||||
SetToolBitmapSize(sizeActual);
|
||||
// Now find the size preferred by most tools.
|
||||
int countMax = 0;
|
||||
wxSize sizePreferred;
|
||||
for ( size_t n = 0; n < prefs.size(); ++n )
|
||||
{
|
||||
const int countThis = prefs[n].count;
|
||||
const wxSize sizeThis = prefs[n].size;
|
||||
|
||||
if ( countThis > countMax )
|
||||
{
|
||||
countMax = countThis;
|
||||
sizePreferred = sizeThis;
|
||||
}
|
||||
else if ( countThis == countMax )
|
||||
{
|
||||
// We have a tie between different sizes, choose the one
|
||||
// corresponding to the current scale factor, if possible, as this
|
||||
// is the ideal bitmap size that should be consistent with all the
|
||||
// other bitmaps.
|
||||
if ( sizePreferred != sizeOrig*scale )
|
||||
{
|
||||
if ( sizeThis == sizeOrig*scale )
|
||||
{
|
||||
sizePreferred = sizeThis;
|
||||
}
|
||||
else // Neither of the sizes is the ideal one.
|
||||
{
|
||||
// Choose the larger one as like this some bitmaps will be
|
||||
// downscaled, which should look better than upscaling some
|
||||
// (other) ones.
|
||||
if ( sizeThis.y > sizePreferred.y )
|
||||
sizePreferred = sizeThis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sizePreferred != sizeOrig )
|
||||
SetToolBitmapSize(sizePreferred);
|
||||
}
|
||||
|
||||
bool wxToolBarBase::Realize()
|
||||
|
@@ -93,6 +93,7 @@ public:
|
||||
}
|
||||
|
||||
virtual wxSize GetDefaultSize() const wxOVERRIDE;
|
||||
virtual wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE;
|
||||
virtual wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE;
|
||||
|
||||
private:
|
||||
@@ -126,6 +127,12 @@ wxSize wxBitmapBundleImplSVG::GetDefaultSize() const
|
||||
return m_sizeDef;
|
||||
}
|
||||
|
||||
wxSize wxBitmapBundleImplSVG::GetPreferredSizeAtScale(double scale) const
|
||||
{
|
||||
// We consider that we can render at any scale.
|
||||
return m_sizeDef*scale;
|
||||
}
|
||||
|
||||
wxBitmap wxBitmapBundleImplSVG::GetBitmap(const wxSize& size)
|
||||
{
|
||||
if ( !m_cachedBitmap.IsOk() || m_cachedBitmap.GetSize() != size )
|
||||
|
@@ -107,7 +107,7 @@ class wxButtonImageData: public wxObject
|
||||
public:
|
||||
wxButtonImageData(wxWindow* btn, const wxBitmapBundle& normalBundle)
|
||||
{
|
||||
m_bitmapSize = normalBundle.GetDefaultSize() * btn->GetDPIScaleFactor();
|
||||
m_bitmapSize = normalBundle.GetPreferredSizeFor(btn);
|
||||
|
||||
m_bitmapBundles[wxAnyButton::State_Normal] = normalBundle;
|
||||
}
|
||||
@@ -254,7 +254,7 @@ public:
|
||||
// the image list
|
||||
wxXPButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle)
|
||||
: wxButtonImageData(btn, bitmapBundle),
|
||||
m_hwndBtn(GetHwndOf(btn))
|
||||
m_btn(btn)
|
||||
{
|
||||
InitImageList();
|
||||
|
||||
@@ -403,7 +403,7 @@ private:
|
||||
|
||||
void UpdateImageInfo()
|
||||
{
|
||||
if ( !::SendMessage(m_hwndBtn, BCM_SETIMAGELIST, 0, (LPARAM)&m_data) )
|
||||
if ( !::SendMessage(GetHwndOf(m_btn), BCM_SETIMAGELIST, 0, (LPARAM)&m_data) )
|
||||
{
|
||||
wxLogDebug("SendMessage(BCM_SETIMAGELIST) failed");
|
||||
}
|
||||
@@ -415,7 +415,7 @@ private:
|
||||
|
||||
// We need to recreate the image list using the new size and re-add all
|
||||
// bitmaps to it.
|
||||
m_bitmapSize = event.Scale(m_bitmapSize);
|
||||
m_bitmapSize = m_bitmapBundles[wxAnyButton::State_Normal].GetPreferredSizeFor(m_btn);
|
||||
|
||||
m_iml.Destroy();
|
||||
InitImageList();
|
||||
@@ -431,7 +431,7 @@ private:
|
||||
BUTTON_IMAGELIST m_data;
|
||||
|
||||
// the button we're associated with
|
||||
const HWND m_hwndBtn;
|
||||
wxWindow* const m_btn;
|
||||
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxXPButtonImageData);
|
||||
|
@@ -138,6 +138,7 @@ public:
|
||||
const wxBitmap& bitmap);
|
||||
|
||||
virtual wxSize GetDefaultSize() const wxOVERRIDE;
|
||||
virtual wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE;
|
||||
virtual wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE;
|
||||
|
||||
private:
|
||||
@@ -185,6 +186,52 @@ wxSize wxBitmapBundleImplRC::GetDefaultSize() const
|
||||
return m_bitmaps[0].GetSize();
|
||||
}
|
||||
|
||||
wxSize wxBitmapBundleImplRC::GetPreferredSizeAtScale(double scale) const
|
||||
{
|
||||
// Optimistically assume we're going to use this exact scale by default.
|
||||
double scalePreferred = scale;
|
||||
|
||||
for ( size_t i = 0; ; ++i )
|
||||
{
|
||||
if ( i == m_resourceInfos.size() )
|
||||
{
|
||||
// The requested scale is bigger than anything we have, so use the
|
||||
// biggest available one.
|
||||
scalePreferred = m_resourceInfos[i - 1].scale;
|
||||
break;
|
||||
}
|
||||
|
||||
const double scaleThis = m_resourceInfos[i].scale;
|
||||
|
||||
// Keep looking for the exact match which we still can hope to find
|
||||
// while the current scale is smaller.
|
||||
if ( scaleThis < scale )
|
||||
continue;
|
||||
|
||||
// If we've found the exact match, just use it.
|
||||
if ( scaleThis == scale )
|
||||
break;
|
||||
|
||||
// We've found the closest bigger scale.
|
||||
|
||||
// If there is no smaller one, we have no choice but to use this one.
|
||||
if ( i == 0 )
|
||||
break;
|
||||
|
||||
// Decide whether we should use this one or the previous smaller one
|
||||
// depending on which of them is closer to the target scale, breaking
|
||||
// the tie in favour of the bigger one.
|
||||
const double scaleLast = m_resourceInfos[i - 1].scale;
|
||||
|
||||
scalePreferred = scaleThis - scale <= scale - scaleLast
|
||||
? scaleThis
|
||||
: scaleLast;
|
||||
break;
|
||||
}
|
||||
|
||||
return GetDefaultSize()*scalePreferred;
|
||||
}
|
||||
|
||||
wxBitmap
|
||||
wxBitmapBundleImplRC::AddBitmap(const ResourceInfo& info,
|
||||
const wxSize& sizeExpected,
|
||||
|
@@ -1949,10 +1949,6 @@ void wxToolBar::RealizeHelper()
|
||||
|
||||
void wxToolBar::OnDPIChanged(wxDPIChangedEvent& event)
|
||||
{
|
||||
// Ensure that when Realize() is called, the bitmaps size corresponding to
|
||||
// the new resolution will be used.
|
||||
SetToolBitmapSize(event.Scale(wxSize(m_defaultWidth, m_defaultHeight)));
|
||||
|
||||
// Manually scale the size of the controls. Even though the font has been
|
||||
// updated, the internal size of the controls does not.
|
||||
wxToolBarToolsList::compatibility_iterator node;
|
||||
|
@@ -46,6 +46,7 @@ public:
|
||||
~wxOSXImageBundleImpl();
|
||||
|
||||
virtual wxSize GetDefaultSize() const wxOVERRIDE;
|
||||
virtual wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE;
|
||||
virtual wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE;
|
||||
|
||||
virtual WXImage OSXGetImage() const wxOVERRIDE;
|
||||
@@ -76,6 +77,14 @@ wxSize wxOSXImageBundleImpl::GetDefaultSize() const
|
||||
return wxSize(sz.width, sz.height);
|
||||
}
|
||||
|
||||
wxSize wxOSXImageBundleImpl::GetPreferredSizeAtScale(double scale) const
|
||||
{
|
||||
// The system always performs scaling, as the scaling factor is integer and
|
||||
// so it doesn't make sense to round it up or down, hence we should use the
|
||||
// theoretical best size for given scale.
|
||||
return GetDefaultSize()*scale;
|
||||
}
|
||||
|
||||
wxBitmap wxOSXImageBundleImpl::GetBitmap(const wxSize& size)
|
||||
{
|
||||
return wxBitmap();
|
||||
|
@@ -47,6 +47,27 @@ TEST_CASE("BitmapBundle::FromBitmaps", "[bmpbundle]")
|
||||
CHECK( b.GetBitmap(wxSize(24, 24)).GetSize() == wxSize(24, 24) );
|
||||
}
|
||||
|
||||
TEST_CASE("BitmapBundle::GetPreferredSize", "[bmpbundle]")
|
||||
{
|
||||
CHECK( wxBitmapBundle().GetPreferredSizeAtScale(1) == wxDefaultSize );
|
||||
|
||||
const wxSize normal(32, 32);
|
||||
const wxSize bigger(64, 64);
|
||||
|
||||
const wxBitmapBundle
|
||||
b = wxBitmapBundle::FromBitmaps(wxBitmap(normal), wxBitmap(bigger));
|
||||
|
||||
CHECK( b.GetPreferredSizeAtScale(0 ) == normal );
|
||||
CHECK( b.GetPreferredSizeAtScale(1 ) == normal );
|
||||
CHECK( b.GetPreferredSizeAtScale(1.25) == normal );
|
||||
CHECK( b.GetPreferredSizeAtScale(1.4 ) == normal );
|
||||
CHECK( b.GetPreferredSizeAtScale(1.5 ) == bigger );
|
||||
CHECK( b.GetPreferredSizeAtScale(1.75) == bigger );
|
||||
CHECK( b.GetPreferredSizeAtScale(2 ) == bigger );
|
||||
CHECK( b.GetPreferredSizeAtScale(2.5 ) == bigger );
|
||||
CHECK( b.GetPreferredSizeAtScale(3 ) == bigger );
|
||||
}
|
||||
|
||||
#ifdef wxHAS_SVG
|
||||
|
||||
TEST_CASE("BitmapBundle::FromSVG", "[bmpbundle][svg]")
|
||||
|
Reference in New Issue
Block a user