2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
7 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
8 * - Fix ImageList_GetIcon.
9 * - Fix drag functions.
10 * - Fix ImageList_Write.
11 * - Fix ImageList_SetFilter (undocumented).
12 * BTW does anybody know anything about this function???
13 * - It removes 12 Bytes from the stack (3 Parameters).
14 * - First parameter SHOULD be a HIMAGELIST.
15 * - Second parameter COULD be an index?????
16 * - Third parameter.... ?????????????????????
19 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
20 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
21 * partially imlemented, the functions mentioned above will be
22 * limited in functionality too.
25 /* This must be defined because the HIMAGELIST type is just a pointer
26 * to the _IMAGELIST data structure. But M$ does not want us to know
27 * anything about its contents. Applications just see a pointer to
28 * an empty structure. It's just to keep compatibility.
30 #define __WINE_IMAGELIST_C
33 #include "wine/obj_base.h"
34 #include "wine/obj_storage.h"
35 #include "imagelist.h"
37 #include "debugtools.h"
40 DEFAULT_DEBUG_CHANNEL(imagelist)
43 #define _MAX(a,b) (((a)>(b))?(a):(b))
44 #define _MIN(a,b) (((a)>(b))?(b):(a))
46 #define MAX_OVERLAYIMAGE 15
49 /* internal image list data used for Drag & Drop operations */
51 static HIMAGELIST himlInternalDrag = NULL;
52 static INT nInternalDragHotspotX = 0;
53 static INT nInternalDragHotspotY = 0;
55 static HWND hwndInternalDrag = 0;
56 static INT xInternalPos = 0;
57 static INT yInternalPos = 0;
59 static HDC hdcBackBuffer = 0;
60 static HBITMAP hbmBackBuffer = 0;
63 /*************************************************************************
64 * IMAGELIST_InternalExpandBitmaps [Internal]
66 * Expands the bitmaps of an image list by the given number of images.
69 * himl [I] handle to image list
70 * nImageCount [I] number of images to add
76 * This function can NOT be used to reduce the number of images.
79 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
81 HDC hdcImageList, hdcBitmap;
83 INT nNewWidth, nNewCount;
85 if ((himl->cCurImage + nImageCount < himl->cMaxImage)
89 if (cy == 0) cy = himl->cy;
90 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
91 nNewWidth = nNewCount * himl->cx;
93 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
94 hdcImageList = CreateCompatibleDC (0);
95 hdcBitmap = CreateCompatibleDC (0);
98 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
99 if (hbmNewBitmap == 0)
100 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
102 SelectObject (hdcImageList, himl->hbmImage);
103 SelectObject (hdcBitmap, hbmNewBitmap);
104 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
105 hdcImageList, 0, 0, SRCCOPY);
107 DeleteObject (himl->hbmImage);
108 himl->hbmImage = hbmNewBitmap;
112 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
114 if (hbmNewBitmap == 0)
115 ERR("creating new mask bitmap!\n");
117 SelectObject (hdcImageList, himl->hbmMask);
118 SelectObject (hdcBitmap, hbmNewBitmap);
119 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
120 hdcImageList, 0, 0, SRCCOPY);
121 DeleteObject (himl->hbmMask);
122 himl->hbmMask = hbmNewBitmap;
125 himl->cMaxImage = nNewCount;
127 DeleteDC (hdcImageList);
128 DeleteDC (hdcBitmap);
132 /*************************************************************************
133 * IMAGELIST_InternalDraw [Internal]
135 * Draws the image in the ImageList (without the mask)
138 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
139 * cx [I] the width of the image to display
140 * cy............[I] the height of the image to display
146 * This functions is used by ImageList_DrawIndirect, when it is
147 * required to draw only the Image (without the mask) to the screen.
149 * Blending and Overlays styles are accomplised by another function
152 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
157 hImageDC = CreateCompatibleDC(0);
158 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
159 BitBlt(pimldp->hdcDst,
160 pimldp->x, pimldp->y, cx, cy,
162 pimldp->himl->cx * pimldp->i, 0,
165 SelectObject(hImageDC, hOldBitmap);
170 /*************************************************************************
171 * IMAGELIST_InternalDrawMask [Internal]
173 * Draws the image in the ImageList witht the mask
176 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
177 * cx [I] the width of the image to display
178 * cy............[I] the height of the image to display
184 * This functions is used by ImageList_DrawIndirect, when it is
185 * required to draw the Image with the mask to the screen.
187 * Blending and Overlays styles are accomplised by another function.
190 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
192 HDC hMaskDC, hImageDC;
193 BOOL bUseCustomBackground, bBlendFlag;
194 HBRUSH hBrush, hOldBrush;
195 HBITMAP hOldBitmapImage, hOldBitmapMask;
196 HIMAGELIST himlLocal = pimldp->himl;
197 COLORREF oldBkColor, oldFgColor;
198 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
200 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
201 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
203 hImageDC = CreateCompatibleDC(0);
204 hMaskDC = CreateCompatibleDC(0);
206 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
207 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
208 /* Draw the Background for the appropriate Styles
210 if( bUseCustomBackground &&
211 (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE || bBlendFlag))
213 hBrush = CreateSolidBrush (himlLocal->clrBk);
214 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
215 PatBlt (pimldp->hdcDst,
216 pimldp->x, pimldp->y, cx, cy,
219 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
222 /* Draw Image Transparently over the current background
224 if(fStyle == ILD_NORMAL
225 || (fStyle & ILD_TRANSPARENT)
226 || ((fStyle & ILD_IMAGE) && bUseCustomBackground)
229 /* to obtain a transparent look, background color should be set
230 to white and foreground color to black when blting the
232 oldBkColor = SetBkColor(pimldp->hdcDst, RGB(0xff, 0xff, 0xff));
233 oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 0));
235 BitBlt(pimldp->hdcDst,
236 pimldp->x, pimldp->y, cx, cy,
238 himlLocal->cx * pimldp->i, 0,
241 BitBlt(pimldp->hdcDst,
242 pimldp->x, pimldp->y, cx, cy,
244 himlLocal->cx * pimldp->i, 0,
247 SetBkColor(pimldp->hdcDst, oldBkColor);
248 SetTextColor(pimldp->hdcDst, oldFgColor);
250 /* Draw the image when no Background is specified
252 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
254 BitBlt(pimldp->hdcDst,
255 pimldp->x, pimldp->y, cx, cy,
257 himlLocal->cx * pimldp->i, 0,
260 /* Draw the mask with or without a background
262 else if(fStyle & ILD_MASK)
264 BitBlt(pimldp->hdcDst,
265 pimldp->x, pimldp->y, cx, cy,
267 himlLocal->cx * pimldp->i, 0,
268 bUseCustomBackground ? SRCCOPY : SRCAND);
270 SelectObject(hImageDC, hOldBitmapImage);
271 SelectObject(hMaskDC, hOldBitmapMask);
276 /*************************************************************************
277 * IMAGELIST_InternalDrawBlend [Internal]
279 * Draws the Blend over the current image
282 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
283 * cx [I] the width of the image to display
284 * cy............[I] the height of the image to display
290 * This functions is used by ImageList_DrawIndirect, when it is
291 * required to add the blend to the current image.
295 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
298 HDC hBlendMaskDC,hMaskDC;
299 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
300 HBITMAP hBlendMaskBitmap, hOldBitmap;
301 COLORREF clrBlend, OldTextColor, OldBkColor;
302 HIMAGELIST himlLocal = pimldp->himl;
304 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
305 if (!(pimldp->rgbFg == CLR_DEFAULT))
307 clrBlend = pimldp->rgbFg;
309 /* Create the blend Mask
311 hBlendMaskDC = CreateCompatibleDC(0);
312 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
313 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
315 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
316 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
318 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
319 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
320 SelectObject(hBlendMaskDC, hOldBrush);
322 /* Modify the blend mask if an Image Mask exist
324 if(pimldp->himl->hbmMask != 0)
326 HBITMAP hOldMaskBitmap;
327 hMaskDC = CreateCompatibleDC(0);
328 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
333 himlLocal->cx * pimldp->i,0,
334 0x220326); /* NOTSRCAND */
342 SelectObject(hMaskDC, hOldMaskBitmap);
346 /* Apply blend to the current image given the BlendMask
348 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
349 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
350 hBlendColorBrush = CreateSolidBrush(clrBlend);
351 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
353 BitBlt (pimldp->hdcDst,
354 pimldp->x, pimldp->y, cx, cy,
357 0xB8074A); /* PSDPxax */
359 SelectObject(pimldp->hdcDst, hOldBrush);
360 SetTextColor(pimldp->hdcDst, OldTextColor);
361 SetBkColor(pimldp->hdcDst, OldBkColor);
362 SelectObject(hBlendMaskDC, hOldBitmap);
363 DeleteDC(hBlendMaskDC);
364 DeleteObject(hBlendMaskBitmap);
365 DeleteObject(hBlendColorBrush);
368 /*************************************************************************
369 * IMAGELIST_InternalDrawOverlay [Internal]
371 * Draws the overlay image
374 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
375 * cx [I] the width of the image to display
376 * cy............[I] the height of the image to display
382 * This functions is used by ImageList_DrawIndirect, when it is
383 * required to draw the overlay
388 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
394 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
395 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
397 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
398 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
400 hImageDC = CreateCompatibleDC(0);
401 if (pimldp->himl->hbmMask)
403 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
404 pimldp->himl->hbmMask);
406 BitBlt (pimldp->hdcDst,
407 pimldp->x, pimldp->y, cx, cy,
408 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
411 SelectObject(hImageDC, hOldBitmap);
413 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
414 pimldp->himl->hbmImage);
416 BitBlt (pimldp->hdcDst,
417 pimldp->x, pimldp->y, cx, cy,
419 pimldp->himl->cx * nOvlIdx, 0,
422 SelectObject(hImageDC, hOldBitmap);
432 /*************************************************************************
433 * ImageList_Add [COMCTL32.39]
435 * Add an image or images to an image list.
438 * himl [I] handle to image list
439 * hbmImage [I] handle to image bitmap
440 * hbmMask [I] handle to mask bitmap
443 * Success: Index of the first new image.
448 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
450 HDC hdcImage, hdcBitmap;
451 INT nFirstIndex, nImageCount;
454 HBITMAP hOldBitmapImage, hOldBitmap;
456 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
457 if (!himl || !hbmImage)
460 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
461 nImageCount = bmp.bmWidth / himl->cx;
463 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
465 nStartX = himl->cCurImage * himl->cx;
467 hdcImage = CreateCompatibleDC(0);
468 hdcBitmap = CreateCompatibleDC(0);
470 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
471 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
473 /* Copy result to the imagelist
475 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
476 hdcBitmap, 0, 0, SRCCOPY);
480 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
482 hdcMask = CreateCompatibleDC (0);
483 hdcTemp = CreateCompatibleDC(0);
484 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
485 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
488 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
493 SelectObject(hdcTemp, hOldBitmapTemp);
496 /* Remove the background from the image
499 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
502 0x220326); /* NOTSRCAND */
504 SelectObject(hdcMask, hOldBitmapMask);
508 SelectObject(hdcImage, hOldBitmapImage);
509 SelectObject(hdcBitmap, hOldBitmap);
513 nFirstIndex = himl->cCurImage;
514 himl->cCurImage += nImageCount;
520 /*************************************************************************
521 * ImageList_AddIcon [COMCTL32.40]
523 * Adds an icon to an image list.
526 * himl [I] handle to image list
527 * hIcon [I] handle to icon
530 * Success: index of the new image
535 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
537 return ImageList_ReplaceIcon (himl, -1, hIcon);
541 /*************************************************************************
542 * ImageList_AddMasked [COMCTL32.41]
544 * Adds an image or images to an image list and creates a mask from the
545 * specified bitmap using the mask color.
548 * himl [I] handle to image list.
549 * hBitmap [I] handle to bitmap
550 * clrMask [I] mask color.
553 * Success: Index of the first new image.
558 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
560 HDC hdcImage, hdcMask, hdcBitmap;
561 INT nIndex, nImageCount, nMaskXOffset=0;
563 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
564 HBITMAP hMaskBitmap=0;
567 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
571 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
574 nImageCount = bmp.bmWidth / himl->cx;
576 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
578 nIndex = himl->cCurImage;
579 himl->cCurImage += nImageCount;
581 hdcMask = CreateCompatibleDC (0);
582 hdcImage = CreateCompatibleDC(0);
583 hdcBitmap = CreateCompatibleDC(0);
586 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
587 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
590 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
591 nMaskXOffset = nIndex * himl->cx;
596 Create a temp Mask so we can remove the background of
597 the Image (Windows does this even if there is no mask)
599 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
600 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
603 /* create monochrome image to the mask bitmap */
604 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
605 GetPixel (hdcBitmap, 0, 0);
606 SetBkColor (hdcBitmap, bkColor);
608 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
612 SetBkColor(hdcBitmap, RGB(255,255,255));
613 /*Remove the background from the image
616 WINDOWS BUG ALERT!!!!!!
617 The statement below should not be done in common practice
618 but this is how ImageList_AddMasked works in Windows.
619 It overwrites the original bitmap passed, this was discovered
620 by using the same bitmap to itterated the different styles
621 on windows where it failed (BUT ImageList_Add is OK)
622 This is here in case some apps really on this bug
625 0, 0, bmp.bmWidth, bmp.bmHeight,
628 0x220326); /* NOTSRCAND */
629 /* Copy result to the imagelist
632 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
638 SelectObject(hdcMask,hOldBitmapMask);
639 SelectObject(hdcImage, hOldBitmapImage);
640 SelectObject(hdcBitmap, hOldBitmap);
646 DeleteObject(hMaskBitmap);
653 /*************************************************************************
654 * ImageList_BeginDrag [COMCTL32.42]
656 * Creates a temporary image list that contains one image. It will be used
660 * himlTrack [I] handle to the source image list
661 * iTrack [I] index of the drag image in the source image list
662 * dxHotspot [I] X position of the hot spot of the drag image
663 * dyHotspot [I] Y position of the hot spot of the drag image
671 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
672 INT dxHotspot, INT dyHotspot)
676 FIXME("partially implemented!\n");
678 if (himlTrack == NULL)
681 if (himlInternalDrag)
682 ImageList_EndDrag ();
685 ImageList_Create (himlTrack->cx, himlTrack->cy,
686 himlTrack->flags, 1, 1);
687 if (himlInternalDrag == NULL) {
688 ERR("Error creating drag image list!\n");
692 nInternalDragHotspotX = dxHotspot;
693 nInternalDragHotspotY = dyHotspot;
695 hdcSrc = CreateCompatibleDC (0);
696 hdcDst = CreateCompatibleDC (0);
699 SelectObject (hdcSrc, himlTrack->hbmImage);
700 SelectObject (hdcDst, himlInternalDrag->hbmImage);
701 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
702 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
705 SelectObject (hdcSrc, himlTrack->hbmMask);
706 SelectObject (hdcDst, himlInternalDrag->hbmMask);
707 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
708 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
713 himlInternalDrag->cCurImage = 1;
719 /*************************************************************************
720 * ImageList_Copy [COMCTL32.43]
722 * Copies an image of the source image list to an image of the
723 * destination image list. Images can be copied or swapped.
726 * himlDst [I] handle to the destination image list
727 * iDst [I] destination image index.
728 * himlSrc [I] handle to the source image list
729 * iSrc [I] source image index
730 * uFlags [I] flags for the copy operation
737 * Copying from one image list to another is possible. The original
738 * implementation just copies or swapps within one image list.
739 * Could this feature become a bug??? ;-)
743 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
744 INT iSrc, INT uFlags)
748 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
750 if ((himlSrc == NULL) || (himlDst == NULL))
752 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
754 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
757 hdcSrc = CreateCompatibleDC (0);
758 if (himlDst == himlSrc)
761 hdcDst = CreateCompatibleDC (0);
763 if (uFlags & ILCF_SWAP) {
765 HBITMAP hbmTempImage, hbmTempMask;
767 /* create temporary bitmaps */
768 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
769 himlSrc->uBitsPixel, NULL);
770 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
773 /* copy (and stretch) destination to temporary bitmaps.(save) */
775 SelectObject (hdcSrc, himlDst->hbmImage);
776 SelectObject (hdcDst, hbmTempImage);
777 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
778 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
781 SelectObject (hdcSrc, himlDst->hbmMask);
782 SelectObject (hdcDst, hbmTempMask);
783 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
784 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
787 /* copy (and stretch) source to destination */
789 SelectObject (hdcSrc, himlSrc->hbmImage);
790 SelectObject (hdcDst, himlDst->hbmImage);
791 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
792 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
795 SelectObject (hdcSrc, himlSrc->hbmMask);
796 SelectObject (hdcDst, himlDst->hbmMask);
797 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
798 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
801 /* copy (without stretching) temporary bitmaps to source (restore) */
803 SelectObject (hdcSrc, hbmTempImage);
804 SelectObject (hdcDst, himlSrc->hbmImage);
805 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
806 hdcSrc, 0, 0, SRCCOPY);
808 SelectObject (hdcSrc, hbmTempMask);
809 SelectObject (hdcDst, himlSrc->hbmMask);
810 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
811 hdcSrc, 0, 0, SRCCOPY);
813 /* delete temporary bitmaps */
814 DeleteObject (hbmTempMask);
815 DeleteObject (hbmTempImage);
819 SelectObject (hdcSrc, himlSrc->hbmImage);
820 if (himlSrc == himlDst)
823 SelectObject (hdcDst, himlDst->hbmImage);
824 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
825 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
829 SelectObject (hdcSrc, himlSrc->hbmMask);
830 if (himlSrc == himlDst)
833 SelectObject (hdcDst, himlDst->hbmMask);
834 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
835 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
840 if (himlSrc != himlDst)
847 /*************************************************************************
848 * ImageList_Create [COMCTL32.44] Creates a new image list.
851 * cx [I] image height
853 * flags [I] creation flags
854 * cInitial [I] initial number of images in the image list
855 * cGrow [I] number of images by which image list grows
858 * Success: Handle to the created image list
863 ImageList_Create (INT cx, INT cy, UINT flags,
864 INT cInitial, INT cGrow)
870 static WORD aBitBlend25[] =
871 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
873 static WORD aBitBlend50[] =
874 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
876 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
878 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
885 himl->cMaxImage = cInitial + cGrow;
886 himl->cInitial = cInitial;
889 himl->clrFg = CLR_DEFAULT;
890 himl->clrBk = CLR_NONE;
892 /* initialize overlay mask indices */
893 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
894 himl->nOvlIdx[nCount] = -1;
896 hdc = CreateCompatibleDC (0);
897 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
900 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
902 if (himl->cMaxImage > 0) {
904 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
905 1, himl->uBitsPixel, NULL);
906 if (himl->hbmImage == 0) {
907 ERR("Error creating image bitmap!\n");
914 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
915 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
917 if (himl->hbmMask == 0) {
918 ERR("Error creating mask bitmap!\n");
920 DeleteObject (himl->hbmImage);
927 /* create blending brushes */
928 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
929 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
930 DeleteObject (hbmTemp);
932 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
933 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
934 DeleteObject (hbmTemp);
936 TRACE("created imagelist %p\n", himl);
941 /*************************************************************************
942 * ImageList_Destroy [COMCTL32.45]
944 * Destroys an image list.
947 * himl [I] handle to image list
955 ImageList_Destroy (HIMAGELIST himl)
960 /* delete image bitmaps */
962 DeleteObject (himl->hbmImage);
964 DeleteObject (himl->hbmMask);
966 /* delete blending brushes */
967 if (himl->hbrBlend25)
968 DeleteObject (himl->hbrBlend25);
969 if (himl->hbrBlend50)
970 DeleteObject (himl->hbrBlend50);
972 COMCTL32_Free (himl);
978 /*************************************************************************
979 * ImageList_DragEnter [COMCTL32.46]
981 * Locks window update and displays the drag image at the given position.
984 * hwndLock [I] handle of the window that owns the drag image.
985 * x [I] X position of the drag image.
986 * y [I] Y position of the drag image.
993 * The position of the drag image is relative to the window, not
998 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1000 if (himlInternalDrag == NULL)
1004 hwndInternalDrag = hwndLock;
1006 hwndInternalDrag = GetDesktopWindow ();
1011 hdcBackBuffer = CreateCompatibleDC (0);
1012 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1013 himlInternalDrag->cx, himlInternalDrag->cy);
1015 ImageList_DragShowNolock (TRUE);
1021 /*************************************************************************
1022 * ImageList_DragLeave [COMCTL32.47]
1024 * Unlocks window update and hides the drag image.
1027 * hwndLock [I] handle of the window that owns the drag image.
1035 ImageList_DragLeave (HWND hwndLock)
1038 hwndInternalDrag = hwndLock;
1040 hwndInternalDrag = GetDesktopWindow ();
1042 ImageList_DragShowNolock (FALSE);
1044 DeleteDC (hdcBackBuffer);
1045 DeleteObject (hbmBackBuffer);
1051 /*************************************************************************
1052 * ImageList_DragMove [COMCTL32.48]
1054 * Moves the drag image.
1057 * x [I] X position of the drag image.
1058 * y [I] Y position of the drag image.
1065 * The position of the drag image is relative to the window, not
1070 ImageList_DragMove (INT x, INT y)
1072 ImageList_DragShowNolock (FALSE);
1077 ImageList_DragShowNolock (TRUE);
1083 /*************************************************************************
1084 * ImageList_DragShowNolock [COMCTL32.49]
1086 * Shows or hides the drag image.
1089 * bShow [I] TRUE shows the drag image, FALSE hides it.
1100 ImageList_DragShowNolock (BOOL bShow)
1104 FIXME("semi-stub!\n");
1105 TRACE("bShow=0x%X!\n", bShow);
1107 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1108 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1111 /* show drag image */
1113 /* save background */
1115 /* draw drag image */
1119 /* hide drag image */
1121 /* restore background */
1125 ReleaseDC (hwndInternalDrag, hdcDrag);
1131 /*************************************************************************
1132 * ImageList_Draw [COMCTL32.50] Draws an image.
1135 * himl [I] handle to image list
1137 * hdc [I] handle to device context
1140 * fStyle [I] drawing flags
1147 * Calls ImageList_DrawIndirect.
1150 * ImageList_DrawIndirect.
1154 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1155 INT x, INT y, UINT fStyle)
1157 IMAGELISTDRAWPARAMS imldp;
1159 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1169 imldp.rgbBk = CLR_DEFAULT;
1170 imldp.rgbFg = CLR_DEFAULT;
1171 imldp.fStyle = fStyle;
1174 return ImageList_DrawIndirect (&imldp);
1178 /*************************************************************************
1179 * ImageList_DrawEx [COMCTL32.51]
1181 * Draws an image and allows to use extended drawing features.
1184 * himl [I] handle to image list
1186 * hdc [I] handle to device context
1189 * xOffs [I] X offset
1190 * yOffs [I] Y offset
1191 * rgbBk [I] background color
1192 * rgbFg [I] foreground color
1193 * fStyle [I] drawing flags
1200 * Calls ImageList_DrawIndirect.
1203 * ImageList_DrawIndirect.
1207 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1208 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1211 IMAGELISTDRAWPARAMS imldp;
1213 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1223 imldp.rgbBk = rgbBk;
1224 imldp.rgbFg = rgbFg;
1225 imldp.fStyle = fStyle;
1228 return ImageList_DrawIndirect (&imldp);
1232 /*************************************************************************
1233 * ImageList_DrawIndirect [COMCTL32.52]
1235 * Draws an image using ...
1238 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1246 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1250 Do some Error Checking
1254 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1256 if (pimldp->himl == NULL)
1258 if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage)) {
1259 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage);
1263 Get the Height and Width to display
1265 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1266 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1270 if(pimldp->himl->hbmMask != 0)
1272 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1276 IMAGELIST_InternalDraw(pimldp, cx, cy);
1279 Apply the blend if needed to the Image
1281 if((pimldp->fStyle & ILD_BLEND50)
1282 || (pimldp->fStyle & ILD_BLEND25))
1284 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1287 Apply the Overlay if needed
1289 if (pimldp->fStyle & ILD_OVERLAYMASK)
1291 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1298 /*************************************************************************
1299 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1302 * himlSrc [I] source image list handle
1305 * Success: Handle of duplicated image list.
1310 ImageList_Duplicate (HIMAGELIST himlSrc)
1315 if (himlSrc == NULL) {
1316 ERR("Invalid image list handle!\n");
1320 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1321 himlSrc->cInitial, himlSrc->cGrow);
1325 hdcSrc = CreateCompatibleDC (0);
1326 hdcDst = CreateCompatibleDC (0);
1327 SelectObject (hdcSrc, himlSrc->hbmImage);
1328 SelectObject (hdcDst, himlDst->hbmImage);
1329 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1330 hdcSrc, 0, 0, SRCCOPY);
1332 if (himlDst->hbmMask)
1334 SelectObject (hdcSrc, himlSrc->hbmMask);
1335 SelectObject (hdcDst, himlDst->hbmMask);
1336 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1337 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1343 himlDst->cCurImage = himlSrc->cCurImage;
1344 himlDst->cMaxImage = himlSrc->cMaxImage;
1350 /*************************************************************************
1351 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1353 * Finishes a drag operation.
1367 ImageList_EndDrag (void)
1369 FIXME("semi-stub!\n");
1371 if (himlInternalDrag)
1374 ImageList_Destroy (himlInternalDrag);
1375 himlInternalDrag = NULL;
1377 nInternalDragHotspotX = 0;
1378 nInternalDragHotspotY = 0;
1386 /*************************************************************************
1387 * ImageList_GetBkColor [COMCTL32.55]
1389 * Returns the background color of an image list.
1392 * himl [I] Image list handle.
1395 * Success: background color
1400 ImageList_GetBkColor (HIMAGELIST himl)
1409 /*************************************************************************
1410 * ImageList_GetDragImage [COMCTL32.56]
1412 * Returns the handle to the internal drag image list.
1415 * ppt [O] Pointer to the drag position. Can be NULL.
1416 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1419 * Success: Handle of the drag image list.
1427 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1429 FIXME("semi-stub!\n");
1431 if (himlInternalDrag)
1432 return (himlInternalDrag);
1438 /*************************************************************************
1439 * ImageList_GetIcon [COMCTL32.57]
1441 * Creates an icon from a masked image of an image list.
1444 * himl [I] handle to image list
1446 * flags [I] drawing style flags
1449 * Success: icon handle
1454 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1458 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1461 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1462 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1466 hdcSrc = CreateCompatibleDC(0);
1467 hdcDst = CreateCompatibleDC(0);
1470 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1473 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1474 if (himl->hbmMask) {
1475 SelectObject (hdcSrc, himl->hbmMask);
1476 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1477 hdcSrc, i * himl->cx, 0, SRCCOPY);
1480 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1483 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1484 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1485 SelectObject (hdcDst, ii.hbmColor);
1486 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1487 hdcSrc, i * himl->cx, 0, SRCCOPY);
1490 * CreateIconIndirect requires us to deselect the bitmaps from
1491 * the DCs before calling
1493 SelectObject(hdcSrc, hOldSrcBitmap);
1494 SelectObject(hdcDst, hOldDstBitmap);
1496 hIcon = CreateIconIndirect (&ii);
1500 DeleteObject (ii.hbmMask);
1501 DeleteObject (ii.hbmColor);
1507 /*************************************************************************
1508 * ImageList_GetIconSize [COMCTL32.58]
1510 * Retrieves the size of an image in an image list.
1513 * himl [I] handle to image list
1514 * cx [O] pointer to the image width.
1515 * cy [O] pointer to the image height.
1522 * All images in an image list have the same size.
1526 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1530 if ((himl->cx <= 0) || (himl->cy <= 0))
1542 /*************************************************************************
1543 * ImageList_GetImageCount [COMCTL32.59]
1545 * Returns the number of images in an image list.
1548 * himl [I] handle to image list
1551 * Success: Number of images.
1556 ImageList_GetImageCount (HIMAGELIST himl)
1561 return himl->cCurImage;
1565 /*************************************************************************
1566 * ImageList_GetImageInfo [COMCTL32.60]
1568 * Returns information about an image in an image list.
1571 * himl [I] handle to image list
1573 * pImageInfo [O] pointer to the image information
1581 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1583 if ((himl == NULL) || (pImageInfo == NULL))
1585 if ((i < 0) || (i >= himl->cCurImage))
1588 pImageInfo->hbmImage = himl->hbmImage;
1589 pImageInfo->hbmMask = himl->hbmMask;
1591 pImageInfo->rcImage.top = 0;
1592 pImageInfo->rcImage.bottom = himl->cy;
1593 pImageInfo->rcImage.left = i * himl->cx;
1594 pImageInfo->rcImage.right = (i+1) * himl->cx;
1600 /*************************************************************************
1601 * ImageList_GetImageRect [COMCTL32.61]
1603 * Retrieves the rectangle of the specified image in an image list.
1606 * himl [I] handle to image list
1608 * lpRect [O] pointer to the image rectangle
1615 * This is an UNDOCUMENTED function!!!
1619 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1621 if ((himl == NULL) || (lpRect == NULL))
1623 if ((i < 0) || (i >= himl->cCurImage))
1626 lpRect->left = i * himl->cx;
1628 lpRect->right = lpRect->left + himl->cx;
1629 lpRect->bottom = himl->cy;
1635 /*************************************************************************
1636 * ImageList_LoadImageA [COMCTL32.63][COMCTL32.62]
1638 * Creates an image list from a bitmap, icon or cursor.
1641 * hi [I] instance handle
1642 * lpbmp [I] name or id of the image
1643 * cx [I] width of each image
1644 * cGrow [I] number of images to expand
1645 * clrMask [I] mask color
1646 * uType [I] type of image to load
1647 * uFlags [I] loading flags
1650 * Success: handle to the loaded image list
1658 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1659 COLORREF clrMask, UINT uType, UINT uFlags)
1661 HIMAGELIST himl = NULL;
1665 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1667 ERR("Error loading image!\n");
1671 if (uType == IMAGE_BITMAP) {
1673 GetObjectA (handle, sizeof(BITMAP), &bmp);
1675 /* To match windows behavior, if cx is set to zero and
1676 the flag DI_DEFAULTSIZE is specified, cx becomes the
1677 system metric value for icons. If the flag is not specified
1678 the function sets the size to the height of the bitmap */
1681 if (uFlags & DI_DEFAULTSIZE)
1682 cx = GetSystemMetrics (SM_CXICON);
1687 nImageCount = bmp.bmWidth / cx;
1689 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1690 nImageCount, cGrow);
1691 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1693 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1697 GetIconInfo (handle, &ii);
1698 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1699 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1700 ILC_MASK | ILC_COLOR, 1, cGrow);
1701 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1702 DeleteObject (ii.hbmColor);
1703 DeleteObject (ii.hbmMask);
1706 DeleteObject (handle);
1712 /*************************************************************************
1713 * ImageList_LoadImageW [COMCTL32.64]
1715 * Creates an image list from a bitmap, icon or cursor.
1718 * hi [I] instance handle
1719 * lpbmp [I] name or id of the image
1720 * cx [I] width of each image
1721 * cGrow [I] number of images to expand
1722 * clrMask [I] mask color
1723 * uType [I] type of image to load
1724 * uFlags [I] loading flags
1727 * Success: handle to the loaded image list
1735 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1736 COLORREF clrMask, UINT uType, UINT uFlags)
1738 HIMAGELIST himl = NULL;
1742 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1744 ERR("Error loading image!\n");
1748 if (uType == IMAGE_BITMAP) {
1750 GetObjectA (handle, sizeof(BITMAP), &bmp);
1751 nImageCount = bmp.bmWidth / cx;
1753 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1754 nImageCount, cGrow);
1755 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1757 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1761 GetIconInfo (handle, &ii);
1762 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1763 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1764 ILC_MASK | ILC_COLOR, 1, cGrow);
1765 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1766 DeleteObject (ii.hbmColor);
1767 DeleteObject (ii.hbmMask);
1770 DeleteObject (handle);
1776 /*************************************************************************
1777 * ImageList_Merge [COMCTL32.65]
1779 * Creates a new image list that contains a merged image from the specified
1780 * images of both source image lists.
1783 * himl1 [I] handle to first image list
1784 * i1 [I] first image index
1785 * himl2 [I] handle to second image list
1786 * i2 [I] second image index
1787 * dx [I] X offset of the second image relative to the first.
1788 * dy [I] Y offset of the second image relative to the first.
1791 * Success: handle of the merged image list.
1796 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1799 HIMAGELIST himlDst = NULL;
1800 HDC hdcSrcImage, hdcDstImage;
1802 INT xOff1, yOff1, xOff2, yOff2;
1805 if ((himl1 == NULL) || (himl2 == NULL))
1809 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1810 ERR("Index 1 out of range! %d\n", i1);
1814 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1815 ERR("Index 2 out of range! %d\n", i2);
1820 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1825 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1830 cxDst = _MAX (himl1->cx, himl2->cx);
1836 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1841 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1846 cyDst = _MAX (himl1->cy, himl2->cy);
1851 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1854 hdcSrcImage = CreateCompatibleDC (0);
1855 hdcDstImage = CreateCompatibleDC (0);
1856 nX1 = i1 * himl1->cx;
1857 nX2 = i2 * himl2->cx;
1860 SelectObject (hdcSrcImage, himl1->hbmImage);
1861 SelectObject (hdcDstImage, himlDst->hbmImage);
1862 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1863 hdcSrcImage, 0, 0, BLACKNESS);
1864 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1865 hdcSrcImage, nX1, 0, SRCCOPY);
1867 SelectObject (hdcSrcImage, himl2->hbmMask);
1868 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1869 hdcSrcImage, nX2, 0, SRCAND);
1871 SelectObject (hdcSrcImage, himl2->hbmImage);
1872 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1873 hdcSrcImage, nX2, 0, SRCPAINT);
1876 SelectObject (hdcSrcImage, himl1->hbmMask);
1877 SelectObject (hdcDstImage, himlDst->hbmMask);
1878 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1879 hdcSrcImage, 0, 0, WHITENESS);
1880 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1881 hdcSrcImage, nX1, 0, SRCCOPY);
1883 SelectObject (hdcSrcImage, himl2->hbmMask);
1884 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1885 hdcSrcImage, nX2, 0, SRCAND);
1887 DeleteDC (hdcSrcImage);
1888 DeleteDC (hdcDstImage);
1895 /* helper for _read_bitmap currently unused */
1897 static int may_use_dibsection(HDC hdc) {
1898 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1903 return GetDeviceCaps(hdc,94) & 0x10;
1907 /* helper for ImageList_Read, see comments below */
1908 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1910 BITMAPFILEHEADER bmfh;
1911 BITMAPINFOHEADER bmih;
1912 int bitsperpixel,palspace,longsperline,width,height;
1913 LPBITMAPINFOHEADER bmihc = NULL;
1915 HBITMAP hbitmap = 0;
1916 LPBYTE bits = NULL,nbits = NULL;
1917 int nbytesperline,bytesperline;
1919 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1920 (bmfh.bfType != (('M'<<8)|'B')) ||
1921 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1922 (bmih.biSize != sizeof(bmih))
1926 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1927 if (bitsperpixel<=8)
1928 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1931 width = bmih.biWidth;
1932 height = bmih.biHeight;
1933 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1934 memcpy(bmihc,&bmih,sizeof(bmih));
1935 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1936 bmihc->biSizeImage = (longsperline*height)<<2;
1938 /* read the palette right after the end of the bitmapinfoheader */
1940 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1944 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1945 if ((bitsperpixel>1) &&
1946 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1948 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1951 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1957 int i,nwidth,nheight;
1959 nwidth = width*(height/cy);
1962 if (bitsperpixel==1)
1963 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1965 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1967 /* Might be a bit excessive memory use here */
1968 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1969 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1970 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1973 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1974 /* Do not forget that windows bitmaps are bottom->top */
1975 bytesperline = longsperline*4;
1976 nbytesperline = (height/cy)*bytesperline;
1977 for (i=0;i<height;i++) {
1979 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1980 bits+bytesperline*(height-1-i),
1984 bmihc->biWidth = nwidth;
1985 bmihc->biHeight = nheight;
1986 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1988 LocalFree((HLOCAL)nbits);
1989 LocalFree((HLOCAL)bits);
1993 if (xdc) ReleaseDC(0,xdc);
1994 if (bmihc) LocalFree((HLOCAL)bmihc);
1997 DeleteObject(hbitmap);
2004 /*************************************************************************
2005 * ImageList_Read [COMCTL32.66]
2007 * Reads an image list from a stream.
2010 * pstm [I] pointer to a stream
2013 * Success: handle to image list
2016 * The format is like this:
2017 * ILHEAD ilheadstruct;
2019 * for the color image part:
2020 * BITMAPFILEHEADER bmfh;
2021 * BITMAPINFOHEADER bmih;
2022 * only if it has a palette:
2023 * RGBQUAD rgbs[nr_of_paletted_colors];
2025 * BYTE colorbits[imagesize];
2027 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2028 * BITMAPFILEHEADER bmfh_mask;
2029 * BITMAPINFOHEADER bmih_mask;
2030 * only if it has a palette (it usually does not):
2031 * RGBQUAD rgbs[nr_of_paletted_colors];
2033 * BYTE maskbits[imagesize];
2035 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2036 * _read_bitmap needs to convert them.
2038 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2042 HBITMAP hbmColor=0,hbmMask=0;
2045 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2047 if (ilHead.usMagic != (('L' << 8) | 'I'))
2049 if (ilHead.usVersion != 0x101) /* probably version? */
2053 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2054 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2055 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2056 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2057 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2058 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2059 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2060 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2061 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2062 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2065 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2068 if (ilHead.flags & ILC_MASK) {
2069 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2071 DeleteObject(hbmColor);
2076 himl = ImageList_Create (
2084 DeleteObject(hbmColor);
2085 DeleteObject(hbmMask);
2088 himl->hbmImage = hbmColor;
2089 himl->hbmMask = hbmMask;
2090 himl->cCurImage = ilHead.cCurImage;
2091 himl->cMaxImage = ilHead.cMaxImage;
2093 ImageList_SetBkColor(himl,ilHead.bkcolor);
2095 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2100 /*************************************************************************
2101 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2104 * himl [I] image list handle
2113 ImageList_Remove (HIMAGELIST himl, INT i)
2115 HBITMAP hbmNewImage, hbmNewMask;
2119 if ((i < -1) || (i >= himl->cCurImage)) {
2120 ERR("index out of range! %d\n", i);
2124 if (himl->cCurImage == 0) {
2125 ERR("image list is already empty!\n");
2131 TRACE("remove all!\n");
2133 himl->cMaxImage = himl->cInitial + himl->cGrow;
2134 himl->cCurImage = 0;
2135 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2136 himl->nOvlIdx[nCount] = -1;
2138 DeleteObject (himl->hbmImage);
2140 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2141 1, himl->uBitsPixel, NULL);
2143 if (himl->hbmMask) {
2144 DeleteObject (himl->hbmMask);
2146 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2151 /* delete one image */
2152 TRACE("Remove single image! %d\n", i);
2154 /* create new bitmap(s) */
2155 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2157 TRACE(" - Number of images: %d / %d (Old/New)\n",
2158 himl->cCurImage, himl->cCurImage - 1);
2159 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2160 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2163 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2166 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2168 hbmNewMask = 0; /* Just to keep compiler happy! */
2170 hdcSrc = CreateCompatibleDC (0);
2171 hdcDst = CreateCompatibleDC (0);
2173 /* copy all images and masks prior to the "removed" image */
2175 TRACE("Pre image copy: Copy %d images\n", i);
2177 SelectObject (hdcSrc, himl->hbmImage);
2178 SelectObject (hdcDst, hbmNewImage);
2179 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2180 hdcSrc, 0, 0, SRCCOPY);
2182 if (himl->hbmMask) {
2183 SelectObject (hdcSrc, himl->hbmMask);
2184 SelectObject (hdcDst, hbmNewMask);
2185 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2186 hdcSrc, 0, 0, SRCCOPY);
2190 /* copy all images and masks behind the removed image */
2191 if (i < himl->cCurImage - 1) {
2192 TRACE("Post image copy!\n");
2193 SelectObject (hdcSrc, himl->hbmImage);
2194 SelectObject (hdcDst, hbmNewImage);
2195 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2196 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2198 if (himl->hbmMask) {
2199 SelectObject (hdcSrc, himl->hbmMask);
2200 SelectObject (hdcDst, hbmNewMask);
2201 BitBlt (hdcDst, i * himl->cx, 0,
2202 (himl->cCurImage - i - 1) * himl->cx,
2203 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2210 /* delete old images and insert new ones */
2211 DeleteObject (himl->hbmImage);
2212 himl->hbmImage = hbmNewImage;
2213 if (himl->hbmMask) {
2214 DeleteObject (himl->hbmMask);
2215 himl->hbmMask = hbmNewMask;
2219 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2226 /*************************************************************************
2227 * ImageList_Replace [COMCTL32.68]
2229 * Replaces an image in an image list with a new image.
2232 * himl [I] handle to image list
2234 * hbmImage [I] handle to image bitmap
2235 * hbmMask [I] handle to mask bitmap. Can be NULL.
2243 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2246 HDC hdcImageList, hdcImage;
2250 ERR("Invalid image list handle!\n");
2254 if ((i >= himl->cCurImage) || (i < 0)) {
2255 ERR("Invalid image index!\n");
2259 hdcImageList = CreateCompatibleDC (0);
2260 hdcImage = CreateCompatibleDC (0);
2261 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2264 SelectObject (hdcImageList, himl->hbmImage);
2265 SelectObject (hdcImage, hbmImage);
2267 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2268 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2273 SelectObject (hdcImageList, himl->hbmMask);
2274 SelectObject (hdcImage, hbmMask);
2276 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2277 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2280 /* Remove the background from the image
2282 SelectObject (hdcImageList, himl->hbmImage);
2283 StretchBlt (hdcImageList,
2284 i*himl->cx, 0, himl->cx, himl->cy,
2286 0, 0, bmp.bmWidth, bmp.bmHeight,
2287 0x220326); /* NOTSRCAND */
2290 DeleteDC (hdcImage);
2291 DeleteDC (hdcImageList);
2297 /*************************************************************************
2298 * ImageList_ReplaceIcon [COMCTL32.69]
2300 * Replaces an image in an image list using an icon.
2303 * himl [I] handle to image list
2305 * hIcon [I] handle to icon
2308 * Success: index of the replaced image
2313 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2315 HDC hdcImageList, hdcImage;
2318 HBITMAP hbmOldSrc, hbmOldDst;
2322 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2326 if ((i >= himl->cCurImage) || (i < -1))
2329 hBestFitIcon = CopyImage(
2332 LR_COPYFROMRESOURCE);
2334 GetIconInfo (hBestFitIcon, &ii);
2335 if (ii.hbmMask == 0)
2337 if (ii.hbmColor == 0)
2339 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2342 if (himl->cCurImage + 1 >= himl->cMaxImage)
2343 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2345 nIndex = himl->cCurImage;
2351 hdcImageList = CreateCompatibleDC (0);
2352 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2353 if (hdcImageList == 0)
2354 ERR("invalid hdcImageList!\n");
2356 hdcImage = CreateCompatibleDC (0);
2357 TRACE("hdcImage=0x%x!\n", hdcImage);
2359 ERR("invalid hdcImage!\n");
2361 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2362 SetTextColor( hdcImageList, RGB(0,0,0));
2363 SetBkColor( hdcImageList, RGB(255,255,255));
2364 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2365 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2366 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2368 if (himl->hbmMask) {
2369 SelectObject (hdcImageList, himl->hbmMask);
2370 SelectObject (hdcImage, ii.hbmMask);
2371 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2372 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2375 SelectObject (hdcImage, hbmOldSrc);
2376 SelectObject (hdcImageList, hbmOldDst);
2379 DestroyIcon(hBestFitIcon);
2381 DeleteDC (hdcImageList);
2383 DeleteDC (hdcImage);
2385 DeleteObject (ii.hbmColor);
2387 DeleteObject (ii.hbmMask);
2393 /*************************************************************************
2394 * ImageList_SetBkColor [COMCTL32.70]
2396 * Sets the background color of an image list.
2399 * himl [I] handle to image list
2400 * clrBk [I] background color
2403 * Success: previous background color
2408 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2415 clrOldBk = himl->clrBk;
2416 himl->clrBk = clrBk;
2421 /*************************************************************************
2422 * ImageList_SetDragCursorImage [COMCTL32.75]
2424 * Combines the specified image with the current drag image
2427 * himlDrag [I] handle to drag image list
2428 * iDrag [I] drag image index
2429 * dxHotspot [I] X position of the hot spot
2430 * dyHotspot [I] Y position of the hot spot
2441 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2442 INT dxHotspot, INT dyHotspot)
2444 HIMAGELIST himlTemp;
2446 FIXME("semi-stub!\n");
2448 if (himlInternalDrag == NULL)
2451 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2452 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2454 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2455 dxHotspot, dyHotspot);
2457 ImageList_Destroy (himlInternalDrag);
2458 himlInternalDrag = himlTemp;
2460 nInternalDragHotspotX = dxHotspot;
2461 nInternalDragHotspotY = dyHotspot;
2467 /*************************************************************************
2468 * ImageList_SetFilter [COMCTL32.76]
2470 * Sets a filter (or does something completely different)!!???
2473 * himl [I] handle to image list
2479 * Failure: FALSE ???
2482 * This is an UNDOCUMENTED function!!!!
2487 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2489 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2496 /*************************************************************************
2497 * ImageList_SetIconSize [COMCTL32.77]
2499 * Sets the image size of the bitmap and deletes all images.
2502 * himl [I] handle to image list
2503 * cx [I] image width
2504 * cy [I] image height
2512 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2519 /* remove all images*/
2520 himl->cMaxImage = himl->cInitial + himl->cGrow;
2521 himl->cCurImage = 0;
2525 /* initialize overlay mask indices */
2526 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2527 himl->nOvlIdx[nCount] = -1;
2529 DeleteObject (himl->hbmImage);
2531 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2532 1, himl->uBitsPixel, NULL);
2534 if (himl->hbmMask) {
2535 DeleteObject (himl->hbmMask);
2537 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2545 /*************************************************************************
2546 * ImageList_SetImageCount [COMCTL32.78]
2548 * Resizes an image list to the specified number of images.
2551 * himl [I] handle to image list
2552 * iImageCount [I] number of images in the image list
2560 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2562 HDC hdcImageList, hdcBitmap;
2563 HBITMAP hbmNewBitmap;
2564 INT nNewCount, nCopyCount;
2568 if (himl->cCurImage >= iImageCount)
2570 if (himl->cMaxImage > iImageCount)
2573 nNewCount = iImageCount + himl->cGrow;
2574 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2576 hdcImageList = CreateCompatibleDC (0);
2577 hdcBitmap = CreateCompatibleDC (0);
2579 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2580 1, himl->uBitsPixel, NULL);
2581 if (hbmNewBitmap != 0)
2583 SelectObject (hdcImageList, himl->hbmImage);
2584 SelectObject (hdcBitmap, hbmNewBitmap);
2587 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2588 hdcImageList, 0, 0, SRCCOPY);
2590 /* delete 'empty' image space */
2591 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2592 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2593 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2594 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2596 DeleteObject (himl->hbmImage);
2597 himl->hbmImage = hbmNewBitmap;
2600 ERR("Could not create new image bitmap !\n");
2604 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2606 if (hbmNewBitmap != 0)
2608 SelectObject (hdcImageList, himl->hbmMask);
2609 SelectObject (hdcBitmap, hbmNewBitmap);
2612 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2613 hdcImageList, 0, 0, SRCCOPY);
2615 /* delete 'empty' image space */
2616 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2617 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2618 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2619 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2621 DeleteObject (himl->hbmMask);
2622 himl->hbmMask = hbmNewBitmap;
2625 ERR("Could not create new mask bitmap!\n");
2628 DeleteDC (hdcImageList);
2629 DeleteDC (hdcBitmap);
2631 /* Update max image count and current image count */
2632 himl->cMaxImage = nNewCount;
2633 if (himl->cCurImage > nCopyCount)
2634 himl->cCurImage = nCopyCount;
2640 /*************************************************************************
2641 * ImageList_SetOverlayImage [COMCTL32.79]
2643 * Assigns an overlay mask index to an existing image in an image list.
2646 * himl [I] handle to image list
2647 * iImage [I] image index
2648 * iOverlay [I] overlay mask index
2656 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2660 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2662 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2664 himl->nOvlIdx[iOverlay - 1] = iImage;
2669 /*************************************************************************
2670 * ImageList_Write [COMCTL32.80]
2672 * Writes an image list to a stream.
2675 * himl [I] handle to image list
2676 * pstm [O] Pointer to a stream.
2683 * This function can not be implemented yet, because
2684 * IStream32::Write is not implemented.
2691 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2696 FIXME("empty stub!\n");