[LT2013]
[reactos.git] / dll / win32 / comctl32 / imagelist.c
1 /*
2 * ImageList implementation
3 *
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001, 2004 Michael Stefaniuc
7 * Copyright 2001 Charles Loep for CodeWeavers
8 * Copyright 2002 Dimitrie O. Paun
9 * Copyright 2009 Owen Rudge for CodeWeavers
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 *
25 * NOTE
26 *
27 * This code was audited for completeness against the documented features
28 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 *
30 * Unless otherwise noted, we believe this code to be complete, as per
31 * the specification mentioned above.
32 * If you discover missing features, or bugs, please note them below.
33 *
34 * TODO:
35 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
36 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE
37 * - Thread-safe locking
38 */
39
40 #define _INC_WINDOWS
41 #define COM_NO_WINDOWS_H
42
43 #include <stdarg.h>
44 //#include <stdlib.h>
45 //#include <string.h>
46
47 #define COBJMACROS
48
49 //#include "winerror.h"
50 #include <windef.h>
51 #include <winbase.h>
52 #include <objbase.h>
53 //#include "wingdi.h"
54 #include <winnls.h>
55 //#include "winuser.h"
56 //#include "commctrl.h"
57 #include "comctl32.h"
58 #include <commoncontrols.h>
59 #include <wine/debug.h>
60 #include <wine/exception.h>
61
62 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
63
64 #define MAX_OVERLAYIMAGE 15
65
66 struct _IMAGELIST
67 {
68 const struct IImageListVtbl *lpVtbl; /* 00: IImageList vtable */
69
70 INT cCurImage; /* 04: ImageCount */
71 INT cMaxImage; /* 08: maximages */
72 INT cGrow; /* 0C: cGrow */
73 INT cx; /* 10: cx */
74 INT cy; /* 14: cy */
75 DWORD x4;
76 UINT flags; /* 1C: flags */
77 COLORREF clrFg; /* 20: foreground color */
78 COLORREF clrBk; /* 24: background color */
79
80
81 HBITMAP hbmImage; /* 28: images Bitmap */
82 HBITMAP hbmMask; /* 2C: masks Bitmap */
83 HDC hdcImage; /* 30: images MemDC */
84 HDC hdcMask; /* 34: masks MemDC */
85 INT nOvlIdx[MAX_OVERLAYIMAGE]; /* 38: overlay images index */
86
87 /* not yet found out */
88 HBRUSH hbrBlend25;
89 HBRUSH hbrBlend50;
90 INT cInitial;
91 UINT uBitsPixel;
92 char *has_alpha;
93
94 LONG ref; /* reference count */
95 };
96
97 #define IMAGELIST_MAGIC 0x53414D58
98
99 /* Header used by ImageList_Read() and ImageList_Write() */
100 #include "pshpack2.h"
101 typedef struct _ILHEAD
102 {
103 USHORT usMagic;
104 USHORT usVersion;
105 WORD cCurImage;
106 WORD cMaxImage;
107 WORD cGrow;
108 WORD cx;
109 WORD cy;
110 COLORREF bkcolor;
111 WORD flags;
112 SHORT ovls[4];
113 } ILHEAD;
114 #include "poppack.h"
115
116 /* internal image list data used for Drag & Drop operations */
117 typedef struct
118 {
119 HWND hwnd;
120 HIMAGELIST himl;
121 /* position of the drag image relative to the window */
122 INT x;
123 INT y;
124 /* offset of the hotspot relative to the origin of the image */
125 INT dxHotspot;
126 INT dyHotspot;
127 /* is the drag image visible */
128 BOOL bShow;
129 /* saved background */
130 HBITMAP hbmBg;
131 } INTERNALDRAG;
132
133 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
134
135 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count);
136 static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv);
137 static inline BOOL is_valid(HIMAGELIST himl);
138
139 /*
140 * An imagelist with N images is tiled like this:
141 *
142 * N/4 ->
143 *
144 * 4 048C..
145 * 159D..
146 * | 26AE.N
147 * V 37BF.
148 */
149
150 #define TILE_COUNT 4
151
152 static inline UINT imagelist_height( UINT count )
153 {
154 return ((count + TILE_COUNT - 1)/TILE_COUNT);
155 }
156
157 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
158 {
159 pt->x = (index%TILE_COUNT) * himl->cx;
160 pt->y = (index/TILE_COUNT) * himl->cy;
161 }
162
163 static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, SIZE *sz )
164 {
165 sz->cx = himl->cx * TILE_COUNT;
166 sz->cy = imagelist_height( count ) * himl->cy;
167 }
168
169 static inline int get_dib_stride( int width, int bpp )
170 {
171 return ((width * bpp + 31) >> 3) & ~3;
172 }
173
174 static inline int get_dib_image_size( const BITMAPINFO *info )
175 {
176 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
177 * abs( info->bmiHeader.biHeight );
178 }
179
180 /*
181 * imagelist_copy_images()
182 *
183 * Copies a block of count images from offset src in the list to offset dest.
184 * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
185 */
186 static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
187 UINT src, UINT count, UINT dest )
188 {
189 POINT ptSrc, ptDest;
190 SIZE sz;
191 UINT i;
192
193 for ( i=0; i<TILE_COUNT; i++ )
194 {
195 imagelist_point_from_index( himl, src+i, &ptSrc );
196 imagelist_point_from_index( himl, dest+i, &ptDest );
197 sz.cx = himl->cx;
198 sz.cy = himl->cy * imagelist_height( count - i );
199
200 BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
201 hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
202 }
203 }
204
205 static void add_dib_bits( HIMAGELIST himl, int pos, int count, int width, int height,
206 BITMAPINFO *info, BITMAPINFO *mask_info, DWORD *bits, BYTE *mask_bits )
207 {
208 int i, j, n;
209 POINT pt;
210 int stride = info->bmiHeader.biWidth;
211 int mask_stride = (info->bmiHeader.biWidth + 31) / 32 * 4;
212
213 for (n = 0; n < count; n++)
214 {
215 int has_alpha = 0;
216
217 imagelist_point_from_index( himl, pos + n, &pt );
218
219 /* check if bitmap has an alpha channel */
220 for (i = 0; i < height && !has_alpha; i++)
221 for (j = n * width; j < (n + 1) * width; j++)
222 if ((has_alpha = ((bits[i * stride + j] & 0xff000000) != 0))) break;
223
224 if (!has_alpha) /* generate alpha channel from the mask */
225 {
226 for (i = 0; i < height; i++)
227 for (j = n * width; j < (n + 1) * width; j++)
228 if (!mask_info || !((mask_bits[i * mask_stride + j / 8] << (j % 8)) & 0x80))
229 bits[i * stride + j] |= 0xff000000;
230 else
231 bits[i * stride + j] = 0;
232 }
233 else
234 {
235 himl->has_alpha[pos + n] = 1;
236
237 if (mask_info && himl->hbmMask) /* generate the mask from the alpha channel */
238 {
239 for (i = 0; i < height; i++)
240 for (j = n * width; j < (n + 1) * width; j++)
241 if ((bits[i * stride + j] >> 24) > 25) /* more than 10% alpha */
242 mask_bits[i * mask_stride + j / 8] &= ~(0x80 >> (j % 8));
243 else
244 mask_bits[i * mask_stride + j / 8] |= 0x80 >> (j % 8);
245 }
246 }
247 StretchDIBits( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
248 n * width, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
249 if (mask_info)
250 StretchDIBits( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
251 n * width, 0, width, height, mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY );
252 }
253 }
254
255 /* add images with an alpha channel when the image list is 32 bpp */
256 static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
257 int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
258 {
259 BOOL ret = FALSE;
260 BITMAP bm;
261 BITMAPINFO *info, *mask_info = NULL;
262 DWORD *bits = NULL;
263 BYTE *mask_bits = NULL;
264 DWORD mask_width;
265
266 if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
267
268 /* if either the imagelist or the source bitmap don't have an alpha channel, bail out now */
269 if (!himl->has_alpha) return FALSE;
270 if (bm.bmBitsPixel != 32) return FALSE;
271
272 SelectObject( hdc, hbmImage );
273 mask_width = (bm.bmWidth + 31) / 32 * 4;
274
275 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
276 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
277 info->bmiHeader.biWidth = bm.bmWidth;
278 info->bmiHeader.biHeight = -height;
279 info->bmiHeader.biPlanes = 1;
280 info->bmiHeader.biBitCount = 32;
281 info->bmiHeader.biCompression = BI_RGB;
282 info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
283 info->bmiHeader.biXPelsPerMeter = 0;
284 info->bmiHeader.biYPelsPerMeter = 0;
285 info->bmiHeader.biClrUsed = 0;
286 info->bmiHeader.biClrImportant = 0;
287 if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
288 if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
289
290 if (hbmMask)
291 {
292 if (!(mask_info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
293 goto done;
294 mask_info->bmiHeader = info->bmiHeader;
295 mask_info->bmiHeader.biBitCount = 1;
296 mask_info->bmiHeader.biSizeImage = mask_width * height;
297 if (!(mask_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
298 goto done;
299 if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, mask_info, DIB_RGB_COLORS )) goto done;
300 }
301
302 add_dib_bits( himl, pos, count, width, height, info, mask_info, bits, mask_bits );
303 ret = TRUE;
304
305 done:
306 HeapFree( GetProcessHeap(), 0, info );
307 HeapFree( GetProcessHeap(), 0, mask_info );
308 HeapFree( GetProcessHeap(), 0, bits );
309 HeapFree( GetProcessHeap(), 0, mask_bits );
310 return ret;
311 }
312
313 /*************************************************************************
314 * IMAGELIST_InternalExpandBitmaps [Internal]
315 *
316 * Expands the bitmaps of an image list by the given number of images.
317 *
318 * PARAMS
319 * himl [I] handle to image list
320 * nImageCount [I] number of images to add
321 *
322 * RETURNS
323 * nothing
324 *
325 * NOTES
326 * This function CANNOT be used to reduce the number of images.
327 */
328 static void
329 IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
330 {
331 HDC hdcBitmap;
332 HBITMAP hbmNewBitmap, hbmNull;
333 INT nNewCount;
334 SIZE sz;
335
336 TRACE("%p has allocated %d, max %d, grow %d images\n", himl, himl->cCurImage, himl->cMaxImage, himl->cGrow);
337
338 if (himl->cCurImage + nImageCount < himl->cMaxImage)
339 return;
340
341 nNewCount = himl->cMaxImage + max(nImageCount, himl->cGrow) + 1;
342
343 imagelist_get_bitmap_size(himl, nNewCount, &sz);
344
345 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, sz.cy, nNewCount);
346 hdcBitmap = CreateCompatibleDC (0);
347
348 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
349
350 if (hbmNewBitmap == 0)
351 ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, sz.cy);
352
353 if (himl->cCurImage)
354 {
355 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
356 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
357 himl->hdcImage, 0, 0, SRCCOPY);
358 SelectObject (hdcBitmap, hbmNull);
359 }
360 SelectObject (himl->hdcImage, hbmNewBitmap);
361 DeleteObject (himl->hbmImage);
362 himl->hbmImage = hbmNewBitmap;
363
364 if (himl->flags & ILC_MASK)
365 {
366 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
367
368 if (hbmNewBitmap == 0)
369 ERR("creating new mask bitmap!\n");
370
371 if(himl->cCurImage)
372 {
373 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
374 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
375 himl->hdcMask, 0, 0, SRCCOPY);
376 SelectObject (hdcBitmap, hbmNull);
377 }
378 SelectObject (himl->hdcMask, hbmNewBitmap);
379 DeleteObject (himl->hbmMask);
380 himl->hbmMask = hbmNewBitmap;
381 }
382
383 if (himl->has_alpha)
384 {
385 char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
386 if (new_alpha) himl->has_alpha = new_alpha;
387 else
388 {
389 HeapFree( GetProcessHeap(), 0, himl->has_alpha );
390 himl->has_alpha = NULL;
391 }
392 }
393
394 himl->cMaxImage = nNewCount;
395
396 DeleteDC (hdcBitmap);
397 }
398
399
400 /*************************************************************************
401 * ImageList_Add [COMCTL32.@]
402 *
403 * Add an image or images to an image list.
404 *
405 * PARAMS
406 * himl [I] handle to image list
407 * hbmImage [I] handle to image bitmap
408 * hbmMask [I] handle to mask bitmap
409 *
410 * RETURNS
411 * Success: Index of the first new image.
412 * Failure: -1
413 */
414
415 INT WINAPI
416 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
417 {
418 HDC hdcBitmap, hdcTemp = 0;
419 INT nFirstIndex, nImageCount, i;
420 BITMAP bmp;
421 POINT pt;
422
423 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
424 if (!is_valid(himl))
425 return -1;
426
427 if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
428 return -1;
429
430 TRACE("himl %p, cCurImage %d, cMaxImage %d, cGrow %d, cx %d, cy %d\n",
431 himl, himl->cCurImage, himl->cMaxImage, himl->cGrow, himl->cx, himl->cy);
432
433 nImageCount = bmp.bmWidth / himl->cx;
434
435 TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);
436
437 IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
438
439 hdcBitmap = CreateCompatibleDC(0);
440
441 SelectObject(hdcBitmap, hbmImage);
442
443 if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
444 himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
445 goto done;
446
447 if (himl->hbmMask)
448 {
449 hdcTemp = CreateCompatibleDC(0);
450 SelectObject(hdcTemp, hbmMask);
451 }
452
453 for (i=0; i<nImageCount; i++)
454 {
455 imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
456
457 /* Copy result to the imagelist
458 */
459 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
460 hdcBitmap, i*himl->cx, 0, SRCCOPY );
461
462 if (!himl->hbmMask)
463 continue;
464
465 BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
466 hdcTemp, i*himl->cx, 0, SRCCOPY );
467
468 /* Remove the background from the image
469 */
470 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
471 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
472 }
473 if (hdcTemp) DeleteDC(hdcTemp);
474
475 done:
476 DeleteDC(hdcBitmap);
477
478 nFirstIndex = himl->cCurImage;
479 himl->cCurImage += nImageCount;
480
481 return nFirstIndex;
482 }
483
484
485 /*************************************************************************
486 * ImageList_AddIcon [COMCTL32.@]
487 *
488 * Adds an icon to an image list.
489 *
490 * PARAMS
491 * himl [I] handle to image list
492 * hIcon [I] handle to icon
493 *
494 * RETURNS
495 * Success: index of the new image
496 * Failure: -1
497 */
498 #undef ImageList_AddIcon
499 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
500 {
501 return ImageList_ReplaceIcon (himl, -1, hIcon);
502 }
503
504
505 /*************************************************************************
506 * ImageList_AddMasked [COMCTL32.@]
507 *
508 * Adds an image or images to an image list and creates a mask from the
509 * specified bitmap using the mask color.
510 *
511 * PARAMS
512 * himl [I] handle to image list.
513 * hBitmap [I] handle to bitmap
514 * clrMask [I] mask color.
515 *
516 * RETURNS
517 * Success: Index of the first new image.
518 * Failure: -1
519 */
520
521 INT WINAPI
522 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
523 {
524 HDC hdcMask, hdcBitmap;
525 INT ret;
526 BITMAP bmp;
527 HBITMAP hMaskBitmap;
528 COLORREF bkColor;
529
530 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
531 if (!is_valid(himl))
532 return -1;
533
534 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
535 return -1;
536
537 hdcBitmap = CreateCompatibleDC(0);
538 SelectObject(hdcBitmap, hBitmap);
539
540 /* Create a temp Mask so we can remove the background of the Image */
541 hdcMask = CreateCompatibleDC(0);
542 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
543 SelectObject(hdcMask, hMaskBitmap);
544
545 /* create monochrome image to the mask bitmap */
546 bkColor = (clrMask != CLR_DEFAULT) ? clrMask : GetPixel (hdcBitmap, 0, 0);
547 SetBkColor (hdcBitmap, bkColor);
548 BitBlt (hdcMask, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
549
550 /*
551 * Remove the background from the image
552 *
553 * WINDOWS BUG ALERT!!!!!!
554 * The statement below should not be done in common practice
555 * but this is how ImageList_AddMasked works in Windows.
556 * It overwrites the original bitmap passed, this was discovered
557 * by using the same bitmap to iterate the different styles
558 * on windows where it failed (BUT ImageList_Add is OK)
559 * This is here in case some apps rely on this bug
560 *
561 * Blt mode 0x220326 is NOTSRCAND
562 */
563 if (bmp.bmBitsPixel > 8) /* NOTSRCAND can't work with palettes */
564 {
565 SetBkColor(hdcBitmap, RGB(255,255,255));
566 BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
567 }
568
569 DeleteDC(hdcBitmap);
570 DeleteDC(hdcMask);
571
572 ret = ImageList_Add( himl, hBitmap, hMaskBitmap );
573
574 DeleteObject(hMaskBitmap);
575 return ret;
576 }
577
578
579 /*************************************************************************
580 * ImageList_BeginDrag [COMCTL32.@]
581 *
582 * Creates a temporary image list that contains one image. It will be used
583 * as a drag image.
584 *
585 * PARAMS
586 * himlTrack [I] handle to the source image list
587 * iTrack [I] index of the drag image in the source image list
588 * dxHotspot [I] X position of the hot spot of the drag image
589 * dyHotspot [I] Y position of the hot spot of the drag image
590 *
591 * RETURNS
592 * Success: TRUE
593 * Failure: FALSE
594 */
595
596 BOOL WINAPI
597 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
598 INT dxHotspot, INT dyHotspot)
599 {
600 INT cx, cy;
601
602 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
603 dxHotspot, dyHotspot);
604
605 if (!is_valid(himlTrack))
606 return FALSE;
607
608 if (InternalDrag.himl)
609 ImageList_EndDrag ();
610
611 cx = himlTrack->cx;
612 cy = himlTrack->cy;
613
614 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
615 if (InternalDrag.himl == NULL) {
616 WARN("Error creating drag image list!\n");
617 return FALSE;
618 }
619
620 InternalDrag.dxHotspot = dxHotspot;
621 InternalDrag.dyHotspot = dyHotspot;
622
623 /* copy image */
624 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
625
626 /* copy mask */
627 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
628
629 InternalDrag.himl->cCurImage = 1;
630
631 return TRUE;
632 }
633
634
635 /*************************************************************************
636 * ImageList_Copy [COMCTL32.@]
637 *
638 * Copies an image of the source image list to an image of the
639 * destination image list. Images can be copied or swapped.
640 *
641 * PARAMS
642 * himlDst [I] handle to the destination image list
643 * iDst [I] destination image index.
644 * himlSrc [I] handle to the source image list
645 * iSrc [I] source image index
646 * uFlags [I] flags for the copy operation
647 *
648 * RETURNS
649 * Success: TRUE
650 * Failure: FALSE
651 *
652 * NOTES
653 * Copying from one image list to another is possible. The original
654 * implementation just copies or swaps within one image list.
655 * Could this feature become a bug??? ;-)
656 */
657
658 BOOL WINAPI
659 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
660 INT iSrc, UINT uFlags)
661 {
662 POINT ptSrc, ptDst;
663
664 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
665
666 if (!is_valid(himlSrc) || !is_valid(himlDst))
667 return FALSE;
668 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
669 return FALSE;
670 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
671 return FALSE;
672
673 imagelist_point_from_index( himlDst, iDst, &ptDst );
674 imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
675
676 if (uFlags & ILCF_SWAP) {
677 /* swap */
678 HDC hdcBmp;
679 HBITMAP hbmTempImage, hbmTempMask;
680
681 hdcBmp = CreateCompatibleDC (0);
682
683 /* create temporary bitmaps */
684 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
685 himlSrc->uBitsPixel, NULL);
686 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
687 1, NULL);
688
689 /* copy (and stretch) destination to temporary bitmaps.(save) */
690 /* image */
691 SelectObject (hdcBmp, hbmTempImage);
692 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
693 himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
694 SRCCOPY);
695 /* mask */
696 SelectObject (hdcBmp, hbmTempMask);
697 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
698 himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
699 SRCCOPY);
700
701 /* copy (and stretch) source to destination */
702 /* image */
703 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
704 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
705 SRCCOPY);
706 /* mask */
707 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
708 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
709 SRCCOPY);
710
711 /* copy (without stretching) temporary bitmaps to source (restore) */
712 /* mask */
713 BitBlt (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
714 hdcBmp, 0, 0, SRCCOPY);
715
716 /* image */
717 BitBlt (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
718 hdcBmp, 0, 0, SRCCOPY);
719 /* delete temporary bitmaps */
720 DeleteObject (hbmTempMask);
721 DeleteObject (hbmTempImage);
722 DeleteDC(hdcBmp);
723 }
724 else {
725 /* copy image */
726 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
727 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
728 SRCCOPY);
729
730 /* copy mask */
731 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
732 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
733 SRCCOPY);
734 }
735
736 return TRUE;
737 }
738
739
740 /*************************************************************************
741 * ImageList_Create [COMCTL32.@]
742 *
743 * Creates a new image list.
744 *
745 * PARAMS
746 * cx [I] image height
747 * cy [I] image width
748 * flags [I] creation flags
749 * cInitial [I] initial number of images in the image list
750 * cGrow [I] number of images by which image list grows
751 *
752 * RETURNS
753 * Success: Handle to the created image list
754 * Failure: NULL
755 */
756 HIMAGELIST WINAPI
757 ImageList_Create (INT cx, INT cy, UINT flags,
758 INT cInitial, INT cGrow)
759 {
760 HIMAGELIST himl;
761 INT nCount;
762 HBITMAP hbmTemp;
763 UINT ilc = (flags & 0xFE);
764 static const WORD aBitBlend25[] =
765 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
766
767 static const WORD aBitBlend50[] =
768 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
769
770 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
771
772 if (cx <= 0 || cy <= 0) return NULL;
773
774 /* Create the IImageList interface for the image list */
775 if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
776 return NULL;
777
778 cGrow = (WORD)((max( cGrow, 1 ) + 3) & ~3);
779
780 if (cGrow > 256)
781 {
782 /* Windows doesn't limit the size here, but X11 doesn't let us allocate such huge bitmaps */
783 WARN( "grow %d too large, limiting to 256\n", cGrow );
784 cGrow = 256;
785 }
786
787 himl->cx = cx;
788 himl->cy = cy;
789 himl->flags = flags;
790 himl->cMaxImage = cInitial + 1;
791 himl->cInitial = cInitial;
792 himl->cGrow = cGrow;
793 himl->clrFg = CLR_DEFAULT;
794 himl->clrBk = CLR_NONE;
795
796 /* initialize overlay mask indices */
797 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
798 himl->nOvlIdx[nCount] = -1;
799
800 /* Create Image & Mask DCs */
801 himl->hdcImage = CreateCompatibleDC (0);
802 if (!himl->hdcImage)
803 goto cleanup;
804 if (himl->flags & ILC_MASK){
805 himl->hdcMask = CreateCompatibleDC(0);
806 if (!himl->hdcMask)
807 goto cleanup;
808 }
809
810 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
811 if (ilc == ILC_COLOR)
812 {
813 ilc = ILC_COLOR4;
814 himl->flags |= ILC_COLOR4;
815 }
816
817 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
818 himl->uBitsPixel = ilc;
819 else
820 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
821
822 if (himl->cMaxImage > 0) {
823 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
824 SelectObject(himl->hdcImage, himl->hbmImage);
825 } else
826 himl->hbmImage = 0;
827
828 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
829 SIZE sz;
830
831 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
832 himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
833 if (himl->hbmMask == 0) {
834 ERR("Error creating mask bitmap!\n");
835 goto cleanup;
836 }
837 SelectObject(himl->hdcMask, himl->hbmMask);
838 }
839 else
840 himl->hbmMask = 0;
841
842 if (ilc == ILC_COLOR32)
843 himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
844 else
845 himl->has_alpha = NULL;
846
847 /* create blending brushes */
848 hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
849 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
850 DeleteObject (hbmTemp);
851
852 hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend50);
853 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
854 DeleteObject (hbmTemp);
855
856 TRACE("created imagelist %p\n", himl);
857 return himl;
858
859 cleanup:
860 ImageList_Destroy(himl);
861 return NULL;
862 }
863
864
865 /*************************************************************************
866 * ImageList_Destroy [COMCTL32.@]
867 *
868 * Destroys an image list.
869 *
870 * PARAMS
871 * himl [I] handle to image list
872 *
873 * RETURNS
874 * Success: TRUE
875 * Failure: FALSE
876 */
877
878 BOOL WINAPI
879 ImageList_Destroy (HIMAGELIST himl)
880 {
881 if (!is_valid(himl))
882 return FALSE;
883
884 IImageList_Release((IImageList *) himl);
885 return TRUE;
886 }
887
888
889 /*************************************************************************
890 * ImageList_DragEnter [COMCTL32.@]
891 *
892 * Locks window update and displays the drag image at the given position.
893 *
894 * PARAMS
895 * hwndLock [I] handle of the window that owns the drag image.
896 * x [I] X position of the drag image.
897 * y [I] Y position of the drag image.
898 *
899 * RETURNS
900 * Success: TRUE
901 * Failure: FALSE
902 *
903 * NOTES
904 * The position of the drag image is relative to the window, not
905 * the client area.
906 */
907
908 BOOL WINAPI
909 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
910 {
911 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
912
913 if (!is_valid(InternalDrag.himl))
914 return FALSE;
915
916 if (hwndLock)
917 InternalDrag.hwnd = hwndLock;
918 else
919 InternalDrag.hwnd = GetDesktopWindow ();
920
921 InternalDrag.x = x;
922 InternalDrag.y = y;
923
924 /* draw the drag image and save the background */
925 if (!ImageList_DragShowNolock(TRUE)) {
926 return FALSE;
927 }
928
929 return TRUE;
930 }
931
932
933 /*************************************************************************
934 * ImageList_DragLeave [COMCTL32.@]
935 *
936 * Unlocks window update and hides the drag image.
937 *
938 * PARAMS
939 * hwndLock [I] handle of the window that owns the drag image.
940 *
941 * RETURNS
942 * Success: TRUE
943 * Failure: FALSE
944 */
945
946 BOOL WINAPI
947 ImageList_DragLeave (HWND hwndLock)
948 {
949 /* As we don't save drag info in the window this can lead to problems if
950 an app does not supply the same window as DragEnter */
951 /* if (hwndLock)
952 InternalDrag.hwnd = hwndLock;
953 else
954 InternalDrag.hwnd = GetDesktopWindow (); */
955 if(!hwndLock)
956 hwndLock = GetDesktopWindow();
957 if(InternalDrag.hwnd != hwndLock)
958 FIXME("DragLeave hWnd != DragEnter hWnd\n");
959
960 ImageList_DragShowNolock (FALSE);
961
962 return TRUE;
963 }
964
965
966 /*************************************************************************
967 * ImageList_InternalDragDraw [Internal]
968 *
969 * Draws the drag image.
970 *
971 * PARAMS
972 * hdc [I] device context to draw into.
973 * x [I] X position of the drag image.
974 * y [I] Y position of the drag image.
975 *
976 * RETURNS
977 * Success: TRUE
978 * Failure: FALSE
979 *
980 * NOTES
981 * The position of the drag image is relative to the window, not
982 * the client area.
983 *
984 */
985
986 static inline void
987 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
988 {
989 IMAGELISTDRAWPARAMS imldp;
990
991 ZeroMemory (&imldp, sizeof(imldp));
992 imldp.cbSize = sizeof(imldp);
993 imldp.himl = InternalDrag.himl;
994 imldp.i = 0;
995 imldp.hdcDst = hdc,
996 imldp.x = x;
997 imldp.y = y;
998 imldp.rgbBk = CLR_DEFAULT;
999 imldp.rgbFg = CLR_DEFAULT;
1000 imldp.fStyle = ILD_NORMAL;
1001 imldp.fState = ILS_ALPHA;
1002 imldp.Frame = 192;
1003 ImageList_DrawIndirect (&imldp);
1004 }
1005
1006 /*************************************************************************
1007 * ImageList_DragMove [COMCTL32.@]
1008 *
1009 * Moves the drag image.
1010 *
1011 * PARAMS
1012 * x [I] X position of the drag image.
1013 * y [I] Y position of the drag image.
1014 *
1015 * RETURNS
1016 * Success: TRUE
1017 * Failure: FALSE
1018 *
1019 * NOTES
1020 * The position of the drag image is relative to the window, not
1021 * the client area.
1022 */
1023
1024 BOOL WINAPI
1025 ImageList_DragMove (INT x, INT y)
1026 {
1027 TRACE("(x=%d y=%d)\n", x, y);
1028
1029 if (!is_valid(InternalDrag.himl))
1030 return FALSE;
1031
1032 /* draw/update the drag image */
1033 if (InternalDrag.bShow) {
1034 HDC hdcDrag;
1035 HDC hdcOffScreen;
1036 HDC hdcBg;
1037 HBITMAP hbmOffScreen;
1038 INT origNewX, origNewY;
1039 INT origOldX, origOldY;
1040 INT origRegX, origRegY;
1041 INT sizeRegX, sizeRegY;
1042
1043
1044 /* calculate the update region */
1045 origNewX = x - InternalDrag.dxHotspot;
1046 origNewY = y - InternalDrag.dyHotspot;
1047 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1048 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1049 origRegX = min(origNewX, origOldX);
1050 origRegY = min(origNewY, origOldY);
1051 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1052 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1053
1054 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1055 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1056 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1057 hdcBg = CreateCompatibleDC(hdcDrag);
1058
1059 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1060 SelectObject(hdcOffScreen, hbmOffScreen);
1061 SelectObject(hdcBg, InternalDrag.hbmBg);
1062
1063 /* get the actual background of the update region */
1064 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1065 origRegX, origRegY, SRCCOPY);
1066 /* erase the old image */
1067 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1068 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1069 SRCCOPY);
1070 /* save the background */
1071 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1072 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1073 /* draw the image */
1074 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
1075 origNewY - origRegY);
1076 /* draw the update region to the screen */
1077 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1078 hdcOffScreen, 0, 0, SRCCOPY);
1079
1080 DeleteDC(hdcBg);
1081 DeleteDC(hdcOffScreen);
1082 DeleteObject(hbmOffScreen);
1083 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1084 }
1085
1086 /* update the image position */
1087 InternalDrag.x = x;
1088 InternalDrag.y = y;
1089
1090 return TRUE;
1091 }
1092
1093
1094 /*************************************************************************
1095 * ImageList_DragShowNolock [COMCTL32.@]
1096 *
1097 * Shows or hides the drag image.
1098 *
1099 * PARAMS
1100 * bShow [I] TRUE shows the drag image, FALSE hides it.
1101 *
1102 * RETURNS
1103 * Success: TRUE
1104 * Failure: FALSE
1105 */
1106
1107 BOOL WINAPI
1108 ImageList_DragShowNolock (BOOL bShow)
1109 {
1110 HDC hdcDrag;
1111 HDC hdcBg;
1112 INT x, y;
1113
1114 if (!is_valid(InternalDrag.himl))
1115 return FALSE;
1116
1117 TRACE("bShow=0x%X!\n", bShow);
1118
1119 /* DragImage is already visible/hidden */
1120 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1121 return FALSE;
1122 }
1123
1124 /* position of the origin of the DragImage */
1125 x = InternalDrag.x - InternalDrag.dxHotspot;
1126 y = InternalDrag.y - InternalDrag.dyHotspot;
1127
1128 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1129 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1130 if (!hdcDrag) {
1131 return FALSE;
1132 }
1133
1134 hdcBg = CreateCompatibleDC(hdcDrag);
1135 if (!InternalDrag.hbmBg) {
1136 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1137 InternalDrag.himl->cx, InternalDrag.himl->cy);
1138 }
1139 SelectObject(hdcBg, InternalDrag.hbmBg);
1140
1141 if (bShow) {
1142 /* save the background */
1143 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1144 hdcDrag, x, y, SRCCOPY);
1145 /* show the image */
1146 ImageList_InternalDragDraw(hdcDrag, x, y);
1147 } else {
1148 /* hide the image */
1149 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1150 hdcBg, 0, 0, SRCCOPY);
1151 }
1152
1153 InternalDrag.bShow = !InternalDrag.bShow;
1154
1155 DeleteDC(hdcBg);
1156 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1157 return TRUE;
1158 }
1159
1160
1161 /*************************************************************************
1162 * ImageList_Draw [COMCTL32.@]
1163 *
1164 * Draws an image.
1165 *
1166 * PARAMS
1167 * himl [I] handle to image list
1168 * i [I] image index
1169 * hdc [I] handle to device context
1170 * x [I] x position
1171 * y [I] y position
1172 * fStyle [I] drawing flags
1173 *
1174 * RETURNS
1175 * Success: TRUE
1176 * Failure: FALSE
1177 *
1178 * SEE
1179 * ImageList_DrawEx.
1180 */
1181
1182 BOOL WINAPI
1183 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1184 {
1185 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1186 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1187 }
1188
1189
1190 /*************************************************************************
1191 * ImageList_DrawEx [COMCTL32.@]
1192 *
1193 * Draws an image and allows using extended drawing features.
1194 *
1195 * PARAMS
1196 * himl [I] handle to image list
1197 * i [I] image index
1198 * hdc [I] handle to device context
1199 * x [I] X position
1200 * y [I] Y position
1201 * dx [I] X offset
1202 * dy [I] Y offset
1203 * rgbBk [I] background color
1204 * rgbFg [I] foreground color
1205 * fStyle [I] drawing flags
1206 *
1207 * RETURNS
1208 * Success: TRUE
1209 * Failure: FALSE
1210 *
1211 * NOTES
1212 * Calls ImageList_DrawIndirect.
1213 *
1214 * SEE
1215 * ImageList_DrawIndirect.
1216 */
1217
1218 BOOL WINAPI
1219 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1220 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1221 UINT fStyle)
1222 {
1223 IMAGELISTDRAWPARAMS imldp;
1224
1225 ZeroMemory (&imldp, sizeof(imldp));
1226 imldp.cbSize = sizeof(imldp);
1227 imldp.himl = himl;
1228 imldp.i = i;
1229 imldp.hdcDst = hdc,
1230 imldp.x = x;
1231 imldp.y = y;
1232 imldp.cx = dx;
1233 imldp.cy = dy;
1234 imldp.rgbBk = rgbBk;
1235 imldp.rgbFg = rgbFg;
1236 imldp.fStyle = fStyle;
1237
1238 return ImageList_DrawIndirect (&imldp);
1239 }
1240
1241
1242 static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1243 int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
1244 UINT style, COLORREF blend_col )
1245 {
1246 BOOL ret = FALSE;
1247 HDC hdc;
1248 HBITMAP bmp = 0, mask = 0;
1249 BITMAPINFO *info;
1250 void *bits, *mask_bits;
1251 unsigned int *ptr;
1252 int i, j;
1253
1254 if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1255 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1256 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1257 info->bmiHeader.biWidth = cx;
1258 info->bmiHeader.biHeight = cy;
1259 info->bmiHeader.biPlanes = 1;
1260 info->bmiHeader.biBitCount = 32;
1261 info->bmiHeader.biCompression = BI_RGB;
1262 info->bmiHeader.biSizeImage = cx * cy * 4;
1263 info->bmiHeader.biXPelsPerMeter = 0;
1264 info->bmiHeader.biYPelsPerMeter = 0;
1265 info->bmiHeader.biClrUsed = 0;
1266 info->bmiHeader.biClrImportant = 0;
1267 if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1268 SelectObject( hdc, bmp );
1269 BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
1270
1271 if (blend_col != CLR_NONE)
1272 {
1273 BYTE r = GetRValue( blend_col );
1274 BYTE g = GetGValue( blend_col );
1275 BYTE b = GetBValue( blend_col );
1276
1277 if (style & ILD_BLEND25)
1278 {
1279 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1280 *ptr = ((*ptr & 0xff000000) |
1281 ((((*ptr & 0x00ff0000) * 3 + (r << 16)) / 4) & 0x00ff0000) |
1282 ((((*ptr & 0x0000ff00) * 3 + (g << 8)) / 4) & 0x0000ff00) |
1283 ((((*ptr & 0x000000ff) * 3 + (b << 0)) / 4) & 0x000000ff));
1284 }
1285 else if (style & ILD_BLEND50)
1286 {
1287 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1288 *ptr = ((*ptr & 0xff000000) |
1289 ((((*ptr & 0x00ff0000) + (r << 16)) / 2) & 0x00ff0000) |
1290 ((((*ptr & 0x0000ff00) + (g << 8)) / 2) & 0x0000ff00) |
1291 ((((*ptr & 0x000000ff) + (b << 0)) / 2) & 0x000000ff));
1292 }
1293 }
1294
1295 if (himl->has_alpha) /* we already have an alpha channel in this case */
1296 {
1297 /* pre-multiply by the alpha channel */
1298 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1299 {
1300 DWORD alpha = *ptr >> 24;
1301 *ptr = ((*ptr & 0xff000000) |
1302 (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
1303 (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
1304 (((*ptr & 0x000000ff) * alpha / 255)));
1305 }
1306 }
1307 else if (himl->hbmMask)
1308 {
1309 unsigned int width_bytes = (cx + 31) / 32 * 4;
1310 /* generate alpha channel from the mask */
1311 info->bmiHeader.biBitCount = 1;
1312 info->bmiHeader.biSizeImage = width_bytes * cy;
1313 info->bmiColors[0].rgbRed = 0;
1314 info->bmiColors[0].rgbGreen = 0;
1315 info->bmiColors[0].rgbBlue = 0;
1316 info->bmiColors[0].rgbReserved = 0;
1317 info->bmiColors[1].rgbRed = 0xff;
1318 info->bmiColors[1].rgbGreen = 0xff;
1319 info->bmiColors[1].rgbBlue = 0xff;
1320 info->bmiColors[1].rgbReserved = 0;
1321 if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
1322 goto done;
1323 SelectObject( hdc, mask );
1324 BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
1325 SelectObject( hdc, bmp );
1326 for (i = 0, ptr = bits; i < cy; i++)
1327 for (j = 0; j < cx; j++, ptr++)
1328 if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
1329 else *ptr |= 0xff000000;
1330 }
1331
1332 ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
1333
1334 done:
1335 DeleteDC( hdc );
1336 if (bmp) DeleteObject( bmp );
1337 if (mask) DeleteObject( mask );
1338 HeapFree( GetProcessHeap(), 0, info );
1339 return ret;
1340 }
1341
1342 /*************************************************************************
1343 * ImageList_DrawIndirect [COMCTL32.@]
1344 *
1345 * Draws an image using various parameters specified in pimldp.
1346 *
1347 * PARAMS
1348 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1349 *
1350 * RETURNS
1351 * Success: TRUE
1352 * Failure: FALSE
1353 */
1354
1355 BOOL WINAPI
1356 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1357 {
1358 INT cx, cy, nOvlIdx;
1359 DWORD fState, dwRop;
1360 UINT fStyle;
1361 COLORREF oldImageBk, oldImageFg;
1362 HDC hImageDC, hImageListDC, hMaskListDC;
1363 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1364 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1365 HIMAGELIST himl;
1366 HBRUSH hOldBrush;
1367 POINT pt;
1368 BOOL has_alpha;
1369
1370 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1371 if (!is_valid(himl)) return FALSE;
1372 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1373
1374 imagelist_point_from_index( himl, pimldp->i, &pt );
1375 pt.x += pimldp->xBitmap;
1376 pt.y += pimldp->yBitmap;
1377
1378 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1379 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1380 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1381 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1382
1383 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1384 if( pimldp->rgbBk == CLR_NONE )
1385 bIsTransparent = TRUE;
1386 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1387 bIsTransparent = TRUE;
1388 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1389 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1390
1391 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1392 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1393
1394 /* we will use these DCs to access the images and masks in the ImageList */
1395 hImageListDC = himl->hdcImage;
1396 hMaskListDC = himl->hdcMask;
1397
1398 /* these will accumulate the image and mask for the image we're drawing */
1399 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1400 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1401 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1402
1403 /* Create a compatible DC. */
1404 if (!hImageListDC || !hImageDC || !hImageBmp ||
1405 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1406 goto cleanup;
1407
1408 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1409
1410 /*
1411 * To obtain a transparent look, background color should be set
1412 * to white and foreground color to black when blitting the
1413 * monochrome mask.
1414 */
1415 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1416 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1417
1418 has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
1419 if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
1420 {
1421 COLORREF colour, blend_col = CLR_NONE;
1422 BLENDFUNCTION func;
1423
1424 if (bBlend)
1425 {
1426 blend_col = pimldp->rgbFg;
1427 if (blend_col == CLR_DEFAULT) blend_col = GetSysColor( COLOR_HIGHLIGHT );
1428 else if (blend_col == CLR_NONE) blend_col = GetTextColor( pimldp->hdcDst );
1429 }
1430
1431 func.BlendOp = AC_SRC_OVER;
1432 func.BlendFlags = 0;
1433 func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
1434 func.AlphaFormat = AC_SRC_ALPHA;
1435
1436 if (bIsTransparent)
1437 {
1438 bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1439 pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1440 goto end;
1441 }
1442 colour = pimldp->rgbBk;
1443 if (colour == CLR_DEFAULT) colour = himl->clrBk;
1444 if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
1445
1446 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1447 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1448 alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1449 DeleteObject (SelectObject (hImageDC, hOldBrush));
1450 bResult = BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
1451 goto end;
1452 }
1453
1454 /*
1455 * Draw the initial image
1456 */
1457 if( bMask ) {
1458 if (himl->hbmMask) {
1459 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1460 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1461 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1462 DeleteObject (SelectObject (hImageDC, hOldBrush));
1463 if( bIsTransparent )
1464 {
1465 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1466 bResult = TRUE;
1467 goto end;
1468 }
1469 } else {
1470 hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1471 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1472 SelectObject(hImageDC, hOldBrush);
1473 }
1474 } else {
1475 /* blend the image with the needed solid background */
1476 COLORREF colour = RGB(0,0,0);
1477
1478 if( !bIsTransparent )
1479 {
1480 colour = pimldp->rgbBk;
1481 if( colour == CLR_DEFAULT )
1482 colour = himl->clrBk;
1483 if( colour == CLR_NONE )
1484 colour = GetBkColor(pimldp->hdcDst);
1485 }
1486
1487 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1488 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1489 if (himl->hbmMask)
1490 {
1491 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1492 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1493 }
1494 else
1495 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1496 DeleteObject (SelectObject (hImageDC, hOldBrush));
1497 }
1498
1499 /* Time for blending, if required */
1500 if (bBlend) {
1501 HBRUSH hBlendBrush;
1502 COLORREF clrBlend = pimldp->rgbFg;
1503 HDC hBlendMaskDC = hImageListDC;
1504 HBITMAP hOldBitmap;
1505
1506 /* Create the blend Mask */
1507 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1508 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1509 hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1510 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1511 SelectObject(hBlendMaskDC, hOldBrush);
1512
1513 /* Modify the blend mask if an Image Mask exist */
1514 if(himl->hbmMask) {
1515 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1516 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1517 }
1518
1519 /* now apply blend to the current image given the BlendMask */
1520 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1521 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1522 hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1523 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1524 DeleteObject(SelectObject(hImageDC, hOldBrush));
1525 SelectObject(hBlendMaskDC, hOldBitmap);
1526 }
1527
1528 /* Now do the overlay image, if any */
1529 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1530 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1531 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1532 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1533 POINT ptOvl;
1534 imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1535 ptOvl.x += pimldp->xBitmap;
1536 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1537 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1538 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1539 }
1540 }
1541
1542 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1543 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1544 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1545
1546 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1547 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1548 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1549
1550 /* now copy the image to the screen */
1551 dwRop = SRCCOPY;
1552 if (himl->hbmMask && bIsTransparent ) {
1553 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1554 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1555 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1556 SetBkColor(pimldp->hdcDst, oldDstBk);
1557 SetTextColor(pimldp->hdcDst, oldDstFg);
1558 dwRop = SRCPAINT;
1559 }
1560 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1561 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1562
1563 bResult = TRUE;
1564 end:
1565 /* cleanup the mess */
1566 SetBkColor(hImageDC, oldImageBk);
1567 SetTextColor(hImageDC, oldImageFg);
1568 SelectObject(hImageDC, hOldImageBmp);
1569 cleanup:
1570 DeleteObject(hBlendMaskBmp);
1571 DeleteObject(hImageBmp);
1572 DeleteDC(hImageDC);
1573
1574 return bResult;
1575 }
1576
1577
1578 /*************************************************************************
1579 * ImageList_Duplicate [COMCTL32.@]
1580 *
1581 * Duplicates an image list.
1582 *
1583 * PARAMS
1584 * himlSrc [I] source image list handle
1585 *
1586 * RETURNS
1587 * Success: Handle of duplicated image list.
1588 * Failure: NULL
1589 */
1590
1591 HIMAGELIST WINAPI
1592 ImageList_Duplicate (HIMAGELIST himlSrc)
1593 {
1594 HIMAGELIST himlDst;
1595
1596 if (!is_valid(himlSrc)) {
1597 ERR("Invalid image list handle!\n");
1598 return NULL;
1599 }
1600
1601 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1602 himlSrc->cCurImage, himlSrc->cGrow);
1603
1604 if (himlDst)
1605 {
1606 SIZE sz;
1607
1608 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
1609 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1610 himlSrc->hdcImage, 0, 0, SRCCOPY);
1611
1612 if (himlDst->hbmMask)
1613 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1614 himlSrc->hdcMask, 0, 0, SRCCOPY);
1615
1616 himlDst->cCurImage = himlSrc->cCurImage;
1617 if (himlSrc->has_alpha && himlDst->has_alpha)
1618 memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
1619 }
1620 return himlDst;
1621 }
1622
1623
1624 /*************************************************************************
1625 * ImageList_EndDrag [COMCTL32.@]
1626 *
1627 * Finishes a drag operation.
1628 *
1629 * PARAMS
1630 * no Parameters
1631 *
1632 * RETURNS
1633 * Success: TRUE
1634 * Failure: FALSE
1635 */
1636
1637 VOID WINAPI
1638 ImageList_EndDrag (void)
1639 {
1640 /* cleanup the InternalDrag struct */
1641 InternalDrag.hwnd = 0;
1642 ImageList_Destroy (InternalDrag.himl);
1643 InternalDrag.himl = 0;
1644 InternalDrag.x= 0;
1645 InternalDrag.y= 0;
1646 InternalDrag.dxHotspot = 0;
1647 InternalDrag.dyHotspot = 0;
1648 InternalDrag.bShow = FALSE;
1649 DeleteObject(InternalDrag.hbmBg);
1650 InternalDrag.hbmBg = 0;
1651 }
1652
1653
1654 /*************************************************************************
1655 * ImageList_GetBkColor [COMCTL32.@]
1656 *
1657 * Returns the background color of an image list.
1658 *
1659 * PARAMS
1660 * himl [I] Image list handle.
1661 *
1662 * RETURNS
1663 * Success: background color
1664 * Failure: CLR_NONE
1665 */
1666
1667 COLORREF WINAPI
1668 ImageList_GetBkColor (HIMAGELIST himl)
1669 {
1670 return himl ? himl->clrBk : CLR_NONE;
1671 }
1672
1673
1674 /*************************************************************************
1675 * ImageList_GetDragImage [COMCTL32.@]
1676 *
1677 * Returns the handle to the internal drag image list.
1678 *
1679 * PARAMS
1680 * ppt [O] Pointer to the drag position. Can be NULL.
1681 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1682 *
1683 * RETURNS
1684 * Success: Handle of the drag image list.
1685 * Failure: NULL.
1686 */
1687
1688 HIMAGELIST WINAPI
1689 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1690 {
1691 if (is_valid(InternalDrag.himl)) {
1692 if (ppt) {
1693 ppt->x = InternalDrag.x;
1694 ppt->y = InternalDrag.y;
1695 }
1696 if (pptHotspot) {
1697 pptHotspot->x = InternalDrag.dxHotspot;
1698 pptHotspot->y = InternalDrag.dyHotspot;
1699 }
1700 return (InternalDrag.himl);
1701 }
1702
1703 return NULL;
1704 }
1705
1706
1707 /*************************************************************************
1708 * ImageList_GetFlags [COMCTL32.@]
1709 *
1710 * Gets the flags of the specified image list.
1711 *
1712 * PARAMS
1713 * himl [I] Handle to image list
1714 *
1715 * RETURNS
1716 * Image list flags.
1717 *
1718 * BUGS
1719 * Stub.
1720 */
1721
1722 DWORD WINAPI
1723 ImageList_GetFlags(HIMAGELIST himl)
1724 {
1725 TRACE("%p\n", himl);
1726
1727 return is_valid(himl) ? himl->flags : 0;
1728 }
1729
1730
1731 /*************************************************************************
1732 * ImageList_GetIcon [COMCTL32.@]
1733 *
1734 * Creates an icon from a masked image of an image list.
1735 *
1736 * PARAMS
1737 * himl [I] handle to image list
1738 * i [I] image index
1739 * flags [I] drawing style flags
1740 *
1741 * RETURNS
1742 * Success: icon handle
1743 * Failure: NULL
1744 */
1745
1746 HICON WINAPI
1747 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1748 {
1749 ICONINFO ii;
1750 HICON hIcon;
1751 HBITMAP hOldDstBitmap;
1752 HDC hdcDst;
1753 POINT pt;
1754
1755 TRACE("%p %d %d\n", himl, i, fStyle);
1756 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1757
1758 ii.fIcon = TRUE;
1759 ii.xHotspot = 0;
1760 ii.yHotspot = 0;
1761
1762 /* create colour bitmap */
1763 hdcDst = GetDC(0);
1764 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1765 ReleaseDC(0, hdcDst);
1766
1767 hdcDst = CreateCompatibleDC(0);
1768
1769 imagelist_point_from_index( himl, i, &pt );
1770
1771 /* draw mask*/
1772 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1773 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1774 if (himl->hbmMask) {
1775 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1776 himl->hdcMask, pt.x, pt.y, SRCCOPY);
1777 }
1778 else
1779 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1780
1781 /* draw image*/
1782 SelectObject (hdcDst, ii.hbmColor);
1783 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1784 himl->hdcImage, pt.x, pt.y, SRCCOPY);
1785
1786 /*
1787 * CreateIconIndirect requires us to deselect the bitmaps from
1788 * the DCs before calling
1789 */
1790 SelectObject(hdcDst, hOldDstBitmap);
1791
1792 hIcon = CreateIconIndirect (&ii);
1793
1794 DeleteObject (ii.hbmMask);
1795 DeleteObject (ii.hbmColor);
1796 DeleteDC (hdcDst);
1797
1798 return hIcon;
1799 }
1800
1801
1802 /*************************************************************************
1803 * ImageList_GetIconSize [COMCTL32.@]
1804 *
1805 * Retrieves the size of an image in an image list.
1806 *
1807 * PARAMS
1808 * himl [I] handle to image list
1809 * cx [O] pointer to the image width.
1810 * cy [O] pointer to the image height.
1811 *
1812 * RETURNS
1813 * Success: TRUE
1814 * Failure: FALSE
1815 *
1816 * NOTES
1817 * All images in an image list have the same size.
1818 */
1819
1820 BOOL WINAPI
1821 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1822 {
1823 if (!is_valid(himl) || !cx || !cy)
1824 return FALSE;
1825 if ((himl->cx <= 0) || (himl->cy <= 0))
1826 return FALSE;
1827
1828 *cx = himl->cx;
1829 *cy = himl->cy;
1830
1831 return TRUE;
1832 }
1833
1834
1835 /*************************************************************************
1836 * ImageList_GetImageCount [COMCTL32.@]
1837 *
1838 * Returns the number of images in an image list.
1839 *
1840 * PARAMS
1841 * himl [I] handle to image list
1842 *
1843 * RETURNS
1844 * Success: Number of images.
1845 * Failure: 0
1846 */
1847
1848 INT WINAPI
1849 ImageList_GetImageCount (HIMAGELIST himl)
1850 {
1851 if (!is_valid(himl))
1852 return 0;
1853
1854 return himl->cCurImage;
1855 }
1856
1857
1858 /*************************************************************************
1859 * ImageList_GetImageInfo [COMCTL32.@]
1860 *
1861 * Returns information about an image in an image list.
1862 *
1863 * PARAMS
1864 * himl [I] handle to image list
1865 * i [I] image index
1866 * pImageInfo [O] pointer to the image information
1867 *
1868 * RETURNS
1869 * Success: TRUE
1870 * Failure: FALSE
1871 */
1872
1873 BOOL WINAPI
1874 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1875 {
1876 POINT pt;
1877
1878 if (!is_valid(himl) || (pImageInfo == NULL))
1879 return FALSE;
1880 if ((i < 0) || (i >= himl->cCurImage))
1881 return FALSE;
1882
1883 pImageInfo->hbmImage = himl->hbmImage;
1884 pImageInfo->hbmMask = himl->hbmMask;
1885
1886 imagelist_point_from_index( himl, i, &pt );
1887 pImageInfo->rcImage.top = pt.y;
1888 pImageInfo->rcImage.bottom = pt.y + himl->cy;
1889 pImageInfo->rcImage.left = pt.x;
1890 pImageInfo->rcImage.right = pt.x + himl->cx;
1891
1892 return TRUE;
1893 }
1894
1895
1896 /*************************************************************************
1897 * ImageList_GetImageRect [COMCTL32.@]
1898 *
1899 * Retrieves the rectangle of the specified image in an image list.
1900 *
1901 * PARAMS
1902 * himl [I] handle to image list
1903 * i [I] image index
1904 * lpRect [O] pointer to the image rectangle
1905 *
1906 * RETURNS
1907 * Success: TRUE
1908 * Failure: FALSE
1909 *
1910 * NOTES
1911 * This is an UNDOCUMENTED function!!!
1912 */
1913
1914 BOOL WINAPI
1915 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1916 {
1917 POINT pt;
1918
1919 if (!is_valid(himl) || (lpRect == NULL))
1920 return FALSE;
1921 if ((i < 0) || (i >= himl->cCurImage))
1922 return FALSE;
1923
1924 imagelist_point_from_index( himl, i, &pt );
1925 lpRect->left = pt.x;
1926 lpRect->top = pt.y;
1927 lpRect->right = pt.x + himl->cx;
1928 lpRect->bottom = pt.y + himl->cy;
1929
1930 return TRUE;
1931 }
1932
1933
1934 /*************************************************************************
1935 * ImageList_LoadImage [COMCTL32.@]
1936 * ImageList_LoadImageA [COMCTL32.@]
1937 *
1938 * Creates an image list from a bitmap, icon or cursor.
1939 *
1940 * See ImageList_LoadImageW.
1941 */
1942
1943 HIMAGELIST WINAPI
1944 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1945 COLORREF clrMask, UINT uType, UINT uFlags)
1946 {
1947 HIMAGELIST himl;
1948 LPWSTR lpbmpW;
1949 DWORD len;
1950
1951 if (IS_INTRESOURCE(lpbmp))
1952 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1953 uType, uFlags);
1954
1955 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1956 lpbmpW = Alloc(len * sizeof(WCHAR));
1957 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1958
1959 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1960 Free (lpbmpW);
1961 return himl;
1962 }
1963
1964
1965 /*************************************************************************
1966 * ImageList_LoadImageW [COMCTL32.@]
1967 *
1968 * Creates an image list from a bitmap, icon or cursor.
1969 *
1970 * PARAMS
1971 * hi [I] instance handle
1972 * lpbmp [I] name or id of the image
1973 * cx [I] width of each image
1974 * cGrow [I] number of images to expand
1975 * clrMask [I] mask color
1976 * uType [I] type of image to load
1977 * uFlags [I] loading flags
1978 *
1979 * RETURNS
1980 * Success: handle to the loaded image list
1981 * Failure: NULL
1982 *
1983 * SEE
1984 * LoadImage ()
1985 */
1986
1987 HIMAGELIST WINAPI
1988 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1989 COLORREF clrMask, UINT uType, UINT uFlags)
1990 {
1991 HIMAGELIST himl = NULL;
1992 HANDLE handle;
1993 INT nImageCount;
1994
1995 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1996 if (!handle) {
1997 WARN("Couldn't load image\n");
1998 return NULL;
1999 }
2000
2001 if (uType == IMAGE_BITMAP) {
2002 DIBSECTION dib;
2003 UINT color;
2004
2005 if (GetObjectW (handle, sizeof(dib), &dib) == sizeof(BITMAP)) color = ILC_COLOR;
2006 else color = dib.dsBm.bmBitsPixel;
2007
2008 /* To match windows behavior, if cx is set to zero and
2009 the flag DI_DEFAULTSIZE is specified, cx becomes the
2010 system metric value for icons. If the flag is not specified
2011 the function sets the size to the height of the bitmap */
2012 if (cx == 0)
2013 {
2014 if (uFlags & DI_DEFAULTSIZE)
2015 cx = GetSystemMetrics (SM_CXICON);
2016 else
2017 cx = dib.dsBm.bmHeight;
2018 }
2019
2020 nImageCount = dib.dsBm.bmWidth / cx;
2021
2022 himl = ImageList_Create (cx, dib.dsBm.bmHeight, ILC_MASK | color, nImageCount, cGrow);
2023 if (!himl) {
2024 DeleteObject (handle);
2025 return NULL;
2026 }
2027 ImageList_AddMasked (himl, handle, clrMask);
2028 }
2029 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
2030 ICONINFO ii;
2031 BITMAP bmp;
2032
2033 GetIconInfo (handle, &ii);
2034 GetObjectW (ii.hbmColor, sizeof(BITMAP), &bmp);
2035 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
2036 ILC_MASK | ILC_COLOR, 1, cGrow);
2037 if (!himl) {
2038 DeleteObject (ii.hbmColor);
2039 DeleteObject (ii.hbmMask);
2040 DeleteObject (handle);
2041 return NULL;
2042 }
2043 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
2044 DeleteObject (ii.hbmColor);
2045 DeleteObject (ii.hbmMask);
2046 }
2047
2048 DeleteObject (handle);
2049
2050 return himl;
2051 }
2052
2053
2054 /*************************************************************************
2055 * ImageList_Merge [COMCTL32.@]
2056 *
2057 * Create an image list containing a merged image from two image lists.
2058 *
2059 * PARAMS
2060 * himl1 [I] handle to first image list
2061 * i1 [I] first image index
2062 * himl2 [I] handle to second image list
2063 * i2 [I] second image index
2064 * dx [I] X offset of the second image relative to the first.
2065 * dy [I] Y offset of the second image relative to the first.
2066 *
2067 * RETURNS
2068 * Success: The newly created image list. It contains a single image
2069 * consisting of the second image merged with the first.
2070 * Failure: NULL, if either himl1 or himl2 are invalid.
2071 *
2072 * NOTES
2073 * - The returned image list should be deleted by the caller using
2074 * ImageList_Destroy() when it is no longer required.
2075 * - If either i1 or i2 are not valid image indices they will be treated
2076 * as a blank image.
2077 */
2078 HIMAGELIST WINAPI
2079 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
2080 INT dx, INT dy)
2081 {
2082 HIMAGELIST himlDst = NULL;
2083 INT cxDst, cyDst;
2084 INT xOff1, yOff1, xOff2, yOff2;
2085 POINT pt1, pt2;
2086
2087 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
2088 i2, dx, dy);
2089
2090 if (!is_valid(himl1) || !is_valid(himl2))
2091 return NULL;
2092
2093 if (dx > 0) {
2094 cxDst = max (himl1->cx, dx + himl2->cx);
2095 xOff1 = 0;
2096 xOff2 = dx;
2097 }
2098 else if (dx < 0) {
2099 cxDst = max (himl2->cx, himl1->cx - dx);
2100 xOff1 = -dx;
2101 xOff2 = 0;
2102 }
2103 else {
2104 cxDst = max (himl1->cx, himl2->cx);
2105 xOff1 = 0;
2106 xOff2 = 0;
2107 }
2108
2109 if (dy > 0) {
2110 cyDst = max (himl1->cy, dy + himl2->cy);
2111 yOff1 = 0;
2112 yOff2 = dy;
2113 }
2114 else if (dy < 0) {
2115 cyDst = max (himl2->cy, himl1->cy - dy);
2116 yOff1 = -dy;
2117 yOff2 = 0;
2118 }
2119 else {
2120 cyDst = max (himl1->cy, himl2->cy);
2121 yOff1 = 0;
2122 yOff2 = 0;
2123 }
2124
2125 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2126
2127 if (himlDst)
2128 {
2129 imagelist_point_from_index( himl1, i1, &pt1 );
2130 imagelist_point_from_index( himl2, i2, &pt2 );
2131
2132 /* copy image */
2133 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
2134 if (i1 >= 0 && i1 < himl1->cCurImage)
2135 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
2136 if (i2 >= 0 && i2 < himl2->cCurImage)
2137 {
2138 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
2139 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
2140 }
2141
2142 /* copy mask */
2143 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
2144 if (i1 >= 0 && i1 < himl1->cCurImage)
2145 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, pt1.x, pt1.y, SRCCOPY);
2146 if (i2 >= 0 && i2 < himl2->cCurImage)
2147 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, pt2.x, pt2.y, SRCAND);
2148
2149 himlDst->cCurImage = 1;
2150 }
2151
2152 return himlDst;
2153 }
2154
2155
2156 /* helper for ImageList_Read, see comments below */
2157 static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
2158 {
2159 BITMAPFILEHEADER bmfh;
2160 int bitsperpixel, palspace;
2161 void *bits;
2162
2163 if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
2164 return NULL;
2165
2166 if (bmfh.bfType != (('M'<<8)|'B'))
2167 return NULL;
2168
2169 if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
2170 return NULL;
2171
2172 if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
2173 return NULL;
2174
2175 TRACE("width %u, height %u, planes %u, bpp %u\n",
2176 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
2177 bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount);
2178
2179 bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
2180 if (bitsperpixel<=8)
2181 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2182 else
2183 palspace = 0;
2184
2185 bmi->bmiHeader.biSizeImage = get_dib_image_size( bmi );
2186
2187 /* read the palette right after the end of the bitmapinfoheader */
2188 if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
2189 return NULL;
2190
2191 bits = Alloc(bmi->bmiHeader.biSizeImage);
2192 if (!bits) return NULL;
2193
2194 if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
2195 {
2196 Free(bits);
2197 return NULL;
2198 }
2199 return bits;
2200 }
2201
2202 /*************************************************************************
2203 * ImageList_Read [COMCTL32.@]
2204 *
2205 * Reads an image list from a stream.
2206 *
2207 * PARAMS
2208 * pstm [I] pointer to a stream
2209 *
2210 * RETURNS
2211 * Success: handle to image list
2212 * Failure: NULL
2213 *
2214 * The format is like this:
2215 * ILHEAD ilheadstruct;
2216 *
2217 * for the color image part:
2218 * BITMAPFILEHEADER bmfh;
2219 * BITMAPINFOHEADER bmih;
2220 * only if it has a palette:
2221 * RGBQUAD rgbs[nr_of_paletted_colors];
2222 *
2223 * BYTE colorbits[imagesize];
2224 *
2225 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2226 * BITMAPFILEHEADER bmfh_mask;
2227 * BITMAPINFOHEADER bmih_mask;
2228 * only if it has a palette (it usually does not):
2229 * RGBQUAD rgbs[nr_of_paletted_colors];
2230 *
2231 * BYTE maskbits[imagesize];
2232 */
2233 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2234 {
2235 char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2236 char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2237 BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
2238 BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
2239 void *image_bits, *mask_bits = NULL;
2240 ILHEAD ilHead;
2241 HIMAGELIST himl;
2242 int i;
2243
2244 TRACE("%p\n", pstm);
2245
2246 if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2247 return NULL;
2248 if (ilHead.usMagic != (('L' << 8) | 'I'))
2249 return NULL;
2250 if (ilHead.usVersion != 0x101) /* probably version? */
2251 return NULL;
2252
2253 TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
2254 ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2255
2256 himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2257 if (!himl)
2258 return NULL;
2259
2260 if (!(image_bits = read_bitmap(pstm, image_info)))
2261 {
2262 WARN("failed to read bitmap from stream\n");
2263 return NULL;
2264 }
2265 if (ilHead.flags & ILC_MASK)
2266 {
2267 if (!(mask_bits = read_bitmap(pstm, mask_info)))
2268 {
2269 WARN("failed to read mask bitmap from stream\n");
2270 return NULL;
2271 }
2272 }
2273 else mask_info = NULL;
2274
2275 if (himl->has_alpha && image_info->bmiHeader.biBitCount == 32)
2276 {
2277 DWORD *ptr = image_bits;
2278 BYTE *mask_ptr = mask_bits;
2279 int stride = himl->cy * image_info->bmiHeader.biWidth;
2280
2281 if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
2282 {
2283 ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
2284 mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
2285 stride = -stride;
2286 image_info->bmiHeader.biHeight = himl->cy;
2287 }
2288 else image_info->bmiHeader.biHeight = -himl->cy;
2289
2290 for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
2291 {
2292 add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
2293 himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
2294 ptr += stride;
2295 mask_ptr += stride / 8;
2296 }
2297 }
2298 else
2299 {
2300 StretchDIBits( himl->hdcImage, 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2301 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2302 image_bits, image_info, DIB_RGB_COLORS, SRCCOPY);
2303 if (mask_info)
2304 StretchDIBits( himl->hdcMask, 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2305 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2306 mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
2307 }
2308 Free( image_bits );
2309 Free( mask_bits );
2310
2311 himl->cCurImage = ilHead.cCurImage;
2312 himl->cMaxImage = ilHead.cMaxImage;
2313
2314 ImageList_SetBkColor(himl,ilHead.bkcolor);
2315 for (i=0;i<4;i++)
2316 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2317 return himl;
2318 }
2319
2320
2321 /*************************************************************************
2322 * ImageList_Remove [COMCTL32.@]
2323 *
2324 * Removes an image from an image list
2325 *
2326 * PARAMS
2327 * himl [I] image list handle
2328 * i [I] image index
2329 *
2330 * RETURNS
2331 * Success: TRUE
2332 * Failure: FALSE
2333 *
2334 * FIXME: as the image list storage test shows, native comctl32 simply shifts
2335 * images without creating a new bitmap.
2336 */
2337 BOOL WINAPI
2338 ImageList_Remove (HIMAGELIST himl, INT i)
2339 {
2340 HBITMAP hbmNewImage, hbmNewMask;
2341 HDC hdcBmp;
2342 SIZE sz;
2343
2344 TRACE("(himl=%p i=%d)\n", himl, i);
2345
2346 if (!is_valid(himl)) {
2347 ERR("Invalid image list handle!\n");
2348 return FALSE;
2349 }
2350
2351 if ((i < -1) || (i >= himl->cCurImage)) {
2352 TRACE("index out of range! %d\n", i);
2353 return FALSE;
2354 }
2355
2356 if (i == -1) {
2357 INT nCount;
2358
2359 /* remove all */
2360 if (himl->cCurImage == 0) {
2361 /* remove all on empty ImageList is allowed */
2362 TRACE("remove all on empty ImageList!\n");
2363 return TRUE;
2364 }
2365
2366 himl->cMaxImage = himl->cGrow;
2367 himl->cCurImage = 0;
2368 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2369 himl->nOvlIdx[nCount] = -1;
2370
2371 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2372 SelectObject (himl->hdcImage, hbmNewImage);
2373 DeleteObject (himl->hbmImage);
2374 himl->hbmImage = hbmNewImage;
2375
2376 if (himl->hbmMask) {
2377
2378 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2379 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2380 SelectObject (himl->hdcMask, hbmNewMask);
2381 DeleteObject (himl->hbmMask);
2382 himl->hbmMask = hbmNewMask;
2383 }
2384 }
2385 else {
2386 /* delete one image */
2387 TRACE("Remove single image! %d\n", i);
2388
2389 /* create new bitmap(s) */
2390 TRACE(" - Number of images: %d / %d (Old/New)\n",
2391 himl->cCurImage, himl->cCurImage - 1);
2392
2393 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2394
2395 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
2396 if (himl->hbmMask)
2397 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2398 else
2399 hbmNewMask = 0; /* Just to keep compiler happy! */
2400
2401 hdcBmp = CreateCompatibleDC (0);
2402
2403 /* copy all images and masks prior to the "removed" image */
2404 if (i > 0) {
2405 TRACE("Pre image copy: Copy %d images\n", i);
2406
2407 SelectObject (hdcBmp, hbmNewImage);
2408 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2409
2410 if (himl->hbmMask) {
2411 SelectObject (hdcBmp, hbmNewMask);
2412 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2413 }
2414 }
2415
2416 /* copy all images and masks behind the removed image */
2417 if (i < himl->cCurImage - 1) {
2418 TRACE("Post image copy!\n");
2419
2420 SelectObject (hdcBmp, hbmNewImage);
2421 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
2422 (himl->cCurImage - i), i );
2423
2424 if (himl->hbmMask) {
2425 SelectObject (hdcBmp, hbmNewMask);
2426 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
2427 (himl->cCurImage - i), i );
2428 }
2429 }
2430
2431 DeleteDC (hdcBmp);
2432
2433 /* delete old images and insert new ones */
2434 SelectObject (himl->hdcImage, hbmNewImage);
2435 DeleteObject (himl->hbmImage);
2436 himl->hbmImage = hbmNewImage;
2437 if (himl->hbmMask) {
2438 SelectObject (himl->hdcMask, hbmNewMask);
2439 DeleteObject (himl->hbmMask);
2440 himl->hbmMask = hbmNewMask;
2441 }
2442
2443 himl->cCurImage--;
2444 }
2445
2446 return TRUE;
2447 }
2448
2449
2450 /*************************************************************************
2451 * ImageList_Replace [COMCTL32.@]
2452 *
2453 * Replaces an image in an image list with a new image.
2454 *
2455 * PARAMS
2456 * himl [I] handle to image list
2457 * i [I] image index
2458 * hbmImage [I] handle to image bitmap
2459 * hbmMask [I] handle to mask bitmap. Can be NULL.
2460 *
2461 * RETURNS
2462 * Success: TRUE
2463 * Failure: FALSE
2464 */
2465
2466 BOOL WINAPI
2467 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2468 HBITMAP hbmMask)
2469 {
2470 HDC hdcImage;
2471 BITMAP bmp;
2472 POINT pt;
2473
2474 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2475
2476 if (!is_valid(himl)) {
2477 ERR("Invalid image list handle!\n");
2478 return FALSE;
2479 }
2480
2481 if ((i >= himl->cMaxImage) || (i < 0)) {
2482 ERR("Invalid image index!\n");
2483 return FALSE;
2484 }
2485
2486 if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
2487 return FALSE;
2488
2489 hdcImage = CreateCompatibleDC (0);
2490
2491 /* Replace Image */
2492 SelectObject (hdcImage, hbmImage);
2493
2494 if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
2495 goto done;
2496
2497 imagelist_point_from_index(himl, i, &pt);
2498 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2499 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2500
2501 if (himl->hbmMask)
2502 {
2503 HDC hdcTemp;
2504 HBITMAP hOldBitmapTemp;
2505
2506 hdcTemp = CreateCompatibleDC(0);
2507 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2508
2509 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2510 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2511 SelectObject(hdcTemp, hOldBitmapTemp);
2512 DeleteDC(hdcTemp);
2513
2514 /* Remove the background from the image
2515 */
2516 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2517 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2518 }
2519
2520 done:
2521 DeleteDC (hdcImage);
2522
2523 return TRUE;
2524 }
2525
2526
2527 /*************************************************************************
2528 * ImageList_ReplaceIcon [COMCTL32.@]
2529 *
2530 * Replaces an image in an image list using an icon.
2531 *
2532 * PARAMS
2533 * himl [I] handle to image list
2534 * i [I] image index
2535 * hIcon [I] handle to icon
2536 *
2537 * RETURNS
2538 * Success: index of the replaced image
2539 * Failure: -1
2540 */
2541
2542 INT WINAPI
2543 ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
2544 {
2545 HICON hBestFitIcon;
2546 ICONINFO ii;
2547 BITMAP bmp;
2548 BOOL ret;
2549 POINT pt;
2550
2551 TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
2552
2553 if (!is_valid(himl)) {
2554 ERR("invalid image list\n");
2555 return -1;
2556 }
2557 if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
2558 ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2559 return -1;
2560 }
2561
2562 hBestFitIcon = CopyImage(
2563 hIcon, IMAGE_ICON,
2564 himl->cx, himl->cy,
2565 LR_COPYFROMRESOURCE);
2566 /* the above will fail if the icon wasn't loaded from a resource, so try
2567 * again without LR_COPYFROMRESOURCE flag */
2568 if (!hBestFitIcon)
2569 hBestFitIcon = CopyImage(
2570 hIcon, IMAGE_ICON,
2571 himl->cx, himl->cy,
2572 0);
2573 if (!hBestFitIcon)
2574 return -1;
2575
2576 if (nIndex == -1) {
2577 if (himl->cCurImage + 1 >= himl->cMaxImage)
2578 IMAGELIST_InternalExpandBitmaps(himl, 1);
2579
2580 nIndex = himl->cCurImage;
2581 himl->cCurImage++;
2582 }
2583
2584 if (himl->has_alpha && GetIconInfo (hBestFitIcon, &ii))
2585 {
2586 HDC hdcImage = CreateCompatibleDC( 0 );
2587 GetObjectW (ii.hbmMask, sizeof(BITMAP), &bmp);
2588
2589 if (!ii.hbmColor)
2590 {
2591 UINT height = bmp.bmHeight / 2;
2592 HDC hdcMask = CreateCompatibleDC( 0 );
2593 HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
2594 SelectObject( hdcImage, color );
2595 SelectObject( hdcMask, ii.hbmMask );
2596 BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
2597 ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
2598 DeleteDC( hdcMask );
2599 DeleteObject( color );
2600 }
2601 else ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight,
2602 ii.hbmColor, ii.hbmMask );
2603
2604 DeleteDC( hdcImage );
2605 DeleteObject (ii.hbmMask);
2606 if (ii.hbmColor) DeleteObject (ii.hbmColor);
2607 if (ret) goto done;
2608 }
2609
2610 imagelist_point_from_index(himl, nIndex, &pt);
2611
2612 if (himl->hbmMask)
2613 {
2614 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_IMAGE );
2615 PatBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy, WHITENESS );
2616 DrawIconEx( himl->hdcMask, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_MASK );
2617 }
2618 else
2619 {
2620 COLORREF color = himl->clrBk != CLR_NONE ? himl->clrBk : comctl32_color.clrWindow;
2621 HBRUSH brush = CreateSolidBrush( GetNearestColor( himl->hdcImage, color ));
2622
2623 SelectObject( himl->hdcImage, brush );
2624 PatBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy, PATCOPY );
2625 SelectObject( himl->hdcImage, GetStockObject(BLACK_BRUSH) );
2626 DeleteObject( brush );
2627 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_NORMAL );
2628 }
2629
2630 done:
2631 DestroyIcon(hBestFitIcon);
2632
2633 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2634 return nIndex;
2635 }
2636
2637
2638 /*************************************************************************
2639 * ImageList_SetBkColor [COMCTL32.@]
2640 *
2641 * Sets the background color of an image list.
2642 *
2643 * PARAMS
2644 * himl [I] handle to image list
2645 * clrBk [I] background color
2646 *
2647 * RETURNS
2648 * Success: previous background color
2649 * Failure: CLR_NONE
2650 */
2651
2652 COLORREF WINAPI
2653 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2654 {
2655 COLORREF clrOldBk;
2656
2657 if (!is_valid(himl))
2658 return CLR_NONE;
2659
2660 clrOldBk = himl->clrBk;
2661 himl->clrBk = clrBk;
2662 return clrOldBk;
2663 }
2664
2665
2666 /*************************************************************************
2667 * ImageList_SetDragCursorImage [COMCTL32.@]
2668 *
2669 * Combines the specified image with the current drag image
2670 *
2671 * PARAMS
2672 * himlDrag [I] handle to drag image list
2673 * iDrag [I] drag image index
2674 * dxHotspot [I] X position of the hot spot
2675 * dyHotspot [I] Y position of the hot spot
2676 *
2677 * RETURNS
2678 * Success: TRUE
2679 * Failure: FALSE
2680 *
2681 * NOTES
2682 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2683 * to do with a hotspot but are only the offset of the origin of the new
2684 * image relative to the origin of the old image.
2685 *
2686 * - When this function is called and the drag image is visible, a
2687 * short flickering occurs but this matches the Win9x behavior. It is
2688 * possible to fix the flickering using code like in ImageList_DragMove.
2689 */
2690
2691 BOOL WINAPI
2692 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2693 INT dxHotspot, INT dyHotspot)
2694 {
2695 HIMAGELIST himlTemp;
2696 BOOL visible;
2697
2698 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2699 return FALSE;
2700
2701 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2702 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2703
2704 visible = InternalDrag.bShow;
2705
2706 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2707 dxHotspot, dyHotspot);
2708
2709 if (visible) {
2710 /* hide the drag image */
2711 ImageList_DragShowNolock(FALSE);
2712 }
2713 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2714 (InternalDrag.himl->cy != himlTemp->cy)) {
2715 /* the size of the drag image changed, invalidate the buffer */
2716 DeleteObject(InternalDrag.hbmBg);
2717 InternalDrag.hbmBg = 0;
2718 }
2719
2720 ImageList_Destroy (InternalDrag.himl);
2721 InternalDrag.himl = himlTemp;
2722
2723 if (visible) {
2724 /* show the drag image */
2725 ImageList_DragShowNolock(TRUE);
2726 }
2727
2728 return TRUE;
2729 }
2730
2731
2732 /*************************************************************************
2733 * ImageList_SetFilter [COMCTL32.@]
2734 *
2735 * Sets a filter (or does something completely different)!!???
2736 * It removes 12 Bytes from the stack (3 Parameters).
2737 *
2738 * PARAMS
2739 * himl [I] SHOULD be a handle to image list
2740 * i [I] COULD be an index?
2741 * dwFilter [I] ???
2742 *
2743 * RETURNS
2744 * Success: TRUE ???
2745 * Failure: FALSE ???
2746 *
2747 * BUGS
2748 * This is an UNDOCUMENTED function!!!!
2749 * empty stub.
2750 */
2751
2752 BOOL WINAPI
2753 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2754 {
2755 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2756
2757 return FALSE;
2758 }
2759
2760
2761 /*************************************************************************
2762 * ImageList_SetFlags [COMCTL32.@]
2763 *
2764 * Sets the image list flags.
2765 *
2766 * PARAMS
2767 * himl [I] Handle to image list
2768 * flags [I] Flags to set
2769 *
2770 * RETURNS
2771 * Old flags?
2772 *
2773 * BUGS
2774 * Stub.
2775 */
2776
2777 DWORD WINAPI
2778 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2779 {
2780 FIXME("(%p %08x):empty stub\n", himl, flags);
2781 return 0;
2782 }
2783
2784
2785 /*************************************************************************
2786 * ImageList_SetIconSize [COMCTL32.@]
2787 *
2788 * Sets the image size of the bitmap and deletes all images.
2789 *
2790 * PARAMS
2791 * himl [I] handle to image list
2792 * cx [I] image width
2793 * cy [I] image height
2794 *
2795 * RETURNS
2796 * Success: TRUE
2797 * Failure: FALSE
2798 */
2799
2800 BOOL WINAPI
2801 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2802 {
2803 INT nCount;
2804 HBITMAP hbmNew;
2805
2806 if (!is_valid(himl))
2807 return FALSE;
2808
2809 /* remove all images */
2810 himl->cMaxImage = himl->cInitial + 1;
2811 himl->cCurImage = 0;
2812 himl->cx = cx;
2813 himl->cy = cy;
2814
2815 /* initialize overlay mask indices */
2816 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2817 himl->nOvlIdx[nCount] = -1;
2818
2819 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2820 SelectObject (himl->hdcImage, hbmNew);
2821 DeleteObject (himl->hbmImage);
2822 himl->hbmImage = hbmNew;
2823
2824 if (himl->hbmMask) {
2825 SIZE sz;
2826 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2827 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2828 SelectObject (himl->hdcMask, hbmNew);
2829 DeleteObject (himl->hbmMask);
2830 himl->hbmMask = hbmNew;
2831 }
2832
2833 return TRUE;
2834 }
2835
2836
2837 /*************************************************************************
2838 * ImageList_SetImageCount [COMCTL32.@]
2839 *
2840 * Resizes an image list to the specified number of images.
2841 *
2842 * PARAMS
2843 * himl [I] handle to image list
2844 * iImageCount [I] number of images in the image list
2845 *
2846 * RETURNS
2847 * Success: TRUE
2848 * Failure: FALSE
2849 */
2850
2851 BOOL WINAPI
2852 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2853 {
2854 HDC hdcBitmap;
2855 HBITMAP hbmNewBitmap, hbmOld;
2856 INT nNewCount, nCopyCount;
2857
2858 TRACE("%p %d\n",himl,iImageCount);
2859
2860 if (!is_valid(himl))
2861 return FALSE;
2862
2863 nNewCount = iImageCount + 1;
2864 nCopyCount = min(himl->cCurImage, iImageCount);
2865
2866 hdcBitmap = CreateCompatibleDC (0);
2867
2868 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
2869
2870 if (hbmNewBitmap != 0)
2871 {
2872 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2873 imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2874 SelectObject (hdcBitmap, hbmOld);
2875
2876 /* FIXME: delete 'empty' image space? */
2877
2878 SelectObject (himl->hdcImage, hbmNewBitmap);
2879 DeleteObject (himl->hbmImage);
2880 himl->hbmImage = hbmNewBitmap;
2881 }
2882 else
2883 ERR("Could not create new image bitmap !\n");
2884
2885 if (himl->hbmMask)
2886 {
2887 SIZE sz;
2888 imagelist_get_bitmap_size( himl, nNewCount, &sz );
2889 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2890 if (hbmNewBitmap != 0)
2891 {
2892 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2893 imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
2894 SelectObject (hdcBitmap, hbmOld);
2895
2896 /* FIXME: delete 'empty' image space? */
2897
2898 SelectObject (himl->hdcMask, hbmNewBitmap);
2899 DeleteObject (himl->hbmMask);
2900 himl->hbmMask = hbmNewBitmap;
2901 }
2902 else
2903 ERR("Could not create new mask bitmap!\n");
2904 }
2905
2906 DeleteDC (hdcBitmap);
2907
2908 if (himl->has_alpha)
2909 {
2910 char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
2911 if (new_alpha) himl->has_alpha = new_alpha;
2912 else
2913 {
2914 HeapFree( GetProcessHeap(), 0, himl->has_alpha );
2915 himl->has_alpha = NULL;
2916 }
2917 }
2918
2919 /* Update max image count and current image count */
2920 himl->cMaxImage = nNewCount;
2921 himl->cCurImage = iImageCount;
2922
2923 return TRUE;
2924 }
2925
2926
2927 /*************************************************************************
2928 * ImageList_SetOverlayImage [COMCTL32.@]
2929 *
2930 * Assigns an overlay mask index to an existing image in an image list.
2931 *
2932 * PARAMS
2933 * himl [I] handle to image list
2934 * iImage [I] image index
2935 * iOverlay [I] overlay mask index
2936 *
2937 * RETURNS
2938 * Success: TRUE
2939 * Failure: FALSE
2940 */
2941
2942 BOOL WINAPI
2943 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2944 {
2945 if (!is_valid(himl))
2946 return FALSE;
2947 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2948 return FALSE;
2949 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2950 return FALSE;
2951 himl->nOvlIdx[iOverlay - 1] = iImage;
2952 return TRUE;
2953 }
2954
2955
2956
2957 /* helper for ImageList_Write - write bitmap to pstm
2958 * currently everything is written as 24 bit RGB, except masks
2959 */
2960 static BOOL
2961 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
2962 {
2963 LPBITMAPFILEHEADER bmfh;
2964 LPBITMAPINFOHEADER bmih;
2965 LPBYTE data = NULL, lpBits;
2966 BITMAP bm;
2967 INT bitCount, sizeImage, offBits, totalSize;
2968 HDC xdc;
2969 BOOL result = FALSE;
2970
2971 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
2972 return FALSE;
2973
2974 bitCount = bm.bmBitsPixel;
2975 sizeImage = get_dib_stride(bm.bmWidth, bitCount) * bm.bmHeight;
2976
2977 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2978 if(bitCount <= 8)
2979 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2980 offBits = totalSize;
2981 totalSize += sizeImage;
2982
2983 data = Alloc(totalSize);
2984 bmfh = (LPBITMAPFILEHEADER)data;
2985 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2986 lpBits = data + offBits;
2987
2988 /* setup BITMAPFILEHEADER */
2989 bmfh->bfType = (('M' << 8) | 'B');
2990 bmfh->bfSize = offBits;
2991 bmfh->bfReserved1 = 0;
2992 bmfh->bfReserved2 = 0;
2993 bmfh->bfOffBits = offBits;
2994
2995 /* setup BITMAPINFOHEADER */
2996 bmih->biSize = sizeof(BITMAPINFOHEADER);
2997 bmih->biWidth = bm.bmWidth;
2998 bmih->biHeight = bm.bmHeight;
2999 bmih->biPlanes = 1;
3000 bmih->biBitCount = bitCount;
3001 bmih->biCompression = BI_RGB;
3002 bmih->biSizeImage = sizeImage;
3003 bmih->biXPelsPerMeter = 0;
3004 bmih->biYPelsPerMeter = 0;
3005 bmih->biClrUsed = 0;
3006 bmih->biClrImportant = 0;
3007
3008 xdc = GetDC(0);
3009 result = GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBits, (BITMAPINFO *)bmih, DIB_RGB_COLORS) == bm.bmHeight;
3010 ReleaseDC(0, xdc);
3011 if (!result)
3012 goto failed;
3013
3014 TRACE("width %u, height %u, planes %u, bpp %u\n",
3015 bmih->biWidth, bmih->biHeight,
3016 bmih->biPlanes, bmih->biBitCount);
3017
3018 if(FAILED(IStream_Write(pstm, data, totalSize, NULL)))
3019 goto failed;
3020
3021 result = TRUE;
3022
3023 failed:
3024 Free(data);
3025
3026 return result;
3027 }
3028
3029
3030 /*************************************************************************
3031 * ImageList_Write [COMCTL32.@]
3032 *
3033 * Writes an image list to a stream.
3034 *
3035 * PARAMS
3036 * himl [I] handle to image list
3037 * pstm [O] Pointer to a stream.
3038 *
3039 * RETURNS
3040 * Success: TRUE
3041 * Failure: FALSE
3042 *
3043 * BUGS
3044 * probably.
3045 */
3046
3047 BOOL WINAPI
3048 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
3049 {
3050 ILHEAD ilHead;
3051 int i;
3052
3053 TRACE("%p %p\n", himl, pstm);
3054
3055 if (!is_valid(himl))
3056 return FALSE;
3057
3058 ilHead.usMagic = (('L' << 8) | 'I');
3059 ilHead.usVersion = 0x101;
3060 ilHead.cCurImage = himl->cCurImage;
3061 ilHead.cMaxImage = himl->cMaxImage;
3062 ilHead.cGrow = himl->cGrow;
3063 ilHead.cx = himl->cx;
3064 ilHead.cy = himl->cy;
3065 ilHead.bkcolor = himl->clrBk;
3066 ilHead.flags = himl->flags;
3067 for(i = 0; i < 4; i++) {
3068 ilHead.ovls[i] = himl->nOvlIdx[i];
3069 }
3070
3071 TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
3072 ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
3073
3074 if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3075 return FALSE;
3076
3077 /* write the bitmap */
3078 if(!_write_bitmap(himl->hbmImage, pstm))
3079 return FALSE;
3080
3081 /* write the mask if we have one */
3082 if(himl->flags & ILC_MASK) {
3083 if(!_write_bitmap(himl->hbmMask, pstm))
3084 return FALSE;
3085 }
3086
3087 return TRUE;
3088 }
3089
3090
3091 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
3092 {
3093 HBITMAP hbmNewBitmap;
3094 UINT ilc = (himl->flags & 0xFE);
3095 SIZE sz;
3096
3097 imagelist_get_bitmap_size( himl, count, &sz );
3098
3099 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
3100 {
3101 char buffer[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
3102 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
3103
3104 TRACE("Creating DIBSection %d x %d, %d Bits per Pixel\n",
3105 sz.cx, sz.cy, himl->uBitsPixel);
3106
3107 memset( buffer, 0, sizeof(buffer) );
3108 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3109 bmi->bmiHeader.biWidth = sz.cx;
3110 bmi->bmiHeader.biHeight = sz.cy;
3111 bmi->bmiHeader.biPlanes = 1;
3112 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
3113 bmi->bmiHeader.biCompression = BI_RGB;
3114
3115 if (himl->uBitsPixel <= ILC_COLOR8)
3116 {
3117 /* retrieve the default color map */
3118 HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
3119 GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
3120 DeleteObject( tmp );
3121 }
3122 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, 0, 0);
3123 }
3124 else /*if (ilc == ILC_COLORDDB)*/
3125 {
3126 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
3127
3128 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
3129 }
3130 TRACE("returning %p\n", hbmNewBitmap);
3131 return hbmNewBitmap;
3132 }
3133
3134 /*************************************************************************
3135 * ImageList_SetColorTable [COMCTL32.@]
3136 *
3137 * Sets the color table of an image list.
3138 *
3139 * PARAMS
3140 * himl [I] Handle to the image list.
3141 * uStartIndex [I] The first index to set.
3142 * cEntries [I] Number of entries to set.
3143 * prgb [I] New color information for color table for the image list.
3144 *
3145 * RETURNS
3146 * Success: Number of entries in the table that were set.
3147 * Failure: Zero.
3148 *
3149 * SEE
3150 * ImageList_Create(), SetDIBColorTable()
3151 */
3152
3153 UINT WINAPI
3154 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
3155 {
3156 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
3157 }
3158
3159 /*************************************************************************
3160 * ImageList_CoCreateInstance [COMCTL32.@]
3161 *
3162 * Creates a new imagelist instance and returns an interface pointer to it.
3163 *
3164 * PARAMS
3165 * rclsid [I] A reference to the CLSID (CLSID_ImageList).
3166 * punkOuter [I] Pointer to IUnknown interface for aggregation, if desired
3167 * riid [I] Identifier of the requested interface.
3168 * ppv [O] Returns the address of the pointer requested, or NULL.
3169 *
3170 * RETURNS
3171 * Success: S_OK.
3172 * Failure: Error value.
3173 */
3174 HRESULT WINAPI
3175 ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID riid, void **ppv)
3176 {
3177 TRACE("(%s,%p,%s,%p)\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
3178
3179 if (!IsEqualCLSID(&CLSID_ImageList, rclsid))
3180 return E_NOINTERFACE;
3181
3182 return ImageListImpl_CreateInstance(punkOuter, riid, ppv);
3183 }
3184
3185
3186 /*************************************************************************
3187 * IImageList implementation
3188 */
3189
3190 static HRESULT WINAPI ImageListImpl_QueryInterface(IImageList *iface,
3191 REFIID iid, void **ppv)
3192 {
3193 HIMAGELIST This = (HIMAGELIST) iface;
3194 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
3195
3196 if (!ppv) return E_INVALIDARG;
3197
3198 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IImageList, iid))
3199 *ppv = This;
3200 else
3201 {
3202 *ppv = NULL;
3203 return E_NOINTERFACE;
3204 }
3205
3206 IUnknown_AddRef((IUnknown*)*ppv);
3207 return S_OK;
3208 }
3209
3210 static ULONG WINAPI ImageListImpl_AddRef(IImageList *iface)
3211 {
3212 HIMAGELIST This = (HIMAGELIST) iface;
3213 ULONG ref = InterlockedIncrement(&This->ref);
3214
3215 TRACE("(%p) refcount=%u\n", iface, ref);
3216 return ref;
3217 }
3218
3219 static ULONG WINAPI ImageListImpl_Release(IImageList *iface)
3220 {
3221 HIMAGELIST This = (HIMAGELIST) iface;
3222 ULONG ref = InterlockedDecrement(&This->ref);
3223
3224 TRACE("(%p) refcount=%u\n", iface, ref);
3225
3226 if (ref == 0)
3227 {
3228 /* delete image bitmaps */
3229 if (This->hbmImage) DeleteObject (This->hbmImage);
3230 if (This->hbmMask) DeleteObject (This->hbmMask);
3231
3232 /* delete image & mask DCs */
3233 if (This->hdcImage) DeleteDC (This->hdcImage);
3234 if (This->hdcMask) DeleteDC (This->hdcMask);
3235
3236 /* delete blending brushes */
3237 if (This->hbrBlend25) DeleteObject (This->hbrBlend25);
3238 if (This->hbrBlend50) DeleteObject (This->hbrBlend50);
3239
3240 This->lpVtbl = NULL;
3241 HeapFree(GetProcessHeap(), 0, This->has_alpha);
3242 HeapFree(GetProcessHeap(), 0, This);
3243 }
3244
3245 return ref;
3246 }
3247
3248 static HRESULT WINAPI ImageListImpl_Add(IImageList *iface, HBITMAP hbmImage,
3249 HBITMAP hbmMask, int *pi)
3250 {
3251 HIMAGELIST This = (HIMAGELIST) iface;
3252 int ret;
3253
3254 if (!pi)
3255 return E_FAIL;
3256
3257 ret = ImageList_Add(This, hbmImage, hbmMask);
3258
3259 if (ret == -1)
3260 return E_FAIL;
3261
3262 *pi = ret;
3263 return S_OK;
3264 }
3265
3266 static HRESULT WINAPI ImageListImpl_ReplaceIcon(IImageList *iface, int i,
3267 HICON hicon, int *pi)
3268 {
3269 HIMAGELIST This = (HIMAGELIST) iface;
3270 int ret;
3271
3272 if (!pi)
3273 return E_FAIL;
3274
3275 ret = ImageList_ReplaceIcon(This, i, hicon);
3276
3277 if (ret == -1)
3278 return E_FAIL;
3279
3280 *pi = ret;
3281 return S_OK;
3282 }
3283
3284 static HRESULT WINAPI ImageListImpl_SetOverlayImage(IImageList *iface,
3285 int iImage, int iOverlay)
3286 {
3287 return ImageList_SetOverlayImage((HIMAGELIST) iface, iImage, iOverlay)
3288 ? S_OK : E_FAIL;
3289 }
3290
3291 static HRESULT WINAPI ImageListImpl_Replace(IImageList *iface, int i,
3292 HBITMAP hbmImage, HBITMAP hbmMask)
3293 {
3294 return ImageList_Replace((HIMAGELIST) iface, i, hbmImage, hbmMask) ? S_OK :
3295 E_FAIL;
3296 }
3297
3298 static HRESULT WINAPI ImageListImpl_AddMasked(IImageList *iface, HBITMAP hbmImage,
3299 COLORREF crMask, int *pi)
3300 {
3301 HIMAGELIST This = (HIMAGELIST) iface;
3302 int ret;
3303
3304 if (!pi)
3305 return E_FAIL;
3306
3307 ret = ImageList_AddMasked(This, hbmImage, crMask);
3308
3309 if (ret == -1)
3310 return E_FAIL;
3311
3312 *pi = ret;
3313 return S_OK;
3314 }
3315
3316 static HRESULT WINAPI ImageListImpl_Draw(IImageList *iface,
3317 IMAGELISTDRAWPARAMS *pimldp)
3318 {
3319 HIMAGELIST This = (HIMAGELIST) iface;
3320 HIMAGELIST old_himl;
3321 int ret;
3322
3323 /* As far as I can tell, Windows simply ignores the contents of pimldp->himl
3324 so we shall simulate the same */
3325 old_himl = pimldp->himl;
3326 pimldp->himl = This;
3327
3328 ret = ImageList_DrawIndirect(pimldp);
3329
3330 pimldp->himl = old_himl;
3331 return ret ? S_OK : E_INVALIDARG;
3332 }
3333
3334 static HRESULT WINAPI ImageListImpl_Remove(IImageList *iface, int i)
3335 {
3336 return (ImageList_Remove((HIMAGELIST) iface, i) == 0) ? E_INVALIDARG : S_OK;
3337 }
3338
3339 static HRESULT WINAPI ImageListImpl_GetIcon(IImageList *iface, int i, UINT flags,
3340 HICON *picon)
3341 {
3342 HICON hIcon;
3343
3344 if (!picon)
3345 return E_FAIL;
3346
3347 hIcon = ImageList_GetIcon((HIMAGELIST) iface, i, flags);
3348
3349 if (hIcon == NULL)
3350 return E_FAIL;
3351
3352 *picon = hIcon;
3353 return S_OK;
3354 }
3355
3356 static HRESULT WINAPI ImageListImpl_GetImageInfo(IImageList *iface, int i,
3357 IMAGEINFO *pImageInfo)
3358 {
3359 return ImageList_GetImageInfo((HIMAGELIST) iface, i, pImageInfo) ? S_OK : E_FAIL;
3360 }
3361
3362 static HRESULT WINAPI ImageListImpl_Copy(IImageList *iface, int iDst,
3363 IUnknown *punkSrc, int iSrc, UINT uFlags)
3364 {
3365 HIMAGELIST This = (HIMAGELIST) iface;
3366 IImageList *src = NULL;
3367 HRESULT ret;
3368
3369 if (!punkSrc)
3370 return E_FAIL;
3371
3372 /* TODO: Add test for IID_ImageList2 too */
3373 if (FAILED(IUnknown_QueryInterface(punkSrc, &IID_IImageList,
3374 (void **) &src)))
3375 return E_FAIL;
3376
3377 if (ImageList_Copy(This, iDst, (HIMAGELIST) src, iSrc, uFlags))
3378 ret = S_OK;
3379 else
3380 ret = E_FAIL;
3381
3382 IImageList_Release(src);
3383 return ret;
3384 }
3385
3386 static HRESULT WINAPI ImageListImpl_Merge(IImageList *iface, int i1,
3387 IUnknown *punk2, int i2, int dx, int dy, REFIID riid, void **ppv)
3388 {
3389 HIMAGELIST This = (HIMAGELIST) iface;
3390 IImageList *iml2 = NULL;
3391 HIMAGELIST hNew;
3392 HRESULT ret = E_FAIL;
3393
3394 TRACE("(%p)->(%d %p %d %d %d %s %p)\n", iface, i1, punk2, i2, dx, dy, debugstr_guid(riid), ppv);
3395
3396 /* TODO: Add test for IID_ImageList2 too */
3397 if (FAILED(IUnknown_QueryInterface(punk2, &IID_IImageList,
3398 (void **) &iml2)))
3399 return E_FAIL;
3400
3401 hNew = ImageList_Merge(This, i1, (HIMAGELIST) iml2, i2, dx, dy);
3402
3403 /* Get the interface for the new image list */
3404 if (hNew)
3405 {
3406 IImageList *imerge = (IImageList*)hNew;
3407
3408 ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
3409 IImageList_Release(imerge);
3410 }
3411
3412 IImageList_Release(iml2);
3413 return ret;
3414 }
3415
3416 static HRESULT WINAPI ImageListImpl_Clone(IImageList *iface, REFIID riid, void **ppv)
3417 {
3418 HIMAGELIST This = (HIMAGELIST) iface;
3419 HIMAGELIST clone;
3420 HRESULT ret = E_FAIL;
3421
3422 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
3423
3424 clone = ImageList_Duplicate(This);
3425
3426 /* Get the interface for the new image list */
3427 if (clone)
3428 {
3429 IImageList *iclone = (IImageList*)clone;
3430
3431 ret = HIMAGELIST_QueryInterface(clone, riid, ppv);
3432 IImageList_Release(iclone);
3433 }
3434
3435 return ret;
3436 }
3437
3438 static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList *iface, int i,
3439 RECT *prc)
3440 {
3441 HIMAGELIST This = (HIMAGELIST) iface;
3442 IMAGEINFO info;
3443
3444 if (!prc)
3445 return E_FAIL;
3446
3447 if (!ImageList_GetImageInfo(This, i, &info))
3448 return E_FAIL;
3449
3450 return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL;
3451 }
3452
3453 static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList *iface, int *cx,
3454 int *cy)
3455 {
3456 HIMAGELIST This = (HIMAGELIST) iface;
3457
3458 return ImageList_GetIconSize(This, cx, cy) ? S_OK : E_INVALIDARG;
3459 }
3460
3461 static HRESULT WINAPI ImageListImpl_SetIconSize(IImageList *iface, int cx,
3462 int cy)
3463 {
3464 return ImageList_SetIconSize((HIMAGELIST) iface, cx, cy) ? S_OK : E_FAIL;
3465 }
3466
3467 static HRESULT WINAPI ImageListImpl_GetImageCount(IImageList *iface, int *pi)
3468 {
3469 *pi = ImageList_GetImageCount((HIMAGELIST) iface);
3470 return S_OK;
3471 }
3472
3473 static HRESULT WINAPI ImageListImpl_SetImageCount(IImageList *iface,
3474 UINT uNewCount)
3475 {
3476 return ImageList_SetImageCount((HIMAGELIST) iface, uNewCount) ? S_OK : E_FAIL;
3477 }
3478
3479 static HRESULT WINAPI ImageListImpl_SetBkColor(IImageList *iface, COLORREF clrBk,
3480 COLORREF *pclr)
3481 {
3482 *pclr = ImageList_SetBkColor((HIMAGELIST) iface, clrBk);
3483 return S_OK;
3484 }
3485
3486 static HRESULT WINAPI ImageListImpl_GetBkColor(IImageList *iface, COLORREF *pclr)
3487 {
3488 *pclr = ImageList_GetBkColor((HIMAGELIST) iface);
3489 return S_OK;
3490 }
3491
3492 static HRESULT WINAPI ImageListImpl_BeginDrag(IImageList *iface, int iTrack,
3493 int dxHotspot, int dyHotspot)
3494 {
3495 return ImageList_BeginDrag((HIMAGELIST) iface, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL;
3496 }
3497
3498 static HRESULT WINAPI ImageListImpl_EndDrag(IImageList *iface)
3499 {
3500 ImageList_EndDrag();
3501 return S_OK;
3502 }
3503
3504 static HRESULT WINAPI ImageListImpl_DragEnter(IImageList *iface, HWND hwndLock,
3505 int x, int y)
3506 {
3507 return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL;
3508 }
3509
3510 static HRESULT WINAPI ImageListImpl_DragLeave(IImageList *iface, HWND hwndLock)
3511 {
3512 return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL;
3513 }
3514
3515 static HRESULT WINAPI ImageListImpl_DragMove(IImageList *iface, int x, int y)
3516 {
3517 return ImageList_DragMove(x, y) ? S_OK : E_FAIL;
3518 }
3519
3520 static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList *iface,
3521 IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
3522 {
3523 IImageList *iml2 = NULL;
3524 HRESULT ret;
3525
3526 if (!punk)
3527 return E_FAIL;
3528
3529 /* TODO: Add test for IID_ImageList2 too */
3530 if (FAILED(IUnknown_QueryInterface(punk, &IID_IImageList,
3531 (void **) &iml2)))
3532 return E_FAIL;
3533
3534 ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot,
3535 dyHotspot);
3536
3537 IImageList_Release(iml2);
3538
3539 return ret ? S_OK : E_FAIL;
3540 }
3541
3542 static HRESULT WINAPI ImageListImpl_DragShowNolock(IImageList *iface, BOOL fShow)
3543 {
3544 return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL;
3545 }
3546
3547 static HRESULT WINAPI ImageListImpl_GetDragImage(IImageList *iface, POINT *ppt,
3548 POINT *pptHotspot, REFIID riid, PVOID *ppv)
3549 {
3550 HRESULT ret = E_FAIL;
3551 HIMAGELIST hNew;
3552
3553 if (!ppv)
3554 return E_FAIL;
3555
3556 hNew = ImageList_GetDragImage(ppt, pptHotspot);
3557
3558 /* Get the interface for the new image list */
3559 if (hNew)
3560 {
3561 IImageList *idrag = (IImageList*)hNew;
3562
3563 ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
3564 IImageList_Release(idrag);
3565 }
3566
3567 return ret;
3568 }
3569
3570 static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i,
3571 DWORD *dwFlags)
3572 {
3573 FIXME("STUB: %p %d %p\n", iface, i, dwFlags);
3574 return E_NOTIMPL;
3575 }
3576
3577 static HRESULT WINAPI ImageListImpl_GetOverlayImage(IImageList *iface, int iOverlay,
3578 int *piIndex)
3579 {
3580 HIMAGELIST This = (HIMAGELIST) iface;
3581 int i;
3582
3583 if ((iOverlay < 0) || (iOverlay > This->cCurImage))
3584 return E_FAIL;
3585
3586 for (i = 0; i < MAX_OVERLAYIMAGE; i++)
3587 {
3588 if (This->nOvlIdx[i] == iOverlay)
3589 {
3590 *piIndex = i + 1;
3591 return S_OK;
3592 }
3593 }
3594
3595 return E_FAIL;
3596 }
3597
3598
3599 static const IImageListVtbl ImageListImpl_Vtbl = {
3600 ImageListImpl_QueryInterface,
3601 ImageListImpl_AddRef,
3602 ImageListImpl_Release,
3603 ImageListImpl_Add,
3604 ImageListImpl_ReplaceIcon,
3605 ImageListImpl_SetOverlayImage,
3606 ImageListImpl_Replace,
3607 ImageListImpl_AddMasked,
3608 ImageListImpl_Draw,
3609 ImageListImpl_Remove,
3610 ImageListImpl_GetIcon,
3611 ImageListImpl_GetImageInfo,
3612 ImageListImpl_Copy,
3613 ImageListImpl_Merge,
3614 ImageListImpl_Clone,
3615 ImageListImpl_GetImageRect,
3616 ImageListImpl_GetIconSize,
3617 ImageListImpl_SetIconSize,
3618 ImageListImpl_GetImageCount,
3619 ImageListImpl_SetImageCount,
3620 ImageListImpl_SetBkColor,
3621 ImageListImpl_GetBkColor,
3622 ImageListImpl_BeginDrag,
3623 ImageListImpl_EndDrag,
3624 ImageListImpl_DragEnter,
3625 ImageListImpl_DragLeave,
3626 ImageListImpl_DragMove,
3627 ImageListImpl_SetDragCursorImage,
3628 ImageListImpl_DragShowNolock,
3629 ImageListImpl_GetDragImage,
3630 ImageListImpl_GetItemFlags,
3631 ImageListImpl_GetOverlayImage
3632 };
3633
3634 static BOOL is_valid(HIMAGELIST himl)
3635 {
3636 BOOL valid;
3637 __TRY
3638 {
3639 valid = himl && himl->lpVtbl == &ImageListImpl_Vtbl;
3640 }
3641 __EXCEPT_PAGE_FAULT
3642 {
3643 valid = FALSE;
3644 }
3645 __ENDTRY
3646 return valid;
3647 }
3648
3649 /*************************************************************************
3650 * HIMAGELIST_QueryInterface [COMCTL32.@]
3651 *
3652 * Returns a pointer to an IImageList or IImageList2 object for the given
3653 * HIMAGELIST.
3654 *
3655 * PARAMS
3656 * himl [I] Image list handle.
3657 * riid [I] Identifier of the requested interface.
3658 * ppv [O] Returns the address of the pointer requested, or NULL.
3659 *
3660 * RETURNS
3661 * Success: S_OK.
3662 * Failure: Error value.
3663 */
3664 HRESULT WINAPI
3665 HIMAGELIST_QueryInterface (HIMAGELIST himl, REFIID riid, void **ppv)
3666 {
3667 TRACE("(%p,%s,%p)\n", himl, debugstr_guid(riid), ppv);
3668 return IImageList_QueryInterface((IImageList *) himl, riid, ppv);
3669 }
3670
3671 static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv)
3672 {
3673 HIMAGELIST This;
3674 HRESULT ret;
3675
3676 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
3677
3678 *ppv = NULL;
3679
3680 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
3681
3682 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct _IMAGELIST));
3683 if (!This) return E_OUTOFMEMORY;
3684
3685 This->lpVtbl = &ImageListImpl_Vtbl;
3686 This->ref = 1;
3687
3688 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
3689 IUnknown_Release((IUnknown*)This);
3690
3691 return ret;
3692 }