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 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
39 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
40 * is the offset of the image position relative to the actual mouse pointer
41 * position. However the Hotspot passed to SetDragCursorImage is the
42 * offset of the mouse messages sent to the application...
56 #include "imagelist.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(imagelist
);
62 #define MAX_OVERLAYIMAGE 15
64 /* internal image list data used for Drag & Drop operations */
69 /* position of the drag image relative to the window */
72 /* offset of the hotspot relative to the origin of the image */
75 /* is the drag image visible */
77 /* saved background */
82 static INTERNALDRAG InternalDrag
= { 0, 0, 0, 0, 0, 0, FALSE
, 0, FALSE
};
84 static HBITMAP
ImageList_CreateImage(HDC hdc
, HIMAGELIST himl
, UINT width
, UINT height
);
86 static inline BOOL
is_valid(HIMAGELIST himl
)
88 return himl
&& himl
->magic
== IMAGELIST_MAGIC
;
92 /*************************************************************************
93 * IMAGELIST_InternalExpandBitmaps [Internal]
95 * Expands the bitmaps of an image list by the given number of images.
98 * himl [I] handle to image list
99 * nImageCount [I] number of images to add
105 * This function can NOT be used to reduce the number of images.
108 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl
, INT nImageCount
, INT cx
, INT cy
)
111 HBITMAP hbmNewBitmap
, hbmNull
;
112 INT nNewWidth
, nNewCount
;
114 if ((himl
->cCurImage
+ nImageCount
<= himl
->cMaxImage
)
118 if (cy
== 0) cy
= himl
->cy
;
119 nNewCount
= himl
->cCurImage
+ nImageCount
+ himl
->cGrow
;
120 nNewWidth
= nNewCount
* himl
->cx
;
122 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl
, nNewWidth
, cy
, nNewCount
);
123 hdcBitmap
= CreateCompatibleDC (0);
125 hbmNewBitmap
= ImageList_CreateImage(hdcBitmap
, himl
, nNewWidth
, cy
);
127 if (hbmNewBitmap
== 0)
128 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth
, cy
);
132 hbmNull
= SelectObject (hdcBitmap
, hbmNewBitmap
);
133 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
134 himl
->hdcImage
, 0, 0, SRCCOPY
);
135 SelectObject (hdcBitmap
, hbmNull
);
137 SelectObject (himl
->hdcImage
, hbmNewBitmap
);
138 DeleteObject (himl
->hbmImage
);
139 himl
->hbmImage
= hbmNewBitmap
;
141 if (himl
->flags
& ILC_MASK
)
143 hbmNewBitmap
= CreateBitmap (nNewWidth
, cy
, 1, 1, NULL
);
145 if (hbmNewBitmap
== 0)
146 ERR("creating new mask bitmap!\n");
150 hbmNull
= SelectObject (hdcBitmap
, hbmNewBitmap
);
151 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
152 himl
->hdcMask
, 0, 0, SRCCOPY
);
153 SelectObject (hdcBitmap
, hbmNull
);
155 SelectObject (himl
->hdcMask
, hbmNewBitmap
);
156 DeleteObject (himl
->hbmMask
);
157 himl
->hbmMask
= hbmNewBitmap
;
160 himl
->cMaxImage
= nNewCount
;
162 DeleteDC (hdcBitmap
);
166 /*************************************************************************
167 * ImageList_Add [COMCTL32.@]
169 * Add an image or images to an image list.
172 * himl [I] handle to image list
173 * hbmImage [I] handle to image bitmap
174 * hbmMask [I] handle to mask bitmap
177 * Success: Index of the first new image.
182 ImageList_Add (HIMAGELIST himl
, HBITMAP hbmImage
, HBITMAP hbmMask
)
185 INT nFirstIndex
, nImageCount
;
190 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl
, hbmImage
, hbmMask
);
194 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
195 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
197 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
199 nStartX
= himl
->cCurImage
* himl
->cx
;
201 hdcBitmap
= CreateCompatibleDC(0);
203 hOldBitmap
= SelectObject(hdcBitmap
, hbmImage
);
205 /* Copy result to the imagelist
207 BitBlt (himl
->hdcImage
, nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
208 hdcBitmap
, 0, 0, SRCCOPY
);
213 HBITMAP hOldBitmapTemp
;
215 hdcTemp
= CreateCompatibleDC(0);
216 hOldBitmapTemp
= SelectObject(hdcTemp
, hbmMask
);
218 BitBlt (himl
->hdcMask
,
219 nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
224 SelectObject(hdcTemp
, hOldBitmapTemp
);
227 /* Remove the background from the image
229 BitBlt (himl
->hdcImage
,
230 nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
233 0x220326); /* NOTSRCAND */
236 SelectObject(hdcBitmap
, hOldBitmap
);
239 nFirstIndex
= himl
->cCurImage
;
240 himl
->cCurImage
+= nImageCount
;
246 /*************************************************************************
247 * ImageList_AddIcon [COMCTL32.@]
249 * Adds an icon to an image list.
252 * himl [I] handle to image list
253 * hIcon [I] handle to icon
256 * Success: index of the new image
259 #undef ImageList_AddIcon
260 INT WINAPI
ImageList_AddIcon (HIMAGELIST himl
, HICON hIcon
)
262 return ImageList_ReplaceIcon (himl
, -1, hIcon
);
266 /*************************************************************************
267 * ImageList_AddMasked [COMCTL32.@]
269 * Adds an image or images to an image list and creates a mask from the
270 * specified bitmap using the mask color.
273 * himl [I] handle to image list.
274 * hBitmap [I] handle to bitmap
275 * clrMask [I] mask color.
278 * Success: Index of the first new image.
283 ImageList_AddMasked (HIMAGELIST himl
, HBITMAP hBitmap
, COLORREF clrMask
)
285 HDC hdcMask
, hdcBitmap
;
286 INT nIndex
, nImageCount
, nMaskXOffset
=0;
289 HBITMAP hMaskBitmap
=0;
292 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl
, hBitmap
, clrMask
);
296 if (!GetObjectA (hBitmap
, sizeof(BITMAP
), &bmp
))
300 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
304 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
306 nIndex
= himl
->cCurImage
;
307 himl
->cCurImage
+= nImageCount
;
309 hdcBitmap
= CreateCompatibleDC(0);
312 hOldBitmap
= SelectObject(hdcBitmap
, hBitmap
);
315 hdcMask
= himl
->hdcMask
;
316 nMaskXOffset
= nIndex
* himl
->cx
;
321 Create a temp Mask so we can remove the background of
322 the Image (Windows does this even if there is no mask)
324 hdcMask
= CreateCompatibleDC(0);
325 hMaskBitmap
= CreateBitmap(bmp
.bmWidth
, bmp
.bmHeight
, 1, 1, NULL
);
326 SelectObject(hdcMask
, hMaskBitmap
);
329 /* create monochrome image to the mask bitmap */
330 bkColor
= (clrMask
!= CLR_DEFAULT
) ? clrMask
:
331 GetPixel (hdcBitmap
, 0, 0);
332 SetBkColor (hdcBitmap
, bkColor
);
334 nMaskXOffset
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
338 SetBkColor(hdcBitmap
, RGB(255,255,255));
339 /*Remove the background from the image
342 WINDOWS BUG ALERT!!!!!!
343 The statement below should not be done in common practice
344 but this is how ImageList_AddMasked works in Windows.
345 It overwrites the original bitmap passed, this was discovered
346 by using the same bitmap to iterate the different styles
347 on windows where it failed (BUT ImageList_Add is OK)
348 This is here in case some apps rely on this bug
351 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
354 0x220326); /* NOTSRCAND */
355 /* Copy result to the imagelist
357 BitBlt (himl
->hdcImage
,
358 nIndex
* himl
->cx
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
364 SelectObject(hdcBitmap
, hOldBitmap
);
368 DeleteObject(hMaskBitmap
);
376 /*************************************************************************
377 * ImageList_BeginDrag [COMCTL32.@]
379 * Creates a temporary image list that contains one image. It will be used
383 * himlTrack [I] handle to the source image list
384 * iTrack [I] index of the drag image in the source image list
385 * dxHotspot [I] X position of the hot spot of the drag image
386 * dyHotspot [I] Y position of the hot spot of the drag image
394 ImageList_BeginDrag (HIMAGELIST himlTrack
, INT iTrack
,
395 INT dxHotspot
, INT dyHotspot
)
399 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack
, iTrack
,
400 dxHotspot
, dyHotspot
);
402 if (!is_valid(himlTrack
))
405 if (InternalDrag
.himl
)
406 ImageList_EndDrag ();
411 InternalDrag
.himl
= ImageList_Create (cx
, cy
, himlTrack
->flags
, 1, 1);
412 if (InternalDrag
.himl
== NULL
) {
413 WARN("Error creating drag image list!\n");
417 InternalDrag
.dxHotspot
= dxHotspot
;
418 InternalDrag
.dyHotspot
= dyHotspot
;
421 BitBlt (InternalDrag
.himl
->hdcImage
, 0, 0, cx
, cy
, himlTrack
->hdcImage
, iTrack
* cx
, 0, SRCCOPY
);
424 BitBlt (InternalDrag
.himl
->hdcMask
, 0, 0, cx
, cy
, himlTrack
->hdcMask
, iTrack
* cx
, 0, SRCCOPY
);
426 InternalDrag
.himl
->cCurImage
= 1;
427 InternalDrag
.bHSPending
= TRUE
;
433 /*************************************************************************
434 * ImageList_Copy [COMCTL32.@]
436 * Copies an image of the source image list to an image of the
437 * destination image list. Images can be copied or swapped.
440 * himlDst [I] handle to the destination image list
441 * iDst [I] destination image index.
442 * himlSrc [I] handle to the source image list
443 * iSrc [I] source image index
444 * uFlags [I] flags for the copy operation
451 * Copying from one image list to another is possible. The original
452 * implementation just copies or swaps within one image list.
453 * Could this feature become a bug??? ;-)
457 ImageList_Copy (HIMAGELIST himlDst
, INT iDst
, HIMAGELIST himlSrc
,
458 INT iSrc
, UINT uFlags
)
460 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst
, iDst
, himlSrc
, iSrc
);
462 if (!is_valid(himlSrc
) || !is_valid(himlDst
))
464 if ((iDst
< 0) || (iDst
>= himlDst
->cCurImage
))
466 if ((iSrc
< 0) || (iSrc
>= himlSrc
->cCurImage
))
469 if (uFlags
& ILCF_SWAP
) {
472 HBITMAP hbmTempImage
, hbmTempMask
;
474 hdcBmp
= CreateCompatibleDC (0);
476 /* create temporary bitmaps */
477 hbmTempImage
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
478 himlSrc
->uBitsPixel
, NULL
);
479 hbmTempMask
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
482 /* copy (and stretch) destination to temporary bitmaps.(save) */
484 SelectObject (hdcBmp
, hbmTempImage
);
485 StretchBlt (hdcBmp
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
486 himlDst
->hdcImage
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
489 SelectObject (hdcBmp
, hbmTempMask
);
490 StretchBlt (hdcBmp
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
491 himlDst
->hdcMask
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
494 /* copy (and stretch) source to destination */
496 StretchBlt (himlDst
->hdcImage
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
497 himlSrc
->hdcImage
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
500 StretchBlt (himlDst
->hdcMask
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
501 himlSrc
->hdcMask
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
504 /* copy (without stretching) temporary bitmaps to source (restore) */
506 BitBlt (himlSrc
->hdcMask
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
507 hdcBmp
, 0, 0, SRCCOPY
);
510 BitBlt (himlSrc
->hdcImage
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
511 hdcBmp
, 0, 0, SRCCOPY
);
512 /* delete temporary bitmaps */
513 DeleteObject (hbmTempMask
);
514 DeleteObject (hbmTempImage
);
519 StretchBlt (himlDst
->hdcImage
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
520 himlSrc
->hdcImage
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
524 StretchBlt (himlDst
->hdcMask
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
525 himlSrc
->hdcMask
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
533 /*************************************************************************
534 * ImageList_Create [COMCTL32.@]
536 * Creates a new image list.
539 * cx [I] image height
541 * flags [I] creation flags
542 * cInitial [I] initial number of images in the image list
543 * cGrow [I] number of images by which image list grows
546 * Success: Handle to the created image list
550 ImageList_Create (INT cx
, INT cy
, UINT flags
,
551 INT cInitial
, INT cGrow
)
556 UINT ilc
= (flags
& 0xFE);
557 static WORD aBitBlend25
[] =
558 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
560 static WORD aBitBlend50
[] =
561 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
563 TRACE("(%d %d 0x%x %d %d)\n", cx
, cy
, flags
, cInitial
, cGrow
);
565 himl
= (HIMAGELIST
)Alloc (sizeof(struct _IMAGELIST
));
569 cGrow
= (cGrow
< 4) ? 4 : (cGrow
+ 3) & ~3;
571 himl
->magic
= IMAGELIST_MAGIC
;
575 himl
->cMaxImage
= cInitial
+ cGrow
;
576 himl
->cInitial
= cInitial
;
578 himl
->clrFg
= CLR_DEFAULT
;
579 himl
->clrBk
= CLR_NONE
;
581 /* initialize overlay mask indices */
582 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
583 himl
->nOvlIdx
[nCount
] = -1;
585 /* Create Image & Mask DCs */
586 himl
->hdcImage
= CreateCompatibleDC (0);
589 if (himl
->flags
& ILC_MASK
){
590 himl
->hdcMask
= CreateCompatibleDC(0);
595 /* Default to ILC_COLOR4 if non of the ILC_COLOR* flags are specified */
596 if (ilc
== ILC_COLOR
)
599 if (ilc
>= ILC_COLOR4
&& ilc
<= ILC_COLOR32
)
600 himl
->uBitsPixel
= ilc
;
602 himl
->uBitsPixel
= (UINT
)GetDeviceCaps (himl
->hdcImage
, BITSPIXEL
);
604 if (himl
->cMaxImage
> 0) {
605 himl
->hbmImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, cx
* himl
->cMaxImage
, cy
);
606 SelectObject(himl
->hdcImage
, himl
->hbmImage
);
610 if ((himl
->cMaxImage
> 0) && (himl
->flags
& ILC_MASK
)) {
612 CreateBitmap (himl
->cx
* himl
->cMaxImage
, himl
->cy
,
614 if (himl
->hbmMask
== 0) {
615 ERR("Error creating mask bitmap!\n");
618 SelectObject(himl
->hdcMask
, himl
->hbmMask
);
621 /* create blending brushes */
622 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend25
);
623 himl
->hbrBlend25
= CreatePatternBrush (hbmTemp
);
624 DeleteObject (hbmTemp
);
626 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend50
);
627 himl
->hbrBlend50
= CreatePatternBrush (hbmTemp
);
628 DeleteObject (hbmTemp
);
630 TRACE("created imagelist %p\n", himl
);
634 if (himl
) ImageList_Destroy(himl
);
639 /*************************************************************************
640 * ImageList_Destroy [COMCTL32.@]
642 * Destroys an image list.
645 * himl [I] handle to image list
653 ImageList_Destroy (HIMAGELIST himl
)
658 /* delete image bitmaps */
660 DeleteObject (himl
->hbmImage
);
662 DeleteObject (himl
->hbmMask
);
664 /* delete image & mask DCs */
666 DeleteDC(himl
->hdcImage
);
668 DeleteDC(himl
->hdcMask
);
670 /* delete blending brushes */
671 if (himl
->hbrBlend25
)
672 DeleteObject (himl
->hbrBlend25
);
673 if (himl
->hbrBlend50
)
674 DeleteObject (himl
->hbrBlend50
);
676 ZeroMemory(himl
, sizeof(*himl
));
683 /*************************************************************************
684 * ImageList_DragEnter [COMCTL32.@]
686 * Locks window update and displays the drag image at the given position.
689 * hwndLock [I] handle of the window that owns the drag image.
690 * x [I] X position of the drag image.
691 * y [I] Y position of the drag image.
698 * The position of the drag image is relative to the window, not
703 ImageList_DragEnter (HWND hwndLock
, INT x
, INT y
)
705 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock
, x
, y
);
707 if (!is_valid(InternalDrag
.himl
))
711 InternalDrag
.hwnd
= hwndLock
;
713 InternalDrag
.hwnd
= GetDesktopWindow ();
718 /* draw the drag image and save the background */
719 if (!ImageList_DragShowNolock(TRUE
)) {
727 /*************************************************************************
728 * ImageList_DragLeave [COMCTL32.@]
730 * Unlocks window update and hides the drag image.
733 * hwndLock [I] handle of the window that owns the drag image.
741 ImageList_DragLeave (HWND hwndLock
)
743 /* As we don't save drag info in the window this can lead to problems if
744 an app does not supply the same window as DragEnter */
746 InternalDrag.hwnd = hwndLock;
748 InternalDrag.hwnd = GetDesktopWindow (); */
750 hwndLock
= GetDesktopWindow();
751 if(InternalDrag
.hwnd
!= hwndLock
)
752 FIXME("DragLeave hWnd != DragEnter hWnd\n");
754 ImageList_DragShowNolock (FALSE
);
760 /*************************************************************************
761 * ImageList_InternalDragDraw [Internal]
763 * Draws the drag image.
766 * hdc [I] device context to draw into.
767 * x [I] X position of the drag image.
768 * y [I] Y position of the drag image.
775 * The position of the drag image is relative to the window, not
781 ImageList_InternalDragDraw (HDC hdc
, INT x
, INT y
)
783 IMAGELISTDRAWPARAMS imldp
;
785 ZeroMemory (&imldp
, sizeof(imldp
));
786 imldp
.cbSize
= sizeof(imldp
);
787 imldp
.himl
= InternalDrag
.himl
;
792 imldp
.rgbBk
= CLR_DEFAULT
;
793 imldp
.rgbFg
= CLR_DEFAULT
;
794 imldp
.fStyle
= ILD_NORMAL
;
795 imldp
.fState
= ILS_ALPHA
;
798 /* FIXME: instead of using the alpha blending, we should
799 * create a 50% mask, and draw it semitransparantly that way */
800 ImageList_DrawIndirect (&imldp
);
803 /*************************************************************************
804 * ImageList_DragMove [COMCTL32.@]
806 * Moves the drag image.
809 * x [I] X position of the drag image.
810 * y [I] Y position of the drag image.
817 * The position of the drag image is relative to the window, not
821 * The drag image should be drawn semitransparent.
825 ImageList_DragMove (INT x
, INT y
)
827 TRACE("(x=%d y=%d)\n", x
, y
);
829 if (!is_valid(InternalDrag
.himl
))
832 /* draw/update the drag image */
833 if (InternalDrag
.bShow
) {
837 HBITMAP hbmOffScreen
;
838 INT origNewX
, origNewY
;
839 INT origOldX
, origOldY
;
840 INT origRegX
, origRegY
;
841 INT sizeRegX
, sizeRegY
;
844 /* calculate the update region */
845 origNewX
= x
- InternalDrag
.dxHotspot
;
846 origNewY
= y
- InternalDrag
.dyHotspot
;
847 origOldX
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
848 origOldY
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
849 origRegX
= min(origNewX
, origOldX
);
850 origRegY
= min(origNewY
, origOldY
);
851 sizeRegX
= InternalDrag
.himl
->cx
+ abs(x
- InternalDrag
.x
);
852 sizeRegY
= InternalDrag
.himl
->cy
+ abs(y
- InternalDrag
.y
);
854 hdcDrag
= GetDCEx(InternalDrag
.hwnd
, 0,
855 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
856 hdcOffScreen
= CreateCompatibleDC(hdcDrag
);
857 hdcBg
= CreateCompatibleDC(hdcDrag
);
859 hbmOffScreen
= CreateCompatibleBitmap(hdcDrag
, sizeRegX
, sizeRegY
);
860 SelectObject(hdcOffScreen
, hbmOffScreen
);
861 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
863 /* get the actual background of the update region */
864 BitBlt(hdcOffScreen
, 0, 0, sizeRegX
, sizeRegY
, hdcDrag
,
865 origRegX
, origRegY
, SRCCOPY
);
866 /* erase the old image */
867 BitBlt(hdcOffScreen
, origOldX
- origRegX
, origOldY
- origRegY
,
868 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
, hdcBg
, 0, 0,
870 /* save the background */
871 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
872 hdcOffScreen
, origNewX
- origRegX
, origNewY
- origRegY
, SRCCOPY
);
874 ImageList_InternalDragDraw(hdcOffScreen
, origNewX
- origRegX
,
875 origNewY
- origRegY
);
876 /* draw the update region to the screen */
877 BitBlt(hdcDrag
, origRegX
, origRegY
, sizeRegX
, sizeRegY
,
878 hdcOffScreen
, 0, 0, SRCCOPY
);
881 DeleteDC(hdcOffScreen
);
882 DeleteObject(hbmOffScreen
);
883 ReleaseDC(InternalDrag
.hwnd
, hdcDrag
);
886 /* update the image position */
894 /*************************************************************************
895 * ImageList_DragShowNolock [COMCTL32.@]
897 * Shows or hides the drag image.
900 * bShow [I] TRUE shows the drag image, FALSE hides it.
907 * The drag image should be drawn semitransparent.
911 ImageList_DragShowNolock (BOOL bShow
)
917 if (!is_valid(InternalDrag
.himl
))
920 TRACE("bShow=0x%X!\n", bShow
);
922 /* DragImage is already visible/hidden */
923 if ((InternalDrag
.bShow
&& bShow
) || (!InternalDrag
.bShow
&& !bShow
)) {
927 /* position of the origin of the DragImage */
928 x
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
929 y
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
931 hdcDrag
= GetDCEx (InternalDrag
.hwnd
, 0,
932 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
937 hdcBg
= CreateCompatibleDC(hdcDrag
);
938 if (!InternalDrag
.hbmBg
) {
939 InternalDrag
.hbmBg
= CreateCompatibleBitmap(hdcDrag
,
940 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
);
942 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
945 /* save the background */
946 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
947 hdcDrag
, x
, y
, SRCCOPY
);
949 ImageList_InternalDragDraw(hdcDrag
, x
, y
);
952 BitBlt(hdcDrag
, x
, y
, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
953 hdcBg
, 0, 0, SRCCOPY
);
956 InternalDrag
.bShow
= !InternalDrag
.bShow
;
959 ReleaseDC (InternalDrag
.hwnd
, hdcDrag
);
964 /*************************************************************************
965 * ImageList_Draw [COMCTL32.@]
970 * himl [I] handle to image list
972 * hdc [I] handle to device context
975 * fStyle [I] drawing flags
986 ImageList_Draw (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
, UINT fStyle
)
988 return ImageList_DrawEx (himl
, i
, hdc
, x
, y
, 0, 0,
989 CLR_DEFAULT
, CLR_DEFAULT
, fStyle
);
993 /*************************************************************************
994 * ImageList_DrawEx [COMCTL32.@]
996 * Draws an image and allows to use extended drawing features.
999 * himl [I] handle to image list
1001 * hdc [I] handle to device context
1006 * rgbBk [I] background color
1007 * rgbFg [I] foreground color
1008 * fStyle [I] drawing flags
1015 * Calls ImageList_DrawIndirect.
1018 * ImageList_DrawIndirect.
1022 ImageList_DrawEx (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
,
1023 INT dx
, INT dy
, COLORREF rgbBk
, COLORREF rgbFg
,
1026 IMAGELISTDRAWPARAMS imldp
;
1028 ZeroMemory (&imldp
, sizeof(imldp
));
1029 imldp
.cbSize
= sizeof(imldp
);
1037 imldp
.rgbBk
= rgbBk
;
1038 imldp
.rgbFg
= rgbFg
;
1039 imldp
.fStyle
= fStyle
;
1041 return ImageList_DrawIndirect (&imldp
);
1045 /*************************************************************************
1046 * ImageList_DrawIndirect [COMCTL32.@]
1048 * Draws an image using various parameters specified in pimldp.
1051 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1059 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS
*pimldp
)
1061 INT cx
, cy
, lx
, ly
, nOvlIdx
;
1062 DWORD fState
, dwRop
;
1064 COLORREF clrBk
, oldImageBk
, oldImageFg
;
1065 HDC hImageDC
, hImageListDC
, hMaskListDC
;
1066 HBITMAP hImageBmp
, hOldImageBmp
, hBlendMaskBmp
;
1067 BOOL bIsTransparent
, bBlend
, bResult
= FALSE
;
1070 if (!pimldp
|| !(himl
= pimldp
->himl
)) return FALSE
;
1071 if (!is_valid(himl
)) return FALSE
;
1072 if ((pimldp
->i
< 0) || (pimldp
->i
>= himl
->cCurImage
)) return FALSE
;
1074 lx
= himl
->cx
* pimldp
->i
+ pimldp
->xBitmap
;
1075 ly
= pimldp
->yBitmap
;
1077 fState
= pimldp
->cbSize
< sizeof(IMAGELISTDRAWPARAMS
) ? ILS_NORMAL
: pimldp
->fState
;
1078 fStyle
= pimldp
->fStyle
& ~ILD_OVERLAYMASK
;
1079 cx
= (pimldp
->cx
== 0) ? himl
->cx
: pimldp
->cx
;
1080 cy
= (pimldp
->cy
== 0) ? himl
->cy
: pimldp
->cy
;
1081 clrBk
= (pimldp
->rgbBk
== CLR_DEFAULT
) ? himl
->clrBk
: pimldp
->rgbBk
;
1082 bIsTransparent
= (fStyle
& ILD_TRANSPARENT
) || clrBk
== CLR_NONE
;
1083 bBlend
= fStyle
& (ILD_BLEND25
| ILD_BLEND50
);
1085 TRACE("himl(0x%lx) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1086 (DWORD
)himl
, himl
->hbmMask
, pimldp
->i
, pimldp
->x
, pimldp
->y
, cx
, cy
);
1088 /* we will use these DCs to access the images and masks in the ImageList */
1089 hImageListDC
= himl
->hdcImage
;
1090 hMaskListDC
= himl
->hdcMask
;
1092 /* these will accumulate the image and mask for the image we're drawing */
1093 hImageDC
= CreateCompatibleDC( pimldp
->hdcDst
);
1094 hImageBmp
= CreateCompatibleBitmap( pimldp
->hdcDst
, cx
, cy
);
1095 hBlendMaskBmp
= bBlend
? CreateBitmap(cx
, cy
, 1, 1, NULL
) : 0;
1097 /* Create a compatible DC. */
1098 if (!hImageListDC
|| !hImageDC
|| !hImageBmp
||
1099 (bBlend
&& !hBlendMaskBmp
) || (himl
->hbmMask
&& !hMaskListDC
))
1102 hOldImageBmp
= SelectObject(hImageDC
, hImageBmp
);
1105 * To obtain a transparent look, background color should be set
1106 * to white and foreground color to black when blting the
1109 oldImageFg
= SetTextColor( hImageDC
, RGB( 0, 0, 0 ) );
1110 oldImageBk
= SetBkColor( hImageDC
, RGB( 0xff, 0xff, 0xff ) );
1113 * Draw the initial image
1115 if(fStyle
& ILD_MASK
) {
1116 if (himl
->hbmMask
) {
1117 BitBlt(hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, lx
, ly
, SRCCOPY
);
1119 HBRUSH hOldBrush
= SelectObject (hImageDC
, GetStockObject(BLACK_BRUSH
));
1120 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1121 SelectObject(hImageDC
, hOldBrush
);
1123 } else if (himl
->hbmMask
&& !bIsTransparent
) {
1124 /* blend the image with the needed solid background */
1125 HBRUSH hOldBrush
= SelectObject (hImageDC
, CreateSolidBrush (clrBk
));
1126 PatBlt( hImageDC
, 0, 0, cx
, cy
, PATCOPY
);
1127 BitBlt( hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, lx
, ly
, SRCAND
);
1128 BitBlt( hImageDC
, 0, 0, cx
, cy
, hImageListDC
, lx
, ly
, SRCPAINT
);
1129 DeleteObject (SelectObject (hImageDC
, hOldBrush
));
1131 /* start off with the image, if we have a mask, we'll use it later */
1132 BitBlt( hImageDC
, 0, 0, cx
, cy
, hImageListDC
, lx
, ly
, SRCCOPY
);
1135 /* Time for blending, if required */
1137 HBRUSH hBlendBrush
, hOldBrush
;
1138 COLORREF clrBlend
= pimldp
->rgbFg
;
1139 HDC hBlendMaskDC
= hImageListDC
;
1142 /* Create the blend Mask */
1143 hOldBitmap
= SelectObject(hBlendMaskDC
, hBlendMaskBmp
);
1144 hBlendBrush
= fStyle
& ILD_BLEND50
? himl
->hbrBlend50
: himl
->hbrBlend25
;
1145 hOldBrush
= (HBRUSH
) SelectObject(hBlendMaskDC
, hBlendBrush
);
1146 PatBlt(hBlendMaskDC
, 0, 0, cx
, cy
, PATCOPY
);
1147 SelectObject(hBlendMaskDC
, hOldBrush
);
1149 /* Modify the blend mask if an Image Mask exist */
1151 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hMaskListDC
, lx
, ly
, 0x220326); /* NOTSRCAND */
1152 BitBlt(hBlendMaskDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, NOTSRCCOPY
);
1155 /* now apply blend to the current image given the BlendMask */
1156 if (clrBlend
== CLR_DEFAULT
) clrBlend
= GetSysColor (COLOR_HIGHLIGHT
);
1157 else if (clrBlend
== CLR_NONE
) clrBlend
= GetTextColor (pimldp
->hdcDst
);
1158 hOldBrush
= (HBRUSH
) SelectObject (hImageDC
, CreateSolidBrush(clrBlend
));
1159 BitBlt (hImageDC
, 0, 0, cx
, cy
, hBlendMaskDC
, 0, 0, 0xB8074A); /* PSDPxax */
1160 DeleteObject(SelectObject(hImageDC
, hOldBrush
));
1161 SelectObject(hBlendMaskDC
, hOldBitmap
);
1164 /* Now do the overlay image, if any */
1165 nOvlIdx
= (pimldp
->fStyle
& ILD_OVERLAYMASK
) >> 8;
1166 if ( (nOvlIdx
>= 1) && (nOvlIdx
<= MAX_OVERLAYIMAGE
)) {
1167 nOvlIdx
= himl
->nOvlIdx
[nOvlIdx
- 1];
1168 if ((nOvlIdx
>= 0) && (nOvlIdx
< himl
->cCurImage
)) {
1169 const INT ox
= himl
->cx
* nOvlIdx
+ pimldp
->xBitmap
;
1170 if (himl
->hbmMask
&& !(fStyle
& ILD_IMAGE
))
1171 BitBlt (hImageDC
, 0, 0, cx
, cy
, hMaskListDC
, ox
, ly
, SRCAND
);
1172 BitBlt (hImageDC
, 0, 0, cx
, cy
, hImageListDC
, ox
, ly
, SRCPAINT
);
1176 if (fState
& ILS_SATURATE
) FIXME("ILS_SATURATE: unimplemented!\n");
1177 if (fState
& ILS_GLOW
) FIXME("ILS_GLOW: unimplemented!\n");
1178 if (fState
& ILS_SHADOW
) FIXME("ILS_SHADOW: unimplemented!\n");
1179 if (fState
& ILS_ALPHA
) FIXME("ILS_ALPHA: unimplemented!\n");
1181 if (fStyle
& ILD_PRESERVEALPHA
) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1182 if (fStyle
& ILD_SCALE
) FIXME("ILD_SCALE: unimplemented!\n");
1183 if (fStyle
& ILD_DPISCALE
) FIXME("ILD_DPISCALE: unimplemented!\n");
1185 /* now copy the image to the screen */
1187 if (himl
->hbmMask
&& bIsTransparent
&& !(fStyle
& ILD_MASK
)) {
1188 COLORREF oldDstFg
= SetTextColor(pimldp
->hdcDst
, RGB( 0, 0, 0 ) );
1189 COLORREF oldDstBk
= SetBkColor(pimldp
->hdcDst
, RGB( 0xff, 0xff, 0xff ));
1190 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hMaskListDC
, lx
, ly
, SRCAND
);
1191 SetBkColor(pimldp
->hdcDst
, oldDstBk
);
1192 SetTextColor(pimldp
->hdcDst
, oldDstFg
);
1195 if (fStyle
& ILD_ROP
) dwRop
= pimldp
->dwRop
;
1196 BitBlt (pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
, hImageDC
, 0, 0, dwRop
);
1200 /* cleanup the mess */
1201 SetBkColor(hImageDC
, oldImageBk
);
1202 SetTextColor(hImageDC
, oldImageFg
);
1203 SelectObject(hImageDC
, hOldImageBmp
);
1205 DeleteObject(hBlendMaskBmp
);
1206 DeleteObject(hImageBmp
);
1213 /*************************************************************************
1214 * ImageList_Duplicate [COMCTL32.@]
1216 * Duplicates an image list.
1219 * himlSrc [I] source image list handle
1222 * Success: Handle of duplicated image list.
1227 ImageList_Duplicate (HIMAGELIST himlSrc
)
1231 if (!is_valid(himlSrc
)) {
1232 ERR("Invalid image list handle!\n");
1236 himlDst
= ImageList_Create (himlSrc
->cx
, himlSrc
->cy
, himlSrc
->flags
,
1237 himlSrc
->cInitial
, himlSrc
->cGrow
);
1241 BitBlt (himlDst
->hdcImage
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
, himlSrc
->cy
,
1242 himlSrc
->hdcImage
, 0, 0, SRCCOPY
);
1244 if (himlDst
->hbmMask
)
1245 BitBlt (himlDst
->hdcMask
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
, himlSrc
->cy
,
1246 himlSrc
->hdcMask
, 0, 0, SRCCOPY
);
1248 himlDst
->cCurImage
= himlSrc
->cCurImage
;
1249 himlDst
->cMaxImage
= himlSrc
->cMaxImage
;
1255 /*************************************************************************
1256 * ImageList_EndDrag [COMCTL32.@]
1258 * Finishes a drag operation.
1269 ImageList_EndDrag (void)
1271 /* cleanup the InternalDrag struct */
1272 InternalDrag
.hwnd
= 0;
1273 ImageList_Destroy (InternalDrag
.himl
);
1274 InternalDrag
.himl
= 0;
1277 InternalDrag
.dxHotspot
= 0;
1278 InternalDrag
.dyHotspot
= 0;
1279 InternalDrag
.bShow
= FALSE
;
1280 DeleteObject(InternalDrag
.hbmBg
);
1281 InternalDrag
.hbmBg
= 0;
1282 InternalDrag
.bHSPending
= FALSE
;
1286 /*************************************************************************
1287 * ImageList_GetBkColor [COMCTL32.@]
1289 * Returns the background color of an image list.
1292 * himl [I] Image list handle.
1295 * Success: background color
1300 ImageList_GetBkColor (HIMAGELIST himl
)
1302 return himl
? himl
->clrBk
: CLR_NONE
;
1306 /*************************************************************************
1307 * ImageList_GetDragImage [COMCTL32.@]
1309 * Returns the handle to the internal drag image list.
1312 * ppt [O] Pointer to the drag position. Can be NULL.
1313 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1316 * Success: Handle of the drag image list.
1321 ImageList_GetDragImage (POINT
*ppt
, POINT
*pptHotspot
)
1323 if (is_valid(InternalDrag
.himl
)) {
1325 ppt
->x
= InternalDrag
.x
;
1326 ppt
->y
= InternalDrag
.y
;
1329 pptHotspot
->x
= InternalDrag
.dxHotspot
;
1330 pptHotspot
->y
= InternalDrag
.dyHotspot
;
1332 return (InternalDrag
.himl
);
1339 /*************************************************************************
1340 * ImageList_GetFlags [COMCTL32.@]
1342 * Gets the flags of the specified image list.
1345 * himl [I] Handle to image list
1355 ImageList_GetFlags(HIMAGELIST himl
)
1357 FIXME("(%p):empty stub\n", himl
);
1362 /*************************************************************************
1363 * ImageList_GetIcon [COMCTL32.@]
1365 * Creates an icon from a masked image of an image list.
1368 * himl [I] handle to image list
1370 * flags [I] drawing style flags
1373 * Success: icon handle
1378 ImageList_GetIcon (HIMAGELIST himl
, INT i
, UINT fStyle
)
1382 HBITMAP hOldDstBitmap
;
1385 TRACE("%p %d %d\n", himl
, i
, fStyle
);
1386 if (!is_valid(himl
) || (i
< 0) || (i
>= himl
->cCurImage
)) return NULL
;
1388 hdcDst
= CreateCompatibleDC(0);
1395 ii
.hbmMask
= CreateCompatibleBitmap (hdcDst
, himl
->cx
, himl
->cy
);
1396 hOldDstBitmap
= SelectObject (hdcDst
, ii
.hbmMask
);
1397 PatBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
, WHITENESS
);
1398 ImageList_Draw(himl
, i
, hdcDst
, 0, 0, fStyle
| ILD_MASK
);
1401 ii
.hbmColor
= CreateCompatibleBitmap (himl
->hdcImage
, himl
->cx
, himl
->cy
);
1402 SelectObject (hdcDst
, ii
.hbmColor
);
1403 PatBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
, BLACKNESS
);
1404 ImageList_Draw(himl
, i
, hdcDst
, 0, 0, fStyle
| ILD_TRANSPARENT
);
1407 * CreateIconIndirect requires us to deselect the bitmaps from
1408 * the DCs before calling
1410 SelectObject(hdcDst
, hOldDstBitmap
);
1412 hIcon
= CreateIconIndirect (&ii
);
1414 DeleteObject (ii
.hbmMask
);
1415 DeleteObject (ii
.hbmColor
);
1422 /*************************************************************************
1423 * ImageList_GetIconSize [COMCTL32.@]
1425 * Retrieves the size of an image in an image list.
1428 * himl [I] handle to image list
1429 * cx [O] pointer to the image width.
1430 * cy [O] pointer to the image height.
1437 * All images in an image list have the same size.
1441 ImageList_GetIconSize (HIMAGELIST himl
, INT
*cx
, INT
*cy
)
1443 if (!is_valid(himl
))
1445 if ((himl
->cx
<= 0) || (himl
->cy
<= 0))
1457 /*************************************************************************
1458 * ImageList_GetImageCount [COMCTL32.@]
1460 * Returns the number of images in an image list.
1463 * himl [I] handle to image list
1466 * Success: Number of images.
1471 ImageList_GetImageCount (HIMAGELIST himl
)
1473 if (!is_valid(himl
))
1476 return himl
->cCurImage
;
1480 /*************************************************************************
1481 * ImageList_GetImageInfo [COMCTL32.@]
1483 * Returns information about an image in an image list.
1486 * himl [I] handle to image list
1488 * pImageInfo [O] pointer to the image information
1496 ImageList_GetImageInfo (HIMAGELIST himl
, INT i
, IMAGEINFO
*pImageInfo
)
1498 if (!is_valid(himl
) || (pImageInfo
== NULL
))
1500 if ((i
< 0) || (i
>= himl
->cCurImage
))
1503 pImageInfo
->hbmImage
= himl
->hbmImage
;
1504 pImageInfo
->hbmMask
= himl
->hbmMask
;
1506 pImageInfo
->rcImage
.top
= 0;
1507 pImageInfo
->rcImage
.bottom
= himl
->cy
;
1508 pImageInfo
->rcImage
.left
= i
* himl
->cx
;
1509 pImageInfo
->rcImage
.right
= (i
+1) * himl
->cx
;
1515 /*************************************************************************
1516 * ImageList_GetImageRect [COMCTL32.@]
1518 * Retrieves the rectangle of the specified image in an image list.
1521 * himl [I] handle to image list
1523 * lpRect [O] pointer to the image rectangle
1530 * This is an UNDOCUMENTED function!!!
1534 ImageList_GetImageRect (HIMAGELIST himl
, INT i
, LPRECT lpRect
)
1536 if (!is_valid(himl
) || (lpRect
== NULL
))
1538 if ((i
< 0) || (i
>= himl
->cCurImage
))
1541 lpRect
->left
= i
* himl
->cx
;
1543 lpRect
->right
= lpRect
->left
+ himl
->cx
;
1544 lpRect
->bottom
= himl
->cy
;
1550 /*************************************************************************
1551 * ImageList_LoadImage [COMCTL32.@]
1552 * ImageList_LoadImageA [COMCTL32.@]
1554 * Creates an image list from a bitmap, icon or cursor.
1557 * hi [I] instance handle
1558 * lpbmp [I] name or id of the image
1559 * cx [I] width of each image
1560 * cGrow [I] number of images to expand
1561 * clrMask [I] mask color
1562 * uType [I] type of image to load
1563 * uFlags [I] loading flags
1566 * Success: handle to the loaded image list
1574 ImageList_LoadImageA (HINSTANCE hi
, LPCSTR lpbmp
, INT cx
, INT cGrow
,
1575 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1577 HIMAGELIST himl
= NULL
;
1581 handle
= LoadImageA (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1583 ERR("Error loading image!\n");
1587 if (uType
== IMAGE_BITMAP
) {
1589 GetObjectA (handle
, sizeof(BITMAP
), &bmp
);
1591 /* To match windows behavior, if cx is set to zero and
1592 the flag DI_DEFAULTSIZE is specified, cx becomes the
1593 system metric value for icons. If the flag is not specified
1594 the function sets the size to the height of the bitmap */
1597 if (uFlags
& DI_DEFAULTSIZE
)
1598 cx
= GetSystemMetrics (SM_CXICON
);
1603 nImageCount
= bmp
.bmWidth
/ cx
;
1605 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1606 nImageCount
, cGrow
);
1608 DeleteObject (handle
);
1611 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1613 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1617 GetIconInfo (handle
, &ii
);
1618 GetObjectA (ii
.hbmColor
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1619 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1620 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1622 DeleteObject (ii
.hbmColor
);
1623 DeleteObject (ii
.hbmMask
);
1624 DeleteObject (handle
);
1627 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1628 DeleteObject (ii
.hbmColor
);
1629 DeleteObject (ii
.hbmMask
);
1632 DeleteObject (handle
);
1638 /*************************************************************************
1639 * ImageList_LoadImageW [COMCTL32.@]
1641 * Creates an image list from a bitmap, icon or cursor.
1644 * hi [I] instance handle
1645 * lpbmp [I] name or id of the image
1646 * cx [I] width of each image
1647 * cGrow [I] number of images to expand
1648 * clrMask [I] mask color
1649 * uType [I] type of image to load
1650 * uFlags [I] loading flags
1653 * Success: handle to the loaded image list
1661 ImageList_LoadImageW (HINSTANCE hi
, LPCWSTR lpbmp
, INT cx
, INT cGrow
,
1662 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1664 HIMAGELIST himl
= NULL
;
1668 handle
= LoadImageW (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1670 ERR("Error loading image!\n");
1674 if (uType
== IMAGE_BITMAP
) {
1676 GetObjectW (handle
, sizeof(BITMAP
), &bmp
);
1678 /* To match windows behavior, if cx is set to zero and
1679 the flag DI_DEFAULTSIZE is specified, cx becomes the
1680 system metric value for icons. If the flag is not specified
1681 the function sets the size to the height of the bitmap */
1684 if (uFlags
& DI_DEFAULTSIZE
)
1685 cx
= GetSystemMetrics (SM_CXICON
);
1690 nImageCount
= bmp
.bmWidth
/ cx
;
1692 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1693 nImageCount
, cGrow
);
1695 DeleteObject (handle
);
1698 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1700 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1704 GetIconInfo (handle
, &ii
);
1705 GetObjectW (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1706 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1707 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1709 DeleteObject (ii
.hbmColor
);
1710 DeleteObject (ii
.hbmMask
);
1711 DeleteObject (handle
);
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
;
1750 INT xOff1
, yOff1
, xOff2
, yOff2
;
1753 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1
, i1
, himl2
,
1756 if (!is_valid(himl1
) || !is_valid(himl2
))
1760 if ((i1
< 0) || (i1
>= himl1
->cCurImage
)) {
1761 ERR("Index 1 out of range! %d\n", i1
);
1765 if ((i2
< 0) || (i2
>= himl2
->cCurImage
)) {
1766 ERR("Index 2 out of range! %d\n", i2
);
1771 cxDst
= max (himl1
->cx
, dx
+ himl2
->cx
);
1776 cxDst
= max (himl2
->cx
, himl1
->cx
- dx
);
1781 cxDst
= max (himl1
->cx
, himl2
->cx
);
1787 cyDst
= max (himl1
->cy
, dy
+ himl2
->cy
);
1792 cyDst
= max (himl2
->cy
, himl1
->cy
- dy
);
1797 cyDst
= max (himl1
->cy
, himl2
->cy
);
1802 himlDst
= ImageList_Create (cxDst
, cyDst
, ILC_MASK
| ILC_COLOR
, 1, 1);
1807 nX1
= i1
* himl1
->cx
;
1808 nX2
= i2
* himl2
->cx
;
1811 BitBlt (himlDst
->hdcImage
, 0, 0, cxDst
, cyDst
, himl1
->hdcImage
, 0, 0, BLACKNESS
);
1812 BitBlt (himlDst
->hdcImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
, himl1
->hdcImage
, nX1
, 0, SRCCOPY
);
1813 BitBlt (himlDst
->hdcImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcMask
, nX2
, 0, SRCAND
);
1814 BitBlt (himlDst
->hdcImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcImage
, nX2
, 0, SRCPAINT
);
1817 BitBlt (himlDst
->hdcMask
, 0, 0, cxDst
, cyDst
, himl1
->hdcMask
, 0, 0, WHITENESS
);
1818 BitBlt (himlDst
->hdcMask
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
, himl1
->hdcMask
, nX1
, 0, SRCCOPY
);
1819 BitBlt (himlDst
->hdcMask
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
, himl2
->hdcMask
, nX2
, 0, SRCAND
);
1821 himlDst
->cCurImage
= 1;
1828 /* helper for _read_bitmap currently unused */
1830 static int may_use_dibsection(HDC hdc
) {
1831 int bitspixel
= GetDeviceCaps(hdc
,BITSPIXEL
)*GetDeviceCaps(hdc
,PLANES
);
1836 return GetDeviceCaps(hdc
,CAPS1
) & C1_DIBENGINE
;
1840 /* helper for ImageList_Read, see comments below */
1841 static HBITMAP
_read_bitmap(LPSTREAM pstm
,int ilcFlag
,int cx
,int cy
) {
1842 HDC xdc
= 0, hBitmapDC
=0;
1843 BITMAPFILEHEADER bmfh
;
1844 BITMAPINFOHEADER bmih
;
1845 int bitsperpixel
,palspace
,longsperline
,width
,height
;
1846 LPBITMAPINFOHEADER bmihc
= NULL
;
1848 HBITMAP hbitmap
= 0, hDIB
= 0;
1851 if (!SUCCEEDED(IStream_Read ( pstm
, &bmfh
, sizeof(bmfh
), NULL
)) ||
1852 (bmfh
.bfType
!= (('M'<<8)|'B')) ||
1853 !SUCCEEDED(IStream_Read ( pstm
, &bmih
, sizeof(bmih
), NULL
)) ||
1854 (bmih
.biSize
!= sizeof(bmih
))
1858 bitsperpixel
= bmih
.biPlanes
* bmih
.biBitCount
;
1859 if (bitsperpixel
<=8)
1860 palspace
= (1<<bitsperpixel
)*sizeof(RGBQUAD
);
1863 width
= bmih
.biWidth
;
1864 height
= bmih
.biHeight
;
1865 bmihc
= (LPBITMAPINFOHEADER
)LocalAlloc(LMEM_ZEROINIT
,sizeof(bmih
)+palspace
);
1866 memcpy(bmihc
,&bmih
,sizeof(bmih
));
1867 longsperline
= ((width
*bitsperpixel
+31)&~0x1f)>>5;
1868 bmihc
->biSizeImage
= (longsperline
*height
)<<2;
1870 /* read the palette right after the end of the bitmapinfoheader */
1872 if (!SUCCEEDED(IStream_Read ( pstm
, bmihc
+1, palspace
, NULL
)))
1876 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1877 if ((bitsperpixel
>1) &&
1878 ((ilcFlag
!=ILC_COLORDDB
) && (!ilcFlag
|| may_use_dibsection(xdc
)))
1880 hbitmap
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1883 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1889 int i
,nwidth
,nheight
,nRows
;
1891 nwidth
= width
*(height
/cy
);
1893 nRows
= (height
/cy
);
1895 if (bitsperpixel
==1)
1896 hbitmap
= CreateBitmap(nwidth
,nheight
,1,1,NULL
);
1898 hbitmap
= CreateCompatibleBitmap(xdc
,nwidth
,nheight
);
1900 hDIB
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
1903 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
1906 hBitmapDC
= CreateCompatibleDC(0);
1907 SelectObject(hBitmapDC
, hbitmap
);
1909 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1910 /* Do not forget that windows bitmaps are bottom->top */
1911 TRACE("nRows=%d\n", nRows
);
1912 for (i
=0; i
< nRows
; i
++){
1913 StretchDIBits(hBitmapDC
, width
*i
, 0, width
, cy
, 0, cy
*(nRows
-1-i
), width
, cy
, bits
,
1914 (BITMAPINFO
*)bmihc
, DIB_RGB_COLORS
, SRCCOPY
);
1920 if (xdc
) ReleaseDC(0,xdc
);
1921 if (bmihc
) LocalFree((HLOCAL
)bmihc
);
1922 if (hDIB
) DeleteObject(hDIB
);
1923 if (hBitmapDC
) DeleteDC(hBitmapDC
);
1926 DeleteObject(hbitmap
);
1933 /*************************************************************************
1934 * ImageList_Read [COMCTL32.@]
1936 * Reads an image list from a stream.
1939 * pstm [I] pointer to a stream
1942 * Success: handle to image list
1945 * The format is like this:
1946 * ILHEAD ilheadstruct;
1948 * for the color image part:
1949 * BITMAPFILEHEADER bmfh;
1950 * BITMAPINFOHEADER bmih;
1951 * only if it has a palette:
1952 * RGBQUAD rgbs[nr_of_paletted_colors];
1954 * BYTE colorbits[imagesize];
1956 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1957 * BITMAPFILEHEADER bmfh_mask;
1958 * BITMAPINFOHEADER bmih_mask;
1959 * only if it has a palette (it usually does not):
1960 * RGBQUAD rgbs[nr_of_paletted_colors];
1962 * BYTE maskbits[imagesize];
1964 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1965 * _read_bitmap needs to convert them.
1967 HIMAGELIST WINAPI
ImageList_Read (LPSTREAM pstm
)
1971 HBITMAP hbmColor
=0,hbmMask
=0;
1974 if (!SUCCEEDED(IStream_Read (pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
1976 if (ilHead
.usMagic
!= (('L' << 8) | 'I'))
1978 if (ilHead
.usVersion
!= 0x101) /* probably version? */
1982 FIXME(" ilHead.cCurImage = %d\n",ilHead
.cCurImage
);
1983 FIXME(" ilHead.cMaxImage = %d\n",ilHead
.cMaxImage
);
1984 FIXME(" ilHead.cGrow = %d\n",ilHead
.cGrow
);
1985 FIXME(" ilHead.cx = %d\n",ilHead
.cx
);
1986 FIXME(" ilHead.cy = %d\n",ilHead
.cy
);
1987 FIXME(" ilHead.flags = %x\n",ilHead
.flags
);
1988 FIXME(" ilHead.ovls[0] = %d\n",ilHead
.ovls
[0]);
1989 FIXME(" ilHead.ovls[1] = %d\n",ilHead
.ovls
[1]);
1990 FIXME(" ilHead.ovls[2] = %d\n",ilHead
.ovls
[2]);
1991 FIXME(" ilHead.ovls[3] = %d\n",ilHead
.ovls
[3]);
1994 hbmColor
= _read_bitmap(pstm
,ilHead
.flags
& ~ILC_MASK
,ilHead
.cx
,ilHead
.cy
);
1997 if (ilHead
.flags
& ILC_MASK
) {
1998 hbmMask
= _read_bitmap(pstm
,0,ilHead
.cx
,ilHead
.cy
);
2000 DeleteObject(hbmColor
);
2005 himl
= ImageList_Create (
2013 DeleteObject(hbmColor
);
2014 DeleteObject(hbmMask
);
2017 SelectObject(himl
->hdcImage
, hbmColor
);
2018 DeleteObject(himl
->hbmImage
);
2019 himl
->hbmImage
= hbmColor
;
2021 SelectObject(himl
->hdcMask
, hbmMask
);
2022 DeleteObject(himl
->hbmMask
);
2023 himl
->hbmMask
= hbmMask
;
2025 himl
->cCurImage
= ilHead
.cCurImage
;
2026 himl
->cMaxImage
= ilHead
.cMaxImage
;
2028 ImageList_SetBkColor(himl
,ilHead
.bkcolor
);
2030 ImageList_SetOverlayImage(himl
,ilHead
.ovls
[i
],i
+1);
2035 /*************************************************************************
2036 * ImageList_Remove [COMCTL32.@]
2038 * Removes an image from an image list
2041 * himl [I] image list handle
2050 ImageList_Remove (HIMAGELIST himl
, INT i
)
2052 HBITMAP hbmNewImage
, hbmNewMask
;
2056 TRACE("(himl=%p i=%d)\n", himl
, i
);
2058 if (!is_valid(himl
)) {
2059 ERR("Invalid image list handle!\n");
2063 if ((i
< -1) || (i
>= himl
->cCurImage
)) {
2064 ERR("index out of range! %d\n", i
);
2070 if (himl
->cCurImage
== 0) {
2071 /* remove all on empty ImageList is allowed */
2072 TRACE("remove all on empty ImageList!\n");
2076 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2077 himl
->cCurImage
= 0;
2078 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2079 himl
->nOvlIdx
[nCount
] = -1;
2081 hbmNewImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
* himl
->cx
, himl
->cy
);
2082 SelectObject (himl
->hdcImage
, hbmNewImage
);
2083 DeleteObject (himl
->hbmImage
);
2084 himl
->hbmImage
= hbmNewImage
;
2086 if (himl
->hbmMask
) {
2087 hbmNewMask
= CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2089 SelectObject (himl
->hdcMask
, hbmNewMask
);
2090 DeleteObject (himl
->hbmMask
);
2091 himl
->hbmMask
= hbmNewMask
;
2095 /* delete one image */
2096 TRACE("Remove single image! %d\n", i
);
2098 /* create new bitmap(s) */
2099 nCount
= (himl
->cCurImage
+ himl
->cGrow
- 1);
2100 cxNew
= nCount
* himl
->cx
;
2102 TRACE(" - Number of images: %d / %d (Old/New)\n",
2103 himl
->cCurImage
, himl
->cCurImage
- 1);
2104 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2105 himl
->cMaxImage
, himl
->cCurImage
+ himl
->cGrow
- 1);
2107 hbmNewImage
= ImageList_CreateImage(himl
->hdcImage
, himl
, cxNew
, himl
->cy
);
2110 hbmNewMask
= CreateBitmap (cxNew
, himl
->cy
, 1, 1, NULL
);
2112 hbmNewMask
= 0; /* Just to keep compiler happy! */
2114 hdcBmp
= CreateCompatibleDC (0);
2116 /* copy all images and masks prior to the "removed" image */
2118 TRACE("Pre image copy: Copy %d images\n", i
);
2120 SelectObject (hdcBmp
, hbmNewImage
);
2121 BitBlt (hdcBmp
, 0, 0, i
* himl
->cx
, himl
->cy
,
2122 himl
->hdcImage
, 0, 0, SRCCOPY
);
2124 if (himl
->hbmMask
) {
2125 SelectObject (hdcBmp
, hbmNewMask
);
2126 BitBlt (hdcBmp
, 0, 0, i
* himl
->cx
, himl
->cy
,
2127 himl
->hdcMask
, 0, 0, SRCCOPY
);
2131 /* copy all images and masks behind the removed image */
2132 if (i
< himl
->cCurImage
- 1) {
2133 TRACE("Post image copy!\n");
2134 SelectObject (hdcBmp
, hbmNewImage
);
2135 BitBlt (hdcBmp
, i
* himl
->cx
, 0, (himl
->cCurImage
- i
- 1) * himl
->cx
,
2136 himl
->cy
, himl
->hdcImage
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2138 if (himl
->hbmMask
) {
2139 SelectObject (hdcBmp
, hbmNewMask
);
2140 BitBlt (hdcBmp
, i
* himl
->cx
, 0,
2141 (himl
->cCurImage
- i
- 1) * himl
->cx
,
2142 himl
->cy
, himl
->hdcMask
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2148 /* delete old images and insert new ones */
2149 SelectObject (himl
->hdcImage
, hbmNewImage
);
2150 DeleteObject (himl
->hbmImage
);
2151 himl
->hbmImage
= hbmNewImage
;
2152 if (himl
->hbmMask
) {
2153 SelectObject (himl
->hdcMask
, hbmNewMask
);
2154 DeleteObject (himl
->hbmMask
);
2155 himl
->hbmMask
= hbmNewMask
;
2159 himl
->cMaxImage
= himl
->cCurImage
+ himl
->cGrow
;
2166 /*************************************************************************
2167 * ImageList_Replace [COMCTL32.@]
2169 * Replaces an image in an image list with a new image.
2172 * himl [I] handle to image list
2174 * hbmImage [I] handle to image bitmap
2175 * hbmMask [I] handle to mask bitmap. Can be NULL.
2183 ImageList_Replace (HIMAGELIST himl
, INT i
, HBITMAP hbmImage
,
2189 TRACE("%p %d %p %p\n", himl
, i
, hbmImage
, hbmMask
);
2191 if (!is_valid(himl
)) {
2192 ERR("Invalid image list handle!\n");
2196 if ((i
>= himl
->cMaxImage
) || (i
< 0)) {
2197 ERR("Invalid image index!\n");
2201 hdcImage
= CreateCompatibleDC (0);
2202 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2205 SelectObject (hdcImage
, hbmImage
);
2207 StretchBlt (himl
->hdcImage
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2208 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2213 SelectObject (hdcImage
, hbmMask
);
2215 StretchBlt (himl
->hdcMask
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2216 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2219 /* Remove the background from the image
2221 StretchBlt (himl
->hdcImage
,
2222 i
*himl
->cx
, 0, himl
->cx
, himl
->cy
,
2224 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
2225 0x220326); /* NOTSRCAND */
2228 DeleteDC (hdcImage
);
2234 /*************************************************************************
2235 * ImageList_ReplaceIcon [COMCTL32.@]
2237 * Replaces an image in an image list using an icon.
2240 * himl [I] handle to image list
2242 * hIcon [I] handle to icon
2245 * Success: index of the replaced image
2250 ImageList_ReplaceIcon (HIMAGELIST himl
, INT i
, HICON hIcon
)
2259 TRACE("(0x%lx 0x%x %p)\n", (DWORD
)himl
, i
, hIcon
);
2261 if (!is_valid(himl
))
2263 if ((i
>= himl
->cMaxImage
) || (i
< -1))
2266 hBestFitIcon
= CopyImage(
2269 LR_COPYFROMRESOURCE
);
2271 GetIconInfo (hBestFitIcon
, &ii
);
2272 if (ii
.hbmMask
== 0)
2274 if (ii
.hbmColor
== 0)
2276 GetObjectA (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2279 if (himl
->cCurImage
+ 1 > himl
->cMaxImage
)
2280 IMAGELIST_InternalExpandBitmaps (himl
, 1, 0, 0);
2282 nIndex
= himl
->cCurImage
;
2288 hdcImage
= CreateCompatibleDC (0);
2289 TRACE("hdcImage=%p\n", hdcImage
);
2291 ERR("invalid hdcImage!\n");
2293 SetTextColor(himl
->hdcImage
, RGB(0,0,0));
2294 SetBkColor (himl
->hdcImage
, RGB(255,255,255));
2295 hbmOldSrc
= SelectObject (hdcImage
, ii
.hbmColor
);
2297 StretchBlt (himl
->hdcImage
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2298 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2300 if (himl
->hbmMask
) {
2301 SelectObject (hdcImage
, ii
.hbmMask
);
2302 StretchBlt (himl
->hdcMask
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2303 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2306 SelectObject (hdcImage
, hbmOldSrc
);
2309 DestroyIcon(hBestFitIcon
);
2311 DeleteDC (hdcImage
);
2313 DeleteObject (ii
.hbmColor
);
2315 DeleteObject (ii
.hbmMask
);
2321 /*************************************************************************
2322 * ImageList_SetBkColor [COMCTL32.@]
2324 * Sets the background color of an image list.
2327 * himl [I] handle to image list
2328 * clrBk [I] background color
2331 * Success: previous background color
2336 ImageList_SetBkColor (HIMAGELIST himl
, COLORREF clrBk
)
2340 if (!is_valid(himl
))
2343 clrOldBk
= himl
->clrBk
;
2344 himl
->clrBk
= clrBk
;
2349 /*************************************************************************
2350 * ImageList_SetDragCursorImage [COMCTL32.@]
2352 * Combines the specified image with the current drag image
2355 * himlDrag [I] handle to drag image list
2356 * iDrag [I] drag image index
2357 * dxHotspot [I] X position of the hot spot
2358 * dyHotspot [I] Y position of the hot spot
2365 * When this function is called and the drag image is visible, a
2366 * short flickering occurs but this matches the Win9x behavior. It is
2367 * possible to fix the flickering using code like in ImageList_DragMove.
2371 ImageList_SetDragCursorImage (HIMAGELIST himlDrag
, INT iDrag
,
2372 INT dxHotspot
, INT dyHotspot
)
2374 HIMAGELIST himlTemp
;
2378 if (!is_valid(InternalDrag
.himl
) || !is_valid(himlDrag
))
2381 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2382 dxHotspot
, dyHotspot
, InternalDrag
.dxHotspot
, InternalDrag
.dyHotspot
);
2384 visible
= InternalDrag
.bShow
;
2386 /* Calculate the offset between the origin of the old image and the
2387 * origin of the second image.
2388 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2389 * hotspot) to the origin of the second image.
2390 * See M$DN for details */
2391 if(InternalDrag
.bHSPending
) {
2394 InternalDrag
.bHSPending
= FALSE
;
2396 dx
= InternalDrag
.dxHotspot
- dxHotspot
;
2397 dy
= InternalDrag
.dyHotspot
- dyHotspot
;
2399 himlTemp
= ImageList_Merge (InternalDrag
.himl
, 0, himlDrag
, iDrag
, dx
, dy
);
2402 /* hide the drag image */
2403 ImageList_DragShowNolock(FALSE
);
2405 if ((InternalDrag
.himl
->cx
!= himlTemp
->cx
) ||
2406 (InternalDrag
.himl
->cy
!= himlTemp
->cy
)) {
2407 /* the size of the drag image changed, invalidate the buffer */
2408 DeleteObject(InternalDrag
.hbmBg
);
2409 InternalDrag
.hbmBg
= 0;
2412 ImageList_Destroy (InternalDrag
.himl
);
2413 InternalDrag
.himl
= himlTemp
;
2415 /* update the InternalDragOffset, if the origin of the
2416 * DragImage was changed by ImageList_Merge. */
2418 InternalDrag
.dxHotspot
= dxHotspot
;
2420 InternalDrag
.dyHotspot
= dyHotspot
;
2423 /* show the drag image */
2424 ImageList_DragShowNolock(TRUE
);
2431 /*************************************************************************
2432 * ImageList_SetFilter [COMCTL32.@]
2434 * Sets a filter (or does something completely different)!!???
2435 * It removes 12 Bytes from the stack (3 Parameters).
2438 * himl [I] SHOULD be a handle to image list
2439 * i [I] COULD be an index?
2444 * Failure: FALSE ???
2447 * This is an UNDOCUMENTED function!!!!
2452 ImageList_SetFilter (HIMAGELIST himl
, INT i
, DWORD dwFilter
)
2454 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl
, i
, dwFilter
);
2460 /*************************************************************************
2461 * ImageList_SetFlags [COMCTL32.@]
2463 * Sets the image list flags.
2466 * himl [I] Handle to image list
2467 * flags [I] Flags to set
2477 ImageList_SetFlags(HIMAGELIST himl
, DWORD flags
)
2479 FIXME("(%p %08lx):empty stub\n", himl
, flags
);
2484 /*************************************************************************
2485 * ImageList_SetIconSize [COMCTL32.@]
2487 * Sets the image size of the bitmap and deletes all images.
2490 * himl [I] handle to image list
2491 * cx [I] image width
2492 * cy [I] image height
2500 ImageList_SetIconSize (HIMAGELIST himl
, INT cx
, INT cy
)
2505 if (!is_valid(himl
))
2508 /* remove all images */
2509 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2510 himl
->cCurImage
= 0;
2514 /* initialize overlay mask indices */
2515 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2516 himl
->nOvlIdx
[nCount
] = -1;
2518 hbmNew
= ImageList_CreateImage(himl
->hdcImage
, himl
, himl
->cMaxImage
* himl
->cx
, himl
->cy
);
2519 SelectObject (himl
->hdcImage
, hbmNew
);
2520 DeleteObject (himl
->hbmImage
);
2521 himl
->hbmImage
= hbmNew
;
2523 if (himl
->hbmMask
) {
2524 hbmNew
= CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2526 SelectObject (himl
->hdcMask
, hbmNew
);
2527 DeleteObject (himl
->hbmMask
);
2528 himl
->hbmMask
= hbmNew
;
2535 /*************************************************************************
2536 * ImageList_SetImageCount [COMCTL32.@]
2538 * Resizes an image list to the specified number of images.
2541 * himl [I] handle to image list
2542 * iImageCount [I] number of images in the image list
2550 ImageList_SetImageCount (HIMAGELIST himl
, UINT iImageCount
)
2553 HBITMAP hbmNewBitmap
;
2554 INT nNewCount
, nCopyCount
;
2556 TRACE("%p %d\n",himl
,iImageCount
);
2558 if (!is_valid(himl
))
2560 if (himl
->cCurImage
>= iImageCount
)
2562 if (himl
->cMaxImage
> iImageCount
)
2564 himl
->cCurImage
= iImageCount
;
2568 nNewCount
= iImageCount
+ himl
->cGrow
;
2569 nCopyCount
= min(himl
->cCurImage
, iImageCount
);
2571 hdcBitmap
= CreateCompatibleDC (0);
2573 hbmNewBitmap
= ImageList_CreateImage(hdcBitmap
, himl
, nNewCount
* himl
->cx
, himl
->cy
);
2575 if (hbmNewBitmap
!= 0)
2577 SelectObject (hdcBitmap
, hbmNewBitmap
);
2580 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2581 himl
->hdcImage
, 0, 0, SRCCOPY
);
2583 /* delete 'empty' image space */
2584 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2585 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2586 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2587 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2589 SelectObject (himl
->hdcImage
, hbmNewBitmap
);
2590 DeleteObject (himl
->hbmImage
);
2591 himl
->hbmImage
= hbmNewBitmap
;
2594 ERR("Could not create new image bitmap !\n");
2598 hbmNewBitmap
= CreateBitmap (nNewCount
* himl
->cx
, himl
->cy
,
2600 if (hbmNewBitmap
!= 0)
2602 SelectObject (hdcBitmap
, hbmNewBitmap
);
2605 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2606 himl
->hdcMask
, 0, 0, SRCCOPY
);
2608 /* delete 'empty' image space */
2609 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2610 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2611 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2612 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2614 SelectObject (himl
->hdcMask
, hbmNewBitmap
);
2615 DeleteObject (himl
->hbmMask
);
2616 himl
->hbmMask
= hbmNewBitmap
;
2619 ERR("Could not create new mask bitmap!\n");
2622 DeleteDC (hdcBitmap
);
2624 /* Update max image count and current image count */
2625 himl
->cMaxImage
= nNewCount
;
2626 himl
->cCurImage
= iImageCount
;
2632 /*************************************************************************
2633 * ImageList_SetOverlayImage [COMCTL32.@]
2635 * Assigns an overlay mask index to an existing image in an image list.
2638 * himl [I] handle to image list
2639 * iImage [I] image index
2640 * iOverlay [I] overlay mask index
2648 ImageList_SetOverlayImage (HIMAGELIST himl
, INT iImage
, INT iOverlay
)
2650 if (!is_valid(himl
))
2652 if ((iOverlay
< 1) || (iOverlay
> MAX_OVERLAYIMAGE
))
2654 if ((iImage
!=-1) && ((iImage
< 0) || (iImage
> himl
->cCurImage
)))
2656 himl
->nOvlIdx
[iOverlay
- 1] = iImage
;
2662 /* helper for ImageList_Write - write bitmap to pstm
2663 * currently everything is written as 24 bit RGB, except masks
2666 _write_bitmap(HBITMAP hBitmap
, LPSTREAM pstm
, int cx
, int cy
)
2668 LPBITMAPFILEHEADER bmfh
;
2669 LPBITMAPINFOHEADER bmih
;
2670 LPBYTE data
, lpBits
, lpBitsOrg
;
2672 INT bitCount
, sizeImage
, offBits
, totalSize
;
2673 INT nwidth
, nheight
, nsizeImage
, icount
;
2675 BOOL result
= FALSE
;
2679 GetObjectA(hBitmap
, sizeof(BITMAP
), (LPVOID
)&bm
);
2681 /* XXX is this always correct? */
2682 icount
= bm
.bmWidth
/ cx
;
2684 nheight
= cy
* icount
;
2686 bitCount
= bm
.bmBitsPixel
== 1 ? 1 : 24;
2687 sizeImage
= ((((bm
.bmWidth
* bitCount
)+31) & ~31) >> 3) * bm
.bmHeight
;
2688 nsizeImage
= ((((nwidth
* bitCount
)+31) & ~31) >> 3) * nheight
;
2690 totalSize
= sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
);
2692 totalSize
+= (1 << bitCount
) * sizeof(RGBQUAD
);
2693 offBits
= totalSize
;
2694 totalSize
+= nsizeImage
;
2696 data
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, totalSize
);
2697 bmfh
= (LPBITMAPFILEHEADER
)data
;
2698 bmih
= (LPBITMAPINFOHEADER
)(data
+ sizeof(BITMAPFILEHEADER
));
2699 lpBits
= data
+ offBits
;
2701 /* setup BITMAPFILEHEADER */
2702 bmfh
->bfType
= (('M' << 8) | 'B');
2704 bmfh
->bfReserved1
= 0;
2705 bmfh
->bfReserved2
= 0;
2706 bmfh
->bfOffBits
= offBits
;
2708 /* setup BITMAPINFOHEADER */
2709 bmih
->biSize
= sizeof(BITMAPINFOHEADER
);
2710 bmih
->biWidth
= bm
.bmWidth
;
2711 bmih
->biHeight
= bm
.bmHeight
;
2713 bmih
->biBitCount
= bitCount
;
2714 bmih
->biCompression
= BI_RGB
;
2715 bmih
->biSizeImage
= sizeImage
;
2716 bmih
->biXPelsPerMeter
= 0;
2717 bmih
->biYPelsPerMeter
= 0;
2718 bmih
->biClrUsed
= 0;
2719 bmih
->biClrImportant
= 0;
2721 lpBitsOrg
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, sizeImage
);
2722 if(!GetDIBits(xdc
, hBitmap
, 0, bm
.bmHeight
, lpBitsOrg
,
2723 (BITMAPINFO
*)bmih
, DIB_RGB_COLORS
))
2727 int obpl
= (((bm
.bmWidth
*bitCount
+31) & ~31)>>3);
2728 int nbpl
= (((nwidth
*bitCount
+31) & ~31)>>3);
2730 for(i
= 0; i
< nheight
; i
++) {
2731 int ooff
= ((nheight
-1-i
)%cy
) * obpl
+ ((i
/cy
) * nbpl
);
2732 int noff
= (nbpl
* (nheight
-1-i
));
2733 memcpy(lpBits
+ noff
, lpBitsOrg
+ ooff
, nbpl
);
2737 bmih
->biWidth
= nwidth
;
2738 bmih
->biHeight
= nheight
;
2739 bmih
->biSizeImage
= nsizeImage
;
2743 LPBITMAPINFO inf
= (LPBITMAPINFO
)bmih
;
2744 inf
->bmiColors
[0].rgbRed
= inf
->bmiColors
[0].rgbGreen
= inf
->bmiColors
[0].rgbBlue
= 0;
2745 inf
->bmiColors
[1].rgbRed
= inf
->bmiColors
[1].rgbGreen
= inf
->bmiColors
[1].rgbBlue
= 0xff;
2748 if(!SUCCEEDED(IStream_Write(pstm
, data
, totalSize
, NULL
)))
2755 LocalFree((HLOCAL
)lpBitsOrg
);
2761 /*************************************************************************
2762 * ImageList_Write [COMCTL32.@]
2764 * Writes an image list to a stream.
2767 * himl [I] handle to image list
2768 * pstm [O] Pointer to a stream.
2779 ImageList_Write (HIMAGELIST himl
, LPSTREAM pstm
)
2784 if (!is_valid(himl
))
2787 ilHead
.usMagic
= (('L' << 8) | 'I');
2788 ilHead
.usVersion
= 0x101;
2789 ilHead
.cCurImage
= himl
->cCurImage
;
2790 ilHead
.cMaxImage
= himl
->cMaxImage
;
2791 ilHead
.cGrow
= himl
->cGrow
;
2792 ilHead
.cx
= himl
->cx
;
2793 ilHead
.cy
= himl
->cy
;
2794 ilHead
.bkcolor
= himl
->clrBk
;
2795 ilHead
.flags
= himl
->flags
;
2796 for(i
= 0; i
< 4; i
++) {
2797 ilHead
.ovls
[i
] = himl
->nOvlIdx
[i
];
2800 if(!SUCCEEDED(IStream_Write(pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
2803 /* write the bitmap */
2804 if(!_write_bitmap(himl
->hbmImage
, pstm
, himl
->cx
, himl
->cy
))
2807 /* write the mask if we have one */
2808 if(himl
->flags
& ILC_MASK
) {
2809 if(!_write_bitmap(himl
->hbmMask
, pstm
, himl
->cx
, himl
->cy
))
2817 static HBITMAP
ImageList_CreateImage(HDC hdc
, HIMAGELIST himl
, UINT width
, UINT height
)
2819 HBITMAP hbmNewBitmap
;
2820 UINT ilc
= (himl
->flags
& 0xFE);
2822 if ((ilc
>= ILC_COLOR4
&& ilc
<= ILC_COLOR32
) || ilc
== ILC_COLOR
)
2827 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl
->uBitsPixel
);
2829 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
2830 bmi
.bmiHeader
.biWidth
= width
;
2831 bmi
.bmiHeader
.biHeight
= height
;
2832 bmi
.bmiHeader
.biPlanes
= 1;
2833 bmi
.bmiHeader
.biBitCount
= himl
->uBitsPixel
;
2834 bmi
.bmiHeader
.biCompression
= BI_RGB
;
2835 bmi
.bmiHeader
.biSizeImage
= 0;
2836 bmi
.bmiHeader
.biXPelsPerMeter
= 0;
2837 bmi
.bmiHeader
.biYPelsPerMeter
= 0;
2838 bmi
.bmiHeader
.biClrUsed
= 0;
2839 bmi
.bmiHeader
.biClrImportant
= 0;
2841 hbmNewBitmap
= CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &bits
, 0, 0);
2843 else /*if (ilc == ILC_COLORDDB)*/
2845 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl
->uBitsPixel
);
2847 hbmNewBitmap
= CreateBitmap (width
, height
, 1, himl
->uBitsPixel
, NULL
);
2850 return hbmNewBitmap
;