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 width
, 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 /*************************************************************************
94 * IMAGELIST_InternalExpandBitmaps [Internal]
96 * Expands the bitmaps of an image list by the given number of images.
99 * himl [I] handle to image list
100 * nImageCount [I] number of images to add
106 * This function CANNOT be used to reduce the number of images.
109 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl
, INT nImageCount
, INT cx
, INT cy
)
112 HBITMAP hbmNewBitmap
, hbmNull
;
113 INT nNewWidth
, nNewCount
;
115 if ((himl
->cCurImage
+ nImageCount
<= himl
->cMaxImage
)
119 if (cy
== 0) cy
= himl
->cy
;
120 nNewCount
= himl
->cCurImage
+ nImageCount
+ himl
->cGrow
;
121 nNewWidth
= nNewCount
* himl
->cx
;
123 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl
, nNewWidth
, cy
, nNewCount
);
124 hdcBitmap
= CreateCompatibleDC (0);
126 hbmNewBitmap
= ImageList_CreateImage(hdcBitmap
, himl
, nNewWidth
, cy
);
128 if (hbmNewBitmap
== 0)
129 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth
, cy
);
133 hbmNull
= SelectObject (hdcBitmap
, hbmNewBitmap
);
134 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
135 himl
->hdcImage
, 0, 0, SRCCOPY
);
136 SelectObject (hdcBitmap
, hbmNull
);
138 SelectObject (himl
->hdcImage
, hbmNewBitmap
);
139 DeleteObject (himl
->hbmImage
);
140 himl
->hbmImage
= hbmNewBitmap
;
142 if (himl
->flags
& ILC_MASK
)
144 hbmNewBitmap
= CreateBitmap (nNewWidth
, cy
, 1, 1, NULL
);
146 if (hbmNewBitmap
== 0)
147 ERR("creating new mask bitmap!\n");
151 hbmNull
= SelectObject (hdcBitmap
, hbmNewBitmap
);
152 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
153 himl
->hdcMask
, 0, 0, SRCCOPY
);
154 SelectObject (hdcBitmap
, hbmNull
);
156 SelectObject (himl
->hdcMask
, hbmNewBitmap
);
157 DeleteObject (himl
->hbmMask
);
158 himl
->hbmMask
= hbmNewBitmap
;
161 himl
->cMaxImage
= nNewCount
;
163 DeleteDC (hdcBitmap
);
167 /*************************************************************************
168 * ImageList_Add [COMCTL32.@]
170 * Add an image or images to an image list.
173 * himl [I] handle to image list
174 * hbmImage [I] handle to image bitmap
175 * hbmMask [I] handle to mask bitmap
178 * Success: Index of the first new image.
183 ImageList_Add (HIMAGELIST himl
, HBITMAP hbmImage
, HBITMAP hbmMask
)
186 INT nFirstIndex
, nImageCount
;
191 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl
, hbmImage
, hbmMask
);
195 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
196 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
198 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
200 imagelist_point_from_index( himl
, himl
->cCurImage
, &pt
);
202 hdcBitmap
= CreateCompatibleDC(0);
204 hOldBitmap
= SelectObject(hdcBitmap
, hbmImage
);
206 /* Copy result to the imagelist
208 BitBlt (himl
->hdcImage
, pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
209 hdcBitmap
, 0, 0, SRCCOPY
);
214 HBITMAP hOldBitmapTemp
;
216 hdcTemp
= CreateCompatibleDC(0);
217 hOldBitmapTemp
= SelectObject(hdcTemp
, hbmMask
);
219 BitBlt (himl
->hdcMask
,
220 pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
225 SelectObject(hdcTemp
, hOldBitmapTemp
);
228 /* Remove the background from the image
230 BitBlt (himl
->hdcImage
,
231 pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
234 0x220326); /* NOTSRCAND */
237 SelectObject(hdcBitmap
, hOldBitmap
);
240 nFirstIndex
= himl
->cCurImage
;
241 himl
->cCurImage
+= nImageCount
;
247 /*************************************************************************
248 * ImageList_AddIcon [COMCTL32.@]
250 * Adds an icon to an image list.
253 * himl [I] handle to image list
254 * hIcon [I] handle to icon
257 * Success: index of the new image
260 #undef ImageList_AddIcon
261 INT WINAPI
ImageList_AddIcon (HIMAGELIST himl
, HICON hIcon
)
263 return ImageList_ReplaceIcon (himl
, -1, hIcon
);
267 /*************************************************************************
268 * ImageList_AddMasked [COMCTL32.@]
270 * Adds an image or images to an image list and creates a mask from the
271 * specified bitmap using the mask color.
274 * himl [I] handle to image list.
275 * hBitmap [I] handle to bitmap
276 * clrMask [I] mask color.
279 * Success: Index of the first new image.
284 ImageList_AddMasked (HIMAGELIST himl
, HBITMAP hBitmap
, COLORREF clrMask
)
286 HDC hdcMask
, hdcBitmap
;
287 INT nIndex
, nImageCount
, nMaskXOffset
=0;
290 HBITMAP hMaskBitmap
=0;
294 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl
, hBitmap
, clrMask
);
298 if (!GetObjectA (hBitmap
, sizeof(BITMAP
), &bmp
))
302 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
306 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
308 nIndex
= himl
->cCurImage
;
309 himl
->cCurImage
+= nImageCount
;
311 hdcBitmap
= CreateCompatibleDC(0);
314 hOldBitmap
= SelectObject(hdcBitmap
, hBitmap
);
317 hdcMask
= himl
->hdcMask
;
318 nMaskXOffset
= nIndex
* himl
->cx
;
323 Create a temp Mask so we can remove the background of
324 the Image (Windows does this even if there is no mask)
326 hdcMask
= CreateCompatibleDC(0);
327 hMaskBitmap
= CreateBitmap(bmp
.bmWidth
, bmp
.bmHeight
, 1, 1, NULL
);
328 SelectObject(hdcMask
, hMaskBitmap
);
331 /* create monochrome image to the mask bitmap */
332 bkColor
= (clrMask
!= CLR_DEFAULT
) ? clrMask
:
333 GetPixel (hdcBitmap
, 0, 0);
334 SetBkColor (hdcBitmap
, bkColor
);
336 nMaskXOffset
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
340 SetBkColor(hdcBitmap
, RGB(255,255,255));
341 /*Remove the background from the image
344 WINDOWS BUG ALERT!!!!!!
345 The statement below should not be done in common practice
346 but this is how ImageList_AddMasked works in Windows.
347 It overwrites the original bitmap passed, this was discovered
348 by using the same bitmap to iterate the different styles
349 on windows where it failed (BUT ImageList_Add is OK)
350 This is here in case some apps rely on this bug
353 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
356 0x220326); /* NOTSRCAND */
357 /* Copy result to the imagelist
359 imagelist_point_from_index( himl
, nIndex
, &pt
);
360 BitBlt (himl
->hdcImage
,
361 pt
.x
, pt
.y
, bmp
.bmWidth
, bmp
.bmHeight
,
367 SelectObject(hdcBitmap
, hOldBitmap
);
371 DeleteObject(hMaskBitmap
);
379 /*************************************************************************
380 * ImageList_BeginDrag [COMCTL32.@]
382 * Creates a temporary image list that contains one image. It will be used
386 * himlTrack [I] handle to the source image list
387 * iTrack [I] index of the drag image in the source image list
388 * dxHotspot [I] X position of the hot spot of the drag image
389 * dyHotspot [I] Y position of the hot spot of the drag image
397 ImageList_BeginDrag (HIMAGELIST himlTrack
, INT iTrack
,
398 INT dxHotspot
, INT dyHotspot
)
402 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack
, iTrack
,
403 dxHotspot
, dyHotspot
);
405 if (!is_valid(himlTrack
))
408 if (InternalDrag
.himl
)
409 ImageList_EndDrag ();
414 InternalDrag
.himl
= ImageList_Create (cx
, cy
, himlTrack
->flags
, 1, 1);
415 if (InternalDrag
.himl
== NULL
) {
416 WARN("Error creating drag image list!\n");
420 InternalDrag
.dxHotspot
= dxHotspot
;
421 InternalDrag
.dyHotspot
= dyHotspot
;
424 BitBlt (InternalDrag
.himl
->hdcImage
, 0, 0, cx
, cy
, himlTrack
->hdcImage
, iTrack
* cx
, 0, SRCCOPY
);
427 BitBlt (InternalDrag
.himl
->hdcMask
, 0, 0, cx
, cy
, himlTrack
->hdcMask
, iTrack
* cx
, 0, SRCCOPY
);
429 InternalDrag
.himl
->cCurImage
= 1;
435 /*************************************************************************
436 * ImageList_Copy [COMCTL32.@]
438 * Copies an image of the source image list to an image of the
439 * destination image list. Images can be copied or swapped.
442 * himlDst [I] handle to the destination image list
443 * iDst [I] destination image index.
444 * himlSrc [I] handle to the source image list
445 * iSrc [I] source image index
446 * uFlags [I] flags for the copy operation
453 * Copying from one image list to another is possible. The original
454 * implementation just copies or swaps within one image list.
455 * Could this feature become a bug??? ;-)
459 ImageList_Copy (HIMAGELIST himlDst
, INT iDst
, HIMAGELIST himlSrc
,
460 INT iSrc
, UINT uFlags
)
464 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst
, iDst
, himlSrc
, iSrc
);
466 if (!is_valid(himlSrc
) || !is_valid(himlDst
))
468 if ((iDst
< 0) || (iDst
>= himlDst
->cCurImage
))
470 if ((iSrc
< 0) || (iSrc
>= himlSrc
->cCurImage
))
473 imagelist_point_from_index( himlDst
, iDst
, &ptDst
);
474 imagelist_point_from_index( himlSrc
, iSrc
, &ptSrc
);
476 if (uFlags
& ILCF_SWAP
) {
479 HBITMAP hbmTempImage
, hbmTempMask
;
481 hdcBmp
= CreateCompatibleDC (0);
483 /* create temporary bitmaps */
484 hbmTempImage
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
485 himlSrc
->uBitsPixel
, NULL
);
486 hbmTempMask
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
489 /* copy (and stretch) destination to temporary bitmaps.(save) */
491 SelectObject (hdcBmp
, hbmTempImage
);
492 StretchBlt (hdcBmp
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
493 himlDst
->hdcImage
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
496 SelectObject (hdcBmp
, hbmTempMask
);
497 StretchBlt (hdcBmp
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
498 himlDst
->hdcMask
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
501 /* copy (and stretch) source to destination */
503 StretchBlt (himlDst
->hdcImage
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
504 himlSrc
->hdcImage
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
507 StretchBlt (himlDst
->hdcMask
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
508 himlSrc
->hdcMask
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
511 /* copy (without stretching) temporary bitmaps to source (restore) */
513 BitBlt (himlSrc
->hdcMask
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
514 hdcBmp
, 0, 0, SRCCOPY
);
517 BitBlt (himlSrc
->hdcImage
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
518 hdcBmp
, 0, 0, SRCCOPY
);
519 /* delete temporary bitmaps */
520 DeleteObject (hbmTempMask
);
521 DeleteObject (hbmTempImage
);
526 StretchBlt (himlDst
->hdcImage
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
527 himlSrc
->hdcImage
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
531 StretchBlt (himlDst
->hdcMask
, ptDst
.x
, ptDst
.y
, himlDst
->cx
, himlDst
->cy
,
532 himlSrc
->hdcMask
, ptSrc
.x
, ptSrc
.y
, himlSrc
->cx
, himlSrc
->cy
,
540 /*************************************************************************
541 * ImageList_Create [COMCTL32.@]
543 * Creates a new image list.
546 * cx [I] image height
548 * flags [I] creation flags
549 * cInitial [I] initial number of images in the image list
550 * cGrow [I] number of images by which image list grows
553 * Success: Handle to the created image list
557 ImageList_Create (INT cx
, INT cy
, UINT flags
,
558 INT cInitial
, INT cGrow
)
563 UINT ilc
= (flags
& 0xFE);
564 static const WORD aBitBlend25
[] =
565 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
567 static const WORD aBitBlend50
[] =
568 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
570 TRACE("(%d %d 0x%x %d %d)\n", cx
, cy
, flags
, cInitial
, cGrow
);
572 himl
= (HIMAGELIST
)Alloc (sizeof(struct _IMAGELIST
));
576 cGrow
= (cGrow
< 4) ? 4 : (cGrow
+ 3) & ~3;
578 himl
->magic
= IMAGELIST_MAGIC
;
582 himl
->cMaxImage
= cInitial
+ cGrow
;
583 himl
->cInitial
= cInitial
;
585 himl
->clrFg
= CLR_DEFAULT
;
586 himl
->clrBk
= CLR_NONE
;
588 /* initialize overlay mask indices */
589 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
590 himl
->nOvlIdx
[nCount
] = -1;
592 /* Create Image & Mask DCs */
593 himl
->hdcImage
= CreateCompatibleDC (0);
596 if (himl
->flags
& ILC_MASK
){
597 himl
->hdcMask
= CreateCompatibleDC(0);
602 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
603 if (ilc
== ILC_COLOR
)
606 if (ilc
>= ILC_COLOR4
&& ilc
<= ILC_COLOR32
)
607 himl
->uBitsPixel
= ilc
;
609 himl
->uBitsPixel
= (UINT
)GetDeviceCaps (himl
->hdcImage
, BITSPIXEL
);
611 if (himl
->cMaxImage
> 0) {
612 himl
->hbmImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, cx
* himl
->cMaxImage
, cy
);
613 SelectObject(himl
->hdcImage
, himl
->hbmImage
);
617 if ((himl
->cMaxImage
> 0) && (himl
->flags
& ILC_MASK
)) {
619 CreateBitmap (himl
->cx
* himl
->cMaxImage
, himl
->cy
,
621 if (himl
->hbmMask
== 0) {
622 ERR("Error creating mask bitmap!\n");
625 SelectObject(himl
->hdcMask
, himl
->hbmMask
);
630 /* create blending brushes */
631 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend25
);
632 himl
->hbrBlend25
= CreatePatternBrush (hbmTemp
);
633 DeleteObject (hbmTemp
);
635 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend50
);
636 himl
->hbrBlend50
= CreatePatternBrush (hbmTemp
);
637 DeleteObject (hbmTemp
);
639 TRACE("created imagelist %p\n", himl
);
643 if (himl
) ImageList_Destroy(himl
);
648 /*************************************************************************
649 * ImageList_Destroy [COMCTL32.@]
651 * Destroys an image list.
654 * himl [I] handle to image list
662 ImageList_Destroy (HIMAGELIST himl
)
667 /* delete image bitmaps */
669 DeleteObject (himl
->hbmImage
);
671 DeleteObject (himl
->hbmMask
);
673 /* delete image & mask DCs */
675 DeleteDC(himl
->hdcImage
);
677 DeleteDC(himl
->hdcMask
);
679 /* delete blending brushes */
680 if (himl
->hbrBlend25
)
681 DeleteObject (himl
->hbrBlend25
);
682 if (himl
->hbrBlend50
)
683 DeleteObject (himl
->hbrBlend50
);
685 ZeroMemory(himl
, sizeof(*himl
));
692 /*************************************************************************
693 * ImageList_DragEnter [COMCTL32.@]
695 * Locks window update and displays the drag image at the given position.
698 * hwndLock [I] handle of the window that owns the drag image.
699 * x [I] X position of the drag image.
700 * y [I] Y position of the drag image.
707 * The position of the drag image is relative to the window, not
712 ImageList_DragEnter (HWND hwndLock
, INT x
, INT y
)
714 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock
, x
, y
);
716 if (!is_valid(InternalDrag
.himl
))
720 InternalDrag
.hwnd
= hwndLock
;
722 InternalDrag
.hwnd
= GetDesktopWindow ();
727 /* draw the drag image and save the background */
728 if (!ImageList_DragShowNolock(TRUE
)) {
736 /*************************************************************************
737 * ImageList_DragLeave [COMCTL32.@]
739 * Unlocks window update and hides the drag image.
742 * hwndLock [I] handle of the window that owns the drag image.
750 ImageList_DragLeave (HWND hwndLock
)
752 /* As we don't save drag info in the window this can lead to problems if
753 an app does not supply the same window as DragEnter */
755 InternalDrag.hwnd = hwndLock;
757 InternalDrag.hwnd = GetDesktopWindow (); */
759 hwndLock
= GetDesktopWindow();
760 if(InternalDrag
.hwnd
!= hwndLock
)
761 FIXME("DragLeave hWnd != DragEnter hWnd\n");
763 ImageList_DragShowNolock (FALSE
);
769 /*************************************************************************
770 * ImageList_InternalDragDraw [Internal]
772 * Draws the drag image.
775 * hdc [I] device context to draw into.
776 * x [I] X position of the drag image.
777 * y [I] Y position of the drag image.
784 * The position of the drag image is relative to the window, not
790 ImageList_InternalDragDraw (HDC hdc
, INT x
, INT y
)
792 IMAGELISTDRAWPARAMS imldp
;
794 ZeroMemory (&imldp
, sizeof(imldp
));
795 imldp
.cbSize
= sizeof(imldp
);
796 imldp
.himl
= InternalDrag
.himl
;
801 imldp
.rgbBk
= CLR_DEFAULT
;
802 imldp
.rgbFg
= CLR_DEFAULT
;
803 imldp
.fStyle
= ILD_NORMAL
;
804 imldp
.fState
= ILS_ALPHA
;
807 /* FIXME: instead of using the alpha blending, we should
808 * create a 50% mask, and draw it semitransparantly that way */
809 ImageList_DrawIndirect (&imldp
);
812 /*************************************************************************
813 * ImageList_DragMove [COMCTL32.@]
815 * Moves the drag image.
818 * x [I] X position of the drag image.
819 * y [I] Y position of the drag image.
826 * The position of the drag image is relative to the window, not
830 * The drag image should be drawn semitransparent.
834 ImageList_DragMove (INT x
, INT y
)
836 TRACE("(x=%d y=%d)\n", x
, y
);
838 if (!is_valid(InternalDrag
.himl
))
841 /* draw/update the drag image */
842 if (InternalDrag
.bShow
) {
846 HBITMAP hbmOffScreen
;
847 INT origNewX
, origNewY
;
848 INT origOldX
, origOldY
;
849 INT origRegX
, origRegY
;
850 INT sizeRegX
, sizeRegY
;
853 /* calculate the update region */
854 origNewX
= x
- InternalDrag
.dxHotspot
;
855 origNewY
= y
- InternalDrag
.dyHotspot
;
856 origOldX
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
857 origOldY
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
858 origRegX
= min(origNewX
, origOldX
);
859 origRegY
= min(origNewY
, origOldY
);
860 sizeRegX
= InternalDrag
.himl
->cx
+ abs(x
- InternalDrag
.x
);
861 sizeRegY
= InternalDrag
.himl
->cy
+ abs(y
- InternalDrag
.y
);
863 hdcDrag
= GetDCEx(InternalDrag
.hwnd
, 0,
864 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
865 hdcOffScreen
= CreateCompatibleDC(hdcDrag
);
866 hdcBg
= CreateCompatibleDC(hdcDrag
);
868 hbmOffScreen
= CreateCompatibleBitmap(hdcDrag
, sizeRegX
, sizeRegY
);
869 SelectObject(hdcOffScreen
, hbmOffScreen
);
870 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
872 /* get the actual background of the update region */
873 BitBlt(hdcOffScreen
, 0, 0, sizeRegX
, sizeRegY
, hdcDrag
,
874 origRegX
, origRegY
, SRCCOPY
);
875 /* erase the old image */
876 BitBlt(hdcOffScreen
, origOldX
- origRegX
, origOldY
- origRegY
,
877 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
, hdcBg
, 0, 0,
879 /* save the background */
880 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
881 hdcOffScreen
, origNewX
- origRegX
, origNewY
- origRegY
, SRCCOPY
);
883 ImageList_InternalDragDraw(hdcOffScreen
, origNewX
- origRegX
,
884 origNewY
- origRegY
);
885 /* draw the update region to the screen */
886 BitBlt(hdcDrag
, origRegX
, origRegY
, sizeRegX
, sizeRegY
,
887 hdcOffScreen
, 0, 0, SRCCOPY
);
890 DeleteDC(hdcOffScreen
);
891 DeleteObject(hbmOffScreen
);
892 ReleaseDC(InternalDrag
.hwnd
, hdcDrag
);
895 /* update the image position */
903 /*************************************************************************
904 * ImageList_DragShowNolock [COMCTL32.@]
906 * Shows or hides the drag image.
909 * bShow [I] TRUE shows the drag image, FALSE hides it.
916 * The drag image should be drawn semitransparent.
920 ImageList_DragShowNolock (BOOL bShow
)
926 if (!is_valid(InternalDrag
.himl
))
929 TRACE("bShow=0x%X!\n", bShow
);
931 /* DragImage is already visible/hidden */
932 if ((InternalDrag
.bShow
&& bShow
) || (!InternalDrag
.bShow
&& !bShow
)) {
936 /* position of the origin of the DragImage */
937 x
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
938 y
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
940 hdcDrag
= GetDCEx (InternalDrag
.hwnd
, 0,
941 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
946 hdcBg
= CreateCompatibleDC(hdcDrag
);
947 if (!InternalDrag
.hbmBg
) {
948 InternalDrag
.hbmBg
= CreateCompatibleBitmap(hdcDrag
,
949 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
);
951 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
954 /* save the background */
955 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
956 hdcDrag
, x
, y
, SRCCOPY
);
958 ImageList_InternalDragDraw(hdcDrag
, x
, y
);
961 BitBlt(hdcDrag
, x
, y
, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
962 hdcBg
, 0, 0, SRCCOPY
);
965 InternalDrag
.bShow
= !InternalDrag
.bShow
;
968 ReleaseDC (InternalDrag
.hwnd
, hdcDrag
);
973 /*************************************************************************
974 * ImageList_Draw [COMCTL32.@]
979 * himl [I] handle to image list
981 * hdc [I] handle to device context
984 * fStyle [I] drawing flags
995 ImageList_Draw (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
, UINT fStyle
)
997 return ImageList_DrawEx (himl
, i
, hdc
, x
, y
, 0, 0,
998 CLR_DEFAULT
, CLR_DEFAULT
, fStyle
);
1002 /*************************************************************************
1003 * ImageList_DrawEx [COMCTL32.@]
1005 * Draws an image and allows to use extended drawing features.
1008 * himl [I] handle to image list
1010 * hdc [I] handle to device context
1015 * rgbBk [I] background color
1016 * rgbFg [I] foreground color
1017 * fStyle [I] drawing flags
1024 * Calls ImageList_DrawIndirect.
1027 * ImageList_DrawIndirect.
1031 ImageList_DrawEx (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
,
1032 INT dx
, INT dy
, COLORREF rgbBk
, COLORREF rgbFg
,
1035 IMAGELISTDRAWPARAMS imldp
;
1037 ZeroMemory (&imldp
, sizeof(imldp
));
1038 imldp
.cbSize
= sizeof(imldp
);
1046 imldp
.rgbBk
= rgbBk
;
1047 imldp
.rgbFg
= rgbFg
;
1048 imldp
.fStyle
= fStyle
;
1050 return ImageList_DrawIndirect (&imldp
);
1054 /*************************************************************************
1055 * ImageList_DrawIndirect [COMCTL32.@]
1057 * Draws an image using various parameters specified in pimldp.
1060 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1068 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS
*pimldp
)
1070 INT cx
, cy
, nOvlIdx
;
1071 DWORD fState
, dwRop
;
1073 COLORREF oldImageBk
, oldImageFg
;
1074 HDC hImageDC
, hImageListDC
, hMaskListDC
;
1075 HBITMAP hImageBmp
, hOldImageBmp
, hBlendMaskBmp
;
1076 BOOL bIsTransparent
, bBlend
, bResult
= FALSE
, bMask
;
1080 if (!pimldp
|| !(himl
= pimldp
->himl
)) return FALSE
;
1081 if (!is_valid(himl
)) return FALSE
;
1082 if ((pimldp
->i
< 0) || (pimldp
->i
>= himl
->cCurImage
)) return FALSE
;
1084 imagelist_point_from_index( himl
, pimldp
->i
, &pt
);
1085 pt
.x
+= pimldp
->xBitmap
;
1086 pt
.y
+= pimldp
->yBitmap
;
1088 fState
= pimldp
->cbSize
< sizeof(IMAGELISTDRAWPARAMS
) ? ILS_NORMAL
: pimldp
->fState
;
1089 fStyle
= pimldp
->fStyle
& ~ILD_OVERLAYMASK
;
1090 cx
= (pimldp
->cx
== 0) ? himl
->cx
: pimldp
->cx
;
1091 cy
= (pimldp
->cy
== 0) ? himl
->cy
: pimldp
->cy
;
1093 bIsTransparent
= (fStyle
& ILD_TRANSPARENT
);
1094 if( pimldp
->rgbBk
== CLR_NONE
)
1095 bIsTransparent
= TRUE
;
1096 if( ( pimldp
->rgbBk
== CLR_DEFAULT
) && ( himl
->clrBk
== CLR_NONE
) )
1097 bIsTransparent
= TRUE
;
1098 bMask
= (himl
->flags
& ILC_MASK
) && (fStyle
& ILD_MASK
) ;
1099 bBlend
= (fStyle
& (ILD_BLEND25
| ILD_BLEND50
) ) && !bMask
;
1101 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1102 himl
, himl
->hbmMask
, pimldp
->i
, pimldp
->x
, pimldp
->y
, cx
, cy
);
1104 /* we will use these DCs to access the images and masks in the ImageList */
1105 hImageListDC
= himl
->hdcImage
;
1106 hMaskListDC
= himl
->hdcMask
;
1108 /* these will accumulate the image and mask for the image we're drawing */
1109 hImageDC
= CreateCompatibleDC( pimldp
->hdcDst
);
1110 hImageBmp
= CreateCompatibleBitmap( pimldp
->hdcDst
, cx
, cy
);
1111 hBlendMaskBmp
= bBlend
? CreateBitmap(cx
, cy
, 1, 1, NULL
) : 0;
1113 /* Create a compatible DC. */
1114 if (!hImageListDC
|| !hImageDC
|| !hImageBmp
||
1115 (bBlend
&& !hBlendMaskBmp
) || (himl
->hbmMask
&& !hMaskListDC
))
1118 hOldImageBmp
= SelectObject(hImageDC
, hImageBmp
);
1121 * To obtain a transparent look, background color should be set
1122 * to white and foreground color to black when blting the
1125 oldImageFg
= SetTextColor( hImageDC
, RGB( 0, 0, 0 ) );
1126 oldImageBk
= SetBkColor( hImageDC
, RGB( 0xff, 0xff, 0xff ) );
1129 * Draw the initial image
1132 if (himl
->hbmMask
) {
1134 hOldBrush
= SelectObject (hImageDC
, CreateSolidBrush (GetTextColor(pimldp
->hdcDst
)));
1135 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1136 BitBlt(hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, SRCPAINT
);
1137 DeleteObject (SelectObject (hImageDC
, hOldBrush
));
1138 if( bIsTransparent
)
1140 BitBlt ( pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hImageDC
, 0, 0, SRCAND
);
1145 HBRUSH hOldBrush
= SelectObject (hImageDC
, GetStockObject(BLACK_BRUSH
));
1146 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1147 SelectObject(hImageDC
, hOldBrush
);
1150 /* blend the image with the needed solid background */
1151 COLORREF colour
= RGB(0,0,0);
1154 if( !bIsTransparent
)
1156 colour
= pimldp
->rgbBk
;
1157 if( colour
== CLR_DEFAULT
)
1158 colour
= himl
->clrBk
;
1159 if( colour
== CLR_NONE
)
1160 colour
= GetBkColor(pimldp
->hdcDst
);
1163 hOldBrush
= SelectObject (hImageDC
, CreateSolidBrush (colour
));
1164 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1165 BitBlt( hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, SRCAND
);
1166 BitBlt( hImageDC
, 0, 0, cx
, cy
, hImageListDC
, pt
.x
, pt
.y
, SRCPAINT
);
1167 DeleteObject (SelectObject (hImageDC
, hOldBrush
));
1170 /* Time for blending, if required */
1172 HBRUSH hBlendBrush
, hOldBrush
;
1173 COLORREF clrBlend
= pimldp
->rgbFg
;
1174 HDC hBlendMaskDC
= hImageListDC
;
1177 /* Create the blend Mask */
1178 hOldBitmap
= SelectObject(hBlendMaskDC
, hBlendMaskBmp
);
1179 hBlendBrush
= fStyle
& ILD_BLEND50
? himl
->hbrBlend50
: himl
->hbrBlend25
;
1180 hOldBrush
= (HBRUSH
) SelectObject(hBlendMaskDC
, hBlendBrush
);
1181 PatBlt(hBlendMaskDC
, 0, 0, cx
, cy
, PATCOPY
);
1182 SelectObject(hBlendMaskDC
, hOldBrush
);
1184 /* Modify the blend mask if an Image Mask exist */
1186 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, 0x220326); /* NOTSRCAND */
1187 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, NOTSRCCOPY
);
1190 /* now apply blend to the current image given the BlendMask */
1191 if (clrBlend
== CLR_DEFAULT
) clrBlend
= GetSysColor (COLOR_HIGHLIGHT
);
1192 else if (clrBlend
== CLR_NONE
) clrBlend
= GetTextColor (pimldp
->hdcDst
);
1193 hOldBrush
= (HBRUSH
) SelectObject (hImageDC
, CreateSolidBrush(clrBlend
));
1194 BitBlt (hImageDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, 0xB8074A); /* PSDPxax */
1195 DeleteObject(SelectObject(hImageDC
, hOldBrush
));
1196 SelectObject(hBlendMaskDC
, hOldBitmap
);
1199 /* Now do the overlay image, if any */
1200 nOvlIdx
= (pimldp
->fStyle
& ILD_OVERLAYMASK
) >> 8;
1201 if ( (nOvlIdx
>= 1) && (nOvlIdx
<= MAX_OVERLAYIMAGE
)) {
1202 nOvlIdx
= himl
->nOvlIdx
[nOvlIdx
- 1];
1203 if ((nOvlIdx
>= 0) && (nOvlIdx
< himl
->cCurImage
)) {
1204 const INT ox
= himl
->cx
* nOvlIdx
+ pimldp
->xBitmap
;
1205 if (himl
->hbmMask
&& !(fStyle
& ILD_IMAGE
))
1206 BitBlt (hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, ox
, pt
.x
, SRCAND
);
1207 BitBlt (hImageDC
, 0, 0, cx
, cy
, hImageListDC
, ox
, pt
.y
, SRCPAINT
);
1211 if (fState
& ILS_SATURATE
) FIXME("ILS_SATURATE: unimplemented!\n");
1212 if (fState
& ILS_GLOW
) FIXME("ILS_GLOW: unimplemented!\n");
1213 if (fState
& ILS_SHADOW
) FIXME("ILS_SHADOW: unimplemented!\n");
1214 if (fState
& ILS_ALPHA
) FIXME("ILS_ALPHA: unimplemented!\n");
1216 if (fStyle
& ILD_PRESERVEALPHA
) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1217 if (fStyle
& ILD_SCALE
) FIXME("ILD_SCALE: unimplemented!\n");
1218 if (fStyle
& ILD_DPISCALE
) FIXME("ILD_DPISCALE: unimplemented!\n");
1220 /* now copy the image to the screen */
1222 if (himl
->hbmMask
&& bIsTransparent
) {
1223 COLORREF oldDstFg
= SetTextColor(pimldp
->hdcDst
, RGB( 0, 0, 0 ) );
1224 COLORREF oldDstBk
= SetBkColor(pimldp
->hdcDst
, RGB( 0xff, 0xff, 0xff ));
1225 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hMaskListDC
, pt
.x
, pt
.y
, SRCAND
);
1226 SetBkColor(pimldp
->hdcDst
, oldDstBk
);
1227 SetTextColor(pimldp
->hdcDst
, oldDstFg
);
1230 if (fStyle
& ILD_ROP
) dwRop
= pimldp
->dwRop
;
1231 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hImageDC
, 0, 0, dwRop
);
1235 /* cleanup the mess */
1236 SetBkColor(hImageDC
, oldImageBk
);
1237 SetTextColor(hImageDC
, oldImageFg
);
1238 SelectObject(hImageDC
, hOldImageBmp
);
1240 DeleteObject(hBlendMaskBmp
);
1241 DeleteObject(hImageBmp
);
1248 /*************************************************************************
1249 * ImageList_Duplicate [COMCTL32.@]
1251 * Duplicates an image list.
1254 * himlSrc [I] source image list handle
1257 * Success: Handle of duplicated image list.
1262 ImageList_Duplicate (HIMAGELIST himlSrc
)
1266 if (!is_valid(himlSrc
)) {
1267 ERR("Invalid image list handle!\n");
1271 himlDst
= ImageList_Create (himlSrc
->cx
, himlSrc
->cy
, himlSrc
->flags
,
1272 himlSrc
->cInitial
, himlSrc
->cGrow
);
1276 BitBlt (himlDst
->hdcImage
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
, himlSrc
->cy
,
1277 himlSrc
->hdcImage
, 0, 0, SRCCOPY
);
1279 if (himlDst
->hbmMask
)
1280 BitBlt (himlDst
->hdcMask
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
, himlSrc
->cy
,
1281 himlSrc
->hdcMask
, 0, 0, SRCCOPY
);
1283 himlDst
->cCurImage
= himlSrc
->cCurImage
;
1284 himlDst
->cMaxImage
= himlSrc
->cMaxImage
;
1290 /*************************************************************************
1291 * ImageList_EndDrag [COMCTL32.@]
1293 * Finishes a drag operation.
1304 ImageList_EndDrag (void)
1306 /* cleanup the InternalDrag struct */
1307 InternalDrag
.hwnd
= 0;
1308 ImageList_Destroy (InternalDrag
.himl
);
1309 InternalDrag
.himl
= 0;
1312 InternalDrag
.dxHotspot
= 0;
1313 InternalDrag
.dyHotspot
= 0;
1314 InternalDrag
.bShow
= FALSE
;
1315 DeleteObject(InternalDrag
.hbmBg
);
1316 InternalDrag
.hbmBg
= 0;
1320 /*************************************************************************
1321 * ImageList_GetBkColor [COMCTL32.@]
1323 * Returns the background color of an image list.
1326 * himl [I] Image list handle.
1329 * Success: background color
1334 ImageList_GetBkColor (HIMAGELIST himl
)
1336 return himl
? himl
->clrBk
: CLR_NONE
;
1340 /*************************************************************************
1341 * ImageList_GetDragImage [COMCTL32.@]
1343 * Returns the handle to the internal drag image list.
1346 * ppt [O] Pointer to the drag position. Can be NULL.
1347 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1350 * Success: Handle of the drag image list.
1355 ImageList_GetDragImage (POINT
*ppt
, POINT
*pptHotspot
)
1357 if (is_valid(InternalDrag
.himl
)) {
1359 ppt
->x
= InternalDrag
.x
;
1360 ppt
->y
= InternalDrag
.y
;
1363 pptHotspot
->x
= InternalDrag
.dxHotspot
;
1364 pptHotspot
->y
= InternalDrag
.dyHotspot
;
1366 return (InternalDrag
.himl
);
1373 /*************************************************************************
1374 * ImageList_GetFlags [COMCTL32.@]
1376 * Gets the flags of the specified image list.
1379 * himl [I] Handle to image list
1389 ImageList_GetFlags(HIMAGELIST himl
)
1391 FIXME("(%p):empty stub\n", himl
);
1396 /*************************************************************************
1397 * ImageList_GetIcon [COMCTL32.@]
1399 * Creates an icon from a masked image of an image list.
1402 * himl [I] handle to image list
1404 * flags [I] drawing style flags
1407 * Success: icon handle
1412 ImageList_GetIcon (HIMAGELIST himl
, INT i
, UINT fStyle
)
1416 HBITMAP hOldDstBitmap
;
1419 TRACE("%p %d %d\n", himl
, i
, fStyle
);
1420 if (!is_valid(himl
) || (i
< 0) || (i
>= himl
->cCurImage
)) return NULL
;
1426 /* create colour bitmap */
1428 ii
.hbmColor
= CreateCompatibleBitmap(hdcDst
, himl
->cx
, himl
->cy
);
1429 ReleaseDC(0, hdcDst
);
1431 hdcDst
= CreateCompatibleDC(0);
1434 ii
.hbmMask
= CreateBitmap (himl
->cx
, himl
->cy
, 1, 1, NULL
);
1435 hOldDstBitmap
= SelectObject (hdcDst
, ii
.hbmMask
);
1436 if (himl
->hbmMask
) {
1437 BitBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
,
1438 himl
->hdcMask
, i
* himl
->cx
, 0, SRCCOPY
);
1441 PatBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
, BLACKNESS
);
1444 SelectObject (hdcDst
, ii
.hbmColor
);
1445 BitBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
,
1446 himl
->hdcImage
, i
* himl
->cx
, 0, SRCCOPY
);
1449 * CreateIconIndirect requires us to deselect the bitmaps from
1450 * the DCs before calling
1452 SelectObject(hdcDst
, hOldDstBitmap
);
1454 hIcon
= CreateIconIndirect (&ii
);
1456 DeleteObject (ii
.hbmMask
);
1457 DeleteObject (ii
.hbmColor
);
1464 /*************************************************************************
1465 * ImageList_GetIconSize [COMCTL32.@]
1467 * Retrieves the size of an image in an image list.
1470 * himl [I] handle to image list
1471 * cx [O] pointer to the image width.
1472 * cy [O] pointer to the image height.
1479 * All images in an image list have the same size.
1483 ImageList_GetIconSize (HIMAGELIST himl
, INT
*cx
, INT
*cy
)
1485 if (!is_valid(himl
))
1487 if ((himl
->cx
<= 0) || (himl
->cy
<= 0))
1499 /*************************************************************************
1500 * ImageList_GetImageCount [COMCTL32.@]
1502 * Returns the number of images in an image list.
1505 * himl [I] handle to image list
1508 * Success: Number of images.
1513 ImageList_GetImageCount (HIMAGELIST himl
)
1515 if (!is_valid(himl
))
1518 return himl
->cCurImage
;
1522 /*************************************************************************
1523 * ImageList_GetImageInfo [COMCTL32.@]
1525 * Returns information about an image in an image list.
1528 * himl [I] handle to image list
1530 * pImageInfo [O] pointer to the image information
1538 ImageList_GetImageInfo (HIMAGELIST himl
, INT i
, IMAGEINFO
*pImageInfo
)
1542 if (!is_valid(himl
) || (pImageInfo
== NULL
))
1544 if ((i
< 0) || (i
>= himl
->cCurImage
))
1547 pImageInfo
->hbmImage
= himl
->hbmImage
;
1548 pImageInfo
->hbmMask
= himl
->hbmMask
;
1550 imagelist_point_from_index( himl
, i
, &pt
);
1551 pImageInfo
->rcImage
.top
= pt
.y
;
1552 pImageInfo
->rcImage
.bottom
= pt
.y
+ himl
->cy
;
1553 pImageInfo
->rcImage
.left
= pt
.x
;
1554 pImageInfo
->rcImage
.right
= pt
.x
+ himl
->cx
;
1560 /*************************************************************************
1561 * ImageList_GetImageRect [COMCTL32.@]
1563 * Retrieves the rectangle of the specified image in an image list.
1566 * himl [I] handle to image list
1568 * lpRect [O] pointer to the image rectangle
1575 * This is an UNDOCUMENTED function!!!
1579 ImageList_GetImageRect (HIMAGELIST himl
, INT i
, LPRECT lpRect
)
1583 if (!is_valid(himl
) || (lpRect
== NULL
))
1585 if ((i
< 0) || (i
>= himl
->cCurImage
))
1588 imagelist_point_from_index( himl
, i
, &pt
);
1589 lpRect
->left
= pt
.x
;
1591 lpRect
->right
= pt
.x
+ himl
->cx
;
1592 lpRect
->bottom
= pt
.y
+ himl
->cy
;
1598 /*************************************************************************
1599 * ImageList_LoadImage [COMCTL32.@]
1600 * ImageList_LoadImageA [COMCTL32.@]
1602 * Creates an image list from a bitmap, icon or cursor.
1604 * See ImageList_LoadImageW.
1608 ImageList_LoadImageA (HINSTANCE hi
, LPCSTR lpbmp
, INT cx
, INT cGrow
,
1609 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1616 return ImageList_LoadImageW(hi
, (LPCWSTR
)lpbmp
, cx
, cGrow
, clrMask
,
1619 len
= MultiByteToWideChar(CP_ACP
, 0, lpbmp
, -1, NULL
, 0);
1620 lpbmpW
= Alloc(len
* sizeof(WCHAR
));
1621 MultiByteToWideChar(CP_ACP
, 0, lpbmp
, -1, lpbmpW
, len
);
1623 himl
= ImageList_LoadImageW(hi
, lpbmpW
, cx
, cGrow
, clrMask
, uType
, uFlags
);
1629 /*************************************************************************
1630 * ImageList_LoadImageW [COMCTL32.@]
1632 * Creates an image list from a bitmap, icon or cursor.
1635 * hi [I] instance handle
1636 * lpbmp [I] name or id of the image
1637 * cx [I] width of each image
1638 * cGrow [I] number of images to expand
1639 * clrMask [I] mask color
1640 * uType [I] type of image to load
1641 * uFlags [I] loading flags
1644 * Success: handle to the loaded image list
1652 ImageList_LoadImageW (HINSTANCE hi
, LPCWSTR lpbmp
, INT cx
, INT cGrow
,
1653 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1655 HIMAGELIST himl
= NULL
;
1659 handle
= LoadImageW (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1661 ERR("Error loading image!\n");
1665 if (uType
== IMAGE_BITMAP
) {
1667 GetObjectW (handle
, sizeof(BITMAP
), &bmp
);
1669 /* To match windows behavior, if cx is set to zero and
1670 the flag DI_DEFAULTSIZE is specified, cx becomes the
1671 system metric value for icons. If the flag is not specified
1672 the function sets the size to the height of the bitmap */
1675 if (uFlags
& DI_DEFAULTSIZE
)
1676 cx
= GetSystemMetrics (SM_CXICON
);
1681 nImageCount
= bmp
.bmWidth
/ cx
;
1683 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1684 nImageCount
, cGrow
);
1686 DeleteObject (handle
);
1689 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1691 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1695 GetIconInfo (handle
, &ii
);
1696 GetObjectW (ii
.hbmColor
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1697 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1698 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1700 DeleteObject (ii
.hbmColor
);
1701 DeleteObject (ii
.hbmMask
);
1702 DeleteObject (handle
);
1705 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1706 DeleteObject (ii
.hbmColor
);
1707 DeleteObject (ii
.hbmMask
);
1710 DeleteObject (handle
);
1716 /*************************************************************************
1717 * ImageList_Merge [COMCTL32.@]
1719 * Create an image list containing a merged image from two image lists.
1722 * himl1 [I] handle to first image list
1723 * i1 [I] first image index
1724 * himl2 [I] handle to second image list
1725 * i2 [I] second image index
1726 * dx [I] X offset of the second image relative to the first.
1727 * dy [I] Y offset of the second image relative to the first.
1730 * Success: The newly created image list. It contains a single image
1731 * consisting of the second image merged with the first.
1732 * Failure: NULL, if either himl1 or himl2 are invalid.
1735 * - The returned image list should be deleted by the caller using
1736 * ImageList_Destroy() when it is no longer required.
1737 * - If either i1 or i2 are not valid image indices they will be treated
1741 ImageList_Merge (HIMAGELIST himl1
, INT i1
, HIMAGELIST himl2
, INT i2
,
1744 HIMAGELIST himlDst
= NULL
;
1746 INT xOff1
, yOff1
, xOff2
, yOff2
;
1749 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1
, i1
, himl2
,
1752 if (!is_valid(himl1
) || !is_valid(himl2
))
1756 cxDst
= max (himl1
->cx
, dx
+ himl2
->cx
);
1761 cxDst
= max (himl2
->cx
, himl1
->cx
- dx
);
1766 cxDst
= max (himl1
->cx
, himl2
->cx
);
1772 cyDst
= max (himl1
->cy
, dy
+ himl2
->cy
);
1777 cyDst
= max (himl2
->cy
, himl1
->cy
- dy
);
1782 cyDst
= max (himl1
->cy
, himl2
->cy
);
1787 himlDst
= ImageList_Create (cxDst
, cyDst
, ILC_MASK
| ILC_COLOR
, 1, 1);
1791 nX1
= i1
* himl1
->cx
;
1792 nX2
= i2
* himl2
->cx
;
1795 BitBlt (himlDst
->hdcImage
, 0, 0, cxDst
, cyDst
, himl1
->hdcImage
, 0, 0, BLACKNESS
);
1796 if (i1
>= 0 && i1
< himl1
->cCurImage
)
1797 BitBlt (himlDst
->hdcImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
, himl1
->hdcImage
, nX1
, 0, SRCCOPY
);
1798 if (i2
>= 0 && i2
< himl2
->cCurImage
)
1800 BitBlt (himlDst
->hdcImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcMask
, nX2
, 0, SRCAND
);
1801 BitBlt (himlDst
->hdcImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcImage
, nX2
, 0, SRCPAINT
);
1805 BitBlt (himlDst
->hdcMask
, 0, 0, cxDst
, cyDst
, himl1
->hdcMask
, 0, 0, WHITENESS
);
1806 if (i1
>= 0 && i1
< himl1
->cCurImage
)
1807 BitBlt (himlDst
->hdcMask
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
, himl1
->hdcMask
, nX1
, 0, SRCCOPY
);
1808 if (i2
>= 0 && i2
< himl2
->cCurImage
)
1809 BitBlt (himlDst
->hdcMask
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcMask
, nX2
, 0, SRCAND
);
1811 himlDst
->cCurImage
= 1;
1818 /* helper for _read_bitmap currently unused */
1820 static int may_use_dibsection(HDC hdc
) {
1821 int bitspixel
= GetDeviceCaps(hdc
,BITSPIXEL
)*GetDeviceCaps(hdc
,PLANES
);
1826 return GetDeviceCaps(hdc
,CAPS1
) & C1_DIBENGINE
;
1830 /* helper for ImageList_Read, see comments below */
1831 static HBITMAP
_read_bitmap(LPSTREAM pstm
,int ilcFlag
,int cx
,int cy
) {
1832 HDC xdc
= 0, hBitmapDC
=0;
1833 BITMAPFILEHEADER bmfh
;
1834 BITMAPINFOHEADER bmih
;
1835 int bitsperpixel
,palspace
,longsperline
,width
,height
;
1836 LPBITMAPINFOHEADER bmihc
= NULL
;
1838 HBITMAP hbitmap
= 0, hDIB
= 0;
1841 if (!SUCCEEDED(IStream_Read ( pstm
, &bmfh
, sizeof(bmfh
), NULL
)) ||
1842 (bmfh
.bfType
!= (('M'<<8)|'B')) ||
1843 !SUCCEEDED(IStream_Read ( pstm
, &bmih
, sizeof(bmih
), NULL
)) ||
1844 (bmih
.biSize
!= sizeof(bmih
))
1848 bitsperpixel
= bmih
.biPlanes
* bmih
.biBitCount
;
1849 if (bitsperpixel
<=8)
1850 palspace
= (1<<bitsperpixel
)*sizeof(RGBQUAD
);
1853 width
= bmih
.biWidth
;
1854 height
= bmih
.biHeight
;
1855 bmihc
= (LPBITMAPINFOHEADER
)LocalAlloc(LMEM_ZEROINIT
,sizeof(bmih
)+palspace
);
1856 if (!bmihc
) goto ret1
;
1857 memcpy(bmihc
,&bmih
,sizeof(bmih
));
1858 longsperline
= ((width
*bitsperpixel
+31)&~0x1f)>>5;
1859 bmihc
->biSizeImage
= (longsperline
*height
)<<2;
1861 /* read the palette right after the end of the bitmapinfoheader */
1863 if (!SUCCEEDED(IStream_Read ( pstm
, bmihc
+1, palspace
, NULL
)))
1867 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1868 if ((bitsperpixel
>1) &&
1869 ((ilcFlag
!=ILC_COLORDDB
) && (!ilcFlag
|| may_use_dibsection(xdc
)))
1871 hbitmap
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1874 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1880 int i
,nwidth
,nheight
,nRows
;
1882 nwidth
= width
*(height
/cy
);
1884 nRows
= (height
/cy
);
1886 if (bitsperpixel
==1)
1887 hbitmap
= CreateBitmap(nwidth
,nheight
,1,1,NULL
);
1889 hbitmap
= CreateCompatibleBitmap(xdc
,nwidth
,nheight
);
1891 hDIB
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1894 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1897 hBitmapDC
= CreateCompatibleDC(0);
1898 SelectObject(hBitmapDC
, hbitmap
);
1900 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1901 /* Do not forget that windows bitmaps are bottom->top */
1902 TRACE("nRows=%d\n", nRows
);
1903 for (i
=0; i
< nRows
; i
++){
1904 StretchDIBits(hBitmapDC
, width
*i
, 0, width
, cy
, 0, cy
*(nRows
-1-i
), width
, cy
, bits
,
1905 (BITMAPINFO
*)bmihc
, DIB_RGB_COLORS
, SRCCOPY
);
1911 if (xdc
) ReleaseDC(0,xdc
);
1912 if (bmihc
) LocalFree((HLOCAL
)bmihc
);
1913 if (hDIB
) DeleteObject(hDIB
);
1914 if (hBitmapDC
) DeleteDC(hBitmapDC
);
1917 DeleteObject(hbitmap
);
1924 /*************************************************************************
1925 * ImageList_Read [COMCTL32.@]
1927 * Reads an image list from a stream.
1930 * pstm [I] pointer to a stream
1933 * Success: handle to image list
1936 * The format is like this:
1937 * ILHEAD ilheadstruct;
1939 * for the color image part:
1940 * BITMAPFILEHEADER bmfh;
1941 * BITMAPINFOHEADER bmih;
1942 * only if it has a palette:
1943 * RGBQUAD rgbs[nr_of_paletted_colors];
1945 * BYTE colorbits[imagesize];
1947 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1948 * BITMAPFILEHEADER bmfh_mask;
1949 * BITMAPINFOHEADER bmih_mask;
1950 * only if it has a palette (it usually does not):
1951 * RGBQUAD rgbs[nr_of_paletted_colors];
1953 * BYTE maskbits[imagesize];
1955 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1956 * _read_bitmap needs to convert them.
1958 HIMAGELIST WINAPI
ImageList_Read (LPSTREAM pstm
)
1962 HBITMAP hbmColor
=0,hbmMask
=0;
1965 if (!SUCCEEDED(IStream_Read (pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
1967 if (ilHead
.usMagic
!= (('L' << 8) | 'I'))
1969 if (ilHead
.usVersion
!= 0x101) /* probably version? */
1973 FIXME(" ilHead.cCurImage = %d\n",ilHead
.cCurImage
);
1974 FIXME(" ilHead.cMaxImage = %d\n",ilHead
.cMaxImage
);
1975 FIXME(" ilHead.cGrow = %d\n",ilHead
.cGrow
);
1976 FIXME(" ilHead.cx = %d\n",ilHead
.cx
);
1977 FIXME(" ilHead.cy = %d\n",ilHead
.cy
);
1978 FIXME(" ilHead.flags = %x\n",ilHead
.flags
);
1979 FIXME(" ilHead.ovls[0] = %d\n",ilHead
.ovls
[0]);
1980 FIXME(" ilHead.ovls[1] = %d\n",ilHead
.ovls
[1]);
1981 FIXME(" ilHead.ovls[2] = %d\n",ilHead
.ovls
[2]);
1982 FIXME(" ilHead.ovls[3] = %d\n",ilHead
.ovls
[3]);
1985 hbmColor
= _read_bitmap(pstm
,ilHead
.flags
& ~ILC_MASK
,ilHead
.cx
,ilHead
.cy
);
1987 WARN("failed to read bitmap from stream\n");
1990 if (ilHead
.flags
& ILC_MASK
) {
1991 hbmMask
= _read_bitmap(pstm
,0,ilHead
.cx
,ilHead
.cy
);
1993 DeleteObject(hbmColor
);
1998 himl
= ImageList_Create (
2006 DeleteObject(hbmColor
);
2007 DeleteObject(hbmMask
);
2010 SelectObject(himl
->hdcImage
, hbmColor
);
2011 DeleteObject(himl
->hbmImage
);
2012 himl
->hbmImage
= hbmColor
;
2014 SelectObject(himl
->hdcMask
, hbmMask
);
2015 DeleteObject(himl
->hbmMask
);
2016 himl
->hbmMask
= hbmMask
;
2018 himl
->cCurImage
= ilHead
.cCurImage
;
2019 himl
->cMaxImage
= ilHead
.cMaxImage
;
2021 ImageList_SetBkColor(himl
,ilHead
.bkcolor
);
2023 ImageList_SetOverlayImage(himl
,ilHead
.ovls
[i
],i
+1);
2028 /*************************************************************************
2029 * ImageList_Remove [COMCTL32.@]
2031 * Removes an image from an image list
2034 * himl [I] image list handle
2043 ImageList_Remove (HIMAGELIST himl
, INT i
)
2045 HBITMAP hbmNewImage
, hbmNewMask
;
2049 TRACE("(himl=%p i=%d)\n", himl
, i
);
2051 if (!is_valid(himl
)) {
2052 ERR("Invalid image list handle!\n");
2056 if ((i
< -1) || (i
>= himl
->cCurImage
)) {
2057 TRACE("index out of range! %d\n", i
);
2063 if (himl
->cCurImage
== 0) {
2064 /* remove all on empty ImageList is allowed */
2065 TRACE("remove all on empty ImageList!\n");
2069 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2070 himl
->cCurImage
= 0;
2071 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2072 himl
->nOvlIdx
[nCount
] = -1;
2074 hbmNewImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
* himl
->cx
, himl
->cy
);
2075 SelectObject (himl
->hdcImage
, hbmNewImage
);
2076 DeleteObject (himl
->hbmImage
);
2077 himl
->hbmImage
= hbmNewImage
;
2079 if (himl
->hbmMask
) {
2080 hbmNewMask
= CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2082 SelectObject (himl
->hdcMask
, hbmNewMask
);
2083 DeleteObject (himl
->hbmMask
);
2084 himl
->hbmMask
= hbmNewMask
;
2088 /* delete one image */
2089 TRACE("Remove single image! %d\n", i
);
2091 /* create new bitmap(s) */
2092 nCount
= (himl
->cCurImage
+ himl
->cGrow
- 1);
2093 cxNew
= nCount
* himl
->cx
;
2095 TRACE(" - Number of images: %d / %d (Old/New)\n",
2096 himl
->cCurImage
, himl
->cCurImage
- 1);
2097 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2098 himl
->cMaxImage
, himl
->cCurImage
+ himl
->cGrow
- 1);
2100 hbmNewImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, cxNew
, himl
->cy
);
2103 hbmNewMask
= CreateBitmap (cxNew
, himl
->cy
, 1, 1, NULL
);
2105 hbmNewMask
= 0; /* Just to keep compiler happy! */
2107 hdcBmp
= CreateCompatibleDC (0);
2109 /* copy all images and masks prior to the "removed" image */
2111 TRACE("Pre image copy: Copy %d images\n", i
);
2113 SelectObject (hdcBmp
, hbmNewImage
);
2114 BitBlt (hdcBmp
, 0, 0, i
* himl
->cx
, himl
->cy
,
2115 himl
->hdcImage
, 0, 0, SRCCOPY
);
2117 if (himl
->hbmMask
) {
2118 SelectObject (hdcBmp
, hbmNewMask
);
2119 BitBlt (hdcBmp
, 0, 0, i
* himl
->cx
, himl
->cy
,
2120 himl
->hdcMask
, 0, 0, SRCCOPY
);
2124 /* copy all images and masks behind the removed image */
2125 if (i
< himl
->cCurImage
- 1) {
2126 TRACE("Post image copy!\n");
2127 SelectObject (hdcBmp
, hbmNewImage
);
2128 BitBlt (hdcBmp
, i
* himl
->cx
, 0, (himl
->cCurImage
- i
- 1) * himl
->cx
,
2129 himl
->cy
, himl
->hdcImage
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2131 if (himl
->hbmMask
) {
2132 SelectObject (hdcBmp
, hbmNewMask
);
2133 BitBlt (hdcBmp
, i
* himl
->cx
, 0,
2134 (himl
->cCurImage
- i
- 1) * himl
->cx
,
2135 himl
->cy
, himl
->hdcMask
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2141 /* delete old images and insert new ones */
2142 SelectObject (himl
->hdcImage
, hbmNewImage
);
2143 DeleteObject (himl
->hbmImage
);
2144 himl
->hbmImage
= hbmNewImage
;
2145 if (himl
->hbmMask
) {
2146 SelectObject (himl
->hdcMask
, hbmNewMask
);
2147 DeleteObject (himl
->hbmMask
);
2148 himl
->hbmMask
= hbmNewMask
;
2152 himl
->cMaxImage
= himl
->cCurImage
+ himl
->cGrow
;
2159 /*************************************************************************
2160 * ImageList_Replace [COMCTL32.@]
2162 * Replaces an image in an image list with a new image.
2165 * himl [I] handle to image list
2167 * hbmImage [I] handle to image bitmap
2168 * hbmMask [I] handle to mask bitmap. Can be NULL.
2176 ImageList_Replace (HIMAGELIST himl
, INT i
, HBITMAP hbmImage
,
2183 TRACE("%p %d %p %p\n", himl
, i
, hbmImage
, hbmMask
);
2185 if (!is_valid(himl
)) {
2186 ERR("Invalid image list handle!\n");
2190 if ((i
>= himl
->cMaxImage
) || (i
< 0)) {
2191 ERR("Invalid image index!\n");
2195 hdcImage
= CreateCompatibleDC (0);
2196 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2199 hOldBitmap
= SelectObject (hdcImage
, hbmImage
);
2201 StretchBlt (himl
->hdcImage
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2202 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2207 HBITMAP hOldBitmapTemp
;
2209 hdcTemp
= CreateCompatibleDC(0);
2210 hOldBitmapTemp
= SelectObject(hdcTemp
, hbmMask
);
2212 StretchBlt (himl
->hdcMask
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2213 hdcTemp
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2214 SelectObject(hdcTemp
, hOldBitmapTemp
);
2217 /* Remove the background from the image
2219 BitBlt (himl
->hdcImage
,
2220 i
*himl
->cx
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
2223 0x220326); /* NOTSRCAND */
2226 SelectObject (hdcImage
, hOldBitmap
);
2227 DeleteDC (hdcImage
);
2233 /*************************************************************************
2234 * ImageList_ReplaceIcon [COMCTL32.@]
2236 * Replaces an image in an image list using an icon.
2239 * himl [I] handle to image list
2241 * hIcon [I] handle to icon
2244 * Success: index of the replaced image
2249 ImageList_ReplaceIcon (HIMAGELIST himl
, INT i
, HICON hIcon
)
2259 TRACE("(%p %d %p)\n", himl
, i
, hIcon
);
2261 if (!is_valid(himl
)) {
2262 ERR("invalid image list\n");
2265 if ((i
>= himl
->cMaxImage
) || (i
< -1)) {
2266 ERR("invalid image index %d / %d\n", i
, himl
->cMaxImage
);
2270 hBestFitIcon
= CopyImage(
2273 LR_COPYFROMRESOURCE
);
2274 /* the above will fail if the icon wasn't loaded from a resource, so try
2275 * again without LR_COPYFROMRESOURCE flag */
2277 hBestFitIcon
= CopyImage(
2284 ret
= GetIconInfo (hBestFitIcon
, &ii
);
2286 DestroyIcon(hBestFitIcon
);
2290 if (ii
.hbmColor
== 0)
2292 ret
= GetObjectW (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2294 ERR("couldn't get mask bitmap info\n");
2296 DeleteObject (ii
.hbmColor
);
2298 DeleteObject (ii
.hbmMask
);
2299 DestroyIcon(hBestFitIcon
);
2304 if (himl
->cCurImage
+ 1 > himl
->cMaxImage
)
2305 IMAGELIST_InternalExpandBitmaps (himl
, 1, 0, 0);
2307 nIndex
= himl
->cCurImage
;
2313 hdcImage
= CreateCompatibleDC (0);
2314 TRACE("hdcImage=%p\n", hdcImage
);
2316 ERR("invalid hdcImage!\n");
2318 SetTextColor(himl
->hdcImage
, RGB(0,0,0));
2319 SetBkColor (himl
->hdcImage
, RGB(255,255,255));
2320 hbmOldSrc
= SelectObject (hdcImage
, ii
.hbmColor
);
2322 StretchBlt (himl
->hdcImage
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2323 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2325 if (himl
->hbmMask
) {
2326 SelectObject (hdcImage
, ii
.hbmMask
);
2327 StretchBlt (himl
->hdcMask
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2328 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2331 SelectObject (hdcImage
, hbmOldSrc
);
2333 DestroyIcon(hBestFitIcon
);
2335 DeleteDC (hdcImage
);
2337 DeleteObject (ii
.hbmColor
);
2339 DeleteObject (ii
.hbmMask
);
2341 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex
, himl
->cCurImage
);
2346 /*************************************************************************
2347 * ImageList_SetBkColor [COMCTL32.@]
2349 * Sets the background color of an image list.
2352 * himl [I] handle to image list
2353 * clrBk [I] background color
2356 * Success: previous background color
2361 ImageList_SetBkColor (HIMAGELIST himl
, COLORREF clrBk
)
2365 if (!is_valid(himl
))
2368 clrOldBk
= himl
->clrBk
;
2369 himl
->clrBk
= clrBk
;
2374 /*************************************************************************
2375 * ImageList_SetDragCursorImage [COMCTL32.@]
2377 * Combines the specified image with the current drag image
2380 * himlDrag [I] handle to drag image list
2381 * iDrag [I] drag image index
2382 * dxHotspot [I] X position of the hot spot
2383 * dyHotspot [I] Y position of the hot spot
2390 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2391 * to do with a hotspot but are only the offset of the origin of the new
2392 * image relative to the origin of the old image.
2394 * - When this function is called and the drag image is visible, a
2395 * short flickering occurs but this matches the Win9x behavior. It is
2396 * possible to fix the flickering using code like in ImageList_DragMove.
2400 ImageList_SetDragCursorImage (HIMAGELIST himlDrag
, INT iDrag
,
2401 INT dxHotspot
, INT dyHotspot
)
2403 HIMAGELIST himlTemp
;
2406 if (!is_valid(InternalDrag
.himl
) || !is_valid(himlDrag
))
2409 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2410 dxHotspot
, dyHotspot
, InternalDrag
.dxHotspot
, InternalDrag
.dyHotspot
);
2412 visible
= InternalDrag
.bShow
;
2414 himlTemp
= ImageList_Merge (InternalDrag
.himl
, 0, himlDrag
, iDrag
,
2415 dxHotspot
, dyHotspot
);
2418 /* hide the drag image */
2419 ImageList_DragShowNolock(FALSE
);
2421 if ((InternalDrag
.himl
->cx
!= himlTemp
->cx
) ||
2422 (InternalDrag
.himl
->cy
!= himlTemp
->cy
)) {
2423 /* the size of the drag image changed, invalidate the buffer */
2424 DeleteObject(InternalDrag
.hbmBg
);
2425 InternalDrag
.hbmBg
= 0;
2428 ImageList_Destroy (InternalDrag
.himl
);
2429 InternalDrag
.himl
= himlTemp
;
2432 /* show the drag image */
2433 ImageList_DragShowNolock(TRUE
);
2440 /*************************************************************************
2441 * ImageList_SetFilter [COMCTL32.@]
2443 * Sets a filter (or does something completely different)!!???
2444 * It removes 12 Bytes from the stack (3 Parameters).
2447 * himl [I] SHOULD be a handle to image list
2448 * i [I] COULD be an index?
2453 * Failure: FALSE ???
2456 * This is an UNDOCUMENTED function!!!!
2461 ImageList_SetFilter (HIMAGELIST himl
, INT i
, DWORD dwFilter
)
2463 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl
, i
, dwFilter
);
2469 /*************************************************************************
2470 * ImageList_SetFlags [COMCTL32.@]
2472 * Sets the image list flags.
2475 * himl [I] Handle to image list
2476 * flags [I] Flags to set
2486 ImageList_SetFlags(HIMAGELIST himl
, DWORD flags
)
2488 FIXME("(%p %08x):empty stub\n", himl
, flags
);
2493 /*************************************************************************
2494 * ImageList_SetIconSize [COMCTL32.@]
2496 * Sets the image size of the bitmap and deletes all images.
2499 * himl [I] handle to image list
2500 * cx [I] image width
2501 * cy [I] image height
2509 ImageList_SetIconSize (HIMAGELIST himl
, INT cx
, INT cy
)
2514 if (!is_valid(himl
))
2517 /* remove all images */
2518 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2519 himl
->cCurImage
= 0;
2523 /* initialize overlay mask indices */
2524 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2525 himl
->nOvlIdx
[nCount
] = -1;
2527 hbmNew
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
* himl
->cx
, himl
->cy
);
2528 SelectObject (himl
->hdcImage
, hbmNew
);
2529 DeleteObject (himl
->hbmImage
);
2530 himl
->hbmImage
= hbmNew
;
2532 if (himl
->hbmMask
) {
2533 hbmNew
= CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2535 SelectObject (himl
->hdcMask
, hbmNew
);
2536 DeleteObject (himl
->hbmMask
);
2537 himl
->hbmMask
= hbmNew
;
2544 /*************************************************************************
2545 * ImageList_SetImageCount [COMCTL32.@]
2547 * Resizes an image list to the specified number of images.
2550 * himl [I] handle to image list
2551 * iImageCount [I] number of images in the image list
2559 ImageList_SetImageCount (HIMAGELIST himl
, UINT iImageCount
)
2562 HBITMAP hbmNewBitmap
;
2563 INT nNewCount
, nCopyCount
;
2565 TRACE("%p %d\n",himl
,iImageCount
);
2567 if (!is_valid(himl
))
2569 if (iImageCount
< 0)
2571 if (himl
->cMaxImage
> iImageCount
)
2573 himl
->cCurImage
= iImageCount
;
2574 /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2578 nNewCount
= iImageCount
+ himl
->cGrow
;
2579 nCopyCount
= min(himl
->cCurImage
, iImageCount
);
2581 hdcBitmap
= CreateCompatibleDC (0);
2583 hbmNewBitmap
= ImageList_CreateImage(hdcBitmap
, himl
, nNewCount
* himl
->cx
, himl
->cy
);
2585 if (hbmNewBitmap
!= 0)
2587 SelectObject (hdcBitmap
, hbmNewBitmap
);
2590 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2591 himl
->hdcImage
, 0, 0, SRCCOPY
);
2593 /* delete 'empty' image space */
2594 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2595 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2596 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2597 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2599 SelectObject (himl
->hdcImage
, hbmNewBitmap
);
2600 DeleteObject (himl
->hbmImage
);
2601 himl
->hbmImage
= hbmNewBitmap
;
2604 ERR("Could not create new image bitmap !\n");
2608 hbmNewBitmap
= CreateBitmap (nNewCount
* himl
->cx
, himl
->cy
,
2610 if (hbmNewBitmap
!= 0)
2612 SelectObject (hdcBitmap
, hbmNewBitmap
);
2615 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2616 himl
->hdcMask
, 0, 0, SRCCOPY
);
2618 /* delete 'empty' image space */
2619 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2620 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2621 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2622 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2624 SelectObject (himl
->hdcMask
, hbmNewBitmap
);
2625 DeleteObject (himl
->hbmMask
);
2626 himl
->hbmMask
= hbmNewBitmap
;
2629 ERR("Could not create new mask bitmap!\n");
2632 DeleteDC (hdcBitmap
);
2634 /* Update max image count and current image count */
2635 himl
->cMaxImage
= nNewCount
;
2636 himl
->cCurImage
= iImageCount
;
2642 /*************************************************************************
2643 * ImageList_SetOverlayImage [COMCTL32.@]
2645 * Assigns an overlay mask index to an existing image in an image list.
2648 * himl [I] handle to image list
2649 * iImage [I] image index
2650 * iOverlay [I] overlay mask index
2658 ImageList_SetOverlayImage (HIMAGELIST himl
, INT iImage
, INT iOverlay
)
2660 if (!is_valid(himl
))
2662 if ((iOverlay
< 1) || (iOverlay
> MAX_OVERLAYIMAGE
))
2664 if ((iImage
!=-1) && ((iImage
< 0) || (iImage
> himl
->cCurImage
)))
2666 himl
->nOvlIdx
[iOverlay
- 1] = iImage
;
2672 /* helper for ImageList_Write - write bitmap to pstm
2673 * currently everything is written as 24 bit RGB, except masks
2676 _write_bitmap(HBITMAP hBitmap
, LPSTREAM pstm
, int cx
, int cy
)
2678 LPBITMAPFILEHEADER bmfh
;
2679 LPBITMAPINFOHEADER bmih
;
2680 LPBYTE data
, lpBits
, lpBitsOrg
;
2682 INT bitCount
, sizeImage
, offBits
, totalSize
;
2683 INT nwidth
, nheight
, nsizeImage
, icount
;
2685 BOOL result
= FALSE
;
2689 GetObjectA(hBitmap
, sizeof(BITMAP
), (LPVOID
)&bm
);
2691 /* XXX is this always correct? */
2692 icount
= bm
.bmWidth
/ cx
;
2694 nheight
= cy
* icount
;
2696 bitCount
= bm
.bmBitsPixel
== 1 ? 1 : 24;
2697 sizeImage
= ((((bm
.bmWidth
* bitCount
)+31) & ~31) >> 3) * bm
.bmHeight
;
2698 nsizeImage
= ((((nwidth
* bitCount
)+31) & ~31) >> 3) * nheight
;
2700 totalSize
= sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
);
2702 totalSize
+= (1 << bitCount
) * sizeof(RGBQUAD
);
2703 offBits
= totalSize
;
2704 totalSize
+= nsizeImage
;
2706 data
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, totalSize
);
2707 bmfh
= (LPBITMAPFILEHEADER
)data
;
2708 bmih
= (LPBITMAPINFOHEADER
)(data
+ sizeof(BITMAPFILEHEADER
));
2709 lpBits
= data
+ offBits
;
2711 /* setup BITMAPFILEHEADER */
2712 bmfh
->bfType
= (('M' << 8) | 'B');
2714 bmfh
->bfReserved1
= 0;
2715 bmfh
->bfReserved2
= 0;
2716 bmfh
->bfOffBits
= offBits
;
2718 /* setup BITMAPINFOHEADER */
2719 bmih
->biSize
= sizeof(BITMAPINFOHEADER
);
2720 bmih
->biWidth
= bm
.bmWidth
;
2721 bmih
->biHeight
= bm
.bmHeight
;
2723 bmih
->biBitCount
= bitCount
;
2724 bmih
->biCompression
= BI_RGB
;
2725 bmih
->biSizeImage
= sizeImage
;
2726 bmih
->biXPelsPerMeter
= 0;
2727 bmih
->biYPelsPerMeter
= 0;
2728 bmih
->biClrUsed
= 0;
2729 bmih
->biClrImportant
= 0;
2731 lpBitsOrg
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, sizeImage
);
2732 if(!GetDIBits(xdc
, hBitmap
, 0, bm
.bmHeight
, lpBitsOrg
,
2733 (BITMAPINFO
*)bmih
, DIB_RGB_COLORS
))
2737 int obpl
= (((bm
.bmWidth
*bitCount
+31) & ~31)>>3);
2738 int nbpl
= (((nwidth
*bitCount
+31) & ~31)>>3);
2740 for(i
= 0; i
< nheight
; i
++) {
2741 int ooff
= ((nheight
-1-i
)%cy
) * obpl
+ ((i
/cy
) * nbpl
);
2742 int noff
= (nbpl
* (nheight
-1-i
));
2743 memcpy(lpBits
+ noff
, lpBitsOrg
+ ooff
, nbpl
);
2747 bmih
->biWidth
= nwidth
;
2748 bmih
->biHeight
= nheight
;
2749 bmih
->biSizeImage
= nsizeImage
;
2753 LPBITMAPINFO inf
= (LPBITMAPINFO
)bmih
;
2754 inf
->bmiColors
[0].rgbRed
= inf
->bmiColors
[0].rgbGreen
= inf
->bmiColors
[0].rgbBlue
= 0;
2755 inf
->bmiColors
[1].rgbRed
= inf
->bmiColors
[1].rgbGreen
= inf
->bmiColors
[1].rgbBlue
= 0xff;
2758 if(!SUCCEEDED(IStream_Write(pstm
, data
, totalSize
, NULL
)))
2765 LocalFree((HLOCAL
)lpBitsOrg
);
2766 LocalFree((HLOCAL
)data
);
2772 /*************************************************************************
2773 * ImageList_Write [COMCTL32.@]
2775 * Writes an image list to a stream.
2778 * himl [I] handle to image list
2779 * pstm [O] Pointer to a stream.
2790 ImageList_Write (HIMAGELIST himl
, LPSTREAM pstm
)
2795 if (!is_valid(himl
))
2798 ilHead
.usMagic
= (('L' << 8) | 'I');
2799 ilHead
.usVersion
= 0x101;
2800 ilHead
.cCurImage
= himl
->cCurImage
;
2801 ilHead
.cMaxImage
= himl
->cMaxImage
;
2802 ilHead
.cGrow
= himl
->cGrow
;
2803 ilHead
.cx
= himl
->cx
;
2804 ilHead
.cy
= himl
->cy
;
2805 ilHead
.bkcolor
= himl
->clrBk
;
2806 ilHead
.flags
= himl
->flags
;
2807 for(i
= 0; i
< 4; i
++) {
2808 ilHead
.ovls
[i
] = himl
->nOvlIdx
[i
];
2811 if(!SUCCEEDED(IStream_Write(pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
2814 /* write the bitmap */
2815 if(!_write_bitmap(himl
->hbmImage
, pstm
, himl
->cx
, himl
->cy
))
2818 /* write the mask if we have one */
2819 if(himl
->flags
& ILC_MASK
) {
2820 if(!_write_bitmap(himl
->hbmMask
, pstm
, himl
->cx
, himl
->cy
))
2828 static HBITMAP
ImageList_CreateImage(HDC hdc
, HIMAGELIST himl
, UINT width
, UINT height
)
2830 HBITMAP hbmNewBitmap
;
2831 UINT ilc
= (himl
->flags
& 0xFE);
2833 if ((ilc
>= ILC_COLOR4
&& ilc
<= ILC_COLOR32
) || ilc
== ILC_COLOR
)
2838 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl
->uBitsPixel
);
2840 if (himl
->uBitsPixel
<= ILC_COLOR8
)
2846 colors
= 1 << himl
->uBitsPixel
;
2847 bmi
= Alloc(sizeof(BITMAPINFOHEADER
) +
2848 sizeof(PALETTEENTRY
) * colors
);
2850 pal
= (LPPALETTEENTRY
)bmi
->bmiColors
;
2851 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE
), 0, colors
, pal
);
2853 /* Swap colors returned by GetPaletteEntries so we can use them for
2854 * CreateDIBSection call. */
2855 for (i
= 0; i
< colors
; i
++)
2857 temp
= pal
[i
].peBlue
;
2858 bmi
->bmiColors
[i
].rgbRed
= pal
[i
].peRed
;
2859 bmi
->bmiColors
[i
].rgbBlue
= temp
;
2864 bmi
= Alloc(sizeof(BITMAPINFOHEADER
));
2867 bmi
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
2868 bmi
->bmiHeader
.biWidth
= width
;
2869 bmi
->bmiHeader
.biHeight
= height
;
2870 bmi
->bmiHeader
.biPlanes
= 1;
2871 bmi
->bmiHeader
.biBitCount
= himl
->uBitsPixel
;
2872 bmi
->bmiHeader
.biCompression
= BI_RGB
;
2873 bmi
->bmiHeader
.biSizeImage
= 0;
2874 bmi
->bmiHeader
.biXPelsPerMeter
= 0;
2875 bmi
->bmiHeader
.biYPelsPerMeter
= 0;
2876 bmi
->bmiHeader
.biClrUsed
= 0;
2877 bmi
->bmiHeader
.biClrImportant
= 0;
2879 hbmNewBitmap
= CreateDIBSection(hdc
, bmi
, DIB_RGB_COLORS
, &bits
, 0, 0);
2883 else /*if (ilc == ILC_COLORDDB)*/
2885 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl
->uBitsPixel
);
2887 hbmNewBitmap
= CreateBitmap (width
, height
, 1, himl
->uBitsPixel
, NULL
);
2889 TRACE("returning %p\n", hbmNewBitmap
);
2890 return hbmNewBitmap
;
2893 /*************************************************************************
2894 * ImageList_SetColorTable [COMCTL32.@]
2896 * Sets the color table of an image list.
2899 * himl [I] Handle to the image list.
2900 * uStartIndex [I] The first index to set.
2901 * cEntries [I] Number of entries to set.
2902 * prgb [I] New color information for color table for the image list.
2905 * Success: Number of entries in the table that were set.
2909 * ImageList_Create(), SetDIBColorTable()
2913 ImageList_SetColorTable (HIMAGELIST himl
, UINT uStartIndex
, UINT cEntries
, CONST RGBQUAD
* prgb
)
2915 return SetDIBColorTable(himl
->hdcImage
, uStartIndex
, cEntries
, prgb
);