2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
8 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
9 * - Fix ImageList_GetIcon.
10 * - Fix drag functions.
11 * - Fix ImageList_Write.
12 * - Fix ImageList_SetFilter (undocumented).
13 * BTW does anybody know anything about this function???
14 * - It removes 12 Bytes from the stack (3 Parameters).
15 * - First parameter SHOULD be a HIMAGELIST.
16 * - Second parameter COULD be an index?????
17 * - Third parameter.... ?????????????????????
20 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
21 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
22 * partially implemented, the functions mentioned above will be
23 * limited in functionality too.
29 #include "wine/obj_base.h"
30 #include "wine/obj_storage.h"
32 #include "imagelist.h"
33 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(imagelist);
38 #define _MAX(a,b) (((a)>(b))?(a):(b))
39 #define _MIN(a,b) (((a)>(b))?(b):(a))
41 #define MAX_OVERLAYIMAGE 15
44 /* internal image list data used for Drag & Drop operations */
46 static HIMAGELIST himlInternalDrag = NULL;
47 static INT nInternalDragHotspotX = 0;
48 static INT nInternalDragHotspotY = 0;
50 static HWND hwndInternalDrag = 0;
51 static INT xInternalPos = 0;
52 static INT yInternalPos = 0;
54 static HDC hdcBackBuffer = 0;
55 static HBITMAP hbmBackBuffer = 0;
58 /*************************************************************************
59 * IMAGELIST_InternalExpandBitmaps [Internal]
61 * Expands the bitmaps of an image list by the given number of images.
64 * himl [I] handle to image list
65 * nImageCount [I] number of images to add
71 * This function can NOT be used to reduce the number of images.
74 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
76 HDC hdcImageList, hdcBitmap;
78 INT nNewWidth, nNewCount;
80 if ((himl->cCurImage + nImageCount < himl->cMaxImage)
84 if (cy == 0) cy = himl->cy;
85 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
86 nNewWidth = nNewCount * himl->cx;
88 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
89 hdcImageList = CreateCompatibleDC (0);
90 hdcBitmap = CreateCompatibleDC (0);
93 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
94 if (hbmNewBitmap == 0)
95 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
97 SelectObject (hdcImageList, himl->hbmImage);
98 SelectObject (hdcBitmap, hbmNewBitmap);
99 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
100 hdcImageList, 0, 0, SRCCOPY);
102 DeleteObject (himl->hbmImage);
103 himl->hbmImage = hbmNewBitmap;
107 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
109 if (hbmNewBitmap == 0)
110 ERR("creating new mask bitmap!\n");
112 SelectObject (hdcImageList, himl->hbmMask);
113 SelectObject (hdcBitmap, hbmNewBitmap);
114 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
115 hdcImageList, 0, 0, SRCCOPY);
116 DeleteObject (himl->hbmMask);
117 himl->hbmMask = hbmNewBitmap;
120 himl->cMaxImage = nNewCount;
122 DeleteDC (hdcImageList);
123 DeleteDC (hdcBitmap);
127 /*************************************************************************
128 * IMAGELIST_InternalDraw [Internal]
130 * Draws the image in the ImageList (without the mask)
133 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
134 * cx [I] the width of the image to display
135 * cy............[I] the height of the image to display
141 * This functions is used by ImageList_DrawIndirect, when it is
142 * required to draw only the Image (without the mask) to the screen.
144 * Blending and Overlays styles are accomplised by another function
147 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
152 hImageDC = CreateCompatibleDC(0);
153 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
154 BitBlt(pimldp->hdcDst,
155 pimldp->x, pimldp->y, cx, cy,
157 pimldp->himl->cx * pimldp->i, 0,
160 SelectObject(hImageDC, hOldBitmap);
165 /*************************************************************************
166 * IMAGELIST_InternalDrawMask [Internal]
168 * Draws the image in the ImageList witht the mask
171 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
172 * cx [I] the width of the image to display
173 * cy............[I] the height of the image to display
179 * This functions is used by ImageList_DrawIndirect, when it is
180 * required to draw the Image with the mask to the screen.
182 * Blending and Overlays styles are accomplised by another function.
184 /*************************************************************************
185 * IMAGELIST_InternalDrawMask [Internal]
187 * Draws the image in the ImageList witht the mask
190 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
191 * cx [I] the width of the image to display
192 * cy............[I] the height of the image to display
198 * This functions is used by ImageList_DrawIndirect, when it is
199 * required to draw the Image with the mask to the screen.
201 * Blending and Overlays styles are accomplised by another function.
204 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
206 BOOL bUseCustomBackground, bBlendFlag;
207 HBRUSH hBrush, hOldBrush;
208 HDC hMaskDC, hImageDC;
209 HBITMAP hOldBitmapImage, hOldBitmapMask;
210 HIMAGELIST himlLocal = pimldp->himl;
211 COLORREF oldBkColor, oldFgColor;
212 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
215 * We need a dc and bitmap to draw on that is
218 HDC hOffScreenDC = 0;
219 HBITMAP hOffScreenBmp = 0;
221 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
222 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
224 hImageDC = CreateCompatibleDC(0);
225 hMaskDC = CreateCompatibleDC(0);
227 /* Create a compatible DC. */
228 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
232 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
235 SelectObject( hOffScreenDC, hOffScreenBmp );
242 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
243 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
246 * Get a copy of the image for the masking operations.
247 * We will use the copy, and this dc for all the various
248 * blitting, and then do one final blit to the screen dc.
249 * This should clean up most of the flickering.
251 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
255 * Draw the Background for the appropriate Styles
257 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
261 hBrush = CreateSolidBrush (himlLocal->clrBk);
262 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
264 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
266 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
270 * Draw Image Transparently over the current background
272 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
273 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
275 * To obtain a transparent look, background color should be set
276 * to white and foreground color to black when blting the
280 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
281 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
283 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
286 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
292 * Draw the image when no Background is specified
294 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
296 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
297 himlLocal->cx * pimldp->i, 0, SRCCOPY);
300 * Draw the mask with or without a background
302 else if(fStyle & ILD_MASK)
304 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
305 0, bUseCustomBackground ? SRCCOPY : SRCAND);
309 * Blit the bitmap to the screen now.
311 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
312 hOffScreenDC, 0, 0, SRCCOPY);
315 SelectObject(hImageDC, hOldBitmapImage);
316 SelectObject(hMaskDC, hOldBitmapMask);
323 DeleteDC( hOffScreenDC );
324 DeleteObject( hOffScreenBmp );
329 /*************************************************************************
330 * IMAGELIST_InternalDrawBlend [Internal]
332 * Draws the Blend over the current image
335 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
336 * cx [I] the width of the image to display
337 * cy............[I] the height of the image to display
343 * This functions is used by ImageList_DrawIndirect, when it is
344 * required to add the blend to the current image.
348 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
351 HDC hBlendMaskDC,hMaskDC;
352 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
353 HBITMAP hBlendMaskBitmap, hOldBitmap;
354 COLORREF clrBlend, OldTextColor, OldBkColor;
355 HIMAGELIST himlLocal = pimldp->himl;
357 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
358 if (!(pimldp->rgbFg == CLR_DEFAULT))
360 clrBlend = pimldp->rgbFg;
362 /* Create the blend Mask
364 hBlendMaskDC = CreateCompatibleDC(0);
365 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
366 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
368 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
369 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
371 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
372 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
373 SelectObject(hBlendMaskDC, hOldBrush);
375 /* Modify the blend mask if an Image Mask exist
377 if(pimldp->himl->hbmMask != 0)
379 HBITMAP hOldMaskBitmap;
380 hMaskDC = CreateCompatibleDC(0);
381 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
386 himlLocal->cx * pimldp->i,0,
387 0x220326); /* NOTSRCAND */
395 SelectObject(hMaskDC, hOldMaskBitmap);
399 /* Apply blend to the current image given the BlendMask
401 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
402 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
403 hBlendColorBrush = CreateSolidBrush(clrBlend);
404 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
406 BitBlt (pimldp->hdcDst,
407 pimldp->x, pimldp->y, cx, cy,
410 0xB8074A); /* PSDPxax */
412 SelectObject(pimldp->hdcDst, hOldBrush);
413 SetTextColor(pimldp->hdcDst, OldTextColor);
414 SetBkColor(pimldp->hdcDst, OldBkColor);
415 SelectObject(hBlendMaskDC, hOldBitmap);
416 DeleteDC(hBlendMaskDC);
417 DeleteObject(hBlendMaskBitmap);
418 DeleteObject(hBlendColorBrush);
421 /*************************************************************************
422 * IMAGELIST_InternalDrawOverlay [Internal]
424 * Draws the overlay image
427 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
428 * cx [I] the width of the image to display
429 * cy............[I] the height of the image to display
435 * This functions is used by ImageList_DrawIndirect, when it is
436 * required to draw the overlay
441 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
447 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
448 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
450 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
451 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
453 hImageDC = CreateCompatibleDC(0);
454 if (pimldp->himl->hbmMask)
456 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
457 pimldp->himl->hbmMask);
459 BitBlt (pimldp->hdcDst,
460 pimldp->x, pimldp->y, cx, cy,
461 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
464 SelectObject(hImageDC, hOldBitmap);
466 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
467 pimldp->himl->hbmImage);
469 BitBlt (pimldp->hdcDst,
470 pimldp->x, pimldp->y, cx, cy,
472 pimldp->himl->cx * nOvlIdx, 0,
475 SelectObject(hImageDC, hOldBitmap);
485 /*************************************************************************
486 * ImageList_Add [COMCTL32.39]
488 * Add an image or images to an image list.
491 * himl [I] handle to image list
492 * hbmImage [I] handle to image bitmap
493 * hbmMask [I] handle to mask bitmap
496 * Success: Index of the first new image.
501 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
503 HDC hdcImage, hdcBitmap;
504 INT nFirstIndex, nImageCount;
507 HBITMAP hOldBitmapImage, hOldBitmap;
509 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
510 if (!himl || !hbmImage)
513 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
514 nImageCount = bmp.bmWidth / himl->cx;
516 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
518 nStartX = himl->cCurImage * himl->cx;
520 hdcImage = CreateCompatibleDC(0);
521 hdcBitmap = CreateCompatibleDC(0);
523 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
524 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
526 /* Copy result to the imagelist
528 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
529 hdcBitmap, 0, 0, SRCCOPY);
533 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
535 hdcMask = CreateCompatibleDC (0);
536 hdcTemp = CreateCompatibleDC(0);
537 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
538 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
541 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
546 SelectObject(hdcTemp, hOldBitmapTemp);
549 /* Remove the background from the image
552 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
555 0x220326); /* NOTSRCAND */
557 SelectObject(hdcMask, hOldBitmapMask);
561 SelectObject(hdcImage, hOldBitmapImage);
562 SelectObject(hdcBitmap, hOldBitmap);
566 nFirstIndex = himl->cCurImage;
567 himl->cCurImage += nImageCount;
573 /*************************************************************************
574 * ImageList_AddIcon [COMCTL32.40]
576 * Adds an icon to an image list.
579 * himl [I] handle to image list
580 * hIcon [I] handle to icon
583 * Success: index of the new image
588 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
590 return ImageList_ReplaceIcon (himl, -1, hIcon);
594 /*************************************************************************
595 * ImageList_AddMasked [COMCTL32.41]
597 * Adds an image or images to an image list and creates a mask from the
598 * specified bitmap using the mask color.
601 * himl [I] handle to image list.
602 * hBitmap [I] handle to bitmap
603 * clrMask [I] mask color.
606 * Success: Index of the first new image.
611 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
613 HDC hdcImage, hdcMask, hdcBitmap;
614 INT nIndex, nImageCount, nMaskXOffset=0;
616 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
617 HBITMAP hMaskBitmap=0;
620 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
624 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
627 nImageCount = bmp.bmWidth / himl->cx;
629 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
631 nIndex = himl->cCurImage;
632 himl->cCurImage += nImageCount;
634 hdcMask = CreateCompatibleDC (0);
635 hdcImage = CreateCompatibleDC(0);
636 hdcBitmap = CreateCompatibleDC(0);
639 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
640 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
643 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
644 nMaskXOffset = nIndex * himl->cx;
649 Create a temp Mask so we can remove the background of
650 the Image (Windows does this even if there is no mask)
652 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
653 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
656 /* create monochrome image to the mask bitmap */
657 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
658 GetPixel (hdcBitmap, 0, 0);
659 SetBkColor (hdcBitmap, bkColor);
661 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
665 SetBkColor(hdcBitmap, RGB(255,255,255));
666 /*Remove the background from the image
669 WINDOWS BUG ALERT!!!!!!
670 The statement below should not be done in common practice
671 but this is how ImageList_AddMasked works in Windows.
672 It overwrites the original bitmap passed, this was discovered
673 by using the same bitmap to itterated the different styles
674 on windows where it failed (BUT ImageList_Add is OK)
675 This is here in case some apps really on this bug
678 0, 0, bmp.bmWidth, bmp.bmHeight,
681 0x220326); /* NOTSRCAND */
682 /* Copy result to the imagelist
685 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
691 SelectObject(hdcMask,hOldBitmapMask);
692 SelectObject(hdcImage, hOldBitmapImage);
693 SelectObject(hdcBitmap, hOldBitmap);
699 DeleteObject(hMaskBitmap);
706 /*************************************************************************
707 * ImageList_BeginDrag [COMCTL32.42]
709 * Creates a temporary image list that contains one image. It will be used
713 * himlTrack [I] handle to the source image list
714 * iTrack [I] index of the drag image in the source image list
715 * dxHotspot [I] X position of the hot spot of the drag image
716 * dyHotspot [I] Y position of the hot spot of the drag image
724 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
725 INT dxHotspot, INT dyHotspot)
729 FIXME("partially implemented!\n");
731 if (himlTrack == NULL)
734 if (himlInternalDrag)
735 ImageList_EndDrag ();
738 ImageList_Create (himlTrack->cx, himlTrack->cy,
739 himlTrack->flags, 1, 1);
740 if (himlInternalDrag == NULL) {
741 ERR("Error creating drag image list!\n");
745 nInternalDragHotspotX = dxHotspot;
746 nInternalDragHotspotY = dyHotspot;
748 hdcSrc = CreateCompatibleDC (0);
749 hdcDst = CreateCompatibleDC (0);
752 SelectObject (hdcSrc, himlTrack->hbmImage);
753 SelectObject (hdcDst, himlInternalDrag->hbmImage);
754 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
755 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
758 SelectObject (hdcSrc, himlTrack->hbmMask);
759 SelectObject (hdcDst, himlInternalDrag->hbmMask);
760 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
761 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
766 himlInternalDrag->cCurImage = 1;
772 /*************************************************************************
773 * ImageList_Copy [COMCTL32.43]
775 * Copies an image of the source image list to an image of the
776 * destination image list. Images can be copied or swapped.
779 * himlDst [I] handle to the destination image list
780 * iDst [I] destination image index.
781 * himlSrc [I] handle to the source image list
782 * iSrc [I] source image index
783 * uFlags [I] flags for the copy operation
790 * Copying from one image list to another is possible. The original
791 * implementation just copies or swapps within one image list.
792 * Could this feature become a bug??? ;-)
796 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
797 INT iSrc, INT uFlags)
801 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
803 if ((himlSrc == NULL) || (himlDst == NULL))
805 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
807 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
810 hdcSrc = CreateCompatibleDC (0);
811 if (himlDst == himlSrc)
814 hdcDst = CreateCompatibleDC (0);
816 if (uFlags & ILCF_SWAP) {
818 HBITMAP hbmTempImage, hbmTempMask;
820 /* create temporary bitmaps */
821 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
822 himlSrc->uBitsPixel, NULL);
823 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
826 /* copy (and stretch) destination to temporary bitmaps.(save) */
828 SelectObject (hdcSrc, himlDst->hbmImage);
829 SelectObject (hdcDst, hbmTempImage);
830 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
831 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
834 SelectObject (hdcSrc, himlDst->hbmMask);
835 SelectObject (hdcDst, hbmTempMask);
836 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
837 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
840 /* copy (and stretch) source to destination */
842 SelectObject (hdcSrc, himlSrc->hbmImage);
843 SelectObject (hdcDst, himlDst->hbmImage);
844 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
845 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
848 SelectObject (hdcSrc, himlSrc->hbmMask);
849 SelectObject (hdcDst, himlDst->hbmMask);
850 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
851 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
854 /* copy (without stretching) temporary bitmaps to source (restore) */
856 SelectObject (hdcSrc, hbmTempImage);
857 SelectObject (hdcDst, himlSrc->hbmImage);
858 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
859 hdcSrc, 0, 0, SRCCOPY);
861 SelectObject (hdcSrc, hbmTempMask);
862 SelectObject (hdcDst, himlSrc->hbmMask);
863 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
864 hdcSrc, 0, 0, SRCCOPY);
866 /* delete temporary bitmaps */
867 DeleteObject (hbmTempMask);
868 DeleteObject (hbmTempImage);
872 SelectObject (hdcSrc, himlSrc->hbmImage);
873 if (himlSrc == himlDst)
876 SelectObject (hdcDst, himlDst->hbmImage);
877 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
878 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
882 SelectObject (hdcSrc, himlSrc->hbmMask);
883 if (himlSrc == himlDst)
886 SelectObject (hdcDst, himlDst->hbmMask);
887 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
888 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
893 if (himlSrc != himlDst)
900 /*************************************************************************
901 * ImageList_Create [COMCTL32.44] Creates a new image list.
904 * cx [I] image height
906 * flags [I] creation flags
907 * cInitial [I] initial number of images in the image list
908 * cGrow [I] number of images by which image list grows
911 * Success: Handle to the created image list
916 ImageList_Create (INT cx, INT cy, UINT flags,
917 INT cInitial, INT cGrow)
923 static WORD aBitBlend25[] =
924 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
926 static WORD aBitBlend50[] =
927 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
929 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
931 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
938 himl->cMaxImage = cInitial + cGrow;
939 himl->cInitial = cInitial;
942 himl->clrFg = CLR_DEFAULT;
943 himl->clrBk = CLR_NONE;
945 /* initialize overlay mask indices */
946 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
947 himl->nOvlIdx[nCount] = -1;
949 hdc = CreateCompatibleDC (0);
950 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
953 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
955 if (himl->cMaxImage > 0) {
957 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
958 1, himl->uBitsPixel, NULL);
959 if (himl->hbmImage == 0) {
960 ERR("Error creating image bitmap!\n");
967 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
968 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
970 if (himl->hbmMask == 0) {
971 ERR("Error creating mask bitmap!\n");
973 DeleteObject (himl->hbmImage);
980 /* create blending brushes */
981 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
982 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
983 DeleteObject (hbmTemp);
985 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
986 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
987 DeleteObject (hbmTemp);
989 TRACE("created imagelist %p\n", himl);
994 /*************************************************************************
995 * ImageList_Destroy [COMCTL32.45]
997 * Destroys an image list.
1000 * himl [I] handle to image list
1008 ImageList_Destroy (HIMAGELIST himl)
1013 /* delete image bitmaps */
1015 DeleteObject (himl->hbmImage);
1017 DeleteObject (himl->hbmMask);
1019 /* delete blending brushes */
1020 if (himl->hbrBlend25)
1021 DeleteObject (himl->hbrBlend25);
1022 if (himl->hbrBlend50)
1023 DeleteObject (himl->hbrBlend50);
1025 COMCTL32_Free (himl);
1031 /*************************************************************************
1032 * ImageList_DragEnter [COMCTL32.46]
1034 * Locks window update and displays the drag image at the given position.
1037 * hwndLock [I] handle of the window that owns the drag image.
1038 * x [I] X position of the drag image.
1039 * y [I] Y position of the drag image.
1046 * The position of the drag image is relative to the window, not
1051 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1053 if (himlInternalDrag == NULL)
1057 hwndInternalDrag = hwndLock;
1059 hwndInternalDrag = GetDesktopWindow ();
1064 hdcBackBuffer = CreateCompatibleDC (0);
1065 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1066 himlInternalDrag->cx, himlInternalDrag->cy);
1068 ImageList_DragShowNolock (TRUE);
1074 /*************************************************************************
1075 * ImageList_DragLeave [COMCTL32.47]
1077 * Unlocks window update and hides the drag image.
1080 * hwndLock [I] handle of the window that owns the drag image.
1088 ImageList_DragLeave (HWND hwndLock)
1091 hwndInternalDrag = hwndLock;
1093 hwndInternalDrag = GetDesktopWindow ();
1095 ImageList_DragShowNolock (FALSE);
1097 DeleteDC (hdcBackBuffer);
1098 DeleteObject (hbmBackBuffer);
1104 /*************************************************************************
1105 * ImageList_DragMove [COMCTL32.48]
1107 * Moves the drag image.
1110 * x [I] X position of the drag image.
1111 * y [I] Y position of the drag image.
1118 * The position of the drag image is relative to the window, not
1123 ImageList_DragMove (INT x, INT y)
1125 ImageList_DragShowNolock (FALSE);
1130 ImageList_DragShowNolock (TRUE);
1136 /*************************************************************************
1137 * ImageList_DragShowNolock [COMCTL32.49]
1139 * Shows or hides the drag image.
1142 * bShow [I] TRUE shows the drag image, FALSE hides it.
1153 ImageList_DragShowNolock (BOOL bShow)
1157 FIXME("semi-stub!\n");
1158 TRACE("bShow=0x%X!\n", bShow);
1160 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1161 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1164 /* show drag image */
1166 /* save background */
1168 /* draw drag image */
1172 /* hide drag image */
1174 /* restore background */
1178 ReleaseDC (hwndInternalDrag, hdcDrag);
1184 /*************************************************************************
1185 * ImageList_Draw [COMCTL32.50] Draws an image.
1188 * himl [I] handle to image list
1190 * hdc [I] handle to device context
1193 * fStyle [I] drawing flags
1200 * Calls ImageList_DrawIndirect.
1203 * ImageList_DrawIndirect.
1207 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1208 INT x, INT y, UINT fStyle)
1210 IMAGELISTDRAWPARAMS imldp;
1212 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1222 imldp.rgbBk = CLR_DEFAULT;
1223 imldp.rgbFg = CLR_DEFAULT;
1224 imldp.fStyle = fStyle;
1227 return ImageList_DrawIndirect (&imldp);
1231 /*************************************************************************
1232 * ImageList_DrawEx [COMCTL32.51]
1234 * Draws an image and allows to use extended drawing features.
1237 * himl [I] handle to image list
1239 * hdc [I] handle to device context
1242 * xOffs [I] X offset
1243 * yOffs [I] Y offset
1244 * rgbBk [I] background color
1245 * rgbFg [I] foreground color
1246 * fStyle [I] drawing flags
1253 * Calls ImageList_DrawIndirect.
1256 * ImageList_DrawIndirect.
1260 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1261 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1264 IMAGELISTDRAWPARAMS imldp;
1266 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1276 imldp.rgbBk = rgbBk;
1277 imldp.rgbFg = rgbFg;
1278 imldp.fStyle = fStyle;
1281 return ImageList_DrawIndirect (&imldp);
1285 /*************************************************************************
1286 * ImageList_DrawIndirect [COMCTL32.52]
1288 * Draws an image using ...
1291 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1299 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1303 Do some Error Checking
1307 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1309 if (pimldp->himl == NULL)
1311 if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage)) {
1312 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage);
1316 Get the Height and Width to display
1318 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1319 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1323 if(pimldp->himl->hbmMask != 0)
1325 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1329 IMAGELIST_InternalDraw(pimldp, cx, cy);
1332 Apply the blend if needed to the Image
1334 if((pimldp->fStyle & ILD_BLEND50)
1335 || (pimldp->fStyle & ILD_BLEND25))
1337 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1340 Apply the Overlay if needed
1342 if (pimldp->fStyle & ILD_OVERLAYMASK)
1344 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1351 /*************************************************************************
1352 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1355 * himlSrc [I] source image list handle
1358 * Success: Handle of duplicated image list.
1363 ImageList_Duplicate (HIMAGELIST himlSrc)
1368 if (himlSrc == NULL) {
1369 ERR("Invalid image list handle!\n");
1373 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1374 himlSrc->cInitial, himlSrc->cGrow);
1378 hdcSrc = CreateCompatibleDC (0);
1379 hdcDst = CreateCompatibleDC (0);
1380 SelectObject (hdcSrc, himlSrc->hbmImage);
1381 SelectObject (hdcDst, himlDst->hbmImage);
1382 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1383 hdcSrc, 0, 0, SRCCOPY);
1385 if (himlDst->hbmMask)
1387 SelectObject (hdcSrc, himlSrc->hbmMask);
1388 SelectObject (hdcDst, himlDst->hbmMask);
1389 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1390 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1396 himlDst->cCurImage = himlSrc->cCurImage;
1397 himlDst->cMaxImage = himlSrc->cMaxImage;
1403 /*************************************************************************
1404 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1406 * Finishes a drag operation.
1420 ImageList_EndDrag (void)
1422 FIXME("semi-stub!\n");
1424 if (himlInternalDrag)
1427 ImageList_Destroy (himlInternalDrag);
1428 himlInternalDrag = NULL;
1430 nInternalDragHotspotX = 0;
1431 nInternalDragHotspotY = 0;
1439 /*************************************************************************
1440 * ImageList_GetBkColor [COMCTL32.55]
1442 * Returns the background color of an image list.
1445 * himl [I] Image list handle.
1448 * Success: background color
1453 ImageList_GetBkColor (HIMAGELIST himl)
1462 /*************************************************************************
1463 * ImageList_GetDragImage [COMCTL32.56]
1465 * Returns the handle to the internal drag image list.
1468 * ppt [O] Pointer to the drag position. Can be NULL.
1469 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1472 * Success: Handle of the drag image list.
1480 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1482 FIXME("semi-stub!\n");
1484 if (himlInternalDrag)
1485 return (himlInternalDrag);
1491 /*************************************************************************
1492 * ImageList_GetIcon [COMCTL32.57]
1494 * Creates an icon from a masked image of an image list.
1497 * himl [I] handle to image list
1499 * flags [I] drawing style flags
1502 * Success: icon handle
1507 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1511 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1514 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1515 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1519 hdcSrc = CreateCompatibleDC(0);
1520 hdcDst = CreateCompatibleDC(0);
1523 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1526 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1527 if (himl->hbmMask) {
1528 SelectObject (hdcSrc, himl->hbmMask);
1529 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1530 hdcSrc, i * himl->cx, 0, SRCCOPY);
1533 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1536 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1537 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1538 SelectObject (hdcDst, ii.hbmColor);
1539 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1540 hdcSrc, i * himl->cx, 0, SRCCOPY);
1543 * CreateIconIndirect requires us to deselect the bitmaps from
1544 * the DCs before calling
1546 SelectObject(hdcSrc, hOldSrcBitmap);
1547 SelectObject(hdcDst, hOldDstBitmap);
1549 hIcon = CreateIconIndirect (&ii);
1553 DeleteObject (ii.hbmMask);
1554 DeleteObject (ii.hbmColor);
1560 /*************************************************************************
1561 * ImageList_GetIconSize [COMCTL32.58]
1563 * Retrieves the size of an image in an image list.
1566 * himl [I] handle to image list
1567 * cx [O] pointer to the image width.
1568 * cy [O] pointer to the image height.
1575 * All images in an image list have the same size.
1579 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1583 if ((himl->cx <= 0) || (himl->cy <= 0))
1595 /*************************************************************************
1596 * ImageList_GetImageCount [COMCTL32.59]
1598 * Returns the number of images in an image list.
1601 * himl [I] handle to image list
1604 * Success: Number of images.
1609 ImageList_GetImageCount (HIMAGELIST himl)
1614 return himl->cCurImage;
1618 /*************************************************************************
1619 * ImageList_GetImageInfo [COMCTL32.60]
1621 * Returns information about an image in an image list.
1624 * himl [I] handle to image list
1626 * pImageInfo [O] pointer to the image information
1634 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1636 if ((himl == NULL) || (pImageInfo == NULL))
1638 if ((i < 0) || (i >= himl->cCurImage))
1641 pImageInfo->hbmImage = himl->hbmImage;
1642 pImageInfo->hbmMask = himl->hbmMask;
1644 pImageInfo->rcImage.top = 0;
1645 pImageInfo->rcImage.bottom = himl->cy;
1646 pImageInfo->rcImage.left = i * himl->cx;
1647 pImageInfo->rcImage.right = (i+1) * himl->cx;
1653 /*************************************************************************
1654 * ImageList_GetImageRect [COMCTL32.61]
1656 * Retrieves the rectangle of the specified image in an image list.
1659 * himl [I] handle to image list
1661 * lpRect [O] pointer to the image rectangle
1668 * This is an UNDOCUMENTED function!!!
1672 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1674 if ((himl == NULL) || (lpRect == NULL))
1676 if ((i < 0) || (i >= himl->cCurImage))
1679 lpRect->left = i * himl->cx;
1681 lpRect->right = lpRect->left + himl->cx;
1682 lpRect->bottom = himl->cy;
1688 /*************************************************************************
1689 * ImageList_LoadImageA [COMCTL32.63][COMCTL32.62]
1691 * Creates an image list from a bitmap, icon or cursor.
1694 * hi [I] instance handle
1695 * lpbmp [I] name or id of the image
1696 * cx [I] width of each image
1697 * cGrow [I] number of images to expand
1698 * clrMask [I] mask color
1699 * uType [I] type of image to load
1700 * uFlags [I] loading flags
1703 * Success: handle to the loaded image list
1711 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1712 COLORREF clrMask, UINT uType, UINT uFlags)
1714 HIMAGELIST himl = NULL;
1718 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1720 ERR("Error loading image!\n");
1724 if (uType == IMAGE_BITMAP) {
1726 GetObjectA (handle, sizeof(BITMAP), &bmp);
1728 /* To match windows behavior, if cx is set to zero and
1729 the flag DI_DEFAULTSIZE is specified, cx becomes the
1730 system metric value for icons. If the flag is not specified
1731 the function sets the size to the height of the bitmap */
1734 if (uFlags & DI_DEFAULTSIZE)
1735 cx = GetSystemMetrics (SM_CXICON);
1740 nImageCount = bmp.bmWidth / cx;
1742 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1743 nImageCount, cGrow);
1744 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1746 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1750 GetIconInfo (handle, &ii);
1751 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1752 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1753 ILC_MASK | ILC_COLOR, 1, cGrow);
1754 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1755 DeleteObject (ii.hbmColor);
1756 DeleteObject (ii.hbmMask);
1759 DeleteObject (handle);
1765 /*************************************************************************
1766 * ImageList_LoadImageW [COMCTL32.64]
1768 * Creates an image list from a bitmap, icon or cursor.
1771 * hi [I] instance handle
1772 * lpbmp [I] name or id of the image
1773 * cx [I] width of each image
1774 * cGrow [I] number of images to expand
1775 * clrMask [I] mask color
1776 * uType [I] type of image to load
1777 * uFlags [I] loading flags
1780 * Success: handle to the loaded image list
1788 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1789 COLORREF clrMask, UINT uType, UINT uFlags)
1791 HIMAGELIST himl = NULL;
1795 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1797 ERR("Error loading image!\n");
1801 if (uType == IMAGE_BITMAP) {
1803 GetObjectA (handle, sizeof(BITMAP), &bmp);
1804 nImageCount = bmp.bmWidth / cx;
1806 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1807 nImageCount, cGrow);
1808 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1810 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1814 GetIconInfo (handle, &ii);
1815 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1816 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1817 ILC_MASK | ILC_COLOR, 1, cGrow);
1818 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1819 DeleteObject (ii.hbmColor);
1820 DeleteObject (ii.hbmMask);
1823 DeleteObject (handle);
1829 /*************************************************************************
1830 * ImageList_Merge [COMCTL32.65]
1832 * Creates a new image list that contains a merged image from the specified
1833 * images of both source image lists.
1836 * himl1 [I] handle to first image list
1837 * i1 [I] first image index
1838 * himl2 [I] handle to second image list
1839 * i2 [I] second image index
1840 * dx [I] X offset of the second image relative to the first.
1841 * dy [I] Y offset of the second image relative to the first.
1844 * Success: handle of the merged image list.
1849 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1852 HIMAGELIST himlDst = NULL;
1853 HDC hdcSrcImage, hdcDstImage;
1855 INT xOff1, yOff1, xOff2, yOff2;
1858 if ((himl1 == NULL) || (himl2 == NULL))
1862 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1863 ERR("Index 1 out of range! %d\n", i1);
1867 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1868 ERR("Index 2 out of range! %d\n", i2);
1873 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1878 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1883 cxDst = _MAX (himl1->cx, himl2->cx);
1889 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1894 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1899 cyDst = _MAX (himl1->cy, himl2->cy);
1904 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1907 hdcSrcImage = CreateCompatibleDC (0);
1908 hdcDstImage = CreateCompatibleDC (0);
1909 nX1 = i1 * himl1->cx;
1910 nX2 = i2 * himl2->cx;
1913 SelectObject (hdcSrcImage, himl1->hbmImage);
1914 SelectObject (hdcDstImage, himlDst->hbmImage);
1915 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1916 hdcSrcImage, 0, 0, BLACKNESS);
1917 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1918 hdcSrcImage, nX1, 0, SRCCOPY);
1920 SelectObject (hdcSrcImage, himl2->hbmMask);
1921 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1922 hdcSrcImage, nX2, 0, SRCAND);
1924 SelectObject (hdcSrcImage, himl2->hbmImage);
1925 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1926 hdcSrcImage, nX2, 0, SRCPAINT);
1929 SelectObject (hdcSrcImage, himl1->hbmMask);
1930 SelectObject (hdcDstImage, himlDst->hbmMask);
1931 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1932 hdcSrcImage, 0, 0, WHITENESS);
1933 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1934 hdcSrcImage, nX1, 0, SRCCOPY);
1936 SelectObject (hdcSrcImage, himl2->hbmMask);
1937 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1938 hdcSrcImage, nX2, 0, SRCAND);
1940 DeleteDC (hdcSrcImage);
1941 DeleteDC (hdcDstImage);
1948 /* helper for _read_bitmap currently unused */
1950 static int may_use_dibsection(HDC hdc) {
1951 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1956 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1960 /* helper for ImageList_Read, see comments below */
1961 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1963 BITMAPFILEHEADER bmfh;
1964 BITMAPINFOHEADER bmih;
1965 int bitsperpixel,palspace,longsperline,width,height;
1966 LPBITMAPINFOHEADER bmihc = NULL;
1968 HBITMAP hbitmap = 0;
1969 LPBYTE bits = NULL,nbits = NULL;
1970 int nbytesperline,bytesperline;
1972 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1973 (bmfh.bfType != (('M'<<8)|'B')) ||
1974 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1975 (bmih.biSize != sizeof(bmih))
1979 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1980 if (bitsperpixel<=8)
1981 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1984 width = bmih.biWidth;
1985 height = bmih.biHeight;
1986 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1987 memcpy(bmihc,&bmih,sizeof(bmih));
1988 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1989 bmihc->biSizeImage = (longsperline*height)<<2;
1991 /* read the palette right after the end of the bitmapinfoheader */
1993 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1997 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1998 if ((bitsperpixel>1) &&
1999 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2001 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2004 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2010 int i,nwidth,nheight;
2012 nwidth = width*(height/cy);
2015 if (bitsperpixel==1)
2016 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2018 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2020 /* Might be a bit excessive memory use here */
2021 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2022 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2023 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2026 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2027 /* Do not forget that windows bitmaps are bottom->top */
2028 bytesperline = longsperline*4;
2029 nbytesperline = (height/cy)*bytesperline;
2030 for (i=0;i<height;i++) {
2032 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2033 bits+bytesperline*(height-1-i),
2037 bmihc->biWidth = nwidth;
2038 bmihc->biHeight = nheight;
2039 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2041 LocalFree((HLOCAL)nbits);
2042 LocalFree((HLOCAL)bits);
2046 if (xdc) ReleaseDC(0,xdc);
2047 if (bmihc) LocalFree((HLOCAL)bmihc);
2050 DeleteObject(hbitmap);
2057 /*************************************************************************
2058 * ImageList_Read [COMCTL32.66]
2060 * Reads an image list from a stream.
2063 * pstm [I] pointer to a stream
2066 * Success: handle to image list
2069 * The format is like this:
2070 * ILHEAD ilheadstruct;
2072 * for the color image part:
2073 * BITMAPFILEHEADER bmfh;
2074 * BITMAPINFOHEADER bmih;
2075 * only if it has a palette:
2076 * RGBQUAD rgbs[nr_of_paletted_colors];
2078 * BYTE colorbits[imagesize];
2080 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2081 * BITMAPFILEHEADER bmfh_mask;
2082 * BITMAPINFOHEADER bmih_mask;
2083 * only if it has a palette (it usually does not):
2084 * RGBQUAD rgbs[nr_of_paletted_colors];
2086 * BYTE maskbits[imagesize];
2088 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2089 * _read_bitmap needs to convert them.
2091 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2095 HBITMAP hbmColor=0,hbmMask=0;
2098 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2100 if (ilHead.usMagic != (('L' << 8) | 'I'))
2102 if (ilHead.usVersion != 0x101) /* probably version? */
2106 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2107 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2108 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2109 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2110 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2111 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2112 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2113 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2114 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2115 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2118 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2121 if (ilHead.flags & ILC_MASK) {
2122 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2124 DeleteObject(hbmColor);
2129 himl = ImageList_Create (
2137 DeleteObject(hbmColor);
2138 DeleteObject(hbmMask);
2141 himl->hbmImage = hbmColor;
2142 himl->hbmMask = hbmMask;
2143 himl->cCurImage = ilHead.cCurImage;
2144 himl->cMaxImage = ilHead.cMaxImage;
2146 ImageList_SetBkColor(himl,ilHead.bkcolor);
2148 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2153 /*************************************************************************
2154 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2157 * himl [I] image list handle
2166 ImageList_Remove (HIMAGELIST himl, INT i)
2168 HBITMAP hbmNewImage, hbmNewMask;
2172 if ((i < -1) || (i >= himl->cCurImage)) {
2173 ERR("index out of range! %d\n", i);
2177 if (himl->cCurImage == 0) {
2178 ERR("image list is already empty!\n");
2184 TRACE("remove all!\n");
2186 himl->cMaxImage = himl->cInitial + himl->cGrow;
2187 himl->cCurImage = 0;
2188 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2189 himl->nOvlIdx[nCount] = -1;
2191 DeleteObject (himl->hbmImage);
2193 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2194 1, himl->uBitsPixel, NULL);
2196 if (himl->hbmMask) {
2197 DeleteObject (himl->hbmMask);
2199 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2204 /* delete one image */
2205 TRACE("Remove single image! %d\n", i);
2207 /* create new bitmap(s) */
2208 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2210 TRACE(" - Number of images: %d / %d (Old/New)\n",
2211 himl->cCurImage, himl->cCurImage - 1);
2212 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2213 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2216 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2219 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2221 hbmNewMask = 0; /* Just to keep compiler happy! */
2223 hdcSrc = CreateCompatibleDC (0);
2224 hdcDst = CreateCompatibleDC (0);
2226 /* copy all images and masks prior to the "removed" image */
2228 TRACE("Pre image copy: Copy %d images\n", i);
2230 SelectObject (hdcSrc, himl->hbmImage);
2231 SelectObject (hdcDst, hbmNewImage);
2232 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2233 hdcSrc, 0, 0, SRCCOPY);
2235 if (himl->hbmMask) {
2236 SelectObject (hdcSrc, himl->hbmMask);
2237 SelectObject (hdcDst, hbmNewMask);
2238 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2239 hdcSrc, 0, 0, SRCCOPY);
2243 /* copy all images and masks behind the removed image */
2244 if (i < himl->cCurImage - 1) {
2245 TRACE("Post image copy!\n");
2246 SelectObject (hdcSrc, himl->hbmImage);
2247 SelectObject (hdcDst, hbmNewImage);
2248 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2249 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2251 if (himl->hbmMask) {
2252 SelectObject (hdcSrc, himl->hbmMask);
2253 SelectObject (hdcDst, hbmNewMask);
2254 BitBlt (hdcDst, i * himl->cx, 0,
2255 (himl->cCurImage - i - 1) * himl->cx,
2256 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2263 /* delete old images and insert new ones */
2264 DeleteObject (himl->hbmImage);
2265 himl->hbmImage = hbmNewImage;
2266 if (himl->hbmMask) {
2267 DeleteObject (himl->hbmMask);
2268 himl->hbmMask = hbmNewMask;
2272 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2279 /*************************************************************************
2280 * ImageList_Replace [COMCTL32.68]
2282 * Replaces an image in an image list with a new image.
2285 * himl [I] handle to image list
2287 * hbmImage [I] handle to image bitmap
2288 * hbmMask [I] handle to mask bitmap. Can be NULL.
2296 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2299 HDC hdcImageList, hdcImage;
2303 ERR("Invalid image list handle!\n");
2307 if ((i >= himl->cMaxImage) || (i < 0)) {
2308 ERR("Invalid image index!\n");
2312 hdcImageList = CreateCompatibleDC (0);
2313 hdcImage = CreateCompatibleDC (0);
2314 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2317 SelectObject (hdcImageList, himl->hbmImage);
2318 SelectObject (hdcImage, hbmImage);
2320 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2321 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2326 SelectObject (hdcImageList, himl->hbmMask);
2327 SelectObject (hdcImage, hbmMask);
2329 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2330 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2333 /* Remove the background from the image
2335 SelectObject (hdcImageList, himl->hbmImage);
2336 StretchBlt (hdcImageList,
2337 i*himl->cx, 0, himl->cx, himl->cy,
2339 0, 0, bmp.bmWidth, bmp.bmHeight,
2340 0x220326); /* NOTSRCAND */
2343 DeleteDC (hdcImage);
2344 DeleteDC (hdcImageList);
2350 /*************************************************************************
2351 * ImageList_ReplaceIcon [COMCTL32.69]
2353 * Replaces an image in an image list using an icon.
2356 * himl [I] handle to image list
2358 * hIcon [I] handle to icon
2361 * Success: index of the replaced image
2366 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2368 HDC hdcImageList, hdcImage;
2371 HBITMAP hbmOldSrc, hbmOldDst;
2375 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2379 if ((i >= himl->cMaxImage) || (i < -1))
2382 hBestFitIcon = CopyImage(
2385 LR_COPYFROMRESOURCE);
2387 GetIconInfo (hBestFitIcon, &ii);
2388 if (ii.hbmMask == 0)
2390 if (ii.hbmColor == 0)
2392 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2395 if (himl->cCurImage + 1 >= himl->cMaxImage)
2396 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2398 nIndex = himl->cCurImage;
2404 hdcImageList = CreateCompatibleDC (0);
2405 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2406 if (hdcImageList == 0)
2407 ERR("invalid hdcImageList!\n");
2409 hdcImage = CreateCompatibleDC (0);
2410 TRACE("hdcImage=0x%x!\n", hdcImage);
2412 ERR("invalid hdcImage!\n");
2414 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2415 SetTextColor( hdcImageList, RGB(0,0,0));
2416 SetBkColor( hdcImageList, RGB(255,255,255));
2417 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2418 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2419 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2421 if (himl->hbmMask) {
2422 SelectObject (hdcImageList, himl->hbmMask);
2423 SelectObject (hdcImage, ii.hbmMask);
2424 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2425 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2428 SelectObject (hdcImage, hbmOldSrc);
2429 SelectObject (hdcImageList, hbmOldDst);
2432 DestroyIcon(hBestFitIcon);
2434 DeleteDC (hdcImageList);
2436 DeleteDC (hdcImage);
2438 DeleteObject (ii.hbmColor);
2440 DeleteObject (ii.hbmMask);
2446 /*************************************************************************
2447 * ImageList_SetBkColor [COMCTL32.70]
2449 * Sets the background color of an image list.
2452 * himl [I] handle to image list
2453 * clrBk [I] background color
2456 * Success: previous background color
2461 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2468 clrOldBk = himl->clrBk;
2469 himl->clrBk = clrBk;
2474 /*************************************************************************
2475 * ImageList_SetDragCursorImage [COMCTL32.75]
2477 * Combines the specified image with the current drag image
2480 * himlDrag [I] handle to drag image list
2481 * iDrag [I] drag image index
2482 * dxHotspot [I] X position of the hot spot
2483 * dyHotspot [I] Y position of the hot spot
2494 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2495 INT dxHotspot, INT dyHotspot)
2497 HIMAGELIST himlTemp;
2499 FIXME("semi-stub!\n");
2501 if (himlInternalDrag == NULL)
2504 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2505 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2507 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2508 dxHotspot, dyHotspot);
2510 ImageList_Destroy (himlInternalDrag);
2511 himlInternalDrag = himlTemp;
2513 nInternalDragHotspotX = dxHotspot;
2514 nInternalDragHotspotY = dyHotspot;
2520 /*************************************************************************
2521 * ImageList_SetFilter [COMCTL32.76]
2523 * Sets a filter (or does something completely different)!!???
2526 * himl [I] handle to image list
2532 * Failure: FALSE ???
2535 * This is an UNDOCUMENTED function!!!!
2540 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2542 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2549 /*************************************************************************
2550 * ImageList_SetIconSize [COMCTL32.77]
2552 * Sets the image size of the bitmap and deletes all images.
2555 * himl [I] handle to image list
2556 * cx [I] image width
2557 * cy [I] image height
2565 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2572 /* remove all images */
2573 himl->cMaxImage = himl->cInitial + himl->cGrow;
2574 himl->cCurImage = 0;
2578 /* initialize overlay mask indices */
2579 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2580 himl->nOvlIdx[nCount] = -1;
2582 DeleteObject (himl->hbmImage);
2584 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2585 1, himl->uBitsPixel, NULL);
2587 if (himl->hbmMask) {
2588 DeleteObject (himl->hbmMask);
2590 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2598 /*************************************************************************
2599 * ImageList_SetImageCount [COMCTL32.78]
2601 * Resizes an image list to the specified number of images.
2604 * himl [I] handle to image list
2605 * iImageCount [I] number of images in the image list
2613 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2615 HDC hdcImageList, hdcBitmap;
2616 HBITMAP hbmNewBitmap;
2617 INT nNewCount, nCopyCount;
2621 if (himl->cCurImage >= iImageCount)
2623 if (himl->cMaxImage > iImageCount)
2626 nNewCount = iImageCount + himl->cGrow;
2627 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2629 hdcImageList = CreateCompatibleDC (0);
2630 hdcBitmap = CreateCompatibleDC (0);
2632 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2633 1, himl->uBitsPixel, NULL);
2634 if (hbmNewBitmap != 0)
2636 SelectObject (hdcImageList, himl->hbmImage);
2637 SelectObject (hdcBitmap, hbmNewBitmap);
2640 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2641 hdcImageList, 0, 0, SRCCOPY);
2643 /* delete 'empty' image space */
2644 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2645 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2646 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2647 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2649 DeleteObject (himl->hbmImage);
2650 himl->hbmImage = hbmNewBitmap;
2653 ERR("Could not create new image bitmap !\n");
2657 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2659 if (hbmNewBitmap != 0)
2661 SelectObject (hdcImageList, himl->hbmMask);
2662 SelectObject (hdcBitmap, hbmNewBitmap);
2665 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2666 hdcImageList, 0, 0, SRCCOPY);
2668 /* delete 'empty' image space */
2669 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2670 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2671 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2672 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2674 DeleteObject (himl->hbmMask);
2675 himl->hbmMask = hbmNewBitmap;
2678 ERR("Could not create new mask bitmap!\n");
2681 DeleteDC (hdcImageList);
2682 DeleteDC (hdcBitmap);
2684 /* Update max image count and current image count */
2685 himl->cMaxImage = nNewCount;
2686 if (himl->cCurImage > nCopyCount)
2687 himl->cCurImage = nCopyCount;
2693 /*************************************************************************
2694 * ImageList_SetOverlayImage [COMCTL32.79]
2696 * Assigns an overlay mask index to an existing image in an image list.
2699 * himl [I] handle to image list
2700 * iImage [I] image index
2701 * iOverlay [I] overlay mask index
2709 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2713 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2715 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2717 himl->nOvlIdx[iOverlay - 1] = iImage;
2722 /*************************************************************************
2723 * ImageList_Write [COMCTL32.80]
2725 * Writes an image list to a stream.
2728 * himl [I] handle to image list
2729 * pstm [O] Pointer to a stream.
2736 * This function can not be implemented yet, because
2737 * IStream32::Write is not implemented.
2744 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2749 FIXME("empty stub!\n");