X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b39dbf34b887a73c525da903d8599f4f6b7eb8f9..1680c3561bc4f44c63a026e0d1a5324a39336156:/src/msw/imaglist.cpp diff --git a/src/msw/imaglist.cpp b/src/msw/imaglist.cpp index d9526df4ed..266af3feb0 100644 --- a/src/msw/imaglist.cpp +++ b/src/msw/imaglist.cpp @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "imaglist.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -28,28 +24,25 @@ #pragma hdrstop #endif -#if defined(__WIN95__) - #ifndef WX_PRECOMP + #include "wx/msw/wrapcctl.h" // include "properly" #include "wx/window.h" #include "wx/icon.h" #include "wx/dc.h" #include "wx/string.h" #include "wx/dcmemory.h" - + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/image.h" #include #endif -#include "wx/log.h" -#include "wx/intl.h" - -#include "wx/msw/imaglist.h" +#include "wx/imaglist.h" +#include "wx/dc.h" +#include "wx/msw/dc.h" +#include "wx/msw/dib.h" #include "wx/msw/private.h" -#if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)) - #include -#endif - // ---------------------------------------------------------------------------- // wxWin macros // ---------------------------------------------------------------------------- @@ -84,13 +77,16 @@ bool wxImageList::Create(int width, int height, bool mask, int initial) { UINT flags = 0; - // set appropriate color depth - int dd = wxDisplayDepth(); - if (dd <= 4) flags |= ILC_COLOR; // 16 color - else if (dd <= 8) flags |= ILC_COLOR8; // 256 color - else if (dd <= 16) flags |= ILC_COLOR16; // 64k hi-color - else if (dd <= 24) flags |= ILC_COLOR24; // 16m truecolor - else if (dd <= 32) flags |= ILC_COLOR32; // 16m truecolor + // as we want to be able to use 32bpp bitmaps in the image lists, we always + // use ILC_COLOR32, even if the display resolution is less -- the system + // will make the best effort to show the bitmap if we do this resulting in + // quite acceptable display while using a lower depth ILC_COLOR constant + // (e.g. ILC_COLOR16) shows completely broken bitmaps +#ifdef __WXWINCE__ + flags |= ILC_COLOR; +#else + flags |= ILC_COLOR32; +#endif if ( mask ) flags |= ILC_MASK; @@ -122,7 +118,7 @@ wxImageList::~wxImageList() // Returns the number of images in the image list. int wxImageList::GetImageCount() const { - wxASSERT_MSG( m_hImageList, _T("invalid image list") ); + wxASSERT_MSG( m_hImageList, wxT("invalid image list") ); return ImageList_GetImageCount(GetHImageList()); } @@ -130,7 +126,7 @@ int wxImageList::GetImageCount() const // Returns the size (same for all images) of the images in the list bool wxImageList::GetSize(int WXUNUSED(index), int &width, int &height) const { - wxASSERT_MSG( m_hImageList, _T("invalid image list") ); + wxASSERT_MSG( m_hImageList, wxT("invalid image list") ); return ImageList_GetIconSize(GetHImageList(), &width, &height) != 0; } @@ -144,16 +140,33 @@ bool wxImageList::GetSize(int WXUNUSED(index), int &width, int &height) const // 'bitmap' and 'mask'. int wxImageList::Add(const wxBitmap& bitmap, const wxBitmap& mask) { - HBITMAP hbmpMask = GetMaskForImage(bitmap, mask); + HBITMAP hbmp; + +#if wxUSE_WXDIB && wxUSE_IMAGE + // wxBitmap normally stores alpha in pre-multiplied format but + // ImageList_Draw() does pre-multiplication internally so we need to undo + // the pre-multiplication here. Converting back and forth like this is, of + // course, very inefficient but it's better than wrong appearance so we do + // this for now until a better way can be found. + AutoHBITMAP hbmpRelease; + if ( bitmap.HasAlpha() ) + { + hbmp = wxDIB(bitmap.ConvertToImage(), + wxDIB::PixelFormat_NotPreMultiplied).Detach(); + hbmpRelease.Init(hbmp); + } + else +#endif // wxUSE_WXDIB && wxUSE_IMAGE + hbmp = GetHbitmapOf(bitmap); + + AutoHBITMAP hbmpMask(GetMaskForImage(bitmap, mask)); - int index = ImageList_Add(GetHImageList(), GetHbitmapOf(bitmap), hbmpMask); + int index = ImageList_Add(GetHImageList(), hbmp, hbmpMask); if ( index == -1 ) { wxLogError(_("Couldn't add an image to the image list.")); } - ::DeleteObject(hbmpMask); - return index; } @@ -162,8 +175,23 @@ int wxImageList::Add(const wxBitmap& bitmap, const wxBitmap& mask) // 'bitmap'. int wxImageList::Add(const wxBitmap& bitmap, const wxColour& maskColour) { + HBITMAP hbmp; + +#if wxUSE_WXDIB && wxUSE_IMAGE + // See the comment in overloaded Add() above. + AutoHBITMAP hbmpRelease; + if ( bitmap.HasAlpha() ) + { + hbmp = wxDIB(bitmap.ConvertToImage(), + wxDIB::PixelFormat_NotPreMultiplied).Detach(); + hbmpRelease.Init(hbmp); + } + else +#endif // wxUSE_WXDIB && wxUSE_IMAGE + hbmp = GetHbitmapOf(bitmap); + int index = ImageList_AddMasked(GetHImageList(), - GetHbitmapOf(bitmap), + hbmp, wxColourToRGB(maskColour)); if ( index == -1 ) { @@ -189,26 +217,39 @@ int wxImageList::Add(const wxIcon& icon) // Note that wxImageList creates new bitmaps, so you may delete // 'bitmap' and 'mask'. bool wxImageList::Replace(int index, - const wxBitmap& bitmap, const wxBitmap& mask) + const wxBitmap& bitmap, + const wxBitmap& mask) { - HBITMAP hbmpMask = GetMaskForImage(bitmap, mask); + HBITMAP hbmp; - bool ok = ImageList_Replace(GetHImageList(), index, - GetHbitmapOf(bitmap), hbmpMask) != 0; - if ( !ok ) +#if wxUSE_WXDIB && wxUSE_IMAGE + // See the comment in Add() above. + AutoHBITMAP hbmpRelease; + if ( bitmap.HasAlpha() ) { - wxLogLastError(wxT("ImageList_Add()")); + hbmp = wxDIB(bitmap.ConvertToImage(), + wxDIB::PixelFormat_NotPreMultiplied).Detach(); + hbmpRelease.Init(hbmp); } + else +#endif // wxUSE_WXDIB && wxUSE_IMAGE + hbmp = GetHbitmapOf(bitmap); - ::DeleteObject(hbmpMask); + AutoHBITMAP hbmpMask(GetMaskForImage(bitmap, mask)); - return ok; + if ( !ImageList_Replace(GetHImageList(), index, hbmp, hbmpMask) ) + { + wxLogLastError(wxT("ImageList_Replace()")); + return false; + } + + return true; } // Replaces a bitmap and mask from an icon. bool wxImageList::Replace(int i, const wxIcon& icon) { - bool ok = ImageList_ReplaceIcon(GetHImageList(), i, GetHiconOf(icon)) != 0; + bool ok = ImageList_ReplaceIcon(GetHImageList(), i, GetHiconOf(icon)) != -1; if ( !ok ) { wxLogLastError(wxT("ImageList_ReplaceIcon()")); @@ -233,19 +274,11 @@ bool wxImageList::Remove(int index) bool wxImageList::RemoveAll() { // don't use ImageList_RemoveAll() because mingw32 headers don't have it - int count = ImageList_GetImageCount(GetHImageList()); - for ( int i = 0; i < count; i++ ) - { - // the image indexes are shifted, so we should always remove the first - // one - (void)Remove(0); - } - - return TRUE; + return Remove(-1); } // Draws the given image on a dc at the specified position. -// If 'solidBackground' is TRUE, Draw sets the image list background +// If 'solidBackground' is true, Draw sets the image list background // colour to the background colour of the wxDC, to speed up // drawing by eliminating masked drawing where possible. bool wxImageList::Draw(int index, @@ -254,16 +287,21 @@ bool wxImageList::Draw(int index, int flags, bool solidBackground) { - HDC hDC = GetHdcOf(dc); - wxCHECK_MSG( hDC, FALSE, _T("invalid wxDC in wxImageList::Draw") ); + wxDCImpl *impl = dc.GetImpl(); + wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl ); + if (!msw_impl) + return false; + + HDC hDC = GetHdcOf(*msw_impl); + wxCHECK_MSG( hDC, false, wxT("invalid wxDC in wxImageList::Draw") ); COLORREF clr = CLR_NONE; // transparent by default if ( solidBackground ) { - wxBrush *brush = & dc.GetBackground(); - if ( brush && brush->Ok() ) + const wxBrush& brush = dc.GetBackground(); + if ( brush.IsOk() ) { - clr = wxColourToRGB(brush->GetColour()); + clr = wxColourToRGB(brush.GetColour()); } } @@ -288,17 +326,80 @@ bool wxImageList::Draw(int index, return ok; } +// Get the bitmap +wxBitmap wxImageList::GetBitmap(int index) const +{ +#if wxUSE_WXDIB && wxUSE_IMAGE + int bmp_width = 0, bmp_height = 0; + GetSize(index, bmp_width, bmp_height); + + wxBitmap bitmap(bmp_width, bmp_height); + wxMemoryDC dc; + dc.SelectObject(bitmap); + + // draw it the first time to find a suitable mask colour + ((wxImageList*)this)->Draw(index, dc, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT); + dc.SelectObject(wxNullBitmap); + + // find the suitable mask colour + wxImage image = bitmap.ConvertToImage(); + unsigned char r = 0, g = 0, b = 0; + image.FindFirstUnusedColour(&r, &g, &b); + + // redraw whole image and bitmap in the mask colour + image.Create(bmp_width, bmp_height); + image.Replace(0, 0, 0, r, g, b); + bitmap = wxBitmap(image); + + // redraw icon over the mask colour to actually draw it + dc.SelectObject(bitmap); + ((wxImageList*)this)->Draw(index, dc, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT); + dc.SelectObject(wxNullBitmap); + + // get the image, set the mask colour and convert back to get transparent bitmap + image = bitmap.ConvertToImage(); + image.SetMaskColour(r, g, b); + bitmap = wxBitmap(image); +#else + wxBitmap bitmap; +#endif + return bitmap; +} + +// Get the icon +wxIcon wxImageList::GetIcon(int index) const +{ + HICON hIcon = ImageList_ExtractIcon(0, GetHImageList(), index); + if (hIcon) + { + wxIcon icon; + icon.SetHICON((WXHICON)hIcon); + + int iconW, iconH; + GetSize(index, iconW, iconH); + icon.SetSize(iconW, iconH); + + return icon; + } + else + return wxNullIcon; +} + // ---------------------------------------------------------------------------- // helpers // ---------------------------------------------------------------------------- static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask) { +#if wxUSE_IMAGE + wxBitmap bitmapWithMask; +#endif // wxUSE_IMAGE + HBITMAP hbmpMask; wxMask *pMask; - bool deleteMask = FALSE; + bool deleteMask = false; - if ( mask.Ok() ) + if ( mask.IsOk() ) { hbmpMask = GetHbitmapOf(mask); pMask = NULL; @@ -306,6 +407,23 @@ static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask) else { pMask = bitmap.GetMask(); + +#if wxUSE_IMAGE + // check if we don't have alpha in this bitmap -- we can create a mask + // from it (and we need to do it for the older systems which don't + // support 32bpp bitmaps natively) + if ( !pMask ) + { + wxImage img(bitmap.ConvertToImage()); + if ( img.HasAlpha() ) + { + img.ConvertAlphaToMask(); + bitmapWithMask = wxBitmap(img); + pMask = bitmapWithMask.GetMask(); + } + } +#endif // wxUSE_IMAGE + if ( !pMask ) { // use the light grey count as transparent: the trouble here is @@ -317,13 +435,13 @@ static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask) pMask = new wxMask(bitmap, col); - deleteMask = TRUE; + deleteMask = true; } hbmpMask = (HBITMAP)pMask->GetMaskBitmap(); } - // windows mask convention is opposite to the wxWindows one + // windows mask convention is opposite to the wxWidgets one HBITMAP hbmpMaskInv = wxInvertMask(hbmpMask); if ( deleteMask ) @@ -333,6 +451,3 @@ static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask) return hbmpMaskInv; } - -#endif // Win95 -