1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/imaglist.cpp 
   3 // Purpose:     wxImageList implementation for Win32 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  28     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  29     #include "wx/window.h" 
  32     #include "wx/string.h" 
  33     #include "wx/dcmemory.h" 
  40 #include "wx/imaglist.h" 
  42 #include "wx/msw/dc.h" 
  43 #include "wx/msw/private.h" 
  45 // ---------------------------------------------------------------------------- 
  47 // ---------------------------------------------------------------------------- 
  49 IMPLEMENT_DYNAMIC_CLASS(wxImageList
, wxObject
) 
  51 #define GetHImageList()     ((HIMAGELIST)m_hImageList) 
  53 // ---------------------------------------------------------------------------- 
  55 // ---------------------------------------------------------------------------- 
  57 // returns the mask if it's valid, otherwise the bitmap mask and, if it's not 
  58 // valid neither, a "solid" mask (no transparent zones at all) 
  59 static HBITMAP 
GetMaskForImage(const wxBitmap
& bitmap
, const wxBitmap
& mask
); 
  61 // ============================================================================ 
  63 // ============================================================================ 
  65 // ---------------------------------------------------------------------------- 
  66 // wxImageList creation/destruction 
  67 // ---------------------------------------------------------------------------- 
  69 wxImageList::wxImageList() 
  74 // Creates an image list 
  75 bool wxImageList::Create(int width
, int height
, bool mask
, int initial
) 
  79     // set appropriate color depth 
  83     int dd 
= wxDisplayDepth(); 
  85     if (dd 
<= 4)       flags 
|= ILC_COLOR
;   // 16 color 
  86     else if (dd 
<= 8)  flags 
|= ILC_COLOR8
;  // 256 color 
  87     else if (dd 
<= 16) flags 
|= ILC_COLOR16
; // 64k hi-color 
  88     else if (dd 
<= 24) flags 
|= ILC_COLOR24
; // 16m truecolor 
  89     else if (dd 
<= 32) flags 
|= ILC_COLOR32
; // 16m truecolor 
  95     // Grow by 1, I guess this is reasonable behaviour most of the time 
  96     m_hImageList 
= (WXHIMAGELIST
) ImageList_Create(width
, height
, flags
, 
 100         wxLogLastError(wxT("ImageList_Create()")); 
 103     return m_hImageList 
!= 0; 
 106 wxImageList::~wxImageList() 
 110         ImageList_Destroy(GetHImageList()); 
 115 // ---------------------------------------------------------------------------- 
 116 // wxImageList attributes 
 117 // ---------------------------------------------------------------------------- 
 119 // Returns the number of images in the image list. 
 120 int wxImageList::GetImageCount() const 
 122     wxASSERT_MSG( m_hImageList
, _T("invalid image list") ); 
 124     return ImageList_GetImageCount(GetHImageList()); 
 127 // Returns the size (same for all images) of the images in the list 
 128 bool wxImageList::GetSize(int WXUNUSED(index
), int &width
, int &height
) const 
 130     wxASSERT_MSG( m_hImageList
, _T("invalid image list") ); 
 132     return ImageList_GetIconSize(GetHImageList(), &width
, &height
) != 0; 
 135 // ---------------------------------------------------------------------------- 
 136 // wxImageList operations 
 137 // ---------------------------------------------------------------------------- 
 139 // Adds a bitmap, and optionally a mask bitmap. 
 140 // Note that wxImageList creates new bitmaps, so you may delete 
 141 // 'bitmap' and 'mask'. 
 142 int wxImageList::Add(const wxBitmap
& bitmap
, const wxBitmap
& mask
) 
 144     HBITMAP hbmpMask 
= GetMaskForImage(bitmap
, mask
); 
 146     int index 
= ImageList_Add(GetHImageList(), GetHbitmapOf(bitmap
), hbmpMask
); 
 149         wxLogError(_("Couldn't add an image to the image list.")); 
 152     ::DeleteObject(hbmpMask
); 
 157 // Adds a bitmap, using the specified colour to create the mask bitmap 
 158 // Note that wxImageList creates new bitmaps, so you may delete 
 160 int wxImageList::Add(const wxBitmap
& bitmap
, const wxColour
& maskColour
) 
 162     int index 
= ImageList_AddMasked(GetHImageList(), 
 163                                     GetHbitmapOf(bitmap
), 
 164                                     wxColourToRGB(maskColour
)); 
 167         wxLogError(_("Couldn't add an image to the image list.")); 
 173 // Adds a bitmap and mask from an icon. 
 174 int wxImageList::Add(const wxIcon
& icon
) 
 176     int index 
= ImageList_AddIcon(GetHImageList(), GetHiconOf(icon
)); 
 179         wxLogError(_("Couldn't add an image to the image list.")); 
 185 // Replaces a bitmap, optionally passing a mask bitmap. 
 186 // Note that wxImageList creates new bitmaps, so you may delete 
 187 // 'bitmap' and 'mask'. 
 188 bool wxImageList::Replace(int index
, 
 189                           const wxBitmap
& bitmap
, const wxBitmap
& mask
) 
 191     HBITMAP hbmpMask 
= GetMaskForImage(bitmap
, mask
); 
 193     bool ok 
= ImageList_Replace(GetHImageList(), index
, 
 194                                 GetHbitmapOf(bitmap
), hbmpMask
) != 0; 
 197         wxLogLastError(wxT("ImageList_Replace()")); 
 200     ::DeleteObject(hbmpMask
); 
 205 // Replaces a bitmap and mask from an icon. 
 206 bool wxImageList::Replace(int i
, const wxIcon
& icon
) 
 208     bool ok 
= ImageList_ReplaceIcon(GetHImageList(), i
, GetHiconOf(icon
)) != -1; 
 211         wxLogLastError(wxT("ImageList_ReplaceIcon()")); 
 217 // Removes the image at the given index. 
 218 bool wxImageList::Remove(int index
) 
 220     bool ok 
= ImageList_Remove(GetHImageList(), index
) != 0; 
 223         wxLogLastError(wxT("ImageList_Remove()")); 
 230 bool wxImageList::RemoveAll() 
 232     // don't use ImageList_RemoveAll() because mingw32 headers don't have it 
 236 // Draws the given image on a dc at the specified position. 
 237 // If 'solidBackground' is true, Draw sets the image list background 
 238 // colour to the background colour of the wxDC, to speed up 
 239 // drawing by eliminating masked drawing where possible. 
 240 bool wxImageList::Draw(int index
, 
 244                        bool solidBackground
) 
 246     wxDCImpl 
*impl 
= dc
.GetImpl(); 
 247     wxMSWDCImpl 
*msw_impl 
= wxDynamicCast( impl
, wxMSWDCImpl 
); 
 251     HDC hDC 
= GetHdcOf(*msw_impl
); 
 252     wxCHECK_MSG( hDC
, false, _T("invalid wxDC in wxImageList::Draw") ); 
 254     COLORREF clr 
= CLR_NONE
;    // transparent by default 
 255     if ( solidBackground 
) 
 257         const wxBrush
& brush 
= dc
.GetBackground(); 
 260             clr 
= wxColourToRGB(brush
.GetColour()); 
 264     ImageList_SetBkColor(GetHImageList(), clr
); 
 267     if ( flags 
& wxIMAGELIST_DRAW_NORMAL 
) 
 269     if ( flags 
& wxIMAGELIST_DRAW_TRANSPARENT 
) 
 270         style 
|= ILD_TRANSPARENT
; 
 271     if ( flags 
& wxIMAGELIST_DRAW_SELECTED 
) 
 272         style 
|= ILD_SELECTED
; 
 273     if ( flags 
& wxIMAGELIST_DRAW_FOCUSED 
) 
 276     bool ok 
= ImageList_Draw(GetHImageList(), index
, hDC
, x
, y
, style
) != 0; 
 279         wxLogLastError(wxT("ImageList_Draw()")); 
 286 wxBitmap 
wxImageList::GetBitmap(int index
) const 
 288 #if wxUSE_WXDIB && wxUSE_IMAGE 
 289     int bmp_width 
= 0, bmp_height 
= 0; 
 290     GetSize(index
, bmp_width
, bmp_height
); 
 292     wxBitmap 
bitmap(bmp_width
, bmp_height
); 
 294     dc
.SelectObject(bitmap
); 
 296     // draw it the first time to find a suitable mask colour 
 297     ((wxImageList
*)this)->Draw(index
, dc
, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT
); 
 298     dc
.SelectObject(wxNullBitmap
); 
 300     // find the suitable mask colour 
 301     wxImage image 
= bitmap
.ConvertToImage(); 
 302     unsigned char r 
= 0, g 
= 0, b 
= 0; 
 303     image
.FindFirstUnusedColour(&r
, &g
, &b
); 
 305     // redraw whole image and bitmap in the mask colour 
 306     image
.Create(bmp_width
, bmp_height
); 
 307     image
.Replace(0, 0, 0, r
, g
, b
); 
 308     bitmap 
= wxBitmap(image
); 
 310     // redraw icon over the mask colour to actually draw it 
 311     dc
.SelectObject(bitmap
); 
 312     ((wxImageList
*)this)->Draw(index
, dc
, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT
); 
 313     dc
.SelectObject(wxNullBitmap
); 
 315     // get the image, set the mask colour and convert back to get transparent bitmap 
 316     image 
= bitmap
.ConvertToImage(); 
 317     image
.SetMaskColour(r
, g
, b
); 
 318     bitmap 
= wxBitmap(image
); 
 326 wxIcon 
wxImageList::GetIcon(int index
) const 
 328     HICON hIcon 
= ImageList_ExtractIcon(0, GetHImageList(), index
); 
 332         icon
.SetHICON((WXHICON
)hIcon
); 
 335         GetSize(index
, iconW
, iconH
); 
 336         icon
.SetSize(iconW
, iconH
); 
 344 // ---------------------------------------------------------------------------- 
 346 // ---------------------------------------------------------------------------- 
 348 static HBITMAP 
GetMaskForImage(const wxBitmap
& bitmap
, const wxBitmap
& mask
) 
 351     wxBitmap bitmapWithMask
; 
 352 #endif // wxUSE_IMAGE 
 356     bool deleteMask 
= false; 
 360         hbmpMask 
= GetHbitmapOf(mask
); 
 365         pMask 
= bitmap
.GetMask(); 
 368         // check if we don't have alpha in this bitmap -- we can create a mask 
 369         // from it (and we need to do it for the older systems which don't 
 370         // support 32bpp bitmaps natively) 
 373             wxImage 
img(bitmap
.ConvertToImage()); 
 374             if ( img
.HasAlpha() ) 
 376                 img
.ConvertAlphaToMask(); 
 377                 bitmapWithMask 
= wxBitmap(img
); 
 378                 pMask 
= bitmapWithMask
.GetMask(); 
 381 #endif // wxUSE_IMAGE 
 385             // use the light grey count as transparent: the trouble here is 
 386             // that the light grey might have been changed by Windows behind 
 387             // our back, so use the standard colour map to get its real value 
 388             wxCOLORMAP 
*cmap 
= wxGetStdColourMap(); 
 390             wxRGBToColour(col
, cmap
[wxSTD_COL_BTNFACE
].from
); 
 392             pMask 
= new wxMask(bitmap
, col
); 
 397         hbmpMask 
= (HBITMAP
)pMask
->GetMaskBitmap(); 
 400     // windows mask convention is opposite to the wxWidgets one 
 401     HBITMAP hbmpMaskInv 
= wxInvertMask(hbmpMask
);