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.40]
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.41]
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.42]
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.43]
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.44]
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.45] 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.46]
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.47]
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.48]
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.49]
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.50]
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.51] 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.52]
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.53]
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.54] 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.55] 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.56]
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.57]
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.59]
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.60]
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.61]
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.62]
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.63]
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_LoadImage [COMCTL32.64]
1671 * ImageList_LoadImageA [COMCTL32.65]
1673 * Creates an image list from a bitmap, icon or cursor.
1676 * hi [I] instance handle
1677 * lpbmp [I] name or id of the image
1678 * cx [I] width of each image
1679 * cGrow [I] number of images to expand
1680 * clrMask [I] mask color
1681 * uType [I] type of image to load
1682 * uFlags [I] loading flags
1685 * Success: handle to the loaded image list
1693 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1694 COLORREF clrMask, UINT uType, UINT uFlags)
1696 HIMAGELIST himl = NULL;
1700 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1702 ERR("Error loading image!\n");
1706 if (uType == IMAGE_BITMAP) {
1708 GetObjectA (handle, sizeof(BITMAP), &bmp);
1710 /* To match windows behavior, if cx is set to zero and
1711 the flag DI_DEFAULTSIZE is specified, cx becomes the
1712 system metric value for icons. If the flag is not specified
1713 the function sets the size to the height of the bitmap */
1716 if (uFlags & DI_DEFAULTSIZE)
1717 cx = GetSystemMetrics (SM_CXICON);
1722 nImageCount = bmp.bmWidth / cx;
1724 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1725 nImageCount, cGrow);
1726 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1728 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1732 GetIconInfo (handle, &ii);
1733 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1734 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1735 ILC_MASK | ILC_COLOR, 1, cGrow);
1736 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1737 DeleteObject (ii.hbmColor);
1738 DeleteObject (ii.hbmMask);
1741 DeleteObject (handle);
1747 /*************************************************************************
1748 * ImageList_LoadImageW [COMCTL32.66]
1750 * Creates an image list from a bitmap, icon or cursor.
1753 * hi [I] instance handle
1754 * lpbmp [I] name or id of the image
1755 * cx [I] width of each image
1756 * cGrow [I] number of images to expand
1757 * clrMask [I] mask color
1758 * uType [I] type of image to load
1759 * uFlags [I] loading flags
1762 * Success: handle to the loaded image list
1770 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1771 COLORREF clrMask, UINT uType, UINT uFlags)
1773 HIMAGELIST himl = NULL;
1777 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1779 ERR("Error loading image!\n");
1783 if (uType == IMAGE_BITMAP) {
1785 GetObjectA (handle, sizeof(BITMAP), &bmp);
1786 nImageCount = bmp.bmWidth / cx;
1788 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1789 nImageCount, cGrow);
1790 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1792 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1796 GetIconInfo (handle, &ii);
1797 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1798 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1799 ILC_MASK | ILC_COLOR, 1, cGrow);
1800 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1801 DeleteObject (ii.hbmColor);
1802 DeleteObject (ii.hbmMask);
1805 DeleteObject (handle);
1811 /*************************************************************************
1812 * ImageList_Merge [COMCTL32.67]
1814 * Creates a new image list that contains a merged image from the specified
1815 * images of both source image lists.
1818 * himl1 [I] handle to first image list
1819 * i1 [I] first image index
1820 * himl2 [I] handle to second image list
1821 * i2 [I] second image index
1822 * dx [I] X offset of the second image relative to the first.
1823 * dy [I] Y offset of the second image relative to the first.
1826 * Success: handle of the merged image list.
1831 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1834 HIMAGELIST himlDst = NULL;
1835 HDC hdcSrcImage, hdcDstImage;
1837 INT xOff1, yOff1, xOff2, yOff2;
1840 if ((himl1 == NULL) || (himl2 == NULL))
1844 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1845 ERR("Index 1 out of range! %d\n", i1);
1849 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1850 ERR("Index 2 out of range! %d\n", i2);
1855 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1860 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1865 cxDst = _MAX (himl1->cx, himl2->cx);
1871 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1876 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1881 cyDst = _MAX (himl1->cy, himl2->cy);
1886 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1889 hdcSrcImage = CreateCompatibleDC (0);
1890 hdcDstImage = CreateCompatibleDC (0);
1891 nX1 = i1 * himl1->cx;
1892 nX2 = i2 * himl2->cx;
1895 SelectObject (hdcSrcImage, himl1->hbmImage);
1896 SelectObject (hdcDstImage, himlDst->hbmImage);
1897 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1898 hdcSrcImage, 0, 0, BLACKNESS);
1899 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1900 hdcSrcImage, nX1, 0, SRCCOPY);
1902 SelectObject (hdcSrcImage, himl2->hbmMask);
1903 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1904 hdcSrcImage, nX2, 0, SRCAND);
1906 SelectObject (hdcSrcImage, himl2->hbmImage);
1907 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1908 hdcSrcImage, nX2, 0, SRCPAINT);
1911 SelectObject (hdcSrcImage, himl1->hbmMask);
1912 SelectObject (hdcDstImage, himlDst->hbmMask);
1913 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1914 hdcSrcImage, 0, 0, WHITENESS);
1915 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1916 hdcSrcImage, nX1, 0, SRCCOPY);
1918 SelectObject (hdcSrcImage, himl2->hbmMask);
1919 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1920 hdcSrcImage, nX2, 0, SRCAND);
1922 DeleteDC (hdcSrcImage);
1923 DeleteDC (hdcDstImage);
1930 /* helper for _read_bitmap currently unused */
1932 static int may_use_dibsection(HDC hdc) {
1933 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1938 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1942 /* helper for ImageList_Read, see comments below */
1943 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1945 BITMAPFILEHEADER bmfh;
1946 BITMAPINFOHEADER bmih;
1947 int bitsperpixel,palspace,longsperline,width,height;
1948 LPBITMAPINFOHEADER bmihc = NULL;
1950 HBITMAP hbitmap = 0;
1951 LPBYTE bits = NULL,nbits = NULL;
1952 int nbytesperline,bytesperline;
1954 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1955 (bmfh.bfType != (('M'<<8)|'B')) ||
1956 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1957 (bmih.biSize != sizeof(bmih))
1961 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1962 if (bitsperpixel<=8)
1963 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1966 width = bmih.biWidth;
1967 height = bmih.biHeight;
1968 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1969 memcpy(bmihc,&bmih,sizeof(bmih));
1970 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1971 bmihc->biSizeImage = (longsperline*height)<<2;
1973 /* read the palette right after the end of the bitmapinfoheader */
1975 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1979 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1980 if ((bitsperpixel>1) &&
1981 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1983 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1986 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1992 int i,nwidth,nheight;
1994 nwidth = width*(height/cy);
1997 if (bitsperpixel==1)
1998 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2000 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2002 /* Might be a bit excessive memory use here */
2003 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2004 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2005 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2008 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2009 /* Do not forget that windows bitmaps are bottom->top */
2010 bytesperline = longsperline*4;
2011 nbytesperline = (height/cy)*bytesperline;
2012 for (i=0;i<height;i++) {
2014 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2015 bits+bytesperline*(height-1-i),
2019 bmihc->biWidth = nwidth;
2020 bmihc->biHeight = nheight;
2021 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2023 LocalFree((HLOCAL)nbits);
2024 LocalFree((HLOCAL)bits);
2028 if (xdc) ReleaseDC(0,xdc);
2029 if (bmihc) LocalFree((HLOCAL)bmihc);
2032 DeleteObject(hbitmap);
2039 /*************************************************************************
2040 * ImageList_Read [COMCTL32.68]
2042 * Reads an image list from a stream.
2045 * pstm [I] pointer to a stream
2048 * Success: handle to image list
2051 * The format is like this:
2052 * ILHEAD ilheadstruct;
2054 * for the color image part:
2055 * BITMAPFILEHEADER bmfh;
2056 * BITMAPINFOHEADER bmih;
2057 * only if it has a palette:
2058 * RGBQUAD rgbs[nr_of_paletted_colors];
2060 * BYTE colorbits[imagesize];
2062 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2063 * BITMAPFILEHEADER bmfh_mask;
2064 * BITMAPINFOHEADER bmih_mask;
2065 * only if it has a palette (it usually does not):
2066 * RGBQUAD rgbs[nr_of_paletted_colors];
2068 * BYTE maskbits[imagesize];
2070 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2071 * _read_bitmap needs to convert them.
2073 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2077 HBITMAP hbmColor=0,hbmMask=0;
2080 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2082 if (ilHead.usMagic != (('L' << 8) | 'I'))
2084 if (ilHead.usVersion != 0x101) /* probably version? */
2088 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2089 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2090 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2091 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2092 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2093 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2094 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2095 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2096 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2097 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2100 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2103 if (ilHead.flags & ILC_MASK) {
2104 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2106 DeleteObject(hbmColor);
2111 himl = ImageList_Create (
2119 DeleteObject(hbmColor);
2120 DeleteObject(hbmMask);
2123 himl->hbmImage = hbmColor;
2124 himl->hbmMask = hbmMask;
2125 himl->cCurImage = ilHead.cCurImage;
2126 himl->cMaxImage = ilHead.cMaxImage;
2128 ImageList_SetBkColor(himl,ilHead.bkcolor);
2130 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2135 /*************************************************************************
2136 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2139 * himl [I] image list handle
2148 ImageList_Remove (HIMAGELIST himl, INT i)
2150 HBITMAP hbmNewImage, hbmNewMask;
2155 ERR("Invalid image list handle!\n");
2159 if ((i < -1) || (i >= himl->cCurImage)) {
2160 ERR("index out of range! %d\n", i);
2164 if (himl->cCurImage == 0) {
2165 ERR("image list is already empty!\n");
2171 TRACE("remove all!\n");
2173 himl->cMaxImage = himl->cInitial + himl->cGrow;
2174 himl->cCurImage = 0;
2175 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2176 himl->nOvlIdx[nCount] = -1;
2178 DeleteObject (himl->hbmImage);
2180 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2181 1, himl->uBitsPixel, NULL);
2183 if (himl->hbmMask) {
2184 DeleteObject (himl->hbmMask);
2186 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2191 /* delete one image */
2192 TRACE("Remove single image! %d\n", i);
2194 /* create new bitmap(s) */
2195 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2197 TRACE(" - Number of images: %d / %d (Old/New)\n",
2198 himl->cCurImage, himl->cCurImage - 1);
2199 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2200 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2203 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2206 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2208 hbmNewMask = 0; /* Just to keep compiler happy! */
2210 hdcSrc = CreateCompatibleDC (0);
2211 hdcDst = CreateCompatibleDC (0);
2213 /* copy all images and masks prior to the "removed" image */
2215 TRACE("Pre image copy: Copy %d images\n", i);
2217 SelectObject (hdcSrc, himl->hbmImage);
2218 SelectObject (hdcDst, hbmNewImage);
2219 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2220 hdcSrc, 0, 0, SRCCOPY);
2222 if (himl->hbmMask) {
2223 SelectObject (hdcSrc, himl->hbmMask);
2224 SelectObject (hdcDst, hbmNewMask);
2225 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2226 hdcSrc, 0, 0, SRCCOPY);
2230 /* copy all images and masks behind the removed image */
2231 if (i < himl->cCurImage - 1) {
2232 TRACE("Post image copy!\n");
2233 SelectObject (hdcSrc, himl->hbmImage);
2234 SelectObject (hdcDst, hbmNewImage);
2235 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2236 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2238 if (himl->hbmMask) {
2239 SelectObject (hdcSrc, himl->hbmMask);
2240 SelectObject (hdcDst, hbmNewMask);
2241 BitBlt (hdcDst, i * himl->cx, 0,
2242 (himl->cCurImage - i - 1) * himl->cx,
2243 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2250 /* delete old images and insert new ones */
2251 DeleteObject (himl->hbmImage);
2252 himl->hbmImage = hbmNewImage;
2253 if (himl->hbmMask) {
2254 DeleteObject (himl->hbmMask);
2255 himl->hbmMask = hbmNewMask;
2259 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2266 /*************************************************************************
2267 * ImageList_Replace [COMCTL32.70]
2269 * Replaces an image in an image list with a new image.
2272 * himl [I] handle to image list
2274 * hbmImage [I] handle to image bitmap
2275 * hbmMask [I] handle to mask bitmap. Can be NULL.
2283 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2286 HDC hdcImageList, hdcImage;
2290 ERR("Invalid image list handle!\n");
2294 if ((i >= himl->cMaxImage) || (i < 0)) {
2295 ERR("Invalid image index!\n");
2299 hdcImageList = CreateCompatibleDC (0);
2300 hdcImage = CreateCompatibleDC (0);
2301 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2304 SelectObject (hdcImageList, himl->hbmImage);
2305 SelectObject (hdcImage, hbmImage);
2307 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2308 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2313 SelectObject (hdcImageList, himl->hbmMask);
2314 SelectObject (hdcImage, hbmMask);
2316 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2317 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2320 /* Remove the background from the image
2322 SelectObject (hdcImageList, himl->hbmImage);
2323 StretchBlt (hdcImageList,
2324 i*himl->cx, 0, himl->cx, himl->cy,
2326 0, 0, bmp.bmWidth, bmp.bmHeight,
2327 0x220326); /* NOTSRCAND */
2330 DeleteDC (hdcImage);
2331 DeleteDC (hdcImageList);
2337 /*************************************************************************
2338 * ImageList_ReplaceIcon [COMCTL32.75]
2340 * Replaces an image in an image list using an icon.
2343 * himl [I] handle to image list
2345 * hIcon [I] handle to icon
2348 * Success: index of the replaced image
2353 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2355 HDC hdcImageList, hdcImage;
2358 HBITMAP hbmOldSrc, hbmOldDst;
2362 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2366 if ((i >= himl->cMaxImage) || (i < -1))
2369 hBestFitIcon = CopyImage(
2372 LR_COPYFROMRESOURCE);
2374 GetIconInfo (hBestFitIcon, &ii);
2375 if (ii.hbmMask == 0)
2377 if (ii.hbmColor == 0)
2379 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2382 if (himl->cCurImage + 1 >= himl->cMaxImage)
2383 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2385 nIndex = himl->cCurImage;
2391 hdcImageList = CreateCompatibleDC (0);
2392 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2393 if (hdcImageList == 0)
2394 ERR("invalid hdcImageList!\n");
2396 hdcImage = CreateCompatibleDC (0);
2397 TRACE("hdcImage=0x%x!\n", hdcImage);
2399 ERR("invalid hdcImage!\n");
2401 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2402 SetTextColor( hdcImageList, RGB(0,0,0));
2403 SetBkColor( hdcImageList, RGB(255,255,255));
2404 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2405 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2406 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2408 if (himl->hbmMask) {
2409 SelectObject (hdcImageList, himl->hbmMask);
2410 SelectObject (hdcImage, ii.hbmMask);
2411 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2412 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2415 SelectObject (hdcImage, hbmOldSrc);
2416 SelectObject (hdcImageList, hbmOldDst);
2419 DestroyIcon(hBestFitIcon);
2421 DeleteDC (hdcImageList);
2423 DeleteDC (hdcImage);
2425 DeleteObject (ii.hbmColor);
2427 DeleteObject (ii.hbmMask);
2433 /*************************************************************************
2434 * ImageList_SetBkColor [COMCTL32.76]
2436 * Sets the background color of an image list.
2439 * himl [I] handle to image list
2440 * clrBk [I] background color
2443 * Success: previous background color
2448 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2455 clrOldBk = himl->clrBk;
2456 himl->clrBk = clrBk;
2461 /*************************************************************************
2462 * ImageList_SetDragCursorImage [COMCTL32.77]
2464 * Combines the specified image with the current drag image
2467 * himlDrag [I] handle to drag image list
2468 * iDrag [I] drag image index
2469 * dxHotspot [I] X position of the hot spot
2470 * dyHotspot [I] Y position of the hot spot
2481 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2482 INT dxHotspot, INT dyHotspot)
2484 HIMAGELIST himlTemp;
2486 FIXME("semi-stub!\n");
2488 if (himlInternalDrag == NULL)
2491 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2492 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2494 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2495 dxHotspot, dyHotspot);
2497 ImageList_Destroy (himlInternalDrag);
2498 himlInternalDrag = himlTemp;
2500 nInternalDragHotspotX = dxHotspot;
2501 nInternalDragHotspotY = dyHotspot;
2507 /*************************************************************************
2508 * ImageList_SetFilter [COMCTL32.78]
2510 * Sets a filter (or does something completely different)!!???
2513 * himl [I] handle to image list
2519 * Failure: FALSE ???
2522 * This is an UNDOCUMENTED function!!!!
2527 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2529 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2536 /*************************************************************************
2537 * ImageList_SetIconSize [COMCTL32.80]
2539 * Sets the image size of the bitmap and deletes all images.
2542 * himl [I] handle to image list
2543 * cx [I] image width
2544 * cy [I] image height
2552 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2559 /* remove all images */
2560 himl->cMaxImage = himl->cInitial + himl->cGrow;
2561 himl->cCurImage = 0;
2565 /* initialize overlay mask indices */
2566 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2567 himl->nOvlIdx[nCount] = -1;
2569 DeleteObject (himl->hbmImage);
2571 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2572 1, himl->uBitsPixel, NULL);
2574 if (himl->hbmMask) {
2575 DeleteObject (himl->hbmMask);
2577 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2585 /*************************************************************************
2586 * ImageList_SetImageCount [COMCTL32.81]
2588 * Resizes an image list to the specified number of images.
2591 * himl [I] handle to image list
2592 * iImageCount [I] number of images in the image list
2600 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2602 HDC hdcImageList, hdcBitmap;
2603 HBITMAP hbmNewBitmap;
2604 INT nNewCount, nCopyCount;
2608 if (himl->cCurImage >= iImageCount)
2610 if (himl->cMaxImage > iImageCount)
2613 nNewCount = iImageCount + himl->cGrow;
2614 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2616 hdcImageList = CreateCompatibleDC (0);
2617 hdcBitmap = CreateCompatibleDC (0);
2619 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2620 1, himl->uBitsPixel, NULL);
2621 if (hbmNewBitmap != 0)
2623 SelectObject (hdcImageList, himl->hbmImage);
2624 SelectObject (hdcBitmap, hbmNewBitmap);
2627 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2628 hdcImageList, 0, 0, SRCCOPY);
2630 /* delete 'empty' image space */
2631 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2632 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2633 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2634 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2636 DeleteObject (himl->hbmImage);
2637 himl->hbmImage = hbmNewBitmap;
2640 ERR("Could not create new image bitmap !\n");
2644 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2646 if (hbmNewBitmap != 0)
2648 SelectObject (hdcImageList, himl->hbmMask);
2649 SelectObject (hdcBitmap, hbmNewBitmap);
2652 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2653 hdcImageList, 0, 0, SRCCOPY);
2655 /* delete 'empty' image space */
2656 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2657 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2658 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2659 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2661 DeleteObject (himl->hbmMask);
2662 himl->hbmMask = hbmNewBitmap;
2665 ERR("Could not create new mask bitmap!\n");
2668 DeleteDC (hdcImageList);
2669 DeleteDC (hdcBitmap);
2671 /* Update max image count and current image count */
2672 himl->cMaxImage = nNewCount;
2673 if (himl->cCurImage > nCopyCount)
2674 himl->cCurImage = nCopyCount;
2680 /*************************************************************************
2681 * ImageList_SetOverlayImage [COMCTL32.82]
2683 * Assigns an overlay mask index to an existing image in an image list.
2686 * himl [I] handle to image list
2687 * iImage [I] image index
2688 * iOverlay [I] overlay mask index
2696 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2700 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2702 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2704 himl->nOvlIdx[iOverlay - 1] = iImage;
2709 /*************************************************************************
2710 * ImageList_Write [COMCTL32.83]
2712 * Writes an image list to a stream.
2715 * himl [I] handle to image list
2716 * pstm [O] Pointer to a stream.
2723 * This function can not be implemented yet, because
2724 * IStream32::Write is not implemented.
2731 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2736 FIXME("empty stub!\n");