Improve fallback logic in wxArtProvider::GetBitmap{,Bundle}()

This improves the changes of f78db92462 (Avoid bitmap scaling in
wxArtProvider::GetBitmapBundle(), 2021-12-17) and still uses a custom
bundle to avoid scaling the bitmap if possible, but does it in
GetBitmapBundle() itself rather than CreateBitmapBundle().

This allows to also use CreateBitmapBundle() from GetBitmap(), as there
is no possibility of infinite recursion due to calling each of these
functions from the other one any more, and so allows defining art
providers overriding only CreateBitmapBundle() instead of having to
always override both it and CreateBitmap().

Also add a unit test, even if just a trivial one, for these functions,
to at least check that they don't crash.
This commit is contained in:
Vadim Zeitlin
2022-01-31 22:44:22 +00:00
parent 1a10199575
commit ae7fa19ae3
3 changed files with 55 additions and 23 deletions

View File

@@ -226,9 +226,14 @@ protected:
return GetSizeHint(client, true);
}
// Derived classes must override CreateBitmap or CreateIconBundle
// (or both) to create requested art resource. This method is called
// only once per instance's lifetime for each requested wxArtID.
// Derived classes must override at least one of the CreateXXX() functions
// below to create requested art resource. Overriding more than one of them
// is also possible but is usually not needed, as both GetBitmap() and
// GetBitmapBundle() will try using both CreateBitmap() and
// CreateBitmapBundle().
//
// Note that these methods are called only once per instance's lifetime for
// each requested wxArtID as the return value is cached.
virtual wxBitmap CreateBitmap(const wxArtID& WXUNUSED(id),
const wxArtClient& WXUNUSED(client),
const wxSize& WXUNUSED(size))
@@ -236,11 +241,12 @@ protected:
return wxNullBitmap;
}
// Default implementation creates a wxBitmapBundle which returns the
// specified art resource in whichever size it is being asked for.
virtual wxBitmapBundle CreateBitmapBundle(const wxArtID& id,
const wxArtClient& client,
const wxSize& size);
virtual wxBitmapBundle CreateBitmapBundle(const wxArtID& WXUNUSED(id),
const wxArtClient& WXUNUSED(client),
const wxSize& WXUNUSED(size))
{
return wxBitmapBundle();
}
virtual wxIconBundle CreateIconBundle(const wxArtID& WXUNUSED(id),
const wxArtClient& WXUNUSED(client))

View File

@@ -325,9 +325,17 @@ void wxArtProvider::RescaleBitmap(wxBitmap& bmp, const wxSize& sizeNeeded)
for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
node; node = node->GetNext())
{
bmp = node->GetData()->CreateBitmap(id, client, size);
wxArtProvider* const provider = node->GetData();
bmp = provider->CreateBitmap(id, client, size);
if ( bmp.IsOk() )
break;
const wxBitmapBundle& bb = provider->CreateBitmapBundle(id, client, size);
if ( bb.IsOk() )
{
bmp = bb.GetBitmap(size);
break;
}
}
wxSize sizeNeeded = size;
@@ -385,9 +393,25 @@ wxBitmapBundle wxArtProvider::GetBitmapBundle(const wxArtID& id,
for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
node; node = node->GetNext())
{
bitmapbundle = node->GetData()->CreateBitmapBundle(id, client, size);
wxArtProvider* const provider = node->GetData();
bitmapbundle = provider->CreateBitmapBundle(id, client, size);
if ( bitmapbundle.IsOk() )
break;
// Try creating the bundle from individual bitmaps returned by the
// provider because they can be available in more than one size,
// i.e. it's better to return a custom bundle returning them in the
// size closest to the requested one rather than a simple bundle
// just containing the single bitmap in the specified size.
//
// Note that we do this here rather than outside of this loop
// because we consider that a simple bitmap defined in a higher
// priority provider should override a bitmap bundle defined in a
// lower priority one: even if this means that the bitmap will be
// scaled, at least we'll be using the expected bitmap rather than
// potentially using a bitmap of a different style.
if ( GetBitmap(id, client, size).IsOk() )
bitmapbundle = wxBitmapBundle::FromImpl(new wxBitmapBundleImplArt(id, client, size));
}
sm_cache->PutBitmapBundle(hashId, bitmapbundle);
@@ -396,19 +420,6 @@ wxBitmapBundle wxArtProvider::GetBitmapBundle(const wxArtID& id,
return bitmapbundle;
}
wxBitmapBundle wxArtProvider::CreateBitmapBundle(const wxArtID& id,
const wxArtClient& client,
const wxSize& size)
{
// Check that we have a valid art ID to ensure that wxBitmapBundleImplArt
// will be able to create valid bitmaps when it is used, because it is
// expected that a non-empty bundle always has at least one valid bitmap.
if ( !GetBitmap(id, client, size).IsOk() )
return wxBitmapBundle();
return wxBitmapBundle::FromImpl(new wxBitmapBundleImplArt(id, client, size));
}
/*static*/
wxIconBundle wxArtProvider::GetIconBundle(const wxArtID& id, const wxArtClient& client)
{

View File

@@ -14,6 +14,8 @@
#include "wx/bmpbndl.h"
#include "wx/artprov.h"
#include "asserthelper.h"
// ----------------------------------------------------------------------------
@@ -144,3 +146,16 @@ TEST_CASE("BitmapBundle::FromSVGFile", "[bmpbundle][svg][file]")
}
#endif // wxHAS_SVG
TEST_CASE("BitmapBundle::ArtProvider", "[bmpbundle][art]")
{
// Check that creating a bogus bundle fails as expected.
wxBitmapBundle b = wxArtProvider::GetBitmapBundle("bloordyblop");
CHECK( !b.IsOk() );
// And that creating a bundle using a standard icon works.
const wxSize size(16, 16);
b = wxArtProvider::GetBitmapBundle(wxART_INFORMATION, wxART_MENU, size);
CHECK( b.IsOk() );
CHECK( b.GetDefaultSize() == size );
}