]> git.saurik.com Git - wxWidgets.git/blame - src/msw/imaglist.cpp
Correct erasing of background behind controls in a toolbar in wxMSW.
[wxWidgets.git] / src / msw / imaglist.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
4b7f2165
VZ
2// Name: src/msw/imaglist.cpp
3// Purpose: wxImageList implementation for Win32
2bda0e17
KB
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
6c9a19aa 7// Copyright: (c) Julian Smart
65571936 8// Licence: wxWindows licence
2bda0e17
KB
9/////////////////////////////////////////////////////////////////////////////
10
4b7f2165
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
2bda0e17
KB
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
4b7f2165 23 #pragma hdrstop
2bda0e17
KB
24#endif
25
2bda0e17 26#ifndef WX_PRECOMP
57bd4c60 27 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
4b7f2165
VZ
28 #include "wx/window.h"
29 #include "wx/icon.h"
30 #include "wx/dc.h"
31 #include "wx/string.h"
e0f15f4a 32 #include "wx/dcmemory.h"
88a7a4e1 33 #include "wx/intl.h"
e4db172a 34 #include "wx/log.h"
155ecd4c 35 #include "wx/image.h"
4b7f2165 36 #include <stdio.h>
2bda0e17
KB
37#endif
38
01f512d7 39#include "wx/imaglist.h"
888dde65
RR
40#include "wx/dc.h"
41#include "wx/msw/dc.h"
5c96c864 42#include "wx/msw/dib.h"
2bda0e17
KB
43#include "wx/msw/private.h"
44
4b7f2165
VZ
45// ----------------------------------------------------------------------------
46// wxWin macros
47// ----------------------------------------------------------------------------
48
2bda0e17 49IMPLEMENT_DYNAMIC_CLASS(wxImageList, wxObject)
2bda0e17 50
4b7f2165
VZ
51#define GetHImageList() ((HIMAGELIST)m_hImageList)
52
53// ----------------------------------------------------------------------------
54// private functions
55// ----------------------------------------------------------------------------
56
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)
3ca6a5f0 59static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask);
4b7f2165
VZ
60
61// ============================================================================
62// implementation
63// ============================================================================
64
65// ----------------------------------------------------------------------------
66// wxImageList creation/destruction
67// ----------------------------------------------------------------------------
68
69wxImageList::wxImageList()
2bda0e17
KB
70{
71 m_hImageList = 0;
72}
73
4b7f2165
VZ
74// Creates an image list
75bool wxImageList::Create(int width, int height, bool mask, int initial)
2bda0e17 76{
a6e2b3a8
VZ
77 UINT flags = 0;
78
a6712ab9
VZ
79 // as we want to be able to use 32bpp bitmaps in the image lists, we always
80 // use ILC_COLOR32, even if the display resolution is less -- the system
81 // will make the best effort to show the bitmap if we do this resulting in
82 // quite acceptable display while using a lower depth ILC_COLOR constant
83 // (e.g. ILC_COLOR16) shows completely broken bitmaps
4676948b
JS
84#ifdef __WXWINCE__
85 flags |= ILC_COLOR;
86#else
a6712ab9 87 flags |= ILC_COLOR32;
4676948b 88#endif
a6e2b3a8 89
4b7f2165
VZ
90 if ( mask )
91 flags |= ILC_MASK;
92
93 // Grow by 1, I guess this is reasonable behaviour most of the time
94 m_hImageList = (WXHIMAGELIST) ImageList_Create(width, height, flags,
95 initial, 1);
96 if ( !m_hImageList )
97 {
f6bcfd97 98 wxLogLastError(wxT("ImageList_Create()"));
4b7f2165 99 }
2bda0e17 100
4b7f2165
VZ
101 return m_hImageList != 0;
102}
2bda0e17 103
4b7f2165 104wxImageList::~wxImageList()
2bda0e17 105{
4b7f2165
VZ
106 if ( m_hImageList )
107 {
108 ImageList_Destroy(GetHImageList());
109 m_hImageList = 0;
110 }
2bda0e17
KB
111}
112
4b7f2165
VZ
113// ----------------------------------------------------------------------------
114// wxImageList attributes
115// ----------------------------------------------------------------------------
2bda0e17 116
4b7f2165
VZ
117// Returns the number of images in the image list.
118int wxImageList::GetImageCount() const
2bda0e17 119{
9a83f860 120 wxASSERT_MSG( m_hImageList, wxT("invalid image list") );
2bda0e17 121
4b7f2165 122 return ImageList_GetImageCount(GetHImageList());
2bda0e17
KB
123}
124
f6bcfd97
BP
125// Returns the size (same for all images) of the images in the list
126bool wxImageList::GetSize(int WXUNUSED(index), int &width, int &height) const
127{
9a83f860 128 wxASSERT_MSG( m_hImageList, wxT("invalid image list") );
f6bcfd97
BP
129
130 return ImageList_GetIconSize(GetHImageList(), &width, &height) != 0;
131}
132
4b7f2165
VZ
133// ----------------------------------------------------------------------------
134// wxImageList operations
135// ----------------------------------------------------------------------------
136
2bda0e17
KB
137// Adds a bitmap, and optionally a mask bitmap.
138// Note that wxImageList creates new bitmaps, so you may delete
139// 'bitmap' and 'mask'.
140int wxImageList::Add(const wxBitmap& bitmap, const wxBitmap& mask)
141{
5c96c864
VZ
142 HBITMAP hbmp;
143
144#if wxUSE_WXDIB && wxUSE_IMAGE
145 // wxBitmap normally stores alpha in pre-multiplied format but
146 // ImageList_Draw() does pre-multiplication internally so we need to undo
147 // the pre-multiplication here. Converting back and forth like this is, of
148 // course, very inefficient but it's better than wrong appearance so we do
149 // this for now until a better way can be found.
150 AutoHBITMAP hbmpRelease;
151 if ( bitmap.HasAlpha() )
152 {
153 hbmp = wxDIB(bitmap.ConvertToImage(),
154 wxDIB::PixelFormat_NotPreMultiplied).Detach();
155 hbmpRelease.Init(hbmp);
156 }
157 else
158#endif // wxUSE_WXDIB && wxUSE_IMAGE
159 hbmp = GetHbitmapOf(bitmap);
160
f7196178 161 AutoHBITMAP hbmpMask(GetMaskForImage(bitmap, mask));
e29b83a4 162
5c96c864 163 int index = ImageList_Add(GetHImageList(), hbmp, hbmpMask);
4b7f2165 164 if ( index == -1 )
e29b83a4
VZ
165 {
166 wxLogError(_("Couldn't add an image to the image list."));
167 }
168
169 return index;
2bda0e17
KB
170}
171
172// Adds a bitmap, using the specified colour to create the mask bitmap
173// Note that wxImageList creates new bitmaps, so you may delete
174// 'bitmap'.
175int wxImageList::Add(const wxBitmap& bitmap, const wxColour& maskColour)
176{
5c96c864
VZ
177 HBITMAP hbmp;
178
179#if wxUSE_WXDIB && wxUSE_IMAGE
180 // See the comment in overloaded Add() above.
181 AutoHBITMAP hbmpRelease;
182 if ( bitmap.HasAlpha() )
183 {
184 hbmp = wxDIB(bitmap.ConvertToImage(),
185 wxDIB::PixelFormat_NotPreMultiplied).Detach();
186 hbmpRelease.Init(hbmp);
187 }
188 else
189#endif // wxUSE_WXDIB && wxUSE_IMAGE
190 hbmp = GetHbitmapOf(bitmap);
191
4b7f2165 192 int index = ImageList_AddMasked(GetHImageList(),
5c96c864 193 hbmp,
4b7f2165
VZ
194 wxColourToRGB(maskColour));
195 if ( index == -1 )
196 {
197 wxLogError(_("Couldn't add an image to the image list."));
198 }
199
200 return index;
2bda0e17
KB
201}
202
203// Adds a bitmap and mask from an icon.
204int wxImageList::Add(const wxIcon& icon)
205{
4b7f2165
VZ
206 int index = ImageList_AddIcon(GetHImageList(), GetHiconOf(icon));
207 if ( index == -1 )
208 {
209 wxLogError(_("Couldn't add an image to the image list."));
210 }
211
212 return index;
2bda0e17
KB
213}
214
215// Replaces a bitmap, optionally passing a mask bitmap.
216// Note that wxImageList creates new bitmaps, so you may delete
217// 'bitmap' and 'mask'.
4b7f2165 218bool wxImageList::Replace(int index,
5c96c864
VZ
219 const wxBitmap& bitmap,
220 const wxBitmap& mask)
2bda0e17 221{
5c96c864
VZ
222 HBITMAP hbmp;
223
224#if wxUSE_WXDIB && wxUSE_IMAGE
225 // See the comment in Add() above.
226 AutoHBITMAP hbmpRelease;
227 if ( bitmap.HasAlpha() )
228 {
229 hbmp = wxDIB(bitmap.ConvertToImage(),
230 wxDIB::PixelFormat_NotPreMultiplied).Detach();
231 hbmpRelease.Init(hbmp);
232 }
233 else
234#endif // wxUSE_WXDIB && wxUSE_IMAGE
235 hbmp = GetHbitmapOf(bitmap);
236
f7196178 237 AutoHBITMAP hbmpMask(GetMaskForImage(bitmap, mask));
2bda0e17 238
f7196178 239 if ( !ImageList_Replace(GetHImageList(), index, hbmp, hbmpMask) )
4b7f2165 240 {
3103e8a9 241 wxLogLastError(wxT("ImageList_Replace()"));
f7196178 242 return false;
4b7f2165
VZ
243 }
244
f7196178 245 return true;
2bda0e17 246}
2bda0e17
KB
247
248// Replaces a bitmap and mask from an icon.
4b7f2165 249bool wxImageList::Replace(int i, const wxIcon& icon)
2bda0e17 250{
9fe0c2fc 251 bool ok = ImageList_ReplaceIcon(GetHImageList(), i, GetHiconOf(icon)) != -1;
4b7f2165
VZ
252 if ( !ok )
253 {
f6bcfd97 254 wxLogLastError(wxT("ImageList_ReplaceIcon()"));
4b7f2165
VZ
255 }
256
257 return ok;
2bda0e17
KB
258}
259
260// Removes the image at the given index.
debe6624 261bool wxImageList::Remove(int index)
2bda0e17 262{
4b7f2165
VZ
263 bool ok = ImageList_Remove(GetHImageList(), index) != 0;
264 if ( !ok )
265 {
f6bcfd97 266 wxLogLastError(wxT("ImageList_Remove()"));
4b7f2165
VZ
267 }
268
269 return ok;
2bda0e17
KB
270}
271
272// Remove all images
4b7f2165 273bool wxImageList::RemoveAll()
2bda0e17 274{
3c1a88d8 275 // don't use ImageList_RemoveAll() because mingw32 headers don't have it
1c304f30 276 return Remove(-1);
2bda0e17
KB
277}
278
279// Draws the given image on a dc at the specified position.
59af881e 280// If 'solidBackground' is true, Draw sets the image list background
2bda0e17
KB
281// colour to the background colour of the wxDC, to speed up
282// drawing by eliminating masked drawing where possible.
4b7f2165
VZ
283bool wxImageList::Draw(int index,
284 wxDC& dc,
285 int x, int y,
286 int flags,
287 bool solidBackground)
2bda0e17 288{
888dde65
RR
289 wxDCImpl *impl = dc.GetImpl();
290 wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl );
291 if (!msw_impl)
292 return false;
03647350 293
888dde65 294 HDC hDC = GetHdcOf(*msw_impl);
9a83f860 295 wxCHECK_MSG( hDC, false, wxT("invalid wxDC in wxImageList::Draw") );
4b7f2165
VZ
296
297 COLORREF clr = CLR_NONE; // transparent by default
298 if ( solidBackground )
299 {
b33576e1 300 const wxBrush& brush = dc.GetBackground();
a1b806b9 301 if ( brush.IsOk() )
4b7f2165 302 {
b33576e1 303 clr = wxColourToRGB(brush.GetColour());
4b7f2165
VZ
304 }
305 }
306
307 ImageList_SetBkColor(GetHImageList(), clr);
2bda0e17
KB
308
309 UINT style = 0;
4b7f2165
VZ
310 if ( flags & wxIMAGELIST_DRAW_NORMAL )
311 style |= ILD_NORMAL;
312 if ( flags & wxIMAGELIST_DRAW_TRANSPARENT )
313 style |= ILD_TRANSPARENT;
314 if ( flags & wxIMAGELIST_DRAW_SELECTED )
315 style |= ILD_SELECTED;
316 if ( flags & wxIMAGELIST_DRAW_FOCUSED )
317 style |= ILD_FOCUS;
318
319 bool ok = ImageList_Draw(GetHImageList(), index, hDC, x, y, style) != 0;
320 if ( !ok )
321 {
f6bcfd97 322 wxLogLastError(wxT("ImageList_Draw()"));
4b7f2165
VZ
323 }
324
325 return ok;
2bda0e17
KB
326}
327
49bf4e3e
JS
328// Get the bitmap
329wxBitmap wxImageList::GetBitmap(int index) const
330{
a8ff046b 331#if wxUSE_WXDIB && wxUSE_IMAGE
49bf4e3e
JS
332 int bmp_width = 0, bmp_height = 0;
333 GetSize(index, bmp_width, bmp_height);
334
335 wxBitmap bitmap(bmp_width, bmp_height);
336 wxMemoryDC dc;
337 dc.SelectObject(bitmap);
338
339 // draw it the first time to find a suitable mask colour
340 ((wxImageList*)this)->Draw(index, dc, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT);
341 dc.SelectObject(wxNullBitmap);
342
343 // find the suitable mask colour
344 wxImage image = bitmap.ConvertToImage();
345 unsigned char r = 0, g = 0, b = 0;
346 image.FindFirstUnusedColour(&r, &g, &b);
347
348 // redraw whole image and bitmap in the mask colour
349 image.Create(bmp_width, bmp_height);
350 image.Replace(0, 0, 0, r, g, b);
351 bitmap = wxBitmap(image);
352
353 // redraw icon over the mask colour to actually draw it
354 dc.SelectObject(bitmap);
355 ((wxImageList*)this)->Draw(index, dc, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT);
356 dc.SelectObject(wxNullBitmap);
357
358 // get the image, set the mask colour and convert back to get transparent bitmap
359 image = bitmap.ConvertToImage();
360 image.SetMaskColour(r, g, b);
361 bitmap = wxBitmap(image);
64c288fa
JS
362#else
363 wxBitmap bitmap;
64c288fa 364#endif
74aa8254 365 return bitmap;
49bf4e3e
JS
366}
367
368// Get the icon
369wxIcon wxImageList::GetIcon(int index) const
370{
371 HICON hIcon = ImageList_ExtractIcon(0, GetHImageList(), index);
372 if (hIcon)
373 {
374 wxIcon icon;
375 icon.SetHICON((WXHICON)hIcon);
a71d815b 376
49bf4e3e
JS
377 int iconW, iconH;
378 GetSize(index, iconW, iconH);
379 icon.SetSize(iconW, iconH);
a71d815b 380
49bf4e3e
JS
381 return icon;
382 }
a71d815b 383 else
49bf4e3e
JS
384 return wxNullIcon;
385}
386
4b7f2165
VZ
387// ----------------------------------------------------------------------------
388// helpers
389// ----------------------------------------------------------------------------
390
3ca6a5f0 391static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask)
4b7f2165 392{
e4a84806
VZ
393#if wxUSE_IMAGE
394 wxBitmap bitmapWithMask;
395#endif // wxUSE_IMAGE
396
3ca6a5f0 397 HBITMAP hbmpMask;
90c1530a 398 wxMask *pMask;
59af881e 399 bool deleteMask = false;
4b7f2165 400
a1b806b9 401 if ( mask.IsOk() )
4b7f2165 402 {
3ca6a5f0 403 hbmpMask = GetHbitmapOf(mask);
90c1530a 404 pMask = NULL;
4b7f2165
VZ
405 }
406 else
407 {
90c1530a 408 pMask = bitmap.GetMask();
e4a84806
VZ
409
410#if wxUSE_IMAGE
411 // check if we don't have alpha in this bitmap -- we can create a mask
412 // from it (and we need to do it for the older systems which don't
413 // support 32bpp bitmaps natively)
414 if ( !pMask )
415 {
416 wxImage img(bitmap.ConvertToImage());
417 if ( img.HasAlpha() )
418 {
419 img.ConvertAlphaToMask();
420 bitmapWithMask = wxBitmap(img);
421 pMask = bitmapWithMask.GetMask();
422 }
423 }
424#endif // wxUSE_IMAGE
425
90c1530a 426 if ( !pMask )
4b7f2165 427 {
90c1530a
VZ
428 // use the light grey count as transparent: the trouble here is
429 // that the light grey might have been changed by Windows behind
430 // our back, so use the standard colour map to get its real value
431 wxCOLORMAP *cmap = wxGetStdColourMap();
432 wxColour col;
433 wxRGBToColour(col, cmap[wxSTD_COL_BTNFACE].from);
4b7f2165 434
90c1530a 435 pMask = new wxMask(bitmap, col);
3ca6a5f0 436
59af881e 437 deleteMask = true;
3ca6a5f0 438 }
90c1530a
VZ
439
440 hbmpMask = (HBITMAP)pMask->GetMaskBitmap();
4b7f2165
VZ
441 }
442
77ffb593 443 // windows mask convention is opposite to the wxWidgets one
3ca6a5f0 444 HBITMAP hbmpMaskInv = wxInvertMask(hbmpMask);
90c1530a
VZ
445
446 if ( deleteMask )
447 {
448 delete pMask;
449 }
3ca6a5f0
BP
450
451 return hbmpMaskInv;
4b7f2165 452}