2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
6 * 2001 Michael Stefaniuc
7 * 2001 Charles Loep for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * - Fix ImageList_DrawIndirect (dwRop).
25 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
26 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
29 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
30 * is the offset of the image position relative to the actual mouse pointer
31 * position. However the Hotspot passed to SetDragCursorImage is the
32 * offset of the mouse messages sent to the application...
39 #include "wine/obj_base.h"
40 #include "wine/obj_storage.h"
42 #include "imagelist.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
48 #define MAX_OVERLAYIMAGE 15
50 /* internal image list data used for Drag & Drop operations */
55 /* position of the drag image relative to the window */
58 /* offset of the hotspot relative to the origin of the image */
61 /* is the drag image visible */
63 /* saved background */
68 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
72 /*************************************************************************
73 * IMAGELIST_InternalExpandBitmaps [Internal]
75 * Expands the bitmaps of an image list by the given number of images.
78 * himl [I] handle to image list
79 * nImageCount [I] number of images to add
85 * This function can NOT be used to reduce the number of images.
88 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
90 HDC hdcImageList, hdcBitmap;
92 INT nNewWidth, nNewCount;
94 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
98 if (cy == 0) cy = himl->cy;
99 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
100 nNewWidth = nNewCount * himl->cx;
102 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
103 hdcImageList = CreateCompatibleDC (0);
104 hdcBitmap = CreateCompatibleDC (0);
107 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
108 if (hbmNewBitmap == 0)
109 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
111 SelectObject (hdcImageList, himl->hbmImage);
112 SelectObject (hdcBitmap, hbmNewBitmap);
113 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
114 hdcImageList, 0, 0, SRCCOPY);
116 DeleteObject (himl->hbmImage);
117 himl->hbmImage = hbmNewBitmap;
121 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
123 if (hbmNewBitmap == 0)
124 ERR("creating new mask bitmap!\n");
126 SelectObject (hdcImageList, himl->hbmMask);
127 SelectObject (hdcBitmap, hbmNewBitmap);
128 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
129 hdcImageList, 0, 0, SRCCOPY);
130 DeleteObject (himl->hbmMask);
131 himl->hbmMask = hbmNewBitmap;
134 himl->cMaxImage = nNewCount;
136 DeleteDC (hdcImageList);
137 DeleteDC (hdcBitmap);
141 /*************************************************************************
142 * IMAGELIST_InternalDraw [Internal]
144 * Draws the image in the ImageList (without the mask)
147 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
148 * cx [I] the width of the image to display
149 * cy [I] the height of the image to display
155 * This function is used by ImageList_DrawIndirect, when it is
156 * required to draw only the Image (without the mask) to the screen.
158 * Blending and Overlays styles are accomplished by another function
161 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
166 hImageDC = CreateCompatibleDC(0);
167 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
168 BitBlt(pimldp->hdcDst,
169 pimldp->x, pimldp->y, cx, cy,
171 pimldp->himl->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
174 SelectObject(hImageDC, hOldBitmap);
179 /*************************************************************************
180 * IMAGELIST_InternalDrawMask [Internal]
182 * Draws the image in the ImageList with the mask
185 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
186 * cx [I] the width of the image to display
187 * cy [I] the height of the image to display
193 * This function is used by ImageList_DrawIndirect, when it is
194 * required to draw the Image with the mask to the screen.
196 * Blending and Overlays styles are accomplished by another function.
199 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
201 HBITMAP hOldBitmapImage, hOldBitmapMask;
202 HIMAGELIST himlLocal = pimldp->himl;
203 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
204 COLORREF clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himlLocal->clrBk : pimldp->rgbBk;
207 * We need a dc and bitmap to draw on that is
210 HDC hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
211 HBITMAP hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
213 BOOL bUseCustomBackground = (clrBk != CLR_NONE) &&
214 !((fStyle & ILD_TRANSPARENT) && himlLocal->hbmMask);
215 BOOL bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
217 HDC hImageDC = CreateCompatibleDC(0);
218 HDC hMaskDC = CreateCompatibleDC(0);
220 /* Create a compatible DC. */
221 if (!hOffScreenDC || !hOffScreenBmp || !hImageDC || !hMaskDC) goto cleanup;
222 SelectObject( hOffScreenDC, hOffScreenBmp );
224 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
225 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
228 * Get a copy of the image for the masking operations.
229 * We will use the copy, and this dc for all the various
230 * blitting, and then do one final blit to the screen dc.
231 * This should clean up most of the flickering.
233 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
237 * Draw the Background for the appropriate Styles
239 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
243 HBRUSH hBrush = CreateSolidBrush (clrBk);
244 HBRUSH hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
246 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
248 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
252 * Draw Image Transparently over the current background
254 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
255 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
257 * To obtain a transparent look, background color should be set
258 * to white and foreground color to black when blting the
262 COLORREF oldBk = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
263 COLORREF oldFg = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
265 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC,
266 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
269 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
270 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
273 SetBkColor( hOffScreenDC, oldBk);
274 SetBkColor( hOffScreenDC, oldFg);
278 * Draw the image when no Background is specified
280 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
282 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
283 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
287 * Draw the mask with or without a background
289 else if(fStyle & ILD_MASK)
291 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC,
292 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
293 bUseCustomBackground ? SRCCOPY : SRCAND);
297 * Blit the bitmap to the screen now.
299 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
300 hOffScreenDC, 0, 0, SRCCOPY);
303 SelectObject(hImageDC, hOldBitmapImage);
304 SelectObject(hMaskDC, hOldBitmapMask);
311 DeleteDC( hOffScreenDC );
312 DeleteObject( hOffScreenBmp );
315 /*************************************************************************
316 * IMAGELIST_InternalDrawBlend [Internal]
318 * Draws the Blend over the current image
321 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
322 * cx [I] the width of the image to display
323 * cy [I] the height of the image to display
329 * This functions is used by ImageList_DrawIndirect, when it is
330 * required to add the blend to the current image.
334 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
338 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
339 HBITMAP hBlendMaskBitmap, hOldBitmap;
340 COLORREF clrBlend, oldFgColor, oldBkColor;
341 HIMAGELIST himlLocal = pimldp->himl;
343 clrBlend = pimldp->rgbFg;
344 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
345 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
347 /* Create the blend Mask
349 hBlendMaskDC = CreateCompatibleDC(0);
350 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
351 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
353 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
354 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
356 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
357 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
358 SelectObject(hBlendMaskDC, hOldBrush);
360 /* Modify the blend mask if an Image Mask exist
362 if(pimldp->himl->hbmMask != 0)
364 HBITMAP hOldMaskBitmap;
365 HDC hMaskDC = CreateCompatibleDC(0);
366 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
368 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskDC,
369 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
370 0x220326); /* NOTSRCAND */
372 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC,
376 SelectObject(hMaskDC, hOldMaskBitmap);
380 /* Apply blend to the current image given the BlendMask
382 oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 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, oldFgColor);
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)) return;
431 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
432 if ((nOvlIdx < 0) || (nOvlIdx > pimldp->himl->cCurImage)) return;
434 if (!(hImageDC = CreateCompatibleDC(0))) return;
436 if (pimldp->himl->hbmMask) {
437 hOldBitmap = (HBITMAP) SelectObject (hImageDC, pimldp->himl->hbmMask);
439 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC,
440 pimldp->himl->cx * nOvlIdx + pimldp->xBitmap, pimldp->yBitmap,
443 SelectObject(hImageDC, hOldBitmap);
446 hOldBitmap = (HBITMAP) SelectObject (hImageDC, pimldp->himl->hbmImage);
448 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC,
449 pimldp->himl->cx * nOvlIdx + pimldp->xBitmap, pimldp->yBitmap,
452 SelectObject(hImageDC, hOldBitmap);
457 /*************************************************************************
458 * ImageList_Add [COMCTL32.@]
460 * Add an image or images to an image list.
463 * himl [I] handle to image list
464 * hbmImage [I] handle to image bitmap
465 * hbmMask [I] handle to mask bitmap
468 * Success: Index of the first new image.
473 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
475 HDC hdcImage, hdcBitmap;
476 INT nFirstIndex, nImageCount;
479 HBITMAP hOldBitmapImage, hOldBitmap;
481 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
482 if (!himl || !hbmImage)
485 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
486 nImageCount = bmp.bmWidth / himl->cx;
488 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
490 nStartX = himl->cCurImage * himl->cx;
492 hdcImage = CreateCompatibleDC(0);
493 hdcBitmap = CreateCompatibleDC(0);
495 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
496 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
498 /* Copy result to the imagelist
500 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
501 hdcBitmap, 0, 0, SRCCOPY);
505 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
507 hdcMask = CreateCompatibleDC (0);
508 hdcTemp = CreateCompatibleDC(0);
509 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
510 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
513 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
518 SelectObject(hdcTemp, hOldBitmapTemp);
521 /* Remove the background from the image
524 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
527 0x220326); /* NOTSRCAND */
529 SelectObject(hdcMask, hOldBitmapMask);
533 SelectObject(hdcImage, hOldBitmapImage);
534 SelectObject(hdcBitmap, hOldBitmap);
538 nFirstIndex = himl->cCurImage;
539 himl->cCurImage += nImageCount;
545 /*************************************************************************
546 * ImageList_AddIcon [COMCTL32.@]
548 * Adds an icon to an image list.
551 * himl [I] handle to image list
552 * hIcon [I] handle to icon
555 * Success: index of the new image
560 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
562 return ImageList_ReplaceIcon (himl, -1, hIcon);
566 /*************************************************************************
567 * ImageList_AddMasked [COMCTL32.@]
569 * Adds an image or images to an image list and creates a mask from the
570 * specified bitmap using the mask color.
573 * himl [I] handle to image list.
574 * hBitmap [I] handle to bitmap
575 * clrMask [I] mask color.
578 * Success: Index of the first new image.
583 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
585 HDC hdcImage, hdcMask, hdcBitmap;
586 INT nIndex, nImageCount, nMaskXOffset=0;
588 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
589 HBITMAP hMaskBitmap=0;
592 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
596 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
599 nImageCount = bmp.bmWidth / himl->cx;
601 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
603 nIndex = himl->cCurImage;
604 himl->cCurImage += nImageCount;
606 hdcMask = CreateCompatibleDC (0);
607 hdcImage = CreateCompatibleDC(0);
608 hdcBitmap = CreateCompatibleDC(0);
611 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
612 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
615 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
616 nMaskXOffset = nIndex * himl->cx;
621 Create a temp Mask so we can remove the background of
622 the Image (Windows does this even if there is no mask)
624 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
625 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
628 /* create monochrome image to the mask bitmap */
629 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
630 GetPixel (hdcBitmap, 0, 0);
631 SetBkColor (hdcBitmap, bkColor);
633 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
637 SetBkColor(hdcBitmap, RGB(255,255,255));
638 /*Remove the background from the image
641 WINDOWS BUG ALERT!!!!!!
642 The statement below should not be done in common practice
643 but this is how ImageList_AddMasked works in Windows.
644 It overwrites the original bitmap passed, this was discovered
645 by using the same bitmap to iterate the different styles
646 on windows where it failed (BUT ImageList_Add is OK)
647 This is here in case some apps rely on this bug
650 0, 0, bmp.bmWidth, bmp.bmHeight,
653 0x220326); /* NOTSRCAND */
654 /* Copy result to the imagelist
657 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
663 SelectObject(hdcMask,hOldBitmapMask);
664 SelectObject(hdcImage, hOldBitmapImage);
665 SelectObject(hdcBitmap, hOldBitmap);
671 DeleteObject(hMaskBitmap);
678 /*************************************************************************
679 * ImageList_BeginDrag [COMCTL32.@]
681 * Creates a temporary image list that contains one image. It will be used
685 * himlTrack [I] handle to the source image list
686 * iTrack [I] index of the drag image in the source image list
687 * dxHotspot [I] X position of the hot spot of the drag image
688 * dyHotspot [I] Y position of the hot spot of the drag image
696 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
697 INT dxHotspot, INT dyHotspot)
702 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
703 dxHotspot, dyHotspot);
705 if (himlTrack == NULL)
708 if (InternalDrag.himl)
709 ImageList_EndDrag ();
714 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
715 if (InternalDrag.himl == NULL) {
716 WARN("Error creating drag image list!\n");
720 InternalDrag.dxHotspot = dxHotspot;
721 InternalDrag.dyHotspot = dyHotspot;
723 hdcSrc = CreateCompatibleDC (0);
724 hdcDst = CreateCompatibleDC (0);
727 SelectObject (hdcSrc, himlTrack->hbmImage);
728 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
729 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
732 SelectObject (hdcSrc, himlTrack->hbmMask);
733 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
734 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
739 InternalDrag.himl->cCurImage = 1;
740 InternalDrag.bHSPending = TRUE;
746 /*************************************************************************
747 * ImageList_Copy [COMCTL32.@]
749 * Copies an image of the source image list to an image of the
750 * destination image list. Images can be copied or swapped.
753 * himlDst [I] handle to the destination image list
754 * iDst [I] destination image index.
755 * himlSrc [I] handle to the source image list
756 * iSrc [I] source image index
757 * uFlags [I] flags for the copy operation
764 * Copying from one image list to another is possible. The original
765 * implementation just copies or swaps within one image list.
766 * Could this feature become a bug??? ;-)
770 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
771 INT iSrc, INT uFlags)
775 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
777 if ((himlSrc == NULL) || (himlDst == NULL))
779 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
781 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
784 hdcSrc = CreateCompatibleDC (0);
785 if (himlDst == himlSrc)
788 hdcDst = CreateCompatibleDC (0);
790 if (uFlags & ILCF_SWAP) {
792 HBITMAP hbmTempImage, hbmTempMask;
794 /* create temporary bitmaps */
795 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
796 himlSrc->uBitsPixel, NULL);
797 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
800 /* copy (and stretch) destination to temporary bitmaps.(save) */
802 SelectObject (hdcSrc, himlDst->hbmImage);
803 SelectObject (hdcDst, hbmTempImage);
804 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
805 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
808 SelectObject (hdcSrc, himlDst->hbmMask);
809 SelectObject (hdcDst, hbmTempMask);
810 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
811 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
814 /* copy (and stretch) source to destination */
816 SelectObject (hdcSrc, himlSrc->hbmImage);
817 SelectObject (hdcDst, himlDst->hbmImage);
818 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
819 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
822 SelectObject (hdcSrc, himlSrc->hbmMask);
823 SelectObject (hdcDst, himlDst->hbmMask);
824 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
825 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
828 /* copy (without stretching) temporary bitmaps to source (restore) */
830 SelectObject (hdcSrc, hbmTempImage);
831 SelectObject (hdcDst, himlSrc->hbmImage);
832 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
833 hdcSrc, 0, 0, SRCCOPY);
835 SelectObject (hdcSrc, hbmTempMask);
836 SelectObject (hdcDst, himlSrc->hbmMask);
837 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
838 hdcSrc, 0, 0, SRCCOPY);
840 /* delete temporary bitmaps */
841 DeleteObject (hbmTempMask);
842 DeleteObject (hbmTempImage);
846 SelectObject (hdcSrc, himlSrc->hbmImage);
847 if (himlSrc == himlDst)
850 SelectObject (hdcDst, himlDst->hbmImage);
851 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
852 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
856 SelectObject (hdcSrc, himlSrc->hbmMask);
857 if (himlSrc == himlDst)
860 SelectObject (hdcDst, himlDst->hbmMask);
861 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
862 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
867 if (himlSrc != himlDst)
874 /*************************************************************************
875 * ImageList_Create [COMCTL32.@] Creates a new image list.
878 * cx [I] image height
880 * flags [I] creation flags
881 * cInitial [I] initial number of images in the image list
882 * cGrow [I] number of images by which image list grows
885 * Success: Handle to the created image list
890 ImageList_Create (INT cx, INT cy, UINT flags,
891 INT cInitial, INT cGrow)
897 static WORD aBitBlend25[] =
898 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
900 static WORD aBitBlend50[] =
901 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
903 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
905 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
912 himl->cMaxImage = cInitial + cGrow;
913 himl->cInitial = cInitial;
916 himl->clrFg = CLR_DEFAULT;
917 himl->clrBk = CLR_NONE;
919 /* initialize overlay mask indices */
920 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
921 himl->nOvlIdx[nCount] = -1;
923 hdc = CreateCompatibleDC (0);
924 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
927 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
929 if (himl->cMaxImage > 0) {
931 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
932 1, himl->uBitsPixel, NULL);
933 if (himl->hbmImage == 0) {
934 ERR("Error creating image bitmap!\n");
941 if ( (himl->flags & ILC_MASK)) {
942 int images = himl->cMaxImage;
946 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
948 if (himl->hbmMask == 0) {
949 ERR("Error creating mask bitmap!\n");
951 DeleteObject (himl->hbmImage);
958 /* create blending brushes */
959 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
960 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
961 DeleteObject (hbmTemp);
963 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
964 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
965 DeleteObject (hbmTemp);
967 TRACE("created imagelist %p\n", himl);
972 /*************************************************************************
973 * ImageList_Destroy [COMCTL32.@]
975 * Destroys an image list.
978 * himl [I] handle to image list
986 ImageList_Destroy (HIMAGELIST himl)
991 /* delete image bitmaps */
993 DeleteObject (himl->hbmImage);
995 DeleteObject (himl->hbmMask);
997 /* delete blending brushes */
998 if (himl->hbrBlend25)
999 DeleteObject (himl->hbrBlend25);
1000 if (himl->hbrBlend50)
1001 DeleteObject (himl->hbrBlend50);
1003 COMCTL32_Free (himl);
1009 /*************************************************************************
1010 * ImageList_DragEnter [COMCTL32.@]
1012 * Locks window update and displays the drag image at the given position.
1015 * hwndLock [I] handle of the window that owns the drag image.
1016 * x [I] X position of the drag image.
1017 * y [I] Y position of the drag image.
1024 * The position of the drag image is relative to the window, not
1029 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1031 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1033 if (InternalDrag.himl == NULL)
1037 InternalDrag.hwnd = hwndLock;
1039 InternalDrag.hwnd = GetDesktopWindow ();
1044 /* draw the drag image and save the background */
1045 if (!ImageList_DragShowNolock(TRUE)) {
1053 /*************************************************************************
1054 * ImageList_DragLeave [COMCTL32.@]
1056 * Unlocks window update and hides the drag image.
1059 * hwndLock [I] handle of the window that owns the drag image.
1067 ImageList_DragLeave (HWND hwndLock)
1069 /* As we don't save drag info in the window this can lead to problems if
1070 an app does not supply the same window as DragEnter */
1072 InternalDrag.hwnd = hwndLock;
1074 InternalDrag.hwnd = GetDesktopWindow (); */
1076 hwndLock = GetDesktopWindow();
1077 if(InternalDrag.hwnd != hwndLock)
1078 FIXME("DragLeave hWnd != DragEnter hWnd\n");
1080 ImageList_DragShowNolock (FALSE);
1086 /*************************************************************************
1087 * ImageList_DragMove [COMCTL32.@]
1089 * Moves the drag image.
1092 * x [I] X position of the drag image.
1093 * y [I] Y position of the drag image.
1100 * The position of the drag image is relative to the window, not
1104 * The drag image should be drawn semitransparent.
1108 ImageList_DragMove (INT x, INT y)
1110 TRACE("(x=%d y=%d)\n", x, y);
1112 if (!InternalDrag.himl) {
1116 /* draw/update the drag image */
1117 if (InternalDrag.bShow) {
1121 HBITMAP hbmOffScreen;
1122 INT origNewX, origNewY;
1123 INT origOldX, origOldY;
1124 INT origRegX, origRegY;
1125 INT sizeRegX, sizeRegY;
1128 /* calculate the update region */
1129 origNewX = x - InternalDrag.dxHotspot;
1130 origNewY = y - InternalDrag.dyHotspot;
1131 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1132 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1133 origRegX = min(origNewX, origOldX);
1134 origRegY = min(origNewY, origOldY);
1135 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1136 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1138 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1139 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1140 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1141 hdcBg = CreateCompatibleDC(hdcDrag);
1143 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1144 SelectObject(hdcOffScreen, hbmOffScreen);
1145 SelectObject(hdcBg, InternalDrag.hbmBg);
1147 /* get the actual background of the update region */
1148 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1149 origRegX, origRegY, SRCCOPY);
1150 /* erase the old image */
1151 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1152 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1154 /* save the background */
1155 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1156 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1157 /* draw the image */
1158 /* FIXME: image should be drawn semitransparent */
1159 ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1160 origNewY - origRegY, ILD_NORMAL);
1161 /* draw the update region to the screen */
1162 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1163 hdcOffScreen, 0, 0, SRCCOPY);
1166 DeleteDC(hdcOffScreen);
1167 DeleteObject(hbmOffScreen);
1168 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1171 /* update the image position */
1179 /*************************************************************************
1180 * ImageList_DragShowNolock [COMCTL32.@]
1182 * Shows or hides the drag image.
1185 * bShow [I] TRUE shows the drag image, FALSE hides it.
1192 * The drag image should be drawn semitransparent.
1196 ImageList_DragShowNolock (BOOL bShow)
1202 TRACE("bShow=0x%X!\n", bShow);
1204 /* DragImage is already visible/hidden */
1205 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1209 /* position of the origin of the DragImage */
1210 x = InternalDrag.x - InternalDrag.dxHotspot;
1211 y = InternalDrag.y - InternalDrag.dyHotspot;
1213 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1214 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1219 hdcBg = CreateCompatibleDC(hdcDrag);
1220 if (!InternalDrag.hbmBg) {
1221 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1222 InternalDrag.himl->cx, InternalDrag.himl->cy);
1224 SelectObject(hdcBg, InternalDrag.hbmBg);
1227 /* save the background */
1228 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1229 hdcDrag, x, y, SRCCOPY);
1230 /* show the image */
1231 /* FIXME: this should be drawn semitransparent */
1232 ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1234 /* hide the image */
1235 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1236 hdcBg, 0, 0, SRCCOPY);
1239 InternalDrag.bShow = !InternalDrag.bShow;
1242 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1247 /*************************************************************************
1248 * ImageList_Draw [COMCTL32.@] Draws an image.
1251 * himl [I] handle to image list
1253 * hdc [I] handle to device context
1256 * fStyle [I] drawing flags
1263 * Calls ImageList_DrawIndirect.
1266 * ImageList_DrawIndirect.
1270 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1271 INT x, INT y, UINT fStyle)
1273 IMAGELISTDRAWPARAMS imldp;
1275 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1285 imldp.rgbBk = CLR_DEFAULT;
1286 imldp.rgbFg = CLR_DEFAULT;
1287 imldp.fStyle = fStyle;
1290 return ImageList_DrawIndirect (&imldp);
1294 /*************************************************************************
1295 * ImageList_DrawEx [COMCTL32.@]
1297 * Draws an image and allows to use extended drawing features.
1300 * himl [I] handle to image list
1302 * hdc [I] handle to device context
1307 * rgbBk [I] background color
1308 * rgbFg [I] foreground color
1309 * fStyle [I] drawing flags
1316 * Calls ImageList_DrawIndirect.
1319 * ImageList_DrawIndirect.
1323 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1324 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1327 IMAGELISTDRAWPARAMS imldp;
1329 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1339 imldp.rgbBk = rgbBk;
1340 imldp.rgbFg = rgbFg;
1341 imldp.fStyle = fStyle;
1344 return ImageList_DrawIndirect (&imldp);
1348 /*************************************************************************
1349 * ImageList_DrawIndirect [COMCTL32.@]
1351 * Draws an image using ...
1354 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1362 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1366 Do some Error Checking
1370 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1372 if (pimldp->himl == NULL)
1374 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1378 Get the Height and Width to display
1380 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1381 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1386 TRACE("hbmMask(0x%08x) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1387 pimldp->himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1389 if(pimldp->himl->hbmMask != 0)
1391 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1395 IMAGELIST_InternalDraw(pimldp, cx, cy);
1398 Apply the blend if needed to the Image
1400 if((pimldp->fStyle & ILD_BLEND50)
1401 || (pimldp->fStyle & ILD_BLEND25))
1403 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1406 Apply the Overlay if needed
1408 if (pimldp->fStyle & ILD_OVERLAYMASK)
1410 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1417 /*************************************************************************
1418 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1421 * himlSrc [I] source image list handle
1424 * Success: Handle of duplicated image list.
1429 ImageList_Duplicate (HIMAGELIST himlSrc)
1434 if (himlSrc == NULL) {
1435 ERR("Invalid image list handle!\n");
1439 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1440 himlSrc->cInitial, himlSrc->cGrow);
1444 hdcSrc = CreateCompatibleDC (0);
1445 hdcDst = CreateCompatibleDC (0);
1446 SelectObject (hdcSrc, himlSrc->hbmImage);
1447 SelectObject (hdcDst, himlDst->hbmImage);
1448 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1449 hdcSrc, 0, 0, SRCCOPY);
1451 if (himlDst->hbmMask)
1453 SelectObject (hdcSrc, himlSrc->hbmMask);
1454 SelectObject (hdcDst, himlDst->hbmMask);
1455 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1456 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1462 himlDst->cCurImage = himlSrc->cCurImage;
1463 himlDst->cMaxImage = himlSrc->cMaxImage;
1469 /*************************************************************************
1470 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1472 * Finishes a drag operation.
1483 ImageList_EndDrag (void)
1485 /* cleanup the InternalDrag struct */
1486 InternalDrag.hwnd = 0;
1487 ImageList_Destroy (InternalDrag.himl);
1488 InternalDrag.himl = 0;
1491 InternalDrag.dxHotspot = 0;
1492 InternalDrag.dyHotspot = 0;
1493 InternalDrag.bShow = FALSE;
1494 DeleteObject(InternalDrag.hbmBg);
1495 InternalDrag.hbmBg = 0;
1496 InternalDrag.bHSPending = FALSE;
1502 /*************************************************************************
1503 * ImageList_GetBkColor [COMCTL32.@]
1505 * Returns the background color of an image list.
1508 * himl [I] Image list handle.
1511 * Success: background color
1516 ImageList_GetBkColor (HIMAGELIST himl)
1518 return himl ? himl->clrBk : CLR_NONE;
1522 /*************************************************************************
1523 * ImageList_GetDragImage [COMCTL32.@]
1525 * Returns the handle to the internal drag image list.
1528 * ppt [O] Pointer to the drag position. Can be NULL.
1529 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1532 * Success: Handle of the drag image list.
1537 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1539 if (InternalDrag.himl) {
1541 ppt->x = InternalDrag.x;
1542 ppt->y = InternalDrag.y;
1545 pptHotspot->x = InternalDrag.dxHotspot;
1546 pptHotspot->y = InternalDrag.dyHotspot;
1548 return (InternalDrag.himl);
1555 /*************************************************************************
1556 * ImageList_GetFlags [COMCTL32.@]
1563 ImageList_GetFlags(HIMAGELIST himl)
1565 FIXME("(%p):empty stub\n", himl);
1570 /*************************************************************************
1571 * ImageList_GetIcon [COMCTL32.@]
1573 * Creates an icon from a masked image of an image list.
1576 * himl [I] handle to image list
1578 * flags [I] drawing style flags
1581 * Success: icon handle
1586 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1590 HBITMAP hOldDstBitmap;
1593 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1595 hdcDst = CreateCompatibleDC(0);
1600 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1601 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1602 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1605 SelectObject (hdcDst, himl->hbmImage);
1606 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1607 SelectObject (hdcDst, ii.hbmColor);
1608 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1611 * CreateIconIndirect requires us to deselect the bitmaps from
1612 * the DCs before calling
1614 SelectObject(hdcDst, hOldDstBitmap);
1616 hIcon = CreateIconIndirect (&ii);
1618 DeleteObject (ii.hbmMask);
1619 DeleteObject (ii.hbmColor);
1626 /*************************************************************************
1627 * ImageList_GetIconSize [COMCTL32.@]
1629 * Retrieves the size of an image in an image list.
1632 * himl [I] handle to image list
1633 * cx [O] pointer to the image width.
1634 * cy [O] pointer to the image height.
1641 * All images in an image list have the same size.
1645 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1649 if ((himl->cx <= 0) || (himl->cy <= 0))
1661 /*************************************************************************
1662 * ImageList_GetImageCount [COMCTL32.@]
1664 * Returns the number of images in an image list.
1667 * himl [I] handle to image list
1670 * Success: Number of images.
1675 ImageList_GetImageCount (HIMAGELIST himl)
1680 return himl->cCurImage;
1684 /*************************************************************************
1685 * ImageList_GetImageInfo [COMCTL32.@]
1687 * Returns information about an image in an image list.
1690 * himl [I] handle to image list
1692 * pImageInfo [O] pointer to the image information
1700 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1702 if ((himl == NULL) || (pImageInfo == NULL))
1704 if ((i < 0) || (i >= himl->cCurImage))
1707 pImageInfo->hbmImage = himl->hbmImage;
1708 pImageInfo->hbmMask = himl->hbmMask;
1710 pImageInfo->rcImage.top = 0;
1711 pImageInfo->rcImage.bottom = himl->cy;
1712 pImageInfo->rcImage.left = i * himl->cx;
1713 pImageInfo->rcImage.right = (i+1) * himl->cx;
1719 /*************************************************************************
1720 * ImageList_GetImageRect [COMCTL32.@]
1722 * Retrieves the rectangle of the specified image in an image list.
1725 * himl [I] handle to image list
1727 * lpRect [O] pointer to the image rectangle
1734 * This is an UNDOCUMENTED function!!!
1738 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1740 if ((himl == NULL) || (lpRect == NULL))
1742 if ((i < 0) || (i >= himl->cCurImage))
1745 lpRect->left = i * himl->cx;
1747 lpRect->right = lpRect->left + himl->cx;
1748 lpRect->bottom = himl->cy;
1754 /*************************************************************************
1755 * ImageList_LoadImage [COMCTL32.@]
1756 * ImageList_LoadImageA [COMCTL32.@]
1758 * Creates an image list from a bitmap, icon or cursor.
1761 * hi [I] instance handle
1762 * lpbmp [I] name or id of the image
1763 * cx [I] width of each image
1764 * cGrow [I] number of images to expand
1765 * clrMask [I] mask color
1766 * uType [I] type of image to load
1767 * uFlags [I] loading flags
1770 * Success: handle to the loaded image list
1778 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1779 COLORREF clrMask, UINT uType, UINT uFlags)
1781 HIMAGELIST himl = NULL;
1785 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1787 ERR("Error loading image!\n");
1791 if (uType == IMAGE_BITMAP) {
1793 GetObjectA (handle, sizeof(BITMAP), &bmp);
1795 /* To match windows behavior, if cx is set to zero and
1796 the flag DI_DEFAULTSIZE is specified, cx becomes the
1797 system metric value for icons. If the flag is not specified
1798 the function sets the size to the height of the bitmap */
1801 if (uFlags & DI_DEFAULTSIZE)
1802 cx = GetSystemMetrics (SM_CXICON);
1807 nImageCount = bmp.bmWidth / cx;
1809 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1810 nImageCount, cGrow);
1811 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1813 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1817 GetIconInfo (handle, &ii);
1818 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1819 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1820 ILC_MASK | ILC_COLOR, 1, cGrow);
1821 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1822 DeleteObject (ii.hbmColor);
1823 DeleteObject (ii.hbmMask);
1826 DeleteObject (handle);
1832 /*************************************************************************
1833 * ImageList_LoadImageW [COMCTL32.@]
1835 * Creates an image list from a bitmap, icon or cursor.
1838 * hi [I] instance handle
1839 * lpbmp [I] name or id of the image
1840 * cx [I] width of each image
1841 * cGrow [I] number of images to expand
1842 * clrMask [I] mask color
1843 * uType [I] type of image to load
1844 * uFlags [I] loading flags
1847 * Success: handle to the loaded image list
1855 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1856 COLORREF clrMask, UINT uType, UINT uFlags)
1858 HIMAGELIST himl = NULL;
1862 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1864 ERR("Error loading image!\n");
1868 if (uType == IMAGE_BITMAP) {
1870 GetObjectA (handle, sizeof(BITMAP), &bmp);
1872 /* To match windows behavior, if cx is set to zero and
1873 the flag DI_DEFAULTSIZE is specified, cx becomes the
1874 system metric value for icons. If the flag is not specified
1875 the function sets the size to the height of the bitmap */
1878 if (uFlags & DI_DEFAULTSIZE)
1879 cx = GetSystemMetrics (SM_CXICON);
1884 nImageCount = bmp.bmWidth / cx;
1886 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1887 nImageCount, cGrow);
1888 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1890 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1894 GetIconInfo (handle, &ii);
1895 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1896 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1897 ILC_MASK | ILC_COLOR, 1, cGrow);
1898 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1899 DeleteObject (ii.hbmColor);
1900 DeleteObject (ii.hbmMask);
1903 DeleteObject (handle);
1909 /*************************************************************************
1910 * ImageList_Merge [COMCTL32.@]
1912 * Creates a new image list that contains a merged image from the specified
1913 * images of both source image lists.
1916 * himl1 [I] handle to first image list
1917 * i1 [I] first image index
1918 * himl2 [I] handle to second image list
1919 * i2 [I] second image index
1920 * dx [I] X offset of the second image relative to the first.
1921 * dy [I] Y offset of the second image relative to the first.
1924 * Success: handle of the merged image list.
1929 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1932 HIMAGELIST himlDst = NULL;
1933 HDC hdcSrcImage, hdcDstImage;
1935 INT xOff1, yOff1, xOff2, yOff2;
1938 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1941 if ((himl1 == NULL) || (himl2 == NULL))
1945 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1946 ERR("Index 1 out of range! %d\n", i1);
1950 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1951 ERR("Index 2 out of range! %d\n", i2);
1956 cxDst = max (himl1->cx, dx + himl2->cx);
1961 cxDst = max (himl2->cx, himl1->cx - dx);
1966 cxDst = max (himl1->cx, himl2->cx);
1972 cyDst = max (himl1->cy, dy + himl2->cy);
1977 cyDst = max (himl2->cy, himl1->cy - dy);
1982 cyDst = max (himl1->cy, himl2->cy);
1987 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1990 hdcSrcImage = CreateCompatibleDC (0);
1991 hdcDstImage = CreateCompatibleDC (0);
1992 nX1 = i1 * himl1->cx;
1993 nX2 = i2 * himl2->cx;
1996 SelectObject (hdcSrcImage, himl1->hbmImage);
1997 SelectObject (hdcDstImage, himlDst->hbmImage);
1998 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1999 hdcSrcImage, 0, 0, BLACKNESS);
2000 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2001 hdcSrcImage, nX1, 0, SRCCOPY);
2003 SelectObject (hdcSrcImage, himl2->hbmMask);
2004 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2005 hdcSrcImage, nX2, 0, SRCAND);
2007 SelectObject (hdcSrcImage, himl2->hbmImage);
2008 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2009 hdcSrcImage, nX2, 0, SRCPAINT);
2012 SelectObject (hdcSrcImage, himl1->hbmMask);
2013 SelectObject (hdcDstImage, himlDst->hbmMask);
2014 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2015 hdcSrcImage, 0, 0, WHITENESS);
2016 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2017 hdcSrcImage, nX1, 0, SRCCOPY);
2019 SelectObject (hdcSrcImage, himl2->hbmMask);
2020 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2021 hdcSrcImage, nX2, 0, SRCAND);
2023 DeleteDC (hdcSrcImage);
2024 DeleteDC (hdcDstImage);
2025 himlDst->cCurImage = 1;
2032 /* helper for _read_bitmap currently unused */
2034 static int may_use_dibsection(HDC hdc) {
2035 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2040 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2044 /* helper for ImageList_Read, see comments below */
2045 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2047 BITMAPFILEHEADER bmfh;
2048 BITMAPINFOHEADER bmih;
2049 int bitsperpixel,palspace,longsperline,width,height;
2050 LPBITMAPINFOHEADER bmihc = NULL;
2052 HBITMAP hbitmap = 0;
2053 LPBYTE bits = NULL,nbits = NULL;
2054 int nbytesperline,bytesperline;
2056 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
2057 (bmfh.bfType != (('M'<<8)|'B')) ||
2058 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
2059 (bmih.biSize != sizeof(bmih))
2063 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2064 if (bitsperpixel<=8)
2065 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2068 width = bmih.biWidth;
2069 height = bmih.biHeight;
2070 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2071 memcpy(bmihc,&bmih,sizeof(bmih));
2072 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
2073 bmihc->biSizeImage = (longsperline*height)<<2;
2075 /* read the palette right after the end of the bitmapinfoheader */
2077 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2081 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2082 if ((bitsperpixel>1) &&
2083 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2085 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2088 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2094 int i,nwidth,nheight;
2096 nwidth = width*(height/cy);
2099 if (bitsperpixel==1)
2100 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2102 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2104 /* Might be a bit excessive memory use here */
2105 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2106 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2107 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2110 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2111 /* Do not forget that windows bitmaps are bottom->top */
2112 bytesperline = longsperline*4;
2113 nbytesperline = (height/cy)*bytesperline;
2114 for (i=0;i<height;i++) {
2116 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2117 bits+bytesperline*(height-1-i),
2121 bmihc->biWidth = nwidth;
2122 bmihc->biHeight = nheight;
2123 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2125 LocalFree((HLOCAL)nbits);
2126 LocalFree((HLOCAL)bits);
2130 if (xdc) ReleaseDC(0,xdc);
2131 if (bmihc) LocalFree((HLOCAL)bmihc);
2134 DeleteObject(hbitmap);
2141 /*************************************************************************
2142 * ImageList_Read [COMCTL32.@]
2144 * Reads an image list from a stream.
2147 * pstm [I] pointer to a stream
2150 * Success: handle to image list
2153 * The format is like this:
2154 * ILHEAD ilheadstruct;
2156 * for the color image part:
2157 * BITMAPFILEHEADER bmfh;
2158 * BITMAPINFOHEADER bmih;
2159 * only if it has a palette:
2160 * RGBQUAD rgbs[nr_of_paletted_colors];
2162 * BYTE colorbits[imagesize];
2164 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2165 * BITMAPFILEHEADER bmfh_mask;
2166 * BITMAPINFOHEADER bmih_mask;
2167 * only if it has a palette (it usually does not):
2168 * RGBQUAD rgbs[nr_of_paletted_colors];
2170 * BYTE maskbits[imagesize];
2172 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2173 * _read_bitmap needs to convert them.
2175 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2179 HBITMAP hbmColor=0,hbmMask=0;
2182 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2184 if (ilHead.usMagic != (('L' << 8) | 'I'))
2186 if (ilHead.usVersion != 0x101) /* probably version? */
2190 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2191 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2192 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2193 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2194 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2195 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2196 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2197 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2198 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2199 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2202 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2205 if (ilHead.flags & ILC_MASK) {
2206 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2208 DeleteObject(hbmColor);
2213 himl = ImageList_Create (
2221 DeleteObject(hbmColor);
2222 DeleteObject(hbmMask);
2225 himl->hbmImage = hbmColor;
2226 himl->hbmMask = hbmMask;
2227 himl->cCurImage = ilHead.cCurImage;
2228 himl->cMaxImage = ilHead.cMaxImage;
2230 ImageList_SetBkColor(himl,ilHead.bkcolor);
2232 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2237 /*************************************************************************
2238 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2241 * himl [I] image list handle
2250 ImageList_Remove (HIMAGELIST himl, INT i)
2252 HBITMAP hbmNewImage, hbmNewMask;
2256 TRACE("(himl=%p i=%d)\n", himl, i);
2259 ERR("Invalid image list handle!\n");
2263 if ((i < -1) || (i >= himl->cCurImage)) {
2264 ERR("index out of range! %d\n", i);
2270 if (himl->cCurImage == 0) {
2271 /* remove all on empty ImageList is allowed */
2272 TRACE("remove all on empty ImageList!\n");
2276 himl->cMaxImage = himl->cInitial + himl->cGrow;
2277 himl->cCurImage = 0;
2278 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2279 himl->nOvlIdx[nCount] = -1;
2281 DeleteObject (himl->hbmImage);
2283 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2284 1, himl->uBitsPixel, NULL);
2286 if (himl->hbmMask) {
2287 DeleteObject (himl->hbmMask);
2289 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2294 /* delete one image */
2295 TRACE("Remove single image! %d\n", i);
2297 /* create new bitmap(s) */
2298 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2300 TRACE(" - Number of images: %d / %d (Old/New)\n",
2301 himl->cCurImage, himl->cCurImage - 1);
2302 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2303 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2306 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2309 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2311 hbmNewMask = 0; /* Just to keep compiler happy! */
2313 hdcSrc = CreateCompatibleDC (0);
2314 hdcDst = CreateCompatibleDC (0);
2316 /* copy all images and masks prior to the "removed" image */
2318 TRACE("Pre image copy: Copy %d images\n", i);
2320 SelectObject (hdcSrc, himl->hbmImage);
2321 SelectObject (hdcDst, hbmNewImage);
2322 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2323 hdcSrc, 0, 0, SRCCOPY);
2325 if (himl->hbmMask) {
2326 SelectObject (hdcSrc, himl->hbmMask);
2327 SelectObject (hdcDst, hbmNewMask);
2328 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2329 hdcSrc, 0, 0, SRCCOPY);
2333 /* copy all images and masks behind the removed image */
2334 if (i < himl->cCurImage - 1) {
2335 TRACE("Post image copy!\n");
2336 SelectObject (hdcSrc, himl->hbmImage);
2337 SelectObject (hdcDst, hbmNewImage);
2338 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2339 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2341 if (himl->hbmMask) {
2342 SelectObject (hdcSrc, himl->hbmMask);
2343 SelectObject (hdcDst, hbmNewMask);
2344 BitBlt (hdcDst, i * himl->cx, 0,
2345 (himl->cCurImage - i - 1) * himl->cx,
2346 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2353 /* delete old images and insert new ones */
2354 DeleteObject (himl->hbmImage);
2355 himl->hbmImage = hbmNewImage;
2356 if (himl->hbmMask) {
2357 DeleteObject (himl->hbmMask);
2358 himl->hbmMask = hbmNewMask;
2362 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2369 /*************************************************************************
2370 * ImageList_Replace [COMCTL32.@]
2372 * Replaces an image in an image list with a new image.
2375 * himl [I] handle to image list
2377 * hbmImage [I] handle to image bitmap
2378 * hbmMask [I] handle to mask bitmap. Can be NULL.
2386 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2389 HDC hdcImageList, hdcImage;
2392 TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2395 ERR("Invalid image list handle!\n");
2399 if ((i >= himl->cMaxImage) || (i < 0)) {
2400 ERR("Invalid image index!\n");
2404 hdcImageList = CreateCompatibleDC (0);
2405 hdcImage = CreateCompatibleDC (0);
2406 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2409 SelectObject (hdcImageList, himl->hbmImage);
2410 SelectObject (hdcImage, hbmImage);
2412 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2413 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2418 SelectObject (hdcImageList, himl->hbmMask);
2419 SelectObject (hdcImage, hbmMask);
2421 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2422 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2425 /* Remove the background from the image
2427 SelectObject (hdcImageList, himl->hbmImage);
2428 StretchBlt (hdcImageList,
2429 i*himl->cx, 0, himl->cx, himl->cy,
2431 0, 0, bmp.bmWidth, bmp.bmHeight,
2432 0x220326); /* NOTSRCAND */
2435 DeleteDC (hdcImage);
2436 DeleteDC (hdcImageList);
2442 /*************************************************************************
2443 * ImageList_ReplaceIcon [COMCTL32.@]
2445 * Replaces an image in an image list using an icon.
2448 * himl [I] handle to image list
2450 * hIcon [I] handle to icon
2453 * Success: index of the replaced image
2458 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2460 HDC hdcImageList, hdcImage;
2463 HBITMAP hbmOldSrc, hbmOldDst;
2467 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2471 if ((i >= himl->cMaxImage) || (i < -1))
2474 hBestFitIcon = CopyImage(
2477 LR_COPYFROMRESOURCE);
2479 GetIconInfo (hBestFitIcon, &ii);
2480 if (ii.hbmMask == 0)
2482 if (ii.hbmColor == 0)
2484 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2487 if (himl->cCurImage + 1 > himl->cMaxImage)
2488 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2490 nIndex = himl->cCurImage;
2496 hdcImageList = CreateCompatibleDC (0);
2497 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2498 if (hdcImageList == 0)
2499 ERR("invalid hdcImageList!\n");
2501 hdcImage = CreateCompatibleDC (0);
2502 TRACE("hdcImage=0x%x!\n", hdcImage);
2504 ERR("invalid hdcImage!\n");
2506 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2507 SetTextColor( hdcImageList, RGB(0,0,0));
2508 SetBkColor( hdcImageList, RGB(255,255,255));
2509 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2510 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2511 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2513 if (himl->hbmMask) {
2514 SelectObject (hdcImageList, himl->hbmMask);
2515 SelectObject (hdcImage, ii.hbmMask);
2516 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2517 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2520 SelectObject (hdcImage, hbmOldSrc);
2521 SelectObject (hdcImageList, hbmOldDst);
2524 DestroyIcon(hBestFitIcon);
2526 DeleteDC (hdcImageList);
2528 DeleteDC (hdcImage);
2530 DeleteObject (ii.hbmColor);
2532 DeleteObject (ii.hbmMask);
2538 /*************************************************************************
2539 * ImageList_SetBkColor [COMCTL32.@]
2541 * Sets the background color of an image list.
2544 * himl [I] handle to image list
2545 * clrBk [I] background color
2548 * Success: previous background color
2553 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2560 clrOldBk = himl->clrBk;
2561 himl->clrBk = clrBk;
2566 /*************************************************************************
2567 * ImageList_SetDragCursorImage [COMCTL32.@]
2569 * Combines the specified image with the current drag image
2572 * himlDrag [I] handle to drag image list
2573 * iDrag [I] drag image index
2574 * dxHotspot [I] X position of the hot spot
2575 * dyHotspot [I] Y position of the hot spot
2582 * When this function is called and the drag image is visible, a
2583 * short flickering occurs but this matches the Win9x behavior. It is
2584 * possible to fix the flickering using code like in ImageList_DragMove.
2588 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2589 INT dxHotspot, INT dyHotspot)
2591 HIMAGELIST himlTemp;
2595 if (InternalDrag.himl == NULL)
2598 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2599 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2601 visible = InternalDrag.bShow;
2603 /* Calculate the offset between the origin of the old image and the
2604 * origin of the second image.
2605 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2606 * hotspot) to the origin of the second image.
2607 * See M$DN for details */
2608 if(InternalDrag.bHSPending) {
2611 InternalDrag.bHSPending = FALSE;
2613 dx = InternalDrag.dxHotspot - dxHotspot;
2614 dy = InternalDrag.dyHotspot - dyHotspot;
2616 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2619 /* hide the drag image */
2620 ImageList_DragShowNolock(FALSE);
2622 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2623 (InternalDrag.himl->cy != himlTemp->cy)) {
2624 /* the size of the drag image changed, invalidate the buffer */
2625 DeleteObject(InternalDrag.hbmBg);
2626 InternalDrag.hbmBg = 0;
2629 ImageList_Destroy (InternalDrag.himl);
2630 InternalDrag.himl = himlTemp;
2632 /* update the InternalDragOffset, if the origin of the
2633 * DragImage was changed by ImageList_Merge. */
2635 InternalDrag.dxHotspot = dxHotspot;
2637 InternalDrag.dyHotspot = dyHotspot;
2640 /* show the drag image */
2641 ImageList_DragShowNolock(TRUE);
2648 /*************************************************************************
2649 * ImageList_SetFilter [COMCTL32.@]
2651 * Sets a filter (or does something completely different)!!???
2652 * It removes 12 Bytes from the stack (3 Parameters).
2655 * himl [I] SHOULD be a handle to image list
2656 * i [I] COULD be an index?
2661 * Failure: FALSE ???
2664 * This is an UNDOCUMENTED function!!!!
2669 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2671 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2677 /*************************************************************************
2678 * ImageList_SetFlags [COMCTL32.@]
2685 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2687 FIXME("(%p %08lx):empty stub\n", himl, flags);
2692 /*************************************************************************
2693 * ImageList_SetIconSize [COMCTL32.@]
2695 * Sets the image size of the bitmap and deletes all images.
2698 * himl [I] handle to image list
2699 * cx [I] image width
2700 * cy [I] image height
2708 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2715 /* remove all images */
2716 himl->cMaxImage = himl->cInitial + himl->cGrow;
2717 himl->cCurImage = 0;
2721 /* initialize overlay mask indices */
2722 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2723 himl->nOvlIdx[nCount] = -1;
2725 DeleteObject (himl->hbmImage);
2727 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2728 1, himl->uBitsPixel, NULL);
2730 if (himl->hbmMask) {
2731 DeleteObject (himl->hbmMask);
2733 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2741 /*************************************************************************
2742 * ImageList_SetImageCount [COMCTL32.@]
2744 * Resizes an image list to the specified number of images.
2747 * himl [I] handle to image list
2748 * iImageCount [I] number of images in the image list
2756 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2758 HDC hdcImageList, hdcBitmap;
2759 HBITMAP hbmNewBitmap;
2760 INT nNewCount, nCopyCount;
2762 TRACE("%p %d\n",himl,iImageCount);
2766 if (himl->cCurImage >= iImageCount)
2768 if (himl->cMaxImage > iImageCount)
2770 himl->cCurImage = iImageCount;
2774 nNewCount = iImageCount + himl->cGrow;
2775 nCopyCount = min(himl->cCurImage, iImageCount);
2777 hdcImageList = CreateCompatibleDC (0);
2778 hdcBitmap = CreateCompatibleDC (0);
2780 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2781 1, himl->uBitsPixel, NULL);
2782 if (hbmNewBitmap != 0)
2784 SelectObject (hdcImageList, himl->hbmImage);
2785 SelectObject (hdcBitmap, hbmNewBitmap);
2788 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2789 hdcImageList, 0, 0, SRCCOPY);
2791 /* delete 'empty' image space */
2792 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2793 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2794 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2795 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2797 DeleteObject (himl->hbmImage);
2798 himl->hbmImage = hbmNewBitmap;
2801 ERR("Could not create new image bitmap !\n");
2805 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2807 if (hbmNewBitmap != 0)
2809 SelectObject (hdcImageList, himl->hbmMask);
2810 SelectObject (hdcBitmap, hbmNewBitmap);
2813 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2814 hdcImageList, 0, 0, SRCCOPY);
2816 /* delete 'empty' image space */
2817 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2818 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2819 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2820 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2822 DeleteObject (himl->hbmMask);
2823 himl->hbmMask = hbmNewBitmap;
2826 ERR("Could not create new mask bitmap!\n");
2829 DeleteDC (hdcImageList);
2830 DeleteDC (hdcBitmap);
2832 /* Update max image count and current image count */
2833 himl->cMaxImage = nNewCount;
2834 himl->cCurImage = iImageCount;
2840 /*************************************************************************
2841 * ImageList_SetOverlayImage [COMCTL32.@]
2843 * Assigns an overlay mask index to an existing image in an image list.
2846 * himl [I] handle to image list
2847 * iImage [I] image index
2848 * iOverlay [I] overlay mask index
2856 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2860 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2862 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2864 himl->nOvlIdx[iOverlay - 1] = iImage;
2870 /* helper for ImageList_Write - write bitmap to pstm
2871 * currently everything is written as 24 bit RGB, except masks
2874 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2876 LPBITMAPFILEHEADER bmfh;
2877 LPBITMAPINFOHEADER bmih;
2878 LPBYTE data, lpBits, lpBitsOrg;
2880 INT bitCount, sizeImage, offBits, totalSize;
2881 INT nwidth, nheight, nsizeImage, icount;
2883 BOOL result = FALSE;
2887 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2889 /* XXX is this always correct? */
2890 icount = bm.bmWidth / cx;
2892 nheight = cy * ((icount+3)>>2);
2894 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2895 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2896 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2898 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2900 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2901 offBits = totalSize;
2902 totalSize += nsizeImage;
2904 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2905 bmfh = (LPBITMAPFILEHEADER)data;
2906 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2907 lpBits = data + offBits;
2909 /* setup BITMAPFILEHEADER */
2910 bmfh->bfType = (('M' << 8) | 'B');
2912 bmfh->bfReserved1 = 0;
2913 bmfh->bfReserved2 = 0;
2914 bmfh->bfOffBits = offBits;
2916 /* setup BITMAPINFOHEADER */
2917 bmih->biSize = sizeof(BITMAPINFOHEADER);
2918 bmih->biWidth = bm.bmWidth;
2919 bmih->biHeight = bm.bmHeight;
2921 bmih->biBitCount = bitCount;
2922 bmih->biCompression = BI_RGB;
2923 bmih->biSizeImage = nsizeImage;
2924 bmih->biXPelsPerMeter = 0;
2925 bmih->biYPelsPerMeter = 0;
2926 bmih->biClrUsed = 0;
2927 bmih->biClrImportant = 0;
2929 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2930 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2931 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2935 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2936 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2938 for(i = 0; i < nheight; i++) {
2939 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2940 int noff = (nbpl * (nheight-1-i));
2941 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2945 bmih->biWidth = nwidth;
2946 bmih->biHeight = nheight;
2950 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2951 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2952 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2955 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2962 LocalFree((HLOCAL)lpBitsOrg);
2968 /*************************************************************************
2969 * ImageList_Write [COMCTL32.@]
2971 * Writes an image list to a stream.
2974 * himl [I] handle to image list
2975 * pstm [O] Pointer to a stream.
2986 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2994 ilHead.usMagic = (('L' << 8) | 'I');
2995 ilHead.usVersion = 0x101;
2996 ilHead.cCurImage = himl->cCurImage;
2997 ilHead.cMaxImage = himl->cMaxImage;
2998 ilHead.cGrow = himl->cGrow;
2999 ilHead.cx = himl->cx;
3000 ilHead.cy = himl->cy;
3001 ilHead.bkcolor = himl->clrBk;
3002 ilHead.flags = himl->flags;
3003 for(i = 0; i < 4; i++) {
3004 ilHead.ovls[i] = himl->nOvlIdx[i];
3007 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3010 /* write the bitmap */
3011 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3014 /* write the mask if we have one */
3015 if(himl->flags & ILC_MASK) {
3016 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))