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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 count, UINT height);
82 static inline BOOL is_valid(HIMAGELIST himl)
84 return himl && himl->magic == IMAGELIST_MAGIC;
87 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
89 pt->x = index * himl->cx;
93 static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cy, SIZE *sz )
95 sz->cx = count * himl->cx;
99 /*************************************************************************
100 * IMAGELIST_InternalExpandBitmaps [Internal]
102 * Expands the bitmaps of an image list by the given number of images.
105 * himl [I] handle to image list
106 * nImageCount [I] number of images to add
112 * This function CANNOT be used to reduce the number of images.
115 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
118 HBITMAP hbmNewBitmap, hbmNull;
122 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
126 if (cy == 0) cy = himl->cy;
127 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
129 imagelist_get_bitmap_size(himl, nNewCount, cy, &sz);
131 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
132 hdcBitmap = CreateCompatibleDC (0);
134 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, cy);
136 if (hbmNewBitmap == 0)
137 ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
141 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
142 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
143 himl->hdcImage, 0, 0, SRCCOPY);
144 SelectObject (hdcBitmap, hbmNull);
146 SelectObject (himl->hdcImage, hbmNewBitmap);
147 DeleteObject (himl->hbmImage);
148 himl->hbmImage = hbmNewBitmap;
150 if (himl->flags & ILC_MASK)
152 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
154 if (hbmNewBitmap == 0)
155 ERR("creating new mask bitmap!\n");
159 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
160 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
161 himl->hdcMask, 0, 0, SRCCOPY);
162 SelectObject (hdcBitmap, hbmNull);
164 SelectObject (himl->hdcMask, hbmNewBitmap);
165 DeleteObject (himl->hbmMask);
166 himl->hbmMask = hbmNewBitmap;
169 himl->cMaxImage = nNewCount;
171 DeleteDC (hdcBitmap);
175 /*************************************************************************
176 * ImageList_Add [COMCTL32.@]
178 * Add an image or images to an image list.
181 * himl [I] handle to image list
182 * hbmImage [I] handle to image bitmap
183 * hbmMask [I] handle to mask bitmap
186 * Success: Index of the first new image.
191 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
194 INT nFirstIndex, nImageCount;
199 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
203 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
204 nImageCount = bmp.bmWidth / himl->cx;
206 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
208 imagelist_point_from_index( himl, himl->cCurImage, &pt );
210 hdcBitmap = CreateCompatibleDC(0);
212 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
214 /* Copy result to the imagelist
216 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
217 hdcBitmap, 0, 0, SRCCOPY);
222 HBITMAP hOldBitmapTemp;
224 hdcTemp = CreateCompatibleDC(0);
225 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
227 BitBlt (himl->hdcMask,
228 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
233 SelectObject(hdcTemp, hOldBitmapTemp);
236 /* Remove the background from the image
238 BitBlt (himl->hdcImage,
239 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
242 0x220326); /* NOTSRCAND */
245 SelectObject(hdcBitmap, hOldBitmap);
248 nFirstIndex = himl->cCurImage;
249 himl->cCurImage += nImageCount;
255 /*************************************************************************
256 * ImageList_AddIcon [COMCTL32.@]
258 * Adds an icon to an image list.
261 * himl [I] handle to image list
262 * hIcon [I] handle to icon
265 * Success: index of the new image
268 #undef ImageList_AddIcon
269 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
271 return ImageList_ReplaceIcon (himl, -1, hIcon);
275 /*************************************************************************
276 * ImageList_AddMasked [COMCTL32.@]
278 * Adds an image or images to an image list and creates a mask from the
279 * specified bitmap using the mask color.
282 * himl [I] handle to image list.
283 * hBitmap [I] handle to bitmap
284 * clrMask [I] mask color.
287 * Success: Index of the first new image.
292 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
294 HDC hdcMask, hdcBitmap;
295 INT nIndex, nImageCount, nMaskXOffset=0;
298 HBITMAP hMaskBitmap=0;
302 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
306 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
310 nImageCount = bmp.bmWidth / himl->cx;
314 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
316 nIndex = himl->cCurImage;
317 himl->cCurImage += nImageCount;
319 hdcBitmap = CreateCompatibleDC(0);
322 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
325 hdcMask = himl->hdcMask;
326 nMaskXOffset = nIndex * himl->cx;
327 imagelist_point_from_index( himl, nIndex, &pt );
332 Create a temp Mask so we can remove the background of
333 the Image (Windows does this even if there is no mask)
335 hdcMask = CreateCompatibleDC(0);
336 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
337 SelectObject(hdcMask, hMaskBitmap);
339 imagelist_point_from_index( himl, 0, &pt );
341 /* create monochrome image to the mask bitmap */
342 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
343 GetPixel (hdcBitmap, 0, 0);
344 SetBkColor (hdcBitmap, bkColor);
346 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
350 SetBkColor(hdcBitmap, RGB(255,255,255));
351 /*Remove the background from the image
354 WINDOWS BUG ALERT!!!!!!
355 The statement below should not be done in common practice
356 but this is how ImageList_AddMasked works in Windows.
357 It overwrites the original bitmap passed, this was discovered
358 by using the same bitmap to iterate the different styles
359 on windows where it failed (BUT ImageList_Add is OK)
360 This is here in case some apps rely on this bug
363 0, 0, bmp.bmWidth, bmp.bmHeight,
366 0x220326); /* NOTSRCAND */
367 /* Copy result to the imagelist
369 imagelist_point_from_index( himl, nIndex, &pt );
370 BitBlt (himl->hdcImage,
371 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
377 SelectObject(hdcBitmap, hOldBitmap);
381 DeleteObject(hMaskBitmap);
389 /*************************************************************************
390 * ImageList_BeginDrag [COMCTL32.@]
392 * Creates a temporary image list that contains one image. It will be used
396 * himlTrack [I] handle to the source image list
397 * iTrack [I] index of the drag image in the source image list
398 * dxHotspot [I] X position of the hot spot of the drag image
399 * dyHotspot [I] Y position of the hot spot of the drag image
407 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
408 INT dxHotspot, INT dyHotspot)
412 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
413 dxHotspot, dyHotspot);
415 if (!is_valid(himlTrack))
418 if (InternalDrag.himl)
419 ImageList_EndDrag ();
424 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
425 if (InternalDrag.himl == NULL) {
426 WARN("Error creating drag image list!\n");
430 InternalDrag.dxHotspot = dxHotspot;
431 InternalDrag.dyHotspot = dyHotspot;
434 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
437 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
439 InternalDrag.himl->cCurImage = 1;
445 /*************************************************************************
446 * ImageList_Copy [COMCTL32.@]
448 * Copies an image of the source image list to an image of the
449 * destination image list. Images can be copied or swapped.
452 * himlDst [I] handle to the destination image list
453 * iDst [I] destination image index.
454 * himlSrc [I] handle to the source image list
455 * iSrc [I] source image index
456 * uFlags [I] flags for the copy operation
463 * Copying from one image list to another is possible. The original
464 * implementation just copies or swaps within one image list.
465 * Could this feature become a bug??? ;-)
469 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
470 INT iSrc, UINT uFlags)
474 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
476 if (!is_valid(himlSrc) || !is_valid(himlDst))
478 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
480 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
483 imagelist_point_from_index( himlDst, iDst, &ptDst );
484 imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
486 if (uFlags & ILCF_SWAP) {
489 HBITMAP hbmTempImage, hbmTempMask;
491 hdcBmp = CreateCompatibleDC (0);
493 /* create temporary bitmaps */
494 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
495 himlSrc->uBitsPixel, NULL);
496 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
499 /* copy (and stretch) destination to temporary bitmaps.(save) */
501 SelectObject (hdcBmp, hbmTempImage);
502 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
503 himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
506 SelectObject (hdcBmp, hbmTempMask);
507 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
508 himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
511 /* copy (and stretch) source to destination */
513 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
514 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
517 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
518 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
521 /* copy (without stretching) temporary bitmaps to source (restore) */
523 BitBlt (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
524 hdcBmp, 0, 0, SRCCOPY);
527 BitBlt (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
528 hdcBmp, 0, 0, SRCCOPY);
529 /* delete temporary bitmaps */
530 DeleteObject (hbmTempMask);
531 DeleteObject (hbmTempImage);
536 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
537 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
541 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
542 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
550 /*************************************************************************
551 * ImageList_Create [COMCTL32.@]
553 * Creates a new image list.
556 * cx [I] image height
558 * flags [I] creation flags
559 * cInitial [I] initial number of images in the image list
560 * cGrow [I] number of images by which image list grows
563 * Success: Handle to the created image list
567 ImageList_Create (INT cx, INT cy, UINT flags,
568 INT cInitial, INT cGrow)
573 UINT ilc = (flags & 0xFE);
574 static const WORD aBitBlend25[] =
575 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
577 static const WORD aBitBlend50[] =
578 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
580 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
582 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
586 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
588 himl->magic = IMAGELIST_MAGIC;
592 himl->cMaxImage = cInitial + cGrow;
593 himl->cInitial = cInitial;
595 himl->clrFg = CLR_DEFAULT;
596 himl->clrBk = CLR_NONE;
598 /* initialize overlay mask indices */
599 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
600 himl->nOvlIdx[nCount] = -1;
602 /* Create Image & Mask DCs */
603 himl->hdcImage = CreateCompatibleDC (0);
606 if (himl->flags & ILC_MASK){
607 himl->hdcMask = CreateCompatibleDC(0);
612 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
613 if (ilc == ILC_COLOR)
616 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
617 himl->uBitsPixel = ilc;
619 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
621 if (himl->cMaxImage > 0) {
622 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cy);
623 SelectObject(himl->hdcImage, himl->hbmImage);
627 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
630 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
631 himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
632 if (himl->hbmMask == 0) {
633 ERR("Error creating mask bitmap!\n");
636 SelectObject(himl->hdcMask, himl->hbmMask);
641 /* create blending brushes */
642 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
643 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
644 DeleteObject (hbmTemp);
646 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
647 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
648 DeleteObject (hbmTemp);
650 TRACE("created imagelist %p\n", himl);
654 if (himl) ImageList_Destroy(himl);
659 /*************************************************************************
660 * ImageList_Destroy [COMCTL32.@]
662 * Destroys an image list.
665 * himl [I] handle to image list
673 ImageList_Destroy (HIMAGELIST himl)
678 /* delete image bitmaps */
680 DeleteObject (himl->hbmImage);
682 DeleteObject (himl->hbmMask);
684 /* delete image & mask DCs */
686 DeleteDC(himl->hdcImage);
688 DeleteDC(himl->hdcMask);
690 /* delete blending brushes */
691 if (himl->hbrBlend25)
692 DeleteObject (himl->hbrBlend25);
693 if (himl->hbrBlend50)
694 DeleteObject (himl->hbrBlend50);
696 ZeroMemory(himl, sizeof(*himl));
703 /*************************************************************************
704 * ImageList_DragEnter [COMCTL32.@]
706 * Locks window update and displays the drag image at the given position.
709 * hwndLock [I] handle of the window that owns the drag image.
710 * x [I] X position of the drag image.
711 * y [I] Y position of the drag image.
718 * The position of the drag image is relative to the window, not
723 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
725 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
727 if (!is_valid(InternalDrag.himl))
731 InternalDrag.hwnd = hwndLock;
733 InternalDrag.hwnd = GetDesktopWindow ();
738 /* draw the drag image and save the background */
739 if (!ImageList_DragShowNolock(TRUE)) {
747 /*************************************************************************
748 * ImageList_DragLeave [COMCTL32.@]
750 * Unlocks window update and hides the drag image.
753 * hwndLock [I] handle of the window that owns the drag image.
761 ImageList_DragLeave (HWND hwndLock)
763 /* As we don't save drag info in the window this can lead to problems if
764 an app does not supply the same window as DragEnter */
766 InternalDrag.hwnd = hwndLock;
768 InternalDrag.hwnd = GetDesktopWindow (); */
770 hwndLock = GetDesktopWindow();
771 if(InternalDrag.hwnd != hwndLock)
772 FIXME("DragLeave hWnd != DragEnter hWnd\n");
774 ImageList_DragShowNolock (FALSE);
780 /*************************************************************************
781 * ImageList_InternalDragDraw [Internal]
783 * Draws the drag image.
786 * hdc [I] device context to draw into.
787 * x [I] X position of the drag image.
788 * y [I] Y position of the drag image.
795 * The position of the drag image is relative to the window, not
801 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
803 IMAGELISTDRAWPARAMS imldp;
805 ZeroMemory (&imldp, sizeof(imldp));
806 imldp.cbSize = sizeof(imldp);
807 imldp.himl = InternalDrag.himl;
812 imldp.rgbBk = CLR_DEFAULT;
813 imldp.rgbFg = CLR_DEFAULT;
814 imldp.fStyle = ILD_NORMAL;
815 imldp.fState = ILS_ALPHA;
818 /* FIXME: instead of using the alpha blending, we should
819 * create a 50% mask, and draw it semitransparantly that way */
820 ImageList_DrawIndirect (&imldp);
823 /*************************************************************************
824 * ImageList_DragMove [COMCTL32.@]
826 * Moves the drag image.
829 * x [I] X position of the drag image.
830 * y [I] Y position of the drag image.
837 * The position of the drag image is relative to the window, not
841 * The drag image should be drawn semitransparent.
845 ImageList_DragMove (INT x, INT y)
847 TRACE("(x=%d y=%d)\n", x, y);
849 if (!is_valid(InternalDrag.himl))
852 /* draw/update the drag image */
853 if (InternalDrag.bShow) {
857 HBITMAP hbmOffScreen;
858 INT origNewX, origNewY;
859 INT origOldX, origOldY;
860 INT origRegX, origRegY;
861 INT sizeRegX, sizeRegY;
864 /* calculate the update region */
865 origNewX = x - InternalDrag.dxHotspot;
866 origNewY = y - InternalDrag.dyHotspot;
867 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
868 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
869 origRegX = min(origNewX, origOldX);
870 origRegY = min(origNewY, origOldY);
871 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
872 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
874 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
875 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
876 hdcOffScreen = CreateCompatibleDC(hdcDrag);
877 hdcBg = CreateCompatibleDC(hdcDrag);
879 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
880 SelectObject(hdcOffScreen, hbmOffScreen);
881 SelectObject(hdcBg, InternalDrag.hbmBg);
883 /* get the actual background of the update region */
884 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
885 origRegX, origRegY, SRCCOPY);
886 /* erase the old image */
887 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
888 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
890 /* save the background */
891 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
892 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
894 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
895 origNewY - origRegY);
896 /* draw the update region to the screen */
897 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
898 hdcOffScreen, 0, 0, SRCCOPY);
901 DeleteDC(hdcOffScreen);
902 DeleteObject(hbmOffScreen);
903 ReleaseDC(InternalDrag.hwnd, hdcDrag);
906 /* update the image position */
914 /*************************************************************************
915 * ImageList_DragShowNolock [COMCTL32.@]
917 * Shows or hides the drag image.
920 * bShow [I] TRUE shows the drag image, FALSE hides it.
927 * The drag image should be drawn semitransparent.
931 ImageList_DragShowNolock (BOOL bShow)
937 if (!is_valid(InternalDrag.himl))
940 TRACE("bShow=0x%X!\n", bShow);
942 /* DragImage is already visible/hidden */
943 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
947 /* position of the origin of the DragImage */
948 x = InternalDrag.x - InternalDrag.dxHotspot;
949 y = InternalDrag.y - InternalDrag.dyHotspot;
951 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
952 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
957 hdcBg = CreateCompatibleDC(hdcDrag);
958 if (!InternalDrag.hbmBg) {
959 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
960 InternalDrag.himl->cx, InternalDrag.himl->cy);
962 SelectObject(hdcBg, InternalDrag.hbmBg);
965 /* save the background */
966 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
967 hdcDrag, x, y, SRCCOPY);
969 ImageList_InternalDragDraw(hdcDrag, x, y);
972 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
973 hdcBg, 0, 0, SRCCOPY);
976 InternalDrag.bShow = !InternalDrag.bShow;
979 ReleaseDC (InternalDrag.hwnd, hdcDrag);
984 /*************************************************************************
985 * ImageList_Draw [COMCTL32.@]
990 * himl [I] handle to image list
992 * hdc [I] handle to device context
995 * fStyle [I] drawing flags
1006 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1008 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1009 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1013 /*************************************************************************
1014 * ImageList_DrawEx [COMCTL32.@]
1016 * Draws an image and allows to use extended drawing features.
1019 * himl [I] handle to image list
1021 * hdc [I] handle to device context
1026 * rgbBk [I] background color
1027 * rgbFg [I] foreground color
1028 * fStyle [I] drawing flags
1035 * Calls ImageList_DrawIndirect.
1038 * ImageList_DrawIndirect.
1042 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1043 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1046 IMAGELISTDRAWPARAMS imldp;
1048 ZeroMemory (&imldp, sizeof(imldp));
1049 imldp.cbSize = sizeof(imldp);
1057 imldp.rgbBk = rgbBk;
1058 imldp.rgbFg = rgbFg;
1059 imldp.fStyle = fStyle;
1061 return ImageList_DrawIndirect (&imldp);
1065 /*************************************************************************
1066 * ImageList_DrawIndirect [COMCTL32.@]
1068 * Draws an image using various parameters specified in pimldp.
1071 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1079 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1081 INT cx, cy, nOvlIdx;
1082 DWORD fState, dwRop;
1084 COLORREF oldImageBk, oldImageFg;
1085 HDC hImageDC, hImageListDC, hMaskListDC;
1086 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1087 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1091 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1092 if (!is_valid(himl)) return FALSE;
1093 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1095 imagelist_point_from_index( himl, pimldp->i, &pt );
1096 pt.x += pimldp->xBitmap;
1097 pt.y += pimldp->yBitmap;
1099 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1100 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1101 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1102 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1104 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1105 if( pimldp->rgbBk == CLR_NONE )
1106 bIsTransparent = TRUE;
1107 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1108 bIsTransparent = TRUE;
1109 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1110 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1112 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1113 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1115 /* we will use these DCs to access the images and masks in the ImageList */
1116 hImageListDC = himl->hdcImage;
1117 hMaskListDC = himl->hdcMask;
1119 /* these will accumulate the image and mask for the image we're drawing */
1120 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1121 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1122 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1124 /* Create a compatible DC. */
1125 if (!hImageListDC || !hImageDC || !hImageBmp ||
1126 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1129 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1132 * To obtain a transparent look, background color should be set
1133 * to white and foreground color to black when blting the
1136 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1137 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1140 * Draw the initial image
1143 if (himl->hbmMask) {
1145 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1146 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1147 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1148 DeleteObject (SelectObject (hImageDC, hOldBrush));
1149 if( bIsTransparent )
1151 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1156 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1157 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1158 SelectObject(hImageDC, hOldBrush);
1161 /* blend the image with the needed solid background */
1162 COLORREF colour = RGB(0,0,0);
1165 if( !bIsTransparent )
1167 colour = pimldp->rgbBk;
1168 if( colour == CLR_DEFAULT )
1169 colour = himl->clrBk;
1170 if( colour == CLR_NONE )
1171 colour = GetBkColor(pimldp->hdcDst);
1174 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1175 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1176 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1177 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1178 DeleteObject (SelectObject (hImageDC, hOldBrush));
1181 /* Time for blending, if required */
1183 HBRUSH hBlendBrush, hOldBrush;
1184 COLORREF clrBlend = pimldp->rgbFg;
1185 HDC hBlendMaskDC = hImageListDC;
1188 /* Create the blend Mask */
1189 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1190 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1191 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1192 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1193 SelectObject(hBlendMaskDC, hOldBrush);
1195 /* Modify the blend mask if an Image Mask exist */
1197 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1198 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1201 /* now apply blend to the current image given the BlendMask */
1202 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1203 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1204 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1205 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1206 DeleteObject(SelectObject(hImageDC, hOldBrush));
1207 SelectObject(hBlendMaskDC, hOldBitmap);
1210 /* Now do the overlay image, if any */
1211 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1212 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1213 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1214 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1215 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1216 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1217 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, pt.x, SRCAND);
1218 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, pt.y, SRCPAINT);
1222 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1223 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1224 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1225 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1227 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1228 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1229 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1231 /* now copy the image to the screen */
1233 if (himl->hbmMask && bIsTransparent ) {
1234 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1235 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1236 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1237 SetBkColor(pimldp->hdcDst, oldDstBk);
1238 SetTextColor(pimldp->hdcDst, oldDstFg);
1241 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1242 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1246 /* cleanup the mess */
1247 SetBkColor(hImageDC, oldImageBk);
1248 SetTextColor(hImageDC, oldImageFg);
1249 SelectObject(hImageDC, hOldImageBmp);
1251 DeleteObject(hBlendMaskBmp);
1252 DeleteObject(hImageBmp);
1259 /*************************************************************************
1260 * ImageList_Duplicate [COMCTL32.@]
1262 * Duplicates an image list.
1265 * himlSrc [I] source image list handle
1268 * Success: Handle of duplicated image list.
1273 ImageList_Duplicate (HIMAGELIST himlSrc)
1277 if (!is_valid(himlSrc)) {
1278 ERR("Invalid image list handle!\n");
1282 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1283 himlSrc->cInitial, himlSrc->cGrow);
1289 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cy, &sz);
1290 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1291 himlSrc->hdcImage, 0, 0, SRCCOPY);
1293 if (himlDst->hbmMask)
1294 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1295 himlSrc->hdcMask, 0, 0, SRCCOPY);
1297 himlDst->cCurImage = himlSrc->cCurImage;
1298 himlDst->cMaxImage = himlSrc->cMaxImage;
1304 /*************************************************************************
1305 * ImageList_EndDrag [COMCTL32.@]
1307 * Finishes a drag operation.
1318 ImageList_EndDrag (void)
1320 /* cleanup the InternalDrag struct */
1321 InternalDrag.hwnd = 0;
1322 ImageList_Destroy (InternalDrag.himl);
1323 InternalDrag.himl = 0;
1326 InternalDrag.dxHotspot = 0;
1327 InternalDrag.dyHotspot = 0;
1328 InternalDrag.bShow = FALSE;
1329 DeleteObject(InternalDrag.hbmBg);
1330 InternalDrag.hbmBg = 0;
1334 /*************************************************************************
1335 * ImageList_GetBkColor [COMCTL32.@]
1337 * Returns the background color of an image list.
1340 * himl [I] Image list handle.
1343 * Success: background color
1348 ImageList_GetBkColor (HIMAGELIST himl)
1350 return himl ? himl->clrBk : CLR_NONE;
1354 /*************************************************************************
1355 * ImageList_GetDragImage [COMCTL32.@]
1357 * Returns the handle to the internal drag image list.
1360 * ppt [O] Pointer to the drag position. Can be NULL.
1361 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1364 * Success: Handle of the drag image list.
1369 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1371 if (is_valid(InternalDrag.himl)) {
1373 ppt->x = InternalDrag.x;
1374 ppt->y = InternalDrag.y;
1377 pptHotspot->x = InternalDrag.dxHotspot;
1378 pptHotspot->y = InternalDrag.dyHotspot;
1380 return (InternalDrag.himl);
1387 /*************************************************************************
1388 * ImageList_GetFlags [COMCTL32.@]
1390 * Gets the flags of the specified image list.
1393 * himl [I] Handle to image list
1403 ImageList_GetFlags(HIMAGELIST himl)
1405 FIXME("(%p):empty stub\n", himl);
1410 /*************************************************************************
1411 * ImageList_GetIcon [COMCTL32.@]
1413 * Creates an icon from a masked image of an image list.
1416 * himl [I] handle to image list
1418 * flags [I] drawing style flags
1421 * Success: icon handle
1426 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1430 HBITMAP hOldDstBitmap;
1433 TRACE("%p %d %d\n", himl, i, fStyle);
1434 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1440 /* create colour bitmap */
1442 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1443 ReleaseDC(0, hdcDst);
1445 hdcDst = CreateCompatibleDC(0);
1448 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1449 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1450 if (himl->hbmMask) {
1451 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1452 himl->hdcMask, i * himl->cx, 0, SRCCOPY);
1455 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1458 SelectObject (hdcDst, ii.hbmColor);
1459 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1460 himl->hdcImage, i * himl->cx, 0, SRCCOPY);
1463 * CreateIconIndirect requires us to deselect the bitmaps from
1464 * the DCs before calling
1466 SelectObject(hdcDst, hOldDstBitmap);
1468 hIcon = CreateIconIndirect (&ii);
1470 DeleteObject (ii.hbmMask);
1471 DeleteObject (ii.hbmColor);
1478 /*************************************************************************
1479 * ImageList_GetIconSize [COMCTL32.@]
1481 * Retrieves the size of an image in an image list.
1484 * himl [I] handle to image list
1485 * cx [O] pointer to the image width.
1486 * cy [O] pointer to the image height.
1493 * All images in an image list have the same size.
1497 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1499 if (!is_valid(himl))
1501 if ((himl->cx <= 0) || (himl->cy <= 0))
1513 /*************************************************************************
1514 * ImageList_GetImageCount [COMCTL32.@]
1516 * Returns the number of images in an image list.
1519 * himl [I] handle to image list
1522 * Success: Number of images.
1527 ImageList_GetImageCount (HIMAGELIST himl)
1529 if (!is_valid(himl))
1532 return himl->cCurImage;
1536 /*************************************************************************
1537 * ImageList_GetImageInfo [COMCTL32.@]
1539 * Returns information about an image in an image list.
1542 * himl [I] handle to image list
1544 * pImageInfo [O] pointer to the image information
1552 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1556 if (!is_valid(himl) || (pImageInfo == NULL))
1558 if ((i < 0) || (i >= himl->cCurImage))
1561 pImageInfo->hbmImage = himl->hbmImage;
1562 pImageInfo->hbmMask = himl->hbmMask;
1564 imagelist_point_from_index( himl, i, &pt );
1565 pImageInfo->rcImage.top = pt.y;
1566 pImageInfo->rcImage.bottom = pt.y + himl->cy;
1567 pImageInfo->rcImage.left = pt.x;
1568 pImageInfo->rcImage.right = pt.x + himl->cx;
1574 /*************************************************************************
1575 * ImageList_GetImageRect [COMCTL32.@]
1577 * Retrieves the rectangle of the specified image in an image list.
1580 * himl [I] handle to image list
1582 * lpRect [O] pointer to the image rectangle
1589 * This is an UNDOCUMENTED function!!!
1593 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1597 if (!is_valid(himl) || (lpRect == NULL))
1599 if ((i < 0) || (i >= himl->cCurImage))
1602 imagelist_point_from_index( himl, i, &pt );
1603 lpRect->left = pt.x;
1605 lpRect->right = pt.x + himl->cx;
1606 lpRect->bottom = pt.y + himl->cy;
1612 /*************************************************************************
1613 * ImageList_LoadImage [COMCTL32.@]
1614 * ImageList_LoadImageA [COMCTL32.@]
1616 * Creates an image list from a bitmap, icon or cursor.
1618 * See ImageList_LoadImageW.
1622 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1623 COLORREF clrMask, UINT uType, UINT uFlags)
1630 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1633 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1634 lpbmpW = Alloc(len * sizeof(WCHAR));
1635 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1637 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1643 /*************************************************************************
1644 * ImageList_LoadImageW [COMCTL32.@]
1646 * Creates an image list from a bitmap, icon or cursor.
1649 * hi [I] instance handle
1650 * lpbmp [I] name or id of the image
1651 * cx [I] width of each image
1652 * cGrow [I] number of images to expand
1653 * clrMask [I] mask color
1654 * uType [I] type of image to load
1655 * uFlags [I] loading flags
1658 * Success: handle to the loaded image list
1666 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1667 COLORREF clrMask, UINT uType, UINT uFlags)
1669 HIMAGELIST himl = NULL;
1673 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1675 ERR("Error loading image!\n");
1679 if (uType == IMAGE_BITMAP) {
1681 GetObjectW (handle, sizeof(BITMAP), &bmp);
1683 /* To match windows behavior, if cx is set to zero and
1684 the flag DI_DEFAULTSIZE is specified, cx becomes the
1685 system metric value for icons. If the flag is not specified
1686 the function sets the size to the height of the bitmap */
1689 if (uFlags & DI_DEFAULTSIZE)
1690 cx = GetSystemMetrics (SM_CXICON);
1695 nImageCount = bmp.bmWidth / cx;
1697 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1698 nImageCount, cGrow);
1700 DeleteObject (handle);
1703 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1705 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1709 GetIconInfo (handle, &ii);
1710 GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1711 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1712 ILC_MASK | ILC_COLOR, 1, cGrow);
1714 DeleteObject (ii.hbmColor);
1715 DeleteObject (ii.hbmMask);
1716 DeleteObject (handle);
1719 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1720 DeleteObject (ii.hbmColor);
1721 DeleteObject (ii.hbmMask);
1724 DeleteObject (handle);
1730 /*************************************************************************
1731 * ImageList_Merge [COMCTL32.@]
1733 * Create an image list containing a merged image from two image lists.
1736 * himl1 [I] handle to first image list
1737 * i1 [I] first image index
1738 * himl2 [I] handle to second image list
1739 * i2 [I] second image index
1740 * dx [I] X offset of the second image relative to the first.
1741 * dy [I] Y offset of the second image relative to the first.
1744 * Success: The newly created image list. It contains a single image
1745 * consisting of the second image merged with the first.
1746 * Failure: NULL, if either himl1 or himl2 are invalid.
1749 * - The returned image list should be deleted by the caller using
1750 * ImageList_Destroy() when it is no longer required.
1751 * - If either i1 or i2 are not valid image indices they will be treated
1755 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1758 HIMAGELIST himlDst = NULL;
1760 INT xOff1, yOff1, xOff2, yOff2;
1763 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1766 if (!is_valid(himl1) || !is_valid(himl2))
1770 cxDst = max (himl1->cx, dx + himl2->cx);
1775 cxDst = max (himl2->cx, himl1->cx - dx);
1780 cxDst = max (himl1->cx, himl2->cx);
1786 cyDst = max (himl1->cy, dy + himl2->cy);
1791 cyDst = max (himl2->cy, himl1->cy - dy);
1796 cyDst = max (himl1->cy, himl2->cy);
1801 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1805 nX1 = i1 * himl1->cx;
1806 nX2 = i2 * himl2->cx;
1809 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1810 if (i1 >= 0 && i1 < himl1->cCurImage)
1811 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1812 if (i2 >= 0 && i2 < himl2->cCurImage)
1814 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1815 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1819 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1820 if (i1 >= 0 && i1 < himl1->cCurImage)
1821 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1822 if (i2 >= 0 && i2 < himl2->cCurImage)
1823 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1825 himlDst->cCurImage = 1;
1832 /* helper for _read_bitmap currently unused */
1834 static int may_use_dibsection(HDC hdc) {
1835 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1840 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1844 /* helper for ImageList_Read, see comments below */
1845 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1846 HDC xdc = 0, hBitmapDC =0;
1847 BITMAPFILEHEADER bmfh;
1848 BITMAPINFOHEADER bmih;
1849 int bitsperpixel,palspace,longsperline,width,height;
1850 LPBITMAPINFOHEADER bmihc = NULL;
1852 HBITMAP hbitmap = 0, hDIB = 0;
1855 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1856 (bmfh.bfType != (('M'<<8)|'B')) ||
1857 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1858 (bmih.biSize != sizeof(bmih))
1862 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1863 if (bitsperpixel<=8)
1864 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1867 width = bmih.biWidth;
1868 height = bmih.biHeight;
1869 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1870 if (!bmihc) goto ret1;
1871 memcpy(bmihc,&bmih,sizeof(bmih));
1872 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1873 bmihc->biSizeImage = (longsperline*height)<<2;
1875 /* read the palette right after the end of the bitmapinfoheader */
1877 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1881 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1882 if ((bitsperpixel>1) &&
1883 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1885 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1888 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1894 int i,nwidth,nheight,nRows;
1896 nwidth = width*(height/cy);
1898 nRows = (height/cy);
1900 if (bitsperpixel==1)
1901 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1903 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1905 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1908 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1911 hBitmapDC = CreateCompatibleDC(0);
1912 SelectObject(hBitmapDC, hbitmap);
1914 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1915 /* Do not forget that windows bitmaps are bottom->top */
1916 TRACE("nRows=%d\n", nRows);
1917 for (i=0; i < nRows; i++){
1918 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1919 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1925 if (xdc) ReleaseDC(0,xdc);
1926 if (bmihc) LocalFree((HLOCAL)bmihc);
1927 if (hDIB) DeleteObject(hDIB);
1928 if (hBitmapDC) DeleteDC(hBitmapDC);
1931 DeleteObject(hbitmap);
1938 /*************************************************************************
1939 * ImageList_Read [COMCTL32.@]
1941 * Reads an image list from a stream.
1944 * pstm [I] pointer to a stream
1947 * Success: handle to image list
1950 * The format is like this:
1951 * ILHEAD ilheadstruct;
1953 * for the color image part:
1954 * BITMAPFILEHEADER bmfh;
1955 * BITMAPINFOHEADER bmih;
1956 * only if it has a palette:
1957 * RGBQUAD rgbs[nr_of_paletted_colors];
1959 * BYTE colorbits[imagesize];
1961 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1962 * BITMAPFILEHEADER bmfh_mask;
1963 * BITMAPINFOHEADER bmih_mask;
1964 * only if it has a palette (it usually does not):
1965 * RGBQUAD rgbs[nr_of_paletted_colors];
1967 * BYTE maskbits[imagesize];
1969 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1970 * _read_bitmap needs to convert them.
1972 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1976 HBITMAP hbmColor=0,hbmMask=0;
1979 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1981 if (ilHead.usMagic != (('L' << 8) | 'I'))
1983 if (ilHead.usVersion != 0x101) /* probably version? */
1987 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1988 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1989 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1990 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1991 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1992 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1993 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1994 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1995 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1996 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1999 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2001 WARN("failed to read bitmap from stream\n");
2004 if (ilHead.flags & ILC_MASK) {
2005 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2007 DeleteObject(hbmColor);
2012 himl = ImageList_Create (
2020 DeleteObject(hbmColor);
2021 DeleteObject(hbmMask);
2024 SelectObject(himl->hdcImage, hbmColor);
2025 DeleteObject(himl->hbmImage);
2026 himl->hbmImage = hbmColor;
2028 SelectObject(himl->hdcMask, hbmMask);
2029 DeleteObject(himl->hbmMask);
2030 himl->hbmMask = hbmMask;
2032 himl->cCurImage = ilHead.cCurImage;
2033 himl->cMaxImage = ilHead.cMaxImage;
2035 ImageList_SetBkColor(himl,ilHead.bkcolor);
2037 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2042 /*************************************************************************
2043 * ImageList_Remove [COMCTL32.@]
2045 * Removes an image from an image list
2048 * himl [I] image list handle
2057 ImageList_Remove (HIMAGELIST himl, INT i)
2059 HBITMAP hbmNewImage, hbmNewMask;
2063 TRACE("(himl=%p i=%d)\n", himl, i);
2065 if (!is_valid(himl)) {
2066 ERR("Invalid image list handle!\n");
2070 if ((i < -1) || (i >= himl->cCurImage)) {
2071 TRACE("index out of range! %d\n", i);
2077 if (himl->cCurImage == 0) {
2078 /* remove all on empty ImageList is allowed */
2079 TRACE("remove all on empty ImageList!\n");
2083 himl->cMaxImage = himl->cInitial + himl->cGrow;
2084 himl->cCurImage = 0;
2085 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2086 himl->nOvlIdx[nCount] = -1;
2088 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2089 SelectObject (himl->hdcImage, hbmNewImage);
2090 DeleteObject (himl->hbmImage);
2091 himl->hbmImage = hbmNewImage;
2093 if (himl->hbmMask) {
2096 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2097 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2098 SelectObject (himl->hdcMask, hbmNewMask);
2099 DeleteObject (himl->hbmMask);
2100 himl->hbmMask = hbmNewMask;
2104 /* delete one image */
2105 TRACE("Remove single image! %d\n", i);
2107 /* create new bitmap(s) */
2108 nCount = (himl->cCurImage + himl->cGrow - 1);
2109 cxNew = nCount * himl->cx;
2111 TRACE(" - Number of images: %d / %d (Old/New)\n",
2112 himl->cCurImage, himl->cCurImage - 1);
2113 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2114 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2116 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, nCount, himl->cy);
2119 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2121 hbmNewMask = 0; /* Just to keep compiler happy! */
2123 hdcBmp = CreateCompatibleDC (0);
2125 /* copy all images and masks prior to the "removed" image */
2129 TRACE("Pre image copy: Copy %d images\n", i);
2131 SelectObject (hdcBmp, hbmNewImage);
2132 imagelist_point_from_index(himl, i, &pt);
2133 BitBlt (hdcBmp, 0, 0, pt.x, pt.y, himl->hdcImage, 0, 0, SRCCOPY);
2135 if (himl->hbmMask) {
2136 SelectObject (hdcBmp, hbmNewMask);
2137 BitBlt (hdcBmp, 0, 0, pt.x, pt.y, himl->hdcMask, 0, 0, SRCCOPY);
2141 /* copy all images and masks behind the removed image */
2142 if (i < himl->cCurImage - 1) {
2143 TRACE("Post image copy!\n");
2144 SelectObject (hdcBmp, hbmNewImage);
2145 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2146 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2148 if (himl->hbmMask) {
2149 SelectObject (hdcBmp, hbmNewMask);
2150 BitBlt (hdcBmp, i * himl->cx, 0,
2151 (himl->cCurImage - i - 1) * himl->cx,
2152 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2158 /* delete old images and insert new ones */
2159 SelectObject (himl->hdcImage, hbmNewImage);
2160 DeleteObject (himl->hbmImage);
2161 himl->hbmImage = hbmNewImage;
2162 if (himl->hbmMask) {
2163 SelectObject (himl->hdcMask, hbmNewMask);
2164 DeleteObject (himl->hbmMask);
2165 himl->hbmMask = hbmNewMask;
2169 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2176 /*************************************************************************
2177 * ImageList_Replace [COMCTL32.@]
2179 * Replaces an image in an image list with a new image.
2182 * himl [I] handle to image list
2184 * hbmImage [I] handle to image bitmap
2185 * hbmMask [I] handle to mask bitmap. Can be NULL.
2193 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2201 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2203 if (!is_valid(himl)) {
2204 ERR("Invalid image list handle!\n");
2208 if ((i >= himl->cMaxImage) || (i < 0)) {
2209 ERR("Invalid image index!\n");
2213 hdcImage = CreateCompatibleDC (0);
2214 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2217 hOldBitmap = SelectObject (hdcImage, hbmImage);
2219 imagelist_point_from_index(himl, i, &pt);
2220 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2221 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2226 HBITMAP hOldBitmapTemp;
2228 hdcTemp = CreateCompatibleDC(0);
2229 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2231 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2232 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2233 SelectObject(hdcTemp, hOldBitmapTemp);
2236 /* Remove the background from the image
2238 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2239 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2242 SelectObject (hdcImage, hOldBitmap);
2243 DeleteDC (hdcImage);
2249 /*************************************************************************
2250 * ImageList_ReplaceIcon [COMCTL32.@]
2252 * Replaces an image in an image list using an icon.
2255 * himl [I] handle to image list
2257 * hIcon [I] handle to icon
2260 * Success: index of the replaced image
2265 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2276 TRACE("(%p %d %p)\n", himl, i, hIcon);
2278 if (!is_valid(himl)) {
2279 ERR("invalid image list\n");
2282 if ((i >= himl->cMaxImage) || (i < -1)) {
2283 ERR("invalid image index %d / %d\n", i, himl->cMaxImage);
2287 hBestFitIcon = CopyImage(
2290 LR_COPYFROMRESOURCE);
2291 /* the above will fail if the icon wasn't loaded from a resource, so try
2292 * again without LR_COPYFROMRESOURCE flag */
2294 hBestFitIcon = CopyImage(
2301 ret = GetIconInfo (hBestFitIcon, &ii);
2303 DestroyIcon(hBestFitIcon);
2307 if (ii.hbmColor == 0)
2309 ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2311 ERR("couldn't get mask bitmap info\n");
2313 DeleteObject (ii.hbmColor);
2315 DeleteObject (ii.hbmMask);
2316 DestroyIcon(hBestFitIcon);
2321 if (himl->cCurImage + 1 > himl->cMaxImage)
2322 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2324 nIndex = himl->cCurImage;
2330 hdcImage = CreateCompatibleDC (0);
2331 TRACE("hdcImage=%p\n", hdcImage);
2333 ERR("invalid hdcImage!\n");
2335 SetTextColor(himl->hdcImage, RGB(0,0,0));
2336 SetBkColor (himl->hdcImage, RGB(255,255,255));
2337 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2339 imagelist_point_from_index(himl, nIndex, &pt);
2340 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2341 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2343 if (himl->hbmMask) {
2344 SelectObject (hdcImage, ii.hbmMask);
2345 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2346 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2349 SelectObject (hdcImage, hbmOldSrc);
2351 DestroyIcon(hBestFitIcon);
2353 DeleteDC (hdcImage);
2355 DeleteObject (ii.hbmColor);
2357 DeleteObject (ii.hbmMask);
2359 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2364 /*************************************************************************
2365 * ImageList_SetBkColor [COMCTL32.@]
2367 * Sets the background color of an image list.
2370 * himl [I] handle to image list
2371 * clrBk [I] background color
2374 * Success: previous background color
2379 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2383 if (!is_valid(himl))
2386 clrOldBk = himl->clrBk;
2387 himl->clrBk = clrBk;
2392 /*************************************************************************
2393 * ImageList_SetDragCursorImage [COMCTL32.@]
2395 * Combines the specified image with the current drag image
2398 * himlDrag [I] handle to drag image list
2399 * iDrag [I] drag image index
2400 * dxHotspot [I] X position of the hot spot
2401 * dyHotspot [I] Y position of the hot spot
2408 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2409 * to do with a hotspot but are only the offset of the origin of the new
2410 * image relative to the origin of the old image.
2412 * - When this function is called and the drag image is visible, a
2413 * short flickering occurs but this matches the Win9x behavior. It is
2414 * possible to fix the flickering using code like in ImageList_DragMove.
2418 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2419 INT dxHotspot, INT dyHotspot)
2421 HIMAGELIST himlTemp;
2424 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2427 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2428 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2430 visible = InternalDrag.bShow;
2432 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2433 dxHotspot, dyHotspot);
2436 /* hide the drag image */
2437 ImageList_DragShowNolock(FALSE);
2439 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2440 (InternalDrag.himl->cy != himlTemp->cy)) {
2441 /* the size of the drag image changed, invalidate the buffer */
2442 DeleteObject(InternalDrag.hbmBg);
2443 InternalDrag.hbmBg = 0;
2446 ImageList_Destroy (InternalDrag.himl);
2447 InternalDrag.himl = himlTemp;
2450 /* show the drag image */
2451 ImageList_DragShowNolock(TRUE);
2458 /*************************************************************************
2459 * ImageList_SetFilter [COMCTL32.@]
2461 * Sets a filter (or does something completely different)!!???
2462 * It removes 12 Bytes from the stack (3 Parameters).
2465 * himl [I] SHOULD be a handle to image list
2466 * i [I] COULD be an index?
2471 * Failure: FALSE ???
2474 * This is an UNDOCUMENTED function!!!!
2479 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2481 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2487 /*************************************************************************
2488 * ImageList_SetFlags [COMCTL32.@]
2490 * Sets the image list flags.
2493 * himl [I] Handle to image list
2494 * flags [I] Flags to set
2504 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2506 FIXME("(%p %08x):empty stub\n", himl, flags);
2511 /*************************************************************************
2512 * ImageList_SetIconSize [COMCTL32.@]
2514 * Sets the image size of the bitmap and deletes all images.
2517 * himl [I] handle to image list
2518 * cx [I] image width
2519 * cy [I] image height
2527 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2532 if (!is_valid(himl))
2535 /* remove all images */
2536 himl->cMaxImage = himl->cInitial + himl->cGrow;
2537 himl->cCurImage = 0;
2541 /* initialize overlay mask indices */
2542 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2543 himl->nOvlIdx[nCount] = -1;
2545 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2546 SelectObject (himl->hdcImage, hbmNew);
2547 DeleteObject (himl->hbmImage);
2548 himl->hbmImage = hbmNew;
2550 if (himl->hbmMask) {
2552 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2553 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2554 SelectObject (himl->hdcMask, hbmNew);
2555 DeleteObject (himl->hbmMask);
2556 himl->hbmMask = hbmNew;
2563 /*************************************************************************
2564 * ImageList_SetImageCount [COMCTL32.@]
2566 * Resizes an image list to the specified number of images.
2569 * himl [I] handle to image list
2570 * iImageCount [I] number of images in the image list
2578 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2581 HBITMAP hbmNewBitmap;
2582 INT nNewCount, nCopyCount;
2584 TRACE("%p %d\n",himl,iImageCount);
2586 if (!is_valid(himl))
2588 if (iImageCount < 0)
2590 if (himl->cMaxImage > iImageCount)
2592 himl->cCurImage = iImageCount;
2593 /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2597 nNewCount = iImageCount + himl->cGrow;
2598 nCopyCount = min(himl->cCurImage, iImageCount);
2600 hdcBitmap = CreateCompatibleDC (0);
2602 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cy);
2604 if (hbmNewBitmap != 0)
2606 SelectObject (hdcBitmap, hbmNewBitmap);
2609 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2610 himl->hdcImage, 0, 0, SRCCOPY);
2612 /* delete 'empty' image space */
2613 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2614 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2615 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2616 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2618 SelectObject (himl->hdcImage, hbmNewBitmap);
2619 DeleteObject (himl->hbmImage);
2620 himl->hbmImage = hbmNewBitmap;
2623 ERR("Could not create new image bitmap !\n");
2627 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2629 if (hbmNewBitmap != 0)
2631 SelectObject (hdcBitmap, hbmNewBitmap);
2634 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2635 himl->hdcMask, 0, 0, SRCCOPY);
2637 /* delete 'empty' image space */
2638 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2639 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2640 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2641 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2643 SelectObject (himl->hdcMask, hbmNewBitmap);
2644 DeleteObject (himl->hbmMask);
2645 himl->hbmMask = hbmNewBitmap;
2648 ERR("Could not create new mask bitmap!\n");
2651 DeleteDC (hdcBitmap);
2653 /* Update max image count and current image count */
2654 himl->cMaxImage = nNewCount;
2655 himl->cCurImage = iImageCount;
2661 /*************************************************************************
2662 * ImageList_SetOverlayImage [COMCTL32.@]
2664 * Assigns an overlay mask index to an existing image in an image list.
2667 * himl [I] handle to image list
2668 * iImage [I] image index
2669 * iOverlay [I] overlay mask index
2677 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2679 if (!is_valid(himl))
2681 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2683 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2685 himl->nOvlIdx[iOverlay - 1] = iImage;
2691 /* helper for ImageList_Write - write bitmap to pstm
2692 * currently everything is written as 24 bit RGB, except masks
2695 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2697 LPBITMAPFILEHEADER bmfh;
2698 LPBITMAPINFOHEADER bmih;
2699 LPBYTE data, lpBits, lpBitsOrg;
2701 INT bitCount, sizeImage, offBits, totalSize;
2702 INT nwidth, nheight, nsizeImage, icount;
2704 BOOL result = FALSE;
2708 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2710 /* XXX is this always correct? */
2711 icount = bm.bmWidth / cx;
2713 nheight = cy * icount;
2715 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2716 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2717 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2719 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2721 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2722 offBits = totalSize;
2723 totalSize += nsizeImage;
2725 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2726 bmfh = (LPBITMAPFILEHEADER)data;
2727 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2728 lpBits = data + offBits;
2730 /* setup BITMAPFILEHEADER */
2731 bmfh->bfType = (('M' << 8) | 'B');
2733 bmfh->bfReserved1 = 0;
2734 bmfh->bfReserved2 = 0;
2735 bmfh->bfOffBits = offBits;
2737 /* setup BITMAPINFOHEADER */
2738 bmih->biSize = sizeof(BITMAPINFOHEADER);
2739 bmih->biWidth = bm.bmWidth;
2740 bmih->biHeight = bm.bmHeight;
2742 bmih->biBitCount = bitCount;
2743 bmih->biCompression = BI_RGB;
2744 bmih->biSizeImage = sizeImage;
2745 bmih->biXPelsPerMeter = 0;
2746 bmih->biYPelsPerMeter = 0;
2747 bmih->biClrUsed = 0;
2748 bmih->biClrImportant = 0;
2750 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2751 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2752 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2756 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2757 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2759 for(i = 0; i < nheight; i++) {
2760 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2761 int noff = (nbpl * (nheight-1-i));
2762 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2766 bmih->biWidth = nwidth;
2767 bmih->biHeight = nheight;
2768 bmih->biSizeImage = nsizeImage;
2772 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2773 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2774 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2777 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2784 LocalFree((HLOCAL)lpBitsOrg);
2785 LocalFree((HLOCAL)data);
2791 /*************************************************************************
2792 * ImageList_Write [COMCTL32.@]
2794 * Writes an image list to a stream.
2797 * himl [I] handle to image list
2798 * pstm [O] Pointer to a stream.
2809 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2814 if (!is_valid(himl))
2817 ilHead.usMagic = (('L' << 8) | 'I');
2818 ilHead.usVersion = 0x101;
2819 ilHead.cCurImage = himl->cCurImage;
2820 ilHead.cMaxImage = himl->cMaxImage;
2821 ilHead.cGrow = himl->cGrow;
2822 ilHead.cx = himl->cx;
2823 ilHead.cy = himl->cy;
2824 ilHead.bkcolor = himl->clrBk;
2825 ilHead.flags = himl->flags;
2826 for(i = 0; i < 4; i++) {
2827 ilHead.ovls[i] = himl->nOvlIdx[i];
2830 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2833 /* write the bitmap */
2834 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2837 /* write the mask if we have one */
2838 if(himl->flags & ILC_MASK) {
2839 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2847 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT height)
2849 HBITMAP hbmNewBitmap;
2850 UINT ilc = (himl->flags & 0xFE);
2853 imagelist_get_bitmap_size( himl, count, height, &sz );
2855 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2860 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2862 if (himl->uBitsPixel <= ILC_COLOR8)
2868 colors = 1 << himl->uBitsPixel;
2869 bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2870 sizeof(PALETTEENTRY) * colors);
2872 pal = (LPPALETTEENTRY)bmi->bmiColors;
2873 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2875 /* Swap colors returned by GetPaletteEntries so we can use them for
2876 * CreateDIBSection call. */
2877 for (i = 0; i < colors; i++)
2879 temp = pal[i].peBlue;
2880 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2881 bmi->bmiColors[i].rgbBlue = temp;
2886 bmi = Alloc(sizeof(BITMAPINFOHEADER));
2889 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2890 bmi->bmiHeader.biWidth = sz.cx;
2891 bmi->bmiHeader.biHeight = sz.cy;
2892 bmi->bmiHeader.biPlanes = 1;
2893 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2894 bmi->bmiHeader.biCompression = BI_RGB;
2895 bmi->bmiHeader.biSizeImage = 0;
2896 bmi->bmiHeader.biXPelsPerMeter = 0;
2897 bmi->bmiHeader.biYPelsPerMeter = 0;
2898 bmi->bmiHeader.biClrUsed = 0;
2899 bmi->bmiHeader.biClrImportant = 0;
2901 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2905 else /*if (ilc == ILC_COLORDDB)*/
2907 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2909 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
2911 TRACE("returning %p\n", hbmNewBitmap);
2912 return hbmNewBitmap;
2915 /*************************************************************************
2916 * ImageList_SetColorTable [COMCTL32.@]
2918 * Sets the color table of an image list.
2921 * himl [I] Handle to the image list.
2922 * uStartIndex [I] The first index to set.
2923 * cEntries [I] Number of entries to set.
2924 * prgb [I] New color information for color table for the image list.
2927 * Success: Number of entries in the table that were set.
2931 * ImageList_Create(), SetDIBColorTable()
2935 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2937 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);