Merge branch 'imaglist-mask'
Make handling of masks in wxImageList simpler and more useful. See #22400.
This commit is contained in:
commit
bb52a5c5b5
8 changed files with 252 additions and 205 deletions
|
|
@ -58,6 +58,8 @@ public:
|
|||
private:
|
||||
const wxBitmap *DoGetPtr(int index) const;
|
||||
|
||||
wxBitmap GetImageListBitmap(const wxBitmap& bitmap) const;
|
||||
|
||||
wxVector<wxBitmap> m_images;
|
||||
bool m_useMask;
|
||||
|
||||
|
|
|
|||
|
|
@ -276,6 +276,10 @@ public:
|
|||
WXHBITMAP GetMaskBitmap() const { return m_maskBitmap; }
|
||||
void SetMaskBitmap(WXHBITMAP bmp) { m_maskBitmap = bmp; }
|
||||
|
||||
#if wxUSE_IMAGE
|
||||
bool MSWCreateFromImageMask(const wxImage& image);
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
protected:
|
||||
WXHBITMAP m_maskBitmap;
|
||||
|
||||
|
|
|
|||
|
|
@ -200,6 +200,14 @@ protected:
|
|||
wxSize m_size;
|
||||
|
||||
private:
|
||||
// Private helper used by GetImageListBitmaps().
|
||||
class wxMSWBitmaps;
|
||||
|
||||
// Fills the provided output "bitmaps" object with the actual bitmaps we need
|
||||
// to use with the native control.
|
||||
void GetImageListBitmaps(wxMSWBitmaps& bitmaps,
|
||||
const wxBitmap& bitmap, const wxBitmap& mask);
|
||||
|
||||
bool m_useMask;
|
||||
|
||||
void Init()
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ enum
|
|||
@class wxImageList
|
||||
|
||||
A wxImageList contains a list of images, which are stored in an unspecified
|
||||
form. Images can have masks for transparent drawing, and can be made from a
|
||||
variety of sources including bitmaps and icons.
|
||||
form. Images can use alpha channel or masks for transparent drawing, and
|
||||
can be made from a variety of sources including bitmaps and icons.
|
||||
|
||||
wxImageList is used principally in conjunction with wxTreeCtrl and
|
||||
wxListCtrl classes.
|
||||
|
|
@ -62,7 +62,12 @@ public:
|
|||
@param height
|
||||
Height of the images in the list.
|
||||
@param mask
|
||||
@true if masks should be created for all images.
|
||||
If @true, all images will have masks, with the mask being created
|
||||
from the light grey pixels if not specified otherwise, i.e. if the
|
||||
image doesn't have neither alpha channel nor mask and no mask is
|
||||
explicitly specified when adding it. Note that if an image does
|
||||
have alpha channel or mask, it will always be used, whether this
|
||||
parameter is @true or @false.
|
||||
@param initialCount
|
||||
The initial size of the list.
|
||||
|
||||
|
|
|
|||
|
|
@ -68,79 +68,29 @@ bool wxGenericImageList::Create( int width, int height, bool mask, int WXUNUSED(
|
|||
return m_size != wxSize(0, 0);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
wxBitmap GetImageListBitmap(const wxBitmap& bitmap, bool useMask, const wxSize& imgSize)
|
||||
wxBitmap wxGenericImageList::GetImageListBitmap(const wxBitmap& bitmap) const
|
||||
{
|
||||
wxBitmap bmp(bitmap);
|
||||
if ( useMask )
|
||||
|
||||
// If we don't have neither mask nor alpha and were asked to use a mask,
|
||||
// create a default one.
|
||||
if ( m_useMask && !bmp.GetMask() && !bmp.HasAlpha() )
|
||||
{
|
||||
if ( bmp.GetMask() )
|
||||
{
|
||||
if ( bmp.HasAlpha() )
|
||||
{
|
||||
// We need to remove alpha channel for compatibility with
|
||||
// native-based wxMSW wxImageList where stored images are not allowed
|
||||
// to have both mask and alpha channel.
|
||||
#if wxUSE_IMAGE
|
||||
wxImage img = bmp.ConvertToImage();
|
||||
img.ClearAlpha();
|
||||
bmp = wxBitmap(img, -1, bmp.GetScaleFactor());
|
||||
#endif // wxUSE_IMAGE
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( bmp.HasAlpha() )
|
||||
{
|
||||
// Convert alpha channel to mask.
|
||||
#if wxUSE_IMAGE
|
||||
wxImage img = bmp.ConvertToImage();
|
||||
img.ConvertAlphaToMask();
|
||||
bmp = wxBitmap(img, -1, bmp.GetScaleFactor());
|
||||
#endif // wxUSE_IMAGE
|
||||
}
|
||||
else
|
||||
{
|
||||
// Like for wxMSW, use the light grey from standard colour map as transparent colour.
|
||||
wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
|
||||
bmp.SetMask(new wxMask(bmp, col));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( bmp.GetMask() )
|
||||
{
|
||||
if ( bmp.HasAlpha() )
|
||||
{
|
||||
// TODO: It would be better to blend a mask with existing alpha values.
|
||||
bmp.SetMask(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert a mask to alpha values.
|
||||
#if wxUSE_IMAGE
|
||||
wxImage img = bmp.ConvertToImage();
|
||||
img.InitAlpha();
|
||||
bmp = wxBitmap(img, -1, bmp.GetScaleFactor());
|
||||
#else
|
||||
bmp.SetMask(NULL);
|
||||
#endif // wxUSE_IMAGE
|
||||
}
|
||||
}
|
||||
// Like for wxMSW, use the light grey from standard colour map as transparent colour.
|
||||
wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
|
||||
bmp.SetMask(new wxMask(bmp, col));
|
||||
}
|
||||
|
||||
// Ensure image size is the same as the size of the images on the image list.
|
||||
wxBitmap bmpResized;
|
||||
const wxSize sz = bmp.GetLogicalSize();
|
||||
if ( sz.x == imgSize.x && sz.y == imgSize.y )
|
||||
if ( sz.x == m_size.x && sz.y == m_size.y )
|
||||
{
|
||||
bmpResized = bmp;
|
||||
}
|
||||
else if ( sz.x > imgSize.x && sz.y > imgSize.y )
|
||||
else if ( sz.x > m_size.x && sz.y > m_size.y )
|
||||
{
|
||||
wxRect r(0, 0, imgSize.x, imgSize.y);
|
||||
wxRect r(0, 0, m_size.x, m_size.y);
|
||||
bmpResized = bmp.GetSubBitmap(r);
|
||||
}
|
||||
else
|
||||
|
|
@ -149,7 +99,7 @@ wxBitmap GetImageListBitmap(const wxBitmap& bitmap, bool useMask, const wxSize&
|
|||
wxImage img = bmp.ConvertToImage();
|
||||
// We need image with new physical size
|
||||
const double scaleFactor = bmp.GetScaleFactor();
|
||||
wxImage imgResized = img.Size(scaleFactor * imgSize, wxPoint(0, 0), 0, 0, 0);
|
||||
wxImage imgResized = img.Size(scaleFactor * m_size, wxPoint(0, 0), 0, 0, 0);
|
||||
bmpResized = wxBitmap(imgResized, -1, scaleFactor);
|
||||
#else
|
||||
bmpResized = bmp;
|
||||
|
|
@ -158,7 +108,6 @@ wxBitmap GetImageListBitmap(const wxBitmap& bitmap, bool useMask, const wxSize&
|
|||
|
||||
return bmpResized;
|
||||
}
|
||||
};
|
||||
|
||||
int wxGenericImageList::Add( const wxBitmap &bitmap )
|
||||
{
|
||||
|
|
@ -175,7 +124,7 @@ int wxGenericImageList::Add( const wxBitmap &bitmap )
|
|||
// ImageList_Add() does.
|
||||
if ( bitmapSize.x == m_size.x )
|
||||
{
|
||||
m_images.push_back(GetImageListBitmap(bitmap, m_useMask, m_size));
|
||||
m_images.push_back(GetImageListBitmap(bitmap));
|
||||
}
|
||||
else if ( bitmapSize.x > m_size.x )
|
||||
{
|
||||
|
|
@ -183,7 +132,7 @@ int wxGenericImageList::Add( const wxBitmap &bitmap )
|
|||
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));
|
||||
m_images.push_back(GetImageListBitmap(bitmap.GetSubBitmap(rect)));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -252,7 +201,7 @@ wxGenericImageList::Replace(int index,
|
|||
if ( mask.IsOk() )
|
||||
bmp.SetMask(new wxMask(mask));
|
||||
|
||||
m_images[index] = GetImageListBitmap(bmp, m_useMask, m_size);
|
||||
m_images[index] = GetImageListBitmap(bmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "wx/image.h"
|
||||
#endif
|
||||
|
||||
#include "wx/scopedarray.h"
|
||||
#include "wx/scopedptr.h"
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/dc.h"
|
||||
|
|
@ -933,42 +934,11 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc)
|
|||
// finally also set the mask if we have one
|
||||
if ( image.HasMask() )
|
||||
{
|
||||
const size_t len = 2*((w+15)/16);
|
||||
BYTE *src = image.GetData();
|
||||
BYTE *data = new BYTE[h*len];
|
||||
memset(data, 0, h*len);
|
||||
BYTE r = image.GetMaskRed(),
|
||||
g = image.GetMaskGreen(),
|
||||
b = image.GetMaskBlue();
|
||||
BYTE *dst = data;
|
||||
for ( int y = 0; y < h; y++, dst += len )
|
||||
{
|
||||
BYTE *dstLine = dst;
|
||||
BYTE mask = 0x80;
|
||||
for ( int x = 0; x < w; x++, src += 3 )
|
||||
{
|
||||
if (src[0] != r || src[1] != g || src[2] != b)
|
||||
*dstLine |= mask;
|
||||
|
||||
if ( (mask >>= 1) == 0 )
|
||||
{
|
||||
dstLine++;
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hbitmap = ::CreateBitmap(w, h, 1, 1, data);
|
||||
if ( !hbitmap )
|
||||
{
|
||||
wxLogLastError(wxT("CreateBitmap(mask)"));
|
||||
}
|
||||
wxMask* mask = new wxMask;
|
||||
if ( mask->MSWCreateFromImageMask(image) )
|
||||
SetMask(mask);
|
||||
else
|
||||
{
|
||||
SetMask(new wxMask((WXHBITMAP)hbitmap));
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
delete mask;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1700,6 +1670,50 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
|
|||
return ok;
|
||||
}
|
||||
|
||||
#if wxUSE_IMAGE
|
||||
bool wxMask::MSWCreateFromImageMask(const wxImage& image)
|
||||
{
|
||||
const int h = image.GetHeight();
|
||||
const int w = image.GetWidth();
|
||||
|
||||
const size_t len = 2*((w+15)/16);
|
||||
BYTE *src = image.GetData();
|
||||
wxScopedArray<BYTE> data(h*len);
|
||||
memset(data.get(), 0, h*len);
|
||||
BYTE r = image.GetMaskRed(),
|
||||
g = image.GetMaskGreen(),
|
||||
b = image.GetMaskBlue();
|
||||
BYTE *dst = data.get();
|
||||
for ( int y = 0; y < h; y++, dst += len )
|
||||
{
|
||||
BYTE *dstLine = dst;
|
||||
BYTE mask = 0x80;
|
||||
for ( int x = 0; x < w; x++, src += 3 )
|
||||
{
|
||||
if (src[0] != r || src[1] != g || src[2] != b)
|
||||
*dstLine |= mask;
|
||||
|
||||
if ( (mask >>= 1) == 0 )
|
||||
{
|
||||
dstLine++;
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HBITMAP hbitmap = ::CreateBitmap(w, h, 1, 1, data.get());
|
||||
if ( !hbitmap )
|
||||
{
|
||||
wxLogLastError(wxT("CreateBitmap(mask)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_maskBitmap = hbitmap;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
wxBitmap wxMask::GetBitmap() const
|
||||
{
|
||||
// We have to do a deep copy of the mask bitmap
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
#include "wx/imaglist.h"
|
||||
#include "wx/dc.h"
|
||||
#include "wx/scopedptr.h"
|
||||
#include "wx/msw/dc.h"
|
||||
#include "wx/msw/dib.h"
|
||||
#include "wx/msw/private.h"
|
||||
|
|
@ -53,9 +52,8 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxImageList, wxObject);
|
|||
// private functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// returns the mask if it's valid, otherwise the bitmap mask and, if it's not
|
||||
// valid neither, a "solid" mask (no transparent zones at all)
|
||||
static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask);
|
||||
// returns the default transparent colour to use for creating the mask
|
||||
static wxColour GetDefaultMaskColour();
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
|
|
@ -81,12 +79,16 @@ bool wxImageList::Create(int width, int height, bool mask, int initial)
|
|||
// (e.g. ILC_COLOR16) shows completely broken bitmaps
|
||||
flags |= ILC_COLOR32;
|
||||
|
||||
m_useMask = mask;
|
||||
|
||||
// For comctl32.dll < 6 always use masks as it doesn't support alpha.
|
||||
if ( mask || wxApp::GetComCtl32Version() < 600 )
|
||||
{
|
||||
m_useMask = true;
|
||||
//
|
||||
// We also have to use masks when we don't have wxImage and wxDIB that are
|
||||
// needed to handle alpha.
|
||||
#if wxUSE_WXDIB && wxUSE_IMAGE
|
||||
if ( wxApp::GetComCtl32Version() < 600 )
|
||||
#endif
|
||||
flags |= ILC_MASK;
|
||||
}
|
||||
|
||||
// Grow by 1, I guess this is reasonable behaviour most of the time
|
||||
m_hImageList = (WXHIMAGELIST) ImageList_Create(width, height, flags,
|
||||
|
|
@ -137,30 +139,70 @@ bool wxImageList::GetSize(int WXUNUSED(index), int &width, int &height) const
|
|||
// wxImageList operations
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
void GetImageListBitmaps(const wxBitmap& bitmap, const wxBitmap& mask, bool useMask,
|
||||
AutoHBITMAP& hbmpRelease, AutoHBITMAP& hbmpMask, HBITMAP& hbmp)
|
||||
class wxImageList::wxMSWBitmaps
|
||||
{
|
||||
public:
|
||||
wxMSWBitmaps() : hbmp(NULL) { }
|
||||
|
||||
#if wxUSE_WXDIB && wxUSE_IMAGE
|
||||
// We can only use directly bitmaps without alpha and without mask unless
|
||||
// the image list uses masks and need to modify bitmap in all the other
|
||||
// cases, so check if this is necessary.
|
||||
if ( bitmap.HasAlpha() || (!useMask && (mask.IsOk() || bitmap.GetMask())) )
|
||||
void InitFromImageWithAlpha(const wxImage& img)
|
||||
{
|
||||
hbmp = wxDIB(img, wxDIB::PixelFormat_NotPreMultiplied).Detach();
|
||||
hbmpRelease.Init(hbmp);
|
||||
}
|
||||
#endif // wxUSE_WXDIB && wxUSE_IMAGE
|
||||
|
||||
// These fields are filled by GetImageListBitmaps().
|
||||
HBITMAP hbmp;
|
||||
AutoHBITMAP hbmpMask;
|
||||
|
||||
private:
|
||||
// This one is only used to delete a temporary bitmap, if necessary, and
|
||||
// shouldn't be used otherwise, so it's private.
|
||||
AutoHBITMAP hbmpRelease;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxMSWBitmaps);
|
||||
};
|
||||
|
||||
void
|
||||
wxImageList::GetImageListBitmaps(wxMSWBitmaps& bitmaps,
|
||||
const wxBitmap& bitmap, const wxBitmap& mask)
|
||||
{
|
||||
// This can be overwritten below if we need to modify the bitmap, but it
|
||||
// doesn't cost anything to initialize the bitmap with this HBITMAP.
|
||||
bitmaps.hbmp = GetHbitmapOf(bitmap);
|
||||
|
||||
#if wxUSE_WXDIB && wxUSE_IMAGE
|
||||
if ( wxApp::GetComCtl32Version() >= 600 )
|
||||
{
|
||||
wxBitmap bmp(bitmap);
|
||||
|
||||
if ( mask.IsOk() || bmp.GetMask() )
|
||||
if ( mask.IsOk() )
|
||||
{
|
||||
// Explicitly specified mask overrides the mask associated with the
|
||||
// bitmap, if any.
|
||||
if ( mask.IsOk() )
|
||||
bmp.SetMask(new wxMask(mask));
|
||||
bmp.SetMask(new wxMask(mask));
|
||||
}
|
||||
|
||||
if ( bmp.GetMask() )
|
||||
{
|
||||
// Get rid of the mask by converting it to alpha.
|
||||
if ( bmp.HasAlpha() )
|
||||
bmp.MSWBlendMaskWithAlpha();
|
||||
}
|
||||
else if ( m_useMask )
|
||||
{
|
||||
// Create the mask from the default transparent colour if we have
|
||||
// nothing else.
|
||||
if ( !bmp.HasAlpha() )
|
||||
bmp.SetMask(new wxMask(bmp, GetDefaultMaskColour()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We actually don't have to do anything at all and can just use
|
||||
// the original bitmap as is.
|
||||
return;
|
||||
}
|
||||
|
||||
// wxBitmap normally stores alpha in pre-multiplied format but
|
||||
// ImageList_Draw() does pre-multiplication internally so we need to undo
|
||||
|
|
@ -170,8 +212,8 @@ void GetImageListBitmaps(const wxBitmap& bitmap, const wxBitmap& mask, bool useM
|
|||
wxImage img = bmp.ConvertToImage();
|
||||
if ( !img.HasAlpha() )
|
||||
img.InitAlpha();
|
||||
hbmp = wxDIB(img, wxDIB::PixelFormat_NotPreMultiplied).Detach();
|
||||
hbmpRelease.Init(hbmp);
|
||||
|
||||
bitmaps.InitFromImageWithAlpha(img);
|
||||
|
||||
// In any case we'll never use mask at the native image list level as
|
||||
// it's incompatible with alpha and we need to use alpha.
|
||||
|
|
@ -179,24 +221,58 @@ void GetImageListBitmaps(const wxBitmap& bitmap, const wxBitmap& mask, bool useM
|
|||
else
|
||||
#endif // wxUSE_WXDIB && wxUSE_IMAGE
|
||||
{
|
||||
hbmp = GetHbitmapOf(bitmap);
|
||||
if ( useMask )
|
||||
hbmpMask.Init(GetMaskForImage(bitmap, mask));
|
||||
wxMask maskToUse;
|
||||
|
||||
HBITMAP hbmpMask = NULL;
|
||||
|
||||
// Always use mask if it is specified.
|
||||
if ( mask.IsOk() )
|
||||
{
|
||||
hbmpMask = GetHbitmapOf(mask);
|
||||
}
|
||||
else if ( bitmap.GetMask() )
|
||||
{
|
||||
hbmpMask = bitmap.GetMask()->GetMaskBitmap();
|
||||
}
|
||||
#if wxUSE_WXDIB && wxUSE_IMAGE
|
||||
// We can also use alpha, but we have to convert it to a mask as it is
|
||||
// not supported by this comctl32.dll version.
|
||||
else if ( bitmap.HasAlpha() )
|
||||
{
|
||||
wxImage img = bitmap.ConvertToImage();
|
||||
img.ConvertAlphaToMask();
|
||||
bitmaps.InitFromImageWithAlpha(img);
|
||||
|
||||
maskToUse.MSWCreateFromImageMask(img);
|
||||
}
|
||||
#endif // wxUSE_WXDIB && wxUSE_IMAGE
|
||||
// We don't have neither mask nor alpha, only force creating the
|
||||
// mask from colour if requested to do it.
|
||||
else if ( m_useMask )
|
||||
{
|
||||
maskToUse.Create(bitmap, GetDefaultMaskColour());
|
||||
}
|
||||
|
||||
if ( !hbmpMask )
|
||||
hbmpMask = maskToUse.GetMaskBitmap();
|
||||
|
||||
if ( hbmpMask )
|
||||
{
|
||||
// windows mask convention is opposite to the wxWidgets one
|
||||
bitmaps.hbmpMask.Init(wxInvertMask(hbmpMask));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
// Adds a bitmap, and optionally a mask bitmap.
|
||||
// Note that wxImageList creates new bitmaps, so you may delete
|
||||
// 'bitmap' and 'mask'.
|
||||
int wxImageList::Add(const wxBitmap& bitmap, const wxBitmap& mask)
|
||||
{
|
||||
HBITMAP hbmp = NULL;
|
||||
AutoHBITMAP hbmpRelease;
|
||||
AutoHBITMAP hbmpMask;
|
||||
GetImageListBitmaps(bitmap, mask, m_useMask, hbmpRelease, hbmpMask, hbmp);
|
||||
wxMSWBitmaps bitmaps;
|
||||
GetImageListBitmaps(bitmaps, bitmap, mask);
|
||||
|
||||
int index = ImageList_Add(GetHImageList(), hbmp, hbmpMask);
|
||||
int index = ImageList_Add(GetHImageList(), bitmaps.hbmp, bitmaps.hbmpMask);
|
||||
if ( index == -1 )
|
||||
{
|
||||
wxLogError(_("Couldn't add an image to the image list."));
|
||||
|
|
@ -210,14 +286,12 @@ int wxImageList::Add(const wxBitmap& bitmap, const wxBitmap& mask)
|
|||
// 'bitmap'.
|
||||
int wxImageList::Add(const wxBitmap& bitmap, const wxColour& maskColour)
|
||||
{
|
||||
HBITMAP hbmp = NULL;
|
||||
AutoHBITMAP hbmpRelease;
|
||||
AutoHBITMAP hbmpMask;
|
||||
wxMSWBitmaps bitmaps;
|
||||
wxMask mask(bitmap, maskColour);
|
||||
GetImageListBitmaps(bitmap, mask.GetBitmap(), m_useMask, hbmpRelease, hbmpMask, hbmp);
|
||||
GetImageListBitmaps(bitmaps, bitmap, mask.GetBitmap());
|
||||
|
||||
int index = ImageList_AddMasked(GetHImageList(),
|
||||
hbmp,
|
||||
bitmaps.hbmp,
|
||||
wxColourToRGB(maskColour));
|
||||
if ( index == -1 )
|
||||
{
|
||||
|
|
@ -259,12 +333,10 @@ bool wxImageList::Replace(int index,
|
|||
const wxBitmap& bitmap,
|
||||
const wxBitmap& mask)
|
||||
{
|
||||
HBITMAP hbmp = NULL;
|
||||
AutoHBITMAP hbmpRelease;
|
||||
AutoHBITMAP hbmpMask;
|
||||
GetImageListBitmaps(bitmap, mask, m_useMask, hbmpRelease, hbmpMask, hbmp);
|
||||
wxMSWBitmaps bitmaps;
|
||||
GetImageListBitmaps(bitmaps, bitmap, mask);
|
||||
|
||||
if ( !ImageList_Replace(GetHImageList(), index, hbmp, hbmpMask) )
|
||||
if ( !ImageList_Replace(GetHImageList(), index, bitmaps.hbmp, bitmaps.hbmpMask) )
|
||||
{
|
||||
wxLogLastError(wxT("ImageList_Replace()"));
|
||||
return false;
|
||||
|
|
@ -457,35 +529,14 @@ wxIcon wxImageList::GetIcon(int index) const
|
|||
// helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask)
|
||||
static wxColour GetDefaultMaskColour()
|
||||
{
|
||||
HBITMAP hbmpMask;
|
||||
wxScopedPtr<wxMask> maskDeleter;
|
||||
// use the light grey count as transparent: the trouble here is
|
||||
// that the light grey might have been changed by Windows behind
|
||||
// our back, so use the standard colour map to get its real value
|
||||
wxCOLORMAP *cmap = wxGetStdColourMap();
|
||||
wxColour col;
|
||||
wxRGBToColour(col, cmap[wxSTD_COL_BTNFACE].from);
|
||||
|
||||
if ( mask.IsOk() )
|
||||
{
|
||||
hbmpMask = GetHbitmapOf(mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxMask* pMask = bitmap.GetMask();
|
||||
if ( !pMask )
|
||||
{
|
||||
// use the light grey count as transparent: the trouble here is
|
||||
// that the light grey might have been changed by Windows behind
|
||||
// our back, so use the standard colour map to get its real value
|
||||
wxCOLORMAP *cmap = wxGetStdColourMap();
|
||||
wxColour col;
|
||||
wxRGBToColour(col, cmap[wxSTD_COL_BTNFACE].from);
|
||||
|
||||
pMask = new wxMask(bitmap, col);
|
||||
|
||||
maskDeleter.reset(pMask);
|
||||
}
|
||||
|
||||
hbmpMask = (HBITMAP)pMask->GetMaskBitmap();
|
||||
}
|
||||
|
||||
// windows mask convention is opposite to the wxWidgets one
|
||||
return wxInvertMask(hbmpMask);
|
||||
return col;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,36 @@
|
|||
|
||||
#include "wx/dcmemory.h"
|
||||
|
||||
static bool HasNoRealAlpha(const wxBitmap& bmp)
|
||||
{
|
||||
if ( !bmp.HasAlpha() )
|
||||
return true;
|
||||
|
||||
// wxMSW can add a fully opaque alpha channel to the bitmaps used in the
|
||||
// image list.
|
||||
const wxImage img = bmp.ConvertToImage();
|
||||
const unsigned char* p = img.GetAlpha();
|
||||
if ( !p )
|
||||
return true;
|
||||
|
||||
const unsigned char* const end = p + img.GetWidth()*img.GetHeight();
|
||||
for ( ; p < end; ++p )
|
||||
{
|
||||
if ( *p != wxALPHA_OPAQUE )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HasMaskOrAlpha(const wxBitmap& bmp)
|
||||
{
|
||||
// When adding bitmaps with mask to the image list, the mask can be
|
||||
// transformed to alpha channel internally, so check that the bitmap has
|
||||
// either mask or alpha.
|
||||
return bmp.HasAlpha() || bmp.GetMask();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// tests
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -88,24 +118,21 @@ TEST_CASE("ImageList:WithMask", "[imagelist][withmask]")
|
|||
int idx = il.Add(bmpRGB);
|
||||
CHECK(il.GetImageCount() == 1);
|
||||
wxBitmap bmp1 = il.GetBitmap(idx);
|
||||
CHECK(bmp1.HasAlpha() == false);
|
||||
CHECK(bmp1.GetMask() != NULL);
|
||||
CHECK(HasNoRealAlpha(bmp1));
|
||||
CHECK(bmp1.GetWidth() == 32);
|
||||
CHECK(bmp1.GetHeight() == 32);
|
||||
|
||||
idx = il.Add(bmpRGBWithMask);
|
||||
CHECK(il.GetImageCount() == 2);
|
||||
wxBitmap bmp2 = il.GetBitmap(idx);
|
||||
CHECK(bmp2.HasAlpha() == false);
|
||||
CHECK(bmp2.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
|
||||
idx = il.Add(bmpRGB, *wxRED);
|
||||
CHECK(il.GetImageCount() == 3);
|
||||
wxBitmap bmp3 = il.GetBitmap(idx);
|
||||
CHECK(bmp3.HasAlpha() == false);
|
||||
CHECK(bmp3.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp3));
|
||||
CHECK(bmp3.GetWidth() == 32);
|
||||
CHECK(bmp3.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -116,24 +143,21 @@ TEST_CASE("ImageList:WithMask", "[imagelist][withmask]")
|
|||
int idx = il.Add(bmpRGBA);
|
||||
CHECK(il.GetImageCount() == 1);
|
||||
wxBitmap bmp1 = il.GetBitmap(idx);
|
||||
CHECK(bmp1.HasAlpha() == false);
|
||||
CHECK(bmp1.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp1));
|
||||
CHECK(bmp1.GetWidth() == 32);
|
||||
CHECK(bmp1.GetHeight() == 32);
|
||||
|
||||
idx = il.Add(bmpRGBAWithMask);
|
||||
CHECK(il.GetImageCount() == 2);
|
||||
wxBitmap bmp2 = il.GetBitmap(idx);
|
||||
CHECK(bmp2.HasAlpha() == false);
|
||||
CHECK(bmp2.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
|
||||
idx = il.Add(bmpRGBA, *wxRED);
|
||||
CHECK(il.GetImageCount() == 3);
|
||||
wxBitmap bmp3 = il.GetBitmap(idx);
|
||||
CHECK(bmp3.HasAlpha() == false);
|
||||
CHECK(bmp3.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp3));
|
||||
CHECK(bmp3.GetWidth() == 32);
|
||||
CHECK(bmp3.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -160,14 +184,12 @@ TEST_CASE("ImageList:WithMask", "[imagelist][withmask]")
|
|||
il.Replace(idx2, bmpRGBWithMask);
|
||||
|
||||
wxBitmap bmp1 = il.GetBitmap(idx1);
|
||||
CHECK(bmp1.HasAlpha() == false);
|
||||
CHECK(bmp1.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp1));
|
||||
CHECK(bmp1.GetWidth() == 32);
|
||||
CHECK(bmp1.GetHeight() == 32);
|
||||
|
||||
wxBitmap bmp2 = il.GetBitmap(idx2);
|
||||
CHECK(bmp2.HasAlpha() == false);
|
||||
CHECK(bmp2.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -184,14 +206,12 @@ TEST_CASE("ImageList:WithMask", "[imagelist][withmask]")
|
|||
il.Replace(idx2, bmpRGBAWithMask);
|
||||
|
||||
wxBitmap bmp1 = il.GetBitmap(idx1);
|
||||
CHECK(bmp1.HasAlpha() == false);
|
||||
CHECK(bmp1.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp1));
|
||||
CHECK(bmp1.GetWidth() == 32);
|
||||
CHECK(bmp1.GetHeight() == 32);
|
||||
|
||||
wxBitmap bmp2 = il.GetBitmap(idx2);
|
||||
CHECK(bmp2.HasAlpha() == false);
|
||||
CHECK(bmp2.GetMask() != NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -506,16 +526,14 @@ TEST_CASE("ImageList:NoMask", "[imagelist][nomask]")
|
|||
idx = il.Add(bmpRGBWithMask);
|
||||
CHECK(il.GetImageCount() == 2);
|
||||
wxBitmap bmp2 = il.GetBitmap(idx);
|
||||
CHECK(bmp2.HasAlpha() == true);
|
||||
CHECK(bmp2.GetMask() == NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
|
||||
idx = il.Add(bmpRGB, *wxRED);
|
||||
CHECK(il.GetImageCount() == 3);
|
||||
wxBitmap bmp3 = il.GetBitmap(idx);
|
||||
CHECK(bmp3.HasAlpha() == true);
|
||||
CHECK(bmp3.GetMask() == NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp3));
|
||||
CHECK(bmp3.GetWidth() == 32);
|
||||
CHECK(bmp3.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -534,16 +552,14 @@ TEST_CASE("ImageList:NoMask", "[imagelist][nomask]")
|
|||
idx = il.Add(bmpRGBAWithMask);
|
||||
CHECK(il.GetImageCount() == 2);
|
||||
wxBitmap bmp2 = il.GetBitmap(idx);
|
||||
CHECK(bmp2.HasAlpha() == true);
|
||||
CHECK(bmp2.GetMask() == NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
|
||||
idx = il.Add(bmpRGBA, *wxRED);
|
||||
CHECK(il.GetImageCount() == 3);
|
||||
wxBitmap bmp3 = il.GetBitmap(idx);
|
||||
CHECK(bmp3.HasAlpha() == true);
|
||||
CHECK(bmp3.GetMask() == NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp3));
|
||||
CHECK(bmp3.GetWidth() == 32);
|
||||
CHECK(bmp3.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -576,8 +592,7 @@ TEST_CASE("ImageList:NoMask", "[imagelist][nomask]")
|
|||
CHECK(bmp1.GetHeight() == 32);
|
||||
|
||||
wxBitmap bmp2 = il.GetBitmap(idx2);
|
||||
CHECK(bmp2.HasAlpha() == true);
|
||||
CHECK(bmp2.GetMask() == NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
}
|
||||
|
|
@ -600,8 +615,7 @@ TEST_CASE("ImageList:NoMask", "[imagelist][nomask]")
|
|||
CHECK(bmp1.GetHeight() == 32);
|
||||
|
||||
wxBitmap bmp2 = il.GetBitmap(idx2);
|
||||
CHECK(bmp2.HasAlpha() == true);
|
||||
CHECK(bmp2.GetMask() == NULL);
|
||||
CHECK(HasMaskOrAlpha(bmp2));
|
||||
CHECK(bmp2.GetWidth() == 32);
|
||||
CHECK(bmp2.GetHeight() == 32);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue