2 * ImageList implementation
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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * This code was audited for completeness against the documented features
27 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 * Unless otherwise noted, we believe this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
36 * - Thread-safe locking
53 #include "imagelist.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(imagelist
);
59 #define MAX_OVERLAYIMAGE 15
61 /* internal image list data used for Drag & Drop operations */
66 /* position of the drag image relative to the window */
69 /* offset of the hotspot relative to the origin of the image */
72 /* is the drag image visible */
74 /* saved background */
78 static INTERNALDRAG InternalDrag
= { 0, 0, 0, 0, 0, 0, FALSE
, 0 };
80 static HBITMAP
ImageList_CreateImage(HDC hdc
, HIMAGELIST himl
, UINT count
, UINT height
);
82 static inline BOOL
is_valid(HIMAGELIST himl
)
84 return himl
&& himl
->magic
== IMAGELIST_MAGIC
;
87 static inline void imagelist_point_from_index( HIMAGELIST himl
, UINT index
, LPPOINT pt
)
89 pt
->x
= index
* himl
->cx
;
93 static inline void imagelist_get_bitmap_size( HIMAGELIST himl
, UINT count
, UINT cy
, SIZE
*sz
)
95 sz
->cx
= count
* himl
->cx
;
99 static inline void imagelist_copy_images( HIMAGELIST himl
, HDC hdcSrc
, HDC hdcDest
,
100 UINT src
, UINT count
, UINT dest
)
105 imagelist_point_from_index( himl
, src
, &ptSrc
);
106 imagelist_point_from_index( himl
, dest
, &ptDest
);
107 imagelist_get_bitmap_size( himl
, count
, himl
->cy
, &sz
);
108 BitBlt (hdcDest
, ptSrc
.x
, ptSrc
.y
, sz
.cx
, sz
.cy
, hdcSrc
, ptDest
.x
, ptDest
.y
, SRCCOPY
);
111 /*************************************************************************
112 * IMAGELIST_InternalExpandBitmaps [Internal]
114 * Expands the bitmaps of an image list by the given number of images.
117 * himl [I] handle to image list
118 * nImageCount [I] number of images to add
124 * This function CANNOT be used to reduce the number of images.
127 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl
, INT nImageCount
, INT cx
, INT cy
)
130 HBITMAP hbmNewBitmap
, hbmNull
;
134 if ((himl
->cCurImage
+ nImageCount
<= himl
->cMaxImage
)
138 if (cy
== 0) cy
= himl
->cy
;
139 nNewCount
= himl
->cCurImage
+ nImageCount
+ himl
->cGrow
;
141 imagelist_get_bitmap_size(himl
, nNewCount
, cy
, &sz
);
143 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl
, sz
.cx
, cy
, nNewCount
);
144 hdcBitmap
= CreateCompatibleDC (0);
146 hbmNewBitmap
= ImageList_CreateImage(hdcBitmap
, himl
, nNewCount
, cy
);
148 if (hbmNewBitmap
== 0)
149 ERR("creating new image bitmap (x=%d y=%d)!\n", sz
.cx
, cy
);
153 hbmNull
= SelectObject (hdcBitmap
, hbmNewBitmap
);
154 BitBlt (hdcBitmap
, 0, 0, sz
.cx
, sz
.cy
,
155 himl
->hdcImage
, 0, 0, SRCCOPY
);
156 SelectObject (hdcBitmap
, hbmNull
);
158 SelectObject (himl
->hdcImage
, hbmNewBitmap
);
159 DeleteObject (himl
->hbmImage
);
160 himl
->hbmImage
= hbmNewBitmap
;
162 if (himl
->flags
& ILC_MASK
)
164 hbmNewBitmap
= CreateBitmap (sz
.cx
, sz
.cy
, 1, 1, NULL
);
166 if (hbmNewBitmap
== 0)
167 ERR("creating new mask bitmap!\n");
171 hbmNull
= SelectObject (hdcBitmap
, hbmNewBitmap
);
172 BitBlt (hdcBitmap
, 0, 0, sz
.cx
, sz
.cy
,
173 himl
->hdcMask
, 0, 0, SRCCOPY
);
174 SelectObject (hdcBitmap
, hbmNull
);
176 SelectObject (himl
->hdcMask
, hbmNewBitmap
);
177 DeleteObject (himl
->hbmMask
);
178 himl
->hbmMask
= hbmNewBitmap
;
181 himl
->cMaxImage
= nNewCount
;
183 DeleteDC (hdcBitmap
);
187 /*************************************************************************
188 * ImageList_Add [COMCTL32.@]
190 * Add an image or images to an image list.
193 * himl [I] handle to image list
194 * hbmImage [I] handle to image bitmap
195 * hbmMask [I] handle to mask bitmap
198 * Success: Index of the first new image.
203 ImageList_Add (HIMAGELIST himl
, HBITMAP hbmImage
, HBITMAP hbmMask
)
205 HDC hdcBitmap
, hdcTemp
;
206 INT nFirstIndex
, nImageCount
, i
;
208 HBITMAP hOldBitmap
, hOldBitmapTemp
;
211 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl
, hbmImage
, hbmMask
);
215 if (!GetObjectW(hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
))
218 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
220 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
222 hdcBitmap
= CreateCompatibleDC(0);
224 hOldBitmap
= SelectObject(hdcBitmap
, hbmImage
);
226 for (i
=0; i
<nImageCount
; i
++)
228 imagelist_point_from_index( himl
, himl
->cCurImage
+ i
, &pt
);
230 /* Copy result to the imagelist
232 BitBlt( himl
->hdcImage
, pt
.x
, pt
.y
, himl
->cx
, bmp
.bmHeight
,
233 hdcBitmap
, i
*himl
->cx
, 0, SRCCOPY
);
238 hdcTemp
= CreateCompatibleDC(0);
239 hOldBitmapTemp
= SelectObject(hdcTemp
, hbmMask
);
241 BitBlt( himl
->hdcMask
, pt
.x
, pt
.y
, himl
->cx
, bmp
.bmHeight
,
242 hdcTemp
, i
*himl
->cx
, 0, SRCCOPY
);
244 SelectObject(hdcTemp
, hOldBitmapTemp
);
247 /* Remove the background from the image
249 BitBlt( himl
->hdcImage
, pt
.x
, pt
.y
, himl
->cx
, bmp
.bmHeight
,
250 himl
->hdcMask
, pt
.x
, pt
.y
, 0x220326 ); /* NOTSRCAND */
253 SelectObject(hdcBitmap
, hOldBitmap
);
256 nFirstIndex
= himl
->cCurImage
;
257 himl
->cCurImage
+= nImageCount
;
263 /*************************************************************************
264 * ImageList_AddIcon [COMCTL32.@]
266 * Adds an icon to an image list.
269 * himl [I] handle to image list
270 * hIcon [I] handle to icon
273 * Success: index of the new image
276 #undef ImageList_AddIcon
277 INT WINAPI
ImageList_AddIcon (HIMAGELIST himl
, HICON hIcon
)
279 return ImageList_ReplaceIcon (himl
, -1, hIcon
);
283 /*************************************************************************
284 * ImageList_AddMasked [COMCTL32.@]
286 * Adds an image or images to an image list and creates a mask from the
287 * specified bitmap using the mask color.
290 * himl [I] handle to image list.
291 * hBitmap [I] handle to bitmap
292 * clrMask [I] mask color.
295 * Success: Index of the first new image.
300 ImageList_AddMasked (HIMAGELIST himl
, HBITMAP hBitmap
, COLORREF clrMask
)
302 HDC hdcMask
, hdcBitmap
;
303 INT nIndex
, nImageCount
;
306 HBITMAP hMaskBitmap
=0;
310 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl
, hBitmap
, clrMask
);
314 if (!GetObjectW(hBitmap
, sizeof(BITMAP
), &bmp
))
318 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
322 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
324 nIndex
= himl
->cCurImage
;
325 himl
->cCurImage
+= nImageCount
;
327 hdcBitmap
= CreateCompatibleDC(0);
330 hOldBitmap
= SelectObject(hdcBitmap
, hBitmap
);
333 hdcMask
= himl
->hdcMask
;
334 imagelist_point_from_index( himl
, nIndex
, &pt
);
339 Create a temp Mask so we can remove the background of
340 the Image (Windows does this even if there is no mask)
342 hdcMask
= CreateCompatibleDC(0);
343 hMaskBitmap
= CreateBitmap(bmp
.bmWidth
, bmp
.bmHeight
, 1, 1, NULL
);
344 SelectObject(hdcMask
, hMaskBitmap
);
345 imagelist_point_from_index( himl
, 0, &pt
);
347 /* create monochrome image to the mask bitmap */
348 bkColor
= (clrMask
!= CLR_DEFAULT
) ? clrMask
:
349 GetPixel (hdcBitmap
, 0, 0);
350 SetBkColor (hdcBitmap
, bkColor
);
352 pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
356 SetBkColor(hdcBitmap
, RGB(255,255,255));
357 /*Remove the background from the image
360 WINDOWS BUG ALERT!!!!!!
361 The statement below should not be done in common practice
362 but this is how ImageList_AddMasked works in Windows.
363 It overwrites the original bitmap passed, this was discovered
364 by using the same bitmap to iterate the different styles
365 on windows where it failed (BUT ImageList_Add is OK)
366 This is here in case some apps rely on this bug
369 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
372 0x220326); /* NOTSRCAND */
373 /* Copy result to the imagelist
375 imagelist_point_from_index( himl
, nIndex
, &pt
);
376 BitBlt (himl
->hdcImage
,
377 pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
383 SelectObject(hdcBitmap
, hOldBitmap
);
387 DeleteObject(hMaskBitmap
);
395 /*************************************************************************
396 * ImageList_BeginDrag [COMCTL32.@]
398 * Creates a temporary image list that contains one image. It will be used
402 * himlTrack [I] handle to the source image list
403 * iTrack [I] index of the drag image in the source image list
404 * dxHotspot [I] X position of the hot spot of the drag image
405 * dyHotspot [I] Y position of the hot spot of the drag image
413 ImageList_BeginDrag (HIMAGELIST himlTrack
, INT iTrack
,
414 INT dxHotspot
, INT dyHotspot
)
418 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack
, iTrack
,
419 dxHotspot
, dyHotspot
);
421 if (!is_valid(himlTrack
))
424 if (InternalDrag
.himl
)
425 ImageList_EndDrag ();
430 InternalDrag
.himl
= ImageList_Create (cx
, cy
, himlTrack
->flags
, 1, 1);
431 if (InternalDrag
.himl
== NULL
) {
432 WARN("Error creating drag image list!\n");
436 InternalDrag
.dxHotspot
= dxHotspot
;
437 InternalDrag
.dyHotspot
= dyHotspot
;
440 BitBlt (InternalDrag
.himl
->hdcImage
, 0, 0, cx
, cy
, himlTrack
->hdcImage
, iTrack
* cx
, 0, SRCCOPY
);
443 BitBlt (InternalDrag
.himl
->hdcMask
, 0, 0, cx
, cy
, himlTrack
->hdcMask
, iTrack
* cx
, 0, SRCCOPY
);
445 InternalDrag
.himl
->cCurImage
= 1;
451 /*************************************************************************
452 * ImageList_Copy [COMCTL32.@]
454 * Copies an image of the source image list to an image of the
455 * destination image list. Images can be copied or swapped.
458 * himlDst [I] handle to the destination image list
459 * iDst [I] destination image index.
460 * himlSrc [I] handle to the source image list
461 * iSrc [I] source image index
462 * uFlags [I] flags for the copy operation
469 * Copying from one image list to another is possible. The original
470 * implementation just copies or swaps within one image list.
471 * Could this feature become a bug??? ;-)
475 ImageList_Copy (HIMAGELIST himlDst
, INT iDst
, HIMAGELIST himlSrc
,
476 INT iSrc
, UINT uFlags
)
480 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst
, iDst
, himlSrc
, iSrc
);
482 if (!is_valid(himlSrc
) || !is_valid(himlDst
))
484 if ((iDst
< 0) || (iDst
>= himlDst
->cCurImage
))
486 if ((iSrc
< 0) || (iSrc
>= himlSrc
->cCurImage
))
489 imagelist_point_from_index( himlDst
, iDst
, &ptDst
);
490 imagelist_point_from_index( himlSrc
, iSrc
, &ptSrc
);
492 if (uFlags
& ILCF_SWAP
) {
495 HBITMAP hbmTempImage
, hbmTempMask
;
497 hdcBmp
= CreateCompatibleDC (0);
499 /* create temporary bitmaps */
500 hbmTempImage
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
501 himlSrc
->uBitsPixel
, NULL
);
502 hbmTempMask
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
505 /* copy (and stretch) destination to temporary bitmaps.(save) */
507 SelectObject (hdcBmp
, hbmTempImage
);
508 StretchBlt (hdcBmp
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
509 himlDst
->hdcImage
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
512 SelectObject (hdcBmp
, hbmTempMask
);
513 StretchBlt (hdcBmp
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
514 himlDst
->hdcMask
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
517 /* copy (and stretch) source to destination */
519 StretchBlt (himlDst
->hdcImage
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
520 himlSrc
->hdcImage
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
523 StretchBlt (himlDst
->hdcMask
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
524 himlSrc
->hdcMask
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
527 /* copy (without stretching) temporary bitmaps to source (restore) */
529 BitBlt (himlSrc
->hdcMask
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
530 hdcBmp
, 0, 0, SRCCOPY
);
533 BitBlt (himlSrc
->hdcImage
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
534 hdcBmp
, 0, 0, SRCCOPY
);
535 /* delete temporary bitmaps */
536 DeleteObject (hbmTempMask
);
537 DeleteObject (hbmTempImage
);
542 StretchBlt (himlDst
->hdcImage
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
543 himlSrc
->hdcImage
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
547 StretchBlt (himlDst
->hdcMask
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
548 himlSrc
->hdcMask
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
556 /*************************************************************************
557 * ImageList_Create [COMCTL32.@]
559 * Creates a new image list.
562 * cx [I] image height
564 * flags [I] creation flags
565 * cInitial [I] initial number of images in the image list
566 * cGrow [I] number of images by which image list grows
569 * Success: Handle to the created image list
573 ImageList_Create (INT cx
, INT cy
, UINT flags
,
574 INT cInitial
, INT cGrow
)
579 UINT ilc
= (flags
& 0xFE);
580 static const WORD aBitBlend25
[] =
581 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
583 static const WORD aBitBlend50
[] =
584 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
586 TRACE("(%d %d 0x%x %d %d)\n", cx
, cy
, flags
, cInitial
, cGrow
);
588 himl
= (HIMAGELIST
)Alloc (sizeof(struct _IMAGELIST
));
592 cGrow
= (cGrow
< 4) ? 4 : (cGrow
+ 3) & ~3;
594 himl
->magic
= IMAGELIST_MAGIC
;
598 himl
->cMaxImage
= cInitial
+ cGrow
;
599 himl
->cInitial
= cInitial
;
601 himl
->clrFg
= CLR_DEFAULT
;
602 himl
->clrBk
= CLR_NONE
;
604 /* initialize overlay mask indices */
605 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
606 himl
->nOvlIdx
[nCount
] = -1;
608 /* Create Image & Mask DCs */
609 himl
->hdcImage
= CreateCompatibleDC (0);
612 if (himl
->flags
& ILC_MASK
){
613 himl
->hdcMask
= CreateCompatibleDC(0);
618 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
619 if (ilc
== ILC_COLOR
)
622 if (ilc
>= ILC_COLOR4
&& ilc
<= ILC_COLOR32
)
623 himl
->uBitsPixel
= ilc
;
625 himl
->uBitsPixel
= (UINT
)GetDeviceCaps (himl
->hdcImage
, BITSPIXEL
);
627 if (himl
->cMaxImage
> 0) {
628 himl
->hbmImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
, cy
);
629 SelectObject(himl
->hdcImage
, himl
->hbmImage
);
633 if ((himl
->cMaxImage
> 0) && (himl
->flags
& ILC_MASK
)) {
636 imagelist_get_bitmap_size(himl
, himl
->cMaxImage
, himl
->cy
, &sz
);
637 himl
->hbmMask
= CreateBitmap (sz
.cx
, sz
.cy
, 1, 1, NULL
);
638 if (himl
->hbmMask
== 0) {
639 ERR("Error creating mask bitmap!\n");
642 SelectObject(himl
->hdcMask
, himl
->hbmMask
);
647 /* create blending brushes */
648 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend25
);
649 himl
->hbrBlend25
= CreatePatternBrush (hbmTemp
);
650 DeleteObject (hbmTemp
);
652 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend50
);
653 himl
->hbrBlend50
= CreatePatternBrush (hbmTemp
);
654 DeleteObject (hbmTemp
);
656 TRACE("created imagelist %p\n", himl
);
660 if (himl
) ImageList_Destroy(himl
);
665 /*************************************************************************
666 * ImageList_Destroy [COMCTL32.@]
668 * Destroys an image list.
671 * himl [I] handle to image list
679 ImageList_Destroy (HIMAGELIST himl
)
684 /* delete image bitmaps */
686 DeleteObject (himl
->hbmImage
);
688 DeleteObject (himl
->hbmMask
);
690 /* delete image & mask DCs */
692 DeleteDC(himl
->hdcImage
);
694 DeleteDC(himl
->hdcMask
);
696 /* delete blending brushes */
697 if (himl
->hbrBlend25
)
698 DeleteObject (himl
->hbrBlend25
);
699 if (himl
->hbrBlend50
)
700 DeleteObject (himl
->hbrBlend50
);
702 ZeroMemory(himl
, sizeof(*himl
));
709 /*************************************************************************
710 * ImageList_DragEnter [COMCTL32.@]
712 * Locks window update and displays the drag image at the given position.
715 * hwndLock [I] handle of the window that owns the drag image.
716 * x [I] X position of the drag image.
717 * y [I] Y position of the drag image.
724 * The position of the drag image is relative to the window, not
729 ImageList_DragEnter (HWND hwndLock
, INT x
, INT y
)
731 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock
, x
, y
);
733 if (!is_valid(InternalDrag
.himl
))
737 InternalDrag
.hwnd
= hwndLock
;
739 InternalDrag
.hwnd
= GetDesktopWindow ();
744 /* draw the drag image and save the background */
745 if (!ImageList_DragShowNolock(TRUE
)) {
753 /*************************************************************************
754 * ImageList_DragLeave [COMCTL32.@]
756 * Unlocks window update and hides the drag image.
759 * hwndLock [I] handle of the window that owns the drag image.
767 ImageList_DragLeave (HWND hwndLock
)
769 /* As we don't save drag info in the window this can lead to problems if
770 an app does not supply the same window as DragEnter */
772 InternalDrag.hwnd = hwndLock;
774 InternalDrag.hwnd = GetDesktopWindow (); */
776 hwndLock
= GetDesktopWindow();
777 if(InternalDrag
.hwnd
!= hwndLock
)
778 FIXME("DragLeave hWnd != DragEnter hWnd\n");
780 ImageList_DragShowNolock (FALSE
);
786 /*************************************************************************
787 * ImageList_InternalDragDraw [Internal]
789 * Draws the drag image.
792 * hdc [I] device context to draw into.
793 * x [I] X position of the drag image.
794 * y [I] Y position of the drag image.
801 * The position of the drag image is relative to the window, not
807 ImageList_InternalDragDraw (HDC hdc
, INT x
, INT y
)
809 IMAGELISTDRAWPARAMS imldp
;
811 ZeroMemory (&imldp
, sizeof(imldp
));
812 imldp
.cbSize
= sizeof(imldp
);
813 imldp
.himl
= InternalDrag
.himl
;
818 imldp
.rgbBk
= CLR_DEFAULT
;
819 imldp
.rgbFg
= CLR_DEFAULT
;
820 imldp
.fStyle
= ILD_NORMAL
;
821 imldp
.fState
= ILS_ALPHA
;
824 /* FIXME: instead of using the alpha blending, we should
825 * create a 50% mask, and draw it semitransparantly that way */
826 ImageList_DrawIndirect (&imldp
);
829 /*************************************************************************
830 * ImageList_DragMove [COMCTL32.@]
832 * Moves the drag image.
835 * x [I] X position of the drag image.
836 * y [I] Y position of the drag image.
843 * The position of the drag image is relative to the window, not
847 * The drag image should be drawn semitransparent.
851 ImageList_DragMove (INT x
, INT y
)
853 TRACE("(x=%d y=%d)\n", x
, y
);
855 if (!is_valid(InternalDrag
.himl
))
858 /* draw/update the drag image */
859 if (InternalDrag
.bShow
) {
863 HBITMAP hbmOffScreen
;
864 INT origNewX
, origNewY
;
865 INT origOldX
, origOldY
;
866 INT origRegX
, origRegY
;
867 INT sizeRegX
, sizeRegY
;
870 /* calculate the update region */
871 origNewX
= x
- InternalDrag
.dxHotspot
;
872 origNewY
= y
- InternalDrag
.dyHotspot
;
873 origOldX
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
874 origOldY
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
875 origRegX
= min(origNewX
, origOldX
);
876 origRegY
= min(origNewY
, origOldY
);
877 sizeRegX
= InternalDrag
.himl
->cx
+ abs(x
- InternalDrag
.x
);
878 sizeRegY
= InternalDrag
.himl
->cy
+ abs(y
- InternalDrag
.y
);
880 hdcDrag
= GetDCEx(InternalDrag
.hwnd
, 0,
881 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
882 hdcOffScreen
= CreateCompatibleDC(hdcDrag
);
883 hdcBg
= CreateCompatibleDC(hdcDrag
);
885 hbmOffScreen
= CreateCompatibleBitmap(hdcDrag
, sizeRegX
, sizeRegY
);
886 SelectObject(hdcOffScreen
, hbmOffScreen
);
887 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
889 /* get the actual background of the update region */
890 BitBlt(hdcOffScreen
, 0, 0, sizeRegX
, sizeRegY
, hdcDrag
,
891 origRegX
, origRegY
, SRCCOPY
);
892 /* erase the old image */
893 BitBlt(hdcOffScreen
, origOldX
- origRegX
, origOldY
- origRegY
,
894 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
, hdcBg
, 0, 0,
896 /* save the background */
897 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
898 hdcOffScreen
, origNewX
- origRegX
, origNewY
- origRegY
, SRCCOPY
);
900 ImageList_InternalDragDraw(hdcOffScreen
, origNewX
- origRegX
,
901 origNewY
- origRegY
);
902 /* draw the update region to the screen */
903 BitBlt(hdcDrag
, origRegX
, origRegY
, sizeRegX
, sizeRegY
,
904 hdcOffScreen
, 0, 0, SRCCOPY
);
907 DeleteDC(hdcOffScreen
);
908 DeleteObject(hbmOffScreen
);
909 ReleaseDC(InternalDrag
.hwnd
, hdcDrag
);
912 /* update the image position */
920 /*************************************************************************
921 * ImageList_DragShowNolock [COMCTL32.@]
923 * Shows or hides the drag image.
926 * bShow [I] TRUE shows the drag image, FALSE hides it.
933 * The drag image should be drawn semitransparent.
937 ImageList_DragShowNolock (BOOL bShow
)
943 if (!is_valid(InternalDrag
.himl
))
946 TRACE("bShow=0x%X!\n", bShow
);
948 /* DragImage is already visible/hidden */
949 if ((InternalDrag
.bShow
&& bShow
) || (!InternalDrag
.bShow
&& !bShow
)) {
953 /* position of the origin of the DragImage */
954 x
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
955 y
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
957 hdcDrag
= GetDCEx (InternalDrag
.hwnd
, 0,
958 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
963 hdcBg
= CreateCompatibleDC(hdcDrag
);
964 if (!InternalDrag
.hbmBg
) {
965 InternalDrag
.hbmBg
= CreateCompatibleBitmap(hdcDrag
,
966 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
);
968 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
971 /* save the background */
972 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
973 hdcDrag
, x
, y
, SRCCOPY
);
975 ImageList_InternalDragDraw(hdcDrag
, x
, y
);
978 BitBlt(hdcDrag
, x
, y
, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
979 hdcBg
, 0, 0, SRCCOPY
);
982 InternalDrag
.bShow
= !InternalDrag
.bShow
;
985 ReleaseDC (InternalDrag
.hwnd
, hdcDrag
);
990 /*************************************************************************
991 * ImageList_Draw [COMCTL32.@]
996 * himl [I] handle to image list
998 * hdc [I] handle to device context
1001 * fStyle [I] drawing flags
1012 ImageList_Draw (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
, UINT fStyle
)
1014 return ImageList_DrawEx (himl
, i
, hdc
, x
, y
, 0, 0,
1015 CLR_DEFAULT
, CLR_DEFAULT
, fStyle
);
1019 /*************************************************************************
1020 * ImageList_DrawEx [COMCTL32.@]
1022 * Draws an image and allows to use extended drawing features.
1025 * himl [I] handle to image list
1027 * hdc [I] handle to device context
1032 * rgbBk [I] background color
1033 * rgbFg [I] foreground color
1034 * fStyle [I] drawing flags
1041 * Calls ImageList_DrawIndirect.
1044 * ImageList_DrawIndirect.
1048 ImageList_DrawEx (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
,
1049 INT dx
, INT dy
, COLORREF rgbBk
, COLORREF rgbFg
,
1052 IMAGELISTDRAWPARAMS imldp
;
1054 ZeroMemory (&imldp
, sizeof(imldp
));
1055 imldp
.cbSize
= sizeof(imldp
);
1063 imldp
.rgbBk
= rgbBk
;
1064 imldp
.rgbFg
= rgbFg
;
1065 imldp
.fStyle
= fStyle
;
1067 return ImageList_DrawIndirect (&imldp
);
1071 /*************************************************************************
1072 * ImageList_DrawIndirect [COMCTL32.@]
1074 * Draws an image using various parameters specified in pimldp.
1077 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1085 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS
*pimldp
)
1087 INT cx
, cy
, nOvlIdx
;
1088 DWORD fState
, dwRop
;
1090 COLORREF oldImageBk
, oldImageFg
;
1091 HDC hImageDC
, hImageListDC
, hMaskListDC
;
1092 HBITMAP hImageBmp
, hOldImageBmp
, hBlendMaskBmp
;
1093 BOOL bIsTransparent
, bBlend
, bResult
= FALSE
, bMask
;
1097 if (!pimldp
|| !(himl
= pimldp
->himl
)) return FALSE
;
1098 if (!is_valid(himl
)) return FALSE
;
1099 if ((pimldp
->i
< 0) || (pimldp
->i
>= himl
->cCurImage
)) return FALSE
;
1101 imagelist_point_from_index( himl
, pimldp
->i
, &pt
);
1102 pt
.x
+= pimldp
->xBitmap
;
1103 pt
.y
+= pimldp
->yBitmap
;
1105 fState
= pimldp
->cbSize
< sizeof(IMAGELISTDRAWPARAMS
) ? ILS_NORMAL
: pimldp
->fState
;
1106 fStyle
= pimldp
->fStyle
& ~ILD_OVERLAYMASK
;
1107 cx
= (pimldp
->cx
== 0) ? himl
->cx
: pimldp
->cx
;
1108 cy
= (pimldp
->cy
== 0) ? himl
->cy
: pimldp
->cy
;
1110 bIsTransparent
= (fStyle
& ILD_TRANSPARENT
);
1111 if( pimldp
->rgbBk
== CLR_NONE
)
1112 bIsTransparent
= TRUE
;
1113 if( ( pimldp
->rgbBk
== CLR_DEFAULT
) && ( himl
->clrBk
== CLR_NONE
) )
1114 bIsTransparent
= TRUE
;
1115 bMask
= (himl
->flags
& ILC_MASK
) && (fStyle
& ILD_MASK
) ;
1116 bBlend
= (fStyle
& (ILD_BLEND25
| ILD_BLEND50
) ) && !bMask
;
1118 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1119 himl
, himl
->hbmMask
, pimldp
->i
, pimldp
->x
, pimldp
->y
, cx
, cy
);
1121 /* we will use these DCs to access the images and masks in the ImageList */
1122 hImageListDC
= himl
->hdcImage
;
1123 hMaskListDC
= himl
->hdcMask
;
1125 /* these will accumulate the image and mask for the image we're drawing */
1126 hImageDC
= CreateCompatibleDC( pimldp
->hdcDst
);
1127 hImageBmp
= CreateCompatibleBitmap( pimldp
->hdcDst
, cx
, cy
);
1128 hBlendMaskBmp
= bBlend
? CreateBitmap(cx
, cy
, 1, 1, NULL
) : 0;
1130 /* Create a compatible DC. */
1131 if (!hImageListDC
|| !hImageDC
|| !hImageBmp
||
1132 (bBlend
&& !hBlendMaskBmp
) || (himl
->hbmMask
&& !hMaskListDC
))
1135 hOldImageBmp
= SelectObject(hImageDC
, hImageBmp
);
1138 * To obtain a transparent look, background color should be set
1139 * to white and foreground color to black when blting the
1142 oldImageFg
= SetTextColor( hImageDC
, RGB( 0, 0, 0 ) );
1143 oldImageBk
= SetBkColor( hImageDC
, RGB( 0xff, 0xff, 0xff ) );
1146 * Draw the initial image
1149 if (himl
->hbmMask
) {
1151 hOldBrush
= SelectObject (hImageDC
, CreateSolidBrush (GetTextColor(pimldp
->hdcDst
)));
1152 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1153 BitBlt(hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, SRCPAINT
);
1154 DeleteObject (SelectObject (hImageDC
, hOldBrush
));
1155 if( bIsTransparent
)
1157 BitBlt ( pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hImageDC
, 0, 0, SRCAND
);
1162 HBRUSH hOldBrush
= SelectObject (hImageDC
, GetStockObject(BLACK_BRUSH
));
1163 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1164 SelectObject(hImageDC
, hOldBrush
);
1167 /* blend the image with the needed solid background */
1168 COLORREF colour
= RGB(0,0,0);
1171 if( !bIsTransparent
)
1173 colour
= pimldp
->rgbBk
;
1174 if( colour
== CLR_DEFAULT
)
1175 colour
= himl
->clrBk
;
1176 if( colour
== CLR_NONE
)
1177 colour
= GetBkColor(pimldp
->hdcDst
);
1180 hOldBrush
= SelectObject (hImageDC
, CreateSolidBrush (colour
));
1181 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1182 BitBlt( hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, SRCAND
);
1183 BitBlt( hImageDC
, 0, 0, cx
, cy
, hImageListDC
, pt
.x
, pt
.y
, SRCPAINT
);
1184 DeleteObject (SelectObject (hImageDC
, hOldBrush
));
1187 /* Time for blending, if required */
1189 HBRUSH hBlendBrush
, hOldBrush
;
1190 COLORREF clrBlend
= pimldp
->rgbFg
;
1191 HDC hBlendMaskDC
= hImageListDC
;
1194 /* Create the blend Mask */
1195 hOldBitmap
= SelectObject(hBlendMaskDC
, hBlendMaskBmp
);
1196 hBlendBrush
= fStyle
& ILD_BLEND50
? himl
->hbrBlend50
: himl
->hbrBlend25
;
1197 hOldBrush
= (HBRUSH
) SelectObject(hBlendMaskDC
, hBlendBrush
);
1198 PatBlt(hBlendMaskDC
, 0, 0, cx
, cy
, PATCOPY
);
1199 SelectObject(hBlendMaskDC
, hOldBrush
);
1201 /* Modify the blend mask if an Image Mask exist */
1203 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, 0x220326); /* NOTSRCAND */
1204 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, NOTSRCCOPY
);
1207 /* now apply blend to the current image given the BlendMask */
1208 if (clrBlend
== CLR_DEFAULT
) clrBlend
= GetSysColor (COLOR_HIGHLIGHT
);
1209 else if (clrBlend
== CLR_NONE
) clrBlend
= GetTextColor (pimldp
->hdcDst
);
1210 hOldBrush
= (HBRUSH
) SelectObject (hImageDC
, CreateSolidBrush(clrBlend
));
1211 BitBlt (hImageDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, 0xB8074A); /* PSDPxax */
1212 DeleteObject(SelectObject(hImageDC
, hOldBrush
));
1213 SelectObject(hBlendMaskDC
, hOldBitmap
);
1216 /* Now do the overlay image, if any */
1217 nOvlIdx
= (pimldp
->fStyle
& ILD_OVERLAYMASK
) >> 8;
1218 if ( (nOvlIdx
>= 1) && (nOvlIdx
<= MAX_OVERLAYIMAGE
)) {
1219 nOvlIdx
= himl
->nOvlIdx
[nOvlIdx
- 1];
1220 if ((nOvlIdx
>= 0) && (nOvlIdx
< himl
->cCurImage
)) {
1222 imagelist_point_from_index( himl
, nOvlIdx
, &ptOvl
);
1223 ptOvl
.x
+= pimldp
->xBitmap
;
1224 if (himl
->hbmMask
&& !(fStyle
& ILD_IMAGE
))
1225 BitBlt (hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, ptOvl
.x
, ptOvl
.y
, SRCAND
);
1226 BitBlt (hImageDC
, 0, 0, cx
, cy
, hImageListDC
, ptOvl
.x
, ptOvl
.y
, SRCPAINT
);
1230 if (fState
& ILS_SATURATE
) FIXME("ILS_SATURATE: unimplemented!\n");
1231 if (fState
& ILS_GLOW
) FIXME("ILS_GLOW: unimplemented!\n");
1232 if (fState
& ILS_SHADOW
) FIXME("ILS_SHADOW: unimplemented!\n");
1233 if (fState
& ILS_ALPHA
) FIXME("ILS_ALPHA: unimplemented!\n");
1235 if (fStyle
& ILD_PRESERVEALPHA
) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1236 if (fStyle
& ILD_SCALE
) FIXME("ILD_SCALE: unimplemented!\n");
1237 if (fStyle
& ILD_DPISCALE
) FIXME("ILD_DPISCALE: unimplemented!\n");
1239 /* now copy the image to the screen */
1241 if (himl
->hbmMask
&& bIsTransparent
) {
1242 COLORREF oldDstFg
= SetTextColor(pimldp
->hdcDst
, RGB( 0, 0, 0 ) );
1243 COLORREF oldDstBk
= SetBkColor(pimldp
->hdcDst
, RGB( 0xff, 0xff, 0xff ));
1244 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, SRCAND
);
1245 SetBkColor(pimldp
->hdcDst
, oldDstBk
);
1246 SetTextColor(pimldp
->hdcDst
, oldDstFg
);
1249 if (fStyle
& ILD_ROP
) dwRop
= pimldp
->dwRop
;
1250 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hImageDC
, 0, 0, dwRop
);
1254 /* cleanup the mess */
1255 SetBkColor(hImageDC
, oldImageBk
);
1256 SetTextColor(hImageDC
, oldImageFg
);
1257 SelectObject(hImageDC
, hOldImageBmp
);
1259 DeleteObject(hBlendMaskBmp
);
1260 DeleteObject(hImageBmp
);
1267 /*************************************************************************
1268 * ImageList_Duplicate [COMCTL32.@]
1270 * Duplicates an image list.
1273 * himlSrc [I] source image list handle
1276 * Success: Handle of duplicated image list.
1281 ImageList_Duplicate (HIMAGELIST himlSrc
)
1285 if (!is_valid(himlSrc
)) {
1286 ERR("Invalid image list handle!\n");
1290 himlDst
= ImageList_Create (himlSrc
->cx
, himlSrc
->cy
, himlSrc
->flags
,
1291 himlSrc
->cInitial
, himlSrc
->cGrow
);
1297 imagelist_get_bitmap_size(himlSrc
, himlSrc
->cCurImage
, himlSrc
->cy
, &sz
);
1298 BitBlt (himlDst
->hdcImage
, 0, 0, sz
.cx
, sz
.cy
,
1299 himlSrc
->hdcImage
, 0, 0, SRCCOPY
);
1301 if (himlDst
->hbmMask
)
1302 BitBlt (himlDst
->hdcMask
, 0, 0, sz
.cx
, sz
.cy
,
1303 himlSrc
->hdcMask
, 0, 0, SRCCOPY
);
1305 himlDst
->cCurImage
= himlSrc
->cCurImage
;
1306 himlDst
->cMaxImage
= himlSrc
->cMaxImage
;
1312 /*************************************************************************
1313 * ImageList_EndDrag [COMCTL32.@]
1315 * Finishes a drag operation.
1326 ImageList_EndDrag (void)
1328 /* cleanup the InternalDrag struct */
1329 InternalDrag
.hwnd
= 0;
1330 ImageList_Destroy (InternalDrag
.himl
);
1331 InternalDrag
.himl
= 0;
1334 InternalDrag
.dxHotspot
= 0;
1335 InternalDrag
.dyHotspot
= 0;
1336 InternalDrag
.bShow
= FALSE
;
1337 DeleteObject(InternalDrag
.hbmBg
);
1338 InternalDrag
.hbmBg
= 0;
1342 /*************************************************************************
1343 * ImageList_GetBkColor [COMCTL32.@]
1345 * Returns the background color of an image list.
1348 * himl [I] Image list handle.
1351 * Success: background color
1356 ImageList_GetBkColor (HIMAGELIST himl
)
1358 return himl
? himl
->clrBk
: CLR_NONE
;
1362 /*************************************************************************
1363 * ImageList_GetDragImage [COMCTL32.@]
1365 * Returns the handle to the internal drag image list.
1368 * ppt [O] Pointer to the drag position. Can be NULL.
1369 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1372 * Success: Handle of the drag image list.
1377 ImageList_GetDragImage (POINT
*ppt
, POINT
*pptHotspot
)
1379 if (is_valid(InternalDrag
.himl
)) {
1381 ppt
->x
= InternalDrag
.x
;
1382 ppt
->y
= InternalDrag
.y
;
1385 pptHotspot
->x
= InternalDrag
.dxHotspot
;
1386 pptHotspot
->y
= InternalDrag
.dyHotspot
;
1388 return (InternalDrag
.himl
);
1395 /*************************************************************************
1396 * ImageList_GetFlags [COMCTL32.@]
1398 * Gets the flags of the specified image list.
1401 * himl [I] Handle to image list
1411 ImageList_GetFlags(HIMAGELIST himl
)
1413 FIXME("(%p):empty stub\n", himl
);
1418 /*************************************************************************
1419 * ImageList_GetIcon [COMCTL32.@]
1421 * Creates an icon from a masked image of an image list.
1424 * himl [I] handle to image list
1426 * flags [I] drawing style flags
1429 * Success: icon handle
1434 ImageList_GetIcon (HIMAGELIST himl
, INT i
, UINT fStyle
)
1438 HBITMAP hOldDstBitmap
;
1442 TRACE("%p %d %d\n", himl
, i
, fStyle
);
1443 if (!is_valid(himl
) || (i
< 0) || (i
>= himl
->cCurImage
)) return NULL
;
1449 /* create colour bitmap */
1451 ii
.hbmColor
= CreateCompatibleBitmap(hdcDst
, himl
->cx
, himl
->cy
);
1452 ReleaseDC(0, hdcDst
);
1454 hdcDst
= CreateCompatibleDC(0);
1456 imagelist_point_from_index( himl
, i
, &pt
);
1459 ii
.hbmMask
= CreateBitmap (himl
->cx
, himl
->cy
, 1, 1, NULL
);
1460 hOldDstBitmap
= SelectObject (hdcDst
, ii
.hbmMask
);
1461 if (himl
->hbmMask
) {
1462 BitBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
,
1463 himl
->hdcMask
, pt
.x
, pt
.y
, SRCCOPY
);
1466 PatBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
, BLACKNESS
);
1469 SelectObject (hdcDst
, ii
.hbmColor
);
1470 BitBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
,
1471 himl
->hdcImage
, pt
.x
, pt
.y
, SRCCOPY
);
1474 * CreateIconIndirect requires us to deselect the bitmaps from
1475 * the DCs before calling
1477 SelectObject(hdcDst
, hOldDstBitmap
);
1479 hIcon
= CreateIconIndirect (&ii
);
1481 DeleteObject (ii
.hbmMask
);
1482 DeleteObject (ii
.hbmColor
);
1489 /*************************************************************************
1490 * ImageList_GetIconSize [COMCTL32.@]
1492 * Retrieves the size of an image in an image list.
1495 * himl [I] handle to image list
1496 * cx [O] pointer to the image width.
1497 * cy [O] pointer to the image height.
1504 * All images in an image list have the same size.
1508 ImageList_GetIconSize (HIMAGELIST himl
, INT
*cx
, INT
*cy
)
1510 if (!is_valid(himl
))
1512 if ((himl
->cx
<= 0) || (himl
->cy
<= 0))
1524 /*************************************************************************
1525 * ImageList_GetImageCount [COMCTL32.@]
1527 * Returns the number of images in an image list.
1530 * himl [I] handle to image list
1533 * Success: Number of images.
1538 ImageList_GetImageCount (HIMAGELIST himl
)
1540 if (!is_valid(himl
))
1543 return himl
->cCurImage
;
1547 /*************************************************************************
1548 * ImageList_GetImageInfo [COMCTL32.@]
1550 * Returns information about an image in an image list.
1553 * himl [I] handle to image list
1555 * pImageInfo [O] pointer to the image information
1563 ImageList_GetImageInfo (HIMAGELIST himl
, INT i
, IMAGEINFO
*pImageInfo
)
1567 if (!is_valid(himl
) || (pImageInfo
== NULL
))
1569 if ((i
< 0) || (i
>= himl
->cCurImage
))
1572 pImageInfo
->hbmImage
= himl
->hbmImage
;
1573 pImageInfo
->hbmMask
= himl
->hbmMask
;
1575 imagelist_point_from_index( himl
, i
, &pt
);
1576 pImageInfo
->rcImage
.top
= pt
.y
;
1577 pImageInfo
->rcImage
.bottom
= pt
.y
+ himl
->cy
;
1578 pImageInfo
->rcImage
.left
= pt
.x
;
1579 pImageInfo
->rcImage
.right
= pt
.x
+ himl
->cx
;
1585 /*************************************************************************
1586 * ImageList_GetImageRect [COMCTL32.@]
1588 * Retrieves the rectangle of the specified image in an image list.
1591 * himl [I] handle to image list
1593 * lpRect [O] pointer to the image rectangle
1600 * This is an UNDOCUMENTED function!!!
1604 ImageList_GetImageRect (HIMAGELIST himl
, INT i
, LPRECT lpRect
)
1608 if (!is_valid(himl
) || (lpRect
== NULL
))
1610 if ((i
< 0) || (i
>= himl
->cCurImage
))
1613 imagelist_point_from_index( himl
, i
, &pt
);
1614 lpRect
->left
= pt
.x
;
1616 lpRect
->right
= pt
.x
+ himl
->cx
;
1617 lpRect
->bottom
= pt
.y
+ himl
->cy
;
1623 /*************************************************************************
1624 * ImageList_LoadImage [COMCTL32.@]
1625 * ImageList_LoadImageA [COMCTL32.@]
1627 * Creates an image list from a bitmap, icon or cursor.
1629 * See ImageList_LoadImageW.
1633 ImageList_LoadImageA (HINSTANCE hi
, LPCSTR lpbmp
, INT cx
, INT cGrow
,
1634 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1641 return ImageList_LoadImageW(hi
, (LPCWSTR
)lpbmp
, cx
, cGrow
, clrMask
,
1644 len
= MultiByteToWideChar(CP_ACP
, 0, lpbmp
, -1, NULL
, 0);
1645 lpbmpW
= Alloc(len
* sizeof(WCHAR
));
1646 MultiByteToWideChar(CP_ACP
, 0, lpbmp
, -1, lpbmpW
, len
);
1648 himl
= ImageList_LoadImageW(hi
, lpbmpW
, cx
, cGrow
, clrMask
, uType
, uFlags
);
1654 /*************************************************************************
1655 * ImageList_LoadImageW [COMCTL32.@]
1657 * Creates an image list from a bitmap, icon or cursor.
1660 * hi [I] instance handle
1661 * lpbmp [I] name or id of the image
1662 * cx [I] width of each image
1663 * cGrow [I] number of images to expand
1664 * clrMask [I] mask color
1665 * uType [I] type of image to load
1666 * uFlags [I] loading flags
1669 * Success: handle to the loaded image list
1677 ImageList_LoadImageW (HINSTANCE hi
, LPCWSTR lpbmp
, INT cx
, INT cGrow
,
1678 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1680 HIMAGELIST himl
= NULL
;
1684 handle
= LoadImageW (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1686 ERR("Error loading image!\n");
1690 if (uType
== IMAGE_BITMAP
) {
1692 GetObjectW (handle
, sizeof(BITMAP
), &bmp
);
1694 /* To match windows behavior, if cx is set to zero and
1695 the flag DI_DEFAULTSIZE is specified, cx becomes the
1696 system metric value for icons. If the flag is not specified
1697 the function sets the size to the height of the bitmap */
1700 if (uFlags
& DI_DEFAULTSIZE
)
1701 cx
= GetSystemMetrics (SM_CXICON
);
1706 nImageCount
= bmp
.bmWidth
/ cx
;
1708 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1709 nImageCount
, cGrow
);
1711 DeleteObject (handle
);
1714 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1716 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1720 GetIconInfo (handle
, &ii
);
1721 GetObjectW (ii
.hbmColor
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1722 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1723 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1725 DeleteObject (ii
.hbmColor
);
1726 DeleteObject (ii
.hbmMask
);
1727 DeleteObject (handle
);
1730 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1731 DeleteObject (ii
.hbmColor
);
1732 DeleteObject (ii
.hbmMask
);
1735 DeleteObject (handle
);
1741 /*************************************************************************
1742 * ImageList_Merge [COMCTL32.@]
1744 * Create an image list containing a merged image from two image lists.
1747 * himl1 [I] handle to first image list
1748 * i1 [I] first image index
1749 * himl2 [I] handle to second image list
1750 * i2 [I] second image index
1751 * dx [I] X offset of the second image relative to the first.
1752 * dy [I] Y offset of the second image relative to the first.
1755 * Success: The newly created image list. It contains a single image
1756 * consisting of the second image merged with the first.
1757 * Failure: NULL, if either himl1 or himl2 are invalid.
1760 * - The returned image list should be deleted by the caller using
1761 * ImageList_Destroy() when it is no longer required.
1762 * - If either i1 or i2 are not valid image indices they will be treated
1766 ImageList_Merge (HIMAGELIST himl1
, INT i1
, HIMAGELIST himl2
, INT i2
,
1769 HIMAGELIST himlDst
= NULL
;
1771 INT xOff1
, yOff1
, xOff2
, yOff2
;
1774 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1
, i1
, himl2
,
1777 if (!is_valid(himl1
) || !is_valid(himl2
))
1781 cxDst
= max (himl1
->cx
, dx
+ himl2
->cx
);
1786 cxDst
= max (himl2
->cx
, himl1
->cx
- dx
);
1791 cxDst
= max (himl1
->cx
, himl2
->cx
);
1797 cyDst
= max (himl1
->cy
, dy
+ himl2
->cy
);
1802 cyDst
= max (himl2
->cy
, himl1
->cy
- dy
);
1807 cyDst
= max (himl1
->cy
, himl2
->cy
);
1812 himlDst
= ImageList_Create (cxDst
, cyDst
, ILC_MASK
| ILC_COLOR
, 1, 1);
1816 imagelist_point_from_index( himl1
, i1
, &pt1
);
1817 imagelist_point_from_index( himl1
, i2
, &pt2
);
1820 BitBlt (himlDst
->hdcImage
, 0, 0, cxDst
, cyDst
, himl1
->hdcImage
, 0, 0, BLACKNESS
);
1821 if (i1
>= 0 && i1
< himl1
->cCurImage
)
1822 BitBlt (himlDst
->hdcImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
, himl1
->hdcImage
, pt1
.x
, pt1
.y
, SRCCOPY
);
1823 if (i2
>= 0 && i2
< himl2
->cCurImage
)
1825 BitBlt (himlDst
->hdcImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcMask
, pt2
.x
, pt2
.y
, SRCAND
);
1826 BitBlt (himlDst
->hdcImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcImage
, pt2
.x
, pt2
.y
, SRCPAINT
);
1830 BitBlt (himlDst
->hdcMask
, 0, 0, cxDst
, cyDst
, himl1
->hdcMask
, 0, 0, WHITENESS
);
1831 if (i1
>= 0 && i1
< himl1
->cCurImage
)
1832 BitBlt (himlDst
->hdcMask
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
, himl1
->hdcMask
, pt1
.x
, pt1
.y
, SRCCOPY
);
1833 if (i2
>= 0 && i2
< himl2
->cCurImage
)
1834 BitBlt (himlDst
->hdcMask
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcMask
, pt2
.x
, pt2
.y
, SRCAND
);
1836 himlDst
->cCurImage
= 1;
1843 /* helper for _read_bitmap currently unused */
1845 static int may_use_dibsection(HDC hdc
) {
1846 int bitspixel
= GetDeviceCaps(hdc
,BITSPIXEL
)*GetDeviceCaps(hdc
,PLANES
);
1851 return GetDeviceCaps(hdc
,CAPS1
) & C1_DIBENGINE
;
1855 /* helper for ImageList_Read, see comments below */
1856 static HBITMAP
_read_bitmap(LPSTREAM pstm
,int ilcFlag
,int cx
,int cy
) {
1857 HDC xdc
= 0, hBitmapDC
=0;
1858 BITMAPFILEHEADER bmfh
;
1859 BITMAPINFOHEADER bmih
;
1860 int bitsperpixel
,palspace
,longsperline
,width
,height
;
1861 LPBITMAPINFOHEADER bmihc
= NULL
;
1863 HBITMAP hbitmap
= 0, hDIB
= 0;
1866 if (!SUCCEEDED(IStream_Read ( pstm
, &bmfh
, sizeof(bmfh
), NULL
)) ||
1867 (bmfh
.bfType
!= (('M'<<8)|'B')) ||
1868 !SUCCEEDED(IStream_Read ( pstm
, &bmih
, sizeof(bmih
), NULL
)) ||
1869 (bmih
.biSize
!= sizeof(bmih
))
1873 bitsperpixel
= bmih
.biPlanes
* bmih
.biBitCount
;
1874 if (bitsperpixel
<=8)
1875 palspace
= (1<<bitsperpixel
)*sizeof(RGBQUAD
);
1878 width
= bmih
.biWidth
;
1879 height
= bmih
.biHeight
;
1880 bmihc
= (LPBITMAPINFOHEADER
)LocalAlloc(LMEM_ZEROINIT
,sizeof(bmih
)+palspace
);
1881 if (!bmihc
) goto ret1
;
1882 memcpy(bmihc
,&bmih
,sizeof(bmih
));
1883 longsperline
= ((width
*bitsperpixel
+31)&~0x1f)>>5;
1884 bmihc
->biSizeImage
= (longsperline
*height
)<<2;
1886 /* read the palette right after the end of the bitmapinfoheader */
1888 if (!SUCCEEDED(IStream_Read ( pstm
, bmihc
+1, palspace
, NULL
)))
1892 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1893 if ((bitsperpixel
>1) &&
1894 ((ilcFlag
!=ILC_COLORDDB
) && (!ilcFlag
|| may_use_dibsection(xdc
)))
1896 hbitmap
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1899 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1905 int i
,nwidth
,nheight
,nRows
;
1907 nwidth
= width
*(height
/cy
);
1909 nRows
= (height
/cy
);
1911 if (bitsperpixel
==1)
1912 hbitmap
= CreateBitmap(nwidth
,nheight
,1,1,NULL
);
1914 hbitmap
= CreateCompatibleBitmap(xdc
,nwidth
,nheight
);
1916 hDIB
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1919 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1922 hBitmapDC
= CreateCompatibleDC(0);
1923 SelectObject(hBitmapDC
, hbitmap
);
1925 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1926 /* Do not forget that windows bitmaps are bottom->top */
1927 TRACE("nRows=%d\n", nRows
);
1928 for (i
=0; i
< nRows
; i
++){
1929 StretchDIBits(hBitmapDC
, width
*i
, 0, width
, cy
, 0, cy
*(nRows
-1-i
), width
, cy
, bits
,
1930 (BITMAPINFO
*)bmihc
, DIB_RGB_COLORS
, SRCCOPY
);
1936 if (xdc
) ReleaseDC(0,xdc
);
1937 if (bmihc
) LocalFree((HLOCAL
)bmihc
);
1938 if (hDIB
) DeleteObject(hDIB
);
1939 if (hBitmapDC
) DeleteDC(hBitmapDC
);
1942 DeleteObject(hbitmap
);
1949 /*************************************************************************
1950 * ImageList_Read [COMCTL32.@]
1952 * Reads an image list from a stream.
1955 * pstm [I] pointer to a stream
1958 * Success: handle to image list
1961 * The format is like this:
1962 * ILHEAD ilheadstruct;
1964 * for the color image part:
1965 * BITMAPFILEHEADER bmfh;
1966 * BITMAPINFOHEADER bmih;
1967 * only if it has a palette:
1968 * RGBQUAD rgbs[nr_of_paletted_colors];
1970 * BYTE colorbits[imagesize];
1972 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1973 * BITMAPFILEHEADER bmfh_mask;
1974 * BITMAPINFOHEADER bmih_mask;
1975 * only if it has a palette (it usually does not):
1976 * RGBQUAD rgbs[nr_of_paletted_colors];
1978 * BYTE maskbits[imagesize];
1980 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1981 * _read_bitmap needs to convert them.
1983 HIMAGELIST WINAPI
ImageList_Read (LPSTREAM pstm
)
1987 HBITMAP hbmColor
=0,hbmMask
=0;
1990 if (!SUCCEEDED(IStream_Read (pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
1992 if (ilHead
.usMagic
!= (('L' << 8) | 'I'))
1994 if (ilHead
.usVersion
!= 0x101) /* probably version? */
1998 FIXME(" ilHead.cCurImage = %d\n",ilHead
.cCurImage
);
1999 FIXME(" ilHead.cMaxImage = %d\n",ilHead
.cMaxImage
);
2000 FIXME(" ilHead.cGrow = %d\n",ilHead
.cGrow
);
2001 FIXME(" ilHead.cx = %d\n",ilHead
.cx
);
2002 FIXME(" ilHead.cy = %d\n",ilHead
.cy
);
2003 FIXME(" ilHead.flags = %x\n",ilHead
.flags
);
2004 FIXME(" ilHead.ovls[0] = %d\n",ilHead
.ovls
[0]);
2005 FIXME(" ilHead.ovls[1] = %d\n",ilHead
.ovls
[1]);
2006 FIXME(" ilHead.ovls[2] = %d\n",ilHead
.ovls
[2]);
2007 FIXME(" ilHead.ovls[3] = %d\n",ilHead
.ovls
[3]);
2010 hbmColor
= _read_bitmap(pstm
,ilHead
.flags
& ~ILC_MASK
,ilHead
.cx
,ilHead
.cy
);
2012 WARN("failed to read bitmap from stream\n");
2015 if (ilHead
.flags
& ILC_MASK
) {
2016 hbmMask
= _read_bitmap(pstm
,0,ilHead
.cx
,ilHead
.cy
);
2018 DeleteObject(hbmColor
);
2023 himl
= ImageList_Create (
2031 DeleteObject(hbmColor
);
2032 DeleteObject(hbmMask
);
2035 SelectObject(himl
->hdcImage
, hbmColor
);
2036 DeleteObject(himl
->hbmImage
);
2037 himl
->hbmImage
= hbmColor
;
2039 SelectObject(himl
->hdcMask
, hbmMask
);
2040 DeleteObject(himl
->hbmMask
);
2041 himl
->hbmMask
= hbmMask
;
2043 himl
->cCurImage
= ilHead
.cCurImage
;
2044 himl
->cMaxImage
= ilHead
.cMaxImage
;
2046 ImageList_SetBkColor(himl
,ilHead
.bkcolor
);
2048 ImageList_SetOverlayImage(himl
,ilHead
.ovls
[i
],i
+1);
2053 /*************************************************************************
2054 * ImageList_Remove [COMCTL32.@]
2056 * Removes an image from an image list
2059 * himl [I] image list handle
2068 ImageList_Remove (HIMAGELIST himl
, INT i
)
2070 HBITMAP hbmNewImage
, hbmNewMask
;
2075 TRACE("(himl=%p i=%d)\n", himl
, i
);
2077 if (!is_valid(himl
)) {
2078 ERR("Invalid image list handle!\n");
2082 if ((i
< -1) || (i
>= himl
->cCurImage
)) {
2083 TRACE("index out of range! %d\n", i
);
2089 if (himl
->cCurImage
== 0) {
2090 /* remove all on empty ImageList is allowed */
2091 TRACE("remove all on empty ImageList!\n");
2095 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2096 himl
->cCurImage
= 0;
2097 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2098 himl
->nOvlIdx
[nCount
] = -1;
2100 hbmNewImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
, himl
->cy
);
2101 SelectObject (himl
->hdcImage
, hbmNewImage
);
2102 DeleteObject (himl
->hbmImage
);
2103 himl
->hbmImage
= hbmNewImage
;
2105 if (himl
->hbmMask
) {
2107 imagelist_get_bitmap_size(himl
, himl
->cMaxImage
, himl
->cy
, &sz
);
2108 hbmNewMask
= CreateBitmap (sz
.cx
, sz
.cy
, 1, 1, NULL
);
2109 SelectObject (himl
->hdcMask
, hbmNewMask
);
2110 DeleteObject (himl
->hbmMask
);
2111 himl
->hbmMask
= hbmNewMask
;
2115 /* delete one image */
2116 TRACE("Remove single image! %d\n", i
);
2118 /* create new bitmap(s) */
2119 nCount
= (himl
->cCurImage
+ himl
->cGrow
- 1);
2121 TRACE(" - Number of images: %d / %d (Old/New)\n",
2122 himl
->cCurImage
, himl
->cCurImage
- 1);
2123 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2124 himl
->cMaxImage
, himl
->cCurImage
+ himl
->cGrow
- 1);
2126 hbmNewImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, nCount
, himl
->cy
);
2128 imagelist_get_bitmap_size(himl
, nCount
, himl
->cy
, &sz
);
2130 hbmNewMask
= CreateBitmap (sz
.cx
, sz
.cy
, 1, 1, NULL
);
2132 hbmNewMask
= 0; /* Just to keep compiler happy! */
2134 hdcBmp
= CreateCompatibleDC (0);
2136 /* copy all images and masks prior to the "removed" image */
2138 TRACE("Pre image copy: Copy %d images\n", i
);
2140 SelectObject (hdcBmp
, hbmNewImage
);
2141 imagelist_copy_images( himl
, himl
->hdcImage
, hdcBmp
, 0, i
, 0 );
2143 if (himl
->hbmMask
) {
2144 SelectObject (hdcBmp
, hbmNewMask
);
2145 imagelist_copy_images( himl
, himl
->hdcMask
, hdcBmp
, 0, i
, 0 );
2149 /* copy all images and masks behind the removed image */
2150 if (i
< himl
->cCurImage
- 1) {
2151 TRACE("Post image copy!\n");
2153 SelectObject (hdcBmp
, hbmNewImage
);
2154 imagelist_copy_images( himl
, himl
->hdcImage
, hdcBmp
, i
,
2155 (himl
->cCurImage
- i
- 1), i
+ 1 );
2157 if (himl
->hbmMask
) {
2158 SelectObject (hdcBmp
, hbmNewMask
);
2159 imagelist_copy_images( himl
, himl
->hdcMask
, hdcBmp
, i
,
2160 (himl
->cCurImage
- i
- 1), i
+ 1 );
2166 /* delete old images and insert new ones */
2167 SelectObject (himl
->hdcImage
, hbmNewImage
);
2168 DeleteObject (himl
->hbmImage
);
2169 himl
->hbmImage
= hbmNewImage
;
2170 if (himl
->hbmMask
) {
2171 SelectObject (himl
->hdcMask
, hbmNewMask
);
2172 DeleteObject (himl
->hbmMask
);
2173 himl
->hbmMask
= hbmNewMask
;
2177 himl
->cMaxImage
= himl
->cCurImage
+ himl
->cGrow
;
2184 /*************************************************************************
2185 * ImageList_Replace [COMCTL32.@]
2187 * Replaces an image in an image list with a new image.
2190 * himl [I] handle to image list
2192 * hbmImage [I] handle to image bitmap
2193 * hbmMask [I] handle to mask bitmap. Can be NULL.
2201 ImageList_Replace (HIMAGELIST himl
, INT i
, HBITMAP hbmImage
,
2209 TRACE("%p %d %p %p\n", himl
, i
, hbmImage
, hbmMask
);
2211 if (!is_valid(himl
)) {
2212 ERR("Invalid image list handle!\n");
2216 if ((i
>= himl
->cMaxImage
) || (i
< 0)) {
2217 ERR("Invalid image index!\n");
2221 if (!GetObjectW(hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
))
2224 hdcImage
= CreateCompatibleDC (0);
2227 hOldBitmap
= SelectObject (hdcImage
, hbmImage
);
2229 imagelist_point_from_index(himl
, i
, &pt
);
2230 StretchBlt (himl
->hdcImage
, pt
.x
, pt
.y
, himl
->cx
, himl
->cy
,
2231 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2236 HBITMAP hOldBitmapTemp
;
2238 hdcTemp
= CreateCompatibleDC(0);
2239 hOldBitmapTemp
= SelectObject(hdcTemp
, hbmMask
);
2241 StretchBlt (himl
->hdcMask
, pt
.x
, pt
.y
, himl
->cx
, himl
->cy
,
2242 hdcTemp
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2243 SelectObject(hdcTemp
, hOldBitmapTemp
);
2246 /* Remove the background from the image
2248 BitBlt (himl
->hdcImage
, pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
2249 himl
->hdcMask
, pt
.x
, pt
.y
, 0x220326); /* NOTSRCAND */
2252 SelectObject (hdcImage
, hOldBitmap
);
2253 DeleteDC (hdcImage
);
2259 /*************************************************************************
2260 * ImageList_ReplaceIcon [COMCTL32.@]
2262 * Replaces an image in an image list using an icon.
2265 * himl [I] handle to image list
2267 * hIcon [I] handle to icon
2270 * Success: index of the replaced image
2275 ImageList_ReplaceIcon (HIMAGELIST himl
, INT i
, HICON hIcon
)
2286 TRACE("(%p %d %p)\n", himl
, i
, hIcon
);
2288 if (!is_valid(himl
)) {
2289 ERR("invalid image list\n");
2292 if ((i
>= himl
->cMaxImage
) || (i
< -1)) {
2293 ERR("invalid image index %d / %d\n", i
, himl
->cMaxImage
);
2297 hBestFitIcon
= CopyImage(
2300 LR_COPYFROMRESOURCE
);
2301 /* the above will fail if the icon wasn't loaded from a resource, so try
2302 * again without LR_COPYFROMRESOURCE flag */
2304 hBestFitIcon
= CopyImage(
2311 ret
= GetIconInfo (hBestFitIcon
, &ii
);
2313 DestroyIcon(hBestFitIcon
);
2317 if (ii
.hbmColor
== 0)
2319 ret
= GetObjectW (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2321 ERR("couldn't get mask bitmap info\n");
2323 DeleteObject (ii
.hbmColor
);
2325 DeleteObject (ii
.hbmMask
);
2326 DestroyIcon(hBestFitIcon
);
2331 if (himl
->cCurImage
+ 1 > himl
->cMaxImage
)
2332 IMAGELIST_InternalExpandBitmaps (himl
, 1, 0, 0);
2334 nIndex
= himl
->cCurImage
;
2340 hdcImage
= CreateCompatibleDC (0);
2341 TRACE("hdcImage=%p\n", hdcImage
);
2343 ERR("invalid hdcImage!\n");
2345 SetTextColor(himl
->hdcImage
, RGB(0,0,0));
2346 SetBkColor (himl
->hdcImage
, RGB(255,255,255));
2347 hbmOldSrc
= SelectObject (hdcImage
, ii
.hbmColor
);
2349 imagelist_point_from_index(himl
, nIndex
, &pt
);
2350 StretchBlt (himl
->hdcImage
, pt
.x
, pt
.y
, himl
->cx
, himl
->cy
,
2351 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2353 if (himl
->hbmMask
) {
2354 SelectObject (hdcImage
, ii
.hbmMask
);
2355 StretchBlt (himl
->hdcMask
, pt
.x
, pt
.y
, himl
->cx
, himl
->cy
,
2356 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2359 SelectObject (hdcImage
, hbmOldSrc
);
2361 DestroyIcon(hBestFitIcon
);
2363 DeleteDC (hdcImage
);
2365 DeleteObject (ii
.hbmColor
);
2367 DeleteObject (ii
.hbmMask
);
2369 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex
, himl
->cCurImage
);
2374 /*************************************************************************
2375 * ImageList_SetBkColor [COMCTL32.@]
2377 * Sets the background color of an image list.
2380 * himl [I] handle to image list
2381 * clrBk [I] background color
2384 * Success: previous background color
2389 ImageList_SetBkColor (HIMAGELIST himl
, COLORREF clrBk
)
2393 if (!is_valid(himl
))
2396 clrOldBk
= himl
->clrBk
;
2397 himl
->clrBk
= clrBk
;
2402 /*************************************************************************
2403 * ImageList_SetDragCursorImage [COMCTL32.@]
2405 * Combines the specified image with the current drag image
2408 * himlDrag [I] handle to drag image list
2409 * iDrag [I] drag image index
2410 * dxHotspot [I] X position of the hot spot
2411 * dyHotspot [I] Y position of the hot spot
2418 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2419 * to do with a hotspot but are only the offset of the origin of the new
2420 * image relative to the origin of the old image.
2422 * - When this function is called and the drag image is visible, a
2423 * short flickering occurs but this matches the Win9x behavior. It is
2424 * possible to fix the flickering using code like in ImageList_DragMove.
2428 ImageList_SetDragCursorImage (HIMAGELIST himlDrag
, INT iDrag
,
2429 INT dxHotspot
, INT dyHotspot
)
2431 HIMAGELIST himlTemp
;
2434 if (!is_valid(InternalDrag
.himl
) || !is_valid(himlDrag
))
2437 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2438 dxHotspot
, dyHotspot
, InternalDrag
.dxHotspot
, InternalDrag
.dyHotspot
);
2440 visible
= InternalDrag
.bShow
;
2442 himlTemp
= ImageList_Merge (InternalDrag
.himl
, 0, himlDrag
, iDrag
,
2443 dxHotspot
, dyHotspot
);
2446 /* hide the drag image */
2447 ImageList_DragShowNolock(FALSE
);
2449 if ((InternalDrag
.himl
->cx
!= himlTemp
->cx
) ||
2450 (InternalDrag
.himl
->cy
!= himlTemp
->cy
)) {
2451 /* the size of the drag image changed, invalidate the buffer */
2452 DeleteObject(InternalDrag
.hbmBg
);
2453 InternalDrag
.hbmBg
= 0;
2456 ImageList_Destroy (InternalDrag
.himl
);
2457 InternalDrag
.himl
= himlTemp
;
2460 /* show the drag image */
2461 ImageList_DragShowNolock(TRUE
);
2468 /*************************************************************************
2469 * ImageList_SetFilter [COMCTL32.@]
2471 * Sets a filter (or does something completely different)!!???
2472 * It removes 12 Bytes from the stack (3 Parameters).
2475 * himl [I] SHOULD be a handle to image list
2476 * i [I] COULD be an index?
2481 * Failure: FALSE ???
2484 * This is an UNDOCUMENTED function!!!!
2489 ImageList_SetFilter (HIMAGELIST himl
, INT i
, DWORD dwFilter
)
2491 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl
, i
, dwFilter
);
2497 /*************************************************************************
2498 * ImageList_SetFlags [COMCTL32.@]
2500 * Sets the image list flags.
2503 * himl [I] Handle to image list
2504 * flags [I] Flags to set
2514 ImageList_SetFlags(HIMAGELIST himl
, DWORD flags
)
2516 FIXME("(%p %08x):empty stub\n", himl
, flags
);
2521 /*************************************************************************
2522 * ImageList_SetIconSize [COMCTL32.@]
2524 * Sets the image size of the bitmap and deletes all images.
2527 * himl [I] handle to image list
2528 * cx [I] image width
2529 * cy [I] image height
2537 ImageList_SetIconSize (HIMAGELIST himl
, INT cx
, INT cy
)
2542 if (!is_valid(himl
))
2545 /* remove all images */
2546 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2547 himl
->cCurImage
= 0;
2551 /* initialize overlay mask indices */
2552 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2553 himl
->nOvlIdx
[nCount
] = -1;
2555 hbmNew
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
, himl
->cy
);
2556 SelectObject (himl
->hdcImage
, hbmNew
);
2557 DeleteObject (himl
->hbmImage
);
2558 himl
->hbmImage
= hbmNew
;
2560 if (himl
->hbmMask
) {
2562 imagelist_get_bitmap_size(himl
, himl
->cMaxImage
, himl
->cy
, &sz
);
2563 hbmNew
= CreateBitmap (sz
.cx
, sz
.cy
, 1, 1, NULL
);
2564 SelectObject (himl
->hdcMask
, hbmNew
);
2565 DeleteObject (himl
->hbmMask
);
2566 himl
->hbmMask
= hbmNew
;
2573 /*************************************************************************
2574 * ImageList_SetImageCount [COMCTL32.@]
2576 * Resizes an image list to the specified number of images.
2579 * himl [I] handle to image list
2580 * iImageCount [I] number of images in the image list
2588 ImageList_SetImageCount (HIMAGELIST himl
, UINT iImageCount
)
2591 HBITMAP hbmNewBitmap
;
2592 INT nNewCount
, nCopyCount
;
2594 TRACE("%p %d\n",himl
,iImageCount
);
2596 if (!is_valid(himl
))
2598 if (iImageCount
< 0)
2600 if (himl
->cMaxImage
> iImageCount
)
2602 himl
->cCurImage
= iImageCount
;
2603 /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2607 nNewCount
= iImageCount
+ himl
->cGrow
;
2608 nCopyCount
= min(himl
->cCurImage
, iImageCount
);
2610 hdcBitmap
= CreateCompatibleDC (0);
2612 hbmNewBitmap
= ImageList_CreateImage(hdcBitmap
, himl
, nNewCount
, himl
->cy
);
2614 if (hbmNewBitmap
!= 0)
2616 SelectObject (hdcBitmap
, hbmNewBitmap
);
2617 imagelist_copy_images( himl
, himl
->hdcImage
, hdcBitmap
, 0, nCopyCount
, 0 );
2619 /* FIXME: delete 'empty' image space? */
2621 SelectObject (himl
->hdcImage
, hbmNewBitmap
);
2622 DeleteObject (himl
->hbmImage
);
2623 himl
->hbmImage
= hbmNewBitmap
;
2626 ERR("Could not create new image bitmap !\n");
2631 imagelist_get_bitmap_size( himl
, nNewCount
, himl
->cy
, &sz
);
2632 hbmNewBitmap
= CreateBitmap (sz
.cx
, sz
.cy
, 1, 1, NULL
);
2633 if (hbmNewBitmap
!= 0)
2635 SelectObject (hdcBitmap
, hbmNewBitmap
);
2636 imagelist_copy_images( himl
, himl
->hdcMask
, hdcBitmap
, 0, nCopyCount
, 0 );
2638 /* FIXME: delete 'empty' image space? */
2640 SelectObject (himl
->hdcMask
, hbmNewBitmap
);
2641 DeleteObject (himl
->hbmMask
);
2642 himl
->hbmMask
= hbmNewBitmap
;
2645 ERR("Could not create new mask bitmap!\n");
2648 DeleteDC (hdcBitmap
);
2650 /* Update max image count and current image count */
2651 himl
->cMaxImage
= nNewCount
;
2652 himl
->cCurImage
= iImageCount
;
2658 /*************************************************************************
2659 * ImageList_SetOverlayImage [COMCTL32.@]
2661 * Assigns an overlay mask index to an existing image in an image list.
2664 * himl [I] handle to image list
2665 * iImage [I] image index
2666 * iOverlay [I] overlay mask index
2674 ImageList_SetOverlayImage (HIMAGELIST himl
, INT iImage
, INT iOverlay
)
2676 if (!is_valid(himl
))
2678 if ((iOverlay
< 1) || (iOverlay
> MAX_OVERLAYIMAGE
))
2680 if ((iImage
!=-1) && ((iImage
< 0) || (iImage
> himl
->cCurImage
)))
2682 himl
->nOvlIdx
[iOverlay
- 1] = iImage
;
2688 /* helper for ImageList_Write - write bitmap to pstm
2689 * currently everything is written as 24 bit RGB, except masks
2692 _write_bitmap(HBITMAP hBitmap
, LPSTREAM pstm
, int cx
, int cy
)
2694 LPBITMAPFILEHEADER bmfh
;
2695 LPBITMAPINFOHEADER bmih
;
2696 LPBYTE data
= NULL
, lpBits
= NULL
, lpBitsOrg
= NULL
;
2698 INT bitCount
, sizeImage
, offBits
, totalSize
;
2699 INT nwidth
, nheight
, nsizeImage
, icount
;
2701 BOOL result
= FALSE
;
2705 if (!GetObjectW(hBitmap
, sizeof(BITMAP
), (LPVOID
)&bm
))
2708 /* XXX is this always correct? */
2709 icount
= bm
.bmWidth
/ cx
;
2711 nheight
= cy
* icount
;
2713 bitCount
= bm
.bmBitsPixel
== 1 ? 1 : 24;
2714 sizeImage
= ((((bm
.bmWidth
* bitCount
)+31) & ~31) >> 3) * bm
.bmHeight
;
2715 nsizeImage
= ((((nwidth
* bitCount
)+31) & ~31) >> 3) * nheight
;
2717 totalSize
= sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
);
2719 totalSize
+= (1 << bitCount
) * sizeof(RGBQUAD
);
2720 offBits
= totalSize
;
2721 totalSize
+= nsizeImage
;
2723 data
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, totalSize
);
2724 bmfh
= (LPBITMAPFILEHEADER
)data
;
2725 bmih
= (LPBITMAPINFOHEADER
)(data
+ sizeof(BITMAPFILEHEADER
));
2726 lpBits
= data
+ offBits
;
2728 /* setup BITMAPFILEHEADER */
2729 bmfh
->bfType
= (('M' << 8) | 'B');
2731 bmfh
->bfReserved1
= 0;
2732 bmfh
->bfReserved2
= 0;
2733 bmfh
->bfOffBits
= offBits
;
2735 /* setup BITMAPINFOHEADER */
2736 bmih
->biSize
= sizeof(BITMAPINFOHEADER
);
2737 bmih
->biWidth
= bm
.bmWidth
;
2738 bmih
->biHeight
= bm
.bmHeight
;
2740 bmih
->biBitCount
= bitCount
;
2741 bmih
->biCompression
= BI_RGB
;
2742 bmih
->biSizeImage
= sizeImage
;
2743 bmih
->biXPelsPerMeter
= 0;
2744 bmih
->biYPelsPerMeter
= 0;
2745 bmih
->biClrUsed
= 0;
2746 bmih
->biClrImportant
= 0;
2748 lpBitsOrg
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, sizeImage
);
2749 if(!GetDIBits(xdc
, hBitmap
, 0, bm
.bmHeight
, lpBitsOrg
,
2750 (BITMAPINFO
*)bmih
, DIB_RGB_COLORS
))
2754 int obpl
= (((bm
.bmWidth
*bitCount
+31) & ~31)>>3);
2755 int nbpl
= (((nwidth
*bitCount
+31) & ~31)>>3);
2757 for(i
= 0; i
< nheight
; i
++) {
2758 int ooff
= ((nheight
-1-i
)%cy
) * obpl
+ ((i
/cy
) * nbpl
);
2759 int noff
= (nbpl
* (nheight
-1-i
));
2760 memcpy(lpBits
+ noff
, lpBitsOrg
+ ooff
, nbpl
);
2764 bmih
->biWidth
= nwidth
;
2765 bmih
->biHeight
= nheight
;
2766 bmih
->biSizeImage
= nsizeImage
;
2770 LPBITMAPINFO inf
= (LPBITMAPINFO
)bmih
;
2771 inf
->bmiColors
[0].rgbRed
= inf
->bmiColors
[0].rgbGreen
= inf
->bmiColors
[0].rgbBlue
= 0;
2772 inf
->bmiColors
[1].rgbRed
= inf
->bmiColors
[1].rgbGreen
= inf
->bmiColors
[1].rgbBlue
= 0xff;
2775 if(!SUCCEEDED(IStream_Write(pstm
, data
, totalSize
, NULL
)))
2782 LocalFree((HLOCAL
)lpBitsOrg
);
2783 LocalFree((HLOCAL
)data
);
2789 /*************************************************************************
2790 * ImageList_Write [COMCTL32.@]
2792 * Writes an image list to a stream.
2795 * himl [I] handle to image list
2796 * pstm [O] Pointer to a stream.
2807 ImageList_Write (HIMAGELIST himl
, LPSTREAM pstm
)
2812 if (!is_valid(himl
))
2815 ilHead
.usMagic
= (('L' << 8) | 'I');
2816 ilHead
.usVersion
= 0x101;
2817 ilHead
.cCurImage
= himl
->cCurImage
;
2818 ilHead
.cMaxImage
= himl
->cMaxImage
;
2819 ilHead
.cGrow
= himl
->cGrow
;
2820 ilHead
.cx
= himl
->cx
;
2821 ilHead
.cy
= himl
->cy
;
2822 ilHead
.bkcolor
= himl
->clrBk
;
2823 ilHead
.flags
= himl
->flags
;
2824 for(i
= 0; i
< 4; i
++) {
2825 ilHead
.ovls
[i
] = himl
->nOvlIdx
[i
];
2828 if(!SUCCEEDED(IStream_Write(pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
2831 /* write the bitmap */
2832 if(!_write_bitmap(himl
->hbmImage
, pstm
, himl
->cx
, himl
->cy
))
2835 /* write the mask if we have one */
2836 if(himl
->flags
& ILC_MASK
) {
2837 if(!_write_bitmap(himl
->hbmMask
, pstm
, himl
->cx
, himl
->cy
))
2845 static HBITMAP
ImageList_CreateImage(HDC hdc
, HIMAGELIST himl
, UINT count
, UINT height
)
2847 HBITMAP hbmNewBitmap
;
2848 UINT ilc
= (himl
->flags
& 0xFE);
2851 imagelist_get_bitmap_size( himl
, count
, height
, &sz
);
2853 if ((ilc
>= ILC_COLOR4
&& ilc
<= ILC_COLOR32
) || ilc
== ILC_COLOR
)
2858 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl
->uBitsPixel
);
2860 if (himl
->uBitsPixel
<= ILC_COLOR8
)
2866 colors
= 1 << himl
->uBitsPixel
;
2867 bmi
= Alloc(sizeof(BITMAPINFOHEADER
) +
2868 sizeof(PALETTEENTRY
) * colors
);
2870 pal
= (LPPALETTEENTRY
)bmi
->bmiColors
;
2871 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE
), 0, colors
, pal
);
2873 /* Swap colors returned by GetPaletteEntries so we can use them for
2874 * CreateDIBSection call. */
2875 for (i
= 0; i
< colors
; i
++)
2877 temp
= pal
[i
].peBlue
;
2878 bmi
->bmiColors
[i
].rgbRed
= pal
[i
].peRed
;
2879 bmi
->bmiColors
[i
].rgbBlue
= temp
;
2884 bmi
= Alloc(sizeof(BITMAPINFOHEADER
));
2887 bmi
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
2888 bmi
->bmiHeader
.biWidth
= sz
.cx
;
2889 bmi
->bmiHeader
.biHeight
= sz
.cy
;
2890 bmi
->bmiHeader
.biPlanes
= 1;
2891 bmi
->bmiHeader
.biBitCount
= himl
->uBitsPixel
;
2892 bmi
->bmiHeader
.biCompression
= BI_RGB
;
2893 bmi
->bmiHeader
.biSizeImage
= 0;
2894 bmi
->bmiHeader
.biXPelsPerMeter
= 0;
2895 bmi
->bmiHeader
.biYPelsPerMeter
= 0;
2896 bmi
->bmiHeader
.biClrUsed
= 0;
2897 bmi
->bmiHeader
.biClrImportant
= 0;
2899 hbmNewBitmap
= CreateDIBSection(hdc
, bmi
, DIB_RGB_COLORS
, &bits
, 0, 0);
2903 else /*if (ilc == ILC_COLORDDB)*/
2905 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl
->uBitsPixel
);
2907 hbmNewBitmap
= CreateBitmap (sz
.cx
, sz
.cy
, 1, himl
->uBitsPixel
, NULL
);
2909 TRACE("returning %p\n", hbmNewBitmap
);
2910 return hbmNewBitmap
;
2913 /*************************************************************************
2914 * ImageList_SetColorTable [COMCTL32.@]
2916 * Sets the color table of an image list.
2919 * himl [I] Handle to the image list.
2920 * uStartIndex [I] The first index to set.
2921 * cEntries [I] Number of entries to set.
2922 * prgb [I] New color information for color table for the image list.
2925 * Success: Number of entries in the table that were set.
2929 * ImageList_Create(), SetDIBColorTable()
2933 ImageList_SetColorTable (HIMAGELIST himl
, UINT uStartIndex
, UINT cEntries
, CONST RGBQUAD
* prgb
)
2935 return SetDIBColorTable(himl
->hdcImage
, uStartIndex
, cEntries
, prgb
);