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 imlemented, the functions mentioned above will be
22 * limited in functionality too.
25 #include "wine/obj_base.h"
26 #include "wine/obj_storage.h"
28 #include "imagelist.h"
29 #include "debugtools.h"
32 DEFAULT_DEBUG_CHANNEL(imagelist);
35 #define _MAX(a,b) (((a)>(b))?(a):(b))
36 #define _MIN(a,b) (((a)>(b))?(b):(a))
38 #define MAX_OVERLAYIMAGE 15
41 /* internal image list data used for Drag & Drop operations */
43 static HIMAGELIST himlInternalDrag = NULL;
44 static INT nInternalDragHotspotX = 0;
45 static INT nInternalDragHotspotY = 0;
47 static HWND hwndInternalDrag = 0;
48 static INT xInternalPos = 0;
49 static INT yInternalPos = 0;
51 static HDC hdcBackBuffer = 0;
52 static HBITMAP hbmBackBuffer = 0;
55 /*************************************************************************
56 * IMAGELIST_InternalExpandBitmaps [Internal]
58 * Expands the bitmaps of an image list by the given number of images.
61 * himl [I] handle to image list
62 * nImageCount [I] number of images to add
68 * This function can NOT be used to reduce the number of images.
71 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
73 HDC hdcImageList, hdcBitmap;
75 INT nNewWidth, nNewCount;
77 if ((himl->cCurImage + nImageCount < himl->cMaxImage)
81 if (cy == 0) cy = himl->cy;
82 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
83 nNewWidth = nNewCount * himl->cx;
85 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
86 hdcImageList = CreateCompatibleDC (0);
87 hdcBitmap = CreateCompatibleDC (0);
90 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
91 if (hbmNewBitmap == 0)
92 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
94 SelectObject (hdcImageList, himl->hbmImage);
95 SelectObject (hdcBitmap, hbmNewBitmap);
96 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
97 hdcImageList, 0, 0, SRCCOPY);
99 DeleteObject (himl->hbmImage);
100 himl->hbmImage = hbmNewBitmap;
104 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
106 if (hbmNewBitmap == 0)
107 ERR("creating new mask bitmap!\n");
109 SelectObject (hdcImageList, himl->hbmMask);
110 SelectObject (hdcBitmap, hbmNewBitmap);
111 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
112 hdcImageList, 0, 0, SRCCOPY);
113 DeleteObject (himl->hbmMask);
114 himl->hbmMask = hbmNewBitmap;
117 himl->cMaxImage = nNewCount;
119 DeleteDC (hdcImageList);
120 DeleteDC (hdcBitmap);
124 /*************************************************************************
125 * IMAGELIST_InternalDraw [Internal]
127 * Draws the image in the ImageList (without the mask)
130 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
131 * cx [I] the width of the image to display
132 * cy............[I] the height of the image to display
138 * This functions is used by ImageList_DrawIndirect, when it is
139 * required to draw only the Image (without the mask) to the screen.
141 * Blending and Overlays styles are accomplised by another function
144 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
149 hImageDC = CreateCompatibleDC(0);
150 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
151 BitBlt(pimldp->hdcDst,
152 pimldp->x, pimldp->y, cx, cy,
154 pimldp->himl->cx * pimldp->i, 0,
157 SelectObject(hImageDC, hOldBitmap);
162 /*************************************************************************
163 * IMAGELIST_InternalDrawMask [Internal]
165 * Draws the image in the ImageList witht the mask
168 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
169 * cx [I] the width of the image to display
170 * cy............[I] the height of the image to display
176 * This functions is used by ImageList_DrawIndirect, when it is
177 * required to draw the Image with the mask to the screen.
179 * Blending and Overlays styles are accomplised by another function.
182 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
184 HDC hMaskDC, hImageDC;
185 BOOL bUseCustomBackground, bBlendFlag;
186 HBRUSH hBrush, hOldBrush;
187 HBITMAP hOldBitmapImage, hOldBitmapMask;
188 HIMAGELIST himlLocal = pimldp->himl;
189 COLORREF oldBkColor, oldFgColor;
190 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
192 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
193 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
195 hImageDC = CreateCompatibleDC(0);
196 hMaskDC = CreateCompatibleDC(0);
198 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
199 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
200 /* Draw the Background for the appropriate Styles
202 if( bUseCustomBackground &&
203 (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE || bBlendFlag))
205 hBrush = CreateSolidBrush (himlLocal->clrBk);
206 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
207 PatBlt (pimldp->hdcDst,
208 pimldp->x, pimldp->y, cx, cy,
211 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
214 /* Draw Image Transparently over the current background
216 if(fStyle == ILD_NORMAL
217 || (fStyle & ILD_TRANSPARENT)
218 || ((fStyle & ILD_IMAGE) && bUseCustomBackground)
221 /* to obtain a transparent look, background color should be set
222 to white and foreground color to black when blting the
224 oldBkColor = SetBkColor(pimldp->hdcDst, RGB(0xff, 0xff, 0xff));
225 oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 0));
227 BitBlt(pimldp->hdcDst,
228 pimldp->x, pimldp->y, cx, cy,
230 himlLocal->cx * pimldp->i, 0,
233 BitBlt(pimldp->hdcDst,
234 pimldp->x, pimldp->y, cx, cy,
236 himlLocal->cx * pimldp->i, 0,
239 SetBkColor(pimldp->hdcDst, oldBkColor);
240 SetTextColor(pimldp->hdcDst, oldFgColor);
242 /* Draw the image when no Background is specified
244 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
246 BitBlt(pimldp->hdcDst,
247 pimldp->x, pimldp->y, cx, cy,
249 himlLocal->cx * pimldp->i, 0,
252 /* Draw the mask with or without a background
254 else if(fStyle & ILD_MASK)
256 BitBlt(pimldp->hdcDst,
257 pimldp->x, pimldp->y, cx, cy,
259 himlLocal->cx * pimldp->i, 0,
260 bUseCustomBackground ? SRCCOPY : SRCAND);
262 SelectObject(hImageDC, hOldBitmapImage);
263 SelectObject(hMaskDC, hOldBitmapMask);
268 /*************************************************************************
269 * IMAGELIST_InternalDrawBlend [Internal]
271 * Draws the Blend over the current image
274 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
275 * cx [I] the width of the image to display
276 * cy............[I] the height of the image to display
282 * This functions is used by ImageList_DrawIndirect, when it is
283 * required to add the blend to the current image.
287 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
290 HDC hBlendMaskDC,hMaskDC;
291 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
292 HBITMAP hBlendMaskBitmap, hOldBitmap;
293 COLORREF clrBlend, OldTextColor, OldBkColor;
294 HIMAGELIST himlLocal = pimldp->himl;
296 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
297 if (!(pimldp->rgbFg == CLR_DEFAULT))
299 clrBlend = pimldp->rgbFg;
301 /* Create the blend Mask
303 hBlendMaskDC = CreateCompatibleDC(0);
304 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
305 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
307 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
308 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
310 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
311 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
312 SelectObject(hBlendMaskDC, hOldBrush);
314 /* Modify the blend mask if an Image Mask exist
316 if(pimldp->himl->hbmMask != 0)
318 HBITMAP hOldMaskBitmap;
319 hMaskDC = CreateCompatibleDC(0);
320 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
325 himlLocal->cx * pimldp->i,0,
326 0x220326); /* NOTSRCAND */
334 SelectObject(hMaskDC, hOldMaskBitmap);
338 /* Apply blend to the current image given the BlendMask
340 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
341 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
342 hBlendColorBrush = CreateSolidBrush(clrBlend);
343 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
345 BitBlt (pimldp->hdcDst,
346 pimldp->x, pimldp->y, cx, cy,
349 0xB8074A); /* PSDPxax */
351 SelectObject(pimldp->hdcDst, hOldBrush);
352 SetTextColor(pimldp->hdcDst, OldTextColor);
353 SetBkColor(pimldp->hdcDst, OldBkColor);
354 SelectObject(hBlendMaskDC, hOldBitmap);
355 DeleteDC(hBlendMaskDC);
356 DeleteObject(hBlendMaskBitmap);
357 DeleteObject(hBlendColorBrush);
360 /*************************************************************************
361 * IMAGELIST_InternalDrawOverlay [Internal]
363 * Draws the overlay image
366 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
367 * cx [I] the width of the image to display
368 * cy............[I] the height of the image to display
374 * This functions is used by ImageList_DrawIndirect, when it is
375 * required to draw the overlay
380 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
386 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
387 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
389 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
390 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
392 hImageDC = CreateCompatibleDC(0);
393 if (pimldp->himl->hbmMask)
395 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
396 pimldp->himl->hbmMask);
398 BitBlt (pimldp->hdcDst,
399 pimldp->x, pimldp->y, cx, cy,
400 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
403 SelectObject(hImageDC, hOldBitmap);
405 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
406 pimldp->himl->hbmImage);
408 BitBlt (pimldp->hdcDst,
409 pimldp->x, pimldp->y, cx, cy,
411 pimldp->himl->cx * nOvlIdx, 0,
414 SelectObject(hImageDC, hOldBitmap);
424 /*************************************************************************
425 * ImageList_Add [COMCTL32.39]
427 * Add an image or images to an image list.
430 * himl [I] handle to image list
431 * hbmImage [I] handle to image bitmap
432 * hbmMask [I] handle to mask bitmap
435 * Success: Index of the first new image.
440 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
442 HDC hdcImage, hdcBitmap;
443 INT nFirstIndex, nImageCount;
446 HBITMAP hOldBitmapImage, hOldBitmap;
448 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
449 if (!himl || !hbmImage)
452 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
453 nImageCount = bmp.bmWidth / himl->cx;
455 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
457 nStartX = himl->cCurImage * himl->cx;
459 hdcImage = CreateCompatibleDC(0);
460 hdcBitmap = CreateCompatibleDC(0);
462 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
463 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
465 /* Copy result to the imagelist
467 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
468 hdcBitmap, 0, 0, SRCCOPY);
472 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
474 hdcMask = CreateCompatibleDC (0);
475 hdcTemp = CreateCompatibleDC(0);
476 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
477 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
480 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
485 SelectObject(hdcTemp, hOldBitmapTemp);
488 /* Remove the background from the image
491 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
494 0x220326); /* NOTSRCAND */
496 SelectObject(hdcMask, hOldBitmapMask);
500 SelectObject(hdcImage, hOldBitmapImage);
501 SelectObject(hdcBitmap, hOldBitmap);
505 nFirstIndex = himl->cCurImage;
506 himl->cCurImage += nImageCount;
512 /*************************************************************************
513 * ImageList_AddIcon [COMCTL32.40]
515 * Adds an icon to an image list.
518 * himl [I] handle to image list
519 * hIcon [I] handle to icon
522 * Success: index of the new image
527 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
529 return ImageList_ReplaceIcon (himl, -1, hIcon);
533 /*************************************************************************
534 * ImageList_AddMasked [COMCTL32.41]
536 * Adds an image or images to an image list and creates a mask from the
537 * specified bitmap using the mask color.
540 * himl [I] handle to image list.
541 * hBitmap [I] handle to bitmap
542 * clrMask [I] mask color.
545 * Success: Index of the first new image.
550 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
552 HDC hdcImage, hdcMask, hdcBitmap;
553 INT nIndex, nImageCount, nMaskXOffset=0;
555 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
556 HBITMAP hMaskBitmap=0;
559 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
563 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
566 nImageCount = bmp.bmWidth / himl->cx;
568 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
570 nIndex = himl->cCurImage;
571 himl->cCurImage += nImageCount;
573 hdcMask = CreateCompatibleDC (0);
574 hdcImage = CreateCompatibleDC(0);
575 hdcBitmap = CreateCompatibleDC(0);
578 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
579 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
582 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
583 nMaskXOffset = nIndex * himl->cx;
588 Create a temp Mask so we can remove the background of
589 the Image (Windows does this even if there is no mask)
591 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
592 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
595 /* create monochrome image to the mask bitmap */
596 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
597 GetPixel (hdcBitmap, 0, 0);
598 SetBkColor (hdcBitmap, bkColor);
600 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
604 SetBkColor(hdcBitmap, RGB(255,255,255));
605 /*Remove the background from the image
608 WINDOWS BUG ALERT!!!!!!
609 The statement below should not be done in common practice
610 but this is how ImageList_AddMasked works in Windows.
611 It overwrites the original bitmap passed, this was discovered
612 by using the same bitmap to itterated the different styles
613 on windows where it failed (BUT ImageList_Add is OK)
614 This is here in case some apps really on this bug
617 0, 0, bmp.bmWidth, bmp.bmHeight,
620 0x220326); /* NOTSRCAND */
621 /* Copy result to the imagelist
624 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
630 SelectObject(hdcMask,hOldBitmapMask);
631 SelectObject(hdcImage, hOldBitmapImage);
632 SelectObject(hdcBitmap, hOldBitmap);
638 DeleteObject(hMaskBitmap);
645 /*************************************************************************
646 * ImageList_BeginDrag [COMCTL32.42]
648 * Creates a temporary image list that contains one image. It will be used
652 * himlTrack [I] handle to the source image list
653 * iTrack [I] index of the drag image in the source image list
654 * dxHotspot [I] X position of the hot spot of the drag image
655 * dyHotspot [I] Y position of the hot spot of the drag image
663 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
664 INT dxHotspot, INT dyHotspot)
668 FIXME("partially implemented!\n");
670 if (himlTrack == NULL)
673 if (himlInternalDrag)
674 ImageList_EndDrag ();
677 ImageList_Create (himlTrack->cx, himlTrack->cy,
678 himlTrack->flags, 1, 1);
679 if (himlInternalDrag == NULL) {
680 ERR("Error creating drag image list!\n");
684 nInternalDragHotspotX = dxHotspot;
685 nInternalDragHotspotY = dyHotspot;
687 hdcSrc = CreateCompatibleDC (0);
688 hdcDst = CreateCompatibleDC (0);
691 SelectObject (hdcSrc, himlTrack->hbmImage);
692 SelectObject (hdcDst, himlInternalDrag->hbmImage);
693 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
694 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
697 SelectObject (hdcSrc, himlTrack->hbmMask);
698 SelectObject (hdcDst, himlInternalDrag->hbmMask);
699 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
700 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
705 himlInternalDrag->cCurImage = 1;
711 /*************************************************************************
712 * ImageList_Copy [COMCTL32.43]
714 * Copies an image of the source image list to an image of the
715 * destination image list. Images can be copied or swapped.
718 * himlDst [I] handle to the destination image list
719 * iDst [I] destination image index.
720 * himlSrc [I] handle to the source image list
721 * iSrc [I] source image index
722 * uFlags [I] flags for the copy operation
729 * Copying from one image list to another is possible. The original
730 * implementation just copies or swapps within one image list.
731 * Could this feature become a bug??? ;-)
735 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
736 INT iSrc, INT uFlags)
740 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
742 if ((himlSrc == NULL) || (himlDst == NULL))
744 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
746 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
749 hdcSrc = CreateCompatibleDC (0);
750 if (himlDst == himlSrc)
753 hdcDst = CreateCompatibleDC (0);
755 if (uFlags & ILCF_SWAP) {
757 HBITMAP hbmTempImage, hbmTempMask;
759 /* create temporary bitmaps */
760 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
761 himlSrc->uBitsPixel, NULL);
762 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
765 /* copy (and stretch) destination to temporary bitmaps.(save) */
767 SelectObject (hdcSrc, himlDst->hbmImage);
768 SelectObject (hdcDst, hbmTempImage);
769 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
770 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
773 SelectObject (hdcSrc, himlDst->hbmMask);
774 SelectObject (hdcDst, hbmTempMask);
775 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
776 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
779 /* copy (and stretch) source to destination */
781 SelectObject (hdcSrc, himlSrc->hbmImage);
782 SelectObject (hdcDst, himlDst->hbmImage);
783 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
784 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
787 SelectObject (hdcSrc, himlSrc->hbmMask);
788 SelectObject (hdcDst, himlDst->hbmMask);
789 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
790 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
793 /* copy (without stretching) temporary bitmaps to source (restore) */
795 SelectObject (hdcSrc, hbmTempImage);
796 SelectObject (hdcDst, himlSrc->hbmImage);
797 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
798 hdcSrc, 0, 0, SRCCOPY);
800 SelectObject (hdcSrc, hbmTempMask);
801 SelectObject (hdcDst, himlSrc->hbmMask);
802 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
803 hdcSrc, 0, 0, SRCCOPY);
805 /* delete temporary bitmaps */
806 DeleteObject (hbmTempMask);
807 DeleteObject (hbmTempImage);
811 SelectObject (hdcSrc, himlSrc->hbmImage);
812 if (himlSrc == himlDst)
815 SelectObject (hdcDst, himlDst->hbmImage);
816 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
817 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
821 SelectObject (hdcSrc, himlSrc->hbmMask);
822 if (himlSrc == himlDst)
825 SelectObject (hdcDst, himlDst->hbmMask);
826 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
827 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
832 if (himlSrc != himlDst)
839 /*************************************************************************
840 * ImageList_Create [COMCTL32.44] Creates a new image list.
843 * cx [I] image height
845 * flags [I] creation flags
846 * cInitial [I] initial number of images in the image list
847 * cGrow [I] number of images by which image list grows
850 * Success: Handle to the created image list
855 ImageList_Create (INT cx, INT cy, UINT flags,
856 INT cInitial, INT cGrow)
862 static WORD aBitBlend25[] =
863 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
865 static WORD aBitBlend50[] =
866 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
868 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
870 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
877 himl->cMaxImage = cInitial + cGrow;
878 himl->cInitial = cInitial;
881 himl->clrFg = CLR_DEFAULT;
882 himl->clrBk = CLR_NONE;
884 /* initialize overlay mask indices */
885 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
886 himl->nOvlIdx[nCount] = -1;
888 hdc = CreateCompatibleDC (0);
889 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
892 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
894 if (himl->cMaxImage > 0) {
896 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
897 1, himl->uBitsPixel, NULL);
898 if (himl->hbmImage == 0) {
899 ERR("Error creating image bitmap!\n");
906 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
907 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
909 if (himl->hbmMask == 0) {
910 ERR("Error creating mask bitmap!\n");
912 DeleteObject (himl->hbmImage);
919 /* create blending brushes */
920 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
921 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
922 DeleteObject (hbmTemp);
924 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
925 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
926 DeleteObject (hbmTemp);
928 TRACE("created imagelist %p\n", himl);
933 /*************************************************************************
934 * ImageList_Destroy [COMCTL32.45]
936 * Destroys an image list.
939 * himl [I] handle to image list
947 ImageList_Destroy (HIMAGELIST himl)
952 /* delete image bitmaps */
954 DeleteObject (himl->hbmImage);
956 DeleteObject (himl->hbmMask);
958 /* delete blending brushes */
959 if (himl->hbrBlend25)
960 DeleteObject (himl->hbrBlend25);
961 if (himl->hbrBlend50)
962 DeleteObject (himl->hbrBlend50);
964 COMCTL32_Free (himl);
970 /*************************************************************************
971 * ImageList_DragEnter [COMCTL32.46]
973 * Locks window update and displays the drag image at the given position.
976 * hwndLock [I] handle of the window that owns the drag image.
977 * x [I] X position of the drag image.
978 * y [I] Y position of the drag image.
985 * The position of the drag image is relative to the window, not
990 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
992 if (himlInternalDrag == NULL)
996 hwndInternalDrag = hwndLock;
998 hwndInternalDrag = GetDesktopWindow ();
1003 hdcBackBuffer = CreateCompatibleDC (0);
1004 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1005 himlInternalDrag->cx, himlInternalDrag->cy);
1007 ImageList_DragShowNolock (TRUE);
1013 /*************************************************************************
1014 * ImageList_DragLeave [COMCTL32.47]
1016 * Unlocks window update and hides the drag image.
1019 * hwndLock [I] handle of the window that owns the drag image.
1027 ImageList_DragLeave (HWND hwndLock)
1030 hwndInternalDrag = hwndLock;
1032 hwndInternalDrag = GetDesktopWindow ();
1034 ImageList_DragShowNolock (FALSE);
1036 DeleteDC (hdcBackBuffer);
1037 DeleteObject (hbmBackBuffer);
1043 /*************************************************************************
1044 * ImageList_DragMove [COMCTL32.48]
1046 * Moves the drag image.
1049 * x [I] X position of the drag image.
1050 * y [I] Y position of the drag image.
1057 * The position of the drag image is relative to the window, not
1062 ImageList_DragMove (INT x, INT y)
1064 ImageList_DragShowNolock (FALSE);
1069 ImageList_DragShowNolock (TRUE);
1075 /*************************************************************************
1076 * ImageList_DragShowNolock [COMCTL32.49]
1078 * Shows or hides the drag image.
1081 * bShow [I] TRUE shows the drag image, FALSE hides it.
1092 ImageList_DragShowNolock (BOOL bShow)
1096 FIXME("semi-stub!\n");
1097 TRACE("bShow=0x%X!\n", bShow);
1099 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1100 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1103 /* show drag image */
1105 /* save background */
1107 /* draw drag image */
1111 /* hide drag image */
1113 /* restore background */
1117 ReleaseDC (hwndInternalDrag, hdcDrag);
1123 /*************************************************************************
1124 * ImageList_Draw [COMCTL32.50] Draws an image.
1127 * himl [I] handle to image list
1129 * hdc [I] handle to device context
1132 * fStyle [I] drawing flags
1139 * Calls ImageList_DrawIndirect.
1142 * ImageList_DrawIndirect.
1146 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1147 INT x, INT y, UINT fStyle)
1149 IMAGELISTDRAWPARAMS imldp;
1151 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1161 imldp.rgbBk = CLR_DEFAULT;
1162 imldp.rgbFg = CLR_DEFAULT;
1163 imldp.fStyle = fStyle;
1166 return ImageList_DrawIndirect (&imldp);
1170 /*************************************************************************
1171 * ImageList_DrawEx [COMCTL32.51]
1173 * Draws an image and allows to use extended drawing features.
1176 * himl [I] handle to image list
1178 * hdc [I] handle to device context
1181 * xOffs [I] X offset
1182 * yOffs [I] Y offset
1183 * rgbBk [I] background color
1184 * rgbFg [I] foreground color
1185 * fStyle [I] drawing flags
1192 * Calls ImageList_DrawIndirect.
1195 * ImageList_DrawIndirect.
1199 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1200 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1203 IMAGELISTDRAWPARAMS imldp;
1205 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1215 imldp.rgbBk = rgbBk;
1216 imldp.rgbFg = rgbFg;
1217 imldp.fStyle = fStyle;
1220 return ImageList_DrawIndirect (&imldp);
1224 /*************************************************************************
1225 * ImageList_DrawIndirect [COMCTL32.52]
1227 * Draws an image using ...
1230 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1238 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1242 Do some Error Checking
1246 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1248 if (pimldp->himl == NULL)
1250 if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage)) {
1251 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage);
1255 Get the Height and Width to display
1257 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1258 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1262 if(pimldp->himl->hbmMask != 0)
1264 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1268 IMAGELIST_InternalDraw(pimldp, cx, cy);
1271 Apply the blend if needed to the Image
1273 if((pimldp->fStyle & ILD_BLEND50)
1274 || (pimldp->fStyle & ILD_BLEND25))
1276 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1279 Apply the Overlay if needed
1281 if (pimldp->fStyle & ILD_OVERLAYMASK)
1283 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1290 /*************************************************************************
1291 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1294 * himlSrc [I] source image list handle
1297 * Success: Handle of duplicated image list.
1302 ImageList_Duplicate (HIMAGELIST himlSrc)
1307 if (himlSrc == NULL) {
1308 ERR("Invalid image list handle!\n");
1312 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1313 himlSrc->cInitial, himlSrc->cGrow);
1317 hdcSrc = CreateCompatibleDC (0);
1318 hdcDst = CreateCompatibleDC (0);
1319 SelectObject (hdcSrc, himlSrc->hbmImage);
1320 SelectObject (hdcDst, himlDst->hbmImage);
1321 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1322 hdcSrc, 0, 0, SRCCOPY);
1324 if (himlDst->hbmMask)
1326 SelectObject (hdcSrc, himlSrc->hbmMask);
1327 SelectObject (hdcDst, himlDst->hbmMask);
1328 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1329 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1335 himlDst->cCurImage = himlSrc->cCurImage;
1336 himlDst->cMaxImage = himlSrc->cMaxImage;
1342 /*************************************************************************
1343 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1345 * Finishes a drag operation.
1359 ImageList_EndDrag (void)
1361 FIXME("semi-stub!\n");
1363 if (himlInternalDrag)
1366 ImageList_Destroy (himlInternalDrag);
1367 himlInternalDrag = NULL;
1369 nInternalDragHotspotX = 0;
1370 nInternalDragHotspotY = 0;
1378 /*************************************************************************
1379 * ImageList_GetBkColor [COMCTL32.55]
1381 * Returns the background color of an image list.
1384 * himl [I] Image list handle.
1387 * Success: background color
1392 ImageList_GetBkColor (HIMAGELIST himl)
1401 /*************************************************************************
1402 * ImageList_GetDragImage [COMCTL32.56]
1404 * Returns the handle to the internal drag image list.
1407 * ppt [O] Pointer to the drag position. Can be NULL.
1408 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1411 * Success: Handle of the drag image list.
1419 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1421 FIXME("semi-stub!\n");
1423 if (himlInternalDrag)
1424 return (himlInternalDrag);
1430 /*************************************************************************
1431 * ImageList_GetIcon [COMCTL32.57]
1433 * Creates an icon from a masked image of an image list.
1436 * himl [I] handle to image list
1438 * flags [I] drawing style flags
1441 * Success: icon handle
1446 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1450 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1453 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1454 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1458 hdcSrc = CreateCompatibleDC(0);
1459 hdcDst = CreateCompatibleDC(0);
1462 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1465 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1466 if (himl->hbmMask) {
1467 SelectObject (hdcSrc, himl->hbmMask);
1468 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1469 hdcSrc, i * himl->cx, 0, SRCCOPY);
1472 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1475 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1476 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1477 SelectObject (hdcDst, ii.hbmColor);
1478 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1479 hdcSrc, i * himl->cx, 0, SRCCOPY);
1482 * CreateIconIndirect requires us to deselect the bitmaps from
1483 * the DCs before calling
1485 SelectObject(hdcSrc, hOldSrcBitmap);
1486 SelectObject(hdcDst, hOldDstBitmap);
1488 hIcon = CreateIconIndirect (&ii);
1492 DeleteObject (ii.hbmMask);
1493 DeleteObject (ii.hbmColor);
1499 /*************************************************************************
1500 * ImageList_GetIconSize [COMCTL32.58]
1502 * Retrieves the size of an image in an image list.
1505 * himl [I] handle to image list
1506 * cx [O] pointer to the image width.
1507 * cy [O] pointer to the image height.
1514 * All images in an image list have the same size.
1518 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1522 if ((himl->cx <= 0) || (himl->cy <= 0))
1534 /*************************************************************************
1535 * ImageList_GetImageCount [COMCTL32.59]
1537 * Returns the number of images in an image list.
1540 * himl [I] handle to image list
1543 * Success: Number of images.
1548 ImageList_GetImageCount (HIMAGELIST himl)
1553 return himl->cCurImage;
1557 /*************************************************************************
1558 * ImageList_GetImageInfo [COMCTL32.60]
1560 * Returns information about an image in an image list.
1563 * himl [I] handle to image list
1565 * pImageInfo [O] pointer to the image information
1573 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1575 if ((himl == NULL) || (pImageInfo == NULL))
1577 if ((i < 0) || (i >= himl->cCurImage))
1580 pImageInfo->hbmImage = himl->hbmImage;
1581 pImageInfo->hbmMask = himl->hbmMask;
1583 pImageInfo->rcImage.top = 0;
1584 pImageInfo->rcImage.bottom = himl->cy;
1585 pImageInfo->rcImage.left = i * himl->cx;
1586 pImageInfo->rcImage.right = (i+1) * himl->cx;
1592 /*************************************************************************
1593 * ImageList_GetImageRect [COMCTL32.61]
1595 * Retrieves the rectangle of the specified image in an image list.
1598 * himl [I] handle to image list
1600 * lpRect [O] pointer to the image rectangle
1607 * This is an UNDOCUMENTED function!!!
1611 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1613 if ((himl == NULL) || (lpRect == NULL))
1615 if ((i < 0) || (i >= himl->cCurImage))
1618 lpRect->left = i * himl->cx;
1620 lpRect->right = lpRect->left + himl->cx;
1621 lpRect->bottom = himl->cy;
1627 /*************************************************************************
1628 * ImageList_LoadImageA [COMCTL32.63][COMCTL32.62]
1630 * Creates an image list from a bitmap, icon or cursor.
1633 * hi [I] instance handle
1634 * lpbmp [I] name or id of the image
1635 * cx [I] width of each image
1636 * cGrow [I] number of images to expand
1637 * clrMask [I] mask color
1638 * uType [I] type of image to load
1639 * uFlags [I] loading flags
1642 * Success: handle to the loaded image list
1650 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1651 COLORREF clrMask, UINT uType, UINT uFlags)
1653 HIMAGELIST himl = NULL;
1657 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1659 ERR("Error loading image!\n");
1663 if (uType == IMAGE_BITMAP) {
1665 GetObjectA (handle, sizeof(BITMAP), &bmp);
1667 /* To match windows behavior, if cx is set to zero and
1668 the flag DI_DEFAULTSIZE is specified, cx becomes the
1669 system metric value for icons. If the flag is not specified
1670 the function sets the size to the height of the bitmap */
1673 if (uFlags & DI_DEFAULTSIZE)
1674 cx = GetSystemMetrics (SM_CXICON);
1679 nImageCount = bmp.bmWidth / cx;
1681 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1682 nImageCount, cGrow);
1683 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1685 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1689 GetIconInfo (handle, &ii);
1690 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1691 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1692 ILC_MASK | ILC_COLOR, 1, cGrow);
1693 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1694 DeleteObject (ii.hbmColor);
1695 DeleteObject (ii.hbmMask);
1698 DeleteObject (handle);
1704 /*************************************************************************
1705 * ImageList_LoadImageW [COMCTL32.64]
1707 * Creates an image list from a bitmap, icon or cursor.
1710 * hi [I] instance handle
1711 * lpbmp [I] name or id of the image
1712 * cx [I] width of each image
1713 * cGrow [I] number of images to expand
1714 * clrMask [I] mask color
1715 * uType [I] type of image to load
1716 * uFlags [I] loading flags
1719 * Success: handle to the loaded image list
1727 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1728 COLORREF clrMask, UINT uType, UINT uFlags)
1730 HIMAGELIST himl = NULL;
1734 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1736 ERR("Error loading image!\n");
1740 if (uType == IMAGE_BITMAP) {
1742 GetObjectA (handle, sizeof(BITMAP), &bmp);
1743 nImageCount = bmp.bmWidth / cx;
1745 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1746 nImageCount, cGrow);
1747 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1749 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1753 GetIconInfo (handle, &ii);
1754 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1755 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1756 ILC_MASK | ILC_COLOR, 1, cGrow);
1757 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1758 DeleteObject (ii.hbmColor);
1759 DeleteObject (ii.hbmMask);
1762 DeleteObject (handle);
1768 /*************************************************************************
1769 * ImageList_Merge [COMCTL32.65]
1771 * Creates a new image list that contains a merged image from the specified
1772 * images of both source image lists.
1775 * himl1 [I] handle to first image list
1776 * i1 [I] first image index
1777 * himl2 [I] handle to second image list
1778 * i2 [I] second image index
1779 * dx [I] X offset of the second image relative to the first.
1780 * dy [I] Y offset of the second image relative to the first.
1783 * Success: handle of the merged image list.
1788 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1791 HIMAGELIST himlDst = NULL;
1792 HDC hdcSrcImage, hdcDstImage;
1794 INT xOff1, yOff1, xOff2, yOff2;
1797 if ((himl1 == NULL) || (himl2 == NULL))
1801 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1802 ERR("Index 1 out of range! %d\n", i1);
1806 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1807 ERR("Index 2 out of range! %d\n", i2);
1812 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1817 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1822 cxDst = _MAX (himl1->cx, himl2->cx);
1828 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1833 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1838 cyDst = _MAX (himl1->cy, himl2->cy);
1843 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1846 hdcSrcImage = CreateCompatibleDC (0);
1847 hdcDstImage = CreateCompatibleDC (0);
1848 nX1 = i1 * himl1->cx;
1849 nX2 = i2 * himl2->cx;
1852 SelectObject (hdcSrcImage, himl1->hbmImage);
1853 SelectObject (hdcDstImage, himlDst->hbmImage);
1854 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1855 hdcSrcImage, 0, 0, BLACKNESS);
1856 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1857 hdcSrcImage, nX1, 0, SRCCOPY);
1859 SelectObject (hdcSrcImage, himl2->hbmMask);
1860 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1861 hdcSrcImage, nX2, 0, SRCAND);
1863 SelectObject (hdcSrcImage, himl2->hbmImage);
1864 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1865 hdcSrcImage, nX2, 0, SRCPAINT);
1868 SelectObject (hdcSrcImage, himl1->hbmMask);
1869 SelectObject (hdcDstImage, himlDst->hbmMask);
1870 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1871 hdcSrcImage, 0, 0, WHITENESS);
1872 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1873 hdcSrcImage, nX1, 0, SRCCOPY);
1875 SelectObject (hdcSrcImage, himl2->hbmMask);
1876 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1877 hdcSrcImage, nX2, 0, SRCAND);
1879 DeleteDC (hdcSrcImage);
1880 DeleteDC (hdcDstImage);
1887 /* helper for _read_bitmap currently unused */
1889 static int may_use_dibsection(HDC hdc) {
1890 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1895 return GetDeviceCaps(hdc,94) & 0x10;
1899 /* helper for ImageList_Read, see comments below */
1900 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1902 BITMAPFILEHEADER bmfh;
1903 BITMAPINFOHEADER bmih;
1904 int bitsperpixel,palspace,longsperline,width,height;
1905 LPBITMAPINFOHEADER bmihc = NULL;
1907 HBITMAP hbitmap = 0;
1908 LPBYTE bits = NULL,nbits = NULL;
1909 int nbytesperline,bytesperline;
1911 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1912 (bmfh.bfType != (('M'<<8)|'B')) ||
1913 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1914 (bmih.biSize != sizeof(bmih))
1918 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1919 if (bitsperpixel<=8)
1920 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1923 width = bmih.biWidth;
1924 height = bmih.biHeight;
1925 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1926 memcpy(bmihc,&bmih,sizeof(bmih));
1927 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1928 bmihc->biSizeImage = (longsperline*height)<<2;
1930 /* read the palette right after the end of the bitmapinfoheader */
1932 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1936 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1937 if ((bitsperpixel>1) &&
1938 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1940 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1943 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1949 int i,nwidth,nheight;
1951 nwidth = width*(height/cy);
1954 if (bitsperpixel==1)
1955 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1957 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1959 /* Might be a bit excessive memory use here */
1960 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1961 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1962 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1965 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1966 /* Do not forget that windows bitmaps are bottom->top */
1967 bytesperline = longsperline*4;
1968 nbytesperline = (height/cy)*bytesperline;
1969 for (i=0;i<height;i++) {
1971 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1972 bits+bytesperline*(height-1-i),
1976 bmihc->biWidth = nwidth;
1977 bmihc->biHeight = nheight;
1978 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1980 LocalFree((HLOCAL)nbits);
1981 LocalFree((HLOCAL)bits);
1985 if (xdc) ReleaseDC(0,xdc);
1986 if (bmihc) LocalFree((HLOCAL)bmihc);
1989 DeleteObject(hbitmap);
1996 /*************************************************************************
1997 * ImageList_Read [COMCTL32.66]
1999 * Reads an image list from a stream.
2002 * pstm [I] pointer to a stream
2005 * Success: handle to image list
2008 * The format is like this:
2009 * ILHEAD ilheadstruct;
2011 * for the color image part:
2012 * BITMAPFILEHEADER bmfh;
2013 * BITMAPINFOHEADER bmih;
2014 * only if it has a palette:
2015 * RGBQUAD rgbs[nr_of_paletted_colors];
2017 * BYTE colorbits[imagesize];
2019 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2020 * BITMAPFILEHEADER bmfh_mask;
2021 * BITMAPINFOHEADER bmih_mask;
2022 * only if it has a palette (it usually does not):
2023 * RGBQUAD rgbs[nr_of_paletted_colors];
2025 * BYTE maskbits[imagesize];
2027 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2028 * _read_bitmap needs to convert them.
2030 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2034 HBITMAP hbmColor=0,hbmMask=0;
2037 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2039 if (ilHead.usMagic != (('L' << 8) | 'I'))
2041 if (ilHead.usVersion != 0x101) /* probably version? */
2045 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2046 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2047 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2048 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2049 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2050 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2051 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2052 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2053 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2054 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2057 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2060 if (ilHead.flags & ILC_MASK) {
2061 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2063 DeleteObject(hbmColor);
2068 himl = ImageList_Create (
2076 DeleteObject(hbmColor);
2077 DeleteObject(hbmMask);
2080 himl->hbmImage = hbmColor;
2081 himl->hbmMask = hbmMask;
2082 himl->cCurImage = ilHead.cCurImage;
2083 himl->cMaxImage = ilHead.cMaxImage;
2085 ImageList_SetBkColor(himl,ilHead.bkcolor);
2087 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2092 /*************************************************************************
2093 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2096 * himl [I] image list handle
2105 ImageList_Remove (HIMAGELIST himl, INT i)
2107 HBITMAP hbmNewImage, hbmNewMask;
2111 if ((i < -1) || (i >= himl->cCurImage)) {
2112 ERR("index out of range! %d\n", i);
2116 if (himl->cCurImage == 0) {
2117 ERR("image list is already empty!\n");
2123 TRACE("remove all!\n");
2125 himl->cMaxImage = himl->cInitial + himl->cGrow;
2126 himl->cCurImage = 0;
2127 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2128 himl->nOvlIdx[nCount] = -1;
2130 DeleteObject (himl->hbmImage);
2132 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2133 1, himl->uBitsPixel, NULL);
2135 if (himl->hbmMask) {
2136 DeleteObject (himl->hbmMask);
2138 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2143 /* delete one image */
2144 TRACE("Remove single image! %d\n", i);
2146 /* create new bitmap(s) */
2147 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2149 TRACE(" - Number of images: %d / %d (Old/New)\n",
2150 himl->cCurImage, himl->cCurImage - 1);
2151 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2152 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2155 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2158 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2160 hbmNewMask = 0; /* Just to keep compiler happy! */
2162 hdcSrc = CreateCompatibleDC (0);
2163 hdcDst = CreateCompatibleDC (0);
2165 /* copy all images and masks prior to the "removed" image */
2167 TRACE("Pre image copy: Copy %d images\n", i);
2169 SelectObject (hdcSrc, himl->hbmImage);
2170 SelectObject (hdcDst, hbmNewImage);
2171 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2172 hdcSrc, 0, 0, SRCCOPY);
2174 if (himl->hbmMask) {
2175 SelectObject (hdcSrc, himl->hbmMask);
2176 SelectObject (hdcDst, hbmNewMask);
2177 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2178 hdcSrc, 0, 0, SRCCOPY);
2182 /* copy all images and masks behind the removed image */
2183 if (i < himl->cCurImage - 1) {
2184 TRACE("Post image copy!\n");
2185 SelectObject (hdcSrc, himl->hbmImage);
2186 SelectObject (hdcDst, hbmNewImage);
2187 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2188 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2190 if (himl->hbmMask) {
2191 SelectObject (hdcSrc, himl->hbmMask);
2192 SelectObject (hdcDst, hbmNewMask);
2193 BitBlt (hdcDst, i * himl->cx, 0,
2194 (himl->cCurImage - i - 1) * himl->cx,
2195 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2202 /* delete old images and insert new ones */
2203 DeleteObject (himl->hbmImage);
2204 himl->hbmImage = hbmNewImage;
2205 if (himl->hbmMask) {
2206 DeleteObject (himl->hbmMask);
2207 himl->hbmMask = hbmNewMask;
2211 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2218 /*************************************************************************
2219 * ImageList_Replace [COMCTL32.68]
2221 * Replaces an image in an image list with a new image.
2224 * himl [I] handle to image list
2226 * hbmImage [I] handle to image bitmap
2227 * hbmMask [I] handle to mask bitmap. Can be NULL.
2235 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2238 HDC hdcImageList, hdcImage;
2242 ERR("Invalid image list handle!\n");
2246 if ((i >= himl->cMaxImage) || (i < 0)) {
2247 ERR("Invalid image index!\n");
2251 hdcImageList = CreateCompatibleDC (0);
2252 hdcImage = CreateCompatibleDC (0);
2253 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2256 SelectObject (hdcImageList, himl->hbmImage);
2257 SelectObject (hdcImage, hbmImage);
2259 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2260 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2265 SelectObject (hdcImageList, himl->hbmMask);
2266 SelectObject (hdcImage, hbmMask);
2268 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2269 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2272 /* Remove the background from the image
2274 SelectObject (hdcImageList, himl->hbmImage);
2275 StretchBlt (hdcImageList,
2276 i*himl->cx, 0, himl->cx, himl->cy,
2278 0, 0, bmp.bmWidth, bmp.bmHeight,
2279 0x220326); /* NOTSRCAND */
2282 DeleteDC (hdcImage);
2283 DeleteDC (hdcImageList);
2289 /*************************************************************************
2290 * ImageList_ReplaceIcon [COMCTL32.69]
2292 * Replaces an image in an image list using an icon.
2295 * himl [I] handle to image list
2297 * hIcon [I] handle to icon
2300 * Success: index of the replaced image
2305 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2307 HDC hdcImageList, hdcImage;
2310 HBITMAP hbmOldSrc, hbmOldDst;
2314 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2318 if ((i >= himl->cMaxImage) || (i < -1))
2321 hBestFitIcon = CopyImage(
2324 LR_COPYFROMRESOURCE);
2326 GetIconInfo (hBestFitIcon, &ii);
2327 if (ii.hbmMask == 0)
2329 if (ii.hbmColor == 0)
2331 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2334 if (himl->cCurImage + 1 >= himl->cMaxImage)
2335 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2337 nIndex = himl->cCurImage;
2343 hdcImageList = CreateCompatibleDC (0);
2344 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2345 if (hdcImageList == 0)
2346 ERR("invalid hdcImageList!\n");
2348 hdcImage = CreateCompatibleDC (0);
2349 TRACE("hdcImage=0x%x!\n", hdcImage);
2351 ERR("invalid hdcImage!\n");
2353 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2354 SetTextColor( hdcImageList, RGB(0,0,0));
2355 SetBkColor( hdcImageList, RGB(255,255,255));
2356 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2357 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2358 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2360 if (himl->hbmMask) {
2361 SelectObject (hdcImageList, himl->hbmMask);
2362 SelectObject (hdcImage, ii.hbmMask);
2363 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2364 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2367 SelectObject (hdcImage, hbmOldSrc);
2368 SelectObject (hdcImageList, hbmOldDst);
2371 DestroyIcon(hBestFitIcon);
2373 DeleteDC (hdcImageList);
2375 DeleteDC (hdcImage);
2377 DeleteObject (ii.hbmColor);
2379 DeleteObject (ii.hbmMask);
2385 /*************************************************************************
2386 * ImageList_SetBkColor [COMCTL32.70]
2388 * Sets the background color of an image list.
2391 * himl [I] handle to image list
2392 * clrBk [I] background color
2395 * Success: previous background color
2400 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2407 clrOldBk = himl->clrBk;
2408 himl->clrBk = clrBk;
2413 /*************************************************************************
2414 * ImageList_SetDragCursorImage [COMCTL32.75]
2416 * Combines the specified image with the current drag image
2419 * himlDrag [I] handle to drag image list
2420 * iDrag [I] drag image index
2421 * dxHotspot [I] X position of the hot spot
2422 * dyHotspot [I] Y position of the hot spot
2433 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2434 INT dxHotspot, INT dyHotspot)
2436 HIMAGELIST himlTemp;
2438 FIXME("semi-stub!\n");
2440 if (himlInternalDrag == NULL)
2443 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2444 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2446 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2447 dxHotspot, dyHotspot);
2449 ImageList_Destroy (himlInternalDrag);
2450 himlInternalDrag = himlTemp;
2452 nInternalDragHotspotX = dxHotspot;
2453 nInternalDragHotspotY = dyHotspot;
2459 /*************************************************************************
2460 * ImageList_SetFilter [COMCTL32.76]
2462 * Sets a filter (or does something completely different)!!???
2465 * himl [I] handle to image list
2471 * Failure: FALSE ???
2474 * This is an UNDOCUMENTED function!!!!
2479 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2481 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2488 /*************************************************************************
2489 * ImageList_SetIconSize [COMCTL32.77]
2491 * Sets the image size of the bitmap and deletes all images.
2494 * himl [I] handle to image list
2495 * cx [I] image width
2496 * cy [I] image height
2504 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2511 /* remove all images */
2512 himl->cMaxImage = himl->cInitial + himl->cGrow;
2513 himl->cCurImage = 0;
2517 /* initialize overlay mask indices */
2518 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2519 himl->nOvlIdx[nCount] = -1;
2521 DeleteObject (himl->hbmImage);
2523 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2524 1, himl->uBitsPixel, NULL);
2526 if (himl->hbmMask) {
2527 DeleteObject (himl->hbmMask);
2529 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2537 /*************************************************************************
2538 * ImageList_SetImageCount [COMCTL32.78]
2540 * Resizes an image list to the specified number of images.
2543 * himl [I] handle to image list
2544 * iImageCount [I] number of images in the image list
2552 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2554 HDC hdcImageList, hdcBitmap;
2555 HBITMAP hbmNewBitmap;
2556 INT nNewCount, nCopyCount;
2560 if (himl->cCurImage >= iImageCount)
2562 if (himl->cMaxImage > iImageCount)
2565 nNewCount = iImageCount + himl->cGrow;
2566 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2568 hdcImageList = CreateCompatibleDC (0);
2569 hdcBitmap = CreateCompatibleDC (0);
2571 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2572 1, himl->uBitsPixel, NULL);
2573 if (hbmNewBitmap != 0)
2575 SelectObject (hdcImageList, himl->hbmImage);
2576 SelectObject (hdcBitmap, hbmNewBitmap);
2579 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2580 hdcImageList, 0, 0, SRCCOPY);
2582 /* delete 'empty' image space */
2583 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2584 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2585 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2586 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2588 DeleteObject (himl->hbmImage);
2589 himl->hbmImage = hbmNewBitmap;
2592 ERR("Could not create new image bitmap !\n");
2596 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2598 if (hbmNewBitmap != 0)
2600 SelectObject (hdcImageList, himl->hbmMask);
2601 SelectObject (hdcBitmap, hbmNewBitmap);
2604 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2605 hdcImageList, 0, 0, SRCCOPY);
2607 /* delete 'empty' image space */
2608 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2609 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2610 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2611 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2613 DeleteObject (himl->hbmMask);
2614 himl->hbmMask = hbmNewBitmap;
2617 ERR("Could not create new mask bitmap!\n");
2620 DeleteDC (hdcImageList);
2621 DeleteDC (hdcBitmap);
2623 /* Update max image count and current image count */
2624 himl->cMaxImage = nNewCount;
2625 if (himl->cCurImage > nCopyCount)
2626 himl->cCurImage = nCopyCount;
2632 /*************************************************************************
2633 * ImageList_SetOverlayImage [COMCTL32.79]
2635 * Assigns an overlay mask index to an existing image in an image list.
2638 * himl [I] handle to image list
2639 * iImage [I] image index
2640 * iOverlay [I] overlay mask index
2648 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2652 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2654 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2656 himl->nOvlIdx[iOverlay - 1] = iImage;
2661 /*************************************************************************
2662 * ImageList_Write [COMCTL32.80]
2664 * Writes an image list to a stream.
2667 * himl [I] handle to image list
2668 * pstm [O] Pointer to a stream.
2675 * This function can not be implemented yet, because
2676 * IStream32::Write is not implemented.
2683 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2688 FIXME("empty stub!\n");