2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 belive 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
38 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
39 * is the offset of the image position relative to the actual mouse pointer
40 * position. However the Hotspot passed to SetDragCursorImage is the
41 * offset of the mouse messages sent to the application...
48 #include "wine/obj_base.h"
49 #include "wine/obj_storage.h"
51 #include "imagelist.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(imagelist
);
57 #define MAX_OVERLAYIMAGE 15
59 /* internal image list data used for Drag & Drop operations */
64 /* position of the drag image relative to the window */
67 /* offset of the hotspot relative to the origin of the image */
70 /* is the drag image visible */
72 /* saved background */
77 static INTERNALDRAG InternalDrag
= { 0, 0, 0, 0, 0, 0, FALSE
, 0, FALSE
};
81 /*************************************************************************
82 * IMAGELIST_InternalExpandBitmaps [Internal]
84 * Expands the bitmaps of an image list by the given number of images.
87 * himl [I] handle to image list
88 * nImageCount [I] number of images to add
94 * This function can NOT be used to reduce the number of images.
97 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl
, INT nImageCount
, INT cx
, INT cy
)
99 HDC hdcImageList
, hdcBitmap
;
100 HBITMAP hbmNewBitmap
;
101 INT nNewWidth
, nNewCount
;
103 if ((himl
->cCurImage
+ nImageCount
<= himl
->cMaxImage
)
107 if (cy
== 0) cy
= himl
->cy
;
108 nNewCount
= himl
->cCurImage
+ nImageCount
+ himl
->cGrow
;
109 nNewWidth
= nNewCount
* himl
->cx
;
111 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl
, nNewWidth
, cy
, nNewCount
);
112 hdcImageList
= CreateCompatibleDC (0);
113 hdcBitmap
= CreateCompatibleDC (0);
116 CreateBitmap (nNewWidth
, cy
, 1, himl
->uBitsPixel
, NULL
);
117 if (hbmNewBitmap
== 0)
118 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth
, cy
);
120 SelectObject (hdcImageList
, himl
->hbmImage
);
121 SelectObject (hdcBitmap
, hbmNewBitmap
);
122 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
123 hdcImageList
, 0, 0, SRCCOPY
);
125 DeleteObject (himl
->hbmImage
);
126 himl
->hbmImage
= hbmNewBitmap
;
130 CreateBitmap (nNewWidth
, cy
, 1, 1, NULL
);
132 if (hbmNewBitmap
== 0)
133 ERR("creating new mask bitmap!\n");
135 SelectObject (hdcImageList
, himl
->hbmMask
);
136 SelectObject (hdcBitmap
, hbmNewBitmap
);
137 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
138 hdcImageList
, 0, 0, SRCCOPY
);
139 DeleteObject (himl
->hbmMask
);
140 himl
->hbmMask
= hbmNewBitmap
;
143 himl
->cMaxImage
= nNewCount
;
145 DeleteDC (hdcImageList
);
146 DeleteDC (hdcBitmap
);
150 /*************************************************************************
151 * ImageList_Add [COMCTL32.@]
153 * Add an image or images to an image list.
156 * himl [I] handle to image list
157 * hbmImage [I] handle to image bitmap
158 * hbmMask [I] handle to mask bitmap
161 * Success: Index of the first new image.
166 ImageList_Add (HIMAGELIST himl
, HBITMAP hbmImage
, HBITMAP hbmMask
)
168 HDC hdcImage
, hdcBitmap
;
169 INT nFirstIndex
, nImageCount
;
172 HBITMAP hOldBitmapImage
, hOldBitmap
;
174 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl
, hbmImage
, hbmMask
);
175 if (!himl
|| !hbmImage
)
178 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
179 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
181 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
183 nStartX
= himl
->cCurImage
* himl
->cx
;
185 hdcImage
= CreateCompatibleDC(0);
186 hdcBitmap
= CreateCompatibleDC(0);
188 hOldBitmapImage
= SelectObject(hdcImage
, himl
->hbmImage
);
189 hOldBitmap
= SelectObject(hdcBitmap
, hbmImage
);
191 /* Copy result to the imagelist
193 BitBlt (hdcImage
, nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
194 hdcBitmap
, 0, 0, SRCCOPY
);
198 HDC hdcMask
, hdcTemp
;
199 HBITMAP hOldBitmapMask
, hOldBitmapTemp
;
201 hdcMask
= CreateCompatibleDC (0);
202 hdcTemp
= CreateCompatibleDC(0);
203 hOldBitmapMask
= SelectObject(hdcMask
, himl
->hbmMask
);
204 hOldBitmapTemp
= SelectObject(hdcTemp
, hbmMask
);
207 nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
212 SelectObject(hdcTemp
, hOldBitmapTemp
);
215 /* Remove the background from the image
218 nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
221 0x220326); /* NOTSRCAND */
223 SelectObject(hdcMask
, hOldBitmapMask
);
227 SelectObject(hdcImage
, hOldBitmapImage
);
228 SelectObject(hdcBitmap
, hOldBitmap
);
232 nFirstIndex
= himl
->cCurImage
;
233 himl
->cCurImage
+= nImageCount
;
239 /*************************************************************************
240 * ImageList_AddIcon [COMCTL32.@]
242 * Adds an icon to an image list.
245 * himl [I] handle to image list
246 * hIcon [I] handle to icon
249 * Success: index of the new image
254 ImageList_AddIcon (HIMAGELIST himl
, HICON hIcon
)
256 return ImageList_ReplaceIcon (himl
, -1, hIcon
);
260 /*************************************************************************
261 * ImageList_AddMasked [COMCTL32.@]
263 * Adds an image or images to an image list and creates a mask from the
264 * specified bitmap using the mask color.
267 * himl [I] handle to image list.
268 * hBitmap [I] handle to bitmap
269 * clrMask [I] mask color.
272 * Success: Index of the first new image.
277 ImageList_AddMasked (HIMAGELIST himl
, HBITMAP hBitmap
, COLORREF clrMask
)
279 HDC hdcImage
, hdcMask
, hdcBitmap
;
280 INT nIndex
, nImageCount
, nMaskXOffset
=0;
282 HBITMAP hOldBitmap
, hOldBitmapMask
, hOldBitmapImage
;
283 HBITMAP hMaskBitmap
=0;
286 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl
, hBitmap
, clrMask
);
290 if (!GetObjectA (hBitmap
, sizeof(BITMAP
), &bmp
))
293 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
295 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
297 nIndex
= himl
->cCurImage
;
298 himl
->cCurImage
+= nImageCount
;
300 hdcMask
= CreateCompatibleDC (0);
301 hdcImage
= CreateCompatibleDC(0);
302 hdcBitmap
= CreateCompatibleDC(0);
305 hOldBitmapImage
= SelectObject(hdcImage
, himl
->hbmImage
);
306 hOldBitmap
= SelectObject(hdcBitmap
, hBitmap
);
309 hOldBitmapMask
= SelectObject(hdcMask
, himl
->hbmMask
);
310 nMaskXOffset
= nIndex
* himl
->cx
;
315 Create a temp Mask so we can remove the background of
316 the Image (Windows does this even if there is no mask)
318 hMaskBitmap
= CreateBitmap(bmp
.bmWidth
, bmp
.bmHeight
, 1, 1, NULL
);
319 hOldBitmapMask
= SelectObject(hdcMask
, hMaskBitmap
);
322 /* create monochrome image to the mask bitmap */
323 bkColor
= (clrMask
!= CLR_DEFAULT
) ? clrMask
:
324 GetPixel (hdcBitmap
, 0, 0);
325 SetBkColor (hdcBitmap
, bkColor
);
327 nMaskXOffset
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
331 SetBkColor(hdcBitmap
, RGB(255,255,255));
332 /*Remove the background from the image
335 WINDOWS BUG ALERT!!!!!!
336 The statement below should not be done in common practice
337 but this is how ImageList_AddMasked works in Windows.
338 It overwrites the original bitmap passed, this was discovered
339 by using the same bitmap to iterate the different styles
340 on windows where it failed (BUT ImageList_Add is OK)
341 This is here in case some apps rely on this bug
344 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
347 0x220326); /* NOTSRCAND */
348 /* Copy result to the imagelist
351 nIndex
* himl
->cx
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
357 SelectObject(hdcMask
,hOldBitmapMask
);
358 SelectObject(hdcImage
, hOldBitmapImage
);
359 SelectObject(hdcBitmap
, hOldBitmap
);
365 DeleteObject(hMaskBitmap
);
372 /*************************************************************************
373 * ImageList_BeginDrag [COMCTL32.@]
375 * Creates a temporary image list that contains one image. It will be used
379 * himlTrack [I] handle to the source image list
380 * iTrack [I] index of the drag image in the source image list
381 * dxHotspot [I] X position of the hot spot of the drag image
382 * dyHotspot [I] Y position of the hot spot of the drag image
390 ImageList_BeginDrag (HIMAGELIST himlTrack
, INT iTrack
,
391 INT dxHotspot
, INT dyHotspot
)
396 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack
, iTrack
,
397 dxHotspot
, dyHotspot
);
399 if (himlTrack
== NULL
)
402 if (InternalDrag
.himl
)
403 ImageList_EndDrag ();
408 InternalDrag
.himl
= ImageList_Create (cx
, cy
, himlTrack
->flags
, 1, 1);
409 if (InternalDrag
.himl
== NULL
) {
410 WARN("Error creating drag image list!\n");
414 InternalDrag
.dxHotspot
= dxHotspot
;
415 InternalDrag
.dyHotspot
= dyHotspot
;
417 hdcSrc
= CreateCompatibleDC (0);
418 hdcDst
= CreateCompatibleDC (0);
421 SelectObject (hdcSrc
, himlTrack
->hbmImage
);
422 SelectObject (hdcDst
, InternalDrag
.himl
->hbmImage
);
423 BitBlt (hdcDst
, 0, 0, cx
, cy
, hdcSrc
, iTrack
* cx
, 0, SRCCOPY
);
426 SelectObject (hdcSrc
, himlTrack
->hbmMask
);
427 SelectObject (hdcDst
, InternalDrag
.himl
->hbmMask
);
428 BitBlt (hdcDst
, 0, 0, cx
, cy
, hdcSrc
, iTrack
* cx
, 0, SRCCOPY
);
433 InternalDrag
.himl
->cCurImage
= 1;
434 InternalDrag
.bHSPending
= TRUE
;
440 /*************************************************************************
441 * ImageList_Copy [COMCTL32.@]
443 * Copies an image of the source image list to an image of the
444 * destination image list. Images can be copied or swapped.
447 * himlDst [I] handle to the destination image list
448 * iDst [I] destination image index.
449 * himlSrc [I] handle to the source image list
450 * iSrc [I] source image index
451 * uFlags [I] flags for the copy operation
458 * Copying from one image list to another is possible. The original
459 * implementation just copies or swaps within one image list.
460 * Could this feature become a bug??? ;-)
464 ImageList_Copy (HIMAGELIST himlDst
, INT iDst
, HIMAGELIST himlSrc
,
465 INT iSrc
, INT uFlags
)
469 TRACE("iDst=%d iSrc=%d\n", iDst
, iSrc
);
471 if ((himlSrc
== NULL
) || (himlDst
== NULL
))
473 if ((iDst
< 0) || (iDst
>= himlDst
->cCurImage
))
475 if ((iSrc
< 0) || (iSrc
>= himlSrc
->cCurImage
))
478 hdcSrc
= CreateCompatibleDC (0);
479 if (himlDst
== himlSrc
)
482 hdcDst
= CreateCompatibleDC (0);
484 if (uFlags
& ILCF_SWAP
) {
486 HBITMAP hbmTempImage
, hbmTempMask
;
488 /* create temporary bitmaps */
489 hbmTempImage
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
490 himlSrc
->uBitsPixel
, NULL
);
491 hbmTempMask
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
494 /* copy (and stretch) destination to temporary bitmaps.(save) */
496 SelectObject (hdcSrc
, himlDst
->hbmImage
);
497 SelectObject (hdcDst
, hbmTempImage
);
498 StretchBlt (hdcDst
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
499 hdcSrc
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
502 SelectObject (hdcSrc
, himlDst
->hbmMask
);
503 SelectObject (hdcDst
, hbmTempMask
);
504 StretchBlt (hdcDst
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
505 hdcSrc
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
508 /* copy (and stretch) source to destination */
510 SelectObject (hdcSrc
, himlSrc
->hbmImage
);
511 SelectObject (hdcDst
, himlDst
->hbmImage
);
512 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
513 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
516 SelectObject (hdcSrc
, himlSrc
->hbmMask
);
517 SelectObject (hdcDst
, himlDst
->hbmMask
);
518 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
519 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
522 /* copy (without stretching) temporary bitmaps to source (restore) */
524 SelectObject (hdcSrc
, hbmTempImage
);
525 SelectObject (hdcDst
, himlSrc
->hbmImage
);
526 BitBlt (hdcDst
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
527 hdcSrc
, 0, 0, SRCCOPY
);
529 SelectObject (hdcSrc
, hbmTempMask
);
530 SelectObject (hdcDst
, himlSrc
->hbmMask
);
531 BitBlt (hdcDst
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
532 hdcSrc
, 0, 0, SRCCOPY
);
534 /* delete temporary bitmaps */
535 DeleteObject (hbmTempMask
);
536 DeleteObject (hbmTempImage
);
540 SelectObject (hdcSrc
, himlSrc
->hbmImage
);
541 if (himlSrc
== himlDst
)
544 SelectObject (hdcDst
, himlDst
->hbmImage
);
545 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
546 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
550 SelectObject (hdcSrc
, himlSrc
->hbmMask
);
551 if (himlSrc
== himlDst
)
554 SelectObject (hdcDst
, himlDst
->hbmMask
);
555 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
556 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
561 if (himlSrc
!= himlDst
)
568 /*************************************************************************
569 * ImageList_Create [COMCTL32.@] Creates a new image list.
572 * cx [I] image height
574 * flags [I] creation flags
575 * cInitial [I] initial number of images in the image list
576 * cGrow [I] number of images by which image list grows
579 * Success: Handle to the created image list
584 ImageList_Create (INT cx
, INT cy
, UINT flags
,
585 INT cInitial
, INT cGrow
)
591 static WORD aBitBlend25
[] =
592 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
594 static WORD aBitBlend50
[] =
595 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
597 TRACE("(%d %d 0x%x %d %d)\n", cx
, cy
, flags
, cInitial
, cGrow
);
599 himl
= (HIMAGELIST
)COMCTL32_Alloc (sizeof(struct _IMAGELIST
));
606 himl
->cMaxImage
= cInitial
+ cGrow
;
607 himl
->cInitial
= cInitial
;
610 himl
->clrFg
= CLR_DEFAULT
;
611 himl
->clrBk
= CLR_NONE
;
613 /* initialize overlay mask indices */
614 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
615 himl
->nOvlIdx
[nCount
] = -1;
617 hdc
= CreateCompatibleDC (0);
618 himl
->uBitsPixel
= (UINT
)GetDeviceCaps (hdc
, BITSPIXEL
);
621 TRACE("Image: %d Bits per Pixel\n", himl
->uBitsPixel
);
623 if (himl
->cMaxImage
> 0) {
625 CreateBitmap (himl
->cx
* himl
->cMaxImage
, himl
->cy
,
626 1, himl
->uBitsPixel
, NULL
);
627 if (himl
->hbmImage
== 0) {
628 ERR("Error creating image bitmap!\n");
635 if ( (himl
->flags
& ILC_MASK
)) {
636 int images
= himl
->cMaxImage
;
640 himl
->hbmMask
= CreateBitmap (himl
->cx
* images
, himl
->cy
,
642 if (himl
->hbmMask
== 0) {
643 ERR("Error creating mask bitmap!\n");
645 DeleteObject (himl
->hbmImage
);
652 /* create blending brushes */
653 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend25
);
654 himl
->hbrBlend25
= CreatePatternBrush (hbmTemp
);
655 DeleteObject (hbmTemp
);
657 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend50
);
658 himl
->hbrBlend50
= CreatePatternBrush (hbmTemp
);
659 DeleteObject (hbmTemp
);
661 TRACE("created imagelist %p\n", himl
);
666 /*************************************************************************
667 * ImageList_Destroy [COMCTL32.@]
669 * Destroys an image list.
672 * himl [I] handle to image list
680 ImageList_Destroy (HIMAGELIST himl
)
685 /* delete image bitmaps */
687 DeleteObject (himl
->hbmImage
);
689 DeleteObject (himl
->hbmMask
);
691 /* delete blending brushes */
692 if (himl
->hbrBlend25
)
693 DeleteObject (himl
->hbrBlend25
);
694 if (himl
->hbrBlend50
)
695 DeleteObject (himl
->hbrBlend50
);
697 COMCTL32_Free (himl
);
703 /*************************************************************************
704 * ImageList_DragEnter [COMCTL32.@]
706 * Locks window update and displays the drag image at the given position.
709 * hwndLock [I] handle of the window that owns the drag image.
710 * x [I] X position of the drag image.
711 * y [I] Y position of the drag image.
718 * The position of the drag image is relative to the window, not
723 ImageList_DragEnter (HWND hwndLock
, INT x
, INT y
)
725 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock
, x
, y
);
727 if (InternalDrag
.himl
== NULL
)
731 InternalDrag
.hwnd
= hwndLock
;
733 InternalDrag
.hwnd
= GetDesktopWindow ();
738 /* draw the drag image and save the background */
739 if (!ImageList_DragShowNolock(TRUE
)) {
747 /*************************************************************************
748 * ImageList_DragLeave [COMCTL32.@]
750 * Unlocks window update and hides the drag image.
753 * hwndLock [I] handle of the window that owns the drag image.
761 ImageList_DragLeave (HWND hwndLock
)
763 /* As we don't save drag info in the window this can lead to problems if
764 an app does not supply the same window as DragEnter */
766 InternalDrag.hwnd = hwndLock;
768 InternalDrag.hwnd = GetDesktopWindow (); */
770 hwndLock
= GetDesktopWindow();
771 if(InternalDrag
.hwnd
!= hwndLock
)
772 FIXME("DragLeave hWnd != DragEnter hWnd\n");
774 ImageList_DragShowNolock (FALSE
);
780 /*************************************************************************
781 * ImageList_InternalDragDraw [Internal]
783 * Draws the drag image.
786 * hdc [I] device context to draw into.
787 * x [I] X position of the drag image.
788 * y [I] Y position of the drag image.
795 * The position of the drag image is relative to the window, not
801 ImageList_InternalDragDraw (HDC hdc
, INT x
, INT y
)
803 IMAGELISTDRAWPARAMS imldp
;
805 ZeroMemory (&imldp
, sizeof(imldp
));
806 imldp
.cbSize
= sizeof(imldp
);
807 imldp
.himl
= InternalDrag
.himl
;
812 imldp
.rgbBk
= CLR_DEFAULT
;
813 imldp
.rgbFg
= CLR_DEFAULT
;
814 imldp
.fStyle
= ILD_NORMAL
;
815 imldp
.fState
= ILS_ALPHA
;
818 /* FIXME: instead of using the alpha blending, we should
819 * create a 50% mask, and draw it semitransparantly that way */
820 ImageList_DrawIndirect (&imldp
);
823 /*************************************************************************
824 * ImageList_DragMove [COMCTL32.@]
826 * Moves the drag image.
829 * x [I] X position of the drag image.
830 * y [I] Y position of the drag image.
837 * The position of the drag image is relative to the window, not
841 * The drag image should be drawn semitransparent.
845 ImageList_DragMove (INT x
, INT y
)
847 TRACE("(x=%d y=%d)\n", x
, y
);
849 if (!InternalDrag
.himl
) {
853 /* draw/update the drag image */
854 if (InternalDrag
.bShow
) {
858 HBITMAP hbmOffScreen
;
859 INT origNewX
, origNewY
;
860 INT origOldX
, origOldY
;
861 INT origRegX
, origRegY
;
862 INT sizeRegX
, sizeRegY
;
865 /* calculate the update region */
866 origNewX
= x
- InternalDrag
.dxHotspot
;
867 origNewY
= y
- InternalDrag
.dyHotspot
;
868 origOldX
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
869 origOldY
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
870 origRegX
= min(origNewX
, origOldX
);
871 origRegY
= min(origNewY
, origOldY
);
872 sizeRegX
= InternalDrag
.himl
->cx
+ abs(x
- InternalDrag
.x
);
873 sizeRegY
= InternalDrag
.himl
->cy
+ abs(y
- InternalDrag
.y
);
875 hdcDrag
= GetDCEx(InternalDrag
.hwnd
, 0,
876 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
877 hdcOffScreen
= CreateCompatibleDC(hdcDrag
);
878 hdcBg
= CreateCompatibleDC(hdcDrag
);
880 hbmOffScreen
= CreateCompatibleBitmap(hdcDrag
, sizeRegX
, sizeRegY
);
881 SelectObject(hdcOffScreen
, hbmOffScreen
);
882 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
884 /* get the actual background of the update region */
885 BitBlt(hdcOffScreen
, 0, 0, sizeRegX
, sizeRegY
, hdcDrag
,
886 origRegX
, origRegY
, SRCCOPY
);
887 /* erase the old image */
888 BitBlt(hdcOffScreen
, origOldX
- origRegX
, origOldY
- origRegY
,
889 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
, hdcBg
, 0, 0,
891 /* save the background */
892 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
893 hdcOffScreen
, origNewX
- origRegX
, origNewY
- origRegY
, SRCCOPY
);
895 ImageList_InternalDragDraw(hdcOffScreen
, origNewX
- origRegX
,
896 origNewY
- origRegY
);
897 /* draw the update region to the screen */
898 BitBlt(hdcDrag
, origRegX
, origRegY
, sizeRegX
, sizeRegY
,
899 hdcOffScreen
, 0, 0, SRCCOPY
);
902 DeleteDC(hdcOffScreen
);
903 DeleteObject(hbmOffScreen
);
904 ReleaseDC(InternalDrag
.hwnd
, hdcDrag
);
907 /* update the image position */
915 /*************************************************************************
916 * ImageList_DragShowNolock [COMCTL32.@]
918 * Shows or hides the drag image.
921 * bShow [I] TRUE shows the drag image, FALSE hides it.
928 * The drag image should be drawn semitransparent.
932 ImageList_DragShowNolock (BOOL bShow
)
938 TRACE("bShow=0x%X!\n", bShow
);
940 /* DragImage is already visible/hidden */
941 if ((InternalDrag
.bShow
&& bShow
) || (!InternalDrag
.bShow
&& !bShow
)) {
945 /* position of the origin of the DragImage */
946 x
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
947 y
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
949 hdcDrag
= GetDCEx (InternalDrag
.hwnd
, 0,
950 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
955 hdcBg
= CreateCompatibleDC(hdcDrag
);
956 if (!InternalDrag
.hbmBg
) {
957 InternalDrag
.hbmBg
= CreateCompatibleBitmap(hdcDrag
,
958 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
);
960 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
963 /* save the background */
964 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
965 hdcDrag
, x
, y
, SRCCOPY
);
967 ImageList_InternalDragDraw(hdcDrag
, x
, y
);
970 BitBlt(hdcDrag
, x
, y
, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
971 hdcBg
, 0, 0, SRCCOPY
);
974 InternalDrag
.bShow
= !InternalDrag
.bShow
;
977 ReleaseDC (InternalDrag
.hwnd
, hdcDrag
);
982 /*************************************************************************
983 * ImageList_Draw [COMCTL32.@] Draws an image.
986 * himl [I] handle to image list
988 * hdc [I] handle to device context
991 * fStyle [I] drawing flags
1002 ImageList_Draw (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
, UINT fStyle
)
1004 return ImageList_DrawEx (himl
, i
, hdc
, x
, y
, 0, 0,
1005 CLR_DEFAULT
, CLR_DEFAULT
, fStyle
);
1009 /*************************************************************************
1010 * ImageList_DrawEx [COMCTL32.@]
1012 * Draws an image and allows to use extended drawing features.
1015 * himl [I] handle to image list
1017 * hdc [I] handle to device context
1022 * rgbBk [I] background color
1023 * rgbFg [I] foreground color
1024 * fStyle [I] drawing flags
1031 * Calls ImageList_DrawIndirect.
1034 * ImageList_DrawIndirect.
1038 ImageList_DrawEx (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
,
1039 INT dx
, INT dy
, COLORREF rgbBk
, COLORREF rgbFg
,
1042 IMAGELISTDRAWPARAMS imldp
;
1044 ZeroMemory (&imldp
, sizeof(imldp
));
1045 imldp
.cbSize
= sizeof(imldp
);
1053 imldp
.rgbBk
= rgbBk
;
1054 imldp
.rgbFg
= rgbFg
;
1055 imldp
.fStyle
= fStyle
;
1057 return ImageList_DrawIndirect (&imldp
);
1061 /*************************************************************************
1062 * ImageList_DrawIndirect [COMCTL32.@]
1064 * Draws an image using ...
1067 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1075 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS
*pimldp
)
1077 INT cx
, cy
, nOvlIdx
;
1078 DWORD fState
, dwRop
;
1080 COLORREF clrBk
, oldImageBk
, oldImageFg
;
1081 HDC hImageDC
, hImageListDC
, hMaskListDC
;
1082 HBITMAP hImageBmp
, hOldImageBmp
, hOldImageListBmp
, hOldMaskListBmp
, hBlendMaskBmp
;
1083 BOOL bIsTransparent
, bBlend
, bResult
= FALSE
;
1084 const HIMAGELIST himl
= pimldp
->himl
;
1085 const INT lx
= himl
->cx
* pimldp
->i
+ pimldp
->xBitmap
;
1086 const INT ly
= pimldp
->yBitmap
;
1088 if (!pimldp
|| !himl
) return FALSE
;
1089 if ((pimldp
->i
< 0) || (pimldp
->i
>= himl
->cCurImage
)) return FALSE
;
1091 fState
= pimldp
->cbSize
< sizeof(IMAGELISTDRAWPARAMS
) ? ILS_NORMAL
: pimldp
->fState
;
1092 fStyle
= pimldp
->fStyle
& ~ILD_OVERLAYMASK
;
1093 cx
= (pimldp
->cx
== 0) ? himl
->cx
: pimldp
->cx
;
1094 cy
= (pimldp
->cy
== 0) ? himl
->cy
: pimldp
->cy
;
1095 clrBk
= (pimldp
->rgbBk
== CLR_DEFAULT
) ? himl
->clrBk
: pimldp
->rgbBk
;
1096 bIsTransparent
= (fStyle
& ILD_TRANSPARENT
) || clrBk
== CLR_NONE
;
1097 bBlend
= fStyle
& (ILD_BLEND25
| ILD_BLEND50
);
1099 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1100 himl
->hbmMask
, pimldp
->i
, pimldp
->x
, pimldp
->y
, cx
, cy
);
1102 /* we will use these DCs to access the images and masks in the ImageList */
1103 hImageListDC
= CreateCompatibleDC(0);
1104 hMaskListDC
= himl
->hbmMask
? CreateCompatibleDC(0) : 0;
1106 /* these will accumulate the image and mask for the image we're drawing */
1107 hImageDC
= CreateCompatibleDC( pimldp
->hdcDst
);
1108 hImageBmp
= CreateCompatibleBitmap( pimldp
->hdcDst
, cx
, cy
);
1109 hBlendMaskBmp
= bBlend
? CreateBitmap(cx
, cy
, 1, 1, NULL
) : 0;
1111 /* Create a compatible DC. */
1112 if (!hImageListDC
|| !hImageDC
|| !hImageBmp
||
1113 (bBlend
&& !hBlendMaskBmp
) || (himl
->hbmMask
&& !hMaskListDC
))
1116 hOldImageListBmp
= SelectObject(hImageListDC
, himl
->hbmImage
);
1117 hOldImageBmp
= SelectObject(hImageDC
, hImageBmp
);
1118 hOldMaskListBmp
= hMaskListDC
? SelectObject(hMaskListDC
, himl
->hbmMask
) : 0;
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
1131 if(fStyle
& ILD_MASK
) {
1132 if (himl
->hbmMask
) {
1133 BitBlt(hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, lx
, ly
, SRCCOPY
);
1135 HBRUSH hOldBrush
= SelectObject (hImageDC
, GetStockObject(BLACK_BRUSH
));
1136 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1137 SelectObject(hImageDC
, hOldBrush
);
1139 } else if (himl
->hbmMask
&& !bIsTransparent
) {
1140 /* blend the image with the needed solid background */
1141 HBRUSH hOldBrush
= SelectObject (hImageDC
, CreateSolidBrush (clrBk
));
1142 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1143 BitBlt( hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, lx
, ly
, SRCAND
);
1144 BitBlt( hImageDC
, 0, 0, cx
, cy
, hImageListDC
, lx
, ly
, SRCPAINT
);
1145 DeleteObject (SelectObject (hImageDC
, hOldBrush
));
1147 /* start off with the image, if we have a mask, we'll use it later */
1148 BitBlt( hImageDC
, 0, 0, cx
, cy
, hImageListDC
, lx
, ly
, SRCCOPY
);
1151 /* Time for blending, if required */
1153 HBRUSH hBlendBrush
, hOldBrush
;
1154 COLORREF clrBlend
= pimldp
->rgbFg
;
1155 HDC hBlendMaskDC
= hImageListDC
;
1158 /* Create the blend Mask */
1159 hOldBitmap
= SelectObject(hBlendMaskDC
, hBlendMaskBmp
);
1160 hBlendBrush
= fStyle
& ILD_BLEND50
? himl
->hbrBlend50
: himl
->hbrBlend25
;
1161 hOldBrush
= (HBRUSH
) SelectObject(hBlendMaskDC
, hBlendBrush
);
1162 PatBlt(hBlendMaskDC
, 0, 0, cx
, cy
, PATCOPY
);
1163 SelectObject(hBlendMaskDC
, hOldBrush
);
1165 /* Modify the blend mask if an Image Mask exist */
1167 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hMaskListDC
, lx
, ly
, 0x220326); /* NOTSRCAND */
1168 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, NOTSRCCOPY
);
1171 /* now apply blend to the current image given the BlendMask */
1172 if (clrBlend
== CLR_DEFAULT
) clrBlend
= GetSysColor (COLOR_HIGHLIGHT
);
1173 else if (clrBlend
== CLR_NONE
) clrBlend
= GetTextColor (pimldp
->hdcDst
);
1174 hOldBrush
= (HBRUSH
) SelectObject (hImageDC
, CreateSolidBrush(clrBlend
));
1175 BitBlt (hImageDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, 0xB8074A); /* PSDPxax */
1176 DeleteObject(SelectObject(hImageDC
, hOldBrush
));
1177 SelectObject(hBlendMaskDC
, hOldBitmap
);
1180 /* Now do the overlay image, if any */
1181 nOvlIdx
= (pimldp
->fStyle
& ILD_OVERLAYMASK
) >> 8;
1182 if ( (nOvlIdx
>= 1) && (nOvlIdx
<= MAX_OVERLAYIMAGE
)) {
1183 nOvlIdx
= himl
->nOvlIdx
[nOvlIdx
- 1];
1184 if ((nOvlIdx
>= 0) && (nOvlIdx
< himl
->cCurImage
)) {
1185 const INT ox
= himl
->cx
* nOvlIdx
+ pimldp
->xBitmap
;
1186 if (himl
->hbmMask
&& !(fStyle
& ILD_IMAGE
))
1187 BitBlt (hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, ox
, ly
, SRCAND
);
1188 BitBlt (hImageDC
, 0, 0, cx
, cy
, hImageListDC
, ox
, ly
, SRCPAINT
);
1192 if (fState
& ILS_SATURATE
) FIXME("ILS_SATURATE: unimplemented!\n");
1193 if (fState
& ILS_GLOW
) FIXME("ILS_GLOW: unimplemented!\n");
1194 if (fState
& ILS_SHADOW
) FIXME("ILS_SHADOW: unimplemented!\n");
1195 if (fState
& ILS_ALPHA
) FIXME("ILS_SHADOW: unimplemented!\n");
1197 if (fStyle
& ILD_PRESERVEALPHA
) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1198 if (fStyle
& ILD_SCALE
) FIXME("ILD_SCALE: unimplemented!\n");
1199 if (fStyle
& ILD_DPISCALE
) FIXME("ILD_DPISCALE: unimplemented!\n");
1201 /* now copy the image to the screen */
1203 if (himl
->hbmMask
&& bIsTransparent
&& !(fStyle
& ILD_MASK
)) {
1204 COLORREF oldDstFg
= SetTextColor(pimldp
->hdcDst
, RGB( 0, 0, 0 ) );
1205 COLORREF oldDstBk
= SetBkColor(pimldp
->hdcDst
, RGB( 0xff, 0xff, 0xff ));
1206 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hMaskListDC
, lx
, ly
, SRCAND
);
1207 SetBkColor(pimldp
->hdcDst
, oldDstBk
);
1208 SetTextColor(pimldp
->hdcDst
, oldDstFg
);
1211 if (fStyle
& ILD_ROP
) dwRop
= pimldp
->dwRop
;
1212 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hImageDC
, 0, 0, dwRop
);
1216 /* cleanup the mess */
1217 SetBkColor(hImageDC
, oldImageBk
);
1218 SetTextColor(hImageDC
, oldImageFg
);
1219 SelectObject(hImageDC
, hOldImageBmp
);
1220 SelectObject(hImageListDC
, hOldImageListBmp
);
1221 if (hMaskListDC
) SelectObject(hMaskListDC
, hOldMaskListBmp
);
1223 DeleteObject(hBlendMaskBmp
);
1224 DeleteObject(hImageBmp
);
1225 DeleteObject(hImageDC
);
1226 DeleteObject(hImageListDC
);
1227 DeleteObject(hMaskListDC
);
1233 /*************************************************************************
1234 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1237 * himlSrc [I] source image list handle
1240 * Success: Handle of duplicated image list.
1245 ImageList_Duplicate (HIMAGELIST himlSrc
)
1250 if (himlSrc
== NULL
) {
1251 ERR("Invalid image list handle!\n");
1255 himlDst
= ImageList_Create (himlSrc
->cx
, himlSrc
->cy
, himlSrc
->flags
,
1256 himlSrc
->cInitial
, himlSrc
->cGrow
);
1260 hdcSrc
= CreateCompatibleDC (0);
1261 hdcDst
= CreateCompatibleDC (0);
1262 SelectObject (hdcSrc
, himlSrc
->hbmImage
);
1263 SelectObject (hdcDst
, himlDst
->hbmImage
);
1264 BitBlt (hdcDst
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
, himlSrc
->cy
,
1265 hdcSrc
, 0, 0, SRCCOPY
);
1267 if (himlDst
->hbmMask
)
1269 SelectObject (hdcSrc
, himlSrc
->hbmMask
);
1270 SelectObject (hdcDst
, himlDst
->hbmMask
);
1271 BitBlt (hdcDst
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
,
1272 himlSrc
->cy
, hdcSrc
, 0, 0, SRCCOPY
);
1278 himlDst
->cCurImage
= himlSrc
->cCurImage
;
1279 himlDst
->cMaxImage
= himlSrc
->cMaxImage
;
1285 /*************************************************************************
1286 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1288 * Finishes a drag operation.
1299 ImageList_EndDrag (void)
1301 /* cleanup the InternalDrag struct */
1302 InternalDrag
.hwnd
= 0;
1303 ImageList_Destroy (InternalDrag
.himl
);
1304 InternalDrag
.himl
= 0;
1307 InternalDrag
.dxHotspot
= 0;
1308 InternalDrag
.dyHotspot
= 0;
1309 InternalDrag
.bShow
= FALSE
;
1310 DeleteObject(InternalDrag
.hbmBg
);
1311 InternalDrag
.hbmBg
= 0;
1312 InternalDrag
.bHSPending
= FALSE
;
1318 /*************************************************************************
1319 * ImageList_GetBkColor [COMCTL32.@]
1321 * Returns the background color of an image list.
1324 * himl [I] Image list handle.
1327 * Success: background color
1332 ImageList_GetBkColor (HIMAGELIST himl
)
1334 return himl
? himl
->clrBk
: CLR_NONE
;
1338 /*************************************************************************
1339 * ImageList_GetDragImage [COMCTL32.@]
1341 * Returns the handle to the internal drag image list.
1344 * ppt [O] Pointer to the drag position. Can be NULL.
1345 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1348 * Success: Handle of the drag image list.
1353 ImageList_GetDragImage (POINT
*ppt
, POINT
*pptHotspot
)
1355 if (InternalDrag
.himl
) {
1357 ppt
->x
= InternalDrag
.x
;
1358 ppt
->y
= InternalDrag
.y
;
1361 pptHotspot
->x
= InternalDrag
.dxHotspot
;
1362 pptHotspot
->y
= InternalDrag
.dyHotspot
;
1364 return (InternalDrag
.himl
);
1371 /*************************************************************************
1372 * ImageList_GetFlags [COMCTL32.@]
1379 ImageList_GetFlags(HIMAGELIST himl
)
1381 FIXME("(%p):empty stub\n", himl
);
1386 /*************************************************************************
1387 * ImageList_GetIcon [COMCTL32.@]
1389 * Creates an icon from a masked image of an image list.
1392 * himl [I] handle to image list
1394 * flags [I] drawing style flags
1397 * Success: icon handle
1402 ImageList_GetIcon (HIMAGELIST himl
, INT i
, UINT fStyle
)
1406 HBITMAP hOldDstBitmap
;
1409 if ((himl
== NULL
) || (i
< 0) || (i
>= himl
->cCurImage
)) return 0;
1411 hdcDst
= CreateCompatibleDC(0);
1416 ii
.hbmMask
= CreateCompatibleBitmap (hdcDst
, himl
->cx
, himl
->cy
);
1417 hOldDstBitmap
= (HBITMAP
)SelectObject (hdcDst
, ii
.hbmMask
);
1418 ImageList_Draw(himl
, i
, hdcDst
, 0, 0, ILD_MASK
);
1421 SelectObject (hdcDst
, himl
->hbmImage
);
1422 ii
.hbmColor
= CreateCompatibleBitmap (hdcDst
, himl
->cx
, himl
->cy
);
1423 SelectObject (hdcDst
, ii
.hbmColor
);
1424 ImageList_Draw(himl
, i
, hdcDst
, 0, 0, fStyle
);
1427 * CreateIconIndirect requires us to deselect the bitmaps from
1428 * the DCs before calling
1430 SelectObject(hdcDst
, hOldDstBitmap
);
1432 hIcon
= CreateIconIndirect (&ii
);
1434 DeleteObject (ii
.hbmMask
);
1435 DeleteObject (ii
.hbmColor
);
1442 /*************************************************************************
1443 * ImageList_GetIconSize [COMCTL32.@]
1445 * Retrieves the size of an image in an image list.
1448 * himl [I] handle to image list
1449 * cx [O] pointer to the image width.
1450 * cy [O] pointer to the image height.
1457 * All images in an image list have the same size.
1461 ImageList_GetIconSize (HIMAGELIST himl
, INT
*cx
, INT
*cy
)
1465 if ((himl
->cx
<= 0) || (himl
->cy
<= 0))
1477 /*************************************************************************
1478 * ImageList_GetImageCount [COMCTL32.@]
1480 * Returns the number of images in an image list.
1483 * himl [I] handle to image list
1486 * Success: Number of images.
1491 ImageList_GetImageCount (HIMAGELIST himl
)
1496 return himl
->cCurImage
;
1500 /*************************************************************************
1501 * ImageList_GetImageInfo [COMCTL32.@]
1503 * Returns information about an image in an image list.
1506 * himl [I] handle to image list
1508 * pImageInfo [O] pointer to the image information
1516 ImageList_GetImageInfo (HIMAGELIST himl
, INT i
, IMAGEINFO
*pImageInfo
)
1518 if ((himl
== NULL
) || (pImageInfo
== NULL
))
1520 if ((i
< 0) || (i
>= himl
->cCurImage
))
1523 pImageInfo
->hbmImage
= himl
->hbmImage
;
1524 pImageInfo
->hbmMask
= himl
->hbmMask
;
1526 pImageInfo
->rcImage
.top
= 0;
1527 pImageInfo
->rcImage
.bottom
= himl
->cy
;
1528 pImageInfo
->rcImage
.left
= i
* himl
->cx
;
1529 pImageInfo
->rcImage
.right
= (i
+1) * himl
->cx
;
1535 /*************************************************************************
1536 * ImageList_GetImageRect [COMCTL32.@]
1538 * Retrieves the rectangle of the specified image in an image list.
1541 * himl [I] handle to image list
1543 * lpRect [O] pointer to the image rectangle
1550 * This is an UNDOCUMENTED function!!!
1554 ImageList_GetImageRect (HIMAGELIST himl
, INT i
, LPRECT lpRect
)
1556 if ((himl
== NULL
) || (lpRect
== NULL
))
1558 if ((i
< 0) || (i
>= himl
->cCurImage
))
1561 lpRect
->left
= i
* himl
->cx
;
1563 lpRect
->right
= lpRect
->left
+ himl
->cx
;
1564 lpRect
->bottom
= himl
->cy
;
1570 /*************************************************************************
1571 * ImageList_LoadImage [COMCTL32.@]
1572 * ImageList_LoadImageA [COMCTL32.@]
1574 * Creates an image list from a bitmap, icon or cursor.
1577 * hi [I] instance handle
1578 * lpbmp [I] name or id of the image
1579 * cx [I] width of each image
1580 * cGrow [I] number of images to expand
1581 * clrMask [I] mask color
1582 * uType [I] type of image to load
1583 * uFlags [I] loading flags
1586 * Success: handle to the loaded image list
1594 ImageList_LoadImageA (HINSTANCE hi
, LPCSTR lpbmp
, INT cx
, INT cGrow
,
1595 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1597 HIMAGELIST himl
= NULL
;
1601 handle
= LoadImageA (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1603 ERR("Error loading image!\n");
1607 if (uType
== IMAGE_BITMAP
) {
1609 GetObjectA (handle
, sizeof(BITMAP
), &bmp
);
1611 /* To match windows behavior, if cx is set to zero and
1612 the flag DI_DEFAULTSIZE is specified, cx becomes the
1613 system metric value for icons. If the flag is not specified
1614 the function sets the size to the height of the bitmap */
1617 if (uFlags
& DI_DEFAULTSIZE
)
1618 cx
= GetSystemMetrics (SM_CXICON
);
1623 nImageCount
= bmp
.bmWidth
/ cx
;
1625 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1626 nImageCount
, cGrow
);
1627 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1629 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1633 GetIconInfo (handle
, &ii
);
1634 GetObjectA (ii
.hbmColor
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1635 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1636 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1637 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1638 DeleteObject (ii
.hbmColor
);
1639 DeleteObject (ii
.hbmMask
);
1642 DeleteObject (handle
);
1648 /*************************************************************************
1649 * ImageList_LoadImageW [COMCTL32.@]
1651 * Creates an image list from a bitmap, icon or cursor.
1654 * hi [I] instance handle
1655 * lpbmp [I] name or id of the image
1656 * cx [I] width of each image
1657 * cGrow [I] number of images to expand
1658 * clrMask [I] mask color
1659 * uType [I] type of image to load
1660 * uFlags [I] loading flags
1663 * Success: handle to the loaded image list
1671 ImageList_LoadImageW (HINSTANCE hi
, LPCWSTR lpbmp
, INT cx
, INT cGrow
,
1672 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1674 HIMAGELIST himl
= NULL
;
1678 handle
= LoadImageW (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1680 ERR("Error loading image!\n");
1684 if (uType
== IMAGE_BITMAP
) {
1686 GetObjectA (handle
, sizeof(BITMAP
), &bmp
);
1688 /* To match windows behavior, if cx is set to zero and
1689 the flag DI_DEFAULTSIZE is specified, cx becomes the
1690 system metric value for icons. If the flag is not specified
1691 the function sets the size to the height of the bitmap */
1694 if (uFlags
& DI_DEFAULTSIZE
)
1695 cx
= GetSystemMetrics (SM_CXICON
);
1700 nImageCount
= bmp
.bmWidth
/ cx
;
1702 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1703 nImageCount
, cGrow
);
1704 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1706 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1710 GetIconInfo (handle
, &ii
);
1711 GetObjectA (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1712 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1713 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1714 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1715 DeleteObject (ii
.hbmColor
);
1716 DeleteObject (ii
.hbmMask
);
1719 DeleteObject (handle
);
1725 /*************************************************************************
1726 * ImageList_Merge [COMCTL32.@]
1728 * Creates a new image list that contains a merged image from the specified
1729 * images of both source image lists.
1732 * himl1 [I] handle to first image list
1733 * i1 [I] first image index
1734 * himl2 [I] handle to second image list
1735 * i2 [I] second image index
1736 * dx [I] X offset of the second image relative to the first.
1737 * dy [I] Y offset of the second image relative to the first.
1740 * Success: handle of the merged image list.
1745 ImageList_Merge (HIMAGELIST himl1
, INT i1
, HIMAGELIST himl2
, INT i2
,
1748 HIMAGELIST himlDst
= NULL
;
1749 HDC hdcSrcImage
, hdcDstImage
;
1751 INT xOff1
, yOff1
, xOff2
, yOff2
;
1754 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1
, i1
, himl2
,
1757 if ((himl1
== NULL
) || (himl2
== NULL
))
1761 if ((i1
< 0) || (i1
>= himl1
->cCurImage
)) {
1762 ERR("Index 1 out of range! %d\n", i1
);
1766 if ((i2
< 0) || (i2
>= himl2
->cCurImage
)) {
1767 ERR("Index 2 out of range! %d\n", i2
);
1772 cxDst
= max (himl1
->cx
, dx
+ himl2
->cx
);
1777 cxDst
= max (himl2
->cx
, himl1
->cx
- dx
);
1782 cxDst
= max (himl1
->cx
, himl2
->cx
);
1788 cyDst
= max (himl1
->cy
, dy
+ himl2
->cy
);
1793 cyDst
= max (himl2
->cy
, himl1
->cy
- dy
);
1798 cyDst
= max (himl1
->cy
, himl2
->cy
);
1803 himlDst
= ImageList_Create (cxDst
, cyDst
, ILC_MASK
| ILC_COLOR
, 1, 1);
1806 hdcSrcImage
= CreateCompatibleDC (0);
1807 hdcDstImage
= CreateCompatibleDC (0);
1808 nX1
= i1
* himl1
->cx
;
1809 nX2
= i2
* himl2
->cx
;
1812 SelectObject (hdcSrcImage
, himl1
->hbmImage
);
1813 SelectObject (hdcDstImage
, himlDst
->hbmImage
);
1814 BitBlt (hdcDstImage
, 0, 0, cxDst
, cyDst
,
1815 hdcSrcImage
, 0, 0, BLACKNESS
);
1816 BitBlt (hdcDstImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
,
1817 hdcSrcImage
, nX1
, 0, SRCCOPY
);
1819 SelectObject (hdcSrcImage
, himl2
->hbmMask
);
1820 BitBlt (hdcDstImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
,
1821 hdcSrcImage
, nX2
, 0, SRCAND
);
1823 SelectObject (hdcSrcImage
, himl2
->hbmImage
);
1824 BitBlt (hdcDstImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
,
1825 hdcSrcImage
, nX2
, 0, SRCPAINT
);
1828 SelectObject (hdcSrcImage
, himl1
->hbmMask
);
1829 SelectObject (hdcDstImage
, himlDst
->hbmMask
);
1830 BitBlt (hdcDstImage
, 0, 0, cxDst
, cyDst
,
1831 hdcSrcImage
, 0, 0, WHITENESS
);
1832 BitBlt (hdcDstImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
,
1833 hdcSrcImage
, nX1
, 0, SRCCOPY
);
1835 SelectObject (hdcSrcImage
, himl2
->hbmMask
);
1836 BitBlt (hdcDstImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
,
1837 hdcSrcImage
, nX2
, 0, SRCAND
);
1839 DeleteDC (hdcSrcImage
);
1840 DeleteDC (hdcDstImage
);
1841 himlDst
->cCurImage
= 1;
1848 /* helper for _read_bitmap currently unused */
1850 static int may_use_dibsection(HDC hdc
) {
1851 int bitspixel
= GetDeviceCaps(hdc
,BITSPIXEL
)*GetDeviceCaps(hdc
,PLANES
);
1856 return GetDeviceCaps(hdc
,CAPS1
) & C1_DIBENGINE
;
1860 /* helper for ImageList_Read, see comments below */
1861 static HBITMAP
_read_bitmap(LPSTREAM pstm
,int ilcFlag
,int cx
,int cy
) {
1863 BITMAPFILEHEADER bmfh
;
1864 BITMAPINFOHEADER bmih
;
1865 int bitsperpixel
,palspace
,longsperline
,width
,height
;
1866 LPBITMAPINFOHEADER bmihc
= NULL
;
1868 HBITMAP hbitmap
= 0;
1869 LPBYTE bits
= NULL
,nbits
= NULL
;
1870 int nbytesperline
,bytesperline
;
1872 if (!SUCCEEDED(IStream_Read ( pstm
, &bmfh
, sizeof(bmfh
), NULL
)) ||
1873 (bmfh
.bfType
!= (('M'<<8)|'B')) ||
1874 !SUCCEEDED(IStream_Read ( pstm
, &bmih
, sizeof(bmih
), NULL
)) ||
1875 (bmih
.biSize
!= sizeof(bmih
))
1879 bitsperpixel
= bmih
.biPlanes
* bmih
.biBitCount
;
1880 if (bitsperpixel
<=8)
1881 palspace
= (1<<bitsperpixel
)*sizeof(RGBQUAD
);
1884 width
= bmih
.biWidth
;
1885 height
= bmih
.biHeight
;
1886 bmihc
= (LPBITMAPINFOHEADER
)LocalAlloc(LMEM_ZEROINIT
,sizeof(bmih
)+palspace
);
1887 memcpy(bmihc
,&bmih
,sizeof(bmih
));
1888 longsperline
= ((width
*bitsperpixel
+31)&~0x1f)>>5;
1889 bmihc
->biSizeImage
= (longsperline
*height
)<<2;
1891 /* read the palette right after the end of the bitmapinfoheader */
1893 if (!SUCCEEDED(IStream_Read ( pstm
, bmihc
+1, palspace
, NULL
)))
1897 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1898 if ((bitsperpixel
>1) &&
1899 ((ilcFlag
!=ILC_COLORDDB
) && (!ilcFlag
|| may_use_dibsection(xdc
)))
1901 hbitmap
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1904 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1910 int i
,nwidth
,nheight
;
1912 nwidth
= width
*(height
/cy
);
1915 if (bitsperpixel
==1)
1916 hbitmap
= CreateBitmap(nwidth
,nheight
,1,1,NULL
);
1918 hbitmap
= CreateCompatibleBitmap(xdc
,nwidth
,nheight
);
1920 /* Might be a bit excessive memory use here */
1921 bits
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
,bmihc
->biSizeImage
);
1922 nbits
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
,bmihc
->biSizeImage
);
1923 if (!SUCCEEDED(IStream_Read ( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1926 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1927 /* Do not forget that windows bitmaps are bottom->top */
1928 bytesperline
= longsperline
*4;
1929 nbytesperline
= (height
/cy
)*bytesperline
;
1930 for (i
=0;i
<height
;i
++) {
1932 nbits
+((height
-1-i
)%cy
)*nbytesperline
+(i
/cy
)*bytesperline
,
1933 bits
+bytesperline
*(height
-1-i
),
1937 bmihc
->biWidth
= nwidth
;
1938 bmihc
->biHeight
= nheight
;
1939 if (!SetDIBits(xdc
,hbitmap
,0,nheight
,nbits
,(BITMAPINFO
*)bmihc
,0))
1941 LocalFree((HLOCAL
)nbits
);
1942 LocalFree((HLOCAL
)bits
);
1946 if (xdc
) ReleaseDC(0,xdc
);
1947 if (bmihc
) LocalFree((HLOCAL
)bmihc
);
1950 DeleteObject(hbitmap
);
1957 /*************************************************************************
1958 * ImageList_Read [COMCTL32.@]
1960 * Reads an image list from a stream.
1963 * pstm [I] pointer to a stream
1966 * Success: handle to image list
1969 * The format is like this:
1970 * ILHEAD ilheadstruct;
1972 * for the color image part:
1973 * BITMAPFILEHEADER bmfh;
1974 * BITMAPINFOHEADER bmih;
1975 * only if it has a palette:
1976 * RGBQUAD rgbs[nr_of_paletted_colors];
1978 * BYTE colorbits[imagesize];
1980 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1981 * BITMAPFILEHEADER bmfh_mask;
1982 * BITMAPINFOHEADER bmih_mask;
1983 * only if it has a palette (it usually does not):
1984 * RGBQUAD rgbs[nr_of_paletted_colors];
1986 * BYTE maskbits[imagesize];
1988 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1989 * _read_bitmap needs to convert them.
1991 HIMAGELIST WINAPI
ImageList_Read (LPSTREAM pstm
)
1995 HBITMAP hbmColor
=0,hbmMask
=0;
1998 if (!SUCCEEDED(IStream_Read (pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
2000 if (ilHead
.usMagic
!= (('L' << 8) | 'I'))
2002 if (ilHead
.usVersion
!= 0x101) /* probably version? */
2006 FIXME(" ilHead.cCurImage = %d\n",ilHead
.cCurImage
);
2007 FIXME(" ilHead.cMaxImage = %d\n",ilHead
.cMaxImage
);
2008 FIXME(" ilHead.cGrow = %d\n",ilHead
.cGrow
);
2009 FIXME(" ilHead.cx = %d\n",ilHead
.cx
);
2010 FIXME(" ilHead.cy = %d\n",ilHead
.cy
);
2011 FIXME(" ilHead.flags = %x\n",ilHead
.flags
);
2012 FIXME(" ilHead.ovls[0] = %d\n",ilHead
.ovls
[0]);
2013 FIXME(" ilHead.ovls[1] = %d\n",ilHead
.ovls
[1]);
2014 FIXME(" ilHead.ovls[2] = %d\n",ilHead
.ovls
[2]);
2015 FIXME(" ilHead.ovls[3] = %d\n",ilHead
.ovls
[3]);
2018 hbmColor
= _read_bitmap(pstm
,ilHead
.flags
& ~ILC_MASK
,ilHead
.cx
,ilHead
.cy
);
2021 if (ilHead
.flags
& ILC_MASK
) {
2022 hbmMask
= _read_bitmap(pstm
,0,ilHead
.cx
,ilHead
.cy
);
2024 DeleteObject(hbmColor
);
2029 himl
= ImageList_Create (
2037 DeleteObject(hbmColor
);
2038 DeleteObject(hbmMask
);
2041 himl
->hbmImage
= hbmColor
;
2042 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.@] Removes an image from an image list
2057 * himl [I] image list handle
2066 ImageList_Remove (HIMAGELIST himl
, INT i
)
2068 HBITMAP hbmNewImage
, hbmNewMask
;
2072 TRACE("(himl=%p i=%d)\n", himl
, i
);
2075 ERR("Invalid image list handle!\n");
2079 if ((i
< -1) || (i
>= himl
->cCurImage
)) {
2080 ERR("index out of range! %d\n", i
);
2086 if (himl
->cCurImage
== 0) {
2087 /* remove all on empty ImageList is allowed */
2088 TRACE("remove all on empty ImageList!\n");
2092 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2093 himl
->cCurImage
= 0;
2094 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2095 himl
->nOvlIdx
[nCount
] = -1;
2097 DeleteObject (himl
->hbmImage
);
2099 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2100 1, himl
->uBitsPixel
, NULL
);
2102 if (himl
->hbmMask
) {
2103 DeleteObject (himl
->hbmMask
);
2105 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2110 /* delete one image */
2111 TRACE("Remove single image! %d\n", i
);
2113 /* create new bitmap(s) */
2114 cxNew
= (himl
->cCurImage
+ himl
->cGrow
- 1) * himl
->cx
;
2116 TRACE(" - Number of images: %d / %d (Old/New)\n",
2117 himl
->cCurImage
, himl
->cCurImage
- 1);
2118 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2119 himl
->cMaxImage
, himl
->cCurImage
+ himl
->cGrow
- 1);
2122 CreateBitmap (cxNew
, himl
->cy
, 1, himl
->uBitsPixel
, NULL
);
2125 hbmNewMask
= CreateBitmap (cxNew
, himl
->cy
, 1, 1, NULL
);
2127 hbmNewMask
= 0; /* Just to keep compiler happy! */
2129 hdcSrc
= CreateCompatibleDC (0);
2130 hdcDst
= CreateCompatibleDC (0);
2132 /* copy all images and masks prior to the "removed" image */
2134 TRACE("Pre image copy: Copy %d images\n", i
);
2136 SelectObject (hdcSrc
, himl
->hbmImage
);
2137 SelectObject (hdcDst
, hbmNewImage
);
2138 BitBlt (hdcDst
, 0, 0, i
* himl
->cx
, himl
->cy
,
2139 hdcSrc
, 0, 0, SRCCOPY
);
2141 if (himl
->hbmMask
) {
2142 SelectObject (hdcSrc
, himl
->hbmMask
);
2143 SelectObject (hdcDst
, hbmNewMask
);
2144 BitBlt (hdcDst
, 0, 0, i
* himl
->cx
, himl
->cy
,
2145 hdcSrc
, 0, 0, SRCCOPY
);
2149 /* copy all images and masks behind the removed image */
2150 if (i
< himl
->cCurImage
- 1) {
2151 TRACE("Post image copy!\n");
2152 SelectObject (hdcSrc
, himl
->hbmImage
);
2153 SelectObject (hdcDst
, hbmNewImage
);
2154 BitBlt (hdcDst
, i
* himl
->cx
, 0, (himl
->cCurImage
- i
- 1) * himl
->cx
,
2155 himl
->cy
, hdcSrc
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2157 if (himl
->hbmMask
) {
2158 SelectObject (hdcSrc
, himl
->hbmMask
);
2159 SelectObject (hdcDst
, hbmNewMask
);
2160 BitBlt (hdcDst
, i
* himl
->cx
, 0,
2161 (himl
->cCurImage
- i
- 1) * himl
->cx
,
2162 himl
->cy
, hdcSrc
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2169 /* delete old images and insert new ones */
2170 DeleteObject (himl
->hbmImage
);
2171 himl
->hbmImage
= hbmNewImage
;
2172 if (himl
->hbmMask
) {
2173 DeleteObject (himl
->hbmMask
);
2174 himl
->hbmMask
= hbmNewMask
;
2178 himl
->cMaxImage
= himl
->cCurImage
+ himl
->cGrow
;
2185 /*************************************************************************
2186 * ImageList_Replace [COMCTL32.@]
2188 * Replaces an image in an image list with a new image.
2191 * himl [I] handle to image list
2193 * hbmImage [I] handle to image bitmap
2194 * hbmMask [I] handle to mask bitmap. Can be NULL.
2202 ImageList_Replace (HIMAGELIST himl
, INT i
, HBITMAP hbmImage
,
2205 HDC hdcImageList
, hdcImage
;
2208 TRACE("%p %d %p %p\n", himl
, i
, hbmImage
, hbmMask
);
2211 ERR("Invalid image list handle!\n");
2215 if ((i
>= himl
->cMaxImage
) || (i
< 0)) {
2216 ERR("Invalid image index!\n");
2220 hdcImageList
= CreateCompatibleDC (0);
2221 hdcImage
= CreateCompatibleDC (0);
2222 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2225 SelectObject (hdcImageList
, himl
->hbmImage
);
2226 SelectObject (hdcImage
, hbmImage
);
2228 StretchBlt (hdcImageList
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2229 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2234 SelectObject (hdcImageList
, himl
->hbmMask
);
2235 SelectObject (hdcImage
, hbmMask
);
2237 StretchBlt (hdcImageList
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2238 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2241 /* Remove the background from the image
2243 SelectObject (hdcImageList
, himl
->hbmImage
);
2244 StretchBlt (hdcImageList
,
2245 i
*himl
->cx
, 0, himl
->cx
, himl
->cy
,
2247 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
2248 0x220326); /* NOTSRCAND */
2251 DeleteDC (hdcImage
);
2252 DeleteDC (hdcImageList
);
2258 /*************************************************************************
2259 * ImageList_ReplaceIcon [COMCTL32.@]
2261 * Replaces an image in an image list using an icon.
2264 * himl [I] handle to image list
2266 * hIcon [I] handle to icon
2269 * Success: index of the replaced image
2274 ImageList_ReplaceIcon (HIMAGELIST himl
, INT i
, HICON hIcon
)
2276 HDC hdcImageList
, hdcImage
;
2279 HBITMAP hbmOldSrc
, hbmOldDst
;
2283 TRACE("(0x%lx 0x%x %p)\n", (DWORD
)himl
, i
, hIcon
);
2287 if ((i
>= himl
->cMaxImage
) || (i
< -1))
2290 hBestFitIcon
= CopyImage(
2293 LR_COPYFROMRESOURCE
);
2295 GetIconInfo (hBestFitIcon
, &ii
);
2296 if (ii
.hbmMask
== 0)
2298 if (ii
.hbmColor
== 0)
2300 GetObjectA (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2303 if (himl
->cCurImage
+ 1 > himl
->cMaxImage
)
2304 IMAGELIST_InternalExpandBitmaps (himl
, 1, 0, 0);
2306 nIndex
= himl
->cCurImage
;
2312 hdcImageList
= CreateCompatibleDC (0);
2313 TRACE("hdcImageList=%p!\n", hdcImageList
);
2314 if (hdcImageList
== 0)
2315 ERR("invalid hdcImageList!\n");
2317 hdcImage
= CreateCompatibleDC (0);
2318 TRACE("hdcImage=%p!\n", hdcImage
);
2320 ERR("invalid hdcImage!\n");
2322 hbmOldDst
= SelectObject (hdcImageList
, himl
->hbmImage
);
2323 SetTextColor( hdcImageList
, RGB(0,0,0));
2324 SetBkColor( hdcImageList
, RGB(255,255,255));
2325 hbmOldSrc
= SelectObject (hdcImage
, ii
.hbmColor
);
2326 StretchBlt (hdcImageList
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2327 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2329 if (himl
->hbmMask
) {
2330 SelectObject (hdcImageList
, himl
->hbmMask
);
2331 SelectObject (hdcImage
, ii
.hbmMask
);
2332 StretchBlt (hdcImageList
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2333 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2336 SelectObject (hdcImage
, hbmOldSrc
);
2337 SelectObject (hdcImageList
, hbmOldDst
);
2340 DestroyIcon(hBestFitIcon
);
2342 DeleteDC (hdcImageList
);
2344 DeleteDC (hdcImage
);
2346 DeleteObject (ii
.hbmColor
);
2348 DeleteObject (ii
.hbmMask
);
2354 /*************************************************************************
2355 * ImageList_SetBkColor [COMCTL32.@]
2357 * Sets the background color of an image list.
2360 * himl [I] handle to image list
2361 * clrBk [I] background color
2364 * Success: previous background color
2369 ImageList_SetBkColor (HIMAGELIST himl
, COLORREF clrBk
)
2376 clrOldBk
= himl
->clrBk
;
2377 himl
->clrBk
= clrBk
;
2382 /*************************************************************************
2383 * ImageList_SetDragCursorImage [COMCTL32.@]
2385 * Combines the specified image with the current drag image
2388 * himlDrag [I] handle to drag image list
2389 * iDrag [I] drag image index
2390 * dxHotspot [I] X position of the hot spot
2391 * dyHotspot [I] Y position of the hot spot
2398 * When this function is called and the drag image is visible, a
2399 * short flickering occurs but this matches the Win9x behavior. It is
2400 * possible to fix the flickering using code like in ImageList_DragMove.
2404 ImageList_SetDragCursorImage (HIMAGELIST himlDrag
, INT iDrag
,
2405 INT dxHotspot
, INT dyHotspot
)
2407 HIMAGELIST himlTemp
;
2411 if (InternalDrag
.himl
== NULL
)
2414 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2415 dxHotspot
, dyHotspot
, InternalDrag
.dxHotspot
, InternalDrag
.dyHotspot
);
2417 visible
= InternalDrag
.bShow
;
2419 /* Calculate the offset between the origin of the old image and the
2420 * origin of the second image.
2421 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2422 * hotspot) to the origin of the second image.
2423 * See M$DN for details */
2424 if(InternalDrag
.bHSPending
) {
2427 InternalDrag
.bHSPending
= FALSE
;
2429 dx
= InternalDrag
.dxHotspot
- dxHotspot
;
2430 dy
= InternalDrag
.dyHotspot
- dyHotspot
;
2432 himlTemp
= ImageList_Merge (InternalDrag
.himl
, 0, himlDrag
, iDrag
, dx
, dy
);
2435 /* hide the drag image */
2436 ImageList_DragShowNolock(FALSE
);
2438 if ((InternalDrag
.himl
->cx
!= himlTemp
->cx
) ||
2439 (InternalDrag
.himl
->cy
!= himlTemp
->cy
)) {
2440 /* the size of the drag image changed, invalidate the buffer */
2441 DeleteObject(InternalDrag
.hbmBg
);
2442 InternalDrag
.hbmBg
= 0;
2445 ImageList_Destroy (InternalDrag
.himl
);
2446 InternalDrag
.himl
= himlTemp
;
2448 /* update the InternalDragOffset, if the origin of the
2449 * DragImage was changed by ImageList_Merge. */
2451 InternalDrag
.dxHotspot
= dxHotspot
;
2453 InternalDrag
.dyHotspot
= dyHotspot
;
2456 /* show the drag image */
2457 ImageList_DragShowNolock(TRUE
);
2464 /*************************************************************************
2465 * ImageList_SetFilter [COMCTL32.@]
2467 * Sets a filter (or does something completely different)!!???
2468 * It removes 12 Bytes from the stack (3 Parameters).
2471 * himl [I] SHOULD be a handle to image list
2472 * i [I] COULD be an index?
2477 * Failure: FALSE ???
2480 * This is an UNDOCUMENTED function!!!!
2485 ImageList_SetFilter (HIMAGELIST himl
, INT i
, DWORD dwFilter
)
2487 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl
, i
, dwFilter
);
2493 /*************************************************************************
2494 * ImageList_SetFlags [COMCTL32.@]
2501 ImageList_SetFlags(HIMAGELIST himl
, DWORD flags
)
2503 FIXME("(%p %08lx):empty stub\n", himl
, flags
);
2508 /*************************************************************************
2509 * ImageList_SetIconSize [COMCTL32.@]
2511 * Sets the image size of the bitmap and deletes all images.
2514 * himl [I] handle to image list
2515 * cx [I] image width
2516 * cy [I] image height
2524 ImageList_SetIconSize (HIMAGELIST himl
, INT cx
, INT cy
)
2531 /* remove all images */
2532 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2533 himl
->cCurImage
= 0;
2537 /* initialize overlay mask indices */
2538 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2539 himl
->nOvlIdx
[nCount
] = -1;
2541 DeleteObject (himl
->hbmImage
);
2543 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2544 1, himl
->uBitsPixel
, NULL
);
2546 if (himl
->hbmMask
) {
2547 DeleteObject (himl
->hbmMask
);
2549 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2557 /*************************************************************************
2558 * ImageList_SetImageCount [COMCTL32.@]
2560 * Resizes an image list to the specified number of images.
2563 * himl [I] handle to image list
2564 * iImageCount [I] number of images in the image list
2572 ImageList_SetImageCount (HIMAGELIST himl
, INT iImageCount
)
2574 HDC hdcImageList
, hdcBitmap
;
2575 HBITMAP hbmNewBitmap
;
2576 INT nNewCount
, nCopyCount
;
2578 TRACE("%p %d\n",himl
,iImageCount
);
2582 if (himl
->cCurImage
>= iImageCount
)
2584 if (himl
->cMaxImage
> iImageCount
)
2586 himl
->cCurImage
= iImageCount
;
2590 nNewCount
= iImageCount
+ himl
->cGrow
;
2591 nCopyCount
= min(himl
->cCurImage
, iImageCount
);
2593 hdcImageList
= CreateCompatibleDC (0);
2594 hdcBitmap
= CreateCompatibleDC (0);
2596 hbmNewBitmap
= CreateBitmap (nNewCount
* himl
->cx
, himl
->cy
,
2597 1, himl
->uBitsPixel
, NULL
);
2598 if (hbmNewBitmap
!= 0)
2600 SelectObject (hdcImageList
, himl
->hbmImage
);
2601 SelectObject (hdcBitmap
, hbmNewBitmap
);
2604 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2605 hdcImageList
, 0, 0, SRCCOPY
);
2607 /* delete 'empty' image space */
2608 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2609 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2610 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2611 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2613 DeleteObject (himl
->hbmImage
);
2614 himl
->hbmImage
= hbmNewBitmap
;
2617 ERR("Could not create new image bitmap !\n");
2621 hbmNewBitmap
= CreateBitmap (nNewCount
* himl
->cx
, himl
->cy
,
2623 if (hbmNewBitmap
!= 0)
2625 SelectObject (hdcImageList
, himl
->hbmMask
);
2626 SelectObject (hdcBitmap
, hbmNewBitmap
);
2629 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2630 hdcImageList
, 0, 0, SRCCOPY
);
2632 /* delete 'empty' image space */
2633 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2634 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2635 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2636 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2638 DeleteObject (himl
->hbmMask
);
2639 himl
->hbmMask
= hbmNewBitmap
;
2642 ERR("Could not create new mask bitmap!\n");
2645 DeleteDC (hdcImageList
);
2646 DeleteDC (hdcBitmap
);
2648 /* Update max image count and current image count */
2649 himl
->cMaxImage
= nNewCount
;
2650 himl
->cCurImage
= iImageCount
;
2656 /*************************************************************************
2657 * ImageList_SetOverlayImage [COMCTL32.@]
2659 * Assigns an overlay mask index to an existing image in an image list.
2662 * himl [I] handle to image list
2663 * iImage [I] image index
2664 * iOverlay [I] overlay mask index
2672 ImageList_SetOverlayImage (HIMAGELIST himl
, INT iImage
, INT iOverlay
)
2676 if ((iOverlay
< 1) || (iOverlay
> MAX_OVERLAYIMAGE
))
2678 if ((iImage
!=-1) && ((iImage
< 0) || (iImage
> himl
->cCurImage
)))
2680 himl
->nOvlIdx
[iOverlay
- 1] = iImage
;
2686 /* helper for ImageList_Write - write bitmap to pstm
2687 * currently everything is written as 24 bit RGB, except masks
2690 _write_bitmap(HBITMAP hBitmap
, LPSTREAM pstm
, int cx
, int cy
)
2692 LPBITMAPFILEHEADER bmfh
;
2693 LPBITMAPINFOHEADER bmih
;
2694 LPBYTE data
, lpBits
, lpBitsOrg
;
2696 INT bitCount
, sizeImage
, offBits
, totalSize
;
2697 INT nwidth
, nheight
, nsizeImage
, icount
;
2699 BOOL result
= FALSE
;
2703 GetObjectA(hBitmap
, sizeof(BITMAP
), (LPVOID
)&bm
);
2705 /* XXX is this always correct? */
2706 icount
= bm
.bmWidth
/ cx
;
2708 nheight
= cy
* ((icount
+3)>>2);
2710 bitCount
= bm
.bmBitsPixel
== 1 ? 1 : 24;
2711 sizeImage
= ((((bm
.bmWidth
* bitCount
)+31) & ~31) >> 3) * bm
.bmHeight
;
2712 nsizeImage
= ((((nwidth
* bitCount
)+31) & ~31) >> 3) * nheight
;
2714 totalSize
= sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
);
2716 totalSize
+= (1 << bitCount
) * sizeof(RGBQUAD
);
2717 offBits
= totalSize
;
2718 totalSize
+= nsizeImage
;
2720 data
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, totalSize
);
2721 bmfh
= (LPBITMAPFILEHEADER
)data
;
2722 bmih
= (LPBITMAPINFOHEADER
)(data
+ sizeof(BITMAPFILEHEADER
));
2723 lpBits
= data
+ offBits
;
2725 /* setup BITMAPFILEHEADER */
2726 bmfh
->bfType
= (('M' << 8) | 'B');
2728 bmfh
->bfReserved1
= 0;
2729 bmfh
->bfReserved2
= 0;
2730 bmfh
->bfOffBits
= offBits
;
2732 /* setup BITMAPINFOHEADER */
2733 bmih
->biSize
= sizeof(BITMAPINFOHEADER
);
2734 bmih
->biWidth
= bm
.bmWidth
;
2735 bmih
->biHeight
= bm
.bmHeight
;
2737 bmih
->biBitCount
= bitCount
;
2738 bmih
->biCompression
= BI_RGB
;
2739 bmih
->biSizeImage
= nsizeImage
;
2740 bmih
->biXPelsPerMeter
= 0;
2741 bmih
->biYPelsPerMeter
= 0;
2742 bmih
->biClrUsed
= 0;
2743 bmih
->biClrImportant
= 0;
2745 lpBitsOrg
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, nsizeImage
);
2746 if(!GetDIBits(xdc
, hBitmap
, 0, bm
.bmHeight
, lpBitsOrg
,
2747 (BITMAPINFO
*)bmih
, DIB_RGB_COLORS
))
2751 int obpl
= (((bm
.bmWidth
*bitCount
+31) & ~31)>>3);
2752 int nbpl
= (((nwidth
*bitCount
+31) & ~31)>>3);
2754 for(i
= 0; i
< nheight
; i
++) {
2755 int ooff
= ((nheight
-1-i
)%cy
) * obpl
+ ((i
/cy
) * nbpl
);
2756 int noff
= (nbpl
* (nheight
-1-i
));
2757 memcpy(lpBits
+ noff
, lpBitsOrg
+ ooff
, nbpl
);
2761 bmih
->biWidth
= nwidth
;
2762 bmih
->biHeight
= nheight
;
2766 LPBITMAPINFO inf
= (LPBITMAPINFO
)bmih
;
2767 inf
->bmiColors
[0].rgbRed
= inf
->bmiColors
[0].rgbGreen
= inf
->bmiColors
[0].rgbBlue
= 0;
2768 inf
->bmiColors
[1].rgbRed
= inf
->bmiColors
[1].rgbGreen
= inf
->bmiColors
[1].rgbBlue
= 0xff;
2771 if(!SUCCEEDED(IStream_Write(pstm
, data
, totalSize
, NULL
)))
2778 LocalFree((HLOCAL
)lpBitsOrg
);
2784 /*************************************************************************
2785 * ImageList_Write [COMCTL32.@]
2787 * Writes an image list to a stream.
2790 * himl [I] handle to image list
2791 * pstm [O] Pointer to a stream.
2802 ImageList_Write (HIMAGELIST himl
, LPSTREAM pstm
)
2810 ilHead
.usMagic
= (('L' << 8) | 'I');
2811 ilHead
.usVersion
= 0x101;
2812 ilHead
.cCurImage
= himl
->cCurImage
;
2813 ilHead
.cMaxImage
= himl
->cMaxImage
;
2814 ilHead
.cGrow
= himl
->cGrow
;
2815 ilHead
.cx
= himl
->cx
;
2816 ilHead
.cy
= himl
->cy
;
2817 ilHead
.bkcolor
= himl
->clrBk
;
2818 ilHead
.flags
= himl
->flags
;
2819 for(i
= 0; i
< 4; i
++) {
2820 ilHead
.ovls
[i
] = himl
->nOvlIdx
[i
];
2823 if(!SUCCEEDED(IStream_Write(pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
2826 /* write the bitmap */
2827 if(!_write_bitmap(himl
->hbmImage
, pstm
, himl
->cx
, himl
->cy
))
2830 /* write the mask if we have one */
2831 if(himl
->flags
& ILC_MASK
) {
2832 if(!_write_bitmap(himl
->hbmMask
, pstm
, himl
->cx
, himl
->cy
))