Fix sizes of images stored in generic wxImageList

Sizing the images stored in the list should stick to the convention
adopted in the native wxImageList implemented in wxMSW.
Images stored in the list should have the sizes as it is declared for
the list even if provided bitmaps have different sizes.
In case of discrepancies their dimensions should be adjusted accordingly
(cropped or extended).
This commit is contained in:
Artur Wieczorek
2021-01-16 22:23:35 +01:00
parent bde82aa9fb
commit 321f38831e
2 changed files with 284 additions and 26 deletions

View File

@@ -54,7 +54,7 @@ bool wxGenericImageList::Create( int width, int height, bool mask, int WXUNUSED(
namespace
{
wxBitmap GetImageListBitmap(const wxBitmap& bitmap, bool useMask)
wxBitmap GetImageListBitmap(const wxBitmap& bitmap, bool useMask, const wxSize& imgSize)
{
wxBitmap bmp(bitmap);
if ( useMask )
@@ -115,7 +115,30 @@ wxBitmap GetImageListBitmap(const wxBitmap& bitmap, bool useMask)
}
}
return bmp;
// Ensure image size is the same as the size of the images on the image list.
wxBitmap bmpResized;
const wxSize sz = bmp.GetSize();
if ( sz.x == imgSize.x && sz.y == imgSize.y )
{
bmpResized = bmp;
}
else if ( sz.x > imgSize.x && sz.y > imgSize.y )
{
wxRect r(0, 0, imgSize.x, imgSize.y);
bmpResized = bmp.GetSubBitmap(r);
}
else
{
#if wxUSE_IMAGE
wxImage img = bmp.ConvertToImage();
wxImage imgResized = img.Size(imgSize, wxPoint(0, 0), 0, 0, 0);
bmpResized = imgResized;
#else
bmpResized = bmp;
#endif // wxUSE_IMAGE
}
return bmpResized;
}
};
@@ -131,29 +154,27 @@ int wxGenericImageList::Add( const wxBitmap &bitmap )
// size: adopt the size of our first bitmap as image size.
m_size = bitmapSize;
}
else // We already have a fixed size, check that the bitmap conforms to it.
// There is a special case: a bitmap may contain more than one image,
// in which case we're supposed to chop it in parts, just as Windows
// ImageList_Add() does.
if ( bitmapSize.x == m_size.x )
{
// There is a special case: a bitmap may contain more than one image,
// in which case we're supposed to chop it in parts, just as Windows
// ImageList_Add() does.
if ( bitmapSize.x > m_size.x && (bitmapSize.x % m_size.x == 0) )
{
const int numImages = bitmapSize.x / m_size.x;
for (int subIndex = 0; subIndex < numImages; subIndex++)
{
wxRect rect(m_size.x * subIndex, 0, m_size.x, m_size.y);
Add(bitmap.GetSubBitmap(rect));
}
return GetImageCount() - 1;
}
wxASSERT_MSG( bitmapSize == m_size,
"All bitmaps in wxImageList must have the same size" );
m_images.push_back(GetImageListBitmap(bitmap, m_useMask, m_size));
}
else if ( bitmapSize.x > m_size.x )
{
const int numImages = bitmapSize.x / m_size.x;
for (int subIndex = 0; subIndex < numImages; subIndex++)
{
wxRect rect(m_size.x * subIndex, 0, m_size.x, m_size.y);
m_images.push_back(GetImageListBitmap(bitmap.GetSubBitmap(rect), m_useMask, m_size));
}
}
else
{
return -1;
}
wxBitmap bmp = GetImageListBitmap(bitmap, m_useMask);
m_images.push_back(bmp);
return GetImageCount() - 1;
}
@@ -175,8 +196,8 @@ int wxGenericImageList::Add( const wxBitmap& bitmap, const wxColour& maskColour
const wxBitmap *wxGenericImageList::DoGetPtr( int index ) const
{
wxCHECK_MSG( index >= 0 && (size_t)index < m_images.size(),
NULL, wxT("wrong index in image list") );
if ( index < 0 || (size_t)index >= m_images.size() )
return NULL;
return &m_images[index];
}
@@ -216,7 +237,7 @@ wxGenericImageList::Replace(int index,
if ( mask.IsOk() )
bmp.SetMask(new wxMask(mask));
m_images[index] = GetImageListBitmap(bmp, m_useMask);
m_images[index] = GetImageListBitmap(bmp, m_useMask, m_size);
return true;
}

View File

@@ -195,6 +195,243 @@ TEST_CASE("ImageList:WithMask", "[imagelist][withmask]")
CHECK(bmp2.GetWidth() == 32);
CHECK(bmp2.GetHeight() == 32);
}
SECTION("Add images with incompatible sizes")
{
il.RemoveAll();
wxSize sz = il.GetSize();
wxBitmap bmpSmallerW(sz.GetWidth() / 2, sz.GetHeight(), 24);
{
wxMemoryDC mdc(bmpSmallerW);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpSmallerW.IsOk());
wxBitmap bmpSmallerH(sz.GetWidth(), sz.GetHeight() / 2, 24);
{
wxMemoryDC mdc(bmpSmallerH);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpSmallerH.IsOk());
wxBitmap bmpSmallerWH(sz.GetWidth() / 2, sz.GetHeight() / 2, 24);
{
wxMemoryDC mdc(bmpSmallerWH);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpSmallerWH.IsOk());
wxBitmap bmpBiggerW(sz.GetWidth() * 3 / 2, sz.GetHeight(), 24);
{
wxMemoryDC mdc(bmpBiggerW);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpBiggerW.IsOk());
wxBitmap bmpBiggerW2x(sz.GetWidth() * 2, sz.GetHeight(), 24);
{
wxMemoryDC mdc(bmpBiggerW2x);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpBiggerW2x.IsOk());
wxBitmap bmpBiggerH(sz.GetWidth(), sz.GetHeight() * 3 / 2, 24);
{
wxMemoryDC mdc(bmpBiggerH);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpBiggerH.IsOk());
wxBitmap bmpBiggerH2x(sz.GetWidth(), sz.GetHeight() * 2, 24);
{
wxMemoryDC mdc(bmpBiggerH2x);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpBiggerH2x.IsOk());
wxBitmap bmpBiggerWH(sz.GetWidth() * 3 / 2, sz.GetHeight() * 3 / 2, 24);
{
wxMemoryDC mdc(bmpBiggerWH);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpBiggerWH.IsOk());
wxBitmap bmpBiggerWH2x(sz.GetWidth() * 2, sz.GetHeight() * 2, 24);
{
wxMemoryDC mdc(bmpBiggerWH2x);
mdc.SetBackground(*wxBLUE_BRUSH);
mdc.Clear();
}
REQUIRE(bmpBiggerWH2x.IsOk());
// Adding
int cnt = il.GetImageCount();
int idx = il.Add(bmpSmallerW);
CHECK(idx == -1);
CHECK(il.GetImageCount() == cnt);
cnt = il.GetImageCount();
idx = il.Add(bmpSmallerH);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 1);
wxBitmap bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
idx = il.Add(bmpSmallerWH);
CHECK(idx == -1);
CHECK(il.GetImageCount() == cnt);
cnt = il.GetImageCount();
idx = il.Add(bmpBiggerW);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 1);
bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
idx = il.Add(bmpBiggerW2x);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 2);
bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
idx = il.Add(bmpBiggerH);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 1);
bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
idx = il.Add(bmpBiggerH2x);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 1);
bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
idx = il.Add(bmpBiggerWH);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 1);
bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
idx = il.Add(bmpBiggerWH2x);
CHECK(idx >= 0);
CHECK(il.GetImageCount() == cnt + 2);
bmp = il.GetBitmap(idx);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
// Replacing
il.RemoveAll();
cnt = il.GetImageCount();
bool ok = il.Replace(0, bmpRGBA);
CHECK(ok == false);
CHECK(il.GetImageCount() == cnt);
// List with 1 image
idx = il.Add(bmpRGB);
CHECK(idx >= 0);
cnt = il.GetImageCount();
ok = il.Replace(0, bmpRGBA);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpSmallerW);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpSmallerH);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpSmallerWH);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpBiggerW);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpBiggerW2x);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpBiggerH);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpBiggerH2x);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpBiggerWH);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
cnt = il.GetImageCount();
ok = il.Replace(0, bmpBiggerWH2x);
CHECK(ok == true);
CHECK(il.GetImageCount() == cnt);
bmp = il.GetBitmap(0);
CHECK(bmp.GetWidth() == sz.GetWidth());
CHECK(bmp.GetHeight() == sz.GetHeight());
}
}
TEST_CASE("ImageList:NoMask", "[imagelist][nomask]")