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 function 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 accomplished 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 with 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 function 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 accomplished by another function.
185 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
187 BOOL bUseCustomBackground, bBlendFlag;
188 HBRUSH hBrush, hOldBrush;
189 HDC hMaskDC, hImageDC;
190 HBITMAP hOldBitmapImage, hOldBitmapMask;
191 HIMAGELIST himlLocal = pimldp->himl;
192 COLORREF oldBkColor, oldFgColor;
193 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
196 * We need a dc and bitmap to draw on that is
199 HDC hOffScreenDC = 0;
200 HBITMAP hOffScreenBmp = 0;
202 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
203 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
205 hImageDC = CreateCompatibleDC(0);
206 hMaskDC = CreateCompatibleDC(0);
208 /* Create a compatible DC. */
209 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
213 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
216 SelectObject( hOffScreenDC, hOffScreenBmp );
223 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
224 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
227 * Get a copy of the image for the masking operations.
228 * We will use the copy, and this dc for all the various
229 * blitting, and then do one final blit to the screen dc.
230 * This should clean up most of the flickering.
232 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
236 * Draw the Background for the appropriate Styles
238 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
242 hBrush = CreateSolidBrush (himlLocal->clrBk);
243 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
245 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
247 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
251 * Draw Image Transparently over the current background
253 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
254 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
256 * To obtain a transparent look, background color should be set
257 * to white and foreground color to black when blting the
261 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
262 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
264 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
267 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
273 * Draw the image when no Background is specified
275 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
277 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
278 himlLocal->cx * pimldp->i, 0, SRCCOPY);
281 * Draw the mask with or without a background
283 else if(fStyle & ILD_MASK)
285 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
286 0, bUseCustomBackground ? SRCCOPY : SRCAND);
290 * Blit the bitmap to the screen now.
292 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
293 hOffScreenDC, 0, 0, SRCCOPY);
296 SelectObject(hImageDC, hOldBitmapImage);
297 SelectObject(hMaskDC, hOldBitmapMask);
304 DeleteDC( hOffScreenDC );
305 DeleteObject( hOffScreenBmp );
310 /*************************************************************************
311 * IMAGELIST_InternalDrawBlend [Internal]
313 * Draws the Blend over the current image
316 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
317 * cx [I] the width of the image to display
318 * cy............[I] the height of the image to display
324 * This functions is used by ImageList_DrawIndirect, when it is
325 * required to add the blend to the current image.
329 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
332 HDC hBlendMaskDC,hMaskDC;
333 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
334 HBITMAP hBlendMaskBitmap, hOldBitmap;
335 COLORREF clrBlend, OldTextColor, OldBkColor;
336 HIMAGELIST himlLocal = pimldp->himl;
338 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
339 if (!(pimldp->rgbFg == CLR_DEFAULT))
341 clrBlend = pimldp->rgbFg;
343 /* Create the blend Mask
345 hBlendMaskDC = CreateCompatibleDC(0);
346 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
347 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
349 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
350 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
352 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
353 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
354 SelectObject(hBlendMaskDC, hOldBrush);
356 /* Modify the blend mask if an Image Mask exist
358 if(pimldp->himl->hbmMask != 0)
360 HBITMAP hOldMaskBitmap;
361 hMaskDC = CreateCompatibleDC(0);
362 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
367 himlLocal->cx * pimldp->i,0,
368 0x220326); /* NOTSRCAND */
376 SelectObject(hMaskDC, hOldMaskBitmap);
380 /* Apply blend to the current image given the BlendMask
382 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
383 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
384 hBlendColorBrush = CreateSolidBrush(clrBlend);
385 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
387 BitBlt (pimldp->hdcDst,
388 pimldp->x, pimldp->y, cx, cy,
391 0xB8074A); /* PSDPxax */
393 SelectObject(pimldp->hdcDst, hOldBrush);
394 SetTextColor(pimldp->hdcDst, OldTextColor);
395 SetBkColor(pimldp->hdcDst, OldBkColor);
396 SelectObject(hBlendMaskDC, hOldBitmap);
397 DeleteDC(hBlendMaskDC);
398 DeleteObject(hBlendMaskBitmap);
399 DeleteObject(hBlendColorBrush);
402 /*************************************************************************
403 * IMAGELIST_InternalDrawOverlay [Internal]
405 * Draws the overlay image
408 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
409 * cx [I] the width of the image to display
410 * cy............[I] the height of the image to display
416 * This functions is used by ImageList_DrawIndirect, when it is
417 * required to draw the overlay
422 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
428 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
429 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
431 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
432 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
434 hImageDC = CreateCompatibleDC(0);
435 if (pimldp->himl->hbmMask)
437 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
438 pimldp->himl->hbmMask);
440 BitBlt (pimldp->hdcDst,
441 pimldp->x, pimldp->y, cx, cy,
442 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
445 SelectObject(hImageDC, hOldBitmap);
447 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
448 pimldp->himl->hbmImage);
450 BitBlt (pimldp->hdcDst,
451 pimldp->x, pimldp->y, cx, cy,
453 pimldp->himl->cx * nOvlIdx, 0,
456 SelectObject(hImageDC, hOldBitmap);
466 /*************************************************************************
467 * ImageList_Add [COMCTL32.39]
469 * Add an image or images to an image list.
472 * himl [I] handle to image list
473 * hbmImage [I] handle to image bitmap
474 * hbmMask [I] handle to mask bitmap
477 * Success: Index of the first new image.
482 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
484 HDC hdcImage, hdcBitmap;
485 INT nFirstIndex, nImageCount;
488 HBITMAP hOldBitmapImage, hOldBitmap;
490 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
491 if (!himl || !hbmImage)
494 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
495 nImageCount = bmp.bmWidth / himl->cx;
497 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
499 nStartX = himl->cCurImage * himl->cx;
501 hdcImage = CreateCompatibleDC(0);
502 hdcBitmap = CreateCompatibleDC(0);
504 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
505 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
507 /* Copy result to the imagelist
509 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
510 hdcBitmap, 0, 0, SRCCOPY);
514 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
516 hdcMask = CreateCompatibleDC (0);
517 hdcTemp = CreateCompatibleDC(0);
518 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
519 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
522 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
527 SelectObject(hdcTemp, hOldBitmapTemp);
530 /* Remove the background from the image
533 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
536 0x220326); /* NOTSRCAND */
538 SelectObject(hdcMask, hOldBitmapMask);
542 SelectObject(hdcImage, hOldBitmapImage);
543 SelectObject(hdcBitmap, hOldBitmap);
547 nFirstIndex = himl->cCurImage;
548 himl->cCurImage += nImageCount;
554 /*************************************************************************
555 * ImageList_AddIcon [COMCTL32.40]
557 * Adds an icon to an image list.
560 * himl [I] handle to image list
561 * hIcon [I] handle to icon
564 * Success: index of the new image
569 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
571 return ImageList_ReplaceIcon (himl, -1, hIcon);
575 /*************************************************************************
576 * ImageList_AddMasked [COMCTL32.41]
578 * Adds an image or images to an image list and creates a mask from the
579 * specified bitmap using the mask color.
582 * himl [I] handle to image list.
583 * hBitmap [I] handle to bitmap
584 * clrMask [I] mask color.
587 * Success: Index of the first new image.
592 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
594 HDC hdcImage, hdcMask, hdcBitmap;
595 INT nIndex, nImageCount, nMaskXOffset=0;
597 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
598 HBITMAP hMaskBitmap=0;
601 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
605 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
608 nImageCount = bmp.bmWidth / himl->cx;
610 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
612 nIndex = himl->cCurImage;
613 himl->cCurImage += nImageCount;
615 hdcMask = CreateCompatibleDC (0);
616 hdcImage = CreateCompatibleDC(0);
617 hdcBitmap = CreateCompatibleDC(0);
620 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
621 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
624 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
625 nMaskXOffset = nIndex * himl->cx;
630 Create a temp Mask so we can remove the background of
631 the Image (Windows does this even if there is no mask)
633 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
634 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
637 /* create monochrome image to the mask bitmap */
638 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
639 GetPixel (hdcBitmap, 0, 0);
640 SetBkColor (hdcBitmap, bkColor);
642 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
646 SetBkColor(hdcBitmap, RGB(255,255,255));
647 /*Remove the background from the image
650 WINDOWS BUG ALERT!!!!!!
651 The statement below should not be done in common practice
652 but this is how ImageList_AddMasked works in Windows.
653 It overwrites the original bitmap passed, this was discovered
654 by using the same bitmap to iterate the different styles
655 on windows where it failed (BUT ImageList_Add is OK)
656 This is here in case some apps rely on this bug
659 0, 0, bmp.bmWidth, bmp.bmHeight,
662 0x220326); /* NOTSRCAND */
663 /* Copy result to the imagelist
666 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
672 SelectObject(hdcMask,hOldBitmapMask);
673 SelectObject(hdcImage, hOldBitmapImage);
674 SelectObject(hdcBitmap, hOldBitmap);
680 DeleteObject(hMaskBitmap);
687 /*************************************************************************
688 * ImageList_BeginDrag [COMCTL32.42]
690 * Creates a temporary image list that contains one image. It will be used
694 * himlTrack [I] handle to the source image list
695 * iTrack [I] index of the drag image in the source image list
696 * dxHotspot [I] X position of the hot spot of the drag image
697 * dyHotspot [I] Y position of the hot spot of the drag image
705 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
706 INT dxHotspot, INT dyHotspot)
710 FIXME("partially implemented!\n");
712 if (himlTrack == NULL)
715 if (himlInternalDrag)
716 ImageList_EndDrag ();
719 ImageList_Create (himlTrack->cx, himlTrack->cy,
720 himlTrack->flags, 1, 1);
721 if (himlInternalDrag == NULL) {
722 ERR("Error creating drag image list!\n");
726 nInternalDragHotspotX = dxHotspot;
727 nInternalDragHotspotY = dyHotspot;
729 hdcSrc = CreateCompatibleDC (0);
730 hdcDst = CreateCompatibleDC (0);
733 SelectObject (hdcSrc, himlTrack->hbmImage);
734 SelectObject (hdcDst, himlInternalDrag->hbmImage);
735 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
736 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
739 SelectObject (hdcSrc, himlTrack->hbmMask);
740 SelectObject (hdcDst, himlInternalDrag->hbmMask);
741 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
742 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
747 himlInternalDrag->cCurImage = 1;
753 /*************************************************************************
754 * ImageList_Copy [COMCTL32.43]
756 * Copies an image of the source image list to an image of the
757 * destination image list. Images can be copied or swapped.
760 * himlDst [I] handle to the destination image list
761 * iDst [I] destination image index.
762 * himlSrc [I] handle to the source image list
763 * iSrc [I] source image index
764 * uFlags [I] flags for the copy operation
771 * Copying from one image list to another is possible. The original
772 * implementation just copies or swaps within one image list.
773 * Could this feature become a bug??? ;-)
777 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
778 INT iSrc, INT uFlags)
782 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
784 if ((himlSrc == NULL) || (himlDst == NULL))
786 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
788 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
791 hdcSrc = CreateCompatibleDC (0);
792 if (himlDst == himlSrc)
795 hdcDst = CreateCompatibleDC (0);
797 if (uFlags & ILCF_SWAP) {
799 HBITMAP hbmTempImage, hbmTempMask;
801 /* create temporary bitmaps */
802 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
803 himlSrc->uBitsPixel, NULL);
804 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
807 /* copy (and stretch) destination to temporary bitmaps.(save) */
809 SelectObject (hdcSrc, himlDst->hbmImage);
810 SelectObject (hdcDst, hbmTempImage);
811 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
812 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
815 SelectObject (hdcSrc, himlDst->hbmMask);
816 SelectObject (hdcDst, hbmTempMask);
817 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
818 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
821 /* copy (and stretch) source to destination */
823 SelectObject (hdcSrc, himlSrc->hbmImage);
824 SelectObject (hdcDst, himlDst->hbmImage);
825 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
826 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
829 SelectObject (hdcSrc, himlSrc->hbmMask);
830 SelectObject (hdcDst, himlDst->hbmMask);
831 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
832 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
835 /* copy (without stretching) temporary bitmaps to source (restore) */
837 SelectObject (hdcSrc, hbmTempImage);
838 SelectObject (hdcDst, himlSrc->hbmImage);
839 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
840 hdcSrc, 0, 0, SRCCOPY);
842 SelectObject (hdcSrc, hbmTempMask);
843 SelectObject (hdcDst, himlSrc->hbmMask);
844 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
845 hdcSrc, 0, 0, SRCCOPY);
847 /* delete temporary bitmaps */
848 DeleteObject (hbmTempMask);
849 DeleteObject (hbmTempImage);
853 SelectObject (hdcSrc, himlSrc->hbmImage);
854 if (himlSrc == himlDst)
857 SelectObject (hdcDst, himlDst->hbmImage);
858 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
859 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
863 SelectObject (hdcSrc, himlSrc->hbmMask);
864 if (himlSrc == himlDst)
867 SelectObject (hdcDst, himlDst->hbmMask);
868 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
869 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
874 if (himlSrc != himlDst)
881 /*************************************************************************
882 * ImageList_Create [COMCTL32.44] Creates a new image list.
885 * cx [I] image height
887 * flags [I] creation flags
888 * cInitial [I] initial number of images in the image list
889 * cGrow [I] number of images by which image list grows
892 * Success: Handle to the created image list
897 ImageList_Create (INT cx, INT cy, UINT flags,
898 INT cInitial, INT cGrow)
904 static WORD aBitBlend25[] =
905 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
907 static WORD aBitBlend50[] =
908 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
910 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
912 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
919 himl->cMaxImage = cInitial + cGrow;
920 himl->cInitial = cInitial;
923 himl->clrFg = CLR_DEFAULT;
924 himl->clrBk = CLR_NONE;
926 /* initialize overlay mask indices */
927 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
928 himl->nOvlIdx[nCount] = -1;
930 hdc = CreateCompatibleDC (0);
931 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
934 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
936 if (himl->cMaxImage > 0) {
938 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
939 1, himl->uBitsPixel, NULL);
940 if (himl->hbmImage == 0) {
941 ERR("Error creating image bitmap!\n");
948 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
949 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
951 if (himl->hbmMask == 0) {
952 ERR("Error creating mask bitmap!\n");
954 DeleteObject (himl->hbmImage);
961 /* create blending brushes */
962 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
963 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
964 DeleteObject (hbmTemp);
966 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
967 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
968 DeleteObject (hbmTemp);
970 TRACE("created imagelist %p\n", himl);
975 /*************************************************************************
976 * ImageList_Destroy [COMCTL32.45]
978 * Destroys an image list.
981 * himl [I] handle to image list
989 ImageList_Destroy (HIMAGELIST himl)
994 /* delete image bitmaps */
996 DeleteObject (himl->hbmImage);
998 DeleteObject (himl->hbmMask);
1000 /* delete blending brushes */
1001 if (himl->hbrBlend25)
1002 DeleteObject (himl->hbrBlend25);
1003 if (himl->hbrBlend50)
1004 DeleteObject (himl->hbrBlend50);
1006 COMCTL32_Free (himl);
1012 /*************************************************************************
1013 * ImageList_DragEnter [COMCTL32.46]
1015 * Locks window update and displays the drag image at the given position.
1018 * hwndLock [I] handle of the window that owns the drag image.
1019 * x [I] X position of the drag image.
1020 * y [I] Y position of the drag image.
1027 * The position of the drag image is relative to the window, not
1032 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1034 if (himlInternalDrag == NULL)
1038 hwndInternalDrag = hwndLock;
1040 hwndInternalDrag = GetDesktopWindow ();
1045 hdcBackBuffer = CreateCompatibleDC (0);
1046 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1047 himlInternalDrag->cx, himlInternalDrag->cy);
1049 ImageList_DragShowNolock (TRUE);
1055 /*************************************************************************
1056 * ImageList_DragLeave [COMCTL32.47]
1058 * Unlocks window update and hides the drag image.
1061 * hwndLock [I] handle of the window that owns the drag image.
1069 ImageList_DragLeave (HWND hwndLock)
1072 hwndInternalDrag = hwndLock;
1074 hwndInternalDrag = GetDesktopWindow ();
1076 ImageList_DragShowNolock (FALSE);
1078 DeleteDC (hdcBackBuffer);
1079 DeleteObject (hbmBackBuffer);
1085 /*************************************************************************
1086 * ImageList_DragMove [COMCTL32.48]
1088 * Moves the drag image.
1091 * x [I] X position of the drag image.
1092 * y [I] Y position of the drag image.
1099 * The position of the drag image is relative to the window, not
1104 ImageList_DragMove (INT x, INT y)
1106 ImageList_DragShowNolock (FALSE);
1111 ImageList_DragShowNolock (TRUE);
1117 /*************************************************************************
1118 * ImageList_DragShowNolock [COMCTL32.49]
1120 * Shows or hides the drag image.
1123 * bShow [I] TRUE shows the drag image, FALSE hides it.
1134 ImageList_DragShowNolock (BOOL bShow)
1138 FIXME("semi-stub!\n");
1139 TRACE("bShow=0x%X!\n", bShow);
1141 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1142 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1145 /* show drag image */
1147 /* save background */
1149 /* draw drag image */
1153 /* hide drag image */
1155 /* restore background */
1159 ReleaseDC (hwndInternalDrag, hdcDrag);
1165 /*************************************************************************
1166 * ImageList_Draw [COMCTL32.50] Draws an image.
1169 * himl [I] handle to image list
1171 * hdc [I] handle to device context
1174 * fStyle [I] drawing flags
1181 * Calls ImageList_DrawIndirect.
1184 * ImageList_DrawIndirect.
1188 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1189 INT x, INT y, UINT fStyle)
1191 IMAGELISTDRAWPARAMS imldp;
1193 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1203 imldp.rgbBk = CLR_DEFAULT;
1204 imldp.rgbFg = CLR_DEFAULT;
1205 imldp.fStyle = fStyle;
1208 return ImageList_DrawIndirect (&imldp);
1212 /*************************************************************************
1213 * ImageList_DrawEx [COMCTL32.51]
1215 * Draws an image and allows to use extended drawing features.
1218 * himl [I] handle to image list
1220 * hdc [I] handle to device context
1223 * xOffs [I] X offset
1224 * yOffs [I] Y offset
1225 * rgbBk [I] background color
1226 * rgbFg [I] foreground color
1227 * fStyle [I] drawing flags
1234 * Calls ImageList_DrawIndirect.
1237 * ImageList_DrawIndirect.
1241 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1242 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1245 IMAGELISTDRAWPARAMS imldp;
1247 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1257 imldp.rgbBk = rgbBk;
1258 imldp.rgbFg = rgbFg;
1259 imldp.fStyle = fStyle;
1262 return ImageList_DrawIndirect (&imldp);
1266 /*************************************************************************
1267 * ImageList_DrawIndirect [COMCTL32.52]
1269 * Draws an image using ...
1272 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1280 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1284 Do some Error Checking
1288 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1290 if (pimldp->himl == NULL)
1292 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1293 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1297 Get the Height and Width to display
1299 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1300 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1304 if(pimldp->himl->hbmMask != 0)
1306 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1310 IMAGELIST_InternalDraw(pimldp, cx, cy);
1313 Apply the blend if needed to the Image
1315 if((pimldp->fStyle & ILD_BLEND50)
1316 || (pimldp->fStyle & ILD_BLEND25))
1318 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1321 Apply the Overlay if needed
1323 if (pimldp->fStyle & ILD_OVERLAYMASK)
1325 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1332 /*************************************************************************
1333 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1336 * himlSrc [I] source image list handle
1339 * Success: Handle of duplicated image list.
1344 ImageList_Duplicate (HIMAGELIST himlSrc)
1349 if (himlSrc == NULL) {
1350 ERR("Invalid image list handle!\n");
1354 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1355 himlSrc->cInitial, himlSrc->cGrow);
1359 hdcSrc = CreateCompatibleDC (0);
1360 hdcDst = CreateCompatibleDC (0);
1361 SelectObject (hdcSrc, himlSrc->hbmImage);
1362 SelectObject (hdcDst, himlDst->hbmImage);
1363 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1364 hdcSrc, 0, 0, SRCCOPY);
1366 if (himlDst->hbmMask)
1368 SelectObject (hdcSrc, himlSrc->hbmMask);
1369 SelectObject (hdcDst, himlDst->hbmMask);
1370 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1371 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1377 himlDst->cCurImage = himlSrc->cCurImage;
1378 himlDst->cMaxImage = himlSrc->cMaxImage;
1384 /*************************************************************************
1385 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1387 * Finishes a drag operation.
1401 ImageList_EndDrag (void)
1403 FIXME("semi-stub!\n");
1405 if (himlInternalDrag)
1408 ImageList_Destroy (himlInternalDrag);
1409 himlInternalDrag = NULL;
1411 nInternalDragHotspotX = 0;
1412 nInternalDragHotspotY = 0;
1420 /*************************************************************************
1421 * ImageList_GetBkColor [COMCTL32.55]
1423 * Returns the background color of an image list.
1426 * himl [I] Image list handle.
1429 * Success: background color
1434 ImageList_GetBkColor (HIMAGELIST himl)
1443 /*************************************************************************
1444 * ImageList_GetDragImage [COMCTL32.56]
1446 * Returns the handle to the internal drag image list.
1449 * ppt [O] Pointer to the drag position. Can be NULL.
1450 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1453 * Success: Handle of the drag image list.
1461 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1463 FIXME("semi-stub!\n");
1465 if (himlInternalDrag)
1466 return (himlInternalDrag);
1472 /*************************************************************************
1473 * ImageList_GetIcon [COMCTL32.57]
1475 * Creates an icon from a masked image of an image list.
1478 * himl [I] handle to image list
1480 * flags [I] drawing style flags
1483 * Success: icon handle
1488 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1492 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1495 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1496 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1500 hdcSrc = CreateCompatibleDC(0);
1501 hdcDst = CreateCompatibleDC(0);
1504 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1507 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1508 if (himl->hbmMask) {
1509 SelectObject (hdcSrc, himl->hbmMask);
1510 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1511 hdcSrc, i * himl->cx, 0, SRCCOPY);
1514 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1517 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1518 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1519 SelectObject (hdcDst, ii.hbmColor);
1520 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1521 hdcSrc, i * himl->cx, 0, SRCCOPY);
1524 * CreateIconIndirect requires us to deselect the bitmaps from
1525 * the DCs before calling
1527 SelectObject(hdcSrc, hOldSrcBitmap);
1528 SelectObject(hdcDst, hOldDstBitmap);
1530 hIcon = CreateIconIndirect (&ii);
1534 DeleteObject (ii.hbmMask);
1535 DeleteObject (ii.hbmColor);
1541 /*************************************************************************
1542 * ImageList_GetIconSize [COMCTL32.58]
1544 * Retrieves the size of an image in an image list.
1547 * himl [I] handle to image list
1548 * cx [O] pointer to the image width.
1549 * cy [O] pointer to the image height.
1556 * All images in an image list have the same size.
1560 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1564 if ((himl->cx <= 0) || (himl->cy <= 0))
1576 /*************************************************************************
1577 * ImageList_GetImageCount [COMCTL32.59]
1579 * Returns the number of images in an image list.
1582 * himl [I] handle to image list
1585 * Success: Number of images.
1590 ImageList_GetImageCount (HIMAGELIST himl)
1595 return himl->cCurImage;
1599 /*************************************************************************
1600 * ImageList_GetImageInfo [COMCTL32.60]
1602 * Returns information about an image in an image list.
1605 * himl [I] handle to image list
1607 * pImageInfo [O] pointer to the image information
1615 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1617 if ((himl == NULL) || (pImageInfo == NULL))
1619 if ((i < 0) || (i >= himl->cCurImage))
1622 pImageInfo->hbmImage = himl->hbmImage;
1623 pImageInfo->hbmMask = himl->hbmMask;
1625 pImageInfo->rcImage.top = 0;
1626 pImageInfo->rcImage.bottom = himl->cy;
1627 pImageInfo->rcImage.left = i * himl->cx;
1628 pImageInfo->rcImage.right = (i+1) * himl->cx;
1634 /*************************************************************************
1635 * ImageList_GetImageRect [COMCTL32.61]
1637 * Retrieves the rectangle of the specified image in an image list.
1640 * himl [I] handle to image list
1642 * lpRect [O] pointer to the image rectangle
1649 * This is an UNDOCUMENTED function!!!
1653 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1655 if ((himl == NULL) || (lpRect == NULL))
1657 if ((i < 0) || (i >= himl->cCurImage))
1660 lpRect->left = i * himl->cx;
1662 lpRect->right = lpRect->left + himl->cx;
1663 lpRect->bottom = himl->cy;
1669 /*************************************************************************
1670 * ImageList_LoadImageA [COMCTL32.63][COMCTL32.62]
1672 * Creates an image list from a bitmap, icon or cursor.
1675 * hi [I] instance handle
1676 * lpbmp [I] name or id of the image
1677 * cx [I] width of each image
1678 * cGrow [I] number of images to expand
1679 * clrMask [I] mask color
1680 * uType [I] type of image to load
1681 * uFlags [I] loading flags
1684 * Success: handle to the loaded image list
1692 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1693 COLORREF clrMask, UINT uType, UINT uFlags)
1695 HIMAGELIST himl = NULL;
1699 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1701 ERR("Error loading image!\n");
1705 if (uType == IMAGE_BITMAP) {
1707 GetObjectA (handle, sizeof(BITMAP), &bmp);
1709 /* To match windows behavior, if cx is set to zero and
1710 the flag DI_DEFAULTSIZE is specified, cx becomes the
1711 system metric value for icons. If the flag is not specified
1712 the function sets the size to the height of the bitmap */
1715 if (uFlags & DI_DEFAULTSIZE)
1716 cx = GetSystemMetrics (SM_CXICON);
1721 nImageCount = bmp.bmWidth / cx;
1723 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1724 nImageCount, cGrow);
1725 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1727 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1731 GetIconInfo (handle, &ii);
1732 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1733 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1734 ILC_MASK | ILC_COLOR, 1, cGrow);
1735 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1736 DeleteObject (ii.hbmColor);
1737 DeleteObject (ii.hbmMask);
1740 DeleteObject (handle);
1746 /*************************************************************************
1747 * ImageList_LoadImageW [COMCTL32.64]
1749 * Creates an image list from a bitmap, icon or cursor.
1752 * hi [I] instance handle
1753 * lpbmp [I] name or id of the image
1754 * cx [I] width of each image
1755 * cGrow [I] number of images to expand
1756 * clrMask [I] mask color
1757 * uType [I] type of image to load
1758 * uFlags [I] loading flags
1761 * Success: handle to the loaded image list
1769 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1770 COLORREF clrMask, UINT uType, UINT uFlags)
1772 HIMAGELIST himl = NULL;
1776 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1778 ERR("Error loading image!\n");
1782 if (uType == IMAGE_BITMAP) {
1784 GetObjectA (handle, sizeof(BITMAP), &bmp);
1785 nImageCount = bmp.bmWidth / cx;
1787 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1788 nImageCount, cGrow);
1789 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1791 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1795 GetIconInfo (handle, &ii);
1796 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1797 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1798 ILC_MASK | ILC_COLOR, 1, cGrow);
1799 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1800 DeleteObject (ii.hbmColor);
1801 DeleteObject (ii.hbmMask);
1804 DeleteObject (handle);
1810 /*************************************************************************
1811 * ImageList_Merge [COMCTL32.65]
1813 * Creates a new image list that contains a merged image from the specified
1814 * images of both source image lists.
1817 * himl1 [I] handle to first image list
1818 * i1 [I] first image index
1819 * himl2 [I] handle to second image list
1820 * i2 [I] second image index
1821 * dx [I] X offset of the second image relative to the first.
1822 * dy [I] Y offset of the second image relative to the first.
1825 * Success: handle of the merged image list.
1830 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1833 HIMAGELIST himlDst = NULL;
1834 HDC hdcSrcImage, hdcDstImage;
1836 INT xOff1, yOff1, xOff2, yOff2;
1839 if ((himl1 == NULL) || (himl2 == NULL))
1843 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1844 ERR("Index 1 out of range! %d\n", i1);
1848 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1849 ERR("Index 2 out of range! %d\n", i2);
1854 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1859 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1864 cxDst = _MAX (himl1->cx, himl2->cx);
1870 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1875 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1880 cyDst = _MAX (himl1->cy, himl2->cy);
1885 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1888 hdcSrcImage = CreateCompatibleDC (0);
1889 hdcDstImage = CreateCompatibleDC (0);
1890 nX1 = i1 * himl1->cx;
1891 nX2 = i2 * himl2->cx;
1894 SelectObject (hdcSrcImage, himl1->hbmImage);
1895 SelectObject (hdcDstImage, himlDst->hbmImage);
1896 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1897 hdcSrcImage, 0, 0, BLACKNESS);
1898 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1899 hdcSrcImage, nX1, 0, SRCCOPY);
1901 SelectObject (hdcSrcImage, himl2->hbmMask);
1902 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1903 hdcSrcImage, nX2, 0, SRCAND);
1905 SelectObject (hdcSrcImage, himl2->hbmImage);
1906 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1907 hdcSrcImage, nX2, 0, SRCPAINT);
1910 SelectObject (hdcSrcImage, himl1->hbmMask);
1911 SelectObject (hdcDstImage, himlDst->hbmMask);
1912 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1913 hdcSrcImage, 0, 0, WHITENESS);
1914 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1915 hdcSrcImage, nX1, 0, SRCCOPY);
1917 SelectObject (hdcSrcImage, himl2->hbmMask);
1918 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1919 hdcSrcImage, nX2, 0, SRCAND);
1921 DeleteDC (hdcSrcImage);
1922 DeleteDC (hdcDstImage);
1929 /* helper for _read_bitmap currently unused */
1931 static int may_use_dibsection(HDC hdc) {
1932 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1937 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1941 /* helper for ImageList_Read, see comments below */
1942 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1944 BITMAPFILEHEADER bmfh;
1945 BITMAPINFOHEADER bmih;
1946 int bitsperpixel,palspace,longsperline,width,height;
1947 LPBITMAPINFOHEADER bmihc = NULL;
1949 HBITMAP hbitmap = 0;
1950 LPBYTE bits = NULL,nbits = NULL;
1951 int nbytesperline,bytesperline;
1953 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1954 (bmfh.bfType != (('M'<<8)|'B')) ||
1955 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1956 (bmih.biSize != sizeof(bmih))
1960 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1961 if (bitsperpixel<=8)
1962 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1965 width = bmih.biWidth;
1966 height = bmih.biHeight;
1967 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1968 memcpy(bmihc,&bmih,sizeof(bmih));
1969 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1970 bmihc->biSizeImage = (longsperline*height)<<2;
1972 /* read the palette right after the end of the bitmapinfoheader */
1974 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1978 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1979 if ((bitsperpixel>1) &&
1980 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1982 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1985 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1991 int i,nwidth,nheight;
1993 nwidth = width*(height/cy);
1996 if (bitsperpixel==1)
1997 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1999 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2001 /* Might be a bit excessive memory use here */
2002 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2003 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2004 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2007 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2008 /* Do not forget that windows bitmaps are bottom->top */
2009 bytesperline = longsperline*4;
2010 nbytesperline = (height/cy)*bytesperline;
2011 for (i=0;i<height;i++) {
2013 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2014 bits+bytesperline*(height-1-i),
2018 bmihc->biWidth = nwidth;
2019 bmihc->biHeight = nheight;
2020 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2022 LocalFree((HLOCAL)nbits);
2023 LocalFree((HLOCAL)bits);
2027 if (xdc) ReleaseDC(0,xdc);
2028 if (bmihc) LocalFree((HLOCAL)bmihc);
2031 DeleteObject(hbitmap);
2038 /*************************************************************************
2039 * ImageList_Read [COMCTL32.66]
2041 * Reads an image list from a stream.
2044 * pstm [I] pointer to a stream
2047 * Success: handle to image list
2050 * The format is like this:
2051 * ILHEAD ilheadstruct;
2053 * for the color image part:
2054 * BITMAPFILEHEADER bmfh;
2055 * BITMAPINFOHEADER bmih;
2056 * only if it has a palette:
2057 * RGBQUAD rgbs[nr_of_paletted_colors];
2059 * BYTE colorbits[imagesize];
2061 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2062 * BITMAPFILEHEADER bmfh_mask;
2063 * BITMAPINFOHEADER bmih_mask;
2064 * only if it has a palette (it usually does not):
2065 * RGBQUAD rgbs[nr_of_paletted_colors];
2067 * BYTE maskbits[imagesize];
2069 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2070 * _read_bitmap needs to convert them.
2072 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2076 HBITMAP hbmColor=0,hbmMask=0;
2079 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2081 if (ilHead.usMagic != (('L' << 8) | 'I'))
2083 if (ilHead.usVersion != 0x101) /* probably version? */
2087 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2088 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2089 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2090 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2091 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2092 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2093 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2094 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2095 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2096 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2099 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2102 if (ilHead.flags & ILC_MASK) {
2103 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2105 DeleteObject(hbmColor);
2110 himl = ImageList_Create (
2118 DeleteObject(hbmColor);
2119 DeleteObject(hbmMask);
2122 himl->hbmImage = hbmColor;
2123 himl->hbmMask = hbmMask;
2124 himl->cCurImage = ilHead.cCurImage;
2125 himl->cMaxImage = ilHead.cMaxImage;
2127 ImageList_SetBkColor(himl,ilHead.bkcolor);
2129 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2134 /*************************************************************************
2135 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2138 * himl [I] image list handle
2147 ImageList_Remove (HIMAGELIST himl, INT i)
2149 HBITMAP hbmNewImage, hbmNewMask;
2154 ERR("Invalid image list handle!\n");
2158 if ((i < -1) || (i >= himl->cCurImage)) {
2159 ERR("index out of range! %d\n", i);
2163 if (himl->cCurImage == 0) {
2164 ERR("image list is already empty!\n");
2170 TRACE("remove all!\n");
2172 himl->cMaxImage = himl->cInitial + himl->cGrow;
2173 himl->cCurImage = 0;
2174 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2175 himl->nOvlIdx[nCount] = -1;
2177 DeleteObject (himl->hbmImage);
2179 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2180 1, himl->uBitsPixel, NULL);
2182 if (himl->hbmMask) {
2183 DeleteObject (himl->hbmMask);
2185 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2190 /* delete one image */
2191 TRACE("Remove single image! %d\n", i);
2193 /* create new bitmap(s) */
2194 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2196 TRACE(" - Number of images: %d / %d (Old/New)\n",
2197 himl->cCurImage, himl->cCurImage - 1);
2198 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2199 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2202 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2205 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2207 hbmNewMask = 0; /* Just to keep compiler happy! */
2209 hdcSrc = CreateCompatibleDC (0);
2210 hdcDst = CreateCompatibleDC (0);
2212 /* copy all images and masks prior to the "removed" image */
2214 TRACE("Pre image copy: Copy %d images\n", i);
2216 SelectObject (hdcSrc, himl->hbmImage);
2217 SelectObject (hdcDst, hbmNewImage);
2218 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2219 hdcSrc, 0, 0, SRCCOPY);
2221 if (himl->hbmMask) {
2222 SelectObject (hdcSrc, himl->hbmMask);
2223 SelectObject (hdcDst, hbmNewMask);
2224 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2225 hdcSrc, 0, 0, SRCCOPY);
2229 /* copy all images and masks behind the removed image */
2230 if (i < himl->cCurImage - 1) {
2231 TRACE("Post image copy!\n");
2232 SelectObject (hdcSrc, himl->hbmImage);
2233 SelectObject (hdcDst, hbmNewImage);
2234 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2235 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2237 if (himl->hbmMask) {
2238 SelectObject (hdcSrc, himl->hbmMask);
2239 SelectObject (hdcDst, hbmNewMask);
2240 BitBlt (hdcDst, i * himl->cx, 0,
2241 (himl->cCurImage - i - 1) * himl->cx,
2242 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2249 /* delete old images and insert new ones */
2250 DeleteObject (himl->hbmImage);
2251 himl->hbmImage = hbmNewImage;
2252 if (himl->hbmMask) {
2253 DeleteObject (himl->hbmMask);
2254 himl->hbmMask = hbmNewMask;
2258 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2265 /*************************************************************************
2266 * ImageList_Replace [COMCTL32.68]
2268 * Replaces an image in an image list with a new image.
2271 * himl [I] handle to image list
2273 * hbmImage [I] handle to image bitmap
2274 * hbmMask [I] handle to mask bitmap. Can be NULL.
2282 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2285 HDC hdcImageList, hdcImage;
2289 ERR("Invalid image list handle!\n");
2293 if ((i >= himl->cMaxImage) || (i < 0)) {
2294 ERR("Invalid image index!\n");
2298 hdcImageList = CreateCompatibleDC (0);
2299 hdcImage = CreateCompatibleDC (0);
2300 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2303 SelectObject (hdcImageList, himl->hbmImage);
2304 SelectObject (hdcImage, hbmImage);
2306 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2307 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2312 SelectObject (hdcImageList, himl->hbmMask);
2313 SelectObject (hdcImage, hbmMask);
2315 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2316 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2319 /* Remove the background from the image
2321 SelectObject (hdcImageList, himl->hbmImage);
2322 StretchBlt (hdcImageList,
2323 i*himl->cx, 0, himl->cx, himl->cy,
2325 0, 0, bmp.bmWidth, bmp.bmHeight,
2326 0x220326); /* NOTSRCAND */
2329 DeleteDC (hdcImage);
2330 DeleteDC (hdcImageList);
2336 /*************************************************************************
2337 * ImageList_ReplaceIcon [COMCTL32.69]
2339 * Replaces an image in an image list using an icon.
2342 * himl [I] handle to image list
2344 * hIcon [I] handle to icon
2347 * Success: index of the replaced image
2352 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2354 HDC hdcImageList, hdcImage;
2357 HBITMAP hbmOldSrc, hbmOldDst;
2361 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2365 if ((i >= himl->cMaxImage) || (i < -1))
2368 hBestFitIcon = CopyImage(
2371 LR_COPYFROMRESOURCE);
2373 GetIconInfo (hBestFitIcon, &ii);
2374 if (ii.hbmMask == 0)
2376 if (ii.hbmColor == 0)
2378 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2381 if (himl->cCurImage + 1 >= himl->cMaxImage)
2382 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2384 nIndex = himl->cCurImage;
2390 hdcImageList = CreateCompatibleDC (0);
2391 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2392 if (hdcImageList == 0)
2393 ERR("invalid hdcImageList!\n");
2395 hdcImage = CreateCompatibleDC (0);
2396 TRACE("hdcImage=0x%x!\n", hdcImage);
2398 ERR("invalid hdcImage!\n");
2400 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2401 SetTextColor( hdcImageList, RGB(0,0,0));
2402 SetBkColor( hdcImageList, RGB(255,255,255));
2403 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2404 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2405 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2407 if (himl->hbmMask) {
2408 SelectObject (hdcImageList, himl->hbmMask);
2409 SelectObject (hdcImage, ii.hbmMask);
2410 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2411 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2414 SelectObject (hdcImage, hbmOldSrc);
2415 SelectObject (hdcImageList, hbmOldDst);
2418 DestroyIcon(hBestFitIcon);
2420 DeleteDC (hdcImageList);
2422 DeleteDC (hdcImage);
2424 DeleteObject (ii.hbmColor);
2426 DeleteObject (ii.hbmMask);
2432 /*************************************************************************
2433 * ImageList_SetBkColor [COMCTL32.70]
2435 * Sets the background color of an image list.
2438 * himl [I] handle to image list
2439 * clrBk [I] background color
2442 * Success: previous background color
2447 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2454 clrOldBk = himl->clrBk;
2455 himl->clrBk = clrBk;
2460 /*************************************************************************
2461 * ImageList_SetDragCursorImage [COMCTL32.75]
2463 * Combines the specified image with the current drag image
2466 * himlDrag [I] handle to drag image list
2467 * iDrag [I] drag image index
2468 * dxHotspot [I] X position of the hot spot
2469 * dyHotspot [I] Y position of the hot spot
2480 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2481 INT dxHotspot, INT dyHotspot)
2483 HIMAGELIST himlTemp;
2485 FIXME("semi-stub!\n");
2487 if (himlInternalDrag == NULL)
2490 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2491 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2493 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2494 dxHotspot, dyHotspot);
2496 ImageList_Destroy (himlInternalDrag);
2497 himlInternalDrag = himlTemp;
2499 nInternalDragHotspotX = dxHotspot;
2500 nInternalDragHotspotY = dyHotspot;
2506 /*************************************************************************
2507 * ImageList_SetFilter [COMCTL32.76]
2509 * Sets a filter (or does something completely different)!!???
2512 * himl [I] handle to image list
2518 * Failure: FALSE ???
2521 * This is an UNDOCUMENTED function!!!!
2526 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2528 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2535 /*************************************************************************
2536 * ImageList_SetIconSize [COMCTL32.77]
2538 * Sets the image size of the bitmap and deletes all images.
2541 * himl [I] handle to image list
2542 * cx [I] image width
2543 * cy [I] image height
2551 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2558 /* remove all images */
2559 himl->cMaxImage = himl->cInitial + himl->cGrow;
2560 himl->cCurImage = 0;
2564 /* initialize overlay mask indices */
2565 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2566 himl->nOvlIdx[nCount] = -1;
2568 DeleteObject (himl->hbmImage);
2570 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2571 1, himl->uBitsPixel, NULL);
2573 if (himl->hbmMask) {
2574 DeleteObject (himl->hbmMask);
2576 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2584 /*************************************************************************
2585 * ImageList_SetImageCount [COMCTL32.78]
2587 * Resizes an image list to the specified number of images.
2590 * himl [I] handle to image list
2591 * iImageCount [I] number of images in the image list
2599 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2601 HDC hdcImageList, hdcBitmap;
2602 HBITMAP hbmNewBitmap;
2603 INT nNewCount, nCopyCount;
2607 if (himl->cCurImage >= iImageCount)
2609 if (himl->cMaxImage > iImageCount)
2612 nNewCount = iImageCount + himl->cGrow;
2613 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2615 hdcImageList = CreateCompatibleDC (0);
2616 hdcBitmap = CreateCompatibleDC (0);
2618 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2619 1, himl->uBitsPixel, NULL);
2620 if (hbmNewBitmap != 0)
2622 SelectObject (hdcImageList, himl->hbmImage);
2623 SelectObject (hdcBitmap, hbmNewBitmap);
2626 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2627 hdcImageList, 0, 0, SRCCOPY);
2629 /* delete 'empty' image space */
2630 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2631 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2632 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2633 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2635 DeleteObject (himl->hbmImage);
2636 himl->hbmImage = hbmNewBitmap;
2639 ERR("Could not create new image bitmap !\n");
2643 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2645 if (hbmNewBitmap != 0)
2647 SelectObject (hdcImageList, himl->hbmMask);
2648 SelectObject (hdcBitmap, hbmNewBitmap);
2651 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2652 hdcImageList, 0, 0, SRCCOPY);
2654 /* delete 'empty' image space */
2655 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2656 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2657 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2658 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2660 DeleteObject (himl->hbmMask);
2661 himl->hbmMask = hbmNewBitmap;
2664 ERR("Could not create new mask bitmap!\n");
2667 DeleteDC (hdcImageList);
2668 DeleteDC (hdcBitmap);
2670 /* Update max image count and current image count */
2671 himl->cMaxImage = nNewCount;
2672 if (himl->cCurImage > nCopyCount)
2673 himl->cCurImage = nCopyCount;
2679 /*************************************************************************
2680 * ImageList_SetOverlayImage [COMCTL32.79]
2682 * Assigns an overlay mask index to an existing image in an image list.
2685 * himl [I] handle to image list
2686 * iImage [I] image index
2687 * iOverlay [I] overlay mask index
2695 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2699 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2701 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2703 himl->nOvlIdx[iOverlay - 1] = iImage;
2708 /*************************************************************************
2709 * ImageList_Write [COMCTL32.80]
2711 * Writes an image list to a stream.
2714 * himl [I] handle to image list
2715 * pstm [O] Pointer to a stream.
2722 * This function can not be implemented yet, because
2723 * IStream32::Write is not implemented.
2730 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2735 FIXME("empty stub!\n");