2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
6 * 2001 Michael Stefaniuc
7 * 2001 Charles Loep for CodeWeavers
10 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
11 * - Fix ImageList_GetIcon.
12 * - Fix ImageList_SetFilter (undocumented).
13 * BTW does anybody know anything about this function???
14 * - It removes 12 Bytes from the stack (3 Parameters).
15 * - First parameter SHOULD be a HIMAGELIST.
16 * - Second parameter COULD be an index?????
17 * - Third parameter.... ?????????????????????
20 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
21 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
22 * partially implemented, the functions mentioned above will be
23 * limited in functionality too.
25 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
26 * is the offset of the image position relative to the actual mouse pointer
27 * position. However the Hotspot passed to SetDragCursorImage is the
28 * offset of the mouse messages sent to the application...
35 #include "wine/obj_base.h"
36 #include "wine/obj_storage.h"
38 #include "imagelist.h"
39 #include "debugtools.h"
41 DEFAULT_DEBUG_CHANNEL(imagelist);
44 #define MAX_OVERLAYIMAGE 15
46 /* internal image list data used for Drag & Drop operations */
51 /* position of the drag image relative to the window */
54 /* offset of the hotspot relative to the origin of the image */
57 /* is the drag image visible */
59 /* saved background */
64 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
68 /*************************************************************************
69 * IMAGELIST_InternalExpandBitmaps [Internal]
71 * Expands the bitmaps of an image list by the given number of images.
74 * himl [I] handle to image list
75 * nImageCount [I] number of images to add
81 * This function can NOT be used to reduce the number of images.
84 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
86 HDC hdcImageList, hdcBitmap;
88 INT nNewWidth, nNewCount;
90 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
94 if (cy == 0) cy = himl->cy;
95 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
96 nNewWidth = nNewCount * himl->cx;
98 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
99 hdcImageList = CreateCompatibleDC (0);
100 hdcBitmap = CreateCompatibleDC (0);
103 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
104 if (hbmNewBitmap == 0)
105 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
107 SelectObject (hdcImageList, himl->hbmImage);
108 SelectObject (hdcBitmap, hbmNewBitmap);
109 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
110 hdcImageList, 0, 0, SRCCOPY);
112 DeleteObject (himl->hbmImage);
113 himl->hbmImage = hbmNewBitmap;
117 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
119 if (hbmNewBitmap == 0)
120 ERR("creating new mask bitmap!\n");
122 SelectObject (hdcImageList, himl->hbmMask);
123 SelectObject (hdcBitmap, hbmNewBitmap);
124 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
125 hdcImageList, 0, 0, SRCCOPY);
126 DeleteObject (himl->hbmMask);
127 himl->hbmMask = hbmNewBitmap;
130 himl->cMaxImage = nNewCount;
132 DeleteDC (hdcImageList);
133 DeleteDC (hdcBitmap);
137 /*************************************************************************
138 * IMAGELIST_InternalDraw [Internal]
140 * Draws the image in the ImageList (without the mask)
143 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
144 * cx [I] the width of the image to display
145 * cy............[I] the height of the image to display
151 * This function is used by ImageList_DrawIndirect, when it is
152 * required to draw only the Image (without the mask) to the screen.
154 * Blending and Overlays styles are accomplished by another function
157 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
162 hImageDC = CreateCompatibleDC(0);
163 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
164 BitBlt(pimldp->hdcDst,
165 pimldp->x, pimldp->y, cx, cy,
167 pimldp->himl->cx * pimldp->i, 0,
170 SelectObject(hImageDC, hOldBitmap);
175 /*************************************************************************
176 * IMAGELIST_InternalDrawMask [Internal]
178 * Draws the image in the ImageList with the mask
181 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
182 * cx [I] the width of the image to display
183 * cy............[I] the height of the image to display
189 * This function is used by ImageList_DrawIndirect, when it is
190 * required to draw the Image with the mask to the screen.
192 * Blending and Overlays styles are accomplished by another function.
195 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
197 BOOL bUseCustomBackground, bBlendFlag;
198 HBRUSH hBrush, hOldBrush;
199 HDC hMaskDC, hImageDC;
200 HBITMAP hOldBitmapImage, hOldBitmapMask;
201 HIMAGELIST himlLocal = pimldp->himl;
202 COLORREF oldBkColor, oldFgColor;
203 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
206 * We need a dc and bitmap to draw on that is
209 HDC hOffScreenDC = 0;
210 HBITMAP hOffScreenBmp = 0;
212 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
213 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
215 hImageDC = CreateCompatibleDC(0);
216 hMaskDC = CreateCompatibleDC(0);
218 /* Create a compatible DC. */
219 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
223 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
226 SelectObject( hOffScreenDC, hOffScreenBmp );
233 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
234 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
237 * Get a copy of the image for the masking operations.
238 * We will use the copy, and this dc for all the various
239 * blitting, and then do one final blit to the screen dc.
240 * This should clean up most of the flickering.
242 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
246 * Draw the Background for the appropriate Styles
248 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
252 hBrush = CreateSolidBrush (himlLocal->clrBk);
253 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
255 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
257 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
261 * Draw Image Transparently over the current background
263 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
264 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
266 * To obtain a transparent look, background color should be set
267 * to white and foreground color to black when blting the
271 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
272 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
274 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
277 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
283 * Draw the image when no Background is specified
285 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
287 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
288 himlLocal->cx * pimldp->i, 0, SRCCOPY);
291 * Draw the mask with or without a background
293 else if(fStyle & ILD_MASK)
295 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
296 0, bUseCustomBackground ? SRCCOPY : SRCAND);
300 * Blit the bitmap to the screen now.
302 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
303 hOffScreenDC, 0, 0, SRCCOPY);
306 SelectObject(hImageDC, hOldBitmapImage);
307 SelectObject(hMaskDC, hOldBitmapMask);
314 DeleteDC( hOffScreenDC );
315 DeleteObject( hOffScreenBmp );
320 /*************************************************************************
321 * IMAGELIST_InternalDrawBlend [Internal]
323 * Draws the Blend over the current image
326 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
327 * cx [I] the width of the image to display
328 * cy............[I] the height of the image to display
334 * This functions is used by ImageList_DrawIndirect, when it is
335 * required to add the blend to the current image.
339 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
342 HDC hBlendMaskDC,hMaskDC;
343 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
344 HBITMAP hBlendMaskBitmap, hOldBitmap;
345 COLORREF clrBlend, OldTextColor, OldBkColor;
346 HIMAGELIST himlLocal = pimldp->himl;
348 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
349 if (!(pimldp->rgbFg == CLR_DEFAULT))
351 clrBlend = pimldp->rgbFg;
353 /* Create the blend Mask
355 hBlendMaskDC = CreateCompatibleDC(0);
356 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
357 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
359 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
360 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
362 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
363 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
364 SelectObject(hBlendMaskDC, hOldBrush);
366 /* Modify the blend mask if an Image Mask exist
368 if(pimldp->himl->hbmMask != 0)
370 HBITMAP hOldMaskBitmap;
371 hMaskDC = CreateCompatibleDC(0);
372 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
377 himlLocal->cx * pimldp->i,0,
378 0x220326); /* NOTSRCAND */
386 SelectObject(hMaskDC, hOldMaskBitmap);
390 /* Apply blend to the current image given the BlendMask
392 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
393 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
394 hBlendColorBrush = CreateSolidBrush(clrBlend);
395 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
397 BitBlt (pimldp->hdcDst,
398 pimldp->x, pimldp->y, cx, cy,
401 0xB8074A); /* PSDPxax */
403 SelectObject(pimldp->hdcDst, hOldBrush);
404 SetTextColor(pimldp->hdcDst, OldTextColor);
405 SetBkColor(pimldp->hdcDst, OldBkColor);
406 SelectObject(hBlendMaskDC, hOldBitmap);
407 DeleteDC(hBlendMaskDC);
408 DeleteObject(hBlendMaskBitmap);
409 DeleteObject(hBlendColorBrush);
412 /*************************************************************************
413 * IMAGELIST_InternalDrawOverlay [Internal]
415 * Draws the overlay image
418 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
419 * cx [I] the width of the image to display
420 * cy............[I] the height of the image to display
426 * This functions is used by ImageList_DrawIndirect, when it is
427 * required to draw the overlay
432 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
438 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
439 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
441 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
442 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
444 hImageDC = CreateCompatibleDC(0);
445 if (pimldp->himl->hbmMask)
447 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
448 pimldp->himl->hbmMask);
450 BitBlt (pimldp->hdcDst,
451 pimldp->x, pimldp->y, cx, cy,
452 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
455 SelectObject(hImageDC, hOldBitmap);
457 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
458 pimldp->himl->hbmImage);
460 BitBlt (pimldp->hdcDst,
461 pimldp->x, pimldp->y, cx, cy,
463 pimldp->himl->cx * nOvlIdx, 0,
466 SelectObject(hImageDC, hOldBitmap);
473 /*************************************************************************
474 * ImageList_Add [COMCTL32.40]
476 * Add an image or images to an image list.
479 * himl [I] handle to image list
480 * hbmImage [I] handle to image bitmap
481 * hbmMask [I] handle to mask bitmap
484 * Success: Index of the first new image.
489 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
491 HDC hdcImage, hdcBitmap;
492 INT nFirstIndex, nImageCount;
495 HBITMAP hOldBitmapImage, hOldBitmap;
497 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
498 if (!himl || !hbmImage)
501 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
502 nImageCount = bmp.bmWidth / himl->cx;
504 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
506 nStartX = himl->cCurImage * himl->cx;
508 hdcImage = CreateCompatibleDC(0);
509 hdcBitmap = CreateCompatibleDC(0);
511 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
512 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
514 /* Copy result to the imagelist
516 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
517 hdcBitmap, 0, 0, SRCCOPY);
521 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
523 hdcMask = CreateCompatibleDC (0);
524 hdcTemp = CreateCompatibleDC(0);
525 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
526 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
529 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
534 SelectObject(hdcTemp, hOldBitmapTemp);
537 /* Remove the background from the image
540 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
543 0x220326); /* NOTSRCAND */
545 SelectObject(hdcMask, hOldBitmapMask);
549 SelectObject(hdcImage, hOldBitmapImage);
550 SelectObject(hdcBitmap, hOldBitmap);
554 nFirstIndex = himl->cCurImage;
555 himl->cCurImage += nImageCount;
561 /*************************************************************************
562 * ImageList_AddIcon [COMCTL32.41]
564 * Adds an icon to an image list.
567 * himl [I] handle to image list
568 * hIcon [I] handle to icon
571 * Success: index of the new image
576 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
578 return ImageList_ReplaceIcon (himl, -1, hIcon);
582 /*************************************************************************
583 * ImageList_AddMasked [COMCTL32.42]
585 * Adds an image or images to an image list and creates a mask from the
586 * specified bitmap using the mask color.
589 * himl [I] handle to image list.
590 * hBitmap [I] handle to bitmap
591 * clrMask [I] mask color.
594 * Success: Index of the first new image.
599 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
601 HDC hdcImage, hdcMask, hdcBitmap;
602 INT nIndex, nImageCount, nMaskXOffset=0;
604 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
605 HBITMAP hMaskBitmap=0;
608 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
612 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
615 nImageCount = bmp.bmWidth / himl->cx;
617 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
619 nIndex = himl->cCurImage;
620 himl->cCurImage += nImageCount;
622 hdcMask = CreateCompatibleDC (0);
623 hdcImage = CreateCompatibleDC(0);
624 hdcBitmap = CreateCompatibleDC(0);
627 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
628 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
631 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
632 nMaskXOffset = nIndex * himl->cx;
637 Create a temp Mask so we can remove the background of
638 the Image (Windows does this even if there is no mask)
640 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
641 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
644 /* create monochrome image to the mask bitmap */
645 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
646 GetPixel (hdcBitmap, 0, 0);
647 SetBkColor (hdcBitmap, bkColor);
649 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
653 SetBkColor(hdcBitmap, RGB(255,255,255));
654 /*Remove the background from the image
657 WINDOWS BUG ALERT!!!!!!
658 The statement below should not be done in common practice
659 but this is how ImageList_AddMasked works in Windows.
660 It overwrites the original bitmap passed, this was discovered
661 by using the same bitmap to iterate the different styles
662 on windows where it failed (BUT ImageList_Add is OK)
663 This is here in case some apps rely on this bug
666 0, 0, bmp.bmWidth, bmp.bmHeight,
669 0x220326); /* NOTSRCAND */
670 /* Copy result to the imagelist
673 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
679 SelectObject(hdcMask,hOldBitmapMask);
680 SelectObject(hdcImage, hOldBitmapImage);
681 SelectObject(hdcBitmap, hOldBitmap);
687 DeleteObject(hMaskBitmap);
694 /*************************************************************************
695 * ImageList_BeginDrag [COMCTL32.43]
697 * Creates a temporary image list that contains one image. It will be used
701 * himlTrack [I] handle to the source image list
702 * iTrack [I] index of the drag image in the source image list
703 * dxHotspot [I] X position of the hot spot of the drag image
704 * dyHotspot [I] Y position of the hot spot of the drag image
712 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
713 INT dxHotspot, INT dyHotspot)
718 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
719 dxHotspot, dyHotspot);
721 if (himlTrack == NULL)
724 if (InternalDrag.himl)
725 ImageList_EndDrag ();
730 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
731 if (InternalDrag.himl == NULL) {
732 ERR("Error creating drag image list!\n");
736 InternalDrag.dxHotspot = dxHotspot;
737 InternalDrag.dyHotspot = dyHotspot;
739 hdcSrc = CreateCompatibleDC (0);
740 hdcDst = CreateCompatibleDC (0);
743 SelectObject (hdcSrc, himlTrack->hbmImage);
744 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
745 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
748 SelectObject (hdcSrc, himlTrack->hbmMask);
749 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
750 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
755 InternalDrag.himl->cCurImage = 1;
756 InternalDrag.bHSPending = TRUE;
762 /*************************************************************************
763 * ImageList_Copy [COMCTL32.44]
765 * Copies an image of the source image list to an image of the
766 * destination image list. Images can be copied or swapped.
769 * himlDst [I] handle to the destination image list
770 * iDst [I] destination image index.
771 * himlSrc [I] handle to the source image list
772 * iSrc [I] source image index
773 * uFlags [I] flags for the copy operation
780 * Copying from one image list to another is possible. The original
781 * implementation just copies or swaps within one image list.
782 * Could this feature become a bug??? ;-)
786 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
787 INT iSrc, INT uFlags)
791 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
793 if ((himlSrc == NULL) || (himlDst == NULL))
795 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
797 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
800 hdcSrc = CreateCompatibleDC (0);
801 if (himlDst == himlSrc)
804 hdcDst = CreateCompatibleDC (0);
806 if (uFlags & ILCF_SWAP) {
808 HBITMAP hbmTempImage, hbmTempMask;
810 /* create temporary bitmaps */
811 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
812 himlSrc->uBitsPixel, NULL);
813 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
816 /* copy (and stretch) destination to temporary bitmaps.(save) */
818 SelectObject (hdcSrc, himlDst->hbmImage);
819 SelectObject (hdcDst, hbmTempImage);
820 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
821 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
824 SelectObject (hdcSrc, himlDst->hbmMask);
825 SelectObject (hdcDst, hbmTempMask);
826 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
827 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
830 /* copy (and stretch) source to destination */
832 SelectObject (hdcSrc, himlSrc->hbmImage);
833 SelectObject (hdcDst, himlDst->hbmImage);
834 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
835 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
838 SelectObject (hdcSrc, himlSrc->hbmMask);
839 SelectObject (hdcDst, himlDst->hbmMask);
840 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
841 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
844 /* copy (without stretching) temporary bitmaps to source (restore) */
846 SelectObject (hdcSrc, hbmTempImage);
847 SelectObject (hdcDst, himlSrc->hbmImage);
848 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
849 hdcSrc, 0, 0, SRCCOPY);
851 SelectObject (hdcSrc, hbmTempMask);
852 SelectObject (hdcDst, himlSrc->hbmMask);
853 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
854 hdcSrc, 0, 0, SRCCOPY);
856 /* delete temporary bitmaps */
857 DeleteObject (hbmTempMask);
858 DeleteObject (hbmTempImage);
862 SelectObject (hdcSrc, himlSrc->hbmImage);
863 if (himlSrc == himlDst)
866 SelectObject (hdcDst, himlDst->hbmImage);
867 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
868 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
872 SelectObject (hdcSrc, himlSrc->hbmMask);
873 if (himlSrc == himlDst)
876 SelectObject (hdcDst, himlDst->hbmMask);
877 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
878 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
883 if (himlSrc != himlDst)
890 /*************************************************************************
891 * ImageList_Create [COMCTL32.45] Creates a new image list.
894 * cx [I] image height
896 * flags [I] creation flags
897 * cInitial [I] initial number of images in the image list
898 * cGrow [I] number of images by which image list grows
901 * Success: Handle to the created image list
906 ImageList_Create (INT cx, INT cy, UINT flags,
907 INT cInitial, INT cGrow)
913 static WORD aBitBlend25[] =
914 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
916 static WORD aBitBlend50[] =
917 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
919 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
921 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
928 himl->cMaxImage = cInitial + cGrow;
929 himl->cInitial = cInitial;
932 himl->clrFg = CLR_DEFAULT;
933 himl->clrBk = CLR_NONE;
935 /* initialize overlay mask indices */
936 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
937 himl->nOvlIdx[nCount] = -1;
939 hdc = CreateCompatibleDC (0);
940 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
943 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
945 if (himl->cMaxImage > 0) {
947 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
948 1, himl->uBitsPixel, NULL);
949 if (himl->hbmImage == 0) {
950 ERR("Error creating image bitmap!\n");
957 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
958 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
960 if (himl->hbmMask == 0) {
961 ERR("Error creating mask bitmap!\n");
963 DeleteObject (himl->hbmImage);
970 /* create blending brushes */
971 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
972 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
973 DeleteObject (hbmTemp);
975 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
976 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
977 DeleteObject (hbmTemp);
979 TRACE("created imagelist %p\n", himl);
984 /*************************************************************************
985 * ImageList_Destroy [COMCTL32.46]
987 * Destroys an image list.
990 * himl [I] handle to image list
998 ImageList_Destroy (HIMAGELIST himl)
1003 /* delete image bitmaps */
1005 DeleteObject (himl->hbmImage);
1007 DeleteObject (himl->hbmMask);
1009 /* delete blending brushes */
1010 if (himl->hbrBlend25)
1011 DeleteObject (himl->hbrBlend25);
1012 if (himl->hbrBlend50)
1013 DeleteObject (himl->hbrBlend50);
1015 COMCTL32_Free (himl);
1021 /*************************************************************************
1022 * ImageList_DragEnter [COMCTL32.47]
1024 * Locks window update and displays the drag image at the given position.
1027 * hwndLock [I] handle of the window that owns the drag image.
1028 * x [I] X position of the drag image.
1029 * y [I] Y position of the drag image.
1036 * The position of the drag image is relative to the window, not
1041 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1043 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1045 if (InternalDrag.himl == NULL)
1049 InternalDrag.hwnd = hwndLock;
1051 InternalDrag.hwnd = GetDesktopWindow ();
1056 /* draw the drag image and save the background */
1057 if (!ImageList_DragShowNolock(TRUE)) {
1065 /*************************************************************************
1066 * ImageList_DragLeave [COMCTL32.48]
1068 * Unlocks window update and hides the drag image.
1071 * hwndLock [I] handle of the window that owns the drag image.
1079 ImageList_DragLeave (HWND hwndLock)
1081 /* As we don't save drag info in the window this can lead to problems if
1082 an app does not supply the same window as DragEnter */
1084 InternalDrag.hwnd = hwndLock;
1086 InternalDrag.hwnd = GetDesktopWindow (); */
1088 hwndLock = GetDesktopWindow();
1089 if(InternalDrag.hwnd != hwndLock)
1090 FIXME("DragLeave hWnd != DragEnter hWnd\n");
1092 ImageList_DragShowNolock (FALSE);
1098 /*************************************************************************
1099 * ImageList_DragMove [COMCTL32.49]
1101 * Moves the drag image.
1104 * x [I] X position of the drag image.
1105 * y [I] Y position of the drag image.
1112 * The position of the drag image is relative to the window, not
1116 * The drag image should be drawn semitransparent.
1120 ImageList_DragMove (INT x, INT y)
1122 TRACE("(x=%d y=%d)\n", x, y);
1124 if (!InternalDrag.himl) {
1128 /* draw/update the drag image */
1129 if (InternalDrag.bShow) {
1133 HBITMAP hbmOffScreen;
1134 INT origNewX, origNewY;
1135 INT origOldX, origOldY;
1136 INT origRegX, origRegY;
1137 INT sizeRegX, sizeRegY;
1140 /* calculate the update region */
1141 origNewX = x - InternalDrag.dxHotspot;
1142 origNewY = y - InternalDrag.dyHotspot;
1143 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1144 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1145 origRegX = min(origNewX, origOldX);
1146 origRegY = min(origNewY, origOldY);
1147 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1148 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1150 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1151 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1152 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1153 hdcBg = CreateCompatibleDC(hdcDrag);
1155 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1156 SelectObject(hdcOffScreen, hbmOffScreen);
1157 SelectObject(hdcBg, InternalDrag.hbmBg);
1159 /* get the actual background of the update region */
1160 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1161 origRegX, origRegY, SRCCOPY);
1162 /* erase the old image */
1163 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1164 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1166 /* save the background */
1167 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1168 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1169 /* draw the image */
1170 /* FIXME: image should be drawn semitransparent */
1171 ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1172 origNewY - origRegY, ILD_NORMAL);
1173 /* draw the update region to the screen */
1174 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1175 hdcOffScreen, 0, 0, SRCCOPY);
1178 DeleteDC(hdcOffScreen);
1179 DeleteObject(hbmOffScreen);
1180 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1183 /* update the image position */
1191 /*************************************************************************
1192 * ImageList_DragShowNolock [COMCTL32.50]
1194 * Shows or hides the drag image.
1197 * bShow [I] TRUE shows the drag image, FALSE hides it.
1204 * The drag image should be drawn semitransparent.
1208 ImageList_DragShowNolock (BOOL bShow)
1214 TRACE("bShow=0x%X!\n", bShow);
1216 /* DragImage is already visible/hidden */
1217 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1221 /* position of the origin of the DragImage */
1222 x = InternalDrag.x - InternalDrag.dxHotspot;
1223 y = InternalDrag.y - InternalDrag.dyHotspot;
1225 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1226 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1231 hdcBg = CreateCompatibleDC(hdcDrag);
1232 if (!InternalDrag.hbmBg) {
1233 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1234 InternalDrag.himl->cx, InternalDrag.himl->cy);
1236 SelectObject(hdcBg, InternalDrag.hbmBg);
1239 /* save the background */
1240 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1241 hdcDrag, x, y, SRCCOPY);
1242 /* show the image */
1243 /* FIXME: this should be drawn semitransparent */
1244 ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1246 /* hide the image */
1247 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1248 hdcBg, 0, 0, SRCCOPY);
1251 InternalDrag.bShow = !InternalDrag.bShow;
1254 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1259 /*************************************************************************
1260 * ImageList_Draw [COMCTL32.51] Draws an image.
1263 * himl [I] handle to image list
1265 * hdc [I] handle to device context
1268 * fStyle [I] drawing flags
1275 * Calls ImageList_DrawIndirect.
1278 * ImageList_DrawIndirect.
1282 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1283 INT x, INT y, UINT fStyle)
1285 IMAGELISTDRAWPARAMS imldp;
1287 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1297 imldp.rgbBk = CLR_DEFAULT;
1298 imldp.rgbFg = CLR_DEFAULT;
1299 imldp.fStyle = fStyle;
1302 return ImageList_DrawIndirect (&imldp);
1306 /*************************************************************************
1307 * ImageList_DrawEx [COMCTL32.52]
1309 * Draws an image and allows to use extended drawing features.
1312 * himl [I] handle to image list
1314 * hdc [I] handle to device context
1317 * xOffs [I] X offset
1318 * yOffs [I] Y offset
1319 * rgbBk [I] background color
1320 * rgbFg [I] foreground color
1321 * fStyle [I] drawing flags
1328 * Calls ImageList_DrawIndirect.
1331 * ImageList_DrawIndirect.
1335 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1336 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1339 IMAGELISTDRAWPARAMS imldp;
1341 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1351 imldp.rgbBk = rgbBk;
1352 imldp.rgbFg = rgbFg;
1353 imldp.fStyle = fStyle;
1356 return ImageList_DrawIndirect (&imldp);
1360 /*************************************************************************
1361 * ImageList_DrawIndirect [COMCTL32.53]
1363 * Draws an image using ...
1366 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1374 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1378 Do some Error Checking
1382 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1384 if (pimldp->himl == NULL)
1386 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1387 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1391 Get the Height and Width to display
1393 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1394 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1398 if(pimldp->himl->hbmMask != 0)
1400 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1404 IMAGELIST_InternalDraw(pimldp, cx, cy);
1407 Apply the blend if needed to the Image
1409 if((pimldp->fStyle & ILD_BLEND50)
1410 || (pimldp->fStyle & ILD_BLEND25))
1412 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1415 Apply the Overlay if needed
1417 if (pimldp->fStyle & ILD_OVERLAYMASK)
1419 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1426 /*************************************************************************
1427 * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
1430 * himlSrc [I] source image list handle
1433 * Success: Handle of duplicated image list.
1438 ImageList_Duplicate (HIMAGELIST himlSrc)
1443 if (himlSrc == NULL) {
1444 ERR("Invalid image list handle!\n");
1448 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1449 himlSrc->cInitial, himlSrc->cGrow);
1453 hdcSrc = CreateCompatibleDC (0);
1454 hdcDst = CreateCompatibleDC (0);
1455 SelectObject (hdcSrc, himlSrc->hbmImage);
1456 SelectObject (hdcDst, himlDst->hbmImage);
1457 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1458 hdcSrc, 0, 0, SRCCOPY);
1460 if (himlDst->hbmMask)
1462 SelectObject (hdcSrc, himlSrc->hbmMask);
1463 SelectObject (hdcDst, himlDst->hbmMask);
1464 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1465 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1471 himlDst->cCurImage = himlSrc->cCurImage;
1472 himlDst->cMaxImage = himlSrc->cMaxImage;
1478 /*************************************************************************
1479 * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
1481 * Finishes a drag operation.
1492 ImageList_EndDrag (void)
1494 /* cleanup the InternalDrag struct */
1495 InternalDrag.hwnd = 0;
1496 ImageList_Destroy (InternalDrag.himl);
1497 InternalDrag.himl = 0;
1500 InternalDrag.dxHotspot = 0;
1501 InternalDrag.dyHotspot = 0;
1502 InternalDrag.bShow = FALSE;
1503 DeleteObject(InternalDrag.hbmBg);
1504 InternalDrag.hbmBg = 0;
1505 InternalDrag.bHSPending = FALSE;
1511 /*************************************************************************
1512 * ImageList_GetBkColor [COMCTL32.56]
1514 * Returns the background color of an image list.
1517 * himl [I] Image list handle.
1520 * Success: background color
1525 ImageList_GetBkColor (HIMAGELIST himl)
1534 /*************************************************************************
1535 * ImageList_GetDragImage [COMCTL32.57]
1537 * Returns the handle to the internal drag image list.
1540 * ppt [O] Pointer to the drag position. Can be NULL.
1541 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1544 * Success: Handle of the drag image list.
1549 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1551 if (InternalDrag.himl) {
1553 ppt->x = InternalDrag.x;
1554 ppt->y = InternalDrag.y;
1557 pptHotspot->x = InternalDrag.dxHotspot;
1558 pptHotspot->y = InternalDrag.dyHotspot;
1560 return (InternalDrag.himl);
1567 /*************************************************************************
1568 * ImageList_GetFlags [COMCTL32.58]
1575 ImageList_GetFlags(HIMAGELIST himl)
1577 FIXME("(%p):empty stub\n", himl);
1582 /*************************************************************************
1583 * ImageList_GetIcon [COMCTL32.59]
1585 * Creates an icon from a masked image of an image list.
1588 * himl [I] handle to image list
1590 * flags [I] drawing style flags
1593 * Success: icon handle
1598 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1602 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1605 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1606 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1610 hdcSrc = CreateCompatibleDC(0);
1611 hdcDst = CreateCompatibleDC(0);
1614 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1617 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1618 if (himl->hbmMask) {
1619 SelectObject (hdcSrc, himl->hbmMask);
1620 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1621 hdcSrc, i * himl->cx, 0, SRCCOPY);
1624 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1627 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1628 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1629 SelectObject (hdcDst, ii.hbmColor);
1630 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1631 hdcSrc, i * himl->cx, 0, SRCCOPY);
1634 * CreateIconIndirect requires us to deselect the bitmaps from
1635 * the DCs before calling
1637 SelectObject(hdcSrc, hOldSrcBitmap);
1638 SelectObject(hdcDst, hOldDstBitmap);
1640 hIcon = CreateIconIndirect (&ii);
1644 DeleteObject (ii.hbmMask);
1645 DeleteObject (ii.hbmColor);
1651 /*************************************************************************
1652 * ImageList_GetIconSize [COMCTL32.60]
1654 * Retrieves the size of an image in an image list.
1657 * himl [I] handle to image list
1658 * cx [O] pointer to the image width.
1659 * cy [O] pointer to the image height.
1666 * All images in an image list have the same size.
1670 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1674 if ((himl->cx <= 0) || (himl->cy <= 0))
1686 /*************************************************************************
1687 * ImageList_GetImageCount [COMCTL32.61]
1689 * Returns the number of images in an image list.
1692 * himl [I] handle to image list
1695 * Success: Number of images.
1700 ImageList_GetImageCount (HIMAGELIST himl)
1705 return himl->cCurImage;
1709 /*************************************************************************
1710 * ImageList_GetImageInfo [COMCTL32.62]
1712 * Returns information about an image in an image list.
1715 * himl [I] handle to image list
1717 * pImageInfo [O] pointer to the image information
1725 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1727 if ((himl == NULL) || (pImageInfo == NULL))
1729 if ((i < 0) || (i >= himl->cCurImage))
1732 pImageInfo->hbmImage = himl->hbmImage;
1733 pImageInfo->hbmMask = himl->hbmMask;
1735 pImageInfo->rcImage.top = 0;
1736 pImageInfo->rcImage.bottom = himl->cy;
1737 pImageInfo->rcImage.left = i * himl->cx;
1738 pImageInfo->rcImage.right = (i+1) * himl->cx;
1744 /*************************************************************************
1745 * ImageList_GetImageRect [COMCTL32.63]
1747 * Retrieves the rectangle of the specified image in an image list.
1750 * himl [I] handle to image list
1752 * lpRect [O] pointer to the image rectangle
1759 * This is an UNDOCUMENTED function!!!
1763 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1765 if ((himl == NULL) || (lpRect == NULL))
1767 if ((i < 0) || (i >= himl->cCurImage))
1770 lpRect->left = i * himl->cx;
1772 lpRect->right = lpRect->left + himl->cx;
1773 lpRect->bottom = himl->cy;
1779 /*************************************************************************
1780 * ImageList_LoadImage [COMCTL32.64]
1781 * ImageList_LoadImageA [COMCTL32.65]
1783 * Creates an image list from a bitmap, icon or cursor.
1786 * hi [I] instance handle
1787 * lpbmp [I] name or id of the image
1788 * cx [I] width of each image
1789 * cGrow [I] number of images to expand
1790 * clrMask [I] mask color
1791 * uType [I] type of image to load
1792 * uFlags [I] loading flags
1795 * Success: handle to the loaded image list
1803 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1804 COLORREF clrMask, UINT uType, UINT uFlags)
1806 HIMAGELIST himl = NULL;
1810 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1812 ERR("Error loading image!\n");
1816 if (uType == IMAGE_BITMAP) {
1818 GetObjectA (handle, sizeof(BITMAP), &bmp);
1820 /* To match windows behavior, if cx is set to zero and
1821 the flag DI_DEFAULTSIZE is specified, cx becomes the
1822 system metric value for icons. If the flag is not specified
1823 the function sets the size to the height of the bitmap */
1826 if (uFlags & DI_DEFAULTSIZE)
1827 cx = GetSystemMetrics (SM_CXICON);
1832 nImageCount = bmp.bmWidth / cx;
1834 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1835 nImageCount, cGrow);
1836 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1838 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1842 GetIconInfo (handle, &ii);
1843 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1844 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1845 ILC_MASK | ILC_COLOR, 1, cGrow);
1846 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1847 DeleteObject (ii.hbmColor);
1848 DeleteObject (ii.hbmMask);
1851 DeleteObject (handle);
1857 /*************************************************************************
1858 * ImageList_LoadImageW [COMCTL32.66]
1860 * Creates an image list from a bitmap, icon or cursor.
1863 * hi [I] instance handle
1864 * lpbmp [I] name or id of the image
1865 * cx [I] width of each image
1866 * cGrow [I] number of images to expand
1867 * clrMask [I] mask color
1868 * uType [I] type of image to load
1869 * uFlags [I] loading flags
1872 * Success: handle to the loaded image list
1880 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1881 COLORREF clrMask, UINT uType, UINT uFlags)
1883 HIMAGELIST himl = NULL;
1887 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1889 ERR("Error loading image!\n");
1893 if (uType == IMAGE_BITMAP) {
1895 GetObjectA (handle, sizeof(BITMAP), &bmp);
1896 nImageCount = bmp.bmWidth / cx;
1898 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1899 nImageCount, cGrow);
1900 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1902 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1906 GetIconInfo (handle, &ii);
1907 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1908 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1909 ILC_MASK | ILC_COLOR, 1, cGrow);
1910 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1911 DeleteObject (ii.hbmColor);
1912 DeleteObject (ii.hbmMask);
1915 DeleteObject (handle);
1921 /*************************************************************************
1922 * ImageList_Merge [COMCTL32.67]
1924 * Creates a new image list that contains a merged image from the specified
1925 * images of both source image lists.
1928 * himl1 [I] handle to first image list
1929 * i1 [I] first image index
1930 * himl2 [I] handle to second image list
1931 * i2 [I] second image index
1932 * dx [I] X offset of the second image relative to the first.
1933 * dy [I] Y offset of the second image relative to the first.
1936 * Success: handle of the merged image list.
1941 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1944 HIMAGELIST himlDst = NULL;
1945 HDC hdcSrcImage, hdcDstImage;
1947 INT xOff1, yOff1, xOff2, yOff2;
1950 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1953 if ((himl1 == NULL) || (himl2 == NULL))
1957 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1958 ERR("Index 1 out of range! %d\n", i1);
1962 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1963 ERR("Index 2 out of range! %d\n", i2);
1968 cxDst = max (himl1->cx, dx + himl2->cx);
1973 cxDst = max (himl2->cx, himl1->cx - dx);
1978 cxDst = max (himl1->cx, himl2->cx);
1984 cyDst = max (himl1->cy, dy + himl2->cy);
1989 cyDst = max (himl2->cy, himl1->cy - dy);
1994 cyDst = max (himl1->cy, himl2->cy);
1999 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2002 hdcSrcImage = CreateCompatibleDC (0);
2003 hdcDstImage = CreateCompatibleDC (0);
2004 nX1 = i1 * himl1->cx;
2005 nX2 = i2 * himl2->cx;
2008 SelectObject (hdcSrcImage, himl1->hbmImage);
2009 SelectObject (hdcDstImage, himlDst->hbmImage);
2010 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2011 hdcSrcImage, 0, 0, BLACKNESS);
2012 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2013 hdcSrcImage, nX1, 0, SRCCOPY);
2015 SelectObject (hdcSrcImage, himl2->hbmMask);
2016 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2017 hdcSrcImage, nX2, 0, SRCAND);
2019 SelectObject (hdcSrcImage, himl2->hbmImage);
2020 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2021 hdcSrcImage, nX2, 0, SRCPAINT);
2024 SelectObject (hdcSrcImage, himl1->hbmMask);
2025 SelectObject (hdcDstImage, himlDst->hbmMask);
2026 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2027 hdcSrcImage, 0, 0, WHITENESS);
2028 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2029 hdcSrcImage, nX1, 0, SRCCOPY);
2031 SelectObject (hdcSrcImage, himl2->hbmMask);
2032 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2033 hdcSrcImage, nX2, 0, SRCAND);
2035 DeleteDC (hdcSrcImage);
2036 DeleteDC (hdcDstImage);
2037 himlDst->cCurImage = 1;
2044 /* helper for _read_bitmap currently unused */
2046 static int may_use_dibsection(HDC hdc) {
2047 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2052 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2056 /* helper for ImageList_Read, see comments below */
2057 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2059 BITMAPFILEHEADER bmfh;
2060 BITMAPINFOHEADER bmih;
2061 int bitsperpixel,palspace,longsperline,width,height;
2062 LPBITMAPINFOHEADER bmihc = NULL;
2064 HBITMAP hbitmap = 0;
2065 LPBYTE bits = NULL,nbits = NULL;
2066 int nbytesperline,bytesperline;
2068 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
2069 (bmfh.bfType != (('M'<<8)|'B')) ||
2070 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
2071 (bmih.biSize != sizeof(bmih))
2075 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2076 if (bitsperpixel<=8)
2077 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2080 width = bmih.biWidth;
2081 height = bmih.biHeight;
2082 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2083 memcpy(bmihc,&bmih,sizeof(bmih));
2084 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
2085 bmihc->biSizeImage = (longsperline*height)<<2;
2087 /* read the palette right after the end of the bitmapinfoheader */
2089 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2093 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2094 if ((bitsperpixel>1) &&
2095 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2097 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2100 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2106 int i,nwidth,nheight;
2108 nwidth = width*(height/cy);
2111 if (bitsperpixel==1)
2112 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2114 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2116 /* Might be a bit excessive memory use here */
2117 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2118 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2119 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2122 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2123 /* Do not forget that windows bitmaps are bottom->top */
2124 bytesperline = longsperline*4;
2125 nbytesperline = (height/cy)*bytesperline;
2126 for (i=0;i<height;i++) {
2128 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2129 bits+bytesperline*(height-1-i),
2133 bmihc->biWidth = nwidth;
2134 bmihc->biHeight = nheight;
2135 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2137 LocalFree((HLOCAL)nbits);
2138 LocalFree((HLOCAL)bits);
2142 if (xdc) ReleaseDC(0,xdc);
2143 if (bmihc) LocalFree((HLOCAL)bmihc);
2146 DeleteObject(hbitmap);
2153 /*************************************************************************
2154 * ImageList_Read [COMCTL32.68]
2156 * Reads an image list from a stream.
2159 * pstm [I] pointer to a stream
2162 * Success: handle to image list
2165 * The format is like this:
2166 * ILHEAD ilheadstruct;
2168 * for the color image part:
2169 * BITMAPFILEHEADER bmfh;
2170 * BITMAPINFOHEADER bmih;
2171 * only if it has a palette:
2172 * RGBQUAD rgbs[nr_of_paletted_colors];
2174 * BYTE colorbits[imagesize];
2176 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2177 * BITMAPFILEHEADER bmfh_mask;
2178 * BITMAPINFOHEADER bmih_mask;
2179 * only if it has a palette (it usually does not):
2180 * RGBQUAD rgbs[nr_of_paletted_colors];
2182 * BYTE maskbits[imagesize];
2184 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2185 * _read_bitmap needs to convert them.
2187 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2191 HBITMAP hbmColor=0,hbmMask=0;
2194 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2196 if (ilHead.usMagic != (('L' << 8) | 'I'))
2198 if (ilHead.usVersion != 0x101) /* probably version? */
2202 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2203 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2204 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2205 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2206 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2207 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2208 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2209 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2210 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2211 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2214 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2217 if (ilHead.flags & ILC_MASK) {
2218 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2220 DeleteObject(hbmColor);
2225 himl = ImageList_Create (
2233 DeleteObject(hbmColor);
2234 DeleteObject(hbmMask);
2237 himl->hbmImage = hbmColor;
2238 himl->hbmMask = hbmMask;
2239 himl->cCurImage = ilHead.cCurImage;
2240 himl->cMaxImage = ilHead.cMaxImage;
2242 ImageList_SetBkColor(himl,ilHead.bkcolor);
2244 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2249 /*************************************************************************
2250 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2253 * himl [I] image list handle
2262 ImageList_Remove (HIMAGELIST himl, INT i)
2264 HBITMAP hbmNewImage, hbmNewMask;
2269 ERR("Invalid image list handle!\n");
2273 if ((i < -1) || (i >= himl->cCurImage)) {
2274 ERR("index out of range! %d\n", i);
2278 if (himl->cCurImage == 0) {
2279 ERR("image list is already empty!\n");
2285 TRACE("remove all!\n");
2287 himl->cMaxImage = himl->cInitial + himl->cGrow;
2288 himl->cCurImage = 0;
2289 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2290 himl->nOvlIdx[nCount] = -1;
2292 DeleteObject (himl->hbmImage);
2294 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2295 1, himl->uBitsPixel, NULL);
2297 if (himl->hbmMask) {
2298 DeleteObject (himl->hbmMask);
2300 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2305 /* delete one image */
2306 TRACE("Remove single image! %d\n", i);
2308 /* create new bitmap(s) */
2309 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2311 TRACE(" - Number of images: %d / %d (Old/New)\n",
2312 himl->cCurImage, himl->cCurImage - 1);
2313 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2314 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2317 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2320 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2322 hbmNewMask = 0; /* Just to keep compiler happy! */
2324 hdcSrc = CreateCompatibleDC (0);
2325 hdcDst = CreateCompatibleDC (0);
2327 /* copy all images and masks prior to the "removed" image */
2329 TRACE("Pre image copy: Copy %d images\n", i);
2331 SelectObject (hdcSrc, himl->hbmImage);
2332 SelectObject (hdcDst, hbmNewImage);
2333 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2334 hdcSrc, 0, 0, SRCCOPY);
2336 if (himl->hbmMask) {
2337 SelectObject (hdcSrc, himl->hbmMask);
2338 SelectObject (hdcDst, hbmNewMask);
2339 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2340 hdcSrc, 0, 0, SRCCOPY);
2344 /* copy all images and masks behind the removed image */
2345 if (i < himl->cCurImage - 1) {
2346 TRACE("Post image copy!\n");
2347 SelectObject (hdcSrc, himl->hbmImage);
2348 SelectObject (hdcDst, hbmNewImage);
2349 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2350 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2352 if (himl->hbmMask) {
2353 SelectObject (hdcSrc, himl->hbmMask);
2354 SelectObject (hdcDst, hbmNewMask);
2355 BitBlt (hdcDst, i * himl->cx, 0,
2356 (himl->cCurImage - i - 1) * himl->cx,
2357 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2364 /* delete old images and insert new ones */
2365 DeleteObject (himl->hbmImage);
2366 himl->hbmImage = hbmNewImage;
2367 if (himl->hbmMask) {
2368 DeleteObject (himl->hbmMask);
2369 himl->hbmMask = hbmNewMask;
2373 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2380 /*************************************************************************
2381 * ImageList_Replace [COMCTL32.70]
2383 * Replaces an image in an image list with a new image.
2386 * himl [I] handle to image list
2388 * hbmImage [I] handle to image bitmap
2389 * hbmMask [I] handle to mask bitmap. Can be NULL.
2397 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2400 HDC hdcImageList, hdcImage;
2404 ERR("Invalid image list handle!\n");
2408 if ((i >= himl->cMaxImage) || (i < 0)) {
2409 ERR("Invalid image index!\n");
2413 hdcImageList = CreateCompatibleDC (0);
2414 hdcImage = CreateCompatibleDC (0);
2415 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2418 SelectObject (hdcImageList, himl->hbmImage);
2419 SelectObject (hdcImage, hbmImage);
2421 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2422 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2427 SelectObject (hdcImageList, himl->hbmMask);
2428 SelectObject (hdcImage, hbmMask);
2430 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2431 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2434 /* Remove the background from the image
2436 SelectObject (hdcImageList, himl->hbmImage);
2437 StretchBlt (hdcImageList,
2438 i*himl->cx, 0, himl->cx, himl->cy,
2440 0, 0, bmp.bmWidth, bmp.bmHeight,
2441 0x220326); /* NOTSRCAND */
2444 DeleteDC (hdcImage);
2445 DeleteDC (hdcImageList);
2451 /*************************************************************************
2452 * ImageList_ReplaceIcon [COMCTL32.75]
2454 * Replaces an image in an image list using an icon.
2457 * himl [I] handle to image list
2459 * hIcon [I] handle to icon
2462 * Success: index of the replaced image
2467 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2469 HDC hdcImageList, hdcImage;
2472 HBITMAP hbmOldSrc, hbmOldDst;
2476 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2480 if ((i >= himl->cMaxImage) || (i < -1))
2483 hBestFitIcon = CopyImage(
2486 LR_COPYFROMRESOURCE);
2488 GetIconInfo (hBestFitIcon, &ii);
2489 if (ii.hbmMask == 0)
2491 if (ii.hbmColor == 0)
2493 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2496 if (himl->cCurImage + 1 > himl->cMaxImage)
2497 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2499 nIndex = himl->cCurImage;
2505 hdcImageList = CreateCompatibleDC (0);
2506 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2507 if (hdcImageList == 0)
2508 ERR("invalid hdcImageList!\n");
2510 hdcImage = CreateCompatibleDC (0);
2511 TRACE("hdcImage=0x%x!\n", hdcImage);
2513 ERR("invalid hdcImage!\n");
2515 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2516 SetTextColor( hdcImageList, RGB(0,0,0));
2517 SetBkColor( hdcImageList, RGB(255,255,255));
2518 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2519 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2520 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2522 if (himl->hbmMask) {
2523 SelectObject (hdcImageList, himl->hbmMask);
2524 SelectObject (hdcImage, ii.hbmMask);
2525 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2526 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2529 SelectObject (hdcImage, hbmOldSrc);
2530 SelectObject (hdcImageList, hbmOldDst);
2533 DestroyIcon(hBestFitIcon);
2535 DeleteDC (hdcImageList);
2537 DeleteDC (hdcImage);
2539 DeleteObject (ii.hbmColor);
2541 DeleteObject (ii.hbmMask);
2547 /*************************************************************************
2548 * ImageList_SetBkColor [COMCTL32.76]
2550 * Sets the background color of an image list.
2553 * himl [I] handle to image list
2554 * clrBk [I] background color
2557 * Success: previous background color
2562 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2569 clrOldBk = himl->clrBk;
2570 himl->clrBk = clrBk;
2575 /*************************************************************************
2576 * ImageList_SetDragCursorImage [COMCTL32.77]
2578 * Combines the specified image with the current drag image
2581 * himlDrag [I] handle to drag image list
2582 * iDrag [I] drag image index
2583 * dxHotspot [I] X position of the hot spot
2584 * dyHotspot [I] Y position of the hot spot
2591 * When this function is called and the drag image is visible, a
2592 * short flickering occurs but this matches the Win9x behavior. It is
2593 * possible to fix the flickering using code like in ImageList_DragMove.
2597 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2598 INT dxHotspot, INT dyHotspot)
2600 HIMAGELIST himlTemp;
2604 if (InternalDrag.himl == NULL)
2607 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2608 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2610 visible = InternalDrag.bShow;
2612 /* Calculate the offset between the origin of the old image and the
2613 * origin of the second image.
2614 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2615 * hotspot) to the origin of the second image.
2616 * See M$DN for details */
2617 if(InternalDrag.bHSPending) {
2620 InternalDrag.bHSPending = FALSE;
2622 dx = InternalDrag.dxHotspot - dxHotspot;
2623 dy = InternalDrag.dyHotspot - dyHotspot;
2625 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2628 /* hide the drag image */
2629 ImageList_DragShowNolock(FALSE);
2631 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2632 (InternalDrag.himl->cy != himlTemp->cy)) {
2633 /* the size of the drag image changed, invalidate the buffer */
2634 DeleteObject(InternalDrag.hbmBg);
2635 InternalDrag.hbmBg = 0;
2638 ImageList_Destroy (InternalDrag.himl);
2639 InternalDrag.himl = himlTemp;
2641 /* update the InternalDragOffset, if the origin of the
2642 * DragImage was changed by ImageList_Merge. */
2644 InternalDrag.dxHotspot = dxHotspot;
2646 InternalDrag.dyHotspot = dyHotspot;
2649 /* show the drag image */
2650 ImageList_DragShowNolock(TRUE);
2657 /*************************************************************************
2658 * ImageList_SetFilter [COMCTL32.78]
2660 * Sets a filter (or does something completely different)!!???
2663 * himl [I] handle to image list
2669 * Failure: FALSE ???
2672 * This is an UNDOCUMENTED function!!!!
2677 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2679 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2686 /*************************************************************************
2687 * ImageList_SetFlags [COMCTL32.79]
2694 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2696 FIXME("(%p %08lx):empty stub\n", himl, flags);
2701 /*************************************************************************
2702 * ImageList_SetIconSize [COMCTL32.80]
2704 * Sets the image size of the bitmap and deletes all images.
2707 * himl [I] handle to image list
2708 * cx [I] image width
2709 * cy [I] image height
2717 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2724 /* remove all images */
2725 himl->cMaxImage = himl->cInitial + himl->cGrow;
2726 himl->cCurImage = 0;
2730 /* initialize overlay mask indices */
2731 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2732 himl->nOvlIdx[nCount] = -1;
2734 DeleteObject (himl->hbmImage);
2736 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2737 1, himl->uBitsPixel, NULL);
2739 if (himl->hbmMask) {
2740 DeleteObject (himl->hbmMask);
2742 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2750 /*************************************************************************
2751 * ImageList_SetImageCount [COMCTL32.81]
2753 * Resizes an image list to the specified number of images.
2756 * himl [I] handle to image list
2757 * iImageCount [I] number of images in the image list
2765 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2767 HDC hdcImageList, hdcBitmap;
2768 HBITMAP hbmNewBitmap;
2769 INT nNewCount, nCopyCount;
2773 if (himl->cCurImage >= iImageCount)
2775 if (himl->cMaxImage > iImageCount)
2778 nNewCount = iImageCount + himl->cGrow;
2779 nCopyCount = min(himl->cCurImage, iImageCount);
2781 hdcImageList = CreateCompatibleDC (0);
2782 hdcBitmap = CreateCompatibleDC (0);
2784 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2785 1, himl->uBitsPixel, NULL);
2786 if (hbmNewBitmap != 0)
2788 SelectObject (hdcImageList, himl->hbmImage);
2789 SelectObject (hdcBitmap, hbmNewBitmap);
2792 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2793 hdcImageList, 0, 0, SRCCOPY);
2795 /* delete 'empty' image space */
2796 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2797 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2798 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2799 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2801 DeleteObject (himl->hbmImage);
2802 himl->hbmImage = hbmNewBitmap;
2805 ERR("Could not create new image bitmap !\n");
2809 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2811 if (hbmNewBitmap != 0)
2813 SelectObject (hdcImageList, himl->hbmMask);
2814 SelectObject (hdcBitmap, hbmNewBitmap);
2817 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2818 hdcImageList, 0, 0, SRCCOPY);
2820 /* delete 'empty' image space */
2821 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2822 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2823 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2824 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2826 DeleteObject (himl->hbmMask);
2827 himl->hbmMask = hbmNewBitmap;
2830 ERR("Could not create new mask bitmap!\n");
2833 DeleteDC (hdcImageList);
2834 DeleteDC (hdcBitmap);
2836 /* Update max image count and current image count */
2837 himl->cMaxImage = nNewCount;
2838 if (himl->cCurImage > nCopyCount)
2839 himl->cCurImage = nCopyCount;
2845 /*************************************************************************
2846 * ImageList_SetOverlayImage [COMCTL32.82]
2848 * Assigns an overlay mask index to an existing image in an image list.
2851 * himl [I] handle to image list
2852 * iImage [I] image index
2853 * iOverlay [I] overlay mask index
2861 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2865 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2867 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2869 himl->nOvlIdx[iOverlay - 1] = iImage;
2875 /* helper for ImageList_Write - write bitmap to pstm
2876 * currently everything is written as 24 bit RGB, except masks
2879 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2881 LPBITMAPFILEHEADER bmfh;
2882 LPBITMAPINFOHEADER bmih;
2883 LPBYTE data, lpBits, lpBitsOrg;
2885 INT bitCount, sizeImage, offBits, totalSize;
2886 INT nwidth, nheight, nsizeImage, icount;
2888 BOOL result = FALSE;
2892 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2894 /* XXX is this always correct? */
2895 icount = bm.bmWidth / cx;
2897 nheight = cy * ((icount+3)>>2);
2899 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2900 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2901 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2903 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2905 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2906 offBits = totalSize;
2907 totalSize += nsizeImage;
2909 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2910 bmfh = (LPBITMAPFILEHEADER)data;
2911 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2912 lpBits = data + offBits;
2914 /* setup BITMAPFILEHEADER */
2915 bmfh->bfType = (('M' << 8) | 'B');
2917 bmfh->bfReserved1 = 0;
2918 bmfh->bfReserved2 = 0;
2919 bmfh->bfOffBits = offBits;
2921 /* setup BITMAPINFOHEADER */
2922 bmih->biSize = sizeof(BITMAPINFOHEADER);
2923 bmih->biWidth = bm.bmWidth;
2924 bmih->biHeight = bm.bmHeight;
2926 bmih->biBitCount = bitCount;
2927 bmih->biCompression = BI_RGB;
2928 bmih->biSizeImage = nsizeImage;
2929 bmih->biXPelsPerMeter = 0;
2930 bmih->biYPelsPerMeter = 0;
2931 bmih->biClrUsed = 0;
2932 bmih->biClrImportant = 0;
2934 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2935 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2936 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2940 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2941 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2943 for(i = 0; i < nheight; i++) {
2944 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2945 int noff = (nbpl * (nheight-1-i));
2946 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2950 bmih->biWidth = nwidth;
2951 bmih->biHeight = nheight;
2955 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2956 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2957 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2960 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2967 LocalFree((HLOCAL)lpBitsOrg);
2973 /*************************************************************************
2974 * ImageList_Write [COMCTL32.83]
2976 * Writes an image list to a stream.
2979 * himl [I] handle to image list
2980 * pstm [O] Pointer to a stream.
2991 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2999 ilHead.usMagic = (('L' << 8) | 'I');
3000 ilHead.usVersion = 0x101;
3001 ilHead.cCurImage = himl->cCurImage;
3002 ilHead.cMaxImage = himl->cMaxImage;
3003 ilHead.cGrow = himl->cGrow;
3004 ilHead.cx = himl->cx;
3005 ilHead.cy = himl->cy;
3006 ilHead.bkcolor = himl->clrBk;
3007 ilHead.flags = himl->flags;
3008 for(i = 0; i < 4; i++) {
3009 ilHead.ovls[i] = himl->nOvlIdx[i];
3012 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3015 /* write the bitmap */
3016 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3019 /* write the mask if we have one */
3020 if(himl->flags & ILC_MASK) {
3021 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))