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.
28 #include "wine/obj_base.h"
29 #include "wine/obj_storage.h"
31 #include "imagelist.h"
32 #include "debugtools.h"
34 DEFAULT_DEBUG_CHANNEL(imagelist);
37 #define _MAX(a,b) (((a)>(b))?(a):(b))
38 #define _MIN(a,b) (((a)>(b))?(b):(a))
40 #define MAX_OVERLAYIMAGE 15
43 /* internal image list data used for Drag & Drop operations */
45 static HIMAGELIST himlInternalDrag = NULL;
46 static INT nInternalDragHotspotX = 0;
47 static INT nInternalDragHotspotY = 0;
49 static HWND hwndInternalDrag = 0;
50 static INT xInternalPos = 0;
51 static INT yInternalPos = 0;
53 static HDC hdcBackBuffer = 0;
54 static HBITMAP hbmBackBuffer = 0;
57 /*************************************************************************
58 * IMAGELIST_InternalExpandBitmaps [Internal]
60 * Expands the bitmaps of an image list by the given number of images.
63 * himl [I] handle to image list
64 * nImageCount [I] number of images to add
70 * This function can NOT be used to reduce the number of images.
73 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
75 HDC hdcImageList, hdcBitmap;
77 INT nNewWidth, nNewCount;
79 if ((himl->cCurImage + nImageCount < himl->cMaxImage)
83 if (cy == 0) cy = himl->cy;
84 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
85 nNewWidth = nNewCount * himl->cx;
87 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
88 hdcImageList = CreateCompatibleDC (0);
89 hdcBitmap = CreateCompatibleDC (0);
92 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
93 if (hbmNewBitmap == 0)
94 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
96 SelectObject (hdcImageList, himl->hbmImage);
97 SelectObject (hdcBitmap, hbmNewBitmap);
98 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
99 hdcImageList, 0, 0, SRCCOPY);
101 DeleteObject (himl->hbmImage);
102 himl->hbmImage = hbmNewBitmap;
106 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
108 if (hbmNewBitmap == 0)
109 ERR("creating new mask bitmap!\n");
111 SelectObject (hdcImageList, himl->hbmMask);
112 SelectObject (hdcBitmap, hbmNewBitmap);
113 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
114 hdcImageList, 0, 0, SRCCOPY);
115 DeleteObject (himl->hbmMask);
116 himl->hbmMask = hbmNewBitmap;
119 himl->cMaxImage = nNewCount;
121 DeleteDC (hdcImageList);
122 DeleteDC (hdcBitmap);
126 /*************************************************************************
127 * IMAGELIST_InternalDraw [Internal]
129 * Draws the image in the ImageList (without the mask)
132 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
133 * cx [I] the width of the image to display
134 * cy............[I] the height of the image to display
140 * This functions is used by ImageList_DrawIndirect, when it is
141 * required to draw only the Image (without the mask) to the screen.
143 * Blending and Overlays styles are accomplised by another function
146 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
151 hImageDC = CreateCompatibleDC(0);
152 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
153 BitBlt(pimldp->hdcDst,
154 pimldp->x, pimldp->y, cx, cy,
156 pimldp->himl->cx * pimldp->i, 0,
159 SelectObject(hImageDC, hOldBitmap);
164 /*************************************************************************
165 * IMAGELIST_InternalDrawMask [Internal]
167 * Draws the image in the ImageList witht the mask
170 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
171 * cx [I] the width of the image to display
172 * cy............[I] the height of the image to display
178 * This functions is used by ImageList_DrawIndirect, when it is
179 * required to draw the Image with the mask to the screen.
181 * Blending and Overlays styles are accomplised by another function.
183 /*************************************************************************
184 * IMAGELIST_InternalDrawMask [Internal]
186 * Draws the image in the ImageList witht the mask
189 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
190 * cx [I] the width of the image to display
191 * cy............[I] the height of the image to display
197 * This functions is used by ImageList_DrawIndirect, when it is
198 * required to draw the Image with the mask to the screen.
200 * Blending and Overlays styles are accomplised by another function.
203 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
205 BOOL bUseCustomBackground, bBlendFlag;
206 HBRUSH hBrush, hOldBrush;
207 HDC hMaskDC, hImageDC;
208 HBITMAP hOldBitmapImage, hOldBitmapMask;
209 HIMAGELIST himlLocal = pimldp->himl;
210 COLORREF oldBkColor, oldFgColor;
211 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
214 * We need a dc and bitmap to draw on that is
217 HDC hOffScreenDC = 0;
218 HBITMAP hOffScreenBmp = 0;
220 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
221 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
223 hImageDC = CreateCompatibleDC(0);
224 hMaskDC = CreateCompatibleDC(0);
226 /* Create a compatible DC. */
227 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
231 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
234 SelectObject( hOffScreenDC, hOffScreenBmp );
241 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
242 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
245 * Get a copy of the image for the masking operations.
246 * We will use the copy, and this dc for all the various
247 * blitting, and then do one final blit to the screen dc.
248 * This should clean up most of the flickering.
250 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
254 * Draw the Background for the appropriate Styles
256 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
260 hBrush = CreateSolidBrush (himlLocal->clrBk);
261 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
263 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
265 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
269 * Draw Image Transparently over the current background
271 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
272 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
274 * To obtain a transparent look, background color should be set
275 * to white and foreground color to black when blting the
279 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
280 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
282 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
285 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
291 * Draw the image when no Background is specified
293 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
295 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
296 himlLocal->cx * pimldp->i, 0, SRCCOPY);
299 * Draw the mask with or without a background
301 else if(fStyle & ILD_MASK)
303 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
304 0, bUseCustomBackground ? SRCCOPY : SRCAND);
308 * Blit the bitmap to the screen now.
310 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
311 hOffScreenDC, 0, 0, SRCCOPY);
314 SelectObject(hImageDC, hOldBitmapImage);
315 SelectObject(hMaskDC, hOldBitmapMask);
322 DeleteDC( hOffScreenDC );
323 DeleteObject( hOffScreenBmp );
328 /*************************************************************************
329 * IMAGELIST_InternalDrawBlend [Internal]
331 * Draws the Blend over the current image
334 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
335 * cx [I] the width of the image to display
336 * cy............[I] the height of the image to display
342 * This functions is used by ImageList_DrawIndirect, when it is
343 * required to add the blend to the current image.
347 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
350 HDC hBlendMaskDC,hMaskDC;
351 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
352 HBITMAP hBlendMaskBitmap, hOldBitmap;
353 COLORREF clrBlend, OldTextColor, OldBkColor;
354 HIMAGELIST himlLocal = pimldp->himl;
356 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
357 if (!(pimldp->rgbFg == CLR_DEFAULT))
359 clrBlend = pimldp->rgbFg;
361 /* Create the blend Mask
363 hBlendMaskDC = CreateCompatibleDC(0);
364 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
365 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
367 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
368 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
370 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
371 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
372 SelectObject(hBlendMaskDC, hOldBrush);
374 /* Modify the blend mask if an Image Mask exist
376 if(pimldp->himl->hbmMask != 0)
378 HBITMAP hOldMaskBitmap;
379 hMaskDC = CreateCompatibleDC(0);
380 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
385 himlLocal->cx * pimldp->i,0,
386 0x220326); /* NOTSRCAND */
394 SelectObject(hMaskDC, hOldMaskBitmap);
398 /* Apply blend to the current image given the BlendMask
400 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
401 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
402 hBlendColorBrush = CreateSolidBrush(clrBlend);
403 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
405 BitBlt (pimldp->hdcDst,
406 pimldp->x, pimldp->y, cx, cy,
409 0xB8074A); /* PSDPxax */
411 SelectObject(pimldp->hdcDst, hOldBrush);
412 SetTextColor(pimldp->hdcDst, OldTextColor);
413 SetBkColor(pimldp->hdcDst, OldBkColor);
414 SelectObject(hBlendMaskDC, hOldBitmap);
415 DeleteDC(hBlendMaskDC);
416 DeleteObject(hBlendMaskBitmap);
417 DeleteObject(hBlendColorBrush);
420 /*************************************************************************
421 * IMAGELIST_InternalDrawOverlay [Internal]
423 * Draws the overlay image
426 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
427 * cx [I] the width of the image to display
428 * cy............[I] the height of the image to display
434 * This functions is used by ImageList_DrawIndirect, when it is
435 * required to draw the overlay
440 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
446 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
447 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
449 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
450 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
452 hImageDC = CreateCompatibleDC(0);
453 if (pimldp->himl->hbmMask)
455 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
456 pimldp->himl->hbmMask);
458 BitBlt (pimldp->hdcDst,
459 pimldp->x, pimldp->y, cx, cy,
460 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
463 SelectObject(hImageDC, hOldBitmap);
465 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
466 pimldp->himl->hbmImage);
468 BitBlt (pimldp->hdcDst,
469 pimldp->x, pimldp->y, cx, cy,
471 pimldp->himl->cx * nOvlIdx, 0,
474 SelectObject(hImageDC, hOldBitmap);
484 /*************************************************************************
485 * ImageList_Add [COMCTL32.39]
487 * Add an image or images to an image list.
490 * himl [I] handle to image list
491 * hbmImage [I] handle to image bitmap
492 * hbmMask [I] handle to mask bitmap
495 * Success: Index of the first new image.
500 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
502 HDC hdcImage, hdcBitmap;
503 INT nFirstIndex, nImageCount;
506 HBITMAP hOldBitmapImage, hOldBitmap;
508 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
509 if (!himl || !hbmImage)
512 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
513 nImageCount = bmp.bmWidth / himl->cx;
515 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
517 nStartX = himl->cCurImage * himl->cx;
519 hdcImage = CreateCompatibleDC(0);
520 hdcBitmap = CreateCompatibleDC(0);
522 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
523 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
525 /* Copy result to the imagelist
527 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
528 hdcBitmap, 0, 0, SRCCOPY);
532 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
534 hdcMask = CreateCompatibleDC (0);
535 hdcTemp = CreateCompatibleDC(0);
536 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
537 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
540 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
545 SelectObject(hdcTemp, hOldBitmapTemp);
548 /* Remove the background from the image
551 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
554 0x220326); /* NOTSRCAND */
556 SelectObject(hdcMask, hOldBitmapMask);
560 SelectObject(hdcImage, hOldBitmapImage);
561 SelectObject(hdcBitmap, hOldBitmap);
565 nFirstIndex = himl->cCurImage;
566 himl->cCurImage += nImageCount;
572 /*************************************************************************
573 * ImageList_AddIcon [COMCTL32.40]
575 * Adds an icon to an image list.
578 * himl [I] handle to image list
579 * hIcon [I] handle to icon
582 * Success: index of the new image
587 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
589 return ImageList_ReplaceIcon (himl, -1, hIcon);
593 /*************************************************************************
594 * ImageList_AddMasked [COMCTL32.41]
596 * Adds an image or images to an image list and creates a mask from the
597 * specified bitmap using the mask color.
600 * himl [I] handle to image list.
601 * hBitmap [I] handle to bitmap
602 * clrMask [I] mask color.
605 * Success: Index of the first new image.
610 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
612 HDC hdcImage, hdcMask, hdcBitmap;
613 INT nIndex, nImageCount, nMaskXOffset=0;
615 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
616 HBITMAP hMaskBitmap=0;
619 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
623 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
626 nImageCount = bmp.bmWidth / himl->cx;
628 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
630 nIndex = himl->cCurImage;
631 himl->cCurImage += nImageCount;
633 hdcMask = CreateCompatibleDC (0);
634 hdcImage = CreateCompatibleDC(0);
635 hdcBitmap = CreateCompatibleDC(0);
638 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
639 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
642 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
643 nMaskXOffset = nIndex * himl->cx;
648 Create a temp Mask so we can remove the background of
649 the Image (Windows does this even if there is no mask)
651 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
652 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
655 /* create monochrome image to the mask bitmap */
656 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
657 GetPixel (hdcBitmap, 0, 0);
658 SetBkColor (hdcBitmap, bkColor);
660 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
664 SetBkColor(hdcBitmap, RGB(255,255,255));
665 /*Remove the background from the image
668 WINDOWS BUG ALERT!!!!!!
669 The statement below should not be done in common practice
670 but this is how ImageList_AddMasked works in Windows.
671 It overwrites the original bitmap passed, this was discovered
672 by using the same bitmap to itterated the different styles
673 on windows where it failed (BUT ImageList_Add is OK)
674 This is here in case some apps really on this bug
677 0, 0, bmp.bmWidth, bmp.bmHeight,
680 0x220326); /* NOTSRCAND */
681 /* Copy result to the imagelist
684 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
690 SelectObject(hdcMask,hOldBitmapMask);
691 SelectObject(hdcImage, hOldBitmapImage);
692 SelectObject(hdcBitmap, hOldBitmap);
698 DeleteObject(hMaskBitmap);
705 /*************************************************************************
706 * ImageList_BeginDrag [COMCTL32.42]
708 * Creates a temporary image list that contains one image. It will be used
712 * himlTrack [I] handle to the source image list
713 * iTrack [I] index of the drag image in the source image list
714 * dxHotspot [I] X position of the hot spot of the drag image
715 * dyHotspot [I] Y position of the hot spot of the drag image
723 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
724 INT dxHotspot, INT dyHotspot)
728 FIXME("partially implemented!\n");
730 if (himlTrack == NULL)
733 if (himlInternalDrag)
734 ImageList_EndDrag ();
737 ImageList_Create (himlTrack->cx, himlTrack->cy,
738 himlTrack->flags, 1, 1);
739 if (himlInternalDrag == NULL) {
740 ERR("Error creating drag image list!\n");
744 nInternalDragHotspotX = dxHotspot;
745 nInternalDragHotspotY = dyHotspot;
747 hdcSrc = CreateCompatibleDC (0);
748 hdcDst = CreateCompatibleDC (0);
751 SelectObject (hdcSrc, himlTrack->hbmImage);
752 SelectObject (hdcDst, himlInternalDrag->hbmImage);
753 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
754 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
757 SelectObject (hdcSrc, himlTrack->hbmMask);
758 SelectObject (hdcDst, himlInternalDrag->hbmMask);
759 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
760 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
765 himlInternalDrag->cCurImage = 1;
771 /*************************************************************************
772 * ImageList_Copy [COMCTL32.43]
774 * Copies an image of the source image list to an image of the
775 * destination image list. Images can be copied or swapped.
778 * himlDst [I] handle to the destination image list
779 * iDst [I] destination image index.
780 * himlSrc [I] handle to the source image list
781 * iSrc [I] source image index
782 * uFlags [I] flags for the copy operation
789 * Copying from one image list to another is possible. The original
790 * implementation just copies or swapps within one image list.
791 * Could this feature become a bug??? ;-)
795 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
796 INT iSrc, INT uFlags)
800 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
802 if ((himlSrc == NULL) || (himlDst == NULL))
804 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
806 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
809 hdcSrc = CreateCompatibleDC (0);
810 if (himlDst == himlSrc)
813 hdcDst = CreateCompatibleDC (0);
815 if (uFlags & ILCF_SWAP) {
817 HBITMAP hbmTempImage, hbmTempMask;
819 /* create temporary bitmaps */
820 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
821 himlSrc->uBitsPixel, NULL);
822 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
825 /* copy (and stretch) destination to temporary bitmaps.(save) */
827 SelectObject (hdcSrc, himlDst->hbmImage);
828 SelectObject (hdcDst, hbmTempImage);
829 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
830 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
833 SelectObject (hdcSrc, himlDst->hbmMask);
834 SelectObject (hdcDst, hbmTempMask);
835 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
836 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
839 /* copy (and stretch) source to destination */
841 SelectObject (hdcSrc, himlSrc->hbmImage);
842 SelectObject (hdcDst, himlDst->hbmImage);
843 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
844 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
847 SelectObject (hdcSrc, himlSrc->hbmMask);
848 SelectObject (hdcDst, himlDst->hbmMask);
849 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
850 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
853 /* copy (without stretching) temporary bitmaps to source (restore) */
855 SelectObject (hdcSrc, hbmTempImage);
856 SelectObject (hdcDst, himlSrc->hbmImage);
857 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
858 hdcSrc, 0, 0, SRCCOPY);
860 SelectObject (hdcSrc, hbmTempMask);
861 SelectObject (hdcDst, himlSrc->hbmMask);
862 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
863 hdcSrc, 0, 0, SRCCOPY);
865 /* delete temporary bitmaps */
866 DeleteObject (hbmTempMask);
867 DeleteObject (hbmTempImage);
871 SelectObject (hdcSrc, himlSrc->hbmImage);
872 if (himlSrc == himlDst)
875 SelectObject (hdcDst, himlDst->hbmImage);
876 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
877 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
881 SelectObject (hdcSrc, himlSrc->hbmMask);
882 if (himlSrc == himlDst)
885 SelectObject (hdcDst, himlDst->hbmMask);
886 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
887 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
892 if (himlSrc != himlDst)
899 /*************************************************************************
900 * ImageList_Create [COMCTL32.44] Creates a new image list.
903 * cx [I] image height
905 * flags [I] creation flags
906 * cInitial [I] initial number of images in the image list
907 * cGrow [I] number of images by which image list grows
910 * Success: Handle to the created image list
915 ImageList_Create (INT cx, INT cy, UINT flags,
916 INT cInitial, INT cGrow)
922 static WORD aBitBlend25[] =
923 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
925 static WORD aBitBlend50[] =
926 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
928 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
930 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
937 himl->cMaxImage = cInitial + cGrow;
938 himl->cInitial = cInitial;
941 himl->clrFg = CLR_DEFAULT;
942 himl->clrBk = CLR_NONE;
944 /* initialize overlay mask indices */
945 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
946 himl->nOvlIdx[nCount] = -1;
948 hdc = CreateCompatibleDC (0);
949 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
952 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
954 if (himl->cMaxImage > 0) {
956 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
957 1, himl->uBitsPixel, NULL);
958 if (himl->hbmImage == 0) {
959 ERR("Error creating image bitmap!\n");
966 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
967 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
969 if (himl->hbmMask == 0) {
970 ERR("Error creating mask bitmap!\n");
972 DeleteObject (himl->hbmImage);
979 /* create blending brushes */
980 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
981 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
982 DeleteObject (hbmTemp);
984 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
985 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
986 DeleteObject (hbmTemp);
988 TRACE("created imagelist %p\n", himl);
993 /*************************************************************************
994 * ImageList_Destroy [COMCTL32.45]
996 * Destroys an image list.
999 * himl [I] handle to image list
1007 ImageList_Destroy (HIMAGELIST himl)
1012 /* delete image bitmaps */
1014 DeleteObject (himl->hbmImage);
1016 DeleteObject (himl->hbmMask);
1018 /* delete blending brushes */
1019 if (himl->hbrBlend25)
1020 DeleteObject (himl->hbrBlend25);
1021 if (himl->hbrBlend50)
1022 DeleteObject (himl->hbrBlend50);
1024 COMCTL32_Free (himl);
1030 /*************************************************************************
1031 * ImageList_DragEnter [COMCTL32.46]
1033 * Locks window update and displays the drag image at the given position.
1036 * hwndLock [I] handle of the window that owns the drag image.
1037 * x [I] X position of the drag image.
1038 * y [I] Y position of the drag image.
1045 * The position of the drag image is relative to the window, not
1050 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1052 if (himlInternalDrag == NULL)
1056 hwndInternalDrag = hwndLock;
1058 hwndInternalDrag = GetDesktopWindow ();
1063 hdcBackBuffer = CreateCompatibleDC (0);
1064 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1065 himlInternalDrag->cx, himlInternalDrag->cy);
1067 ImageList_DragShowNolock (TRUE);
1073 /*************************************************************************
1074 * ImageList_DragLeave [COMCTL32.47]
1076 * Unlocks window update and hides the drag image.
1079 * hwndLock [I] handle of the window that owns the drag image.
1087 ImageList_DragLeave (HWND hwndLock)
1090 hwndInternalDrag = hwndLock;
1092 hwndInternalDrag = GetDesktopWindow ();
1094 ImageList_DragShowNolock (FALSE);
1096 DeleteDC (hdcBackBuffer);
1097 DeleteObject (hbmBackBuffer);
1103 /*************************************************************************
1104 * ImageList_DragMove [COMCTL32.48]
1106 * Moves the drag image.
1109 * x [I] X position of the drag image.
1110 * y [I] Y position of the drag image.
1117 * The position of the drag image is relative to the window, not
1122 ImageList_DragMove (INT x, INT y)
1124 ImageList_DragShowNolock (FALSE);
1129 ImageList_DragShowNolock (TRUE);
1135 /*************************************************************************
1136 * ImageList_DragShowNolock [COMCTL32.49]
1138 * Shows or hides the drag image.
1141 * bShow [I] TRUE shows the drag image, FALSE hides it.
1152 ImageList_DragShowNolock (BOOL bShow)
1156 FIXME("semi-stub!\n");
1157 TRACE("bShow=0x%X!\n", bShow);
1159 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1160 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1163 /* show drag image */
1165 /* save background */
1167 /* draw drag image */
1171 /* hide drag image */
1173 /* restore background */
1177 ReleaseDC (hwndInternalDrag, hdcDrag);
1183 /*************************************************************************
1184 * ImageList_Draw [COMCTL32.50] Draws an image.
1187 * himl [I] handle to image list
1189 * hdc [I] handle to device context
1192 * fStyle [I] drawing flags
1199 * Calls ImageList_DrawIndirect.
1202 * ImageList_DrawIndirect.
1206 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1207 INT x, INT y, UINT fStyle)
1209 IMAGELISTDRAWPARAMS imldp;
1211 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1221 imldp.rgbBk = CLR_DEFAULT;
1222 imldp.rgbFg = CLR_DEFAULT;
1223 imldp.fStyle = fStyle;
1226 return ImageList_DrawIndirect (&imldp);
1230 /*************************************************************************
1231 * ImageList_DrawEx [COMCTL32.51]
1233 * Draws an image and allows to use extended drawing features.
1236 * himl [I] handle to image list
1238 * hdc [I] handle to device context
1241 * xOffs [I] X offset
1242 * yOffs [I] Y offset
1243 * rgbBk [I] background color
1244 * rgbFg [I] foreground color
1245 * fStyle [I] drawing flags
1252 * Calls ImageList_DrawIndirect.
1255 * ImageList_DrawIndirect.
1259 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1260 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1263 IMAGELISTDRAWPARAMS imldp;
1265 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1275 imldp.rgbBk = rgbBk;
1276 imldp.rgbFg = rgbFg;
1277 imldp.fStyle = fStyle;
1280 return ImageList_DrawIndirect (&imldp);
1284 /*************************************************************************
1285 * ImageList_DrawIndirect [COMCTL32.52]
1287 * Draws an image using ...
1290 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1298 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1302 Do some Error Checking
1306 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1308 if (pimldp->himl == NULL)
1310 if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage)) {
1311 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage);
1315 Get the Height and Width to display
1317 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1318 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1322 if(pimldp->himl->hbmMask != 0)
1324 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1328 IMAGELIST_InternalDraw(pimldp, cx, cy);
1331 Apply the blend if needed to the Image
1333 if((pimldp->fStyle & ILD_BLEND50)
1334 || (pimldp->fStyle & ILD_BLEND25))
1336 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1339 Apply the Overlay if needed
1341 if (pimldp->fStyle & ILD_OVERLAYMASK)
1343 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1350 /*************************************************************************
1351 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1354 * himlSrc [I] source image list handle
1357 * Success: Handle of duplicated image list.
1362 ImageList_Duplicate (HIMAGELIST himlSrc)
1367 if (himlSrc == NULL) {
1368 ERR("Invalid image list handle!\n");
1372 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1373 himlSrc->cInitial, himlSrc->cGrow);
1377 hdcSrc = CreateCompatibleDC (0);
1378 hdcDst = CreateCompatibleDC (0);
1379 SelectObject (hdcSrc, himlSrc->hbmImage);
1380 SelectObject (hdcDst, himlDst->hbmImage);
1381 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1382 hdcSrc, 0, 0, SRCCOPY);
1384 if (himlDst->hbmMask)
1386 SelectObject (hdcSrc, himlSrc->hbmMask);
1387 SelectObject (hdcDst, himlDst->hbmMask);
1388 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1389 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1395 himlDst->cCurImage = himlSrc->cCurImage;
1396 himlDst->cMaxImage = himlSrc->cMaxImage;
1402 /*************************************************************************
1403 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1405 * Finishes a drag operation.
1419 ImageList_EndDrag (void)
1421 FIXME("semi-stub!\n");
1423 if (himlInternalDrag)
1426 ImageList_Destroy (himlInternalDrag);
1427 himlInternalDrag = NULL;
1429 nInternalDragHotspotX = 0;
1430 nInternalDragHotspotY = 0;
1438 /*************************************************************************
1439 * ImageList_GetBkColor [COMCTL32.55]
1441 * Returns the background color of an image list.
1444 * himl [I] Image list handle.
1447 * Success: background color
1452 ImageList_GetBkColor (HIMAGELIST himl)
1461 /*************************************************************************
1462 * ImageList_GetDragImage [COMCTL32.56]
1464 * Returns the handle to the internal drag image list.
1467 * ppt [O] Pointer to the drag position. Can be NULL.
1468 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1471 * Success: Handle of the drag image list.
1479 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1481 FIXME("semi-stub!\n");
1483 if (himlInternalDrag)
1484 return (himlInternalDrag);
1490 /*************************************************************************
1491 * ImageList_GetIcon [COMCTL32.57]
1493 * Creates an icon from a masked image of an image list.
1496 * himl [I] handle to image list
1498 * flags [I] drawing style flags
1501 * Success: icon handle
1506 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1510 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1513 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1514 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1518 hdcSrc = CreateCompatibleDC(0);
1519 hdcDst = CreateCompatibleDC(0);
1522 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1525 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1526 if (himl->hbmMask) {
1527 SelectObject (hdcSrc, himl->hbmMask);
1528 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1529 hdcSrc, i * himl->cx, 0, SRCCOPY);
1532 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1535 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1536 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1537 SelectObject (hdcDst, ii.hbmColor);
1538 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1539 hdcSrc, i * himl->cx, 0, SRCCOPY);
1542 * CreateIconIndirect requires us to deselect the bitmaps from
1543 * the DCs before calling
1545 SelectObject(hdcSrc, hOldSrcBitmap);
1546 SelectObject(hdcDst, hOldDstBitmap);
1548 hIcon = CreateIconIndirect (&ii);
1552 DeleteObject (ii.hbmMask);
1553 DeleteObject (ii.hbmColor);
1559 /*************************************************************************
1560 * ImageList_GetIconSize [COMCTL32.58]
1562 * Retrieves the size of an image in an image list.
1565 * himl [I] handle to image list
1566 * cx [O] pointer to the image width.
1567 * cy [O] pointer to the image height.
1574 * All images in an image list have the same size.
1578 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1582 if ((himl->cx <= 0) || (himl->cy <= 0))
1594 /*************************************************************************
1595 * ImageList_GetImageCount [COMCTL32.59]
1597 * Returns the number of images in an image list.
1600 * himl [I] handle to image list
1603 * Success: Number of images.
1608 ImageList_GetImageCount (HIMAGELIST himl)
1613 return himl->cCurImage;
1617 /*************************************************************************
1618 * ImageList_GetImageInfo [COMCTL32.60]
1620 * Returns information about an image in an image list.
1623 * himl [I] handle to image list
1625 * pImageInfo [O] pointer to the image information
1633 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1635 if ((himl == NULL) || (pImageInfo == NULL))
1637 if ((i < 0) || (i >= himl->cCurImage))
1640 pImageInfo->hbmImage = himl->hbmImage;
1641 pImageInfo->hbmMask = himl->hbmMask;
1643 pImageInfo->rcImage.top = 0;
1644 pImageInfo->rcImage.bottom = himl->cy;
1645 pImageInfo->rcImage.left = i * himl->cx;
1646 pImageInfo->rcImage.right = (i+1) * himl->cx;
1652 /*************************************************************************
1653 * ImageList_GetImageRect [COMCTL32.61]
1655 * Retrieves the rectangle of the specified image in an image list.
1658 * himl [I] handle to image list
1660 * lpRect [O] pointer to the image rectangle
1667 * This is an UNDOCUMENTED function!!!
1671 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1673 if ((himl == NULL) || (lpRect == NULL))
1675 if ((i < 0) || (i >= himl->cCurImage))
1678 lpRect->left = i * himl->cx;
1680 lpRect->right = lpRect->left + himl->cx;
1681 lpRect->bottom = himl->cy;
1687 /*************************************************************************
1688 * ImageList_LoadImageA [COMCTL32.63][COMCTL32.62]
1690 * Creates an image list from a bitmap, icon or cursor.
1693 * hi [I] instance handle
1694 * lpbmp [I] name or id of the image
1695 * cx [I] width of each image
1696 * cGrow [I] number of images to expand
1697 * clrMask [I] mask color
1698 * uType [I] type of image to load
1699 * uFlags [I] loading flags
1702 * Success: handle to the loaded image list
1710 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1711 COLORREF clrMask, UINT uType, UINT uFlags)
1713 HIMAGELIST himl = NULL;
1717 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1719 ERR("Error loading image!\n");
1723 if (uType == IMAGE_BITMAP) {
1725 GetObjectA (handle, sizeof(BITMAP), &bmp);
1727 /* To match windows behavior, if cx is set to zero and
1728 the flag DI_DEFAULTSIZE is specified, cx becomes the
1729 system metric value for icons. If the flag is not specified
1730 the function sets the size to the height of the bitmap */
1733 if (uFlags & DI_DEFAULTSIZE)
1734 cx = GetSystemMetrics (SM_CXICON);
1739 nImageCount = bmp.bmWidth / cx;
1741 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1742 nImageCount, cGrow);
1743 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1745 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1749 GetIconInfo (handle, &ii);
1750 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1751 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1752 ILC_MASK | ILC_COLOR, 1, cGrow);
1753 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1754 DeleteObject (ii.hbmColor);
1755 DeleteObject (ii.hbmMask);
1758 DeleteObject (handle);
1764 /*************************************************************************
1765 * ImageList_LoadImageW [COMCTL32.64]
1767 * Creates an image list from a bitmap, icon or cursor.
1770 * hi [I] instance handle
1771 * lpbmp [I] name or id of the image
1772 * cx [I] width of each image
1773 * cGrow [I] number of images to expand
1774 * clrMask [I] mask color
1775 * uType [I] type of image to load
1776 * uFlags [I] loading flags
1779 * Success: handle to the loaded image list
1787 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1788 COLORREF clrMask, UINT uType, UINT uFlags)
1790 HIMAGELIST himl = NULL;
1794 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1796 ERR("Error loading image!\n");
1800 if (uType == IMAGE_BITMAP) {
1802 GetObjectA (handle, sizeof(BITMAP), &bmp);
1803 nImageCount = bmp.bmWidth / cx;
1805 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1806 nImageCount, cGrow);
1807 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1809 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1813 GetIconInfo (handle, &ii);
1814 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1815 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1816 ILC_MASK | ILC_COLOR, 1, cGrow);
1817 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1818 DeleteObject (ii.hbmColor);
1819 DeleteObject (ii.hbmMask);
1822 DeleteObject (handle);
1828 /*************************************************************************
1829 * ImageList_Merge [COMCTL32.65]
1831 * Creates a new image list that contains a merged image from the specified
1832 * images of both source image lists.
1835 * himl1 [I] handle to first image list
1836 * i1 [I] first image index
1837 * himl2 [I] handle to second image list
1838 * i2 [I] second image index
1839 * dx [I] X offset of the second image relative to the first.
1840 * dy [I] Y offset of the second image relative to the first.
1843 * Success: handle of the merged image list.
1848 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1851 HIMAGELIST himlDst = NULL;
1852 HDC hdcSrcImage, hdcDstImage;
1854 INT xOff1, yOff1, xOff2, yOff2;
1857 if ((himl1 == NULL) || (himl2 == NULL))
1861 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1862 ERR("Index 1 out of range! %d\n", i1);
1866 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1867 ERR("Index 2 out of range! %d\n", i2);
1872 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1877 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1882 cxDst = _MAX (himl1->cx, himl2->cx);
1888 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1893 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1898 cyDst = _MAX (himl1->cy, himl2->cy);
1903 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1906 hdcSrcImage = CreateCompatibleDC (0);
1907 hdcDstImage = CreateCompatibleDC (0);
1908 nX1 = i1 * himl1->cx;
1909 nX2 = i2 * himl2->cx;
1912 SelectObject (hdcSrcImage, himl1->hbmImage);
1913 SelectObject (hdcDstImage, himlDst->hbmImage);
1914 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1915 hdcSrcImage, 0, 0, BLACKNESS);
1916 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1917 hdcSrcImage, nX1, 0, SRCCOPY);
1919 SelectObject (hdcSrcImage, himl2->hbmMask);
1920 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1921 hdcSrcImage, nX2, 0, SRCAND);
1923 SelectObject (hdcSrcImage, himl2->hbmImage);
1924 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1925 hdcSrcImage, nX2, 0, SRCPAINT);
1928 SelectObject (hdcSrcImage, himl1->hbmMask);
1929 SelectObject (hdcDstImage, himlDst->hbmMask);
1930 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1931 hdcSrcImage, 0, 0, WHITENESS);
1932 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1933 hdcSrcImage, nX1, 0, SRCCOPY);
1935 SelectObject (hdcSrcImage, himl2->hbmMask);
1936 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1937 hdcSrcImage, nX2, 0, SRCAND);
1939 DeleteDC (hdcSrcImage);
1940 DeleteDC (hdcDstImage);
1947 /* helper for _read_bitmap currently unused */
1949 static int may_use_dibsection(HDC hdc) {
1950 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1955 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1959 /* helper for ImageList_Read, see comments below */
1960 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1962 BITMAPFILEHEADER bmfh;
1963 BITMAPINFOHEADER bmih;
1964 int bitsperpixel,palspace,longsperline,width,height;
1965 LPBITMAPINFOHEADER bmihc = NULL;
1967 HBITMAP hbitmap = 0;
1968 LPBYTE bits = NULL,nbits = NULL;
1969 int nbytesperline,bytesperline;
1971 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1972 (bmfh.bfType != (('M'<<8)|'B')) ||
1973 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1974 (bmih.biSize != sizeof(bmih))
1978 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1979 if (bitsperpixel<=8)
1980 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1983 width = bmih.biWidth;
1984 height = bmih.biHeight;
1985 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1986 memcpy(bmihc,&bmih,sizeof(bmih));
1987 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1988 bmihc->biSizeImage = (longsperline*height)<<2;
1990 /* read the palette right after the end of the bitmapinfoheader */
1992 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1996 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1997 if ((bitsperpixel>1) &&
1998 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2000 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2003 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2009 int i,nwidth,nheight;
2011 nwidth = width*(height/cy);
2014 if (bitsperpixel==1)
2015 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2017 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2019 /* Might be a bit excessive memory use here */
2020 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2021 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2022 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2025 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2026 /* Do not forget that windows bitmaps are bottom->top */
2027 bytesperline = longsperline*4;
2028 nbytesperline = (height/cy)*bytesperline;
2029 for (i=0;i<height;i++) {
2031 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2032 bits+bytesperline*(height-1-i),
2036 bmihc->biWidth = nwidth;
2037 bmihc->biHeight = nheight;
2038 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2040 LocalFree((HLOCAL)nbits);
2041 LocalFree((HLOCAL)bits);
2045 if (xdc) ReleaseDC(0,xdc);
2046 if (bmihc) LocalFree((HLOCAL)bmihc);
2049 DeleteObject(hbitmap);
2056 /*************************************************************************
2057 * ImageList_Read [COMCTL32.66]
2059 * Reads an image list from a stream.
2062 * pstm [I] pointer to a stream
2065 * Success: handle to image list
2068 * The format is like this:
2069 * ILHEAD ilheadstruct;
2071 * for the color image part:
2072 * BITMAPFILEHEADER bmfh;
2073 * BITMAPINFOHEADER bmih;
2074 * only if it has a palette:
2075 * RGBQUAD rgbs[nr_of_paletted_colors];
2077 * BYTE colorbits[imagesize];
2079 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2080 * BITMAPFILEHEADER bmfh_mask;
2081 * BITMAPINFOHEADER bmih_mask;
2082 * only if it has a palette (it usually does not):
2083 * RGBQUAD rgbs[nr_of_paletted_colors];
2085 * BYTE maskbits[imagesize];
2087 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2088 * _read_bitmap needs to convert them.
2090 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2094 HBITMAP hbmColor=0,hbmMask=0;
2097 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2099 if (ilHead.usMagic != (('L' << 8) | 'I'))
2101 if (ilHead.usVersion != 0x101) /* probably version? */
2105 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2106 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2107 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2108 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2109 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2110 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2111 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2112 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2113 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2114 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2117 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2120 if (ilHead.flags & ILC_MASK) {
2121 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2123 DeleteObject(hbmColor);
2128 himl = ImageList_Create (
2136 DeleteObject(hbmColor);
2137 DeleteObject(hbmMask);
2140 himl->hbmImage = hbmColor;
2141 himl->hbmMask = hbmMask;
2142 himl->cCurImage = ilHead.cCurImage;
2143 himl->cMaxImage = ilHead.cMaxImage;
2145 ImageList_SetBkColor(himl,ilHead.bkcolor);
2147 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2152 /*************************************************************************
2153 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2156 * himl [I] image list handle
2165 ImageList_Remove (HIMAGELIST himl, INT i)
2167 HBITMAP hbmNewImage, hbmNewMask;
2171 if ((i < -1) || (i >= himl->cCurImage)) {
2172 ERR("index out of range! %d\n", i);
2176 if (himl->cCurImage == 0) {
2177 ERR("image list is already empty!\n");
2183 TRACE("remove all!\n");
2185 himl->cMaxImage = himl->cInitial + himl->cGrow;
2186 himl->cCurImage = 0;
2187 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2188 himl->nOvlIdx[nCount] = -1;
2190 DeleteObject (himl->hbmImage);
2192 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2193 1, himl->uBitsPixel, NULL);
2195 if (himl->hbmMask) {
2196 DeleteObject (himl->hbmMask);
2198 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2203 /* delete one image */
2204 TRACE("Remove single image! %d\n", i);
2206 /* create new bitmap(s) */
2207 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2209 TRACE(" - Number of images: %d / %d (Old/New)\n",
2210 himl->cCurImage, himl->cCurImage - 1);
2211 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2212 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2215 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2218 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2220 hbmNewMask = 0; /* Just to keep compiler happy! */
2222 hdcSrc = CreateCompatibleDC (0);
2223 hdcDst = CreateCompatibleDC (0);
2225 /* copy all images and masks prior to the "removed" image */
2227 TRACE("Pre image copy: Copy %d images\n", i);
2229 SelectObject (hdcSrc, himl->hbmImage);
2230 SelectObject (hdcDst, hbmNewImage);
2231 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2232 hdcSrc, 0, 0, SRCCOPY);
2234 if (himl->hbmMask) {
2235 SelectObject (hdcSrc, himl->hbmMask);
2236 SelectObject (hdcDst, hbmNewMask);
2237 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2238 hdcSrc, 0, 0, SRCCOPY);
2242 /* copy all images and masks behind the removed image */
2243 if (i < himl->cCurImage - 1) {
2244 TRACE("Post image copy!\n");
2245 SelectObject (hdcSrc, himl->hbmImage);
2246 SelectObject (hdcDst, hbmNewImage);
2247 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2248 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2250 if (himl->hbmMask) {
2251 SelectObject (hdcSrc, himl->hbmMask);
2252 SelectObject (hdcDst, hbmNewMask);
2253 BitBlt (hdcDst, i * himl->cx, 0,
2254 (himl->cCurImage - i - 1) * himl->cx,
2255 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2262 /* delete old images and insert new ones */
2263 DeleteObject (himl->hbmImage);
2264 himl->hbmImage = hbmNewImage;
2265 if (himl->hbmMask) {
2266 DeleteObject (himl->hbmMask);
2267 himl->hbmMask = hbmNewMask;
2271 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2278 /*************************************************************************
2279 * ImageList_Replace [COMCTL32.68]
2281 * Replaces an image in an image list with a new image.
2284 * himl [I] handle to image list
2286 * hbmImage [I] handle to image bitmap
2287 * hbmMask [I] handle to mask bitmap. Can be NULL.
2295 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2298 HDC hdcImageList, hdcImage;
2302 ERR("Invalid image list handle!\n");
2306 if ((i >= himl->cMaxImage) || (i < 0)) {
2307 ERR("Invalid image index!\n");
2311 hdcImageList = CreateCompatibleDC (0);
2312 hdcImage = CreateCompatibleDC (0);
2313 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2316 SelectObject (hdcImageList, himl->hbmImage);
2317 SelectObject (hdcImage, hbmImage);
2319 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2320 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2325 SelectObject (hdcImageList, himl->hbmMask);
2326 SelectObject (hdcImage, hbmMask);
2328 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2329 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2332 /* Remove the background from the image
2334 SelectObject (hdcImageList, himl->hbmImage);
2335 StretchBlt (hdcImageList,
2336 i*himl->cx, 0, himl->cx, himl->cy,
2338 0, 0, bmp.bmWidth, bmp.bmHeight,
2339 0x220326); /* NOTSRCAND */
2342 DeleteDC (hdcImage);
2343 DeleteDC (hdcImageList);
2349 /*************************************************************************
2350 * ImageList_ReplaceIcon [COMCTL32.69]
2352 * Replaces an image in an image list using an icon.
2355 * himl [I] handle to image list
2357 * hIcon [I] handle to icon
2360 * Success: index of the replaced image
2365 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2367 HDC hdcImageList, hdcImage;
2370 HBITMAP hbmOldSrc, hbmOldDst;
2374 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2378 if ((i >= himl->cMaxImage) || (i < -1))
2381 hBestFitIcon = CopyImage(
2384 LR_COPYFROMRESOURCE);
2386 GetIconInfo (hBestFitIcon, &ii);
2387 if (ii.hbmMask == 0)
2389 if (ii.hbmColor == 0)
2391 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2394 if (himl->cCurImage + 1 >= himl->cMaxImage)
2395 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2397 nIndex = himl->cCurImage;
2403 hdcImageList = CreateCompatibleDC (0);
2404 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2405 if (hdcImageList == 0)
2406 ERR("invalid hdcImageList!\n");
2408 hdcImage = CreateCompatibleDC (0);
2409 TRACE("hdcImage=0x%x!\n", hdcImage);
2411 ERR("invalid hdcImage!\n");
2413 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2414 SetTextColor( hdcImageList, RGB(0,0,0));
2415 SetBkColor( hdcImageList, RGB(255,255,255));
2416 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2417 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2418 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2420 if (himl->hbmMask) {
2421 SelectObject (hdcImageList, himl->hbmMask);
2422 SelectObject (hdcImage, ii.hbmMask);
2423 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2424 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2427 SelectObject (hdcImage, hbmOldSrc);
2428 SelectObject (hdcImageList, hbmOldDst);
2431 DestroyIcon(hBestFitIcon);
2433 DeleteDC (hdcImageList);
2435 DeleteDC (hdcImage);
2437 DeleteObject (ii.hbmColor);
2439 DeleteObject (ii.hbmMask);
2445 /*************************************************************************
2446 * ImageList_SetBkColor [COMCTL32.70]
2448 * Sets the background color of an image list.
2451 * himl [I] handle to image list
2452 * clrBk [I] background color
2455 * Success: previous background color
2460 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2467 clrOldBk = himl->clrBk;
2468 himl->clrBk = clrBk;
2473 /*************************************************************************
2474 * ImageList_SetDragCursorImage [COMCTL32.75]
2476 * Combines the specified image with the current drag image
2479 * himlDrag [I] handle to drag image list
2480 * iDrag [I] drag image index
2481 * dxHotspot [I] X position of the hot spot
2482 * dyHotspot [I] Y position of the hot spot
2493 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2494 INT dxHotspot, INT dyHotspot)
2496 HIMAGELIST himlTemp;
2498 FIXME("semi-stub!\n");
2500 if (himlInternalDrag == NULL)
2503 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2504 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2506 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2507 dxHotspot, dyHotspot);
2509 ImageList_Destroy (himlInternalDrag);
2510 himlInternalDrag = himlTemp;
2512 nInternalDragHotspotX = dxHotspot;
2513 nInternalDragHotspotY = dyHotspot;
2519 /*************************************************************************
2520 * ImageList_SetFilter [COMCTL32.76]
2522 * Sets a filter (or does something completely different)!!???
2525 * himl [I] handle to image list
2531 * Failure: FALSE ???
2534 * This is an UNDOCUMENTED function!!!!
2539 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2541 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2548 /*************************************************************************
2549 * ImageList_SetIconSize [COMCTL32.77]
2551 * Sets the image size of the bitmap and deletes all images.
2554 * himl [I] handle to image list
2555 * cx [I] image width
2556 * cy [I] image height
2564 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2571 /* remove all images */
2572 himl->cMaxImage = himl->cInitial + himl->cGrow;
2573 himl->cCurImage = 0;
2577 /* initialize overlay mask indices */
2578 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2579 himl->nOvlIdx[nCount] = -1;
2581 DeleteObject (himl->hbmImage);
2583 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2584 1, himl->uBitsPixel, NULL);
2586 if (himl->hbmMask) {
2587 DeleteObject (himl->hbmMask);
2589 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2597 /*************************************************************************
2598 * ImageList_SetImageCount [COMCTL32.78]
2600 * Resizes an image list to the specified number of images.
2603 * himl [I] handle to image list
2604 * iImageCount [I] number of images in the image list
2612 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2614 HDC hdcImageList, hdcBitmap;
2615 HBITMAP hbmNewBitmap;
2616 INT nNewCount, nCopyCount;
2620 if (himl->cCurImage >= iImageCount)
2622 if (himl->cMaxImage > iImageCount)
2625 nNewCount = iImageCount + himl->cGrow;
2626 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2628 hdcImageList = CreateCompatibleDC (0);
2629 hdcBitmap = CreateCompatibleDC (0);
2631 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2632 1, himl->uBitsPixel, NULL);
2633 if (hbmNewBitmap != 0)
2635 SelectObject (hdcImageList, himl->hbmImage);
2636 SelectObject (hdcBitmap, hbmNewBitmap);
2639 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2640 hdcImageList, 0, 0, SRCCOPY);
2642 /* delete 'empty' image space */
2643 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2644 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2645 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2646 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2648 DeleteObject (himl->hbmImage);
2649 himl->hbmImage = hbmNewBitmap;
2652 ERR("Could not create new image bitmap !\n");
2656 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2658 if (hbmNewBitmap != 0)
2660 SelectObject (hdcImageList, himl->hbmMask);
2661 SelectObject (hdcBitmap, hbmNewBitmap);
2664 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2665 hdcImageList, 0, 0, SRCCOPY);
2667 /* delete 'empty' image space */
2668 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2669 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2670 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2671 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2673 DeleteObject (himl->hbmMask);
2674 himl->hbmMask = hbmNewBitmap;
2677 ERR("Could not create new mask bitmap!\n");
2680 DeleteDC (hdcImageList);
2681 DeleteDC (hdcBitmap);
2683 /* Update max image count and current image count */
2684 himl->cMaxImage = nNewCount;
2685 if (himl->cCurImage > nCopyCount)
2686 himl->cCurImage = nCopyCount;
2692 /*************************************************************************
2693 * ImageList_SetOverlayImage [COMCTL32.79]
2695 * Assigns an overlay mask index to an existing image in an image list.
2698 * himl [I] handle to image list
2699 * iImage [I] image index
2700 * iOverlay [I] overlay mask index
2708 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2712 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2714 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2716 himl->nOvlIdx[iOverlay - 1] = iImage;
2721 /*************************************************************************
2722 * ImageList_Write [COMCTL32.80]
2724 * Writes an image list to a stream.
2727 * himl [I] handle to image list
2728 * pstm [O] Pointer to a stream.
2735 * This function can not be implemented yet, because
2736 * IStream32::Write is not implemented.
2743 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2748 FIXME("empty stub!\n");