Allow wxBitmapBundle to specify its preferred bitmap size
Using bitmaps of preferred size avoids scaling and results in much better appearance, so add methods allowing querying the bundle about the bitmaps it supports and implement them in the various implementations. This is not actually used anywhere yet, but will be soon.
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 )
|
||||
|
@@ -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 )
|
||||
|
@@ -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,
|
||||
|
@@ -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