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 (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
25 * - Fix ImageList_GetIcon.
26 * - Fix ImageList_SetFilter (undocumented).
27 * BTW does anybody know anything about this function???
28 * - It removes 12 Bytes from the stack (3 Parameters).
29 * - First parameter SHOULD be a HIMAGELIST.
30 * - Second parameter COULD be an index?????
31 * - Third parameter.... ?????????????????????
34 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
35 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
36 * partially implemented, the functions mentioned above will be
37 * limited in functionality too.
39 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
40 * is the offset of the image position relative to the actual mouse pointer
41 * position. However the Hotspot passed to SetDragCursorImage is the
42 * offset of the mouse messages sent to the application...
49 #include "wine/obj_base.h"
50 #include "wine/obj_storage.h"
52 #include "imagelist.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
58 #define MAX_OVERLAYIMAGE 15
60 /* internal image list data used for Drag & Drop operations */
65 /* position of the drag image relative to the window */
68 /* offset of the hotspot relative to the origin of the image */
71 /* is the drag image visible */
73 /* saved background */
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
82 /*************************************************************************
83 * IMAGELIST_InternalExpandBitmaps [Internal]
85 * Expands the bitmaps of an image list by the given number of images.
88 * himl [I] handle to image list
89 * nImageCount [I] number of images to add
95 * This function can NOT be used to reduce the number of images.
98 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
100 HDC hdcImageList, hdcBitmap;
101 HBITMAP hbmNewBitmap;
102 INT nNewWidth, nNewCount;
104 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
108 if (cy == 0) cy = himl->cy;
109 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
110 nNewWidth = nNewCount * himl->cx;
112 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
113 hdcImageList = CreateCompatibleDC (0);
114 hdcBitmap = CreateCompatibleDC (0);
117 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
118 if (hbmNewBitmap == 0)
119 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
121 SelectObject (hdcImageList, himl->hbmImage);
122 SelectObject (hdcBitmap, hbmNewBitmap);
123 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
124 hdcImageList, 0, 0, SRCCOPY);
126 DeleteObject (himl->hbmImage);
127 himl->hbmImage = hbmNewBitmap;
131 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
133 if (hbmNewBitmap == 0)
134 ERR("creating new mask bitmap!\n");
136 SelectObject (hdcImageList, himl->hbmMask);
137 SelectObject (hdcBitmap, hbmNewBitmap);
138 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
139 hdcImageList, 0, 0, SRCCOPY);
140 DeleteObject (himl->hbmMask);
141 himl->hbmMask = hbmNewBitmap;
144 himl->cMaxImage = nNewCount;
146 DeleteDC (hdcImageList);
147 DeleteDC (hdcBitmap);
151 /*************************************************************************
152 * IMAGELIST_InternalDraw [Internal]
154 * Draws the image in the ImageList (without the mask)
157 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
158 * cx [I] the width of the image to display
159 * cy............[I] the height of the image to display
165 * This function is used by ImageList_DrawIndirect, when it is
166 * required to draw only the Image (without the mask) to the screen.
168 * Blending and Overlays styles are accomplished by another function
171 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
176 hImageDC = CreateCompatibleDC(0);
177 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
178 BitBlt(pimldp->hdcDst,
179 pimldp->x, pimldp->y, cx, cy,
181 pimldp->himl->cx * pimldp->i, 0,
184 SelectObject(hImageDC, hOldBitmap);
189 /*************************************************************************
190 * IMAGELIST_InternalDrawMask [Internal]
192 * Draws the image in the ImageList with the mask
195 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
196 * cx [I] the width of the image to display
197 * cy............[I] the height of the image to display
203 * This function is used by ImageList_DrawIndirect, when it is
204 * required to draw the Image with the mask to the screen.
206 * Blending and Overlays styles are accomplished by another function.
209 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
211 BOOL bUseCustomBackground, bBlendFlag;
212 HBRUSH hBrush, hOldBrush;
213 HDC hMaskDC, hImageDC;
214 HBITMAP hOldBitmapImage, hOldBitmapMask;
215 HIMAGELIST himlLocal = pimldp->himl;
216 COLORREF oldBkColor, oldFgColor;
217 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
220 * We need a dc and bitmap to draw on that is
223 HDC hOffScreenDC = 0;
224 HBITMAP hOffScreenBmp = 0;
226 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
227 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
229 hImageDC = CreateCompatibleDC(0);
230 hMaskDC = CreateCompatibleDC(0);
232 /* Create a compatible DC. */
233 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
237 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
240 SelectObject( hOffScreenDC, hOffScreenBmp );
247 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
248 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
251 * Get a copy of the image for the masking operations.
252 * We will use the copy, and this dc for all the various
253 * blitting, and then do one final blit to the screen dc.
254 * This should clean up most of the flickering.
256 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
260 * Draw the Background for the appropriate Styles
262 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
266 hBrush = CreateSolidBrush (himlLocal->clrBk);
267 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
269 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
271 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
275 * Draw Image Transparently over the current background
277 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
278 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
280 * To obtain a transparent look, background color should be set
281 * to white and foreground color to black when blting the
285 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
286 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
288 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
291 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
297 * Draw the image when no Background is specified
299 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
301 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
302 himlLocal->cx * pimldp->i, 0, SRCCOPY);
305 * Draw the mask with or without a background
307 else if(fStyle & ILD_MASK)
309 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
310 0, bUseCustomBackground ? SRCCOPY : SRCAND);
314 * Blit the bitmap to the screen now.
316 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
317 hOffScreenDC, 0, 0, SRCCOPY);
320 SelectObject(hImageDC, hOldBitmapImage);
321 SelectObject(hMaskDC, hOldBitmapMask);
328 DeleteDC( hOffScreenDC );
329 DeleteObject( hOffScreenBmp );
334 /*************************************************************************
335 * IMAGELIST_InternalDrawBlend [Internal]
337 * Draws the Blend over the current image
340 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
341 * cx [I] the width of the image to display
342 * cy............[I] the height of the image to display
348 * This functions is used by ImageList_DrawIndirect, when it is
349 * required to add the blend to the current image.
353 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
356 HDC hBlendMaskDC,hMaskDC;
357 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
358 HBITMAP hBlendMaskBitmap, hOldBitmap;
359 COLORREF clrBlend, OldTextColor, OldBkColor;
360 HIMAGELIST himlLocal = pimldp->himl;
362 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
363 if (!(pimldp->rgbFg == CLR_DEFAULT))
365 clrBlend = pimldp->rgbFg;
367 /* Create the blend Mask
369 hBlendMaskDC = CreateCompatibleDC(0);
370 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
371 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
373 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
374 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
376 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
377 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
378 SelectObject(hBlendMaskDC, hOldBrush);
380 /* Modify the blend mask if an Image Mask exist
382 if(pimldp->himl->hbmMask != 0)
384 HBITMAP hOldMaskBitmap;
385 hMaskDC = CreateCompatibleDC(0);
386 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
391 himlLocal->cx * pimldp->i,0,
392 0x220326); /* NOTSRCAND */
400 SelectObject(hMaskDC, hOldMaskBitmap);
404 /* Apply blend to the current image given the BlendMask
406 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
407 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
408 hBlendColorBrush = CreateSolidBrush(clrBlend);
409 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
411 BitBlt (pimldp->hdcDst,
412 pimldp->x, pimldp->y, cx, cy,
415 0xB8074A); /* PSDPxax */
417 SelectObject(pimldp->hdcDst, hOldBrush);
418 SetTextColor(pimldp->hdcDst, OldTextColor);
419 SetBkColor(pimldp->hdcDst, OldBkColor);
420 SelectObject(hBlendMaskDC, hOldBitmap);
421 DeleteDC(hBlendMaskDC);
422 DeleteObject(hBlendMaskBitmap);
423 DeleteObject(hBlendColorBrush);
426 /*************************************************************************
427 * IMAGELIST_InternalDrawOverlay [Internal]
429 * Draws the overlay image
432 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
433 * cx [I] the width of the image to display
434 * cy............[I] the height of the image to display
440 * This functions is used by ImageList_DrawIndirect, when it is
441 * required to draw the overlay
446 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
452 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
453 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
455 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
456 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
458 hImageDC = CreateCompatibleDC(0);
459 if (pimldp->himl->hbmMask)
461 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
462 pimldp->himl->hbmMask);
464 BitBlt (pimldp->hdcDst,
465 pimldp->x, pimldp->y, cx, cy,
466 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
469 SelectObject(hImageDC, hOldBitmap);
471 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
472 pimldp->himl->hbmImage);
474 BitBlt (pimldp->hdcDst,
475 pimldp->x, pimldp->y, cx, cy,
477 pimldp->himl->cx * nOvlIdx, 0,
480 SelectObject(hImageDC, hOldBitmap);
487 /*************************************************************************
488 * ImageList_Add [COMCTL32.@]
490 * Add an image or images to an image list.
493 * himl [I] handle to image list
494 * hbmImage [I] handle to image bitmap
495 * hbmMask [I] handle to mask bitmap
498 * Success: Index of the first new image.
503 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
505 HDC hdcImage, hdcBitmap;
506 INT nFirstIndex, nImageCount;
509 HBITMAP hOldBitmapImage, hOldBitmap;
511 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
512 if (!himl || !hbmImage)
515 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
516 nImageCount = bmp.bmWidth / himl->cx;
518 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
520 nStartX = himl->cCurImage * himl->cx;
522 hdcImage = CreateCompatibleDC(0);
523 hdcBitmap = CreateCompatibleDC(0);
525 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
526 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
528 /* Copy result to the imagelist
530 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
531 hdcBitmap, 0, 0, SRCCOPY);
535 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
537 hdcMask = CreateCompatibleDC (0);
538 hdcTemp = CreateCompatibleDC(0);
539 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
540 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
543 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
548 SelectObject(hdcTemp, hOldBitmapTemp);
551 /* Remove the background from the image
554 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
557 0x220326); /* NOTSRCAND */
559 SelectObject(hdcMask, hOldBitmapMask);
563 SelectObject(hdcImage, hOldBitmapImage);
564 SelectObject(hdcBitmap, hOldBitmap);
568 nFirstIndex = himl->cCurImage;
569 himl->cCurImage += nImageCount;
575 /*************************************************************************
576 * ImageList_AddIcon [COMCTL32.@]
578 * Adds an icon to an image list.
581 * himl [I] handle to image list
582 * hIcon [I] handle to icon
585 * Success: index of the new image
590 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
592 return ImageList_ReplaceIcon (himl, -1, hIcon);
596 /*************************************************************************
597 * ImageList_AddMasked [COMCTL32.@]
599 * Adds an image or images to an image list and creates a mask from the
600 * specified bitmap using the mask color.
603 * himl [I] handle to image list.
604 * hBitmap [I] handle to bitmap
605 * clrMask [I] mask color.
608 * Success: Index of the first new image.
613 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
615 HDC hdcImage, hdcMask, hdcBitmap;
616 INT nIndex, nImageCount, nMaskXOffset=0;
618 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
619 HBITMAP hMaskBitmap=0;
622 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
626 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
629 nImageCount = bmp.bmWidth / himl->cx;
631 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
633 nIndex = himl->cCurImage;
634 himl->cCurImage += nImageCount;
636 hdcMask = CreateCompatibleDC (0);
637 hdcImage = CreateCompatibleDC(0);
638 hdcBitmap = CreateCompatibleDC(0);
641 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
642 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
645 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
646 nMaskXOffset = nIndex * himl->cx;
651 Create a temp Mask so we can remove the background of
652 the Image (Windows does this even if there is no mask)
654 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
655 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
658 /* create monochrome image to the mask bitmap */
659 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
660 GetPixel (hdcBitmap, 0, 0);
661 SetBkColor (hdcBitmap, bkColor);
663 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
667 SetBkColor(hdcBitmap, RGB(255,255,255));
668 /*Remove the background from the image
671 WINDOWS BUG ALERT!!!!!!
672 The statement below should not be done in common practice
673 but this is how ImageList_AddMasked works in Windows.
674 It overwrites the original bitmap passed, this was discovered
675 by using the same bitmap to iterate the different styles
676 on windows where it failed (BUT ImageList_Add is OK)
677 This is here in case some apps rely on this bug
680 0, 0, bmp.bmWidth, bmp.bmHeight,
683 0x220326); /* NOTSRCAND */
684 /* Copy result to the imagelist
687 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
693 SelectObject(hdcMask,hOldBitmapMask);
694 SelectObject(hdcImage, hOldBitmapImage);
695 SelectObject(hdcBitmap, hOldBitmap);
701 DeleteObject(hMaskBitmap);
708 /*************************************************************************
709 * ImageList_BeginDrag [COMCTL32.@]
711 * Creates a temporary image list that contains one image. It will be used
715 * himlTrack [I] handle to the source image list
716 * iTrack [I] index of the drag image in the source image list
717 * dxHotspot [I] X position of the hot spot of the drag image
718 * dyHotspot [I] Y position of the hot spot of the drag image
726 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
727 INT dxHotspot, INT dyHotspot)
732 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
733 dxHotspot, dyHotspot);
735 if (himlTrack == NULL)
738 if (InternalDrag.himl)
739 ImageList_EndDrag ();
744 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
745 if (InternalDrag.himl == NULL) {
746 ERR("Error creating drag image list!\n");
750 InternalDrag.dxHotspot = dxHotspot;
751 InternalDrag.dyHotspot = dyHotspot;
753 hdcSrc = CreateCompatibleDC (0);
754 hdcDst = CreateCompatibleDC (0);
757 SelectObject (hdcSrc, himlTrack->hbmImage);
758 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
759 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
762 SelectObject (hdcSrc, himlTrack->hbmMask);
763 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
764 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
769 InternalDrag.himl->cCurImage = 1;
770 InternalDrag.bHSPending = TRUE;
776 /*************************************************************************
777 * ImageList_Copy [COMCTL32.@]
779 * Copies an image of the source image list to an image of the
780 * destination image list. Images can be copied or swapped.
783 * himlDst [I] handle to the destination image list
784 * iDst [I] destination image index.
785 * himlSrc [I] handle to the source image list
786 * iSrc [I] source image index
787 * uFlags [I] flags for the copy operation
794 * Copying from one image list to another is possible. The original
795 * implementation just copies or swaps within one image list.
796 * Could this feature become a bug??? ;-)
800 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
801 INT iSrc, INT uFlags)
805 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
807 if ((himlSrc == NULL) || (himlDst == NULL))
809 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
811 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
814 hdcSrc = CreateCompatibleDC (0);
815 if (himlDst == himlSrc)
818 hdcDst = CreateCompatibleDC (0);
820 if (uFlags & ILCF_SWAP) {
822 HBITMAP hbmTempImage, hbmTempMask;
824 /* create temporary bitmaps */
825 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
826 himlSrc->uBitsPixel, NULL);
827 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
830 /* copy (and stretch) destination to temporary bitmaps.(save) */
832 SelectObject (hdcSrc, himlDst->hbmImage);
833 SelectObject (hdcDst, hbmTempImage);
834 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
835 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
838 SelectObject (hdcSrc, himlDst->hbmMask);
839 SelectObject (hdcDst, hbmTempMask);
840 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
841 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
844 /* copy (and stretch) source to destination */
846 SelectObject (hdcSrc, himlSrc->hbmImage);
847 SelectObject (hdcDst, himlDst->hbmImage);
848 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
849 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
852 SelectObject (hdcSrc, himlSrc->hbmMask);
853 SelectObject (hdcDst, himlDst->hbmMask);
854 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
855 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
858 /* copy (without stretching) temporary bitmaps to source (restore) */
860 SelectObject (hdcSrc, hbmTempImage);
861 SelectObject (hdcDst, himlSrc->hbmImage);
862 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
863 hdcSrc, 0, 0, SRCCOPY);
865 SelectObject (hdcSrc, hbmTempMask);
866 SelectObject (hdcDst, himlSrc->hbmMask);
867 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
868 hdcSrc, 0, 0, SRCCOPY);
870 /* delete temporary bitmaps */
871 DeleteObject (hbmTempMask);
872 DeleteObject (hbmTempImage);
876 SelectObject (hdcSrc, himlSrc->hbmImage);
877 if (himlSrc == himlDst)
880 SelectObject (hdcDst, himlDst->hbmImage);
881 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
882 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
886 SelectObject (hdcSrc, himlSrc->hbmMask);
887 if (himlSrc == himlDst)
890 SelectObject (hdcDst, himlDst->hbmMask);
891 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
892 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
897 if (himlSrc != himlDst)
904 /*************************************************************************
905 * ImageList_Create [COMCTL32.@] Creates a new image list.
908 * cx [I] image height
910 * flags [I] creation flags
911 * cInitial [I] initial number of images in the image list
912 * cGrow [I] number of images by which image list grows
915 * Success: Handle to the created image list
920 ImageList_Create (INT cx, INT cy, UINT flags,
921 INT cInitial, INT cGrow)
927 static WORD aBitBlend25[] =
928 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
930 static WORD aBitBlend50[] =
931 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
933 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
935 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
942 himl->cMaxImage = cInitial + cGrow;
943 himl->cInitial = cInitial;
946 himl->clrFg = CLR_DEFAULT;
947 himl->clrBk = CLR_NONE;
949 /* initialize overlay mask indices */
950 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
951 himl->nOvlIdx[nCount] = -1;
953 hdc = CreateCompatibleDC (0);
954 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
957 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
959 if (himl->cMaxImage > 0) {
961 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
962 1, himl->uBitsPixel, NULL);
963 if (himl->hbmImage == 0) {
964 ERR("Error creating image bitmap!\n");
971 if ( (himl->flags & ILC_MASK)) {
972 int images = himl->cMaxImage;
976 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
978 if (himl->hbmMask == 0) {
979 ERR("Error creating mask bitmap!\n");
981 DeleteObject (himl->hbmImage);
988 /* create blending brushes */
989 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
990 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
991 DeleteObject (hbmTemp);
993 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
994 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
995 DeleteObject (hbmTemp);
997 TRACE("created imagelist %p\n", himl);
1002 /*************************************************************************
1003 * ImageList_Destroy [COMCTL32.@]
1005 * Destroys an image list.
1008 * himl [I] handle to image list
1016 ImageList_Destroy (HIMAGELIST himl)
1021 /* delete image bitmaps */
1023 DeleteObject (himl->hbmImage);
1025 DeleteObject (himl->hbmMask);
1027 /* delete blending brushes */
1028 if (himl->hbrBlend25)
1029 DeleteObject (himl->hbrBlend25);
1030 if (himl->hbrBlend50)
1031 DeleteObject (himl->hbrBlend50);
1033 COMCTL32_Free (himl);
1039 /*************************************************************************
1040 * ImageList_DragEnter [COMCTL32.@]
1042 * Locks window update and displays the drag image at the given position.
1045 * hwndLock [I] handle of the window that owns the drag image.
1046 * x [I] X position of the drag image.
1047 * y [I] Y position of the drag image.
1054 * The position of the drag image is relative to the window, not
1059 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1061 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1063 if (InternalDrag.himl == NULL)
1067 InternalDrag.hwnd = hwndLock;
1069 InternalDrag.hwnd = GetDesktopWindow ();
1074 /* draw the drag image and save the background */
1075 if (!ImageList_DragShowNolock(TRUE)) {
1083 /*************************************************************************
1084 * ImageList_DragLeave [COMCTL32.@]
1086 * Unlocks window update and hides the drag image.
1089 * hwndLock [I] handle of the window that owns the drag image.
1097 ImageList_DragLeave (HWND hwndLock)
1099 /* As we don't save drag info in the window this can lead to problems if
1100 an app does not supply the same window as DragEnter */
1102 InternalDrag.hwnd = hwndLock;
1104 InternalDrag.hwnd = GetDesktopWindow (); */
1106 hwndLock = GetDesktopWindow();
1107 if(InternalDrag.hwnd != hwndLock)
1108 FIXME("DragLeave hWnd != DragEnter hWnd\n");
1110 ImageList_DragShowNolock (FALSE);
1116 /*************************************************************************
1117 * ImageList_DragMove [COMCTL32.@]
1119 * Moves the drag image.
1122 * x [I] X position of the drag image.
1123 * y [I] Y position of the drag image.
1130 * The position of the drag image is relative to the window, not
1134 * The drag image should be drawn semitransparent.
1138 ImageList_DragMove (INT x, INT y)
1140 TRACE("(x=%d y=%d)\n", x, y);
1142 if (!InternalDrag.himl) {
1146 /* draw/update the drag image */
1147 if (InternalDrag.bShow) {
1151 HBITMAP hbmOffScreen;
1152 INT origNewX, origNewY;
1153 INT origOldX, origOldY;
1154 INT origRegX, origRegY;
1155 INT sizeRegX, sizeRegY;
1158 /* calculate the update region */
1159 origNewX = x - InternalDrag.dxHotspot;
1160 origNewY = y - InternalDrag.dyHotspot;
1161 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1162 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1163 origRegX = min(origNewX, origOldX);
1164 origRegY = min(origNewY, origOldY);
1165 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1166 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1168 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1169 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1170 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1171 hdcBg = CreateCompatibleDC(hdcDrag);
1173 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1174 SelectObject(hdcOffScreen, hbmOffScreen);
1175 SelectObject(hdcBg, InternalDrag.hbmBg);
1177 /* get the actual background of the update region */
1178 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1179 origRegX, origRegY, SRCCOPY);
1180 /* erase the old image */
1181 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1182 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1184 /* save the background */
1185 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1186 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1187 /* draw the image */
1188 /* FIXME: image should be drawn semitransparent */
1189 ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1190 origNewY - origRegY, ILD_NORMAL);
1191 /* draw the update region to the screen */
1192 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1193 hdcOffScreen, 0, 0, SRCCOPY);
1196 DeleteDC(hdcOffScreen);
1197 DeleteObject(hbmOffScreen);
1198 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1201 /* update the image position */
1209 /*************************************************************************
1210 * ImageList_DragShowNolock [COMCTL32.@]
1212 * Shows or hides the drag image.
1215 * bShow [I] TRUE shows the drag image, FALSE hides it.
1222 * The drag image should be drawn semitransparent.
1226 ImageList_DragShowNolock (BOOL bShow)
1232 TRACE("bShow=0x%X!\n", bShow);
1234 /* DragImage is already visible/hidden */
1235 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1239 /* position of the origin of the DragImage */
1240 x = InternalDrag.x - InternalDrag.dxHotspot;
1241 y = InternalDrag.y - InternalDrag.dyHotspot;
1243 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1244 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1249 hdcBg = CreateCompatibleDC(hdcDrag);
1250 if (!InternalDrag.hbmBg) {
1251 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1252 InternalDrag.himl->cx, InternalDrag.himl->cy);
1254 SelectObject(hdcBg, InternalDrag.hbmBg);
1257 /* save the background */
1258 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1259 hdcDrag, x, y, SRCCOPY);
1260 /* show the image */
1261 /* FIXME: this should be drawn semitransparent */
1262 ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1264 /* hide the image */
1265 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1266 hdcBg, 0, 0, SRCCOPY);
1269 InternalDrag.bShow = !InternalDrag.bShow;
1272 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1277 /*************************************************************************
1278 * ImageList_Draw [COMCTL32.@] Draws an image.
1281 * himl [I] handle to image list
1283 * hdc [I] handle to device context
1286 * fStyle [I] drawing flags
1293 * Calls ImageList_DrawIndirect.
1296 * ImageList_DrawIndirect.
1300 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1301 INT x, INT y, UINT fStyle)
1303 IMAGELISTDRAWPARAMS imldp;
1305 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1315 imldp.rgbBk = CLR_DEFAULT;
1316 imldp.rgbFg = CLR_DEFAULT;
1317 imldp.fStyle = fStyle;
1320 return ImageList_DrawIndirect (&imldp);
1324 /*************************************************************************
1325 * ImageList_DrawEx [COMCTL32.@]
1327 * Draws an image and allows to use extended drawing features.
1330 * himl [I] handle to image list
1332 * hdc [I] handle to device context
1335 * xOffs [I] X offset
1336 * yOffs [I] Y offset
1337 * rgbBk [I] background color
1338 * rgbFg [I] foreground color
1339 * fStyle [I] drawing flags
1346 * Calls ImageList_DrawIndirect.
1349 * ImageList_DrawIndirect.
1353 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1354 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1357 IMAGELISTDRAWPARAMS imldp;
1359 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1369 imldp.rgbBk = rgbBk;
1370 imldp.rgbFg = rgbFg;
1371 imldp.fStyle = fStyle;
1374 return ImageList_DrawIndirect (&imldp);
1378 /*************************************************************************
1379 * ImageList_DrawIndirect [COMCTL32.@]
1381 * Draws an image using ...
1384 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1392 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1396 Do some Error Checking
1400 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1402 if (pimldp->himl == NULL)
1404 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1405 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1409 Get the Height and Width to display
1411 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1412 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1417 TRACE("hbmMask(0x%08x) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1418 pimldp->himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1420 if(pimldp->himl->hbmMask != 0)
1422 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1426 IMAGELIST_InternalDraw(pimldp, cx, cy);
1429 Apply the blend if needed to the Image
1431 if((pimldp->fStyle & ILD_BLEND50)
1432 || (pimldp->fStyle & ILD_BLEND25))
1434 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1437 Apply the Overlay if needed
1439 if (pimldp->fStyle & ILD_OVERLAYMASK)
1441 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1448 /*************************************************************************
1449 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1452 * himlSrc [I] source image list handle
1455 * Success: Handle of duplicated image list.
1460 ImageList_Duplicate (HIMAGELIST himlSrc)
1465 if (himlSrc == NULL) {
1466 ERR("Invalid image list handle!\n");
1470 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1471 himlSrc->cInitial, himlSrc->cGrow);
1475 hdcSrc = CreateCompatibleDC (0);
1476 hdcDst = CreateCompatibleDC (0);
1477 SelectObject (hdcSrc, himlSrc->hbmImage);
1478 SelectObject (hdcDst, himlDst->hbmImage);
1479 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1480 hdcSrc, 0, 0, SRCCOPY);
1482 if (himlDst->hbmMask)
1484 SelectObject (hdcSrc, himlSrc->hbmMask);
1485 SelectObject (hdcDst, himlDst->hbmMask);
1486 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1487 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1493 himlDst->cCurImage = himlSrc->cCurImage;
1494 himlDst->cMaxImage = himlSrc->cMaxImage;
1500 /*************************************************************************
1501 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1503 * Finishes a drag operation.
1514 ImageList_EndDrag (void)
1516 /* cleanup the InternalDrag struct */
1517 InternalDrag.hwnd = 0;
1518 ImageList_Destroy (InternalDrag.himl);
1519 InternalDrag.himl = 0;
1522 InternalDrag.dxHotspot = 0;
1523 InternalDrag.dyHotspot = 0;
1524 InternalDrag.bShow = FALSE;
1525 DeleteObject(InternalDrag.hbmBg);
1526 InternalDrag.hbmBg = 0;
1527 InternalDrag.bHSPending = FALSE;
1533 /*************************************************************************
1534 * ImageList_GetBkColor [COMCTL32.@]
1536 * Returns the background color of an image list.
1539 * himl [I] Image list handle.
1542 * Success: background color
1547 ImageList_GetBkColor (HIMAGELIST himl)
1556 /*************************************************************************
1557 * ImageList_GetDragImage [COMCTL32.@]
1559 * Returns the handle to the internal drag image list.
1562 * ppt [O] Pointer to the drag position. Can be NULL.
1563 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1566 * Success: Handle of the drag image list.
1571 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1573 if (InternalDrag.himl) {
1575 ppt->x = InternalDrag.x;
1576 ppt->y = InternalDrag.y;
1579 pptHotspot->x = InternalDrag.dxHotspot;
1580 pptHotspot->y = InternalDrag.dyHotspot;
1582 return (InternalDrag.himl);
1589 /*************************************************************************
1590 * ImageList_GetFlags [COMCTL32.@]
1597 ImageList_GetFlags(HIMAGELIST himl)
1599 FIXME("(%p):empty stub\n", himl);
1604 /*************************************************************************
1605 * ImageList_GetIcon [COMCTL32.@]
1607 * Creates an icon from a masked image of an image list.
1610 * himl [I] handle to image list
1612 * flags [I] drawing style flags
1615 * Success: icon handle
1620 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1624 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1627 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1628 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1632 hdcSrc = CreateCompatibleDC(0);
1633 hdcDst = CreateCompatibleDC(0);
1636 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1639 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1640 if (himl->hbmMask) {
1641 SelectObject (hdcSrc, himl->hbmMask);
1642 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1643 hdcSrc, i * himl->cx, 0, SRCCOPY);
1646 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1649 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1650 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1651 SelectObject (hdcDst, ii.hbmColor);
1652 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1653 hdcSrc, i * himl->cx, 0, SRCCOPY);
1656 * CreateIconIndirect requires us to deselect the bitmaps from
1657 * the DCs before calling
1659 SelectObject(hdcSrc, hOldSrcBitmap);
1660 SelectObject(hdcDst, hOldDstBitmap);
1662 hIcon = CreateIconIndirect (&ii);
1666 DeleteObject (ii.hbmMask);
1667 DeleteObject (ii.hbmColor);
1673 /*************************************************************************
1674 * ImageList_GetIconSize [COMCTL32.@]
1676 * Retrieves the size of an image in an image list.
1679 * himl [I] handle to image list
1680 * cx [O] pointer to the image width.
1681 * cy [O] pointer to the image height.
1688 * All images in an image list have the same size.
1692 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1696 if ((himl->cx <= 0) || (himl->cy <= 0))
1708 /*************************************************************************
1709 * ImageList_GetImageCount [COMCTL32.@]
1711 * Returns the number of images in an image list.
1714 * himl [I] handle to image list
1717 * Success: Number of images.
1722 ImageList_GetImageCount (HIMAGELIST himl)
1727 return himl->cCurImage;
1731 /*************************************************************************
1732 * ImageList_GetImageInfo [COMCTL32.@]
1734 * Returns information about an image in an image list.
1737 * himl [I] handle to image list
1739 * pImageInfo [O] pointer to the image information
1747 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1749 if ((himl == NULL) || (pImageInfo == NULL))
1751 if ((i < 0) || (i >= himl->cCurImage))
1754 pImageInfo->hbmImage = himl->hbmImage;
1755 pImageInfo->hbmMask = himl->hbmMask;
1757 pImageInfo->rcImage.top = 0;
1758 pImageInfo->rcImage.bottom = himl->cy;
1759 pImageInfo->rcImage.left = i * himl->cx;
1760 pImageInfo->rcImage.right = (i+1) * himl->cx;
1766 /*************************************************************************
1767 * ImageList_GetImageRect [COMCTL32.@]
1769 * Retrieves the rectangle of the specified image in an image list.
1772 * himl [I] handle to image list
1774 * lpRect [O] pointer to the image rectangle
1781 * This is an UNDOCUMENTED function!!!
1785 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1787 if ((himl == NULL) || (lpRect == NULL))
1789 if ((i < 0) || (i >= himl->cCurImage))
1792 lpRect->left = i * himl->cx;
1794 lpRect->right = lpRect->left + himl->cx;
1795 lpRect->bottom = himl->cy;
1801 /*************************************************************************
1802 * ImageList_LoadImage [COMCTL32.@]
1803 * ImageList_LoadImageA [COMCTL32.@]
1805 * Creates an image list from a bitmap, icon or cursor.
1808 * hi [I] instance handle
1809 * lpbmp [I] name or id of the image
1810 * cx [I] width of each image
1811 * cGrow [I] number of images to expand
1812 * clrMask [I] mask color
1813 * uType [I] type of image to load
1814 * uFlags [I] loading flags
1817 * Success: handle to the loaded image list
1825 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1826 COLORREF clrMask, UINT uType, UINT uFlags)
1828 HIMAGELIST himl = NULL;
1832 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1834 ERR("Error loading image!\n");
1838 if (uType == IMAGE_BITMAP) {
1840 GetObjectA (handle, sizeof(BITMAP), &bmp);
1842 /* To match windows behavior, if cx is set to zero and
1843 the flag DI_DEFAULTSIZE is specified, cx becomes the
1844 system metric value for icons. If the flag is not specified
1845 the function sets the size to the height of the bitmap */
1848 if (uFlags & DI_DEFAULTSIZE)
1849 cx = GetSystemMetrics (SM_CXICON);
1854 nImageCount = bmp.bmWidth / cx;
1856 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1857 nImageCount, cGrow);
1858 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1860 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1864 GetIconInfo (handle, &ii);
1865 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1866 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1867 ILC_MASK | ILC_COLOR, 1, cGrow);
1868 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1869 DeleteObject (ii.hbmColor);
1870 DeleteObject (ii.hbmMask);
1873 DeleteObject (handle);
1879 /*************************************************************************
1880 * ImageList_LoadImageW [COMCTL32.@]
1882 * Creates an image list from a bitmap, icon or cursor.
1885 * hi [I] instance handle
1886 * lpbmp [I] name or id of the image
1887 * cx [I] width of each image
1888 * cGrow [I] number of images to expand
1889 * clrMask [I] mask color
1890 * uType [I] type of image to load
1891 * uFlags [I] loading flags
1894 * Success: handle to the loaded image list
1902 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1903 COLORREF clrMask, UINT uType, UINT uFlags)
1905 HIMAGELIST himl = NULL;
1909 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1911 ERR("Error loading image!\n");
1915 if (uType == IMAGE_BITMAP) {
1917 GetObjectA (handle, sizeof(BITMAP), &bmp);
1919 /* To match windows behavior, if cx is set to zero and
1920 the flag DI_DEFAULTSIZE is specified, cx becomes the
1921 system metric value for icons. If the flag is not specified
1922 the function sets the size to the height of the bitmap */
1925 if (uFlags & DI_DEFAULTSIZE)
1926 cx = GetSystemMetrics (SM_CXICON);
1931 nImageCount = bmp.bmWidth / cx;
1933 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1934 nImageCount, cGrow);
1935 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1937 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1941 GetIconInfo (handle, &ii);
1942 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1943 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1944 ILC_MASK | ILC_COLOR, 1, cGrow);
1945 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1946 DeleteObject (ii.hbmColor);
1947 DeleteObject (ii.hbmMask);
1950 DeleteObject (handle);
1956 /*************************************************************************
1957 * ImageList_Merge [COMCTL32.@]
1959 * Creates a new image list that contains a merged image from the specified
1960 * images of both source image lists.
1963 * himl1 [I] handle to first image list
1964 * i1 [I] first image index
1965 * himl2 [I] handle to second image list
1966 * i2 [I] second image index
1967 * dx [I] X offset of the second image relative to the first.
1968 * dy [I] Y offset of the second image relative to the first.
1971 * Success: handle of the merged image list.
1976 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1979 HIMAGELIST himlDst = NULL;
1980 HDC hdcSrcImage, hdcDstImage;
1982 INT xOff1, yOff1, xOff2, yOff2;
1985 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1988 if ((himl1 == NULL) || (himl2 == NULL))
1992 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1993 ERR("Index 1 out of range! %d\n", i1);
1997 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1998 ERR("Index 2 out of range! %d\n", i2);
2003 cxDst = max (himl1->cx, dx + himl2->cx);
2008 cxDst = max (himl2->cx, himl1->cx - dx);
2013 cxDst = max (himl1->cx, himl2->cx);
2019 cyDst = max (himl1->cy, dy + himl2->cy);
2024 cyDst = max (himl2->cy, himl1->cy - dy);
2029 cyDst = max (himl1->cy, himl2->cy);
2034 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2037 hdcSrcImage = CreateCompatibleDC (0);
2038 hdcDstImage = CreateCompatibleDC (0);
2039 nX1 = i1 * himl1->cx;
2040 nX2 = i2 * himl2->cx;
2043 SelectObject (hdcSrcImage, himl1->hbmImage);
2044 SelectObject (hdcDstImage, himlDst->hbmImage);
2045 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2046 hdcSrcImage, 0, 0, BLACKNESS);
2047 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2048 hdcSrcImage, nX1, 0, SRCCOPY);
2050 SelectObject (hdcSrcImage, himl2->hbmMask);
2051 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2052 hdcSrcImage, nX2, 0, SRCAND);
2054 SelectObject (hdcSrcImage, himl2->hbmImage);
2055 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2056 hdcSrcImage, nX2, 0, SRCPAINT);
2059 SelectObject (hdcSrcImage, himl1->hbmMask);
2060 SelectObject (hdcDstImage, himlDst->hbmMask);
2061 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2062 hdcSrcImage, 0, 0, WHITENESS);
2063 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2064 hdcSrcImage, nX1, 0, SRCCOPY);
2066 SelectObject (hdcSrcImage, himl2->hbmMask);
2067 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2068 hdcSrcImage, nX2, 0, SRCAND);
2070 DeleteDC (hdcSrcImage);
2071 DeleteDC (hdcDstImage);
2072 himlDst->cCurImage = 1;
2079 /* helper for _read_bitmap currently unused */
2081 static int may_use_dibsection(HDC hdc) {
2082 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2087 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2091 /* helper for ImageList_Read, see comments below */
2092 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2094 BITMAPFILEHEADER bmfh;
2095 BITMAPINFOHEADER bmih;
2096 int bitsperpixel,palspace,longsperline,width,height;
2097 LPBITMAPINFOHEADER bmihc = NULL;
2099 HBITMAP hbitmap = 0;
2100 LPBYTE bits = NULL,nbits = NULL;
2101 int nbytesperline,bytesperline;
2103 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
2104 (bmfh.bfType != (('M'<<8)|'B')) ||
2105 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
2106 (bmih.biSize != sizeof(bmih))
2110 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2111 if (bitsperpixel<=8)
2112 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2115 width = bmih.biWidth;
2116 height = bmih.biHeight;
2117 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2118 memcpy(bmihc,&bmih,sizeof(bmih));
2119 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
2120 bmihc->biSizeImage = (longsperline*height)<<2;
2122 /* read the palette right after the end of the bitmapinfoheader */
2124 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2128 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2129 if ((bitsperpixel>1) &&
2130 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2132 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2135 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2141 int i,nwidth,nheight;
2143 nwidth = width*(height/cy);
2146 if (bitsperpixel==1)
2147 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2149 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2151 /* Might be a bit excessive memory use here */
2152 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2153 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2154 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2157 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2158 /* Do not forget that windows bitmaps are bottom->top */
2159 bytesperline = longsperline*4;
2160 nbytesperline = (height/cy)*bytesperline;
2161 for (i=0;i<height;i++) {
2163 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2164 bits+bytesperline*(height-1-i),
2168 bmihc->biWidth = nwidth;
2169 bmihc->biHeight = nheight;
2170 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2172 LocalFree((HLOCAL)nbits);
2173 LocalFree((HLOCAL)bits);
2177 if (xdc) ReleaseDC(0,xdc);
2178 if (bmihc) LocalFree((HLOCAL)bmihc);
2181 DeleteObject(hbitmap);
2188 /*************************************************************************
2189 * ImageList_Read [COMCTL32.@]
2191 * Reads an image list from a stream.
2194 * pstm [I] pointer to a stream
2197 * Success: handle to image list
2200 * The format is like this:
2201 * ILHEAD ilheadstruct;
2203 * for the color image part:
2204 * BITMAPFILEHEADER bmfh;
2205 * BITMAPINFOHEADER bmih;
2206 * only if it has a palette:
2207 * RGBQUAD rgbs[nr_of_paletted_colors];
2209 * BYTE colorbits[imagesize];
2211 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2212 * BITMAPFILEHEADER bmfh_mask;
2213 * BITMAPINFOHEADER bmih_mask;
2214 * only if it has a palette (it usually does not):
2215 * RGBQUAD rgbs[nr_of_paletted_colors];
2217 * BYTE maskbits[imagesize];
2219 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2220 * _read_bitmap needs to convert them.
2222 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2226 HBITMAP hbmColor=0,hbmMask=0;
2229 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2231 if (ilHead.usMagic != (('L' << 8) | 'I'))
2233 if (ilHead.usVersion != 0x101) /* probably version? */
2237 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2238 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2239 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2240 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2241 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2242 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2243 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2244 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2245 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2246 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2249 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2252 if (ilHead.flags & ILC_MASK) {
2253 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2255 DeleteObject(hbmColor);
2260 himl = ImageList_Create (
2268 DeleteObject(hbmColor);
2269 DeleteObject(hbmMask);
2272 himl->hbmImage = hbmColor;
2273 himl->hbmMask = hbmMask;
2274 himl->cCurImage = ilHead.cCurImage;
2275 himl->cMaxImage = ilHead.cMaxImage;
2277 ImageList_SetBkColor(himl,ilHead.bkcolor);
2279 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2284 /*************************************************************************
2285 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2288 * himl [I] image list handle
2297 ImageList_Remove (HIMAGELIST himl, INT i)
2299 HBITMAP hbmNewImage, hbmNewMask;
2303 TRACE("(himl=%p i=%d)\n", himl, i);
2306 ERR("Invalid image list handle!\n");
2310 if ((i < -1) || (i >= himl->cCurImage)) {
2311 ERR("index out of range! %d\n", i);
2317 if (himl->cCurImage == 0) {
2318 /* remove all on empty ImageList is allowed */
2319 TRACE("remove all on empty ImageList!\n");
2323 himl->cMaxImage = himl->cInitial + himl->cGrow;
2324 himl->cCurImage = 0;
2325 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2326 himl->nOvlIdx[nCount] = -1;
2328 DeleteObject (himl->hbmImage);
2330 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2331 1, himl->uBitsPixel, NULL);
2333 if (himl->hbmMask) {
2334 DeleteObject (himl->hbmMask);
2336 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2341 /* delete one image */
2342 TRACE("Remove single image! %d\n", i);
2344 /* create new bitmap(s) */
2345 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2347 TRACE(" - Number of images: %d / %d (Old/New)\n",
2348 himl->cCurImage, himl->cCurImage - 1);
2349 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2350 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2353 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2356 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2358 hbmNewMask = 0; /* Just to keep compiler happy! */
2360 hdcSrc = CreateCompatibleDC (0);
2361 hdcDst = CreateCompatibleDC (0);
2363 /* copy all images and masks prior to the "removed" image */
2365 TRACE("Pre image copy: Copy %d images\n", i);
2367 SelectObject (hdcSrc, himl->hbmImage);
2368 SelectObject (hdcDst, hbmNewImage);
2369 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2370 hdcSrc, 0, 0, SRCCOPY);
2372 if (himl->hbmMask) {
2373 SelectObject (hdcSrc, himl->hbmMask);
2374 SelectObject (hdcDst, hbmNewMask);
2375 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2376 hdcSrc, 0, 0, SRCCOPY);
2380 /* copy all images and masks behind the removed image */
2381 if (i < himl->cCurImage - 1) {
2382 TRACE("Post image copy!\n");
2383 SelectObject (hdcSrc, himl->hbmImage);
2384 SelectObject (hdcDst, hbmNewImage);
2385 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2386 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2388 if (himl->hbmMask) {
2389 SelectObject (hdcSrc, himl->hbmMask);
2390 SelectObject (hdcDst, hbmNewMask);
2391 BitBlt (hdcDst, i * himl->cx, 0,
2392 (himl->cCurImage - i - 1) * himl->cx,
2393 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2400 /* delete old images and insert new ones */
2401 DeleteObject (himl->hbmImage);
2402 himl->hbmImage = hbmNewImage;
2403 if (himl->hbmMask) {
2404 DeleteObject (himl->hbmMask);
2405 himl->hbmMask = hbmNewMask;
2409 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2416 /*************************************************************************
2417 * ImageList_Replace [COMCTL32.@]
2419 * Replaces an image in an image list with a new image.
2422 * himl [I] handle to image list
2424 * hbmImage [I] handle to image bitmap
2425 * hbmMask [I] handle to mask bitmap. Can be NULL.
2433 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2436 HDC hdcImageList, hdcImage;
2439 TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2442 ERR("Invalid image list handle!\n");
2446 if ((i >= himl->cMaxImage) || (i < 0)) {
2447 ERR("Invalid image index!\n");
2451 hdcImageList = CreateCompatibleDC (0);
2452 hdcImage = CreateCompatibleDC (0);
2453 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2456 SelectObject (hdcImageList, himl->hbmImage);
2457 SelectObject (hdcImage, hbmImage);
2459 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2460 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2465 SelectObject (hdcImageList, himl->hbmMask);
2466 SelectObject (hdcImage, hbmMask);
2468 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2469 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2472 /* Remove the background from the image
2474 SelectObject (hdcImageList, himl->hbmImage);
2475 StretchBlt (hdcImageList,
2476 i*himl->cx, 0, himl->cx, himl->cy,
2478 0, 0, bmp.bmWidth, bmp.bmHeight,
2479 0x220326); /* NOTSRCAND */
2482 DeleteDC (hdcImage);
2483 DeleteDC (hdcImageList);
2489 /*************************************************************************
2490 * ImageList_ReplaceIcon [COMCTL32.@]
2492 * Replaces an image in an image list using an icon.
2495 * himl [I] handle to image list
2497 * hIcon [I] handle to icon
2500 * Success: index of the replaced image
2505 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2507 HDC hdcImageList, hdcImage;
2510 HBITMAP hbmOldSrc, hbmOldDst;
2514 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2518 if ((i >= himl->cMaxImage) || (i < -1))
2521 hBestFitIcon = CopyImage(
2524 LR_COPYFROMRESOURCE);
2526 GetIconInfo (hBestFitIcon, &ii);
2527 if (ii.hbmMask == 0)
2529 if (ii.hbmColor == 0)
2531 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2534 if (himl->cCurImage + 1 > himl->cMaxImage)
2535 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2537 nIndex = himl->cCurImage;
2543 hdcImageList = CreateCompatibleDC (0);
2544 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2545 if (hdcImageList == 0)
2546 ERR("invalid hdcImageList!\n");
2548 hdcImage = CreateCompatibleDC (0);
2549 TRACE("hdcImage=0x%x!\n", hdcImage);
2551 ERR("invalid hdcImage!\n");
2553 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2554 SetTextColor( hdcImageList, RGB(0,0,0));
2555 SetBkColor( hdcImageList, RGB(255,255,255));
2556 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2557 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2558 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2560 if (himl->hbmMask) {
2561 SelectObject (hdcImageList, himl->hbmMask);
2562 SelectObject (hdcImage, ii.hbmMask);
2563 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2564 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2567 SelectObject (hdcImage, hbmOldSrc);
2568 SelectObject (hdcImageList, hbmOldDst);
2571 DestroyIcon(hBestFitIcon);
2573 DeleteDC (hdcImageList);
2575 DeleteDC (hdcImage);
2577 DeleteObject (ii.hbmColor);
2579 DeleteObject (ii.hbmMask);
2585 /*************************************************************************
2586 * ImageList_SetBkColor [COMCTL32.@]
2588 * Sets the background color of an image list.
2591 * himl [I] handle to image list
2592 * clrBk [I] background color
2595 * Success: previous background color
2600 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2607 clrOldBk = himl->clrBk;
2608 himl->clrBk = clrBk;
2613 /*************************************************************************
2614 * ImageList_SetDragCursorImage [COMCTL32.@]
2616 * Combines the specified image with the current drag image
2619 * himlDrag [I] handle to drag image list
2620 * iDrag [I] drag image index
2621 * dxHotspot [I] X position of the hot spot
2622 * dyHotspot [I] Y position of the hot spot
2629 * When this function is called and the drag image is visible, a
2630 * short flickering occurs but this matches the Win9x behavior. It is
2631 * possible to fix the flickering using code like in ImageList_DragMove.
2635 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2636 INT dxHotspot, INT dyHotspot)
2638 HIMAGELIST himlTemp;
2642 if (InternalDrag.himl == NULL)
2645 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2646 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2648 visible = InternalDrag.bShow;
2650 /* Calculate the offset between the origin of the old image and the
2651 * origin of the second image.
2652 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2653 * hotspot) to the origin of the second image.
2654 * See M$DN for details */
2655 if(InternalDrag.bHSPending) {
2658 InternalDrag.bHSPending = FALSE;
2660 dx = InternalDrag.dxHotspot - dxHotspot;
2661 dy = InternalDrag.dyHotspot - dyHotspot;
2663 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2666 /* hide the drag image */
2667 ImageList_DragShowNolock(FALSE);
2669 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2670 (InternalDrag.himl->cy != himlTemp->cy)) {
2671 /* the size of the drag image changed, invalidate the buffer */
2672 DeleteObject(InternalDrag.hbmBg);
2673 InternalDrag.hbmBg = 0;
2676 ImageList_Destroy (InternalDrag.himl);
2677 InternalDrag.himl = himlTemp;
2679 /* update the InternalDragOffset, if the origin of the
2680 * DragImage was changed by ImageList_Merge. */
2682 InternalDrag.dxHotspot = dxHotspot;
2684 InternalDrag.dyHotspot = dyHotspot;
2687 /* show the drag image */
2688 ImageList_DragShowNolock(TRUE);
2695 /*************************************************************************
2696 * ImageList_SetFilter [COMCTL32.@]
2698 * Sets a filter (or does something completely different)!!???
2701 * himl [I] handle to image list
2707 * Failure: FALSE ???
2710 * This is an UNDOCUMENTED function!!!!
2715 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2717 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2724 /*************************************************************************
2725 * ImageList_SetFlags [COMCTL32.@]
2732 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2734 FIXME("(%p %08lx):empty stub\n", himl, flags);
2739 /*************************************************************************
2740 * ImageList_SetIconSize [COMCTL32.@]
2742 * Sets the image size of the bitmap and deletes all images.
2745 * himl [I] handle to image list
2746 * cx [I] image width
2747 * cy [I] image height
2755 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2762 /* remove all images */
2763 himl->cMaxImage = himl->cInitial + himl->cGrow;
2764 himl->cCurImage = 0;
2768 /* initialize overlay mask indices */
2769 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2770 himl->nOvlIdx[nCount] = -1;
2772 DeleteObject (himl->hbmImage);
2774 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2775 1, himl->uBitsPixel, NULL);
2777 if (himl->hbmMask) {
2778 DeleteObject (himl->hbmMask);
2780 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2788 /*************************************************************************
2789 * ImageList_SetImageCount [COMCTL32.@]
2791 * Resizes an image list to the specified number of images.
2794 * himl [I] handle to image list
2795 * iImageCount [I] number of images in the image list
2803 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2805 HDC hdcImageList, hdcBitmap;
2806 HBITMAP hbmNewBitmap;
2807 INT nNewCount, nCopyCount;
2809 TRACE("%p %d\n",himl,iImageCount);
2813 if (himl->cCurImage >= iImageCount)
2815 if (himl->cMaxImage > iImageCount)
2817 himl->cCurImage = iImageCount;
2821 nNewCount = iImageCount + himl->cGrow;
2822 nCopyCount = min(himl->cCurImage, iImageCount);
2824 hdcImageList = CreateCompatibleDC (0);
2825 hdcBitmap = CreateCompatibleDC (0);
2827 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2828 1, himl->uBitsPixel, NULL);
2829 if (hbmNewBitmap != 0)
2831 SelectObject (hdcImageList, himl->hbmImage);
2832 SelectObject (hdcBitmap, hbmNewBitmap);
2835 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2836 hdcImageList, 0, 0, SRCCOPY);
2838 /* delete 'empty' image space */
2839 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2840 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2841 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2842 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2844 DeleteObject (himl->hbmImage);
2845 himl->hbmImage = hbmNewBitmap;
2848 ERR("Could not create new image bitmap !\n");
2852 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2854 if (hbmNewBitmap != 0)
2856 SelectObject (hdcImageList, himl->hbmMask);
2857 SelectObject (hdcBitmap, hbmNewBitmap);
2860 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2861 hdcImageList, 0, 0, SRCCOPY);
2863 /* delete 'empty' image space */
2864 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2865 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2866 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2867 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2869 DeleteObject (himl->hbmMask);
2870 himl->hbmMask = hbmNewBitmap;
2873 ERR("Could not create new mask bitmap!\n");
2876 DeleteDC (hdcImageList);
2877 DeleteDC (hdcBitmap);
2879 /* Update max image count and current image count */
2880 himl->cMaxImage = nNewCount;
2881 himl->cCurImage = iImageCount;
2887 /*************************************************************************
2888 * ImageList_SetOverlayImage [COMCTL32.@]
2890 * Assigns an overlay mask index to an existing image in an image list.
2893 * himl [I] handle to image list
2894 * iImage [I] image index
2895 * iOverlay [I] overlay mask index
2903 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2907 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2909 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2911 himl->nOvlIdx[iOverlay - 1] = iImage;
2917 /* helper for ImageList_Write - write bitmap to pstm
2918 * currently everything is written as 24 bit RGB, except masks
2921 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2923 LPBITMAPFILEHEADER bmfh;
2924 LPBITMAPINFOHEADER bmih;
2925 LPBYTE data, lpBits, lpBitsOrg;
2927 INT bitCount, sizeImage, offBits, totalSize;
2928 INT nwidth, nheight, nsizeImage, icount;
2930 BOOL result = FALSE;
2934 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2936 /* XXX is this always correct? */
2937 icount = bm.bmWidth / cx;
2939 nheight = cy * ((icount+3)>>2);
2941 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2942 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2943 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2945 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2947 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2948 offBits = totalSize;
2949 totalSize += nsizeImage;
2951 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2952 bmfh = (LPBITMAPFILEHEADER)data;
2953 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2954 lpBits = data + offBits;
2956 /* setup BITMAPFILEHEADER */
2957 bmfh->bfType = (('M' << 8) | 'B');
2959 bmfh->bfReserved1 = 0;
2960 bmfh->bfReserved2 = 0;
2961 bmfh->bfOffBits = offBits;
2963 /* setup BITMAPINFOHEADER */
2964 bmih->biSize = sizeof(BITMAPINFOHEADER);
2965 bmih->biWidth = bm.bmWidth;
2966 bmih->biHeight = bm.bmHeight;
2968 bmih->biBitCount = bitCount;
2969 bmih->biCompression = BI_RGB;
2970 bmih->biSizeImage = nsizeImage;
2971 bmih->biXPelsPerMeter = 0;
2972 bmih->biYPelsPerMeter = 0;
2973 bmih->biClrUsed = 0;
2974 bmih->biClrImportant = 0;
2976 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2977 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2978 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2982 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2983 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2985 for(i = 0; i < nheight; i++) {
2986 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2987 int noff = (nbpl * (nheight-1-i));
2988 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2992 bmih->biWidth = nwidth;
2993 bmih->biHeight = nheight;
2997 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2998 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2999 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
3002 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
3009 LocalFree((HLOCAL)lpBitsOrg);
3015 /*************************************************************************
3016 * ImageList_Write [COMCTL32.@]
3018 * Writes an image list to a stream.
3021 * himl [I] handle to image list
3022 * pstm [O] Pointer to a stream.
3033 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
3041 ilHead.usMagic = (('L' << 8) | 'I');
3042 ilHead.usVersion = 0x101;
3043 ilHead.cCurImage = himl->cCurImage;
3044 ilHead.cMaxImage = himl->cMaxImage;
3045 ilHead.cGrow = himl->cGrow;
3046 ilHead.cx = himl->cx;
3047 ilHead.cy = himl->cy;
3048 ilHead.bkcolor = himl->clrBk;
3049 ilHead.flags = himl->flags;
3050 for(i = 0; i < 4; i++) {
3051 ilHead.ovls[i] = himl->nOvlIdx[i];
3054 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3057 /* write the bitmap */
3058 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3061 /* write the mask if we have one */
3062 if(himl->flags & ILC_MASK) {
3063 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))