2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
7 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
8 * - Fix ImageList_GetIcon.
9 * - Fix drag functions.
10 * - Fix ImageList_Write.
11 * - Fix ImageList_SetFilter (undocumented).
12 * BTW does anybody know anything about this function???
13 * - It removes 12 Bytes from the stack (3 Parameters).
14 * - First parameter SHOULD be a HIMAGELIST.
15 * - Second parameter COULD be an index?????
16 * - Third parameter.... ?????????????????????
19 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
20 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
21 * partially implemented, the functions mentioned above will be
22 * limited in functionality too.
27 #include "wine/obj_base.h"
28 #include "wine/obj_storage.h"
30 #include "imagelist.h"
31 #include "debugtools.h"
33 DEFAULT_DEBUG_CHANNEL(imagelist);
36 #define _MAX(a,b) (((a)>(b))?(a):(b))
37 #define _MIN(a,b) (((a)>(b))?(b):(a))
39 #define MAX_OVERLAYIMAGE 15
42 /* internal image list data used for Drag & Drop operations */
44 static HIMAGELIST himlInternalDrag = NULL;
45 static INT nInternalDragHotspotX = 0;
46 static INT nInternalDragHotspotY = 0;
48 static HWND hwndInternalDrag = 0;
49 static INT xInternalPos = 0;
50 static INT yInternalPos = 0;
52 static HDC hdcBackBuffer = 0;
53 static HBITMAP hbmBackBuffer = 0;
56 /*************************************************************************
57 * IMAGELIST_InternalExpandBitmaps [Internal]
59 * Expands the bitmaps of an image list by the given number of images.
62 * himl [I] handle to image list
63 * nImageCount [I] number of images to add
69 * This function can NOT be used to reduce the number of images.
72 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
74 HDC hdcImageList, hdcBitmap;
76 INT nNewWidth, nNewCount;
78 if ((himl->cCurImage + nImageCount < himl->cMaxImage)
82 if (cy == 0) cy = himl->cy;
83 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
84 nNewWidth = nNewCount * himl->cx;
86 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
87 hdcImageList = CreateCompatibleDC (0);
88 hdcBitmap = CreateCompatibleDC (0);
91 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
92 if (hbmNewBitmap == 0)
93 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
95 SelectObject (hdcImageList, himl->hbmImage);
96 SelectObject (hdcBitmap, hbmNewBitmap);
97 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
98 hdcImageList, 0, 0, SRCCOPY);
100 DeleteObject (himl->hbmImage);
101 himl->hbmImage = hbmNewBitmap;
105 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
107 if (hbmNewBitmap == 0)
108 ERR("creating new mask bitmap!\n");
110 SelectObject (hdcImageList, himl->hbmMask);
111 SelectObject (hdcBitmap, hbmNewBitmap);
112 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
113 hdcImageList, 0, 0, SRCCOPY);
114 DeleteObject (himl->hbmMask);
115 himl->hbmMask = hbmNewBitmap;
118 himl->cMaxImage = nNewCount;
120 DeleteDC (hdcImageList);
121 DeleteDC (hdcBitmap);
125 /*************************************************************************
126 * IMAGELIST_InternalDraw [Internal]
128 * Draws the image in the ImageList (without the mask)
131 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
132 * cx [I] the width of the image to display
133 * cy............[I] the height of the image to display
139 * This functions is used by ImageList_DrawIndirect, when it is
140 * required to draw only the Image (without the mask) to the screen.
142 * Blending and Overlays styles are accomplised by another function
145 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
150 hImageDC = CreateCompatibleDC(0);
151 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
152 BitBlt(pimldp->hdcDst,
153 pimldp->x, pimldp->y, cx, cy,
155 pimldp->himl->cx * pimldp->i, 0,
158 SelectObject(hImageDC, hOldBitmap);
163 /*************************************************************************
164 * IMAGELIST_InternalDrawMask [Internal]
166 * Draws the image in the ImageList witht the mask
169 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
170 * cx [I] the width of the image to display
171 * cy............[I] the height of the image to display
177 * This functions is used by ImageList_DrawIndirect, when it is
178 * required to draw the Image with the mask to the screen.
180 * Blending and Overlays styles are accomplised by another function.
183 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
185 HDC hMaskDC, hImageDC;
186 BOOL bUseCustomBackground, bBlendFlag;
187 HBRUSH hBrush, hOldBrush;
188 HBITMAP hOldBitmapImage, hOldBitmapMask;
189 HIMAGELIST himlLocal = pimldp->himl;
190 COLORREF oldBkColor, oldFgColor;
191 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
193 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
194 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
196 hImageDC = CreateCompatibleDC(0);
197 hMaskDC = CreateCompatibleDC(0);
199 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
200 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
201 /* Draw the Background for the appropriate Styles
203 if( bUseCustomBackground &&
204 (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE || bBlendFlag))
206 hBrush = CreateSolidBrush (himlLocal->clrBk);
207 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
208 PatBlt (pimldp->hdcDst,
209 pimldp->x, pimldp->y, cx, cy,
212 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
215 /* Draw Image Transparently over the current background
217 if(fStyle == ILD_NORMAL
218 || (fStyle & ILD_TRANSPARENT)
219 || ((fStyle & ILD_IMAGE) && bUseCustomBackground)
222 /* to obtain a transparent look, background color should be set
223 to white and foreground color to black when blting the
225 oldBkColor = SetBkColor(pimldp->hdcDst, RGB(0xff, 0xff, 0xff));
226 oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 0));
228 BitBlt(pimldp->hdcDst,
229 pimldp->x, pimldp->y, cx, cy,
231 himlLocal->cx * pimldp->i, 0,
234 BitBlt(pimldp->hdcDst,
235 pimldp->x, pimldp->y, cx, cy,
237 himlLocal->cx * pimldp->i, 0,
240 SetBkColor(pimldp->hdcDst, oldBkColor);
241 SetTextColor(pimldp->hdcDst, oldFgColor);
243 /* Draw the image when no Background is specified
245 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
247 BitBlt(pimldp->hdcDst,
248 pimldp->x, pimldp->y, cx, cy,
250 himlLocal->cx * pimldp->i, 0,
253 /* Draw the mask with or without a background
255 else if(fStyle & ILD_MASK)
257 BitBlt(pimldp->hdcDst,
258 pimldp->x, pimldp->y, cx, cy,
260 himlLocal->cx * pimldp->i, 0,
261 bUseCustomBackground ? SRCCOPY : SRCAND);
263 SelectObject(hImageDC, hOldBitmapImage);
264 SelectObject(hMaskDC, hOldBitmapMask);
269 /*************************************************************************
270 * IMAGELIST_InternalDrawBlend [Internal]
272 * Draws the Blend over the current image
275 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
276 * cx [I] the width of the image to display
277 * cy............[I] the height of the image to display
283 * This functions is used by ImageList_DrawIndirect, when it is
284 * required to add the blend to the current image.
288 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
291 HDC hBlendMaskDC,hMaskDC;
292 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
293 HBITMAP hBlendMaskBitmap, hOldBitmap;
294 COLORREF clrBlend, OldTextColor, OldBkColor;
295 HIMAGELIST himlLocal = pimldp->himl;
297 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
298 if (!(pimldp->rgbFg == CLR_DEFAULT))
300 clrBlend = pimldp->rgbFg;
302 /* Create the blend Mask
304 hBlendMaskDC = CreateCompatibleDC(0);
305 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
306 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
308 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
309 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
311 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
312 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
313 SelectObject(hBlendMaskDC, hOldBrush);
315 /* Modify the blend mask if an Image Mask exist
317 if(pimldp->himl->hbmMask != 0)
319 HBITMAP hOldMaskBitmap;
320 hMaskDC = CreateCompatibleDC(0);
321 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
326 himlLocal->cx * pimldp->i,0,
327 0x220326); /* NOTSRCAND */
335 SelectObject(hMaskDC, hOldMaskBitmap);
339 /* Apply blend to the current image given the BlendMask
341 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
342 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
343 hBlendColorBrush = CreateSolidBrush(clrBlend);
344 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
346 BitBlt (pimldp->hdcDst,
347 pimldp->x, pimldp->y, cx, cy,
350 0xB8074A); /* PSDPxax */
352 SelectObject(pimldp->hdcDst, hOldBrush);
353 SetTextColor(pimldp->hdcDst, OldTextColor);
354 SetBkColor(pimldp->hdcDst, OldBkColor);
355 SelectObject(hBlendMaskDC, hOldBitmap);
356 DeleteDC(hBlendMaskDC);
357 DeleteObject(hBlendMaskBitmap);
358 DeleteObject(hBlendColorBrush);
361 /*************************************************************************
362 * IMAGELIST_InternalDrawOverlay [Internal]
364 * Draws the overlay image
367 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
368 * cx [I] the width of the image to display
369 * cy............[I] the height of the image to display
375 * This functions is used by ImageList_DrawIndirect, when it is
376 * required to draw the overlay
381 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
387 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
388 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
390 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
391 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
393 hImageDC = CreateCompatibleDC(0);
394 if (pimldp->himl->hbmMask)
396 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
397 pimldp->himl->hbmMask);
399 BitBlt (pimldp->hdcDst,
400 pimldp->x, pimldp->y, cx, cy,
401 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
404 SelectObject(hImageDC, hOldBitmap);
406 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
407 pimldp->himl->hbmImage);
409 BitBlt (pimldp->hdcDst,
410 pimldp->x, pimldp->y, cx, cy,
412 pimldp->himl->cx * nOvlIdx, 0,
415 SelectObject(hImageDC, hOldBitmap);
425 /*************************************************************************
426 * ImageList_Add [COMCTL32.39]
428 * Add an image or images to an image list.
431 * himl [I] handle to image list
432 * hbmImage [I] handle to image bitmap
433 * hbmMask [I] handle to mask bitmap
436 * Success: Index of the first new image.
441 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
443 HDC hdcImage, hdcBitmap;
444 INT nFirstIndex, nImageCount;
447 HBITMAP hOldBitmapImage, hOldBitmap;
449 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
450 if (!himl || !hbmImage)
453 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
454 nImageCount = bmp.bmWidth / himl->cx;
456 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
458 nStartX = himl->cCurImage * himl->cx;
460 hdcImage = CreateCompatibleDC(0);
461 hdcBitmap = CreateCompatibleDC(0);
463 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
464 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
466 /* Copy result to the imagelist
468 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
469 hdcBitmap, 0, 0, SRCCOPY);
473 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
475 hdcMask = CreateCompatibleDC (0);
476 hdcTemp = CreateCompatibleDC(0);
477 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
478 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
481 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
486 SelectObject(hdcTemp, hOldBitmapTemp);
489 /* Remove the background from the image
492 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
495 0x220326); /* NOTSRCAND */
497 SelectObject(hdcMask, hOldBitmapMask);
501 SelectObject(hdcImage, hOldBitmapImage);
502 SelectObject(hdcBitmap, hOldBitmap);
506 nFirstIndex = himl->cCurImage;
507 himl->cCurImage += nImageCount;
513 /*************************************************************************
514 * ImageList_AddIcon [COMCTL32.40]
516 * Adds an icon to an image list.
519 * himl [I] handle to image list
520 * hIcon [I] handle to icon
523 * Success: index of the new image
528 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
530 return ImageList_ReplaceIcon (himl, -1, hIcon);
534 /*************************************************************************
535 * ImageList_AddMasked [COMCTL32.41]
537 * Adds an image or images to an image list and creates a mask from the
538 * specified bitmap using the mask color.
541 * himl [I] handle to image list.
542 * hBitmap [I] handle to bitmap
543 * clrMask [I] mask color.
546 * Success: Index of the first new image.
551 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
553 HDC hdcImage, hdcMask, hdcBitmap;
554 INT nIndex, nImageCount, nMaskXOffset=0;
556 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
557 HBITMAP hMaskBitmap=0;
560 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
564 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
567 nImageCount = bmp.bmWidth / himl->cx;
569 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
571 nIndex = himl->cCurImage;
572 himl->cCurImage += nImageCount;
574 hdcMask = CreateCompatibleDC (0);
575 hdcImage = CreateCompatibleDC(0);
576 hdcBitmap = CreateCompatibleDC(0);
579 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
580 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
583 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
584 nMaskXOffset = nIndex * himl->cx;
589 Create a temp Mask so we can remove the background of
590 the Image (Windows does this even if there is no mask)
592 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
593 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
596 /* create monochrome image to the mask bitmap */
597 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
598 GetPixel (hdcBitmap, 0, 0);
599 SetBkColor (hdcBitmap, bkColor);
601 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
605 SetBkColor(hdcBitmap, RGB(255,255,255));
606 /*Remove the background from the image
609 WINDOWS BUG ALERT!!!!!!
610 The statement below should not be done in common practice
611 but this is how ImageList_AddMasked works in Windows.
612 It overwrites the original bitmap passed, this was discovered
613 by using the same bitmap to itterated the different styles
614 on windows where it failed (BUT ImageList_Add is OK)
615 This is here in case some apps really on this bug
618 0, 0, bmp.bmWidth, bmp.bmHeight,
621 0x220326); /* NOTSRCAND */
622 /* Copy result to the imagelist
625 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
631 SelectObject(hdcMask,hOldBitmapMask);
632 SelectObject(hdcImage, hOldBitmapImage);
633 SelectObject(hdcBitmap, hOldBitmap);
639 DeleteObject(hMaskBitmap);
646 /*************************************************************************
647 * ImageList_BeginDrag [COMCTL32.42]
649 * Creates a temporary image list that contains one image. It will be used
653 * himlTrack [I] handle to the source image list
654 * iTrack [I] index of the drag image in the source image list
655 * dxHotspot [I] X position of the hot spot of the drag image
656 * dyHotspot [I] Y position of the hot spot of the drag image
664 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
665 INT dxHotspot, INT dyHotspot)
669 FIXME("partially implemented!\n");
671 if (himlTrack == NULL)
674 if (himlInternalDrag)
675 ImageList_EndDrag ();
678 ImageList_Create (himlTrack->cx, himlTrack->cy,
679 himlTrack->flags, 1, 1);
680 if (himlInternalDrag == NULL) {
681 ERR("Error creating drag image list!\n");
685 nInternalDragHotspotX = dxHotspot;
686 nInternalDragHotspotY = dyHotspot;
688 hdcSrc = CreateCompatibleDC (0);
689 hdcDst = CreateCompatibleDC (0);
692 SelectObject (hdcSrc, himlTrack->hbmImage);
693 SelectObject (hdcDst, himlInternalDrag->hbmImage);
694 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
695 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
698 SelectObject (hdcSrc, himlTrack->hbmMask);
699 SelectObject (hdcDst, himlInternalDrag->hbmMask);
700 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
701 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
706 himlInternalDrag->cCurImage = 1;
712 /*************************************************************************
713 * ImageList_Copy [COMCTL32.43]
715 * Copies an image of the source image list to an image of the
716 * destination image list. Images can be copied or swapped.
719 * himlDst [I] handle to the destination image list
720 * iDst [I] destination image index.
721 * himlSrc [I] handle to the source image list
722 * iSrc [I] source image index
723 * uFlags [I] flags for the copy operation
730 * Copying from one image list to another is possible. The original
731 * implementation just copies or swapps within one image list.
732 * Could this feature become a bug??? ;-)
736 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
737 INT iSrc, INT uFlags)
741 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
743 if ((himlSrc == NULL) || (himlDst == NULL))
745 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
747 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
750 hdcSrc = CreateCompatibleDC (0);
751 if (himlDst == himlSrc)
754 hdcDst = CreateCompatibleDC (0);
756 if (uFlags & ILCF_SWAP) {
758 HBITMAP hbmTempImage, hbmTempMask;
760 /* create temporary bitmaps */
761 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
762 himlSrc->uBitsPixel, NULL);
763 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
766 /* copy (and stretch) destination to temporary bitmaps.(save) */
768 SelectObject (hdcSrc, himlDst->hbmImage);
769 SelectObject (hdcDst, hbmTempImage);
770 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
771 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
774 SelectObject (hdcSrc, himlDst->hbmMask);
775 SelectObject (hdcDst, hbmTempMask);
776 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
777 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
780 /* copy (and stretch) source to destination */
782 SelectObject (hdcSrc, himlSrc->hbmImage);
783 SelectObject (hdcDst, himlDst->hbmImage);
784 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
785 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
788 SelectObject (hdcSrc, himlSrc->hbmMask);
789 SelectObject (hdcDst, himlDst->hbmMask);
790 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
791 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
794 /* copy (without stretching) temporary bitmaps to source (restore) */
796 SelectObject (hdcSrc, hbmTempImage);
797 SelectObject (hdcDst, himlSrc->hbmImage);
798 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
799 hdcSrc, 0, 0, SRCCOPY);
801 SelectObject (hdcSrc, hbmTempMask);
802 SelectObject (hdcDst, himlSrc->hbmMask);
803 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
804 hdcSrc, 0, 0, SRCCOPY);
806 /* delete temporary bitmaps */
807 DeleteObject (hbmTempMask);
808 DeleteObject (hbmTempImage);
812 SelectObject (hdcSrc, himlSrc->hbmImage);
813 if (himlSrc == himlDst)
816 SelectObject (hdcDst, himlDst->hbmImage);
817 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
818 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
822 SelectObject (hdcSrc, himlSrc->hbmMask);
823 if (himlSrc == himlDst)
826 SelectObject (hdcDst, himlDst->hbmMask);
827 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
828 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
833 if (himlSrc != himlDst)
840 /*************************************************************************
841 * ImageList_Create [COMCTL32.44] Creates a new image list.
844 * cx [I] image height
846 * flags [I] creation flags
847 * cInitial [I] initial number of images in the image list
848 * cGrow [I] number of images by which image list grows
851 * Success: Handle to the created image list
856 ImageList_Create (INT cx, INT cy, UINT flags,
857 INT cInitial, INT cGrow)
863 static WORD aBitBlend25[] =
864 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
866 static WORD aBitBlend50[] =
867 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
869 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
871 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
878 himl->cMaxImage = cInitial + cGrow;
879 himl->cInitial = cInitial;
882 himl->clrFg = CLR_DEFAULT;
883 himl->clrBk = CLR_NONE;
885 /* initialize overlay mask indices */
886 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
887 himl->nOvlIdx[nCount] = -1;
889 hdc = CreateCompatibleDC (0);
890 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
893 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
895 if (himl->cMaxImage > 0) {
897 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
898 1, himl->uBitsPixel, NULL);
899 if (himl->hbmImage == 0) {
900 ERR("Error creating image bitmap!\n");
907 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
908 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
910 if (himl->hbmMask == 0) {
911 ERR("Error creating mask bitmap!\n");
913 DeleteObject (himl->hbmImage);
920 /* create blending brushes */
921 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
922 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
923 DeleteObject (hbmTemp);
925 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
926 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
927 DeleteObject (hbmTemp);
929 TRACE("created imagelist %p\n", himl);
934 /*************************************************************************
935 * ImageList_Destroy [COMCTL32.45]
937 * Destroys an image list.
940 * himl [I] handle to image list
948 ImageList_Destroy (HIMAGELIST himl)
953 /* delete image bitmaps */
955 DeleteObject (himl->hbmImage);
957 DeleteObject (himl->hbmMask);
959 /* delete blending brushes */
960 if (himl->hbrBlend25)
961 DeleteObject (himl->hbrBlend25);
962 if (himl->hbrBlend50)
963 DeleteObject (himl->hbrBlend50);
965 COMCTL32_Free (himl);
971 /*************************************************************************
972 * ImageList_DragEnter [COMCTL32.46]
974 * Locks window update and displays the drag image at the given position.
977 * hwndLock [I] handle of the window that owns the drag image.
978 * x [I] X position of the drag image.
979 * y [I] Y position of the drag image.
986 * The position of the drag image is relative to the window, not
991 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
993 if (himlInternalDrag == NULL)
997 hwndInternalDrag = hwndLock;
999 hwndInternalDrag = GetDesktopWindow ();
1004 hdcBackBuffer = CreateCompatibleDC (0);
1005 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1006 himlInternalDrag->cx, himlInternalDrag->cy);
1008 ImageList_DragShowNolock (TRUE);
1014 /*************************************************************************
1015 * ImageList_DragLeave [COMCTL32.47]
1017 * Unlocks window update and hides the drag image.
1020 * hwndLock [I] handle of the window that owns the drag image.
1028 ImageList_DragLeave (HWND hwndLock)
1031 hwndInternalDrag = hwndLock;
1033 hwndInternalDrag = GetDesktopWindow ();
1035 ImageList_DragShowNolock (FALSE);
1037 DeleteDC (hdcBackBuffer);
1038 DeleteObject (hbmBackBuffer);
1044 /*************************************************************************
1045 * ImageList_DragMove [COMCTL32.48]
1047 * Moves the drag image.
1050 * x [I] X position of the drag image.
1051 * y [I] Y position of the drag image.
1058 * The position of the drag image is relative to the window, not
1063 ImageList_DragMove (INT x, INT y)
1065 ImageList_DragShowNolock (FALSE);
1070 ImageList_DragShowNolock (TRUE);
1076 /*************************************************************************
1077 * ImageList_DragShowNolock [COMCTL32.49]
1079 * Shows or hides the drag image.
1082 * bShow [I] TRUE shows the drag image, FALSE hides it.
1093 ImageList_DragShowNolock (BOOL bShow)
1097 FIXME("semi-stub!\n");
1098 TRACE("bShow=0x%X!\n", bShow);
1100 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1101 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1104 /* show drag image */
1106 /* save background */
1108 /* draw drag image */
1112 /* hide drag image */
1114 /* restore background */
1118 ReleaseDC (hwndInternalDrag, hdcDrag);
1124 /*************************************************************************
1125 * ImageList_Draw [COMCTL32.50] Draws an image.
1128 * himl [I] handle to image list
1130 * hdc [I] handle to device context
1133 * fStyle [I] drawing flags
1140 * Calls ImageList_DrawIndirect.
1143 * ImageList_DrawIndirect.
1147 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1148 INT x, INT y, UINT fStyle)
1150 IMAGELISTDRAWPARAMS imldp;
1152 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1162 imldp.rgbBk = CLR_DEFAULT;
1163 imldp.rgbFg = CLR_DEFAULT;
1164 imldp.fStyle = fStyle;
1167 return ImageList_DrawIndirect (&imldp);
1171 /*************************************************************************
1172 * ImageList_DrawEx [COMCTL32.51]
1174 * Draws an image and allows to use extended drawing features.
1177 * himl [I] handle to image list
1179 * hdc [I] handle to device context
1182 * xOffs [I] X offset
1183 * yOffs [I] Y offset
1184 * rgbBk [I] background color
1185 * rgbFg [I] foreground color
1186 * fStyle [I] drawing flags
1193 * Calls ImageList_DrawIndirect.
1196 * ImageList_DrawIndirect.
1200 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1201 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1204 IMAGELISTDRAWPARAMS imldp;
1206 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1216 imldp.rgbBk = rgbBk;
1217 imldp.rgbFg = rgbFg;
1218 imldp.fStyle = fStyle;
1221 return ImageList_DrawIndirect (&imldp);
1225 /*************************************************************************
1226 * ImageList_DrawIndirect [COMCTL32.52]
1228 * Draws an image using ...
1231 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1239 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1243 Do some Error Checking
1247 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1249 if (pimldp->himl == NULL)
1251 if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage)) {
1252 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage);
1256 Get the Height and Width to display
1258 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1259 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1263 if(pimldp->himl->hbmMask != 0)
1265 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1269 IMAGELIST_InternalDraw(pimldp, cx, cy);
1272 Apply the blend if needed to the Image
1274 if((pimldp->fStyle & ILD_BLEND50)
1275 || (pimldp->fStyle & ILD_BLEND25))
1277 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1280 Apply the Overlay if needed
1282 if (pimldp->fStyle & ILD_OVERLAYMASK)
1284 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1291 /*************************************************************************
1292 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1295 * himlSrc [I] source image list handle
1298 * Success: Handle of duplicated image list.
1303 ImageList_Duplicate (HIMAGELIST himlSrc)
1308 if (himlSrc == NULL) {
1309 ERR("Invalid image list handle!\n");
1313 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1314 himlSrc->cInitial, himlSrc->cGrow);
1318 hdcSrc = CreateCompatibleDC (0);
1319 hdcDst = CreateCompatibleDC (0);
1320 SelectObject (hdcSrc, himlSrc->hbmImage);
1321 SelectObject (hdcDst, himlDst->hbmImage);
1322 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1323 hdcSrc, 0, 0, SRCCOPY);
1325 if (himlDst->hbmMask)
1327 SelectObject (hdcSrc, himlSrc->hbmMask);
1328 SelectObject (hdcDst, himlDst->hbmMask);
1329 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1330 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1336 himlDst->cCurImage = himlSrc->cCurImage;
1337 himlDst->cMaxImage = himlSrc->cMaxImage;
1343 /*************************************************************************
1344 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1346 * Finishes a drag operation.
1360 ImageList_EndDrag (void)
1362 FIXME("semi-stub!\n");
1364 if (himlInternalDrag)
1367 ImageList_Destroy (himlInternalDrag);
1368 himlInternalDrag = NULL;
1370 nInternalDragHotspotX = 0;
1371 nInternalDragHotspotY = 0;
1379 /*************************************************************************
1380 * ImageList_GetBkColor [COMCTL32.55]
1382 * Returns the background color of an image list.
1385 * himl [I] Image list handle.
1388 * Success: background color
1393 ImageList_GetBkColor (HIMAGELIST himl)
1402 /*************************************************************************
1403 * ImageList_GetDragImage [COMCTL32.56]
1405 * Returns the handle to the internal drag image list.
1408 * ppt [O] Pointer to the drag position. Can be NULL.
1409 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1412 * Success: Handle of the drag image list.
1420 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1422 FIXME("semi-stub!\n");
1424 if (himlInternalDrag)
1425 return (himlInternalDrag);
1431 /*************************************************************************
1432 * ImageList_GetIcon [COMCTL32.57]
1434 * Creates an icon from a masked image of an image list.
1437 * himl [I] handle to image list
1439 * flags [I] drawing style flags
1442 * Success: icon handle
1447 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1451 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1454 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1455 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1459 hdcSrc = CreateCompatibleDC(0);
1460 hdcDst = CreateCompatibleDC(0);
1463 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1466 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1467 if (himl->hbmMask) {
1468 SelectObject (hdcSrc, himl->hbmMask);
1469 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1470 hdcSrc, i * himl->cx, 0, SRCCOPY);
1473 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1476 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1477 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1478 SelectObject (hdcDst, ii.hbmColor);
1479 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1480 hdcSrc, i * himl->cx, 0, SRCCOPY);
1483 * CreateIconIndirect requires us to deselect the bitmaps from
1484 * the DCs before calling
1486 SelectObject(hdcSrc, hOldSrcBitmap);
1487 SelectObject(hdcDst, hOldDstBitmap);
1489 hIcon = CreateIconIndirect (&ii);
1493 DeleteObject (ii.hbmMask);
1494 DeleteObject (ii.hbmColor);
1500 /*************************************************************************
1501 * ImageList_GetIconSize [COMCTL32.58]
1503 * Retrieves the size of an image in an image list.
1506 * himl [I] handle to image list
1507 * cx [O] pointer to the image width.
1508 * cy [O] pointer to the image height.
1515 * All images in an image list have the same size.
1519 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1523 if ((himl->cx <= 0) || (himl->cy <= 0))
1535 /*************************************************************************
1536 * ImageList_GetImageCount [COMCTL32.59]
1538 * Returns the number of images in an image list.
1541 * himl [I] handle to image list
1544 * Success: Number of images.
1549 ImageList_GetImageCount (HIMAGELIST himl)
1554 return himl->cCurImage;
1558 /*************************************************************************
1559 * ImageList_GetImageInfo [COMCTL32.60]
1561 * Returns information about an image in an image list.
1564 * himl [I] handle to image list
1566 * pImageInfo [O] pointer to the image information
1574 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1576 if ((himl == NULL) || (pImageInfo == NULL))
1578 if ((i < 0) || (i >= himl->cCurImage))
1581 pImageInfo->hbmImage = himl->hbmImage;
1582 pImageInfo->hbmMask = himl->hbmMask;
1584 pImageInfo->rcImage.top = 0;
1585 pImageInfo->rcImage.bottom = himl->cy;
1586 pImageInfo->rcImage.left = i * himl->cx;
1587 pImageInfo->rcImage.right = (i+1) * himl->cx;
1593 /*************************************************************************
1594 * ImageList_GetImageRect [COMCTL32.61]
1596 * Retrieves the rectangle of the specified image in an image list.
1599 * himl [I] handle to image list
1601 * lpRect [O] pointer to the image rectangle
1608 * This is an UNDOCUMENTED function!!!
1612 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1614 if ((himl == NULL) || (lpRect == NULL))
1616 if ((i < 0) || (i >= himl->cCurImage))
1619 lpRect->left = i * himl->cx;
1621 lpRect->right = lpRect->left + himl->cx;
1622 lpRect->bottom = himl->cy;
1628 /*************************************************************************
1629 * ImageList_LoadImageA [COMCTL32.63][COMCTL32.62]
1631 * Creates an image list from a bitmap, icon or cursor.
1634 * hi [I] instance handle
1635 * lpbmp [I] name or id of the image
1636 * cx [I] width of each image
1637 * cGrow [I] number of images to expand
1638 * clrMask [I] mask color
1639 * uType [I] type of image to load
1640 * uFlags [I] loading flags
1643 * Success: handle to the loaded image list
1651 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1652 COLORREF clrMask, UINT uType, UINT uFlags)
1654 HIMAGELIST himl = NULL;
1658 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1660 ERR("Error loading image!\n");
1664 if (uType == IMAGE_BITMAP) {
1666 GetObjectA (handle, sizeof(BITMAP), &bmp);
1668 /* To match windows behavior, if cx is set to zero and
1669 the flag DI_DEFAULTSIZE is specified, cx becomes the
1670 system metric value for icons. If the flag is not specified
1671 the function sets the size to the height of the bitmap */
1674 if (uFlags & DI_DEFAULTSIZE)
1675 cx = GetSystemMetrics (SM_CXICON);
1680 nImageCount = bmp.bmWidth / cx;
1682 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1683 nImageCount, cGrow);
1684 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1686 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1690 GetIconInfo (handle, &ii);
1691 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1692 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1693 ILC_MASK | ILC_COLOR, 1, cGrow);
1694 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1695 DeleteObject (ii.hbmColor);
1696 DeleteObject (ii.hbmMask);
1699 DeleteObject (handle);
1705 /*************************************************************************
1706 * ImageList_LoadImageW [COMCTL32.64]
1708 * Creates an image list from a bitmap, icon or cursor.
1711 * hi [I] instance handle
1712 * lpbmp [I] name or id of the image
1713 * cx [I] width of each image
1714 * cGrow [I] number of images to expand
1715 * clrMask [I] mask color
1716 * uType [I] type of image to load
1717 * uFlags [I] loading flags
1720 * Success: handle to the loaded image list
1728 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1729 COLORREF clrMask, UINT uType, UINT uFlags)
1731 HIMAGELIST himl = NULL;
1735 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1737 ERR("Error loading image!\n");
1741 if (uType == IMAGE_BITMAP) {
1743 GetObjectA (handle, sizeof(BITMAP), &bmp);
1744 nImageCount = bmp.bmWidth / cx;
1746 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1747 nImageCount, cGrow);
1748 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1750 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1754 GetIconInfo (handle, &ii);
1755 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1756 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1757 ILC_MASK | ILC_COLOR, 1, cGrow);
1758 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1759 DeleteObject (ii.hbmColor);
1760 DeleteObject (ii.hbmMask);
1763 DeleteObject (handle);
1769 /*************************************************************************
1770 * ImageList_Merge [COMCTL32.65]
1772 * Creates a new image list that contains a merged image from the specified
1773 * images of both source image lists.
1776 * himl1 [I] handle to first image list
1777 * i1 [I] first image index
1778 * himl2 [I] handle to second image list
1779 * i2 [I] second image index
1780 * dx [I] X offset of the second image relative to the first.
1781 * dy [I] Y offset of the second image relative to the first.
1784 * Success: handle of the merged image list.
1789 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1792 HIMAGELIST himlDst = NULL;
1793 HDC hdcSrcImage, hdcDstImage;
1795 INT xOff1, yOff1, xOff2, yOff2;
1798 if ((himl1 == NULL) || (himl2 == NULL))
1802 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1803 ERR("Index 1 out of range! %d\n", i1);
1807 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1808 ERR("Index 2 out of range! %d\n", i2);
1813 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1818 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1823 cxDst = _MAX (himl1->cx, himl2->cx);
1829 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1834 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1839 cyDst = _MAX (himl1->cy, himl2->cy);
1844 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1847 hdcSrcImage = CreateCompatibleDC (0);
1848 hdcDstImage = CreateCompatibleDC (0);
1849 nX1 = i1 * himl1->cx;
1850 nX2 = i2 * himl2->cx;
1853 SelectObject (hdcSrcImage, himl1->hbmImage);
1854 SelectObject (hdcDstImage, himlDst->hbmImage);
1855 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1856 hdcSrcImage, 0, 0, BLACKNESS);
1857 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1858 hdcSrcImage, nX1, 0, SRCCOPY);
1860 SelectObject (hdcSrcImage, himl2->hbmMask);
1861 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1862 hdcSrcImage, nX2, 0, SRCAND);
1864 SelectObject (hdcSrcImage, himl2->hbmImage);
1865 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1866 hdcSrcImage, nX2, 0, SRCPAINT);
1869 SelectObject (hdcSrcImage, himl1->hbmMask);
1870 SelectObject (hdcDstImage, himlDst->hbmMask);
1871 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1872 hdcSrcImage, 0, 0, WHITENESS);
1873 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1874 hdcSrcImage, nX1, 0, SRCCOPY);
1876 SelectObject (hdcSrcImage, himl2->hbmMask);
1877 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1878 hdcSrcImage, nX2, 0, SRCAND);
1880 DeleteDC (hdcSrcImage);
1881 DeleteDC (hdcDstImage);
1888 /* helper for _read_bitmap currently unused */
1890 static int may_use_dibsection(HDC hdc) {
1891 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1896 return GetDeviceCaps(hdc,94) & 0x10;
1900 /* helper for ImageList_Read, see comments below */
1901 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1903 BITMAPFILEHEADER bmfh;
1904 BITMAPINFOHEADER bmih;
1905 int bitsperpixel,palspace,longsperline,width,height;
1906 LPBITMAPINFOHEADER bmihc = NULL;
1908 HBITMAP hbitmap = 0;
1909 LPBYTE bits = NULL,nbits = NULL;
1910 int nbytesperline,bytesperline;
1912 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1913 (bmfh.bfType != (('M'<<8)|'B')) ||
1914 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1915 (bmih.biSize != sizeof(bmih))
1919 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1920 if (bitsperpixel<=8)
1921 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1924 width = bmih.biWidth;
1925 height = bmih.biHeight;
1926 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1927 memcpy(bmihc,&bmih,sizeof(bmih));
1928 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1929 bmihc->biSizeImage = (longsperline*height)<<2;
1931 /* read the palette right after the end of the bitmapinfoheader */
1933 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1937 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1938 if ((bitsperpixel>1) &&
1939 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1941 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1944 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1950 int i,nwidth,nheight;
1952 nwidth = width*(height/cy);
1955 if (bitsperpixel==1)
1956 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1958 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1960 /* Might be a bit excessive memory use here */
1961 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1962 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1963 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1966 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1967 /* Do not forget that windows bitmaps are bottom->top */
1968 bytesperline = longsperline*4;
1969 nbytesperline = (height/cy)*bytesperline;
1970 for (i=0;i<height;i++) {
1972 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1973 bits+bytesperline*(height-1-i),
1977 bmihc->biWidth = nwidth;
1978 bmihc->biHeight = nheight;
1979 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1981 LocalFree((HLOCAL)nbits);
1982 LocalFree((HLOCAL)bits);
1986 if (xdc) ReleaseDC(0,xdc);
1987 if (bmihc) LocalFree((HLOCAL)bmihc);
1990 DeleteObject(hbitmap);
1997 /*************************************************************************
1998 * ImageList_Read [COMCTL32.66]
2000 * Reads an image list from a stream.
2003 * pstm [I] pointer to a stream
2006 * Success: handle to image list
2009 * The format is like this:
2010 * ILHEAD ilheadstruct;
2012 * for the color image part:
2013 * BITMAPFILEHEADER bmfh;
2014 * BITMAPINFOHEADER bmih;
2015 * only if it has a palette:
2016 * RGBQUAD rgbs[nr_of_paletted_colors];
2018 * BYTE colorbits[imagesize];
2020 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2021 * BITMAPFILEHEADER bmfh_mask;
2022 * BITMAPINFOHEADER bmih_mask;
2023 * only if it has a palette (it usually does not):
2024 * RGBQUAD rgbs[nr_of_paletted_colors];
2026 * BYTE maskbits[imagesize];
2028 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2029 * _read_bitmap needs to convert them.
2031 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2035 HBITMAP hbmColor=0,hbmMask=0;
2038 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2040 if (ilHead.usMagic != (('L' << 8) | 'I'))
2042 if (ilHead.usVersion != 0x101) /* probably version? */
2046 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2047 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2048 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2049 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2050 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2051 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2052 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2053 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2054 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2055 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2058 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2061 if (ilHead.flags & ILC_MASK) {
2062 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2064 DeleteObject(hbmColor);
2069 himl = ImageList_Create (
2077 DeleteObject(hbmColor);
2078 DeleteObject(hbmMask);
2081 himl->hbmImage = hbmColor;
2082 himl->hbmMask = hbmMask;
2083 himl->cCurImage = ilHead.cCurImage;
2084 himl->cMaxImage = ilHead.cMaxImage;
2086 ImageList_SetBkColor(himl,ilHead.bkcolor);
2088 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2093 /*************************************************************************
2094 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2097 * himl [I] image list handle
2106 ImageList_Remove (HIMAGELIST himl, INT i)
2108 HBITMAP hbmNewImage, hbmNewMask;
2112 if ((i < -1) || (i >= himl->cCurImage)) {
2113 ERR("index out of range! %d\n", i);
2117 if (himl->cCurImage == 0) {
2118 ERR("image list is already empty!\n");
2124 TRACE("remove all!\n");
2126 himl->cMaxImage = himl->cInitial + himl->cGrow;
2127 himl->cCurImage = 0;
2128 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2129 himl->nOvlIdx[nCount] = -1;
2131 DeleteObject (himl->hbmImage);
2133 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2134 1, himl->uBitsPixel, NULL);
2136 if (himl->hbmMask) {
2137 DeleteObject (himl->hbmMask);
2139 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2144 /* delete one image */
2145 TRACE("Remove single image! %d\n", i);
2147 /* create new bitmap(s) */
2148 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2150 TRACE(" - Number of images: %d / %d (Old/New)\n",
2151 himl->cCurImage, himl->cCurImage - 1);
2152 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2153 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2156 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2159 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2161 hbmNewMask = 0; /* Just to keep compiler happy! */
2163 hdcSrc = CreateCompatibleDC (0);
2164 hdcDst = CreateCompatibleDC (0);
2166 /* copy all images and masks prior to the "removed" image */
2168 TRACE("Pre image copy: Copy %d images\n", i);
2170 SelectObject (hdcSrc, himl->hbmImage);
2171 SelectObject (hdcDst, hbmNewImage);
2172 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2173 hdcSrc, 0, 0, SRCCOPY);
2175 if (himl->hbmMask) {
2176 SelectObject (hdcSrc, himl->hbmMask);
2177 SelectObject (hdcDst, hbmNewMask);
2178 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2179 hdcSrc, 0, 0, SRCCOPY);
2183 /* copy all images and masks behind the removed image */
2184 if (i < himl->cCurImage - 1) {
2185 TRACE("Post image copy!\n");
2186 SelectObject (hdcSrc, himl->hbmImage);
2187 SelectObject (hdcDst, hbmNewImage);
2188 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2189 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2191 if (himl->hbmMask) {
2192 SelectObject (hdcSrc, himl->hbmMask);
2193 SelectObject (hdcDst, hbmNewMask);
2194 BitBlt (hdcDst, i * himl->cx, 0,
2195 (himl->cCurImage - i - 1) * himl->cx,
2196 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2203 /* delete old images and insert new ones */
2204 DeleteObject (himl->hbmImage);
2205 himl->hbmImage = hbmNewImage;
2206 if (himl->hbmMask) {
2207 DeleteObject (himl->hbmMask);
2208 himl->hbmMask = hbmNewMask;
2212 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2219 /*************************************************************************
2220 * ImageList_Replace [COMCTL32.68]
2222 * Replaces an image in an image list with a new image.
2225 * himl [I] handle to image list
2227 * hbmImage [I] handle to image bitmap
2228 * hbmMask [I] handle to mask bitmap. Can be NULL.
2236 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2239 HDC hdcImageList, hdcImage;
2243 ERR("Invalid image list handle!\n");
2247 if ((i >= himl->cMaxImage) || (i < 0)) {
2248 ERR("Invalid image index!\n");
2252 hdcImageList = CreateCompatibleDC (0);
2253 hdcImage = CreateCompatibleDC (0);
2254 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2257 SelectObject (hdcImageList, himl->hbmImage);
2258 SelectObject (hdcImage, hbmImage);
2260 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2261 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2266 SelectObject (hdcImageList, himl->hbmMask);
2267 SelectObject (hdcImage, hbmMask);
2269 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2270 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2273 /* Remove the background from the image
2275 SelectObject (hdcImageList, himl->hbmImage);
2276 StretchBlt (hdcImageList,
2277 i*himl->cx, 0, himl->cx, himl->cy,
2279 0, 0, bmp.bmWidth, bmp.bmHeight,
2280 0x220326); /* NOTSRCAND */
2283 DeleteDC (hdcImage);
2284 DeleteDC (hdcImageList);
2290 /*************************************************************************
2291 * ImageList_ReplaceIcon [COMCTL32.69]
2293 * Replaces an image in an image list using an icon.
2296 * himl [I] handle to image list
2298 * hIcon [I] handle to icon
2301 * Success: index of the replaced image
2306 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2308 HDC hdcImageList, hdcImage;
2311 HBITMAP hbmOldSrc, hbmOldDst;
2315 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2319 if ((i >= himl->cMaxImage) || (i < -1))
2322 hBestFitIcon = CopyImage(
2325 LR_COPYFROMRESOURCE);
2327 GetIconInfo (hBestFitIcon, &ii);
2328 if (ii.hbmMask == 0)
2330 if (ii.hbmColor == 0)
2332 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2335 if (himl->cCurImage + 1 >= himl->cMaxImage)
2336 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2338 nIndex = himl->cCurImage;
2344 hdcImageList = CreateCompatibleDC (0);
2345 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2346 if (hdcImageList == 0)
2347 ERR("invalid hdcImageList!\n");
2349 hdcImage = CreateCompatibleDC (0);
2350 TRACE("hdcImage=0x%x!\n", hdcImage);
2352 ERR("invalid hdcImage!\n");
2354 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2355 SetTextColor( hdcImageList, RGB(0,0,0));
2356 SetBkColor( hdcImageList, RGB(255,255,255));
2357 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2358 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2359 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2361 if (himl->hbmMask) {
2362 SelectObject (hdcImageList, himl->hbmMask);
2363 SelectObject (hdcImage, ii.hbmMask);
2364 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2365 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2368 SelectObject (hdcImage, hbmOldSrc);
2369 SelectObject (hdcImageList, hbmOldDst);
2372 DestroyIcon(hBestFitIcon);
2374 DeleteDC (hdcImageList);
2376 DeleteDC (hdcImage);
2378 DeleteObject (ii.hbmColor);
2380 DeleteObject (ii.hbmMask);
2386 /*************************************************************************
2387 * ImageList_SetBkColor [COMCTL32.70]
2389 * Sets the background color of an image list.
2392 * himl [I] handle to image list
2393 * clrBk [I] background color
2396 * Success: previous background color
2401 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2408 clrOldBk = himl->clrBk;
2409 himl->clrBk = clrBk;
2414 /*************************************************************************
2415 * ImageList_SetDragCursorImage [COMCTL32.75]
2417 * Combines the specified image with the current drag image
2420 * himlDrag [I] handle to drag image list
2421 * iDrag [I] drag image index
2422 * dxHotspot [I] X position of the hot spot
2423 * dyHotspot [I] Y position of the hot spot
2434 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2435 INT dxHotspot, INT dyHotspot)
2437 HIMAGELIST himlTemp;
2439 FIXME("semi-stub!\n");
2441 if (himlInternalDrag == NULL)
2444 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2445 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2447 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2448 dxHotspot, dyHotspot);
2450 ImageList_Destroy (himlInternalDrag);
2451 himlInternalDrag = himlTemp;
2453 nInternalDragHotspotX = dxHotspot;
2454 nInternalDragHotspotY = dyHotspot;
2460 /*************************************************************************
2461 * ImageList_SetFilter [COMCTL32.76]
2463 * Sets a filter (or does something completely different)!!???
2466 * himl [I] handle to image list
2472 * Failure: FALSE ???
2475 * This is an UNDOCUMENTED function!!!!
2480 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2482 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2489 /*************************************************************************
2490 * ImageList_SetIconSize [COMCTL32.77]
2492 * Sets the image size of the bitmap and deletes all images.
2495 * himl [I] handle to image list
2496 * cx [I] image width
2497 * cy [I] image height
2505 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2512 /* remove all images */
2513 himl->cMaxImage = himl->cInitial + himl->cGrow;
2514 himl->cCurImage = 0;
2518 /* initialize overlay mask indices */
2519 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2520 himl->nOvlIdx[nCount] = -1;
2522 DeleteObject (himl->hbmImage);
2524 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2525 1, himl->uBitsPixel, NULL);
2527 if (himl->hbmMask) {
2528 DeleteObject (himl->hbmMask);
2530 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2538 /*************************************************************************
2539 * ImageList_SetImageCount [COMCTL32.78]
2541 * Resizes an image list to the specified number of images.
2544 * himl [I] handle to image list
2545 * iImageCount [I] number of images in the image list
2553 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2555 HDC hdcImageList, hdcBitmap;
2556 HBITMAP hbmNewBitmap;
2557 INT nNewCount, nCopyCount;
2561 if (himl->cCurImage >= iImageCount)
2563 if (himl->cMaxImage > iImageCount)
2566 nNewCount = iImageCount + himl->cGrow;
2567 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2569 hdcImageList = CreateCompatibleDC (0);
2570 hdcBitmap = CreateCompatibleDC (0);
2572 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2573 1, himl->uBitsPixel, NULL);
2574 if (hbmNewBitmap != 0)
2576 SelectObject (hdcImageList, himl->hbmImage);
2577 SelectObject (hdcBitmap, hbmNewBitmap);
2580 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2581 hdcImageList, 0, 0, SRCCOPY);
2583 /* delete 'empty' image space */
2584 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2585 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2586 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2587 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2589 DeleteObject (himl->hbmImage);
2590 himl->hbmImage = hbmNewBitmap;
2593 ERR("Could not create new image bitmap !\n");
2597 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2599 if (hbmNewBitmap != 0)
2601 SelectObject (hdcImageList, himl->hbmMask);
2602 SelectObject (hdcBitmap, hbmNewBitmap);
2605 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2606 hdcImageList, 0, 0, SRCCOPY);
2608 /* delete 'empty' image space */
2609 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2610 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2611 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2612 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2614 DeleteObject (himl->hbmMask);
2615 himl->hbmMask = hbmNewBitmap;
2618 ERR("Could not create new mask bitmap!\n");
2621 DeleteDC (hdcImageList);
2622 DeleteDC (hdcBitmap);
2624 /* Update max image count and current image count */
2625 himl->cMaxImage = nNewCount;
2626 if (himl->cCurImage > nCopyCount)
2627 himl->cCurImage = nCopyCount;
2633 /*************************************************************************
2634 * ImageList_SetOverlayImage [COMCTL32.79]
2636 * Assigns an overlay mask index to an existing image in an image list.
2639 * himl [I] handle to image list
2640 * iImage [I] image index
2641 * iOverlay [I] overlay mask index
2649 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2653 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2655 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2657 himl->nOvlIdx[iOverlay - 1] = iImage;
2662 /*************************************************************************
2663 * ImageList_Write [COMCTL32.80]
2665 * Writes an image list to a stream.
2668 * himl [I] handle to image list
2669 * pstm [O] Pointer to a stream.
2676 * This function can not be implemented yet, because
2677 * IStream32::Write is not implemented.
2684 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2689 FIXME("empty stub!\n");