2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
6 * 2001 Michael Stefaniuc
7 * 2001 Charles Loep for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
25 * - Fix ImageList_GetIcon.
26 * - Fix ImageList_SetFilter (undocumented).
27 * BTW does anybody know anything about this function???
28 * - It removes 12 Bytes from the stack (3 Parameters).
29 * - First parameter SHOULD be a HIMAGELIST.
30 * - Second parameter COULD be an index?????
31 * - Third parameter.... ?????????????????????
34 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
35 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
36 * partially implemented, the functions mentioned above will be
37 * limited in functionality too.
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...
49 #include "wine/obj_base.h"
50 #include "wine/obj_storage.h"
52 #include "imagelist.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(imagelist
);
58 #define MAX_OVERLAYIMAGE 15
60 /* internal image list data used for Drag & Drop operations */
65 /* position of the drag image relative to the window */
68 /* offset of the hotspot relative to the origin of the image */
71 /* is the drag image visible */
73 /* saved background */
78 static INTERNALDRAG InternalDrag
= { 0, 0, 0, 0, 0, 0, FALSE
, 0, FALSE
};
82 /*************************************************************************
83 * IMAGELIST_InternalExpandBitmaps [Internal]
85 * Expands the bitmaps of an image list by the given number of images.
88 * himl [I] handle to image list
89 * nImageCount [I] number of images to add
95 * This function can NOT be used to reduce the number of images.
98 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl
, INT nImageCount
, INT cx
, INT cy
)
100 HDC hdcImageList
, hdcBitmap
;
101 HBITMAP hbmNewBitmap
;
102 INT nNewWidth
, nNewCount
;
104 if ((himl
->cCurImage
+ nImageCount
<= himl
->cMaxImage
)
108 if (cy
== 0) cy
= himl
->cy
;
109 nNewCount
= himl
->cCurImage
+ nImageCount
+ himl
->cGrow
;
110 nNewWidth
= nNewCount
* himl
->cx
;
112 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl
, nNewWidth
, cy
, nNewCount
);
113 hdcImageList
= CreateCompatibleDC (0);
114 hdcBitmap
= CreateCompatibleDC (0);
117 CreateBitmap (nNewWidth
, cy
, 1, himl
->uBitsPixel
, NULL
);
118 if (hbmNewBitmap
== 0)
119 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth
, cy
);
121 SelectObject (hdcImageList
, himl
->hbmImage
);
122 SelectObject (hdcBitmap
, hbmNewBitmap
);
123 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
124 hdcImageList
, 0, 0, SRCCOPY
);
126 DeleteObject (himl
->hbmImage
);
127 himl
->hbmImage
= hbmNewBitmap
;
131 CreateBitmap (nNewWidth
, cy
, 1, 1, NULL
);
133 if (hbmNewBitmap
== 0)
134 ERR("creating new mask bitmap!\n");
136 SelectObject (hdcImageList
, himl
->hbmMask
);
137 SelectObject (hdcBitmap
, hbmNewBitmap
);
138 BitBlt (hdcBitmap
, 0, 0, himl
->cCurImage
* himl
->cx
, cy
,
139 hdcImageList
, 0, 0, SRCCOPY
);
140 DeleteObject (himl
->hbmMask
);
141 himl
->hbmMask
= hbmNewBitmap
;
144 himl
->cMaxImage
= nNewCount
;
146 DeleteDC (hdcImageList
);
147 DeleteDC (hdcBitmap
);
151 /*************************************************************************
152 * IMAGELIST_InternalDraw [Internal]
154 * Draws the image in the ImageList (without the mask)
157 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
158 * cx [I] the width of the image to display
159 * cy............[I] the height of the image to display
165 * This function is used by ImageList_DrawIndirect, when it is
166 * required to draw only the Image (without the mask) to the screen.
168 * Blending and Overlays styles are accomplished by another function
171 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS
*pimldp
, INT cx
, INT cy
)
176 hImageDC
= CreateCompatibleDC(0);
177 hOldBitmap
= SelectObject(hImageDC
, pimldp
->himl
->hbmImage
);
178 BitBlt(pimldp
->hdcDst
,
179 pimldp
->x
, pimldp
->y
, cx
, cy
,
181 pimldp
->himl
->cx
* pimldp
->i
, 0,
184 SelectObject(hImageDC
, hOldBitmap
);
189 /*************************************************************************
190 * IMAGELIST_InternalDrawMask [Internal]
192 * Draws the image in the ImageList with the mask
195 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
196 * cx [I] the width of the image to display
197 * cy............[I] the height of the image to display
203 * This function is used by ImageList_DrawIndirect, when it is
204 * required to draw the Image with the mask to the screen.
206 * Blending and Overlays styles are accomplished by another function.
209 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS
*pimldp
, INT cx
, INT cy
)
211 BOOL bUseCustomBackground
, bBlendFlag
;
212 HBRUSH hBrush
, hOldBrush
;
213 HDC hMaskDC
, hImageDC
;
214 HBITMAP hOldBitmapImage
, hOldBitmapMask
;
215 HIMAGELIST himlLocal
= pimldp
->himl
;
216 COLORREF oldBkColor
, oldFgColor
;
217 UINT fStyle
= pimldp
->fStyle
& (~ILD_OVERLAYMASK
);
220 * We need a dc and bitmap to draw on that is
223 HDC hOffScreenDC
= 0;
224 HBITMAP hOffScreenBmp
= 0;
226 bUseCustomBackground
= (himlLocal
->clrBk
!= CLR_NONE
);
227 bBlendFlag
= (fStyle
& ILD_BLEND50
) || (fStyle
& ILD_BLEND25
);
229 hImageDC
= CreateCompatibleDC(0);
230 hMaskDC
= CreateCompatibleDC(0);
232 /* Create a compatible DC. */
233 hOffScreenDC
= CreateCompatibleDC( pimldp
->hdcDst
);
237 hOffScreenBmp
= CreateCompatibleBitmap( pimldp
->hdcDst
, cx
, cy
);
240 SelectObject( hOffScreenDC
, hOffScreenBmp
);
247 hOldBitmapImage
= SelectObject(hImageDC
, himlLocal
->hbmImage
);
248 hOldBitmapMask
= SelectObject(hMaskDC
, himlLocal
->hbmMask
);
251 * Get a copy of the image for the masking operations.
252 * We will use the copy, and this dc for all the various
253 * blitting, and then do one final blit to the screen dc.
254 * This should clean up most of the flickering.
256 BitBlt( hOffScreenDC
, 0, 0, cx
, cy
, pimldp
->hdcDst
, pimldp
->x
,
260 * Draw the Background for the appropriate Styles
262 if( bUseCustomBackground
&& (fStyle
== ILD_NORMAL
|| fStyle
& ILD_IMAGE
266 hBrush
= CreateSolidBrush (himlLocal
->clrBk
);
267 hOldBrush
= SelectObject (pimldp
->hdcDst
, hBrush
);
269 PatBlt( hOffScreenDC
, pimldp
->x
, pimldp
->y
, cx
, cy
, PATCOPY
);
271 DeleteObject (SelectObject (pimldp
->hdcDst
, hOldBrush
));
275 * Draw Image Transparently over the current background
277 if(fStyle
== ILD_NORMAL
|| (fStyle
& ILD_TRANSPARENT
) ||
278 ((fStyle
& ILD_IMAGE
) && bUseCustomBackground
) || bBlendFlag
)
280 * To obtain a transparent look, background color should be set
281 * to white and foreground color to black when blting the
285 oldBkColor
= SetBkColor( hOffScreenDC
, RGB( 0xff, 0xff, 0xff ) );
286 oldFgColor
= SetTextColor( hOffScreenDC
, RGB( 0, 0, 0 ) );
288 BitBlt( hOffScreenDC
, 0, 0, cx
, cy
,hMaskDC
, himlLocal
->cx
* pimldp
->i
,
291 BitBlt( hOffScreenDC
, 0, 0, cx
, cy
, hImageDC
,himlLocal
->cx
* pimldp
->i
,
297 * Draw the image when no Background is specified
299 else if((fStyle
& ILD_IMAGE
) && !bUseCustomBackground
)
301 BitBlt( hOffScreenDC
, 0, 0, cx
, cy
, hImageDC
,
302 himlLocal
->cx
* pimldp
->i
, 0, SRCCOPY
);
305 * Draw the mask with or without a background
307 else if(fStyle
& ILD_MASK
)
309 BitBlt( hOffScreenDC
, 0, 0, cx
, cy
, hMaskDC
, himlLocal
->cx
* pimldp
->i
,
310 0, bUseCustomBackground
? SRCCOPY
: SRCAND
);
314 * Blit the bitmap to the screen now.
316 BitBlt( pimldp
->hdcDst
, pimldp
->x
, pimldp
->y
, cx
, cy
,
317 hOffScreenDC
, 0, 0, SRCCOPY
);
320 SelectObject(hImageDC
, hOldBitmapImage
);
321 SelectObject(hMaskDC
, hOldBitmapMask
);
328 DeleteDC( hOffScreenDC
);
329 DeleteObject( hOffScreenBmp
);
334 /*************************************************************************
335 * IMAGELIST_InternalDrawBlend [Internal]
337 * Draws the Blend over the current image
340 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
341 * cx [I] the width of the image to display
342 * cy............[I] the height of the image to display
348 * This functions is used by ImageList_DrawIndirect, when it is
349 * required to add the blend to the current image.
353 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS
*pimldp
, INT cx
, INT cy
)
356 HDC hBlendMaskDC
,hMaskDC
;
357 HBRUSH hBlendColorBrush
, hBlendBrush
, hOldBrush
;
358 HBITMAP hBlendMaskBitmap
, hOldBitmap
;
359 COLORREF clrBlend
, OldTextColor
, OldBkColor
;
360 HIMAGELIST himlLocal
= pimldp
->himl
;
362 clrBlend
= GetSysColor (COLOR_HIGHLIGHT
);
363 if (!(pimldp
->rgbFg
== CLR_DEFAULT
))
365 clrBlend
= pimldp
->rgbFg
;
367 /* Create the blend Mask
369 hBlendMaskDC
= CreateCompatibleDC(0);
370 hBlendBrush
= pimldp
->fStyle
& ILD_BLEND50
?
371 himlLocal
->hbrBlend50
: himlLocal
->hbrBlend25
;
373 hBlendMaskBitmap
= CreateBitmap(cx
, cy
, 1, 1, NULL
);
374 hOldBitmap
= SelectObject(hBlendMaskDC
, hBlendMaskBitmap
);
376 hOldBrush
= (HBRUSH
) SelectObject(hBlendMaskDC
, hBlendBrush
);
377 PatBlt(hBlendMaskDC
, 0, 0, cx
, cy
, PATCOPY
);
378 SelectObject(hBlendMaskDC
, hOldBrush
);
380 /* Modify the blend mask if an Image Mask exist
382 if(pimldp
->himl
->hbmMask
!= 0)
384 HBITMAP hOldMaskBitmap
;
385 hMaskDC
= CreateCompatibleDC(0);
386 hOldMaskBitmap
= (HBITMAP
) SelectObject(hMaskDC
, himlLocal
->hbmMask
);
391 himlLocal
->cx
* pimldp
->i
,0,
392 0x220326); /* NOTSRCAND */
400 SelectObject(hMaskDC
, hOldMaskBitmap
);
404 /* Apply blend to the current image given the BlendMask
406 OldTextColor
= SetTextColor(pimldp
->hdcDst
, 0);
407 OldBkColor
= SetBkColor(pimldp
->hdcDst
, RGB(255,255,255));
408 hBlendColorBrush
= CreateSolidBrush(clrBlend
);
409 hOldBrush
= (HBRUSH
) SelectObject (pimldp
->hdcDst
, hBlendColorBrush
);
411 BitBlt (pimldp
->hdcDst
,
412 pimldp
->x
, pimldp
->y
, cx
, cy
,
415 0xB8074A); /* PSDPxax */
417 SelectObject(pimldp
->hdcDst
, hOldBrush
);
418 SetTextColor(pimldp
->hdcDst
, OldTextColor
);
419 SetBkColor(pimldp
->hdcDst
, OldBkColor
);
420 SelectObject(hBlendMaskDC
, hOldBitmap
);
421 DeleteDC(hBlendMaskDC
);
422 DeleteObject(hBlendMaskBitmap
);
423 DeleteObject(hBlendColorBrush
);
426 /*************************************************************************
427 * IMAGELIST_InternalDrawOverlay [Internal]
429 * Draws the overlay image
432 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
433 * cx [I] the width of the image to display
434 * cy............[I] the height of the image to display
440 * This functions is used by ImageList_DrawIndirect, when it is
441 * required to draw the overlay
446 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS
*pimldp
, INT cx
, INT cy
)
452 nOvlIdx
= (pimldp
->fStyle
& ILD_OVERLAYMASK
) >> 8;
453 if ((nOvlIdx
>= 1) && (nOvlIdx
<= MAX_OVERLAYIMAGE
))
455 nOvlIdx
= pimldp
->himl
->nOvlIdx
[nOvlIdx
- 1];
456 if ((nOvlIdx
>= 0) && (nOvlIdx
<= pimldp
->himl
->cCurImage
))
458 hImageDC
= CreateCompatibleDC(0);
459 if (pimldp
->himl
->hbmMask
)
461 hOldBitmap
= (HBITMAP
) SelectObject (hImageDC
,
462 pimldp
->himl
->hbmMask
);
464 BitBlt (pimldp
->hdcDst
,
465 pimldp
->x
, pimldp
->y
, cx
, cy
,
466 hImageDC
, pimldp
->himl
->cx
* nOvlIdx
, 0,
469 SelectObject(hImageDC
, hOldBitmap
);
471 hOldBitmap
= (HBITMAP
) SelectObject (hImageDC
,
472 pimldp
->himl
->hbmImage
);
474 BitBlt (pimldp
->hdcDst
,
475 pimldp
->x
, pimldp
->y
, cx
, cy
,
477 pimldp
->himl
->cx
* nOvlIdx
, 0,
480 SelectObject(hImageDC
, hOldBitmap
);
487 /*************************************************************************
488 * ImageList_Add [COMCTL32.40]
490 * Add an image or images to an image list.
493 * himl [I] handle to image list
494 * hbmImage [I] handle to image bitmap
495 * hbmMask [I] handle to mask bitmap
498 * Success: Index of the first new image.
503 ImageList_Add (HIMAGELIST himl
, HBITMAP hbmImage
, HBITMAP hbmMask
)
505 HDC hdcImage
, hdcBitmap
;
506 INT nFirstIndex
, nImageCount
;
509 HBITMAP hOldBitmapImage
, hOldBitmap
;
511 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl
, hbmImage
, hbmMask
);
512 if (!himl
|| !hbmImage
)
515 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
516 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
518 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
520 nStartX
= himl
->cCurImage
* himl
->cx
;
522 hdcImage
= CreateCompatibleDC(0);
523 hdcBitmap
= CreateCompatibleDC(0);
525 hOldBitmapImage
= SelectObject(hdcImage
, himl
->hbmImage
);
526 hOldBitmap
= SelectObject(hdcBitmap
, hbmImage
);
528 /* Copy result to the imagelist
530 BitBlt (hdcImage
, nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
531 hdcBitmap
, 0, 0, SRCCOPY
);
535 HDC hdcMask
, hdcTemp
, hOldBitmapMask
, hOldBitmapTemp
;
537 hdcMask
= CreateCompatibleDC (0);
538 hdcTemp
= CreateCompatibleDC(0);
539 hOldBitmapMask
= (HBITMAP
) SelectObject(hdcMask
, himl
->hbmMask
);
540 hOldBitmapTemp
= (HBITMAP
) SelectObject(hdcTemp
, hbmMask
);
543 nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
548 SelectObject(hdcTemp
, hOldBitmapTemp
);
551 /* Remove the background from the image
554 nStartX
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
557 0x220326); /* NOTSRCAND */
559 SelectObject(hdcMask
, hOldBitmapMask
);
563 SelectObject(hdcImage
, hOldBitmapImage
);
564 SelectObject(hdcBitmap
, hOldBitmap
);
568 nFirstIndex
= himl
->cCurImage
;
569 himl
->cCurImage
+= nImageCount
;
575 /*************************************************************************
576 * ImageList_AddIcon [COMCTL32.41]
578 * Adds an icon to an image list.
581 * himl [I] handle to image list
582 * hIcon [I] handle to icon
585 * Success: index of the new image
590 ImageList_AddIcon (HIMAGELIST himl
, HICON hIcon
)
592 return ImageList_ReplaceIcon (himl
, -1, hIcon
);
596 /*************************************************************************
597 * ImageList_AddMasked [COMCTL32.42]
599 * Adds an image or images to an image list and creates a mask from the
600 * specified bitmap using the mask color.
603 * himl [I] handle to image list.
604 * hBitmap [I] handle to bitmap
605 * clrMask [I] mask color.
608 * Success: Index of the first new image.
613 ImageList_AddMasked (HIMAGELIST himl
, HBITMAP hBitmap
, COLORREF clrMask
)
615 HDC hdcImage
, hdcMask
, hdcBitmap
;
616 INT nIndex
, nImageCount
, nMaskXOffset
=0;
618 HBITMAP hOldBitmap
, hOldBitmapMask
, hOldBitmapImage
;
619 HBITMAP hMaskBitmap
=0;
622 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl
, hBitmap
, clrMask
);
626 if (!GetObjectA (hBitmap
, sizeof(BITMAP
), &bmp
))
629 nImageCount
= bmp
.bmWidth
/ himl
->cx
;
631 IMAGELIST_InternalExpandBitmaps (himl
, nImageCount
, bmp
.bmWidth
, bmp
.bmHeight
);
633 nIndex
= himl
->cCurImage
;
634 himl
->cCurImage
+= nImageCount
;
636 hdcMask
= CreateCompatibleDC (0);
637 hdcImage
= CreateCompatibleDC(0);
638 hdcBitmap
= CreateCompatibleDC(0);
641 hOldBitmapImage
= SelectObject(hdcImage
, himl
->hbmImage
);
642 hOldBitmap
= SelectObject(hdcBitmap
, hBitmap
);
645 hOldBitmapMask
= SelectObject(hdcMask
, himl
->hbmMask
);
646 nMaskXOffset
= nIndex
* himl
->cx
;
651 Create a temp Mask so we can remove the background of
652 the Image (Windows does this even if there is no mask)
654 hMaskBitmap
= CreateBitmap(bmp
.bmWidth
, bmp
.bmHeight
, 1, 1, NULL
);
655 hOldBitmapMask
= SelectObject(hdcMask
, hMaskBitmap
);
658 /* create monochrome image to the mask bitmap */
659 bkColor
= (clrMask
!= CLR_DEFAULT
) ? clrMask
:
660 GetPixel (hdcBitmap
, 0, 0);
661 SetBkColor (hdcBitmap
, bkColor
);
663 nMaskXOffset
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
667 SetBkColor(hdcBitmap
, RGB(255,255,255));
668 /*Remove the background from the image
671 WINDOWS BUG ALERT!!!!!!
672 The statement below should not be done in common practice
673 but this is how ImageList_AddMasked works in Windows.
674 It overwrites the original bitmap passed, this was discovered
675 by using the same bitmap to iterate the different styles
676 on windows where it failed (BUT ImageList_Add is OK)
677 This is here in case some apps rely on this bug
680 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
683 0x220326); /* NOTSRCAND */
684 /* Copy result to the imagelist
687 nIndex
* himl
->cx
, 0, bmp
.bmWidth
, bmp
.bmHeight
,
693 SelectObject(hdcMask
,hOldBitmapMask
);
694 SelectObject(hdcImage
, hOldBitmapImage
);
695 SelectObject(hdcBitmap
, hOldBitmap
);
701 DeleteObject(hMaskBitmap
);
708 /*************************************************************************
709 * ImageList_BeginDrag [COMCTL32.43]
711 * Creates a temporary image list that contains one image. It will be used
715 * himlTrack [I] handle to the source image list
716 * iTrack [I] index of the drag image in the source image list
717 * dxHotspot [I] X position of the hot spot of the drag image
718 * dyHotspot [I] Y position of the hot spot of the drag image
726 ImageList_BeginDrag (HIMAGELIST himlTrack
, INT iTrack
,
727 INT dxHotspot
, INT dyHotspot
)
732 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack
, iTrack
,
733 dxHotspot
, dyHotspot
);
735 if (himlTrack
== NULL
)
738 if (InternalDrag
.himl
)
739 ImageList_EndDrag ();
744 InternalDrag
.himl
= ImageList_Create (cx
, cy
, himlTrack
->flags
, 1, 1);
745 if (InternalDrag
.himl
== NULL
) {
746 ERR("Error creating drag image list!\n");
750 InternalDrag
.dxHotspot
= dxHotspot
;
751 InternalDrag
.dyHotspot
= dyHotspot
;
753 hdcSrc
= CreateCompatibleDC (0);
754 hdcDst
= CreateCompatibleDC (0);
757 SelectObject (hdcSrc
, himlTrack
->hbmImage
);
758 SelectObject (hdcDst
, InternalDrag
.himl
->hbmImage
);
759 BitBlt (hdcDst
, 0, 0, cx
, cy
, hdcSrc
, iTrack
* cx
, 0, SRCCOPY
);
762 SelectObject (hdcSrc
, himlTrack
->hbmMask
);
763 SelectObject (hdcDst
, InternalDrag
.himl
->hbmMask
);
764 BitBlt (hdcDst
, 0, 0, cx
, cy
, hdcSrc
, iTrack
* cx
, 0, SRCCOPY
);
769 InternalDrag
.himl
->cCurImage
= 1;
770 InternalDrag
.bHSPending
= TRUE
;
776 /*************************************************************************
777 * ImageList_Copy [COMCTL32.44]
779 * Copies an image of the source image list to an image of the
780 * destination image list. Images can be copied or swapped.
783 * himlDst [I] handle to the destination image list
784 * iDst [I] destination image index.
785 * himlSrc [I] handle to the source image list
786 * iSrc [I] source image index
787 * uFlags [I] flags for the copy operation
794 * Copying from one image list to another is possible. The original
795 * implementation just copies or swaps within one image list.
796 * Could this feature become a bug??? ;-)
800 ImageList_Copy (HIMAGELIST himlDst
, INT iDst
, HIMAGELIST himlSrc
,
801 INT iSrc
, INT uFlags
)
805 TRACE("iDst=%d iSrc=%d\n", iDst
, iSrc
);
807 if ((himlSrc
== NULL
) || (himlDst
== NULL
))
809 if ((iDst
< 0) || (iDst
>= himlDst
->cCurImage
))
811 if ((iSrc
< 0) || (iSrc
>= himlSrc
->cCurImage
))
814 hdcSrc
= CreateCompatibleDC (0);
815 if (himlDst
== himlSrc
)
818 hdcDst
= CreateCompatibleDC (0);
820 if (uFlags
& ILCF_SWAP
) {
822 HBITMAP hbmTempImage
, hbmTempMask
;
824 /* create temporary bitmaps */
825 hbmTempImage
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
826 himlSrc
->uBitsPixel
, NULL
);
827 hbmTempMask
= CreateBitmap (himlSrc
->cx
, himlSrc
->cy
, 1,
830 /* copy (and stretch) destination to temporary bitmaps.(save) */
832 SelectObject (hdcSrc
, himlDst
->hbmImage
);
833 SelectObject (hdcDst
, hbmTempImage
);
834 StretchBlt (hdcDst
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
835 hdcSrc
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
838 SelectObject (hdcSrc
, himlDst
->hbmMask
);
839 SelectObject (hdcDst
, hbmTempMask
);
840 StretchBlt (hdcDst
, 0, 0, himlSrc
->cx
, himlSrc
->cy
,
841 hdcSrc
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
844 /* copy (and stretch) source to destination */
846 SelectObject (hdcSrc
, himlSrc
->hbmImage
);
847 SelectObject (hdcDst
, himlDst
->hbmImage
);
848 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
849 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
852 SelectObject (hdcSrc
, himlSrc
->hbmMask
);
853 SelectObject (hdcDst
, himlDst
->hbmMask
);
854 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
855 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
858 /* copy (without stretching) temporary bitmaps to source (restore) */
860 SelectObject (hdcSrc
, hbmTempImage
);
861 SelectObject (hdcDst
, himlSrc
->hbmImage
);
862 BitBlt (hdcDst
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
863 hdcSrc
, 0, 0, SRCCOPY
);
865 SelectObject (hdcSrc
, hbmTempMask
);
866 SelectObject (hdcDst
, himlSrc
->hbmMask
);
867 BitBlt (hdcDst
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
868 hdcSrc
, 0, 0, SRCCOPY
);
870 /* delete temporary bitmaps */
871 DeleteObject (hbmTempMask
);
872 DeleteObject (hbmTempImage
);
876 SelectObject (hdcSrc
, himlSrc
->hbmImage
);
877 if (himlSrc
== himlDst
)
880 SelectObject (hdcDst
, himlDst
->hbmImage
);
881 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
882 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
886 SelectObject (hdcSrc
, himlSrc
->hbmMask
);
887 if (himlSrc
== himlDst
)
890 SelectObject (hdcDst
, himlDst
->hbmMask
);
891 StretchBlt (hdcDst
, iDst
* himlDst
->cx
, 0, himlDst
->cx
, himlDst
->cy
,
892 hdcSrc
, iSrc
* himlSrc
->cx
, 0, himlSrc
->cx
, himlSrc
->cy
,
897 if (himlSrc
!= himlDst
)
904 /*************************************************************************
905 * ImageList_Create [COMCTL32.45] Creates a new image list.
908 * cx [I] image height
910 * flags [I] creation flags
911 * cInitial [I] initial number of images in the image list
912 * cGrow [I] number of images by which image list grows
915 * Success: Handle to the created image list
920 ImageList_Create (INT cx
, INT cy
, UINT flags
,
921 INT cInitial
, INT cGrow
)
927 static WORD aBitBlend25
[] =
928 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
930 static WORD aBitBlend50
[] =
931 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
933 TRACE("(%d %d 0x%x %d %d)\n", cx
, cy
, flags
, cInitial
, cGrow
);
935 himl
= (HIMAGELIST
)COMCTL32_Alloc (sizeof(struct _IMAGELIST
));
942 himl
->cMaxImage
= cInitial
+ cGrow
;
943 himl
->cInitial
= cInitial
;
946 himl
->clrFg
= CLR_DEFAULT
;
947 himl
->clrBk
= CLR_NONE
;
949 /* initialize overlay mask indices */
950 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
951 himl
->nOvlIdx
[nCount
] = -1;
953 hdc
= CreateCompatibleDC (0);
954 himl
->uBitsPixel
= (UINT
)GetDeviceCaps (hdc
, BITSPIXEL
);
957 TRACE("Image: %d Bits per Pixel\n", himl
->uBitsPixel
);
959 if (himl
->cMaxImage
> 0) {
961 CreateBitmap (himl
->cx
* himl
->cMaxImage
, himl
->cy
,
962 1, himl
->uBitsPixel
, NULL
);
963 if (himl
->hbmImage
== 0) {
964 ERR("Error creating image bitmap!\n");
971 if ( (himl
->cMaxImage
> 0) && (himl
->flags
& ILC_MASK
)) {
972 himl
->hbmMask
= CreateBitmap (himl
->cx
* himl
->cMaxImage
, himl
->cy
,
974 if (himl
->hbmMask
== 0) {
975 ERR("Error creating mask bitmap!\n");
977 DeleteObject (himl
->hbmImage
);
984 /* create blending brushes */
985 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend25
);
986 himl
->hbrBlend25
= CreatePatternBrush (hbmTemp
);
987 DeleteObject (hbmTemp
);
989 hbmTemp
= CreateBitmap (8, 8, 1, 1, &aBitBlend50
);
990 himl
->hbrBlend50
= CreatePatternBrush (hbmTemp
);
991 DeleteObject (hbmTemp
);
993 TRACE("created imagelist %p\n", himl
);
998 /*************************************************************************
999 * ImageList_Destroy [COMCTL32.46]
1001 * Destroys an image list.
1004 * himl [I] handle to image list
1012 ImageList_Destroy (HIMAGELIST himl
)
1017 /* delete image bitmaps */
1019 DeleteObject (himl
->hbmImage
);
1021 DeleteObject (himl
->hbmMask
);
1023 /* delete blending brushes */
1024 if (himl
->hbrBlend25
)
1025 DeleteObject (himl
->hbrBlend25
);
1026 if (himl
->hbrBlend50
)
1027 DeleteObject (himl
->hbrBlend50
);
1029 COMCTL32_Free (himl
);
1035 /*************************************************************************
1036 * ImageList_DragEnter [COMCTL32.47]
1038 * Locks window update and displays the drag image at the given position.
1041 * hwndLock [I] handle of the window that owns the drag image.
1042 * x [I] X position of the drag image.
1043 * y [I] Y position of the drag image.
1050 * The position of the drag image is relative to the window, not
1055 ImageList_DragEnter (HWND hwndLock
, INT x
, INT y
)
1057 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock
, x
, y
);
1059 if (InternalDrag
.himl
== NULL
)
1063 InternalDrag
.hwnd
= hwndLock
;
1065 InternalDrag
.hwnd
= GetDesktopWindow ();
1070 /* draw the drag image and save the background */
1071 if (!ImageList_DragShowNolock(TRUE
)) {
1079 /*************************************************************************
1080 * ImageList_DragLeave [COMCTL32.48]
1082 * Unlocks window update and hides the drag image.
1085 * hwndLock [I] handle of the window that owns the drag image.
1093 ImageList_DragLeave (HWND hwndLock
)
1095 /* As we don't save drag info in the window this can lead to problems if
1096 an app does not supply the same window as DragEnter */
1098 InternalDrag.hwnd = hwndLock;
1100 InternalDrag.hwnd = GetDesktopWindow (); */
1102 hwndLock
= GetDesktopWindow();
1103 if(InternalDrag
.hwnd
!= hwndLock
)
1104 FIXME("DragLeave hWnd != DragEnter hWnd\n");
1106 ImageList_DragShowNolock (FALSE
);
1112 /*************************************************************************
1113 * ImageList_DragMove [COMCTL32.49]
1115 * Moves the drag image.
1118 * x [I] X position of the drag image.
1119 * y [I] Y position of the drag image.
1126 * The position of the drag image is relative to the window, not
1130 * The drag image should be drawn semitransparent.
1134 ImageList_DragMove (INT x
, INT y
)
1136 TRACE("(x=%d y=%d)\n", x
, y
);
1138 if (!InternalDrag
.himl
) {
1142 /* draw/update the drag image */
1143 if (InternalDrag
.bShow
) {
1147 HBITMAP hbmOffScreen
;
1148 INT origNewX
, origNewY
;
1149 INT origOldX
, origOldY
;
1150 INT origRegX
, origRegY
;
1151 INT sizeRegX
, sizeRegY
;
1154 /* calculate the update region */
1155 origNewX
= x
- InternalDrag
.dxHotspot
;
1156 origNewY
= y
- InternalDrag
.dyHotspot
;
1157 origOldX
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
1158 origOldY
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
1159 origRegX
= min(origNewX
, origOldX
);
1160 origRegY
= min(origNewY
, origOldY
);
1161 sizeRegX
= InternalDrag
.himl
->cx
+ abs(x
- InternalDrag
.x
);
1162 sizeRegY
= InternalDrag
.himl
->cy
+ abs(y
- InternalDrag
.y
);
1164 hdcDrag
= GetDCEx(InternalDrag
.hwnd
, 0,
1165 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
1166 hdcOffScreen
= CreateCompatibleDC(hdcDrag
);
1167 hdcBg
= CreateCompatibleDC(hdcDrag
);
1169 hbmOffScreen
= CreateCompatibleBitmap(hdcDrag
, sizeRegX
, sizeRegY
);
1170 SelectObject(hdcOffScreen
, hbmOffScreen
);
1171 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
1173 /* get the actual background of the update region */
1174 BitBlt(hdcOffScreen
, 0, 0, sizeRegX
, sizeRegY
, hdcDrag
,
1175 origRegX
, origRegY
, SRCCOPY
);
1176 /* erase the old image */
1177 BitBlt(hdcOffScreen
, origOldX
- origRegX
, origOldY
- origRegY
,
1178 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
, hdcBg
, 0, 0,
1180 /* save the background */
1181 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
1182 hdcOffScreen
, origNewX
- origRegX
, origNewY
- origRegY
, SRCCOPY
);
1183 /* draw the image */
1184 /* FIXME: image should be drawn semitransparent */
1185 ImageList_Draw(InternalDrag
.himl
, 0, hdcOffScreen
, origNewX
- origRegX
,
1186 origNewY
- origRegY
, ILD_NORMAL
);
1187 /* draw the update region to the screen */
1188 BitBlt(hdcDrag
, origRegX
, origRegY
, sizeRegX
, sizeRegY
,
1189 hdcOffScreen
, 0, 0, SRCCOPY
);
1192 DeleteDC(hdcOffScreen
);
1193 DeleteObject(hbmOffScreen
);
1194 ReleaseDC(InternalDrag
.hwnd
, hdcDrag
);
1197 /* update the image position */
1205 /*************************************************************************
1206 * ImageList_DragShowNolock [COMCTL32.50]
1208 * Shows or hides the drag image.
1211 * bShow [I] TRUE shows the drag image, FALSE hides it.
1218 * The drag image should be drawn semitransparent.
1222 ImageList_DragShowNolock (BOOL bShow
)
1228 TRACE("bShow=0x%X!\n", bShow
);
1230 /* DragImage is already visible/hidden */
1231 if ((InternalDrag
.bShow
&& bShow
) || (!InternalDrag
.bShow
&& !bShow
)) {
1235 /* position of the origin of the DragImage */
1236 x
= InternalDrag
.x
- InternalDrag
.dxHotspot
;
1237 y
= InternalDrag
.y
- InternalDrag
.dyHotspot
;
1239 hdcDrag
= GetDCEx (InternalDrag
.hwnd
, 0,
1240 DCX_WINDOW
| DCX_CACHE
| DCX_LOCKWINDOWUPDATE
);
1245 hdcBg
= CreateCompatibleDC(hdcDrag
);
1246 if (!InternalDrag
.hbmBg
) {
1247 InternalDrag
.hbmBg
= CreateCompatibleBitmap(hdcDrag
,
1248 InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
);
1250 SelectObject(hdcBg
, InternalDrag
.hbmBg
);
1253 /* save the background */
1254 BitBlt(hdcBg
, 0, 0, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
1255 hdcDrag
, x
, y
, SRCCOPY
);
1256 /* show the image */
1257 /* FIXME: this should be drawn semitransparent */
1258 ImageList_Draw(InternalDrag
.himl
, 0, hdcDrag
, x
, y
, ILD_NORMAL
);
1260 /* hide the image */
1261 BitBlt(hdcDrag
, x
, y
, InternalDrag
.himl
->cx
, InternalDrag
.himl
->cy
,
1262 hdcBg
, 0, 0, SRCCOPY
);
1265 InternalDrag
.bShow
= !InternalDrag
.bShow
;
1268 ReleaseDC (InternalDrag
.hwnd
, hdcDrag
);
1273 /*************************************************************************
1274 * ImageList_Draw [COMCTL32.51] Draws an image.
1277 * himl [I] handle to image list
1279 * hdc [I] handle to device context
1282 * fStyle [I] drawing flags
1289 * Calls ImageList_DrawIndirect.
1292 * ImageList_DrawIndirect.
1296 ImageList_Draw (HIMAGELIST himl
, INT i
, HDC hdc
,
1297 INT x
, INT y
, UINT fStyle
)
1299 IMAGELISTDRAWPARAMS imldp
;
1301 imldp
.cbSize
= sizeof(IMAGELISTDRAWPARAMS
);
1311 imldp
.rgbBk
= CLR_DEFAULT
;
1312 imldp
.rgbFg
= CLR_DEFAULT
;
1313 imldp
.fStyle
= fStyle
;
1316 return ImageList_DrawIndirect (&imldp
);
1320 /*************************************************************************
1321 * ImageList_DrawEx [COMCTL32.52]
1323 * Draws an image and allows to use extended drawing features.
1326 * himl [I] handle to image list
1328 * hdc [I] handle to device context
1331 * xOffs [I] X offset
1332 * yOffs [I] Y offset
1333 * rgbBk [I] background color
1334 * rgbFg [I] foreground color
1335 * fStyle [I] drawing flags
1342 * Calls ImageList_DrawIndirect.
1345 * ImageList_DrawIndirect.
1349 ImageList_DrawEx (HIMAGELIST himl
, INT i
, HDC hdc
, INT x
, INT y
,
1350 INT dx
, INT dy
, COLORREF rgbBk
, COLORREF rgbFg
,
1353 IMAGELISTDRAWPARAMS imldp
;
1355 imldp
.cbSize
= sizeof(IMAGELISTDRAWPARAMS
);
1365 imldp
.rgbBk
= rgbBk
;
1366 imldp
.rgbFg
= rgbFg
;
1367 imldp
.fStyle
= fStyle
;
1370 return ImageList_DrawIndirect (&imldp
);
1374 /*************************************************************************
1375 * ImageList_DrawIndirect [COMCTL32.53]
1377 * Draws an image using ...
1380 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1388 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS
*pimldp
)
1392 Do some Error Checking
1396 if (pimldp
->cbSize
< sizeof(IMAGELISTDRAWPARAMS
))
1398 if (pimldp
->himl
== NULL
)
1400 if ((pimldp
->i
< 0) || (pimldp
->i
>= pimldp
->himl
->cCurImage
)) {
1401 ERR("%d not within range (max %d)\n",pimldp
->i
,pimldp
->himl
->cCurImage
-1);
1405 Get the Height and Width to display
1407 cx
= (pimldp
->cx
== 0) ? pimldp
->himl
->cx
: pimldp
->cx
;
1408 cy
= (pimldp
->cy
== 0) ? pimldp
->himl
->cy
: pimldp
->cy
;
1412 if(pimldp
->himl
->hbmMask
!= 0)
1414 IMAGELIST_InternalDrawMask(pimldp
, cx
, cy
);
1418 IMAGELIST_InternalDraw(pimldp
, cx
, cy
);
1421 Apply the blend if needed to the Image
1423 if((pimldp
->fStyle
& ILD_BLEND50
)
1424 || (pimldp
->fStyle
& ILD_BLEND25
))
1426 IMAGELIST_InternalDrawBlend(pimldp
, cx
, cy
);
1429 Apply the Overlay if needed
1431 if (pimldp
->fStyle
& ILD_OVERLAYMASK
)
1433 IMAGELIST_InternalDrawOverlay(pimldp
, cx
, cy
);
1440 /*************************************************************************
1441 * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
1444 * himlSrc [I] source image list handle
1447 * Success: Handle of duplicated image list.
1452 ImageList_Duplicate (HIMAGELIST himlSrc
)
1457 if (himlSrc
== NULL
) {
1458 ERR("Invalid image list handle!\n");
1462 himlDst
= ImageList_Create (himlSrc
->cx
, himlSrc
->cy
, himlSrc
->flags
,
1463 himlSrc
->cInitial
, himlSrc
->cGrow
);
1467 hdcSrc
= CreateCompatibleDC (0);
1468 hdcDst
= CreateCompatibleDC (0);
1469 SelectObject (hdcSrc
, himlSrc
->hbmImage
);
1470 SelectObject (hdcDst
, himlDst
->hbmImage
);
1471 BitBlt (hdcDst
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
, himlSrc
->cy
,
1472 hdcSrc
, 0, 0, SRCCOPY
);
1474 if (himlDst
->hbmMask
)
1476 SelectObject (hdcSrc
, himlSrc
->hbmMask
);
1477 SelectObject (hdcDst
, himlDst
->hbmMask
);
1478 BitBlt (hdcDst
, 0, 0, himlSrc
->cCurImage
* himlSrc
->cx
,
1479 himlSrc
->cy
, hdcSrc
, 0, 0, SRCCOPY
);
1485 himlDst
->cCurImage
= himlSrc
->cCurImage
;
1486 himlDst
->cMaxImage
= himlSrc
->cMaxImage
;
1492 /*************************************************************************
1493 * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
1495 * Finishes a drag operation.
1506 ImageList_EndDrag (void)
1508 /* cleanup the InternalDrag struct */
1509 InternalDrag
.hwnd
= 0;
1510 ImageList_Destroy (InternalDrag
.himl
);
1511 InternalDrag
.himl
= 0;
1514 InternalDrag
.dxHotspot
= 0;
1515 InternalDrag
.dyHotspot
= 0;
1516 InternalDrag
.bShow
= FALSE
;
1517 DeleteObject(InternalDrag
.hbmBg
);
1518 InternalDrag
.hbmBg
= 0;
1519 InternalDrag
.bHSPending
= FALSE
;
1525 /*************************************************************************
1526 * ImageList_GetBkColor [COMCTL32.56]
1528 * Returns the background color of an image list.
1531 * himl [I] Image list handle.
1534 * Success: background color
1539 ImageList_GetBkColor (HIMAGELIST himl
)
1548 /*************************************************************************
1549 * ImageList_GetDragImage [COMCTL32.57]
1551 * Returns the handle to the internal drag image list.
1554 * ppt [O] Pointer to the drag position. Can be NULL.
1555 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1558 * Success: Handle of the drag image list.
1563 ImageList_GetDragImage (POINT
*ppt
, POINT
*pptHotspot
)
1565 if (InternalDrag
.himl
) {
1567 ppt
->x
= InternalDrag
.x
;
1568 ppt
->y
= InternalDrag
.y
;
1571 pptHotspot
->x
= InternalDrag
.dxHotspot
;
1572 pptHotspot
->y
= InternalDrag
.dyHotspot
;
1574 return (InternalDrag
.himl
);
1581 /*************************************************************************
1582 * ImageList_GetFlags [COMCTL32.58]
1589 ImageList_GetFlags(HIMAGELIST himl
)
1591 FIXME("(%p):empty stub\n", himl
);
1596 /*************************************************************************
1597 * ImageList_GetIcon [COMCTL32.59]
1599 * Creates an icon from a masked image of an image list.
1602 * himl [I] handle to image list
1604 * flags [I] drawing style flags
1607 * Success: icon handle
1612 ImageList_GetIcon (HIMAGELIST himl
, INT i
, UINT fStyle
)
1616 HBITMAP hOldSrcBitmap
,hOldDstBitmap
;
1619 if ((himl
== NULL
) || (i
< 0) || (i
>= himl
->cCurImage
)) {
1620 FIXME("(%p,%d,%x), params out of range!\n",himl
,i
,fStyle
);
1624 hdcSrc
= CreateCompatibleDC(0);
1625 hdcDst
= CreateCompatibleDC(0);
1628 ii
.hbmMask
= CreateCompatibleBitmap (hdcDst
, himl
->cx
, himl
->cy
);
1631 hOldDstBitmap
= (HBITMAP
)SelectObject (hdcDst
, ii
.hbmMask
);
1632 if (himl
->hbmMask
) {
1633 SelectObject (hdcSrc
, himl
->hbmMask
);
1634 BitBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
,
1635 hdcSrc
, i
* himl
->cx
, 0, SRCCOPY
);
1638 PatBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
, BLACKNESS
);
1641 hOldSrcBitmap
= (HBITMAP
)SelectObject (hdcSrc
, himl
->hbmImage
);
1642 ii
.hbmColor
= CreateCompatibleBitmap (hdcSrc
, himl
->cx
, himl
->cy
);
1643 SelectObject (hdcDst
, ii
.hbmColor
);
1644 BitBlt (hdcDst
, 0, 0, himl
->cx
, himl
->cy
,
1645 hdcSrc
, i
* himl
->cx
, 0, SRCCOPY
);
1648 * CreateIconIndirect requires us to deselect the bitmaps from
1649 * the DCs before calling
1651 SelectObject(hdcSrc
, hOldSrcBitmap
);
1652 SelectObject(hdcDst
, hOldDstBitmap
);
1654 hIcon
= CreateIconIndirect (&ii
);
1658 DeleteObject (ii
.hbmMask
);
1659 DeleteObject (ii
.hbmColor
);
1665 /*************************************************************************
1666 * ImageList_GetIconSize [COMCTL32.60]
1668 * Retrieves the size of an image in an image list.
1671 * himl [I] handle to image list
1672 * cx [O] pointer to the image width.
1673 * cy [O] pointer to the image height.
1680 * All images in an image list have the same size.
1684 ImageList_GetIconSize (HIMAGELIST himl
, INT
*cx
, INT
*cy
)
1688 if ((himl
->cx
<= 0) || (himl
->cy
<= 0))
1700 /*************************************************************************
1701 * ImageList_GetImageCount [COMCTL32.61]
1703 * Returns the number of images in an image list.
1706 * himl [I] handle to image list
1709 * Success: Number of images.
1714 ImageList_GetImageCount (HIMAGELIST himl
)
1719 return himl
->cCurImage
;
1723 /*************************************************************************
1724 * ImageList_GetImageInfo [COMCTL32.62]
1726 * Returns information about an image in an image list.
1729 * himl [I] handle to image list
1731 * pImageInfo [O] pointer to the image information
1739 ImageList_GetImageInfo (HIMAGELIST himl
, INT i
, IMAGEINFO
*pImageInfo
)
1741 if ((himl
== NULL
) || (pImageInfo
== NULL
))
1743 if ((i
< 0) || (i
>= himl
->cCurImage
))
1746 pImageInfo
->hbmImage
= himl
->hbmImage
;
1747 pImageInfo
->hbmMask
= himl
->hbmMask
;
1749 pImageInfo
->rcImage
.top
= 0;
1750 pImageInfo
->rcImage
.bottom
= himl
->cy
;
1751 pImageInfo
->rcImage
.left
= i
* himl
->cx
;
1752 pImageInfo
->rcImage
.right
= (i
+1) * himl
->cx
;
1758 /*************************************************************************
1759 * ImageList_GetImageRect [COMCTL32.63]
1761 * Retrieves the rectangle of the specified image in an image list.
1764 * himl [I] handle to image list
1766 * lpRect [O] pointer to the image rectangle
1773 * This is an UNDOCUMENTED function!!!
1777 ImageList_GetImageRect (HIMAGELIST himl
, INT i
, LPRECT lpRect
)
1779 if ((himl
== NULL
) || (lpRect
== NULL
))
1781 if ((i
< 0) || (i
>= himl
->cCurImage
))
1784 lpRect
->left
= i
* himl
->cx
;
1786 lpRect
->right
= lpRect
->left
+ himl
->cx
;
1787 lpRect
->bottom
= himl
->cy
;
1793 /*************************************************************************
1794 * ImageList_LoadImage [COMCTL32.64]
1795 * ImageList_LoadImageA [COMCTL32.65]
1797 * Creates an image list from a bitmap, icon or cursor.
1800 * hi [I] instance handle
1801 * lpbmp [I] name or id of the image
1802 * cx [I] width of each image
1803 * cGrow [I] number of images to expand
1804 * clrMask [I] mask color
1805 * uType [I] type of image to load
1806 * uFlags [I] loading flags
1809 * Success: handle to the loaded image list
1817 ImageList_LoadImageA (HINSTANCE hi
, LPCSTR lpbmp
, INT cx
, INT cGrow
,
1818 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1820 HIMAGELIST himl
= NULL
;
1824 handle
= LoadImageA (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1826 ERR("Error loading image!\n");
1830 if (uType
== IMAGE_BITMAP
) {
1832 GetObjectA (handle
, sizeof(BITMAP
), &bmp
);
1834 /* To match windows behavior, if cx is set to zero and
1835 the flag DI_DEFAULTSIZE is specified, cx becomes the
1836 system metric value for icons. If the flag is not specified
1837 the function sets the size to the height of the bitmap */
1840 if (uFlags
& DI_DEFAULTSIZE
)
1841 cx
= GetSystemMetrics (SM_CXICON
);
1846 nImageCount
= bmp
.bmWidth
/ cx
;
1848 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1849 nImageCount
, cGrow
);
1850 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1852 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1856 GetIconInfo (handle
, &ii
);
1857 GetObjectA (ii
.hbmColor
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1858 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1859 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1860 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1861 DeleteObject (ii
.hbmColor
);
1862 DeleteObject (ii
.hbmMask
);
1865 DeleteObject (handle
);
1871 /*************************************************************************
1872 * ImageList_LoadImageW [COMCTL32.66]
1874 * Creates an image list from a bitmap, icon or cursor.
1877 * hi [I] instance handle
1878 * lpbmp [I] name or id of the image
1879 * cx [I] width of each image
1880 * cGrow [I] number of images to expand
1881 * clrMask [I] mask color
1882 * uType [I] type of image to load
1883 * uFlags [I] loading flags
1886 * Success: handle to the loaded image list
1894 ImageList_LoadImageW (HINSTANCE hi
, LPCWSTR lpbmp
, INT cx
, INT cGrow
,
1895 COLORREF clrMask
, UINT uType
, UINT uFlags
)
1897 HIMAGELIST himl
= NULL
;
1901 handle
= LoadImageW (hi
, lpbmp
, uType
, 0, 0, uFlags
);
1903 ERR("Error loading image!\n");
1907 if (uType
== IMAGE_BITMAP
) {
1909 GetObjectA (handle
, sizeof(BITMAP
), &bmp
);
1911 /* To match windows behavior, if cx is set to zero and
1912 the flag DI_DEFAULTSIZE is specified, cx becomes the
1913 system metric value for icons. If the flag is not specified
1914 the function sets the size to the height of the bitmap */
1917 if (uFlags
& DI_DEFAULTSIZE
)
1918 cx
= GetSystemMetrics (SM_CXICON
);
1923 nImageCount
= bmp
.bmWidth
/ cx
;
1925 himl
= ImageList_Create (cx
, bmp
.bmHeight
, ILC_MASK
| ILC_COLOR
,
1926 nImageCount
, cGrow
);
1927 ImageList_AddMasked (himl
, (HBITMAP
)handle
, clrMask
);
1929 else if ((uType
== IMAGE_ICON
) || (uType
== IMAGE_CURSOR
)) {
1933 GetIconInfo (handle
, &ii
);
1934 GetObjectA (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
1935 himl
= ImageList_Create (bmp
.bmWidth
, bmp
.bmHeight
,
1936 ILC_MASK
| ILC_COLOR
, 1, cGrow
);
1937 ImageList_Add (himl
, ii
.hbmColor
, ii
.hbmMask
);
1938 DeleteObject (ii
.hbmColor
);
1939 DeleteObject (ii
.hbmMask
);
1942 DeleteObject (handle
);
1948 /*************************************************************************
1949 * ImageList_Merge [COMCTL32.67]
1951 * Creates a new image list that contains a merged image from the specified
1952 * images of both source image lists.
1955 * himl1 [I] handle to first image list
1956 * i1 [I] first image index
1957 * himl2 [I] handle to second image list
1958 * i2 [I] second image index
1959 * dx [I] X offset of the second image relative to the first.
1960 * dy [I] Y offset of the second image relative to the first.
1963 * Success: handle of the merged image list.
1968 ImageList_Merge (HIMAGELIST himl1
, INT i1
, HIMAGELIST himl2
, INT i2
,
1971 HIMAGELIST himlDst
= NULL
;
1972 HDC hdcSrcImage
, hdcDstImage
;
1974 INT xOff1
, yOff1
, xOff2
, yOff2
;
1977 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1
, i1
, himl2
,
1980 if ((himl1
== NULL
) || (himl2
== NULL
))
1984 if ((i1
< 0) || (i1
>= himl1
->cCurImage
)) {
1985 ERR("Index 1 out of range! %d\n", i1
);
1989 if ((i2
< 0) || (i2
>= himl2
->cCurImage
)) {
1990 ERR("Index 2 out of range! %d\n", i2
);
1995 cxDst
= max (himl1
->cx
, dx
+ himl2
->cx
);
2000 cxDst
= max (himl2
->cx
, himl1
->cx
- dx
);
2005 cxDst
= max (himl1
->cx
, himl2
->cx
);
2011 cyDst
= max (himl1
->cy
, dy
+ himl2
->cy
);
2016 cyDst
= max (himl2
->cy
, himl1
->cy
- dy
);
2021 cyDst
= max (himl1
->cy
, himl2
->cy
);
2026 himlDst
= ImageList_Create (cxDst
, cyDst
, ILC_MASK
| ILC_COLOR
, 1, 1);
2029 hdcSrcImage
= CreateCompatibleDC (0);
2030 hdcDstImage
= CreateCompatibleDC (0);
2031 nX1
= i1
* himl1
->cx
;
2032 nX2
= i2
* himl2
->cx
;
2035 SelectObject (hdcSrcImage
, himl1
->hbmImage
);
2036 SelectObject (hdcDstImage
, himlDst
->hbmImage
);
2037 BitBlt (hdcDstImage
, 0, 0, cxDst
, cyDst
,
2038 hdcSrcImage
, 0, 0, BLACKNESS
);
2039 BitBlt (hdcDstImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
,
2040 hdcSrcImage
, nX1
, 0, SRCCOPY
);
2042 SelectObject (hdcSrcImage
, himl2
->hbmMask
);
2043 BitBlt (hdcDstImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
,
2044 hdcSrcImage
, nX2
, 0, SRCAND
);
2046 SelectObject (hdcSrcImage
, himl2
->hbmImage
);
2047 BitBlt (hdcDstImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
,
2048 hdcSrcImage
, nX2
, 0, SRCPAINT
);
2051 SelectObject (hdcSrcImage
, himl1
->hbmMask
);
2052 SelectObject (hdcDstImage
, himlDst
->hbmMask
);
2053 BitBlt (hdcDstImage
, 0, 0, cxDst
, cyDst
,
2054 hdcSrcImage
, 0, 0, WHITENESS
);
2055 BitBlt (hdcDstImage
, xOff1
, yOff1
, himl1
->cx
, himl1
->cy
,
2056 hdcSrcImage
, nX1
, 0, SRCCOPY
);
2058 SelectObject (hdcSrcImage
, himl2
->hbmMask
);
2059 BitBlt (hdcDstImage
, xOff2
, yOff2
, himl2
->cx
, himl2
->cy
,
2060 hdcSrcImage
, nX2
, 0, SRCAND
);
2062 DeleteDC (hdcSrcImage
);
2063 DeleteDC (hdcDstImage
);
2064 himlDst
->cCurImage
= 1;
2071 /* helper for _read_bitmap currently unused */
2073 static int may_use_dibsection(HDC hdc
) {
2074 int bitspixel
= GetDeviceCaps(hdc
,BITSPIXEL
)*GetDeviceCaps(hdc
,PLANES
);
2079 return GetDeviceCaps(hdc
,CAPS1
) & C1_DIBENGINE
;
2083 /* helper for ImageList_Read, see comments below */
2084 static HBITMAP
_read_bitmap(LPSTREAM pstm
,int ilcFlag
,int cx
,int cy
) {
2086 BITMAPFILEHEADER bmfh
;
2087 BITMAPINFOHEADER bmih
;
2088 int bitsperpixel
,palspace
,longsperline
,width
,height
;
2089 LPBITMAPINFOHEADER bmihc
= NULL
;
2091 HBITMAP hbitmap
= 0;
2092 LPBYTE bits
= NULL
,nbits
= NULL
;
2093 int nbytesperline
,bytesperline
;
2095 if (!SUCCEEDED(IStream_Read ( pstm
, &bmfh
, sizeof(bmfh
), NULL
)) ||
2096 (bmfh
.bfType
!= (('M'<<8)|'B')) ||
2097 !SUCCEEDED(IStream_Read ( pstm
, &bmih
, sizeof(bmih
), NULL
)) ||
2098 (bmih
.biSize
!= sizeof(bmih
))
2102 bitsperpixel
= bmih
.biPlanes
* bmih
.biBitCount
;
2103 if (bitsperpixel
<=8)
2104 palspace
= (1<<bitsperpixel
)*sizeof(RGBQUAD
);
2107 width
= bmih
.biWidth
;
2108 height
= bmih
.biHeight
;
2109 bmihc
= (LPBITMAPINFOHEADER
)LocalAlloc(LMEM_ZEROINIT
,sizeof(bmih
)+palspace
);
2110 memcpy(bmihc
,&bmih
,sizeof(bmih
));
2111 longsperline
= ((width
*bitsperpixel
+31)&~0x1f)>>5;
2112 bmihc
->biSizeImage
= (longsperline
*height
)<<2;
2114 /* read the palette right after the end of the bitmapinfoheader */
2116 if (!SUCCEEDED(IStream_Read ( pstm
, bmihc
+1, palspace
, NULL
)))
2120 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2121 if ((bitsperpixel
>1) &&
2122 ((ilcFlag
!=ILC_COLORDDB
) && (!ilcFlag
|| may_use_dibsection(xdc
)))
2124 hbitmap
= CreateDIBSection(xdc
,(BITMAPINFO
*)bmihc
,0,(LPVOID
*)&bits
,0,0);
2127 if (!SUCCEEDED(IStream_Read( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
2133 int i
,nwidth
,nheight
;
2135 nwidth
= width
*(height
/cy
);
2138 if (bitsperpixel
==1)
2139 hbitmap
= CreateBitmap(nwidth
,nheight
,1,1,NULL
);
2141 hbitmap
= CreateCompatibleBitmap(xdc
,nwidth
,nheight
);
2143 /* Might be a bit excessive memory use here */
2144 bits
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
,bmihc
->biSizeImage
);
2145 nbits
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
,bmihc
->biSizeImage
);
2146 if (!SUCCEEDED(IStream_Read ( pstm
, bits
, bmihc
->biSizeImage
, NULL
)))
2149 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2150 /* Do not forget that windows bitmaps are bottom->top */
2151 bytesperline
= longsperline
*4;
2152 nbytesperline
= (height
/cy
)*bytesperline
;
2153 for (i
=0;i
<height
;i
++) {
2155 nbits
+((height
-1-i
)%cy
)*nbytesperline
+(i
/cy
)*bytesperline
,
2156 bits
+bytesperline
*(height
-1-i
),
2160 bmihc
->biWidth
= nwidth
;
2161 bmihc
->biHeight
= nheight
;
2162 if (!SetDIBits(xdc
,hbitmap
,0,nheight
,nbits
,(BITMAPINFO
*)bmihc
,0))
2164 LocalFree((HLOCAL
)nbits
);
2165 LocalFree((HLOCAL
)bits
);
2169 if (xdc
) ReleaseDC(0,xdc
);
2170 if (bmihc
) LocalFree((HLOCAL
)bmihc
);
2173 DeleteObject(hbitmap
);
2180 /*************************************************************************
2181 * ImageList_Read [COMCTL32.68]
2183 * Reads an image list from a stream.
2186 * pstm [I] pointer to a stream
2189 * Success: handle to image list
2192 * The format is like this:
2193 * ILHEAD ilheadstruct;
2195 * for the color image part:
2196 * BITMAPFILEHEADER bmfh;
2197 * BITMAPINFOHEADER bmih;
2198 * only if it has a palette:
2199 * RGBQUAD rgbs[nr_of_paletted_colors];
2201 * BYTE colorbits[imagesize];
2203 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2204 * BITMAPFILEHEADER bmfh_mask;
2205 * BITMAPINFOHEADER bmih_mask;
2206 * only if it has a palette (it usually does not):
2207 * RGBQUAD rgbs[nr_of_paletted_colors];
2209 * BYTE maskbits[imagesize];
2211 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2212 * _read_bitmap needs to convert them.
2214 HIMAGELIST WINAPI
ImageList_Read (LPSTREAM pstm
)
2218 HBITMAP hbmColor
=0,hbmMask
=0;
2221 if (!SUCCEEDED(IStream_Read (pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
2223 if (ilHead
.usMagic
!= (('L' << 8) | 'I'))
2225 if (ilHead
.usVersion
!= 0x101) /* probably version? */
2229 FIXME(" ilHead.cCurImage = %d\n",ilHead
.cCurImage
);
2230 FIXME(" ilHead.cMaxImage = %d\n",ilHead
.cMaxImage
);
2231 FIXME(" ilHead.cGrow = %d\n",ilHead
.cGrow
);
2232 FIXME(" ilHead.cx = %d\n",ilHead
.cx
);
2233 FIXME(" ilHead.cy = %d\n",ilHead
.cy
);
2234 FIXME(" ilHead.flags = %x\n",ilHead
.flags
);
2235 FIXME(" ilHead.ovls[0] = %d\n",ilHead
.ovls
[0]);
2236 FIXME(" ilHead.ovls[1] = %d\n",ilHead
.ovls
[1]);
2237 FIXME(" ilHead.ovls[2] = %d\n",ilHead
.ovls
[2]);
2238 FIXME(" ilHead.ovls[3] = %d\n",ilHead
.ovls
[3]);
2241 hbmColor
= _read_bitmap(pstm
,ilHead
.flags
& ~ILC_MASK
,ilHead
.cx
,ilHead
.cy
);
2244 if (ilHead
.flags
& ILC_MASK
) {
2245 hbmMask
= _read_bitmap(pstm
,0,ilHead
.cx
,ilHead
.cy
);
2247 DeleteObject(hbmColor
);
2252 himl
= ImageList_Create (
2260 DeleteObject(hbmColor
);
2261 DeleteObject(hbmMask
);
2264 himl
->hbmImage
= hbmColor
;
2265 himl
->hbmMask
= hbmMask
;
2266 himl
->cCurImage
= ilHead
.cCurImage
;
2267 himl
->cMaxImage
= ilHead
.cMaxImage
;
2269 ImageList_SetBkColor(himl
,ilHead
.bkcolor
);
2271 ImageList_SetOverlayImage(himl
,ilHead
.ovls
[i
],i
+1);
2276 /*************************************************************************
2277 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2280 * himl [I] image list handle
2289 ImageList_Remove (HIMAGELIST himl
, INT i
)
2291 HBITMAP hbmNewImage
, hbmNewMask
;
2295 TRACE("(himl=%p i=%d)\n", himl
, i
);
2298 ERR("Invalid image list handle!\n");
2302 if ((i
< -1) || (i
>= himl
->cCurImage
)) {
2303 ERR("index out of range! %d\n", i
);
2309 if (himl
->cCurImage
== 0) {
2310 /* remove all on empty ImageList is allowed */
2311 TRACE("remove all on empty ImageList!\n");
2315 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2316 himl
->cCurImage
= 0;
2317 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2318 himl
->nOvlIdx
[nCount
] = -1;
2320 DeleteObject (himl
->hbmImage
);
2322 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2323 1, himl
->uBitsPixel
, NULL
);
2325 if (himl
->hbmMask
) {
2326 DeleteObject (himl
->hbmMask
);
2328 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2333 /* delete one image */
2334 TRACE("Remove single image! %d\n", i
);
2336 /* create new bitmap(s) */
2337 cxNew
= (himl
->cCurImage
+ himl
->cGrow
- 1) * himl
->cx
;
2339 TRACE(" - Number of images: %d / %d (Old/New)\n",
2340 himl
->cCurImage
, himl
->cCurImage
- 1);
2341 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2342 himl
->cMaxImage
, himl
->cCurImage
+ himl
->cGrow
- 1);
2345 CreateBitmap (cxNew
, himl
->cy
, 1, himl
->uBitsPixel
, NULL
);
2348 hbmNewMask
= CreateBitmap (cxNew
, himl
->cy
, 1, 1, NULL
);
2350 hbmNewMask
= 0; /* Just to keep compiler happy! */
2352 hdcSrc
= CreateCompatibleDC (0);
2353 hdcDst
= CreateCompatibleDC (0);
2355 /* copy all images and masks prior to the "removed" image */
2357 TRACE("Pre image copy: Copy %d images\n", i
);
2359 SelectObject (hdcSrc
, himl
->hbmImage
);
2360 SelectObject (hdcDst
, hbmNewImage
);
2361 BitBlt (hdcDst
, 0, 0, i
* himl
->cx
, himl
->cy
,
2362 hdcSrc
, 0, 0, SRCCOPY
);
2364 if (himl
->hbmMask
) {
2365 SelectObject (hdcSrc
, himl
->hbmMask
);
2366 SelectObject (hdcDst
, hbmNewMask
);
2367 BitBlt (hdcDst
, 0, 0, i
* himl
->cx
, himl
->cy
,
2368 hdcSrc
, 0, 0, SRCCOPY
);
2372 /* copy all images and masks behind the removed image */
2373 if (i
< himl
->cCurImage
- 1) {
2374 TRACE("Post image copy!\n");
2375 SelectObject (hdcSrc
, himl
->hbmImage
);
2376 SelectObject (hdcDst
, hbmNewImage
);
2377 BitBlt (hdcDst
, i
* himl
->cx
, 0, (himl
->cCurImage
- i
- 1) * himl
->cx
,
2378 himl
->cy
, hdcSrc
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2380 if (himl
->hbmMask
) {
2381 SelectObject (hdcSrc
, himl
->hbmMask
);
2382 SelectObject (hdcDst
, hbmNewMask
);
2383 BitBlt (hdcDst
, i
* himl
->cx
, 0,
2384 (himl
->cCurImage
- i
- 1) * himl
->cx
,
2385 himl
->cy
, hdcSrc
, (i
+ 1) * himl
->cx
, 0, SRCCOPY
);
2392 /* delete old images and insert new ones */
2393 DeleteObject (himl
->hbmImage
);
2394 himl
->hbmImage
= hbmNewImage
;
2395 if (himl
->hbmMask
) {
2396 DeleteObject (himl
->hbmMask
);
2397 himl
->hbmMask
= hbmNewMask
;
2401 himl
->cMaxImage
= himl
->cCurImage
+ himl
->cGrow
;
2408 /*************************************************************************
2409 * ImageList_Replace [COMCTL32.70]
2411 * Replaces an image in an image list with a new image.
2414 * himl [I] handle to image list
2416 * hbmImage [I] handle to image bitmap
2417 * hbmMask [I] handle to mask bitmap. Can be NULL.
2425 ImageList_Replace (HIMAGELIST himl
, INT i
, HBITMAP hbmImage
,
2428 HDC hdcImageList
, hdcImage
;
2432 ERR("Invalid image list handle!\n");
2436 if ((i
>= himl
->cMaxImage
) || (i
< 0)) {
2437 ERR("Invalid image index!\n");
2441 hdcImageList
= CreateCompatibleDC (0);
2442 hdcImage
= CreateCompatibleDC (0);
2443 GetObjectA (hbmImage
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2446 SelectObject (hdcImageList
, himl
->hbmImage
);
2447 SelectObject (hdcImage
, hbmImage
);
2449 StretchBlt (hdcImageList
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2450 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2455 SelectObject (hdcImageList
, himl
->hbmMask
);
2456 SelectObject (hdcImage
, hbmMask
);
2458 StretchBlt (hdcImageList
, i
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2459 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2462 /* Remove the background from the image
2464 SelectObject (hdcImageList
, himl
->hbmImage
);
2465 StretchBlt (hdcImageList
,
2466 i
*himl
->cx
, 0, himl
->cx
, himl
->cy
,
2468 0, 0, bmp
.bmWidth
, bmp
.bmHeight
,
2469 0x220326); /* NOTSRCAND */
2472 DeleteDC (hdcImage
);
2473 DeleteDC (hdcImageList
);
2479 /*************************************************************************
2480 * ImageList_ReplaceIcon [COMCTL32.75]
2482 * Replaces an image in an image list using an icon.
2485 * himl [I] handle to image list
2487 * hIcon [I] handle to icon
2490 * Success: index of the replaced image
2495 ImageList_ReplaceIcon (HIMAGELIST himl
, INT i
, HICON hIcon
)
2497 HDC hdcImageList
, hdcImage
;
2500 HBITMAP hbmOldSrc
, hbmOldDst
;
2504 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD
)himl
, i
, hIcon
);
2508 if ((i
>= himl
->cMaxImage
) || (i
< -1))
2511 hBestFitIcon
= CopyImage(
2514 LR_COPYFROMRESOURCE
);
2516 GetIconInfo (hBestFitIcon
, &ii
);
2517 if (ii
.hbmMask
== 0)
2519 if (ii
.hbmColor
== 0)
2521 GetObjectA (ii
.hbmMask
, sizeof(BITMAP
), (LPVOID
)&bmp
);
2524 if (himl
->cCurImage
+ 1 > himl
->cMaxImage
)
2525 IMAGELIST_InternalExpandBitmaps (himl
, 1, 0, 0);
2527 nIndex
= himl
->cCurImage
;
2533 hdcImageList
= CreateCompatibleDC (0);
2534 TRACE("hdcImageList=0x%x!\n", hdcImageList
);
2535 if (hdcImageList
== 0)
2536 ERR("invalid hdcImageList!\n");
2538 hdcImage
= CreateCompatibleDC (0);
2539 TRACE("hdcImage=0x%x!\n", hdcImage
);
2541 ERR("invalid hdcImage!\n");
2543 hbmOldDst
= SelectObject (hdcImageList
, himl
->hbmImage
);
2544 SetTextColor( hdcImageList
, RGB(0,0,0));
2545 SetBkColor( hdcImageList
, RGB(255,255,255));
2546 hbmOldSrc
= SelectObject (hdcImage
, ii
.hbmColor
);
2547 StretchBlt (hdcImageList
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2548 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2550 if (himl
->hbmMask
) {
2551 SelectObject (hdcImageList
, himl
->hbmMask
);
2552 SelectObject (hdcImage
, ii
.hbmMask
);
2553 StretchBlt (hdcImageList
, nIndex
* himl
->cx
, 0, himl
->cx
, himl
->cy
,
2554 hdcImage
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, SRCCOPY
);
2557 SelectObject (hdcImage
, hbmOldSrc
);
2558 SelectObject (hdcImageList
, hbmOldDst
);
2561 DestroyIcon(hBestFitIcon
);
2563 DeleteDC (hdcImageList
);
2565 DeleteDC (hdcImage
);
2567 DeleteObject (ii
.hbmColor
);
2569 DeleteObject (ii
.hbmMask
);
2575 /*************************************************************************
2576 * ImageList_SetBkColor [COMCTL32.76]
2578 * Sets the background color of an image list.
2581 * himl [I] handle to image list
2582 * clrBk [I] background color
2585 * Success: previous background color
2590 ImageList_SetBkColor (HIMAGELIST himl
, COLORREF clrBk
)
2597 clrOldBk
= himl
->clrBk
;
2598 himl
->clrBk
= clrBk
;
2603 /*************************************************************************
2604 * ImageList_SetDragCursorImage [COMCTL32.77]
2606 * Combines the specified image with the current drag image
2609 * himlDrag [I] handle to drag image list
2610 * iDrag [I] drag image index
2611 * dxHotspot [I] X position of the hot spot
2612 * dyHotspot [I] Y position of the hot spot
2619 * When this function is called and the drag image is visible, a
2620 * short flickering occurs but this matches the Win9x behavior. It is
2621 * possible to fix the flickering using code like in ImageList_DragMove.
2625 ImageList_SetDragCursorImage (HIMAGELIST himlDrag
, INT iDrag
,
2626 INT dxHotspot
, INT dyHotspot
)
2628 HIMAGELIST himlTemp
;
2632 if (InternalDrag
.himl
== NULL
)
2635 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2636 dxHotspot
, dyHotspot
, InternalDrag
.dxHotspot
, InternalDrag
.dyHotspot
);
2638 visible
= InternalDrag
.bShow
;
2640 /* Calculate the offset between the origin of the old image and the
2641 * origin of the second image.
2642 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2643 * hotspot) to the origin of the second image.
2644 * See M$DN for details */
2645 if(InternalDrag
.bHSPending
) {
2648 InternalDrag
.bHSPending
= FALSE
;
2650 dx
= InternalDrag
.dxHotspot
- dxHotspot
;
2651 dy
= InternalDrag
.dyHotspot
- dyHotspot
;
2653 himlTemp
= ImageList_Merge (InternalDrag
.himl
, 0, himlDrag
, iDrag
, dx
, dy
);
2656 /* hide the drag image */
2657 ImageList_DragShowNolock(FALSE
);
2659 if ((InternalDrag
.himl
->cx
!= himlTemp
->cx
) ||
2660 (InternalDrag
.himl
->cy
!= himlTemp
->cy
)) {
2661 /* the size of the drag image changed, invalidate the buffer */
2662 DeleteObject(InternalDrag
.hbmBg
);
2663 InternalDrag
.hbmBg
= 0;
2666 ImageList_Destroy (InternalDrag
.himl
);
2667 InternalDrag
.himl
= himlTemp
;
2669 /* update the InternalDragOffset, if the origin of the
2670 * DragImage was changed by ImageList_Merge. */
2672 InternalDrag
.dxHotspot
= dxHotspot
;
2674 InternalDrag
.dyHotspot
= dyHotspot
;
2677 /* show the drag image */
2678 ImageList_DragShowNolock(TRUE
);
2685 /*************************************************************************
2686 * ImageList_SetFilter [COMCTL32.78]
2688 * Sets a filter (or does something completely different)!!???
2691 * himl [I] handle to image list
2697 * Failure: FALSE ???
2700 * This is an UNDOCUMENTED function!!!!
2705 ImageList_SetFilter (HIMAGELIST himl
, INT i
, DWORD dwFilter
)
2707 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2714 /*************************************************************************
2715 * ImageList_SetFlags [COMCTL32.79]
2722 ImageList_SetFlags(HIMAGELIST himl
, DWORD flags
)
2724 FIXME("(%p %08lx):empty stub\n", himl
, flags
);
2729 /*************************************************************************
2730 * ImageList_SetIconSize [COMCTL32.80]
2732 * Sets the image size of the bitmap and deletes all images.
2735 * himl [I] handle to image list
2736 * cx [I] image width
2737 * cy [I] image height
2745 ImageList_SetIconSize (HIMAGELIST himl
, INT cx
, INT cy
)
2752 /* remove all images */
2753 himl
->cMaxImage
= himl
->cInitial
+ himl
->cGrow
;
2754 himl
->cCurImage
= 0;
2758 /* initialize overlay mask indices */
2759 for (nCount
= 0; nCount
< MAX_OVERLAYIMAGE
; nCount
++)
2760 himl
->nOvlIdx
[nCount
] = -1;
2762 DeleteObject (himl
->hbmImage
);
2764 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2765 1, himl
->uBitsPixel
, NULL
);
2767 if (himl
->hbmMask
) {
2768 DeleteObject (himl
->hbmMask
);
2770 CreateBitmap (himl
->cMaxImage
* himl
->cx
, himl
->cy
,
2778 /*************************************************************************
2779 * ImageList_SetImageCount [COMCTL32.81]
2781 * Resizes an image list to the specified number of images.
2784 * himl [I] handle to image list
2785 * iImageCount [I] number of images in the image list
2793 ImageList_SetImageCount (HIMAGELIST himl
, INT iImageCount
)
2795 HDC hdcImageList
, hdcBitmap
;
2796 HBITMAP hbmNewBitmap
;
2797 INT nNewCount
, nCopyCount
;
2801 if (himl
->cCurImage
>= iImageCount
)
2803 if (himl
->cMaxImage
> iImageCount
)
2806 nNewCount
= iImageCount
+ himl
->cGrow
;
2807 nCopyCount
= min(himl
->cCurImage
, iImageCount
);
2809 hdcImageList
= CreateCompatibleDC (0);
2810 hdcBitmap
= CreateCompatibleDC (0);
2812 hbmNewBitmap
= CreateBitmap (nNewCount
* himl
->cx
, himl
->cy
,
2813 1, himl
->uBitsPixel
, NULL
);
2814 if (hbmNewBitmap
!= 0)
2816 SelectObject (hdcImageList
, himl
->hbmImage
);
2817 SelectObject (hdcBitmap
, hbmNewBitmap
);
2820 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2821 hdcImageList
, 0, 0, SRCCOPY
);
2823 /* delete 'empty' image space */
2824 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2825 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2826 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2827 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2829 DeleteObject (himl
->hbmImage
);
2830 himl
->hbmImage
= hbmNewBitmap
;
2833 ERR("Could not create new image bitmap !\n");
2837 hbmNewBitmap
= CreateBitmap (nNewCount
* himl
->cx
, himl
->cy
,
2839 if (hbmNewBitmap
!= 0)
2841 SelectObject (hdcImageList
, himl
->hbmMask
);
2842 SelectObject (hdcBitmap
, hbmNewBitmap
);
2845 BitBlt (hdcBitmap
, 0, 0, nCopyCount
* himl
->cx
, himl
->cy
,
2846 hdcImageList
, 0, 0, SRCCOPY
);
2848 /* delete 'empty' image space */
2849 SetBkColor (hdcBitmap
, RGB(255, 255, 255));
2850 SetTextColor (hdcBitmap
, RGB(0, 0, 0));
2851 PatBlt (hdcBitmap
, nCopyCount
* himl
->cx
, 0,
2852 (nNewCount
- nCopyCount
) * himl
->cx
, himl
->cy
, BLACKNESS
);
2854 DeleteObject (himl
->hbmMask
);
2855 himl
->hbmMask
= hbmNewBitmap
;
2858 ERR("Could not create new mask bitmap!\n");
2861 DeleteDC (hdcImageList
);
2862 DeleteDC (hdcBitmap
);
2864 /* Update max image count and current image count */
2865 himl
->cMaxImage
= nNewCount
;
2866 if (himl
->cCurImage
> nCopyCount
)
2867 himl
->cCurImage
= nCopyCount
;
2873 /*************************************************************************
2874 * ImageList_SetOverlayImage [COMCTL32.82]
2876 * Assigns an overlay mask index to an existing image in an image list.
2879 * himl [I] handle to image list
2880 * iImage [I] image index
2881 * iOverlay [I] overlay mask index
2889 ImageList_SetOverlayImage (HIMAGELIST himl
, INT iImage
, INT iOverlay
)
2893 if ((iOverlay
< 1) || (iOverlay
> MAX_OVERLAYIMAGE
))
2895 if ((iImage
!=-1) && ((iImage
< 0) || (iImage
> himl
->cCurImage
)))
2897 himl
->nOvlIdx
[iOverlay
- 1] = iImage
;
2903 /* helper for ImageList_Write - write bitmap to pstm
2904 * currently everything is written as 24 bit RGB, except masks
2907 _write_bitmap(HBITMAP hBitmap
, LPSTREAM pstm
, int cx
, int cy
)
2909 LPBITMAPFILEHEADER bmfh
;
2910 LPBITMAPINFOHEADER bmih
;
2911 LPBYTE data
, lpBits
, lpBitsOrg
;
2913 INT bitCount
, sizeImage
, offBits
, totalSize
;
2914 INT nwidth
, nheight
, nsizeImage
, icount
;
2916 BOOL result
= FALSE
;
2920 GetObjectA(hBitmap
, sizeof(BITMAP
), (LPVOID
)&bm
);
2922 /* XXX is this always correct? */
2923 icount
= bm
.bmWidth
/ cx
;
2925 nheight
= cy
* ((icount
+3)>>2);
2927 bitCount
= bm
.bmBitsPixel
== 1 ? 1 : 24;
2928 sizeImage
= ((((bm
.bmWidth
* bitCount
)+31) & ~31) >> 3) * bm
.bmHeight
;
2929 nsizeImage
= ((((nwidth
* bitCount
)+31) & ~31) >> 3) * nheight
;
2931 totalSize
= sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
);
2933 totalSize
+= (1 << bitCount
) * sizeof(RGBQUAD
);
2934 offBits
= totalSize
;
2935 totalSize
+= nsizeImage
;
2937 data
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, totalSize
);
2938 bmfh
= (LPBITMAPFILEHEADER
)data
;
2939 bmih
= (LPBITMAPINFOHEADER
)(data
+ sizeof(BITMAPFILEHEADER
));
2940 lpBits
= data
+ offBits
;
2942 /* setup BITMAPFILEHEADER */
2943 bmfh
->bfType
= (('M' << 8) | 'B');
2945 bmfh
->bfReserved1
= 0;
2946 bmfh
->bfReserved2
= 0;
2947 bmfh
->bfOffBits
= offBits
;
2949 /* setup BITMAPINFOHEADER */
2950 bmih
->biSize
= sizeof(BITMAPINFOHEADER
);
2951 bmih
->biWidth
= bm
.bmWidth
;
2952 bmih
->biHeight
= bm
.bmHeight
;
2954 bmih
->biBitCount
= bitCount
;
2955 bmih
->biCompression
= BI_RGB
;
2956 bmih
->biSizeImage
= nsizeImage
;
2957 bmih
->biXPelsPerMeter
= 0;
2958 bmih
->biYPelsPerMeter
= 0;
2959 bmih
->biClrUsed
= 0;
2960 bmih
->biClrImportant
= 0;
2962 lpBitsOrg
= (LPBYTE
)LocalAlloc(LMEM_ZEROINIT
, nsizeImage
);
2963 if(!GetDIBits(xdc
, hBitmap
, 0, bm
.bmHeight
, lpBitsOrg
,
2964 (BITMAPINFO
*)bmih
, DIB_RGB_COLORS
))
2968 int obpl
= (((bm
.bmWidth
*bitCount
+31) & ~31)>>3);
2969 int nbpl
= (((nwidth
*bitCount
+31) & ~31)>>3);
2971 for(i
= 0; i
< nheight
; i
++) {
2972 int ooff
= ((nheight
-1-i
)%cy
) * obpl
+ ((i
/cy
) * nbpl
);
2973 int noff
= (nbpl
* (nheight
-1-i
));
2974 memcpy(lpBits
+ noff
, lpBitsOrg
+ ooff
, nbpl
);
2978 bmih
->biWidth
= nwidth
;
2979 bmih
->biHeight
= nheight
;
2983 LPBITMAPINFO inf
= (LPBITMAPINFO
)bmih
;
2984 inf
->bmiColors
[0].rgbRed
= inf
->bmiColors
[0].rgbGreen
= inf
->bmiColors
[0].rgbBlue
= 0;
2985 inf
->bmiColors
[1].rgbRed
= inf
->bmiColors
[1].rgbGreen
= inf
->bmiColors
[1].rgbBlue
= 0xff;
2988 if(!SUCCEEDED(IStream_Write(pstm
, data
, totalSize
, NULL
)))
2995 LocalFree((HLOCAL
)lpBitsOrg
);
3001 /*************************************************************************
3002 * ImageList_Write [COMCTL32.83]
3004 * Writes an image list to a stream.
3007 * himl [I] handle to image list
3008 * pstm [O] Pointer to a stream.
3019 ImageList_Write (HIMAGELIST himl
, LPSTREAM pstm
)
3027 ilHead
.usMagic
= (('L' << 8) | 'I');
3028 ilHead
.usVersion
= 0x101;
3029 ilHead
.cCurImage
= himl
->cCurImage
;
3030 ilHead
.cMaxImage
= himl
->cMaxImage
;
3031 ilHead
.cGrow
= himl
->cGrow
;
3032 ilHead
.cx
= himl
->cx
;
3033 ilHead
.cy
= himl
->cy
;
3034 ilHead
.bkcolor
= himl
->clrBk
;
3035 ilHead
.flags
= himl
->flags
;
3036 for(i
= 0; i
< 4; i
++) {
3037 ilHead
.ovls
[i
] = himl
->nOvlIdx
[i
];
3040 if(!SUCCEEDED(IStream_Write(pstm
, &ilHead
, sizeof(ILHEAD
), NULL
)))
3043 /* write the bitmap */
3044 if(!_write_bitmap(himl
->hbmImage
, pstm
, himl
->cx
, himl
->cy
))
3047 /* write the mask if we have one */
3048 if(himl
->flags
& ILC_MASK
) {
3049 if(!_write_bitmap(himl
->hbmMask
, pstm
, himl
->cx
, himl
->cy
))