2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001 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
25 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
26 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
29 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
30 * is the offset of the image position relative to the actual mouse pointer
31 * position. However the Hotspot passed to SetDragCursorImage is the
32 * offset of the mouse messages sent to the application...
39 #include "wine/obj_base.h"
40 #include "wine/obj_storage.h"
42 #include "imagelist.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
48 #define MAX_OVERLAYIMAGE 15
50 /* internal image list data used for Drag & Drop operations */
55 /* position of the drag image relative to the window */
58 /* offset of the hotspot relative to the origin of the image */
61 /* is the drag image visible */
63 /* saved background */
68 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
72 /*************************************************************************
73 * IMAGELIST_InternalExpandBitmaps [Internal]
75 * Expands the bitmaps of an image list by the given number of images.
78 * himl [I] handle to image list
79 * nImageCount [I] number of images to add
85 * This function can NOT be used to reduce the number of images.
88 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
90 HDC hdcImageList, hdcBitmap;
92 INT nNewWidth, nNewCount;
94 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
98 if (cy == 0) cy = himl->cy;
99 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
100 nNewWidth = nNewCount * himl->cx;
102 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
103 hdcImageList = CreateCompatibleDC (0);
104 hdcBitmap = CreateCompatibleDC (0);
107 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
108 if (hbmNewBitmap == 0)
109 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
111 SelectObject (hdcImageList, himl->hbmImage);
112 SelectObject (hdcBitmap, hbmNewBitmap);
113 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
114 hdcImageList, 0, 0, SRCCOPY);
116 DeleteObject (himl->hbmImage);
117 himl->hbmImage = hbmNewBitmap;
121 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
123 if (hbmNewBitmap == 0)
124 ERR("creating new mask bitmap!\n");
126 SelectObject (hdcImageList, himl->hbmMask);
127 SelectObject (hdcBitmap, hbmNewBitmap);
128 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
129 hdcImageList, 0, 0, SRCCOPY);
130 DeleteObject (himl->hbmMask);
131 himl->hbmMask = hbmNewBitmap;
134 himl->cMaxImage = nNewCount;
136 DeleteDC (hdcImageList);
137 DeleteDC (hdcBitmap);
141 /*************************************************************************
142 * ImageList_Add [COMCTL32.@]
144 * Add an image or images to an image list.
147 * himl [I] handle to image list
148 * hbmImage [I] handle to image bitmap
149 * hbmMask [I] handle to mask bitmap
152 * Success: Index of the first new image.
157 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
159 HDC hdcImage, hdcBitmap;
160 INT nFirstIndex, nImageCount;
163 HBITMAP hOldBitmapImage, hOldBitmap;
165 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
166 if (!himl || !hbmImage)
169 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
170 nImageCount = bmp.bmWidth / himl->cx;
172 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
174 nStartX = himl->cCurImage * himl->cx;
176 hdcImage = CreateCompatibleDC(0);
177 hdcBitmap = CreateCompatibleDC(0);
179 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
180 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
182 /* Copy result to the imagelist
184 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
185 hdcBitmap, 0, 0, SRCCOPY);
189 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
191 hdcMask = CreateCompatibleDC (0);
192 hdcTemp = CreateCompatibleDC(0);
193 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
194 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
197 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
202 SelectObject(hdcTemp, hOldBitmapTemp);
205 /* Remove the background from the image
208 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
211 0x220326); /* NOTSRCAND */
213 SelectObject(hdcMask, hOldBitmapMask);
217 SelectObject(hdcImage, hOldBitmapImage);
218 SelectObject(hdcBitmap, hOldBitmap);
222 nFirstIndex = himl->cCurImage;
223 himl->cCurImage += nImageCount;
229 /*************************************************************************
230 * ImageList_AddIcon [COMCTL32.@]
232 * Adds an icon to an image list.
235 * himl [I] handle to image list
236 * hIcon [I] handle to icon
239 * Success: index of the new image
244 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
246 return ImageList_ReplaceIcon (himl, -1, hIcon);
250 /*************************************************************************
251 * ImageList_AddMasked [COMCTL32.@]
253 * Adds an image or images to an image list and creates a mask from the
254 * specified bitmap using the mask color.
257 * himl [I] handle to image list.
258 * hBitmap [I] handle to bitmap
259 * clrMask [I] mask color.
262 * Success: Index of the first new image.
267 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
269 HDC hdcImage, hdcMask, hdcBitmap;
270 INT nIndex, nImageCount, nMaskXOffset=0;
272 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
273 HBITMAP hMaskBitmap=0;
276 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
280 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
283 nImageCount = bmp.bmWidth / himl->cx;
285 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
287 nIndex = himl->cCurImage;
288 himl->cCurImage += nImageCount;
290 hdcMask = CreateCompatibleDC (0);
291 hdcImage = CreateCompatibleDC(0);
292 hdcBitmap = CreateCompatibleDC(0);
295 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
296 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
299 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
300 nMaskXOffset = nIndex * himl->cx;
305 Create a temp Mask so we can remove the background of
306 the Image (Windows does this even if there is no mask)
308 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
309 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
312 /* create monochrome image to the mask bitmap */
313 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
314 GetPixel (hdcBitmap, 0, 0);
315 SetBkColor (hdcBitmap, bkColor);
317 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
321 SetBkColor(hdcBitmap, RGB(255,255,255));
322 /*Remove the background from the image
325 WINDOWS BUG ALERT!!!!!!
326 The statement below should not be done in common practice
327 but this is how ImageList_AddMasked works in Windows.
328 It overwrites the original bitmap passed, this was discovered
329 by using the same bitmap to iterate the different styles
330 on windows where it failed (BUT ImageList_Add is OK)
331 This is here in case some apps rely on this bug
334 0, 0, bmp.bmWidth, bmp.bmHeight,
337 0x220326); /* NOTSRCAND */
338 /* Copy result to the imagelist
341 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
347 SelectObject(hdcMask,hOldBitmapMask);
348 SelectObject(hdcImage, hOldBitmapImage);
349 SelectObject(hdcBitmap, hOldBitmap);
355 DeleteObject(hMaskBitmap);
362 /*************************************************************************
363 * ImageList_BeginDrag [COMCTL32.@]
365 * Creates a temporary image list that contains one image. It will be used
369 * himlTrack [I] handle to the source image list
370 * iTrack [I] index of the drag image in the source image list
371 * dxHotspot [I] X position of the hot spot of the drag image
372 * dyHotspot [I] Y position of the hot spot of the drag image
380 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
381 INT dxHotspot, INT dyHotspot)
386 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
387 dxHotspot, dyHotspot);
389 if (himlTrack == NULL)
392 if (InternalDrag.himl)
393 ImageList_EndDrag ();
398 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
399 if (InternalDrag.himl == NULL) {
400 WARN("Error creating drag image list!\n");
404 InternalDrag.dxHotspot = dxHotspot;
405 InternalDrag.dyHotspot = dyHotspot;
407 hdcSrc = CreateCompatibleDC (0);
408 hdcDst = CreateCompatibleDC (0);
411 SelectObject (hdcSrc, himlTrack->hbmImage);
412 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
413 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
416 SelectObject (hdcSrc, himlTrack->hbmMask);
417 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
418 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
423 InternalDrag.himl->cCurImage = 1;
424 InternalDrag.bHSPending = TRUE;
430 /*************************************************************************
431 * ImageList_Copy [COMCTL32.@]
433 * Copies an image of the source image list to an image of the
434 * destination image list. Images can be copied or swapped.
437 * himlDst [I] handle to the destination image list
438 * iDst [I] destination image index.
439 * himlSrc [I] handle to the source image list
440 * iSrc [I] source image index
441 * uFlags [I] flags for the copy operation
448 * Copying from one image list to another is possible. The original
449 * implementation just copies or swaps within one image list.
450 * Could this feature become a bug??? ;-)
454 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
455 INT iSrc, INT uFlags)
459 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
461 if ((himlSrc == NULL) || (himlDst == NULL))
463 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
465 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
468 hdcSrc = CreateCompatibleDC (0);
469 if (himlDst == himlSrc)
472 hdcDst = CreateCompatibleDC (0);
474 if (uFlags & ILCF_SWAP) {
476 HBITMAP hbmTempImage, hbmTempMask;
478 /* create temporary bitmaps */
479 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
480 himlSrc->uBitsPixel, NULL);
481 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
484 /* copy (and stretch) destination to temporary bitmaps.(save) */
486 SelectObject (hdcSrc, himlDst->hbmImage);
487 SelectObject (hdcDst, hbmTempImage);
488 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
489 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
492 SelectObject (hdcSrc, himlDst->hbmMask);
493 SelectObject (hdcDst, hbmTempMask);
494 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
495 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
498 /* copy (and stretch) source to destination */
500 SelectObject (hdcSrc, himlSrc->hbmImage);
501 SelectObject (hdcDst, himlDst->hbmImage);
502 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
503 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
506 SelectObject (hdcSrc, himlSrc->hbmMask);
507 SelectObject (hdcDst, himlDst->hbmMask);
508 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
509 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
512 /* copy (without stretching) temporary bitmaps to source (restore) */
514 SelectObject (hdcSrc, hbmTempImage);
515 SelectObject (hdcDst, himlSrc->hbmImage);
516 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
517 hdcSrc, 0, 0, SRCCOPY);
519 SelectObject (hdcSrc, hbmTempMask);
520 SelectObject (hdcDst, himlSrc->hbmMask);
521 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
522 hdcSrc, 0, 0, SRCCOPY);
524 /* delete temporary bitmaps */
525 DeleteObject (hbmTempMask);
526 DeleteObject (hbmTempImage);
530 SelectObject (hdcSrc, himlSrc->hbmImage);
531 if (himlSrc == himlDst)
534 SelectObject (hdcDst, himlDst->hbmImage);
535 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
536 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
540 SelectObject (hdcSrc, himlSrc->hbmMask);
541 if (himlSrc == himlDst)
544 SelectObject (hdcDst, himlDst->hbmMask);
545 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
546 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
551 if (himlSrc != himlDst)
558 /*************************************************************************
559 * ImageList_Create [COMCTL32.@] Creates a new image list.
562 * cx [I] image height
564 * flags [I] creation flags
565 * cInitial [I] initial number of images in the image list
566 * cGrow [I] number of images by which image list grows
569 * Success: Handle to the created image list
574 ImageList_Create (INT cx, INT cy, UINT flags,
575 INT cInitial, INT cGrow)
581 static WORD aBitBlend25[] =
582 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
584 static WORD aBitBlend50[] =
585 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
587 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
589 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
596 himl->cMaxImage = cInitial + cGrow;
597 himl->cInitial = cInitial;
600 himl->clrFg = CLR_DEFAULT;
601 himl->clrBk = CLR_NONE;
603 /* initialize overlay mask indices */
604 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
605 himl->nOvlIdx[nCount] = -1;
607 hdc = CreateCompatibleDC (0);
608 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
611 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
613 if (himl->cMaxImage > 0) {
615 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
616 1, himl->uBitsPixel, NULL);
617 if (himl->hbmImage == 0) {
618 ERR("Error creating image bitmap!\n");
625 if ( (himl->flags & ILC_MASK)) {
626 int images = himl->cMaxImage;
630 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
632 if (himl->hbmMask == 0) {
633 ERR("Error creating mask bitmap!\n");
635 DeleteObject (himl->hbmImage);
642 /* create blending brushes */
643 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
644 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
645 DeleteObject (hbmTemp);
647 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
648 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
649 DeleteObject (hbmTemp);
651 TRACE("created imagelist %p\n", himl);
656 /*************************************************************************
657 * ImageList_Destroy [COMCTL32.@]
659 * Destroys an image list.
662 * himl [I] handle to image list
670 ImageList_Destroy (HIMAGELIST himl)
675 /* delete image bitmaps */
677 DeleteObject (himl->hbmImage);
679 DeleteObject (himl->hbmMask);
681 /* delete blending brushes */
682 if (himl->hbrBlend25)
683 DeleteObject (himl->hbrBlend25);
684 if (himl->hbrBlend50)
685 DeleteObject (himl->hbrBlend50);
687 COMCTL32_Free (himl);
693 /*************************************************************************
694 * ImageList_DragEnter [COMCTL32.@]
696 * Locks window update and displays the drag image at the given position.
699 * hwndLock [I] handle of the window that owns the drag image.
700 * x [I] X position of the drag image.
701 * y [I] Y position of the drag image.
708 * The position of the drag image is relative to the window, not
713 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
715 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
717 if (InternalDrag.himl == NULL)
721 InternalDrag.hwnd = hwndLock;
723 InternalDrag.hwnd = GetDesktopWindow ();
728 /* draw the drag image and save the background */
729 if (!ImageList_DragShowNolock(TRUE)) {
737 /*************************************************************************
738 * ImageList_DragLeave [COMCTL32.@]
740 * Unlocks window update and hides the drag image.
743 * hwndLock [I] handle of the window that owns the drag image.
751 ImageList_DragLeave (HWND hwndLock)
753 /* As we don't save drag info in the window this can lead to problems if
754 an app does not supply the same window as DragEnter */
756 InternalDrag.hwnd = hwndLock;
758 InternalDrag.hwnd = GetDesktopWindow (); */
760 hwndLock = GetDesktopWindow();
761 if(InternalDrag.hwnd != hwndLock)
762 FIXME("DragLeave hWnd != DragEnter hWnd\n");
764 ImageList_DragShowNolock (FALSE);
770 /*************************************************************************
771 * ImageList_InternalDragDraw [Internal]
773 * Draws the drag image.
776 * hdc [I] device context to draw into.
777 * x [I] X position of the drag image.
778 * y [I] Y position of the drag image.
785 * The position of the drag image is relative to the window, not
791 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
793 IMAGELISTDRAWPARAMS imldp;
795 ZeroMemory (&imldp, sizeof(imldp));
796 imldp.cbSize = sizeof(imldp);
797 imldp.himl = InternalDrag.himl;
802 imldp.rgbBk = CLR_DEFAULT;
803 imldp.rgbFg = CLR_DEFAULT;
804 imldp.fStyle = ILD_NORMAL;
805 imldp.fState = ILS_ALPHA;
808 /* FIXME: instead of using the alpha blending, we should
809 * create a 50% mask, and draw it semitransparantly that way */
810 ImageList_DrawIndirect (&imldp);
813 /*************************************************************************
814 * ImageList_DragMove [COMCTL32.@]
816 * Moves the drag image.
819 * x [I] X position of the drag image.
820 * y [I] Y position of the drag image.
827 * The position of the drag image is relative to the window, not
831 * The drag image should be drawn semitransparent.
835 ImageList_DragMove (INT x, INT y)
837 TRACE("(x=%d y=%d)\n", x, y);
839 if (!InternalDrag.himl) {
843 /* draw/update the drag image */
844 if (InternalDrag.bShow) {
848 HBITMAP hbmOffScreen;
849 INT origNewX, origNewY;
850 INT origOldX, origOldY;
851 INT origRegX, origRegY;
852 INT sizeRegX, sizeRegY;
855 /* calculate the update region */
856 origNewX = x - InternalDrag.dxHotspot;
857 origNewY = y - InternalDrag.dyHotspot;
858 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
859 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
860 origRegX = min(origNewX, origOldX);
861 origRegY = min(origNewY, origOldY);
862 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
863 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
865 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
866 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
867 hdcOffScreen = CreateCompatibleDC(hdcDrag);
868 hdcBg = CreateCompatibleDC(hdcDrag);
870 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
871 SelectObject(hdcOffScreen, hbmOffScreen);
872 SelectObject(hdcBg, InternalDrag.hbmBg);
874 /* get the actual background of the update region */
875 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
876 origRegX, origRegY, SRCCOPY);
877 /* erase the old image */
878 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
879 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
881 /* save the background */
882 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
883 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
885 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
886 origNewY - origRegY);
887 /* draw the update region to the screen */
888 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
889 hdcOffScreen, 0, 0, SRCCOPY);
892 DeleteDC(hdcOffScreen);
893 DeleteObject(hbmOffScreen);
894 ReleaseDC(InternalDrag.hwnd, hdcDrag);
897 /* update the image position */
905 /*************************************************************************
906 * ImageList_DragShowNolock [COMCTL32.@]
908 * Shows or hides the drag image.
911 * bShow [I] TRUE shows the drag image, FALSE hides it.
918 * The drag image should be drawn semitransparent.
922 ImageList_DragShowNolock (BOOL bShow)
928 TRACE("bShow=0x%X!\n", bShow);
930 /* DragImage is already visible/hidden */
931 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
935 /* position of the origin of the DragImage */
936 x = InternalDrag.x - InternalDrag.dxHotspot;
937 y = InternalDrag.y - InternalDrag.dyHotspot;
939 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
940 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
945 hdcBg = CreateCompatibleDC(hdcDrag);
946 if (!InternalDrag.hbmBg) {
947 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
948 InternalDrag.himl->cx, InternalDrag.himl->cy);
950 SelectObject(hdcBg, InternalDrag.hbmBg);
953 /* save the background */
954 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
955 hdcDrag, x, y, SRCCOPY);
957 ImageList_InternalDragDraw(hdcDrag, x, y);
960 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
961 hdcBg, 0, 0, SRCCOPY);
964 InternalDrag.bShow = !InternalDrag.bShow;
967 ReleaseDC (InternalDrag.hwnd, hdcDrag);
972 /*************************************************************************
973 * ImageList_Draw [COMCTL32.@] Draws an image.
976 * himl [I] handle to image list
978 * hdc [I] handle to device context
981 * fStyle [I] drawing flags
992 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
994 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
995 CLR_DEFAULT, CLR_DEFAULT, fStyle);
999 /*************************************************************************
1000 * ImageList_DrawEx [COMCTL32.@]
1002 * Draws an image and allows to use extended drawing features.
1005 * himl [I] handle to image list
1007 * hdc [I] handle to device context
1012 * rgbBk [I] background color
1013 * rgbFg [I] foreground color
1014 * fStyle [I] drawing flags
1021 * Calls ImageList_DrawIndirect.
1024 * ImageList_DrawIndirect.
1028 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1029 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1032 IMAGELISTDRAWPARAMS imldp;
1034 ZeroMemory (&imldp, sizeof(imldp));
1035 imldp.cbSize = sizeof(imldp);
1043 imldp.rgbBk = rgbBk;
1044 imldp.rgbFg = rgbFg;
1045 imldp.fStyle = fStyle;
1047 return ImageList_DrawIndirect (&imldp);
1051 /*************************************************************************
1052 * ImageList_DrawIndirect [COMCTL32.@]
1054 * Draws an image using ...
1057 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1065 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1067 INT cx, cy, nOvlIdx;
1068 DWORD fState, dwRop;
1070 COLORREF clrBk, oldImageBk, oldImageFg;
1071 HDC hImageDC, hImageListDC, hMaskListDC;
1072 HBITMAP hImageBmp, hOldImageBmp, hOldImageListBmp, hOldMaskListBmp, hBlendMaskBmp;
1073 BOOL bIsTransparent, bBlend, bResult = FALSE;
1074 const HIMAGELIST himl = pimldp->himl;
1075 const INT lx = himl->cx * pimldp->i + pimldp->xBitmap;
1076 const INT ly = pimldp->yBitmap;
1078 if (!pimldp || !himl) return FALSE;
1079 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1081 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1082 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1083 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1084 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1085 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1086 bIsTransparent = himl->hbmMask && ((fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE);
1087 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1089 TRACE("hbmMask(0x%08x) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1090 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1092 /* we will use these DCs to access the images and masks in the ImageList */
1093 hImageListDC = CreateCompatibleDC(0);
1094 hMaskListDC = himl->hbmMask ? CreateCompatibleDC(0) : 0;
1096 /* these will accumulate the image and mask for the image we're drawing */
1097 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1098 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1099 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1101 /* Create a compatible DC. */
1102 if (!hImageListDC || !hImageDC || !hImageBmp ||
1103 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1106 hOldImageListBmp = SelectObject(hImageListDC, himl->hbmImage);
1107 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1108 hOldMaskListBmp = hMaskListDC ? SelectObject(hMaskListDC, himl->hbmMask) : 0;
1111 * To obtain a transparent look, background color should be set
1112 * to white and foreground color to black when blting the
1115 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1116 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1118 /* If we have an opaque image, draw the background */
1119 if (!bIsTransparent && himl->hbmMask) {
1120 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1121 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1122 DeleteObject (SelectObject (hImageDC, hOldBrush));
1126 * Draw Image over the current background
1128 if(fStyle & ILD_MASK) {
1129 if (himl->hbmMask) {
1130 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1132 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1133 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1134 SelectObject(hImageDC, hOldBrush);
1136 } else if (himl->hbmMask) {
1137 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1138 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1140 /* the image is opaque, just copy it */
1141 TRACE(" - Image is opaque\n");
1142 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1145 /* Time for blending, if required */
1147 HBRUSH hBlendBrush, hOldBrush;
1148 COLORREF clrBlend = pimldp->rgbFg;
1149 HDC hBlendMaskDC = hImageListDC;
1152 /* Create the blend Mask */
1153 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1154 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1155 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1156 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1157 SelectObject(hBlendMaskDC, hOldBrush);
1159 /* Modify the blend mask if an Image Mask exist */
1161 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1162 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1165 /* now apply blend to the current image given the BlendMask */
1166 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1167 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1168 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1169 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1170 DeleteObject(SelectObject(hImageDC, hOldBrush));
1171 SelectObject(hBlendMaskDC, hOldBitmap);
1174 /* Now do the overlay image, if any */
1175 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1176 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1177 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1178 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1179 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1180 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1181 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1182 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1186 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1187 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1188 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1189 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1191 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1192 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1193 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1195 /* now copy the image to the screen */
1197 if (bIsTransparent && !(fStyle & ILD_MASK)) {
1198 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1199 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1200 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1201 SetBkColor(pimldp->hdcDst, oldDstBk);
1202 SetTextColor(pimldp->hdcDst, oldDstFg);
1205 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1206 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1210 /* cleanup the mess */
1211 SetBkColor(hImageDC, oldImageBk);
1212 SetTextColor(hImageDC, oldImageFg);
1213 SelectObject(hImageDC, hOldImageBmp);
1214 SelectObject(hImageListDC, hOldImageListBmp);
1215 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1217 DeleteObject(hBlendMaskBmp);
1218 DeleteObject(hImageBmp);
1219 DeleteObject(hImageDC);
1220 DeleteObject(hImageListDC);
1221 DeleteObject(hMaskListDC);
1227 /*************************************************************************
1228 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1231 * himlSrc [I] source image list handle
1234 * Success: Handle of duplicated image list.
1239 ImageList_Duplicate (HIMAGELIST himlSrc)
1244 if (himlSrc == NULL) {
1245 ERR("Invalid image list handle!\n");
1249 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1250 himlSrc->cInitial, himlSrc->cGrow);
1254 hdcSrc = CreateCompatibleDC (0);
1255 hdcDst = CreateCompatibleDC (0);
1256 SelectObject (hdcSrc, himlSrc->hbmImage);
1257 SelectObject (hdcDst, himlDst->hbmImage);
1258 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1259 hdcSrc, 0, 0, SRCCOPY);
1261 if (himlDst->hbmMask)
1263 SelectObject (hdcSrc, himlSrc->hbmMask);
1264 SelectObject (hdcDst, himlDst->hbmMask);
1265 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1266 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1272 himlDst->cCurImage = himlSrc->cCurImage;
1273 himlDst->cMaxImage = himlSrc->cMaxImage;
1279 /*************************************************************************
1280 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1282 * Finishes a drag operation.
1293 ImageList_EndDrag (void)
1295 /* cleanup the InternalDrag struct */
1296 InternalDrag.hwnd = 0;
1297 ImageList_Destroy (InternalDrag.himl);
1298 InternalDrag.himl = 0;
1301 InternalDrag.dxHotspot = 0;
1302 InternalDrag.dyHotspot = 0;
1303 InternalDrag.bShow = FALSE;
1304 DeleteObject(InternalDrag.hbmBg);
1305 InternalDrag.hbmBg = 0;
1306 InternalDrag.bHSPending = FALSE;
1312 /*************************************************************************
1313 * ImageList_GetBkColor [COMCTL32.@]
1315 * Returns the background color of an image list.
1318 * himl [I] Image list handle.
1321 * Success: background color
1326 ImageList_GetBkColor (HIMAGELIST himl)
1328 return himl ? himl->clrBk : CLR_NONE;
1332 /*************************************************************************
1333 * ImageList_GetDragImage [COMCTL32.@]
1335 * Returns the handle to the internal drag image list.
1338 * ppt [O] Pointer to the drag position. Can be NULL.
1339 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1342 * Success: Handle of the drag image list.
1347 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1349 if (InternalDrag.himl) {
1351 ppt->x = InternalDrag.x;
1352 ppt->y = InternalDrag.y;
1355 pptHotspot->x = InternalDrag.dxHotspot;
1356 pptHotspot->y = InternalDrag.dyHotspot;
1358 return (InternalDrag.himl);
1365 /*************************************************************************
1366 * ImageList_GetFlags [COMCTL32.@]
1373 ImageList_GetFlags(HIMAGELIST himl)
1375 FIXME("(%p):empty stub\n", himl);
1380 /*************************************************************************
1381 * ImageList_GetIcon [COMCTL32.@]
1383 * Creates an icon from a masked image of an image list.
1386 * himl [I] handle to image list
1388 * flags [I] drawing style flags
1391 * Success: icon handle
1396 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1400 HBITMAP hOldDstBitmap;
1403 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1405 hdcDst = CreateCompatibleDC(0);
1410 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1411 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1412 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1415 SelectObject (hdcDst, himl->hbmImage);
1416 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1417 SelectObject (hdcDst, ii.hbmColor);
1418 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1421 * CreateIconIndirect requires us to deselect the bitmaps from
1422 * the DCs before calling
1424 SelectObject(hdcDst, hOldDstBitmap);
1426 hIcon = CreateIconIndirect (&ii);
1428 DeleteObject (ii.hbmMask);
1429 DeleteObject (ii.hbmColor);
1436 /*************************************************************************
1437 * ImageList_GetIconSize [COMCTL32.@]
1439 * Retrieves the size of an image in an image list.
1442 * himl [I] handle to image list
1443 * cx [O] pointer to the image width.
1444 * cy [O] pointer to the image height.
1451 * All images in an image list have the same size.
1455 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1459 if ((himl->cx <= 0) || (himl->cy <= 0))
1471 /*************************************************************************
1472 * ImageList_GetImageCount [COMCTL32.@]
1474 * Returns the number of images in an image list.
1477 * himl [I] handle to image list
1480 * Success: Number of images.
1485 ImageList_GetImageCount (HIMAGELIST himl)
1490 return himl->cCurImage;
1494 /*************************************************************************
1495 * ImageList_GetImageInfo [COMCTL32.@]
1497 * Returns information about an image in an image list.
1500 * himl [I] handle to image list
1502 * pImageInfo [O] pointer to the image information
1510 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1512 if ((himl == NULL) || (pImageInfo == NULL))
1514 if ((i < 0) || (i >= himl->cCurImage))
1517 pImageInfo->hbmImage = himl->hbmImage;
1518 pImageInfo->hbmMask = himl->hbmMask;
1520 pImageInfo->rcImage.top = 0;
1521 pImageInfo->rcImage.bottom = himl->cy;
1522 pImageInfo->rcImage.left = i * himl->cx;
1523 pImageInfo->rcImage.right = (i+1) * himl->cx;
1529 /*************************************************************************
1530 * ImageList_GetImageRect [COMCTL32.@]
1532 * Retrieves the rectangle of the specified image in an image list.
1535 * himl [I] handle to image list
1537 * lpRect [O] pointer to the image rectangle
1544 * This is an UNDOCUMENTED function!!!
1548 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1550 if ((himl == NULL) || (lpRect == NULL))
1552 if ((i < 0) || (i >= himl->cCurImage))
1555 lpRect->left = i * himl->cx;
1557 lpRect->right = lpRect->left + himl->cx;
1558 lpRect->bottom = himl->cy;
1564 /*************************************************************************
1565 * ImageList_LoadImage [COMCTL32.@]
1566 * ImageList_LoadImageA [COMCTL32.@]
1568 * Creates an image list from a bitmap, icon or cursor.
1571 * hi [I] instance handle
1572 * lpbmp [I] name or id of the image
1573 * cx [I] width of each image
1574 * cGrow [I] number of images to expand
1575 * clrMask [I] mask color
1576 * uType [I] type of image to load
1577 * uFlags [I] loading flags
1580 * Success: handle to the loaded image list
1588 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1589 COLORREF clrMask, UINT uType, UINT uFlags)
1591 HIMAGELIST himl = NULL;
1595 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1597 ERR("Error loading image!\n");
1601 if (uType == IMAGE_BITMAP) {
1603 GetObjectA (handle, sizeof(BITMAP), &bmp);
1605 /* To match windows behavior, if cx is set to zero and
1606 the flag DI_DEFAULTSIZE is specified, cx becomes the
1607 system metric value for icons. If the flag is not specified
1608 the function sets the size to the height of the bitmap */
1611 if (uFlags & DI_DEFAULTSIZE)
1612 cx = GetSystemMetrics (SM_CXICON);
1617 nImageCount = bmp.bmWidth / cx;
1619 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1620 nImageCount, cGrow);
1621 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1623 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1627 GetIconInfo (handle, &ii);
1628 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1629 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1630 ILC_MASK | ILC_COLOR, 1, cGrow);
1631 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1632 DeleteObject (ii.hbmColor);
1633 DeleteObject (ii.hbmMask);
1636 DeleteObject (handle);
1642 /*************************************************************************
1643 * ImageList_LoadImageW [COMCTL32.@]
1645 * Creates an image list from a bitmap, icon or cursor.
1648 * hi [I] instance handle
1649 * lpbmp [I] name or id of the image
1650 * cx [I] width of each image
1651 * cGrow [I] number of images to expand
1652 * clrMask [I] mask color
1653 * uType [I] type of image to load
1654 * uFlags [I] loading flags
1657 * Success: handle to the loaded image list
1665 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1666 COLORREF clrMask, UINT uType, UINT uFlags)
1668 HIMAGELIST himl = NULL;
1672 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1674 ERR("Error loading image!\n");
1678 if (uType == IMAGE_BITMAP) {
1680 GetObjectA (handle, sizeof(BITMAP), &bmp);
1682 /* To match windows behavior, if cx is set to zero and
1683 the flag DI_DEFAULTSIZE is specified, cx becomes the
1684 system metric value for icons. If the flag is not specified
1685 the function sets the size to the height of the bitmap */
1688 if (uFlags & DI_DEFAULTSIZE)
1689 cx = GetSystemMetrics (SM_CXICON);
1694 nImageCount = bmp.bmWidth / cx;
1696 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1697 nImageCount, cGrow);
1698 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1700 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1704 GetIconInfo (handle, &ii);
1705 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1706 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1707 ILC_MASK | ILC_COLOR, 1, cGrow);
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 * Creates a new image list that contains a merged image from the specified
1723 * images of both source image lists.
1726 * himl1 [I] handle to first image list
1727 * i1 [I] first image index
1728 * himl2 [I] handle to second image list
1729 * i2 [I] second image index
1730 * dx [I] X offset of the second image relative to the first.
1731 * dy [I] Y offset of the second image relative to the first.
1734 * Success: handle of the merged image list.
1739 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1742 HIMAGELIST himlDst = NULL;
1743 HDC hdcSrcImage, hdcDstImage;
1745 INT xOff1, yOff1, xOff2, yOff2;
1748 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1751 if ((himl1 == NULL) || (himl2 == NULL))
1755 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1756 ERR("Index 1 out of range! %d\n", i1);
1760 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1761 ERR("Index 2 out of range! %d\n", i2);
1766 cxDst = max (himl1->cx, dx + himl2->cx);
1771 cxDst = max (himl2->cx, himl1->cx - dx);
1776 cxDst = max (himl1->cx, himl2->cx);
1782 cyDst = max (himl1->cy, dy + himl2->cy);
1787 cyDst = max (himl2->cy, himl1->cy - dy);
1792 cyDst = max (himl1->cy, himl2->cy);
1797 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1800 hdcSrcImage = CreateCompatibleDC (0);
1801 hdcDstImage = CreateCompatibleDC (0);
1802 nX1 = i1 * himl1->cx;
1803 nX2 = i2 * himl2->cx;
1806 SelectObject (hdcSrcImage, himl1->hbmImage);
1807 SelectObject (hdcDstImage, himlDst->hbmImage);
1808 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1809 hdcSrcImage, 0, 0, BLACKNESS);
1810 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1811 hdcSrcImage, nX1, 0, SRCCOPY);
1813 SelectObject (hdcSrcImage, himl2->hbmMask);
1814 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1815 hdcSrcImage, nX2, 0, SRCAND);
1817 SelectObject (hdcSrcImage, himl2->hbmImage);
1818 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1819 hdcSrcImage, nX2, 0, SRCPAINT);
1822 SelectObject (hdcSrcImage, himl1->hbmMask);
1823 SelectObject (hdcDstImage, himlDst->hbmMask);
1824 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1825 hdcSrcImage, 0, 0, WHITENESS);
1826 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1827 hdcSrcImage, nX1, 0, SRCCOPY);
1829 SelectObject (hdcSrcImage, himl2->hbmMask);
1830 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1831 hdcSrcImage, nX2, 0, SRCAND);
1833 DeleteDC (hdcSrcImage);
1834 DeleteDC (hdcDstImage);
1835 himlDst->cCurImage = 1;
1842 /* helper for _read_bitmap currently unused */
1844 static int may_use_dibsection(HDC hdc) {
1845 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1850 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1854 /* helper for ImageList_Read, see comments below */
1855 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1857 BITMAPFILEHEADER bmfh;
1858 BITMAPINFOHEADER bmih;
1859 int bitsperpixel,palspace,longsperline,width,height;
1860 LPBITMAPINFOHEADER bmihc = NULL;
1862 HBITMAP hbitmap = 0;
1863 LPBYTE bits = NULL,nbits = NULL;
1864 int nbytesperline,bytesperline;
1866 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1867 (bmfh.bfType != (('M'<<8)|'B')) ||
1868 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1869 (bmih.biSize != sizeof(bmih))
1873 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1874 if (bitsperpixel<=8)
1875 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1878 width = bmih.biWidth;
1879 height = bmih.biHeight;
1880 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1881 memcpy(bmihc,&bmih,sizeof(bmih));
1882 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1883 bmihc->biSizeImage = (longsperline*height)<<2;
1885 /* read the palette right after the end of the bitmapinfoheader */
1887 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1891 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1892 if ((bitsperpixel>1) &&
1893 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1895 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1898 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1904 int i,nwidth,nheight;
1906 nwidth = width*(height/cy);
1909 if (bitsperpixel==1)
1910 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1912 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1914 /* Might be a bit excessive memory use here */
1915 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1916 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1917 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1920 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1921 /* Do not forget that windows bitmaps are bottom->top */
1922 bytesperline = longsperline*4;
1923 nbytesperline = (height/cy)*bytesperline;
1924 for (i=0;i<height;i++) {
1926 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1927 bits+bytesperline*(height-1-i),
1931 bmihc->biWidth = nwidth;
1932 bmihc->biHeight = nheight;
1933 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1935 LocalFree((HLOCAL)nbits);
1936 LocalFree((HLOCAL)bits);
1940 if (xdc) ReleaseDC(0,xdc);
1941 if (bmihc) LocalFree((HLOCAL)bmihc);
1944 DeleteObject(hbitmap);
1951 /*************************************************************************
1952 * ImageList_Read [COMCTL32.@]
1954 * Reads an image list from a stream.
1957 * pstm [I] pointer to a stream
1960 * Success: handle to image list
1963 * The format is like this:
1964 * ILHEAD ilheadstruct;
1966 * for the color image part:
1967 * BITMAPFILEHEADER bmfh;
1968 * BITMAPINFOHEADER bmih;
1969 * only if it has a palette:
1970 * RGBQUAD rgbs[nr_of_paletted_colors];
1972 * BYTE colorbits[imagesize];
1974 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1975 * BITMAPFILEHEADER bmfh_mask;
1976 * BITMAPINFOHEADER bmih_mask;
1977 * only if it has a palette (it usually does not):
1978 * RGBQUAD rgbs[nr_of_paletted_colors];
1980 * BYTE maskbits[imagesize];
1982 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1983 * _read_bitmap needs to convert them.
1985 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1989 HBITMAP hbmColor=0,hbmMask=0;
1992 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1994 if (ilHead.usMagic != (('L' << 8) | 'I'))
1996 if (ilHead.usVersion != 0x101) /* probably version? */
2000 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2001 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2002 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2003 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2004 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2005 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2006 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2007 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2008 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2009 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2012 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2015 if (ilHead.flags & ILC_MASK) {
2016 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2018 DeleteObject(hbmColor);
2023 himl = ImageList_Create (
2031 DeleteObject(hbmColor);
2032 DeleteObject(hbmMask);
2035 himl->hbmImage = hbmColor;
2036 himl->hbmMask = hbmMask;
2037 himl->cCurImage = ilHead.cCurImage;
2038 himl->cMaxImage = ilHead.cMaxImage;
2040 ImageList_SetBkColor(himl,ilHead.bkcolor);
2042 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2047 /*************************************************************************
2048 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2051 * himl [I] image list handle
2060 ImageList_Remove (HIMAGELIST himl, INT i)
2062 HBITMAP hbmNewImage, hbmNewMask;
2066 TRACE("(himl=%p i=%d)\n", himl, i);
2069 ERR("Invalid image list handle!\n");
2073 if ((i < -1) || (i >= himl->cCurImage)) {
2074 ERR("index out of range! %d\n", i);
2080 if (himl->cCurImage == 0) {
2081 /* remove all on empty ImageList is allowed */
2082 TRACE("remove all on empty ImageList!\n");
2086 himl->cMaxImage = himl->cInitial + himl->cGrow;
2087 himl->cCurImage = 0;
2088 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2089 himl->nOvlIdx[nCount] = -1;
2091 DeleteObject (himl->hbmImage);
2093 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2094 1, himl->uBitsPixel, NULL);
2096 if (himl->hbmMask) {
2097 DeleteObject (himl->hbmMask);
2099 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2104 /* delete one image */
2105 TRACE("Remove single image! %d\n", i);
2107 /* create new bitmap(s) */
2108 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2110 TRACE(" - Number of images: %d / %d (Old/New)\n",
2111 himl->cCurImage, himl->cCurImage - 1);
2112 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2113 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2116 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2119 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2121 hbmNewMask = 0; /* Just to keep compiler happy! */
2123 hdcSrc = CreateCompatibleDC (0);
2124 hdcDst = CreateCompatibleDC (0);
2126 /* copy all images and masks prior to the "removed" image */
2128 TRACE("Pre image copy: Copy %d images\n", i);
2130 SelectObject (hdcSrc, himl->hbmImage);
2131 SelectObject (hdcDst, hbmNewImage);
2132 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2133 hdcSrc, 0, 0, SRCCOPY);
2135 if (himl->hbmMask) {
2136 SelectObject (hdcSrc, himl->hbmMask);
2137 SelectObject (hdcDst, hbmNewMask);
2138 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2139 hdcSrc, 0, 0, SRCCOPY);
2143 /* copy all images and masks behind the removed image */
2144 if (i < himl->cCurImage - 1) {
2145 TRACE("Post image copy!\n");
2146 SelectObject (hdcSrc, himl->hbmImage);
2147 SelectObject (hdcDst, hbmNewImage);
2148 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2149 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2151 if (himl->hbmMask) {
2152 SelectObject (hdcSrc, himl->hbmMask);
2153 SelectObject (hdcDst, hbmNewMask);
2154 BitBlt (hdcDst, i * himl->cx, 0,
2155 (himl->cCurImage - i - 1) * himl->cx,
2156 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2163 /* delete old images and insert new ones */
2164 DeleteObject (himl->hbmImage);
2165 himl->hbmImage = hbmNewImage;
2166 if (himl->hbmMask) {
2167 DeleteObject (himl->hbmMask);
2168 himl->hbmMask = hbmNewMask;
2172 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2179 /*************************************************************************
2180 * ImageList_Replace [COMCTL32.@]
2182 * Replaces an image in an image list with a new image.
2185 * himl [I] handle to image list
2187 * hbmImage [I] handle to image bitmap
2188 * hbmMask [I] handle to mask bitmap. Can be NULL.
2196 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2199 HDC hdcImageList, hdcImage;
2202 TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2205 ERR("Invalid image list handle!\n");
2209 if ((i >= himl->cMaxImage) || (i < 0)) {
2210 ERR("Invalid image index!\n");
2214 hdcImageList = CreateCompatibleDC (0);
2215 hdcImage = CreateCompatibleDC (0);
2216 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2219 SelectObject (hdcImageList, himl->hbmImage);
2220 SelectObject (hdcImage, hbmImage);
2222 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2223 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2228 SelectObject (hdcImageList, himl->hbmMask);
2229 SelectObject (hdcImage, hbmMask);
2231 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2232 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2235 /* Remove the background from the image
2237 SelectObject (hdcImageList, himl->hbmImage);
2238 StretchBlt (hdcImageList,
2239 i*himl->cx, 0, himl->cx, himl->cy,
2241 0, 0, bmp.bmWidth, bmp.bmHeight,
2242 0x220326); /* NOTSRCAND */
2245 DeleteDC (hdcImage);
2246 DeleteDC (hdcImageList);
2252 /*************************************************************************
2253 * ImageList_ReplaceIcon [COMCTL32.@]
2255 * Replaces an image in an image list using an icon.
2258 * himl [I] handle to image list
2260 * hIcon [I] handle to icon
2263 * Success: index of the replaced image
2268 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2270 HDC hdcImageList, hdcImage;
2273 HBITMAP hbmOldSrc, hbmOldDst;
2277 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2281 if ((i >= himl->cMaxImage) || (i < -1))
2284 hBestFitIcon = CopyImage(
2287 LR_COPYFROMRESOURCE);
2289 GetIconInfo (hBestFitIcon, &ii);
2290 if (ii.hbmMask == 0)
2292 if (ii.hbmColor == 0)
2294 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2297 if (himl->cCurImage + 1 > himl->cMaxImage)
2298 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2300 nIndex = himl->cCurImage;
2306 hdcImageList = CreateCompatibleDC (0);
2307 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2308 if (hdcImageList == 0)
2309 ERR("invalid hdcImageList!\n");
2311 hdcImage = CreateCompatibleDC (0);
2312 TRACE("hdcImage=0x%x!\n", hdcImage);
2314 ERR("invalid hdcImage!\n");
2316 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2317 SetTextColor( hdcImageList, RGB(0,0,0));
2318 SetBkColor( hdcImageList, RGB(255,255,255));
2319 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2320 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2321 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2323 if (himl->hbmMask) {
2324 SelectObject (hdcImageList, himl->hbmMask);
2325 SelectObject (hdcImage, ii.hbmMask);
2326 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2327 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2330 SelectObject (hdcImage, hbmOldSrc);
2331 SelectObject (hdcImageList, hbmOldDst);
2334 DestroyIcon(hBestFitIcon);
2336 DeleteDC (hdcImageList);
2338 DeleteDC (hdcImage);
2340 DeleteObject (ii.hbmColor);
2342 DeleteObject (ii.hbmMask);
2348 /*************************************************************************
2349 * ImageList_SetBkColor [COMCTL32.@]
2351 * Sets the background color of an image list.
2354 * himl [I] handle to image list
2355 * clrBk [I] background color
2358 * Success: previous background color
2363 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2370 clrOldBk = himl->clrBk;
2371 himl->clrBk = clrBk;
2376 /*************************************************************************
2377 * ImageList_SetDragCursorImage [COMCTL32.@]
2379 * Combines the specified image with the current drag image
2382 * himlDrag [I] handle to drag image list
2383 * iDrag [I] drag image index
2384 * dxHotspot [I] X position of the hot spot
2385 * dyHotspot [I] Y position of the hot spot
2392 * When this function is called and the drag image is visible, a
2393 * short flickering occurs but this matches the Win9x behavior. It is
2394 * possible to fix the flickering using code like in ImageList_DragMove.
2398 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2399 INT dxHotspot, INT dyHotspot)
2401 HIMAGELIST himlTemp;
2405 if (InternalDrag.himl == NULL)
2408 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2409 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2411 visible = InternalDrag.bShow;
2413 /* Calculate the offset between the origin of the old image and the
2414 * origin of the second image.
2415 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2416 * hotspot) to the origin of the second image.
2417 * See M$DN for details */
2418 if(InternalDrag.bHSPending) {
2421 InternalDrag.bHSPending = FALSE;
2423 dx = InternalDrag.dxHotspot - dxHotspot;
2424 dy = InternalDrag.dyHotspot - dyHotspot;
2426 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2429 /* hide the drag image */
2430 ImageList_DragShowNolock(FALSE);
2432 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2433 (InternalDrag.himl->cy != himlTemp->cy)) {
2434 /* the size of the drag image changed, invalidate the buffer */
2435 DeleteObject(InternalDrag.hbmBg);
2436 InternalDrag.hbmBg = 0;
2439 ImageList_Destroy (InternalDrag.himl);
2440 InternalDrag.himl = himlTemp;
2442 /* update the InternalDragOffset, if the origin of the
2443 * DragImage was changed by ImageList_Merge. */
2445 InternalDrag.dxHotspot = dxHotspot;
2447 InternalDrag.dyHotspot = dyHotspot;
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%lx):empty stub!\n", himl, i, dwFilter);
2487 /*************************************************************************
2488 * ImageList_SetFlags [COMCTL32.@]
2495 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2497 FIXME("(%p %08lx):empty stub\n", himl, flags);
2502 /*************************************************************************
2503 * ImageList_SetIconSize [COMCTL32.@]
2505 * Sets the image size of the bitmap and deletes all images.
2508 * himl [I] handle to image list
2509 * cx [I] image width
2510 * cy [I] image height
2518 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2525 /* remove all images */
2526 himl->cMaxImage = himl->cInitial + himl->cGrow;
2527 himl->cCurImage = 0;
2531 /* initialize overlay mask indices */
2532 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2533 himl->nOvlIdx[nCount] = -1;
2535 DeleteObject (himl->hbmImage);
2537 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2538 1, himl->uBitsPixel, NULL);
2540 if (himl->hbmMask) {
2541 DeleteObject (himl->hbmMask);
2543 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2551 /*************************************************************************
2552 * ImageList_SetImageCount [COMCTL32.@]
2554 * Resizes an image list to the specified number of images.
2557 * himl [I] handle to image list
2558 * iImageCount [I] number of images in the image list
2566 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2568 HDC hdcImageList, hdcBitmap;
2569 HBITMAP hbmNewBitmap;
2570 INT nNewCount, nCopyCount;
2572 TRACE("%p %d\n",himl,iImageCount);
2576 if (himl->cCurImage >= iImageCount)
2578 if (himl->cMaxImage > iImageCount)
2580 himl->cCurImage = iImageCount;
2584 nNewCount = iImageCount + himl->cGrow;
2585 nCopyCount = min(himl->cCurImage, iImageCount);
2587 hdcImageList = CreateCompatibleDC (0);
2588 hdcBitmap = CreateCompatibleDC (0);
2590 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2591 1, himl->uBitsPixel, NULL);
2592 if (hbmNewBitmap != 0)
2594 SelectObject (hdcImageList, himl->hbmImage);
2595 SelectObject (hdcBitmap, hbmNewBitmap);
2598 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2599 hdcImageList, 0, 0, SRCCOPY);
2601 /* delete 'empty' image space */
2602 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2603 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2604 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2605 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2607 DeleteObject (himl->hbmImage);
2608 himl->hbmImage = hbmNewBitmap;
2611 ERR("Could not create new image bitmap !\n");
2615 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2617 if (hbmNewBitmap != 0)
2619 SelectObject (hdcImageList, himl->hbmMask);
2620 SelectObject (hdcBitmap, hbmNewBitmap);
2623 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2624 hdcImageList, 0, 0, SRCCOPY);
2626 /* delete 'empty' image space */
2627 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2628 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2629 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2630 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2632 DeleteObject (himl->hbmMask);
2633 himl->hbmMask = hbmNewBitmap;
2636 ERR("Could not create new mask bitmap!\n");
2639 DeleteDC (hdcImageList);
2640 DeleteDC (hdcBitmap);
2642 /* Update max image count and current image count */
2643 himl->cMaxImage = nNewCount;
2644 himl->cCurImage = iImageCount;
2650 /*************************************************************************
2651 * ImageList_SetOverlayImage [COMCTL32.@]
2653 * Assigns an overlay mask index to an existing image in an image list.
2656 * himl [I] handle to image list
2657 * iImage [I] image index
2658 * iOverlay [I] overlay mask index
2666 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2670 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2672 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2674 himl->nOvlIdx[iOverlay - 1] = iImage;
2680 /* helper for ImageList_Write - write bitmap to pstm
2681 * currently everything is written as 24 bit RGB, except masks
2684 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2686 LPBITMAPFILEHEADER bmfh;
2687 LPBITMAPINFOHEADER bmih;
2688 LPBYTE data, lpBits, lpBitsOrg;
2690 INT bitCount, sizeImage, offBits, totalSize;
2691 INT nwidth, nheight, nsizeImage, icount;
2693 BOOL result = FALSE;
2697 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2699 /* XXX is this always correct? */
2700 icount = bm.bmWidth / cx;
2702 nheight = cy * ((icount+3)>>2);
2704 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2705 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2706 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2708 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2710 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2711 offBits = totalSize;
2712 totalSize += nsizeImage;
2714 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2715 bmfh = (LPBITMAPFILEHEADER)data;
2716 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2717 lpBits = data + offBits;
2719 /* setup BITMAPFILEHEADER */
2720 bmfh->bfType = (('M' << 8) | 'B');
2722 bmfh->bfReserved1 = 0;
2723 bmfh->bfReserved2 = 0;
2724 bmfh->bfOffBits = offBits;
2726 /* setup BITMAPINFOHEADER */
2727 bmih->biSize = sizeof(BITMAPINFOHEADER);
2728 bmih->biWidth = bm.bmWidth;
2729 bmih->biHeight = bm.bmHeight;
2731 bmih->biBitCount = bitCount;
2732 bmih->biCompression = BI_RGB;
2733 bmih->biSizeImage = nsizeImage;
2734 bmih->biXPelsPerMeter = 0;
2735 bmih->biYPelsPerMeter = 0;
2736 bmih->biClrUsed = 0;
2737 bmih->biClrImportant = 0;
2739 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2740 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2741 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2745 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2746 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2748 for(i = 0; i < nheight; i++) {
2749 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2750 int noff = (nbpl * (nheight-1-i));
2751 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2755 bmih->biWidth = nwidth;
2756 bmih->biHeight = nheight;
2760 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2761 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2762 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2765 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2772 LocalFree((HLOCAL)lpBitsOrg);
2778 /*************************************************************************
2779 * ImageList_Write [COMCTL32.@]
2781 * Writes an image list to a stream.
2784 * himl [I] handle to image list
2785 * pstm [O] Pointer to a stream.
2796 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2804 ilHead.usMagic = (('L' << 8) | 'I');
2805 ilHead.usVersion = 0x101;
2806 ilHead.cCurImage = himl->cCurImage;
2807 ilHead.cMaxImage = himl->cMaxImage;
2808 ilHead.cGrow = himl->cGrow;
2809 ilHead.cx = himl->cx;
2810 ilHead.cy = himl->cy;
2811 ilHead.bkcolor = himl->clrBk;
2812 ilHead.flags = himl->flags;
2813 for(i = 0; i < 4; i++) {
2814 ilHead.ovls[i] = himl->nOvlIdx[i];
2817 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2820 /* write the bitmap */
2821 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2824 /* write the mask if we have one */
2825 if(himl->flags & ILC_MASK) {
2826 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))