2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001, 2004 Michael Stefaniuc
7 * Copyright 2001 Charles Loep for CodeWeavers
8 * Copyright 2002 Dimitrie O. Paun
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * This code was audited for completeness against the documented features
27 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 * Unless otherwise noted, we believe this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
36 * - Thread-safe locking
53 #include "imagelist.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
59 #define MAX_OVERLAYIMAGE 15
61 /* internal image list data used for Drag & Drop operations */
66 /* position of the drag image relative to the window */
69 /* offset of the hotspot relative to the origin of the image */
72 /* is the drag image visible */
74 /* saved background */
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
80 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height);
82 static inline BOOL is_valid(HIMAGELIST himl)
84 return himl && himl->magic == IMAGELIST_MAGIC;
88 /*************************************************************************
89 * IMAGELIST_InternalExpandBitmaps [Internal]
91 * Expands the bitmaps of an image list by the given number of images.
94 * himl [I] handle to image list
95 * nImageCount [I] number of images to add
101 * This function can NOT be used to reduce the number of images.
104 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
107 HBITMAP hbmNewBitmap, hbmNull;
108 INT nNewWidth, nNewCount;
110 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
114 if (cy == 0) cy = himl->cy;
115 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
116 nNewWidth = nNewCount * himl->cx;
118 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
119 hdcBitmap = CreateCompatibleDC (0);
121 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy);
123 if (hbmNewBitmap == 0)
124 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
128 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
129 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
130 himl->hdcImage, 0, 0, SRCCOPY);
131 SelectObject (hdcBitmap, hbmNull);
133 SelectObject (himl->hdcImage, hbmNewBitmap);
134 DeleteObject (himl->hbmImage);
135 himl->hbmImage = hbmNewBitmap;
137 if (himl->flags & ILC_MASK)
139 hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL);
141 if (hbmNewBitmap == 0)
142 ERR("creating new mask bitmap!\n");
146 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
147 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
148 himl->hdcMask, 0, 0, SRCCOPY);
149 SelectObject (hdcBitmap, hbmNull);
151 SelectObject (himl->hdcMask, hbmNewBitmap);
152 DeleteObject (himl->hbmMask);
153 himl->hbmMask = hbmNewBitmap;
156 himl->cMaxImage = nNewCount;
158 DeleteDC (hdcBitmap);
162 /*************************************************************************
163 * ImageList_Add [COMCTL32.@]
165 * Add an image or images to an image list.
168 * himl [I] handle to image list
169 * hbmImage [I] handle to image bitmap
170 * hbmMask [I] handle to mask bitmap
173 * Success: Index of the first new image.
178 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
181 INT nFirstIndex, nImageCount;
186 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
190 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
191 nImageCount = bmp.bmWidth / himl->cx;
193 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
195 nStartX = himl->cCurImage * himl->cx;
197 hdcBitmap = CreateCompatibleDC(0);
199 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
201 /* Copy result to the imagelist
203 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
204 hdcBitmap, 0, 0, SRCCOPY);
209 HBITMAP hOldBitmapTemp;
211 hdcTemp = CreateCompatibleDC(0);
212 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
214 BitBlt (himl->hdcMask,
215 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
220 SelectObject(hdcTemp, hOldBitmapTemp);
223 /* Remove the background from the image
225 BitBlt (himl->hdcImage,
226 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
229 0x220326); /* NOTSRCAND */
232 SelectObject(hdcBitmap, hOldBitmap);
235 nFirstIndex = himl->cCurImage;
236 himl->cCurImage += nImageCount;
242 /*************************************************************************
243 * ImageList_AddIcon [COMCTL32.@]
245 * Adds an icon to an image list.
248 * himl [I] handle to image list
249 * hIcon [I] handle to icon
252 * Success: index of the new image
255 #undef ImageList_AddIcon
256 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
258 return ImageList_ReplaceIcon (himl, -1, hIcon);
262 /*************************************************************************
263 * ImageList_AddMasked [COMCTL32.@]
265 * Adds an image or images to an image list and creates a mask from the
266 * specified bitmap using the mask color.
269 * himl [I] handle to image list.
270 * hBitmap [I] handle to bitmap
271 * clrMask [I] mask color.
274 * Success: Index of the first new image.
279 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
281 HDC hdcMask, hdcBitmap;
282 INT nIndex, nImageCount, nMaskXOffset=0;
285 HBITMAP hMaskBitmap=0;
288 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
292 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
296 nImageCount = bmp.bmWidth / himl->cx;
300 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
302 nIndex = himl->cCurImage;
303 himl->cCurImage += nImageCount;
305 hdcBitmap = CreateCompatibleDC(0);
308 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
311 hdcMask = himl->hdcMask;
312 nMaskXOffset = nIndex * himl->cx;
317 Create a temp Mask so we can remove the background of
318 the Image (Windows does this even if there is no mask)
320 hdcMask = CreateCompatibleDC(0);
321 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
322 SelectObject(hdcMask, hMaskBitmap);
325 /* create monochrome image to the mask bitmap */
326 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
327 GetPixel (hdcBitmap, 0, 0);
328 SetBkColor (hdcBitmap, bkColor);
330 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
334 SetBkColor(hdcBitmap, RGB(255,255,255));
335 /*Remove the background from the image
338 WINDOWS BUG ALERT!!!!!!
339 The statement below should not be done in common practice
340 but this is how ImageList_AddMasked works in Windows.
341 It overwrites the original bitmap passed, this was discovered
342 by using the same bitmap to iterate the different styles
343 on windows where it failed (BUT ImageList_Add is OK)
344 This is here in case some apps rely on this bug
347 0, 0, bmp.bmWidth, bmp.bmHeight,
350 0x220326); /* NOTSRCAND */
351 /* Copy result to the imagelist
353 BitBlt (himl->hdcImage,
354 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
360 SelectObject(hdcBitmap, hOldBitmap);
364 DeleteObject(hMaskBitmap);
372 /*************************************************************************
373 * ImageList_BeginDrag [COMCTL32.@]
375 * Creates a temporary image list that contains one image. It will be used
379 * himlTrack [I] handle to the source image list
380 * iTrack [I] index of the drag image in the source image list
381 * dxHotspot [I] X position of the hot spot of the drag image
382 * dyHotspot [I] Y position of the hot spot of the drag image
390 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
391 INT dxHotspot, INT dyHotspot)
395 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
396 dxHotspot, dyHotspot);
398 if (!is_valid(himlTrack))
401 if (InternalDrag.himl)
402 ImageList_EndDrag ();
407 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
408 if (InternalDrag.himl == NULL) {
409 WARN("Error creating drag image list!\n");
413 InternalDrag.dxHotspot = dxHotspot;
414 InternalDrag.dyHotspot = dyHotspot;
417 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
420 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
422 InternalDrag.himl->cCurImage = 1;
428 /*************************************************************************
429 * ImageList_Copy [COMCTL32.@]
431 * Copies an image of the source image list to an image of the
432 * destination image list. Images can be copied or swapped.
435 * himlDst [I] handle to the destination image list
436 * iDst [I] destination image index.
437 * himlSrc [I] handle to the source image list
438 * iSrc [I] source image index
439 * uFlags [I] flags for the copy operation
446 * Copying from one image list to another is possible. The original
447 * implementation just copies or swaps within one image list.
448 * Could this feature become a bug??? ;-)
452 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
453 INT iSrc, UINT uFlags)
455 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
457 if (!is_valid(himlSrc) || !is_valid(himlDst))
459 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
461 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
464 if (uFlags & ILCF_SWAP) {
467 HBITMAP hbmTempImage, hbmTempMask;
469 hdcBmp = CreateCompatibleDC (0);
471 /* create temporary bitmaps */
472 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
473 himlSrc->uBitsPixel, NULL);
474 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
477 /* copy (and stretch) destination to temporary bitmaps.(save) */
479 SelectObject (hdcBmp, hbmTempImage);
480 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
481 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
484 SelectObject (hdcBmp, hbmTempMask);
485 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
486 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
489 /* copy (and stretch) source to destination */
491 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
492 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
495 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
496 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
499 /* copy (without stretching) temporary bitmaps to source (restore) */
501 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
502 hdcBmp, 0, 0, SRCCOPY);
505 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
506 hdcBmp, 0, 0, SRCCOPY);
507 /* delete temporary bitmaps */
508 DeleteObject (hbmTempMask);
509 DeleteObject (hbmTempImage);
514 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
515 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
519 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
520 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
528 /*************************************************************************
529 * ImageList_Create [COMCTL32.@]
531 * Creates a new image list.
534 * cx [I] image height
536 * flags [I] creation flags
537 * cInitial [I] initial number of images in the image list
538 * cGrow [I] number of images by which image list grows
541 * Success: Handle to the created image list
545 ImageList_Create (INT cx, INT cy, UINT flags,
546 INT cInitial, INT cGrow)
551 UINT ilc = (flags & 0xFE);
552 static const WORD aBitBlend25[] =
553 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
555 static const WORD aBitBlend50[] =
556 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
558 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
560 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
564 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
566 himl->magic = IMAGELIST_MAGIC;
570 himl->cMaxImage = cInitial + cGrow;
571 himl->cInitial = cInitial;
573 himl->clrFg = CLR_DEFAULT;
574 himl->clrBk = CLR_NONE;
576 /* initialize overlay mask indices */
577 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
578 himl->nOvlIdx[nCount] = -1;
580 /* Create Image & Mask DCs */
581 himl->hdcImage = CreateCompatibleDC (0);
584 if (himl->flags & ILC_MASK){
585 himl->hdcMask = CreateCompatibleDC(0);
590 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
591 if (ilc == ILC_COLOR)
594 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
595 himl->uBitsPixel = ilc;
597 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
599 if (himl->cMaxImage > 0) {
600 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy);
601 SelectObject(himl->hdcImage, himl->hbmImage);
605 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
607 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
609 if (himl->hbmMask == 0) {
610 ERR("Error creating mask bitmap!\n");
613 SelectObject(himl->hdcMask, himl->hbmMask);
616 /* create blending brushes */
617 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
618 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
619 DeleteObject (hbmTemp);
621 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
622 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
623 DeleteObject (hbmTemp);
625 TRACE("created imagelist %p\n", himl);
629 if (himl) ImageList_Destroy(himl);
634 /*************************************************************************
635 * ImageList_Destroy [COMCTL32.@]
637 * Destroys an image list.
640 * himl [I] handle to image list
648 ImageList_Destroy (HIMAGELIST himl)
653 /* delete image bitmaps */
655 DeleteObject (himl->hbmImage);
657 DeleteObject (himl->hbmMask);
659 /* delete image & mask DCs */
661 DeleteDC(himl->hdcImage);
663 DeleteDC(himl->hdcMask);
665 /* delete blending brushes */
666 if (himl->hbrBlend25)
667 DeleteObject (himl->hbrBlend25);
668 if (himl->hbrBlend50)
669 DeleteObject (himl->hbrBlend50);
671 ZeroMemory(himl, sizeof(*himl));
678 /*************************************************************************
679 * ImageList_DragEnter [COMCTL32.@]
681 * Locks window update and displays the drag image at the given position.
684 * hwndLock [I] handle of the window that owns the drag image.
685 * x [I] X position of the drag image.
686 * y [I] Y position of the drag image.
693 * The position of the drag image is relative to the window, not
698 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
700 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
702 if (!is_valid(InternalDrag.himl))
706 InternalDrag.hwnd = hwndLock;
708 InternalDrag.hwnd = GetDesktopWindow ();
713 /* draw the drag image and save the background */
714 if (!ImageList_DragShowNolock(TRUE)) {
722 /*************************************************************************
723 * ImageList_DragLeave [COMCTL32.@]
725 * Unlocks window update and hides the drag image.
728 * hwndLock [I] handle of the window that owns the drag image.
736 ImageList_DragLeave (HWND hwndLock)
738 /* As we don't save drag info in the window this can lead to problems if
739 an app does not supply the same window as DragEnter */
741 InternalDrag.hwnd = hwndLock;
743 InternalDrag.hwnd = GetDesktopWindow (); */
745 hwndLock = GetDesktopWindow();
746 if(InternalDrag.hwnd != hwndLock)
747 FIXME("DragLeave hWnd != DragEnter hWnd\n");
749 ImageList_DragShowNolock (FALSE);
755 /*************************************************************************
756 * ImageList_InternalDragDraw [Internal]
758 * Draws the drag image.
761 * hdc [I] device context to draw into.
762 * x [I] X position of the drag image.
763 * y [I] Y position of the drag image.
770 * The position of the drag image is relative to the window, not
776 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
778 IMAGELISTDRAWPARAMS imldp;
780 ZeroMemory (&imldp, sizeof(imldp));
781 imldp.cbSize = sizeof(imldp);
782 imldp.himl = InternalDrag.himl;
787 imldp.rgbBk = CLR_DEFAULT;
788 imldp.rgbFg = CLR_DEFAULT;
789 imldp.fStyle = ILD_NORMAL;
790 imldp.fState = ILS_ALPHA;
793 /* FIXME: instead of using the alpha blending, we should
794 * create a 50% mask, and draw it semitransparantly that way */
795 ImageList_DrawIndirect (&imldp);
798 /*************************************************************************
799 * ImageList_DragMove [COMCTL32.@]
801 * Moves the drag image.
804 * x [I] X position of the drag image.
805 * y [I] Y position of the drag image.
812 * The position of the drag image is relative to the window, not
816 * The drag image should be drawn semitransparent.
820 ImageList_DragMove (INT x, INT y)
822 TRACE("(x=%d y=%d)\n", x, y);
824 if (!is_valid(InternalDrag.himl))
827 /* draw/update the drag image */
828 if (InternalDrag.bShow) {
832 HBITMAP hbmOffScreen;
833 INT origNewX, origNewY;
834 INT origOldX, origOldY;
835 INT origRegX, origRegY;
836 INT sizeRegX, sizeRegY;
839 /* calculate the update region */
840 origNewX = x - InternalDrag.dxHotspot;
841 origNewY = y - InternalDrag.dyHotspot;
842 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
843 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
844 origRegX = min(origNewX, origOldX);
845 origRegY = min(origNewY, origOldY);
846 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
847 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
849 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
850 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
851 hdcOffScreen = CreateCompatibleDC(hdcDrag);
852 hdcBg = CreateCompatibleDC(hdcDrag);
854 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
855 SelectObject(hdcOffScreen, hbmOffScreen);
856 SelectObject(hdcBg, InternalDrag.hbmBg);
858 /* get the actual background of the update region */
859 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
860 origRegX, origRegY, SRCCOPY);
861 /* erase the old image */
862 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
863 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
865 /* save the background */
866 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
867 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
869 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
870 origNewY - origRegY);
871 /* draw the update region to the screen */
872 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
873 hdcOffScreen, 0, 0, SRCCOPY);
876 DeleteDC(hdcOffScreen);
877 DeleteObject(hbmOffScreen);
878 ReleaseDC(InternalDrag.hwnd, hdcDrag);
881 /* update the image position */
889 /*************************************************************************
890 * ImageList_DragShowNolock [COMCTL32.@]
892 * Shows or hides the drag image.
895 * bShow [I] TRUE shows the drag image, FALSE hides it.
902 * The drag image should be drawn semitransparent.
906 ImageList_DragShowNolock (BOOL bShow)
912 if (!is_valid(InternalDrag.himl))
915 TRACE("bShow=0x%X!\n", bShow);
917 /* DragImage is already visible/hidden */
918 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
922 /* position of the origin of the DragImage */
923 x = InternalDrag.x - InternalDrag.dxHotspot;
924 y = InternalDrag.y - InternalDrag.dyHotspot;
926 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
927 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
932 hdcBg = CreateCompatibleDC(hdcDrag);
933 if (!InternalDrag.hbmBg) {
934 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
935 InternalDrag.himl->cx, InternalDrag.himl->cy);
937 SelectObject(hdcBg, InternalDrag.hbmBg);
940 /* save the background */
941 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
942 hdcDrag, x, y, SRCCOPY);
944 ImageList_InternalDragDraw(hdcDrag, x, y);
947 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
948 hdcBg, 0, 0, SRCCOPY);
951 InternalDrag.bShow = !InternalDrag.bShow;
954 ReleaseDC (InternalDrag.hwnd, hdcDrag);
959 /*************************************************************************
960 * ImageList_Draw [COMCTL32.@]
965 * himl [I] handle to image list
967 * hdc [I] handle to device context
970 * fStyle [I] drawing flags
981 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
983 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
984 CLR_DEFAULT, CLR_DEFAULT, fStyle);
988 /*************************************************************************
989 * ImageList_DrawEx [COMCTL32.@]
991 * Draws an image and allows to use extended drawing features.
994 * himl [I] handle to image list
996 * hdc [I] handle to device context
1001 * rgbBk [I] background color
1002 * rgbFg [I] foreground color
1003 * fStyle [I] drawing flags
1010 * Calls ImageList_DrawIndirect.
1013 * ImageList_DrawIndirect.
1017 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1018 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1021 IMAGELISTDRAWPARAMS imldp;
1023 ZeroMemory (&imldp, sizeof(imldp));
1024 imldp.cbSize = sizeof(imldp);
1032 imldp.rgbBk = rgbBk;
1033 imldp.rgbFg = rgbFg;
1034 imldp.fStyle = fStyle;
1036 return ImageList_DrawIndirect (&imldp);
1040 /*************************************************************************
1041 * ImageList_DrawIndirect [COMCTL32.@]
1043 * Draws an image using various parameters specified in pimldp.
1046 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1054 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1056 INT cx, cy, lx, ly, nOvlIdx;
1057 DWORD fState, dwRop;
1059 COLORREF clrBk, oldImageBk, oldImageFg;
1060 HDC hImageDC, hImageListDC, hMaskListDC;
1061 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1062 BOOL bIsTransparent, bBlend, bResult = FALSE;
1065 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1066 if (!is_valid(himl)) return FALSE;
1067 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1069 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1070 ly = pimldp->yBitmap;
1072 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1073 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1074 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1075 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1076 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1077 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1078 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1080 TRACE("himl(0x%lx) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1081 (DWORD)himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1083 /* we will use these DCs to access the images and masks in the ImageList */
1084 hImageListDC = himl->hdcImage;
1085 hMaskListDC = himl->hdcMask;
1087 /* these will accumulate the image and mask for the image we're drawing */
1088 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1089 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1090 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1092 /* Create a compatible DC. */
1093 if (!hImageListDC || !hImageDC || !hImageBmp ||
1094 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1097 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1100 * To obtain a transparent look, background color should be set
1101 * to white and foreground color to black when blting the
1104 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1105 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1108 * Draw the initial image
1110 if (fStyle & ILD_MASK) {
1111 if (himl->hbmMask) {
1112 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1114 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1115 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1116 SelectObject(hImageDC, hOldBrush);
1118 } else if (himl->hbmMask && !bIsTransparent) {
1119 /* blend the image with the needed solid background */
1120 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1121 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1122 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1123 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1124 DeleteObject (SelectObject (hImageDC, hOldBrush));
1126 /* start off with the image, if we have a mask, we'll use it later */
1127 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1130 /* Time for blending, if required */
1132 HBRUSH hBlendBrush, hOldBrush;
1133 COLORREF clrBlend = pimldp->rgbFg;
1134 HDC hBlendMaskDC = hImageListDC;
1137 /* Create the blend Mask */
1138 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1139 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1140 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1141 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1142 SelectObject(hBlendMaskDC, hOldBrush);
1144 /* Modify the blend mask if an Image Mask exist */
1146 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1147 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1150 /* now apply blend to the current image given the BlendMask */
1151 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1152 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1153 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1154 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1155 DeleteObject(SelectObject(hImageDC, hOldBrush));
1156 SelectObject(hBlendMaskDC, hOldBitmap);
1159 /* Now do the overlay image, if any */
1160 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1161 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1162 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1163 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1164 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1165 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1166 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1167 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1171 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1172 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1173 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1174 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1176 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1177 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1178 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1180 /* now copy the image to the screen */
1182 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1183 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1184 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1185 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1186 SetBkColor(pimldp->hdcDst, oldDstBk);
1187 SetTextColor(pimldp->hdcDst, oldDstFg);
1190 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1191 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1195 /* cleanup the mess */
1196 SetBkColor(hImageDC, oldImageBk);
1197 SetTextColor(hImageDC, oldImageFg);
1198 SelectObject(hImageDC, hOldImageBmp);
1200 DeleteObject(hBlendMaskBmp);
1201 DeleteObject(hImageBmp);
1208 /*************************************************************************
1209 * ImageList_Duplicate [COMCTL32.@]
1211 * Duplicates an image list.
1214 * himlSrc [I] source image list handle
1217 * Success: Handle of duplicated image list.
1222 ImageList_Duplicate (HIMAGELIST himlSrc)
1226 if (!is_valid(himlSrc)) {
1227 ERR("Invalid image list handle!\n");
1231 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1232 himlSrc->cInitial, himlSrc->cGrow);
1236 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1237 himlSrc->hdcImage, 0, 0, SRCCOPY);
1239 if (himlDst->hbmMask)
1240 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1241 himlSrc->hdcMask, 0, 0, SRCCOPY);
1243 himlDst->cCurImage = himlSrc->cCurImage;
1244 himlDst->cMaxImage = himlSrc->cMaxImage;
1250 /*************************************************************************
1251 * ImageList_EndDrag [COMCTL32.@]
1253 * Finishes a drag operation.
1264 ImageList_EndDrag (void)
1266 /* cleanup the InternalDrag struct */
1267 InternalDrag.hwnd = 0;
1268 ImageList_Destroy (InternalDrag.himl);
1269 InternalDrag.himl = 0;
1272 InternalDrag.dxHotspot = 0;
1273 InternalDrag.dyHotspot = 0;
1274 InternalDrag.bShow = FALSE;
1275 DeleteObject(InternalDrag.hbmBg);
1276 InternalDrag.hbmBg = 0;
1280 /*************************************************************************
1281 * ImageList_GetBkColor [COMCTL32.@]
1283 * Returns the background color of an image list.
1286 * himl [I] Image list handle.
1289 * Success: background color
1294 ImageList_GetBkColor (HIMAGELIST himl)
1296 return himl ? himl->clrBk : CLR_NONE;
1300 /*************************************************************************
1301 * ImageList_GetDragImage [COMCTL32.@]
1303 * Returns the handle to the internal drag image list.
1306 * ppt [O] Pointer to the drag position. Can be NULL.
1307 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1310 * Success: Handle of the drag image list.
1315 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1317 if (is_valid(InternalDrag.himl)) {
1319 ppt->x = InternalDrag.x;
1320 ppt->y = InternalDrag.y;
1323 pptHotspot->x = InternalDrag.dxHotspot;
1324 pptHotspot->y = InternalDrag.dyHotspot;
1326 return (InternalDrag.himl);
1333 /*************************************************************************
1334 * ImageList_GetFlags [COMCTL32.@]
1336 * Gets the flags of the specified image list.
1339 * himl [I] Handle to image list
1349 ImageList_GetFlags(HIMAGELIST himl)
1351 FIXME("(%p):empty stub\n", himl);
1356 /*************************************************************************
1357 * ImageList_GetIcon [COMCTL32.@]
1359 * Creates an icon from a masked image of an image list.
1362 * himl [I] handle to image list
1364 * flags [I] drawing style flags
1367 * Success: icon handle
1372 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1376 HBITMAP hOldDstBitmap;
1379 TRACE("%p %d %d\n", himl, i, fStyle);
1380 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1382 hdcDst = CreateCompatibleDC(0);
1389 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1390 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1391 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1392 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1395 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1396 SelectObject (hdcDst, ii.hbmColor);
1397 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1398 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1401 * CreateIconIndirect requires us to deselect the bitmaps from
1402 * the DCs before calling
1404 SelectObject(hdcDst, hOldDstBitmap);
1406 hIcon = CreateIconIndirect (&ii);
1408 DeleteObject (ii.hbmMask);
1409 DeleteObject (ii.hbmColor);
1416 /*************************************************************************
1417 * ImageList_GetIconSize [COMCTL32.@]
1419 * Retrieves the size of an image in an image list.
1422 * himl [I] handle to image list
1423 * cx [O] pointer to the image width.
1424 * cy [O] pointer to the image height.
1431 * All images in an image list have the same size.
1435 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1437 if (!is_valid(himl))
1439 if ((himl->cx <= 0) || (himl->cy <= 0))
1451 /*************************************************************************
1452 * ImageList_GetImageCount [COMCTL32.@]
1454 * Returns the number of images in an image list.
1457 * himl [I] handle to image list
1460 * Success: Number of images.
1465 ImageList_GetImageCount (HIMAGELIST himl)
1467 if (!is_valid(himl))
1470 return himl->cCurImage;
1474 /*************************************************************************
1475 * ImageList_GetImageInfo [COMCTL32.@]
1477 * Returns information about an image in an image list.
1480 * himl [I] handle to image list
1482 * pImageInfo [O] pointer to the image information
1490 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1492 if (!is_valid(himl) || (pImageInfo == NULL))
1494 if ((i < 0) || (i >= himl->cCurImage))
1497 pImageInfo->hbmImage = himl->hbmImage;
1498 pImageInfo->hbmMask = himl->hbmMask;
1500 pImageInfo->rcImage.top = 0;
1501 pImageInfo->rcImage.bottom = himl->cy;
1502 pImageInfo->rcImage.left = i * himl->cx;
1503 pImageInfo->rcImage.right = (i+1) * himl->cx;
1509 /*************************************************************************
1510 * ImageList_GetImageRect [COMCTL32.@]
1512 * Retrieves the rectangle of the specified image in an image list.
1515 * himl [I] handle to image list
1517 * lpRect [O] pointer to the image rectangle
1524 * This is an UNDOCUMENTED function!!!
1528 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1530 if (!is_valid(himl) || (lpRect == NULL))
1532 if ((i < 0) || (i >= himl->cCurImage))
1535 lpRect->left = i * himl->cx;
1537 lpRect->right = lpRect->left + himl->cx;
1538 lpRect->bottom = himl->cy;
1544 /*************************************************************************
1545 * ImageList_LoadImage [COMCTL32.@]
1546 * ImageList_LoadImageA [COMCTL32.@]
1548 * Creates an image list from a bitmap, icon or cursor.
1551 * hi [I] instance handle
1552 * lpbmp [I] name or id of the image
1553 * cx [I] width of each image
1554 * cGrow [I] number of images to expand
1555 * clrMask [I] mask color
1556 * uType [I] type of image to load
1557 * uFlags [I] loading flags
1560 * Success: handle to the loaded image list
1568 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1569 COLORREF clrMask, UINT uType, UINT uFlags)
1571 HIMAGELIST himl = NULL;
1575 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1577 ERR("Error loading image!\n");
1581 if (uType == IMAGE_BITMAP) {
1583 GetObjectA (handle, sizeof(BITMAP), &bmp);
1585 /* To match windows behavior, if cx is set to zero and
1586 the flag DI_DEFAULTSIZE is specified, cx becomes the
1587 system metric value for icons. If the flag is not specified
1588 the function sets the size to the height of the bitmap */
1591 if (uFlags & DI_DEFAULTSIZE)
1592 cx = GetSystemMetrics (SM_CXICON);
1597 nImageCount = bmp.bmWidth / cx;
1599 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1600 nImageCount, cGrow);
1602 DeleteObject (handle);
1605 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1607 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1611 GetIconInfo (handle, &ii);
1612 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1613 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1614 ILC_MASK | ILC_COLOR, 1, cGrow);
1616 DeleteObject (ii.hbmColor);
1617 DeleteObject (ii.hbmMask);
1618 DeleteObject (handle);
1621 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1622 DeleteObject (ii.hbmColor);
1623 DeleteObject (ii.hbmMask);
1626 DeleteObject (handle);
1632 /*************************************************************************
1633 * ImageList_LoadImageW [COMCTL32.@]
1635 * Creates an image list from a bitmap, icon or cursor.
1638 * hi [I] instance handle
1639 * lpbmp [I] name or id of the image
1640 * cx [I] width of each image
1641 * cGrow [I] number of images to expand
1642 * clrMask [I] mask color
1643 * uType [I] type of image to load
1644 * uFlags [I] loading flags
1647 * Success: handle to the loaded image list
1655 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1656 COLORREF clrMask, UINT uType, UINT uFlags)
1658 HIMAGELIST himl = NULL;
1662 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1664 ERR("Error loading image!\n");
1668 if (uType == IMAGE_BITMAP) {
1670 GetObjectW (handle, sizeof(BITMAP), &bmp);
1672 /* To match windows behavior, if cx is set to zero and
1673 the flag DI_DEFAULTSIZE is specified, cx becomes the
1674 system metric value for icons. If the flag is not specified
1675 the function sets the size to the height of the bitmap */
1678 if (uFlags & DI_DEFAULTSIZE)
1679 cx = GetSystemMetrics (SM_CXICON);
1684 nImageCount = bmp.bmWidth / cx;
1686 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1687 nImageCount, cGrow);
1689 DeleteObject (handle);
1692 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1694 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1698 GetIconInfo (handle, &ii);
1699 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1700 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1701 ILC_MASK | ILC_COLOR, 1, cGrow);
1703 DeleteObject (ii.hbmColor);
1704 DeleteObject (ii.hbmMask);
1705 DeleteObject (handle);
1708 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1709 DeleteObject (ii.hbmColor);
1710 DeleteObject (ii.hbmMask);
1713 DeleteObject (handle);
1719 /*************************************************************************
1720 * ImageList_Merge [COMCTL32.@]
1722 * Create an image list containing a merged image from two image lists.
1725 * himl1 [I] handle to first image list
1726 * i1 [I] first image index
1727 * himl2 [I] handle to second image list
1728 * i2 [I] second image index
1729 * dx [I] X offset of the second image relative to the first.
1730 * dy [I] Y offset of the second image relative to the first.
1733 * Success: The newly created image list. It contains a single image
1734 * consisting of the second image merged with the first.
1735 * Failure: NULL, if either himl1 or himl2 are invalid.
1738 * - The returned image list should be deleted by the caller using
1739 * ImageList_Destroy() when it is no longer required.
1740 * - If either i1 or i2 are not valid image indices they will be treated
1744 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1747 HIMAGELIST himlDst = NULL;
1749 INT xOff1, yOff1, xOff2, yOff2;
1752 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1755 if (!is_valid(himl1) || !is_valid(himl2))
1759 cxDst = max (himl1->cx, dx + himl2->cx);
1764 cxDst = max (himl2->cx, himl1->cx - dx);
1769 cxDst = max (himl1->cx, himl2->cx);
1775 cyDst = max (himl1->cy, dy + himl2->cy);
1780 cyDst = max (himl2->cy, himl1->cy - dy);
1785 cyDst = max (himl1->cy, himl2->cy);
1790 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1794 nX1 = i1 * himl1->cx;
1795 nX2 = i2 * himl2->cx;
1798 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1799 if (i1 >= 0 && i1 < himl1->cCurImage)
1800 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1801 if (i2 >= 0 && i2 < himl2->cCurImage)
1803 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1804 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1808 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1809 if (i1 >= 0 && i1 < himl1->cCurImage)
1810 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1811 if (i2 >= 0 && i2 < himl2->cCurImage)
1812 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1814 himlDst->cCurImage = 1;
1821 /* helper for _read_bitmap currently unused */
1823 static int may_use_dibsection(HDC hdc) {
1824 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1829 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1833 /* helper for ImageList_Read, see comments below */
1834 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1835 HDC xdc = 0, hBitmapDC =0;
1836 BITMAPFILEHEADER bmfh;
1837 BITMAPINFOHEADER bmih;
1838 int bitsperpixel,palspace,longsperline,width,height;
1839 LPBITMAPINFOHEADER bmihc = NULL;
1841 HBITMAP hbitmap = 0, hDIB = 0;
1844 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1845 (bmfh.bfType != (('M'<<8)|'B')) ||
1846 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1847 (bmih.biSize != sizeof(bmih))
1851 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1852 if (bitsperpixel<=8)
1853 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1856 width = bmih.biWidth;
1857 height = bmih.biHeight;
1858 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1859 memcpy(bmihc,&bmih,sizeof(bmih));
1860 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1861 bmihc->biSizeImage = (longsperline*height)<<2;
1863 /* read the palette right after the end of the bitmapinfoheader */
1865 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1869 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1870 if ((bitsperpixel>1) &&
1871 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1873 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1876 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1882 int i,nwidth,nheight,nRows;
1884 nwidth = width*(height/cy);
1886 nRows = (height/cy);
1888 if (bitsperpixel==1)
1889 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1891 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1893 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1896 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1899 hBitmapDC = CreateCompatibleDC(0);
1900 SelectObject(hBitmapDC, hbitmap);
1902 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1903 /* Do not forget that windows bitmaps are bottom->top */
1904 TRACE("nRows=%d\n", nRows);
1905 for (i=0; i < nRows; i++){
1906 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1907 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1913 if (xdc) ReleaseDC(0,xdc);
1914 if (bmihc) LocalFree((HLOCAL)bmihc);
1915 if (hDIB) DeleteObject(hDIB);
1916 if (hBitmapDC) DeleteDC(hBitmapDC);
1919 DeleteObject(hbitmap);
1926 /*************************************************************************
1927 * ImageList_Read [COMCTL32.@]
1929 * Reads an image list from a stream.
1932 * pstm [I] pointer to a stream
1935 * Success: handle to image list
1938 * The format is like this:
1939 * ILHEAD ilheadstruct;
1941 * for the color image part:
1942 * BITMAPFILEHEADER bmfh;
1943 * BITMAPINFOHEADER bmih;
1944 * only if it has a palette:
1945 * RGBQUAD rgbs[nr_of_paletted_colors];
1947 * BYTE colorbits[imagesize];
1949 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1950 * BITMAPFILEHEADER bmfh_mask;
1951 * BITMAPINFOHEADER bmih_mask;
1952 * only if it has a palette (it usually does not):
1953 * RGBQUAD rgbs[nr_of_paletted_colors];
1955 * BYTE maskbits[imagesize];
1957 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1958 * _read_bitmap needs to convert them.
1960 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1964 HBITMAP hbmColor=0,hbmMask=0;
1967 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1969 if (ilHead.usMagic != (('L' << 8) | 'I'))
1971 if (ilHead.usVersion != 0x101) /* probably version? */
1975 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1976 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1977 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1978 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1979 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1980 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1981 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1982 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1983 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1984 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1987 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1990 if (ilHead.flags & ILC_MASK) {
1991 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1993 DeleteObject(hbmColor);
1998 himl = ImageList_Create (
2006 DeleteObject(hbmColor);
2007 DeleteObject(hbmMask);
2010 SelectObject(himl->hdcImage, hbmColor);
2011 DeleteObject(himl->hbmImage);
2012 himl->hbmImage = hbmColor;
2014 SelectObject(himl->hdcMask, hbmMask);
2015 DeleteObject(himl->hbmMask);
2016 himl->hbmMask = hbmMask;
2018 himl->cCurImage = ilHead.cCurImage;
2019 himl->cMaxImage = ilHead.cMaxImage;
2021 ImageList_SetBkColor(himl,ilHead.bkcolor);
2023 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2028 /*************************************************************************
2029 * ImageList_Remove [COMCTL32.@]
2031 * Removes an image from an image list
2034 * himl [I] image list handle
2043 ImageList_Remove (HIMAGELIST himl, INT i)
2045 HBITMAP hbmNewImage, hbmNewMask;
2049 TRACE("(himl=%p i=%d)\n", himl, i);
2051 if (!is_valid(himl)) {
2052 ERR("Invalid image list handle!\n");
2056 if ((i < -1) || (i >= himl->cCurImage)) {
2057 TRACE("index out of range! %d\n", i);
2063 if (himl->cCurImage == 0) {
2064 /* remove all on empty ImageList is allowed */
2065 TRACE("remove all on empty ImageList!\n");
2069 himl->cMaxImage = himl->cInitial + himl->cGrow;
2070 himl->cCurImage = 0;
2071 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2072 himl->nOvlIdx[nCount] = -1;
2074 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2075 SelectObject (himl->hdcImage, hbmNewImage);
2076 DeleteObject (himl->hbmImage);
2077 himl->hbmImage = hbmNewImage;
2079 if (himl->hbmMask) {
2080 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2082 SelectObject (himl->hdcMask, hbmNewMask);
2083 DeleteObject (himl->hbmMask);
2084 himl->hbmMask = hbmNewMask;
2088 /* delete one image */
2089 TRACE("Remove single image! %d\n", i);
2091 /* create new bitmap(s) */
2092 nCount = (himl->cCurImage + himl->cGrow - 1);
2093 cxNew = nCount * himl->cx;
2095 TRACE(" - Number of images: %d / %d (Old/New)\n",
2096 himl->cCurImage, himl->cCurImage - 1);
2097 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2098 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2100 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy);
2103 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2105 hbmNewMask = 0; /* Just to keep compiler happy! */
2107 hdcBmp = CreateCompatibleDC (0);
2109 /* copy all images and masks prior to the "removed" image */
2111 TRACE("Pre image copy: Copy %d images\n", i);
2113 SelectObject (hdcBmp, hbmNewImage);
2114 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2115 himl->hdcImage, 0, 0, SRCCOPY);
2117 if (himl->hbmMask) {
2118 SelectObject (hdcBmp, hbmNewMask);
2119 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2120 himl->hdcMask, 0, 0, SRCCOPY);
2124 /* copy all images and masks behind the removed image */
2125 if (i < himl->cCurImage - 1) {
2126 TRACE("Post image copy!\n");
2127 SelectObject (hdcBmp, hbmNewImage);
2128 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2129 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2131 if (himl->hbmMask) {
2132 SelectObject (hdcBmp, hbmNewMask);
2133 BitBlt (hdcBmp, i * himl->cx, 0,
2134 (himl->cCurImage - i - 1) * himl->cx,
2135 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2141 /* delete old images and insert new ones */
2142 SelectObject (himl->hdcImage, hbmNewImage);
2143 DeleteObject (himl->hbmImage);
2144 himl->hbmImage = hbmNewImage;
2145 if (himl->hbmMask) {
2146 SelectObject (himl->hdcMask, hbmNewMask);
2147 DeleteObject (himl->hbmMask);
2148 himl->hbmMask = hbmNewMask;
2152 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2159 /*************************************************************************
2160 * ImageList_Replace [COMCTL32.@]
2162 * Replaces an image in an image list with a new image.
2165 * himl [I] handle to image list
2167 * hbmImage [I] handle to image bitmap
2168 * hbmMask [I] handle to mask bitmap. Can be NULL.
2176 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2182 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2184 if (!is_valid(himl)) {
2185 ERR("Invalid image list handle!\n");
2189 if ((i >= himl->cMaxImage) || (i < 0)) {
2190 ERR("Invalid image index!\n");
2194 hdcImage = CreateCompatibleDC (0);
2195 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2198 SelectObject (hdcImage, hbmImage);
2200 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2201 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2206 SelectObject (hdcImage, hbmMask);
2208 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2209 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2212 /* Remove the background from the image
2214 StretchBlt (himl->hdcImage,
2215 i*himl->cx, 0, himl->cx, himl->cy,
2217 0, 0, bmp.bmWidth, bmp.bmHeight,
2218 0x220326); /* NOTSRCAND */
2221 DeleteDC (hdcImage);
2227 /*************************************************************************
2228 * ImageList_ReplaceIcon [COMCTL32.@]
2230 * Replaces an image in an image list using an icon.
2233 * himl [I] handle to image list
2235 * hIcon [I] handle to icon
2238 * Success: index of the replaced image
2243 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2252 TRACE("(%p %d %p)\n", himl, i, hIcon);
2254 if (!is_valid(himl))
2256 if ((i >= himl->cMaxImage) || (i < -1))
2259 hBestFitIcon = CopyImage(
2262 LR_COPYFROMRESOURCE);
2264 GetIconInfo (hBestFitIcon, &ii);
2265 if (ii.hbmMask == 0)
2267 if (ii.hbmColor == 0)
2269 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2272 if (himl->cCurImage + 1 > himl->cMaxImage)
2273 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2275 nIndex = himl->cCurImage;
2281 hdcImage = CreateCompatibleDC (0);
2282 TRACE("hdcImage=%p\n", hdcImage);
2284 ERR("invalid hdcImage!\n");
2286 SetTextColor(himl->hdcImage, RGB(0,0,0));
2287 SetBkColor (himl->hdcImage, RGB(255,255,255));
2288 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2290 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2291 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2293 if (himl->hbmMask) {
2294 SelectObject (hdcImage, ii.hbmMask);
2295 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2296 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2299 SelectObject (hdcImage, hbmOldSrc);
2302 DestroyIcon(hBestFitIcon);
2304 DeleteDC (hdcImage);
2306 DeleteObject (ii.hbmColor);
2308 DeleteObject (ii.hbmMask);
2310 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2315 /*************************************************************************
2316 * ImageList_SetBkColor [COMCTL32.@]
2318 * Sets the background color of an image list.
2321 * himl [I] handle to image list
2322 * clrBk [I] background color
2325 * Success: previous background color
2330 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2334 if (!is_valid(himl))
2337 clrOldBk = himl->clrBk;
2338 himl->clrBk = clrBk;
2343 /*************************************************************************
2344 * ImageList_SetDragCursorImage [COMCTL32.@]
2346 * Combines the specified image with the current drag image
2349 * himlDrag [I] handle to drag image list
2350 * iDrag [I] drag image index
2351 * dxHotspot [I] X position of the hot spot
2352 * dyHotspot [I] Y position of the hot spot
2359 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2360 * to do with a hotspot but are only the offset of the origin of the new
2361 * image relative to the origin of the old image.
2363 * - When this function is called and the drag image is visible, a
2364 * short flickering occurs but this matches the Win9x behavior. It is
2365 * possible to fix the flickering using code like in ImageList_DragMove.
2369 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2370 INT dxHotspot, INT dyHotspot)
2372 HIMAGELIST himlTemp;
2375 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2378 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2379 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2381 visible = InternalDrag.bShow;
2383 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2384 dxHotspot, dyHotspot);
2387 /* hide the drag image */
2388 ImageList_DragShowNolock(FALSE);
2390 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2391 (InternalDrag.himl->cy != himlTemp->cy)) {
2392 /* the size of the drag image changed, invalidate the buffer */
2393 DeleteObject(InternalDrag.hbmBg);
2394 InternalDrag.hbmBg = 0;
2397 ImageList_Destroy (InternalDrag.himl);
2398 InternalDrag.himl = himlTemp;
2401 /* show the drag image */
2402 ImageList_DragShowNolock(TRUE);
2409 /*************************************************************************
2410 * ImageList_SetFilter [COMCTL32.@]
2412 * Sets a filter (or does something completely different)!!???
2413 * It removes 12 Bytes from the stack (3 Parameters).
2416 * himl [I] SHOULD be a handle to image list
2417 * i [I] COULD be an index?
2422 * Failure: FALSE ???
2425 * This is an UNDOCUMENTED function!!!!
2430 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2432 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2438 /*************************************************************************
2439 * ImageList_SetFlags [COMCTL32.@]
2441 * Sets the image list flags.
2444 * himl [I] Handle to image list
2445 * flags [I] Flags to set
2455 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2457 FIXME("(%p %08lx):empty stub\n", himl, flags);
2462 /*************************************************************************
2463 * ImageList_SetIconSize [COMCTL32.@]
2465 * Sets the image size of the bitmap and deletes all images.
2468 * himl [I] handle to image list
2469 * cx [I] image width
2470 * cy [I] image height
2478 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2483 if (!is_valid(himl))
2486 /* remove all images */
2487 himl->cMaxImage = himl->cInitial + himl->cGrow;
2488 himl->cCurImage = 0;
2492 /* initialize overlay mask indices */
2493 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2494 himl->nOvlIdx[nCount] = -1;
2496 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2497 SelectObject (himl->hdcImage, hbmNew);
2498 DeleteObject (himl->hbmImage);
2499 himl->hbmImage = hbmNew;
2501 if (himl->hbmMask) {
2502 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2504 SelectObject (himl->hdcMask, hbmNew);
2505 DeleteObject (himl->hbmMask);
2506 himl->hbmMask = hbmNew;
2513 /*************************************************************************
2514 * ImageList_SetImageCount [COMCTL32.@]
2516 * Resizes an image list to the specified number of images.
2519 * himl [I] handle to image list
2520 * iImageCount [I] number of images in the image list
2528 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2531 HBITMAP hbmNewBitmap;
2532 INT nNewCount, nCopyCount;
2534 TRACE("%p %d\n",himl,iImageCount);
2536 if (!is_valid(himl))
2538 if (himl->cCurImage >= iImageCount)
2540 if (himl->cMaxImage > iImageCount)
2542 himl->cCurImage = iImageCount;
2546 nNewCount = iImageCount + himl->cGrow;
2547 nCopyCount = min(himl->cCurImage, iImageCount);
2549 hdcBitmap = CreateCompatibleDC (0);
2551 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy);
2553 if (hbmNewBitmap != 0)
2555 SelectObject (hdcBitmap, hbmNewBitmap);
2558 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2559 himl->hdcImage, 0, 0, SRCCOPY);
2561 /* delete 'empty' image space */
2562 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2563 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2564 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2565 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2567 SelectObject (himl->hdcImage, hbmNewBitmap);
2568 DeleteObject (himl->hbmImage);
2569 himl->hbmImage = hbmNewBitmap;
2572 ERR("Could not create new image bitmap !\n");
2576 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2578 if (hbmNewBitmap != 0)
2580 SelectObject (hdcBitmap, hbmNewBitmap);
2583 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2584 himl->hdcMask, 0, 0, SRCCOPY);
2586 /* delete 'empty' image space */
2587 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2588 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2589 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2590 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2592 SelectObject (himl->hdcMask, hbmNewBitmap);
2593 DeleteObject (himl->hbmMask);
2594 himl->hbmMask = hbmNewBitmap;
2597 ERR("Could not create new mask bitmap!\n");
2600 DeleteDC (hdcBitmap);
2602 /* Update max image count and current image count */
2603 himl->cMaxImage = nNewCount;
2604 himl->cCurImage = iImageCount;
2610 /*************************************************************************
2611 * ImageList_SetOverlayImage [COMCTL32.@]
2613 * Assigns an overlay mask index to an existing image in an image list.
2616 * himl [I] handle to image list
2617 * iImage [I] image index
2618 * iOverlay [I] overlay mask index
2626 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2628 if (!is_valid(himl))
2630 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2632 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2634 himl->nOvlIdx[iOverlay - 1] = iImage;
2640 /* helper for ImageList_Write - write bitmap to pstm
2641 * currently everything is written as 24 bit RGB, except masks
2644 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2646 LPBITMAPFILEHEADER bmfh;
2647 LPBITMAPINFOHEADER bmih;
2648 LPBYTE data, lpBits, lpBitsOrg;
2650 INT bitCount, sizeImage, offBits, totalSize;
2651 INT nwidth, nheight, nsizeImage, icount;
2653 BOOL result = FALSE;
2657 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2659 /* XXX is this always correct? */
2660 icount = bm.bmWidth / cx;
2662 nheight = cy * icount;
2664 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2665 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2666 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2668 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2670 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2671 offBits = totalSize;
2672 totalSize += nsizeImage;
2674 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2675 bmfh = (LPBITMAPFILEHEADER)data;
2676 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2677 lpBits = data + offBits;
2679 /* setup BITMAPFILEHEADER */
2680 bmfh->bfType = (('M' << 8) | 'B');
2682 bmfh->bfReserved1 = 0;
2683 bmfh->bfReserved2 = 0;
2684 bmfh->bfOffBits = offBits;
2686 /* setup BITMAPINFOHEADER */
2687 bmih->biSize = sizeof(BITMAPINFOHEADER);
2688 bmih->biWidth = bm.bmWidth;
2689 bmih->biHeight = bm.bmHeight;
2691 bmih->biBitCount = bitCount;
2692 bmih->biCompression = BI_RGB;
2693 bmih->biSizeImage = sizeImage;
2694 bmih->biXPelsPerMeter = 0;
2695 bmih->biYPelsPerMeter = 0;
2696 bmih->biClrUsed = 0;
2697 bmih->biClrImportant = 0;
2699 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2700 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2701 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2705 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2706 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2708 for(i = 0; i < nheight; i++) {
2709 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2710 int noff = (nbpl * (nheight-1-i));
2711 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2715 bmih->biWidth = nwidth;
2716 bmih->biHeight = nheight;
2717 bmih->biSizeImage = nsizeImage;
2721 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2722 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2723 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2726 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2733 LocalFree((HLOCAL)lpBitsOrg);
2734 LocalFree((HLOCAL)data);
2740 /*************************************************************************
2741 * ImageList_Write [COMCTL32.@]
2743 * Writes an image list to a stream.
2746 * himl [I] handle to image list
2747 * pstm [O] Pointer to a stream.
2758 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2763 if (!is_valid(himl))
2766 ilHead.usMagic = (('L' << 8) | 'I');
2767 ilHead.usVersion = 0x101;
2768 ilHead.cCurImage = himl->cCurImage;
2769 ilHead.cMaxImage = himl->cMaxImage;
2770 ilHead.cGrow = himl->cGrow;
2771 ilHead.cx = himl->cx;
2772 ilHead.cy = himl->cy;
2773 ilHead.bkcolor = himl->clrBk;
2774 ilHead.flags = himl->flags;
2775 for(i = 0; i < 4; i++) {
2776 ilHead.ovls[i] = himl->nOvlIdx[i];
2779 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2782 /* write the bitmap */
2783 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2786 /* write the mask if we have one */
2787 if(himl->flags & ILC_MASK) {
2788 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2796 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height)
2798 HBITMAP hbmNewBitmap;
2799 UINT ilc = (himl->flags & 0xFE);
2801 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2806 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2808 if (himl->uBitsPixel <= ILC_COLOR8)
2814 colors = 1 << himl->uBitsPixel;
2815 bmi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) +
2816 sizeof(PALETTEENTRY) * colors);
2818 pal = (LPPALETTEENTRY)bmi->bmiColors;
2819 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2821 /* Swap colors returned by GetPaletteEntries so we can use them for
2822 * CreateDIBSection call. */
2823 for (i = 0; i < colors; i++)
2825 temp = pal[i].peBlue;
2826 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2827 bmi->bmiColors[i].rgbBlue = temp;
2832 bmi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER));
2835 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2836 bmi->bmiHeader.biWidth = width;
2837 bmi->bmiHeader.biHeight = height;
2838 bmi->bmiHeader.biPlanes = 1;
2839 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2840 bmi->bmiHeader.biCompression = BI_RGB;
2841 bmi->bmiHeader.biSizeImage = 0;
2842 bmi->bmiHeader.biXPelsPerMeter = 0;
2843 bmi->bmiHeader.biYPelsPerMeter = 0;
2844 bmi->bmiHeader.biClrUsed = 0;
2845 bmi->bmiHeader.biClrImportant = 0;
2847 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2849 HeapFree(GetProcessHeap(), 0, bmi);
2851 else /*if (ilc == ILC_COLORDDB)*/
2853 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2855 hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL);
2857 TRACE("returning %p\n", hbmNewBitmap);
2858 return hbmNewBitmap;
2861 /*************************************************************************
2862 * ImageList_SetColorTable [COMCTL32.@]
2864 * Sets the color table of an image list.
2867 * himl [I] Handle to the image list.
2868 * uStartIndex [I] The first index to set.
2869 * cEntries [I] Number of entries to set.
2870 * prgb [I] New color information for color table for the image list.
2873 * Success: Number of entries in the table that were set.
2877 * ImageList_Create(), SetDIBColorTable()
2881 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2883 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);