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 = (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 ) );
1119 * Draw the initial image
1121 if(fStyle & ILD_MASK) {
1122 if (himl->hbmMask) {
1123 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1125 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1126 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1127 SelectObject(hImageDC, hOldBrush);
1129 } else if (himl->hbmMask && !bIsTransparent) {
1130 /* blend the image with the needed solid background */
1131 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1132 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1133 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1134 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1135 DeleteObject (SelectObject (hImageDC, hOldBrush));
1137 /* start off with the image, if we have a mask, we'll use it later */
1138 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1141 /* Time for blending, if required */
1143 HBRUSH hBlendBrush, hOldBrush;
1144 COLORREF clrBlend = pimldp->rgbFg;
1145 HDC hBlendMaskDC = hImageListDC;
1148 /* Create the blend Mask */
1149 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1150 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1151 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1152 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1153 SelectObject(hBlendMaskDC, hOldBrush);
1155 /* Modify the blend mask if an Image Mask exist */
1157 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1158 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1161 /* now apply blend to the current image given the BlendMask */
1162 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1163 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1164 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1165 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1166 DeleteObject(SelectObject(hImageDC, hOldBrush));
1167 SelectObject(hBlendMaskDC, hOldBitmap);
1170 /* Now do the overlay image, if any */
1171 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1172 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1173 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1174 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1175 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1176 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1177 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1178 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1182 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1183 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1184 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1185 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1187 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1188 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1189 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1191 /* now copy the image to the screen */
1193 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1194 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1195 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1196 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1197 SetBkColor(pimldp->hdcDst, oldDstBk);
1198 SetTextColor(pimldp->hdcDst, oldDstFg);
1201 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1202 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1206 /* cleanup the mess */
1207 SetBkColor(hImageDC, oldImageBk);
1208 SetTextColor(hImageDC, oldImageFg);
1209 SelectObject(hImageDC, hOldImageBmp);
1210 SelectObject(hImageListDC, hOldImageListBmp);
1211 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1213 DeleteObject(hBlendMaskBmp);
1214 DeleteObject(hImageBmp);
1215 DeleteObject(hImageDC);
1216 DeleteObject(hImageListDC);
1217 DeleteObject(hMaskListDC);
1223 /*************************************************************************
1224 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1227 * himlSrc [I] source image list handle
1230 * Success: Handle of duplicated image list.
1235 ImageList_Duplicate (HIMAGELIST himlSrc)
1240 if (himlSrc == NULL) {
1241 ERR("Invalid image list handle!\n");
1245 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1246 himlSrc->cInitial, himlSrc->cGrow);
1250 hdcSrc = CreateCompatibleDC (0);
1251 hdcDst = CreateCompatibleDC (0);
1252 SelectObject (hdcSrc, himlSrc->hbmImage);
1253 SelectObject (hdcDst, himlDst->hbmImage);
1254 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1255 hdcSrc, 0, 0, SRCCOPY);
1257 if (himlDst->hbmMask)
1259 SelectObject (hdcSrc, himlSrc->hbmMask);
1260 SelectObject (hdcDst, himlDst->hbmMask);
1261 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1262 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1268 himlDst->cCurImage = himlSrc->cCurImage;
1269 himlDst->cMaxImage = himlSrc->cMaxImage;
1275 /*************************************************************************
1276 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1278 * Finishes a drag operation.
1289 ImageList_EndDrag (void)
1291 /* cleanup the InternalDrag struct */
1292 InternalDrag.hwnd = 0;
1293 ImageList_Destroy (InternalDrag.himl);
1294 InternalDrag.himl = 0;
1297 InternalDrag.dxHotspot = 0;
1298 InternalDrag.dyHotspot = 0;
1299 InternalDrag.bShow = FALSE;
1300 DeleteObject(InternalDrag.hbmBg);
1301 InternalDrag.hbmBg = 0;
1302 InternalDrag.bHSPending = FALSE;
1308 /*************************************************************************
1309 * ImageList_GetBkColor [COMCTL32.@]
1311 * Returns the background color of an image list.
1314 * himl [I] Image list handle.
1317 * Success: background color
1322 ImageList_GetBkColor (HIMAGELIST himl)
1324 return himl ? himl->clrBk : CLR_NONE;
1328 /*************************************************************************
1329 * ImageList_GetDragImage [COMCTL32.@]
1331 * Returns the handle to the internal drag image list.
1334 * ppt [O] Pointer to the drag position. Can be NULL.
1335 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1338 * Success: Handle of the drag image list.
1343 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1345 if (InternalDrag.himl) {
1347 ppt->x = InternalDrag.x;
1348 ppt->y = InternalDrag.y;
1351 pptHotspot->x = InternalDrag.dxHotspot;
1352 pptHotspot->y = InternalDrag.dyHotspot;
1354 return (InternalDrag.himl);
1361 /*************************************************************************
1362 * ImageList_GetFlags [COMCTL32.@]
1369 ImageList_GetFlags(HIMAGELIST himl)
1371 FIXME("(%p):empty stub\n", himl);
1376 /*************************************************************************
1377 * ImageList_GetIcon [COMCTL32.@]
1379 * Creates an icon from a masked image of an image list.
1382 * himl [I] handle to image list
1384 * flags [I] drawing style flags
1387 * Success: icon handle
1392 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1396 HBITMAP hOldDstBitmap;
1399 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1401 hdcDst = CreateCompatibleDC(0);
1406 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1407 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1408 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1411 SelectObject (hdcDst, himl->hbmImage);
1412 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1413 SelectObject (hdcDst, ii.hbmColor);
1414 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1417 * CreateIconIndirect requires us to deselect the bitmaps from
1418 * the DCs before calling
1420 SelectObject(hdcDst, hOldDstBitmap);
1422 hIcon = CreateIconIndirect (&ii);
1424 DeleteObject (ii.hbmMask);
1425 DeleteObject (ii.hbmColor);
1432 /*************************************************************************
1433 * ImageList_GetIconSize [COMCTL32.@]
1435 * Retrieves the size of an image in an image list.
1438 * himl [I] handle to image list
1439 * cx [O] pointer to the image width.
1440 * cy [O] pointer to the image height.
1447 * All images in an image list have the same size.
1451 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1455 if ((himl->cx <= 0) || (himl->cy <= 0))
1467 /*************************************************************************
1468 * ImageList_GetImageCount [COMCTL32.@]
1470 * Returns the number of images in an image list.
1473 * himl [I] handle to image list
1476 * Success: Number of images.
1481 ImageList_GetImageCount (HIMAGELIST himl)
1486 return himl->cCurImage;
1490 /*************************************************************************
1491 * ImageList_GetImageInfo [COMCTL32.@]
1493 * Returns information about an image in an image list.
1496 * himl [I] handle to image list
1498 * pImageInfo [O] pointer to the image information
1506 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1508 if ((himl == NULL) || (pImageInfo == NULL))
1510 if ((i < 0) || (i >= himl->cCurImage))
1513 pImageInfo->hbmImage = himl->hbmImage;
1514 pImageInfo->hbmMask = himl->hbmMask;
1516 pImageInfo->rcImage.top = 0;
1517 pImageInfo->rcImage.bottom = himl->cy;
1518 pImageInfo->rcImage.left = i * himl->cx;
1519 pImageInfo->rcImage.right = (i+1) * himl->cx;
1525 /*************************************************************************
1526 * ImageList_GetImageRect [COMCTL32.@]
1528 * Retrieves the rectangle of the specified image in an image list.
1531 * himl [I] handle to image list
1533 * lpRect [O] pointer to the image rectangle
1540 * This is an UNDOCUMENTED function!!!
1544 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1546 if ((himl == NULL) || (lpRect == NULL))
1548 if ((i < 0) || (i >= himl->cCurImage))
1551 lpRect->left = i * himl->cx;
1553 lpRect->right = lpRect->left + himl->cx;
1554 lpRect->bottom = himl->cy;
1560 /*************************************************************************
1561 * ImageList_LoadImage [COMCTL32.@]
1562 * ImageList_LoadImageA [COMCTL32.@]
1564 * Creates an image list from a bitmap, icon or cursor.
1567 * hi [I] instance handle
1568 * lpbmp [I] name or id of the image
1569 * cx [I] width of each image
1570 * cGrow [I] number of images to expand
1571 * clrMask [I] mask color
1572 * uType [I] type of image to load
1573 * uFlags [I] loading flags
1576 * Success: handle to the loaded image list
1584 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1585 COLORREF clrMask, UINT uType, UINT uFlags)
1587 HIMAGELIST himl = NULL;
1591 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1593 ERR("Error loading image!\n");
1597 if (uType == IMAGE_BITMAP) {
1599 GetObjectA (handle, sizeof(BITMAP), &bmp);
1601 /* To match windows behavior, if cx is set to zero and
1602 the flag DI_DEFAULTSIZE is specified, cx becomes the
1603 system metric value for icons. If the flag is not specified
1604 the function sets the size to the height of the bitmap */
1607 if (uFlags & DI_DEFAULTSIZE)
1608 cx = GetSystemMetrics (SM_CXICON);
1613 nImageCount = bmp.bmWidth / cx;
1615 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1616 nImageCount, cGrow);
1617 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1619 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1623 GetIconInfo (handle, &ii);
1624 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1625 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1626 ILC_MASK | ILC_COLOR, 1, cGrow);
1627 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1628 DeleteObject (ii.hbmColor);
1629 DeleteObject (ii.hbmMask);
1632 DeleteObject (handle);
1638 /*************************************************************************
1639 * ImageList_LoadImageW [COMCTL32.@]
1641 * Creates an image list from a bitmap, icon or cursor.
1644 * hi [I] instance handle
1645 * lpbmp [I] name or id of the image
1646 * cx [I] width of each image
1647 * cGrow [I] number of images to expand
1648 * clrMask [I] mask color
1649 * uType [I] type of image to load
1650 * uFlags [I] loading flags
1653 * Success: handle to the loaded image list
1661 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1662 COLORREF clrMask, UINT uType, UINT uFlags)
1664 HIMAGELIST himl = NULL;
1668 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1670 ERR("Error loading image!\n");
1674 if (uType == IMAGE_BITMAP) {
1676 GetObjectA (handle, sizeof(BITMAP), &bmp);
1678 /* To match windows behavior, if cx is set to zero and
1679 the flag DI_DEFAULTSIZE is specified, cx becomes the
1680 system metric value for icons. If the flag is not specified
1681 the function sets the size to the height of the bitmap */
1684 if (uFlags & DI_DEFAULTSIZE)
1685 cx = GetSystemMetrics (SM_CXICON);
1690 nImageCount = bmp.bmWidth / cx;
1692 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1693 nImageCount, cGrow);
1694 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1696 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1700 GetIconInfo (handle, &ii);
1701 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1702 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1703 ILC_MASK | ILC_COLOR, 1, cGrow);
1704 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1705 DeleteObject (ii.hbmColor);
1706 DeleteObject (ii.hbmMask);
1709 DeleteObject (handle);
1715 /*************************************************************************
1716 * ImageList_Merge [COMCTL32.@]
1718 * Creates a new image list that contains a merged image from the specified
1719 * images of both source image lists.
1722 * himl1 [I] handle to first image list
1723 * i1 [I] first image index
1724 * himl2 [I] handle to second image list
1725 * i2 [I] second image index
1726 * dx [I] X offset of the second image relative to the first.
1727 * dy [I] Y offset of the second image relative to the first.
1730 * Success: handle of the merged image list.
1735 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1738 HIMAGELIST himlDst = NULL;
1739 HDC hdcSrcImage, hdcDstImage;
1741 INT xOff1, yOff1, xOff2, yOff2;
1744 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1747 if ((himl1 == NULL) || (himl2 == NULL))
1751 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1752 ERR("Index 1 out of range! %d\n", i1);
1756 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1757 ERR("Index 2 out of range! %d\n", i2);
1762 cxDst = max (himl1->cx, dx + himl2->cx);
1767 cxDst = max (himl2->cx, himl1->cx - dx);
1772 cxDst = max (himl1->cx, himl2->cx);
1778 cyDst = max (himl1->cy, dy + himl2->cy);
1783 cyDst = max (himl2->cy, himl1->cy - dy);
1788 cyDst = max (himl1->cy, himl2->cy);
1793 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1796 hdcSrcImage = CreateCompatibleDC (0);
1797 hdcDstImage = CreateCompatibleDC (0);
1798 nX1 = i1 * himl1->cx;
1799 nX2 = i2 * himl2->cx;
1802 SelectObject (hdcSrcImage, himl1->hbmImage);
1803 SelectObject (hdcDstImage, himlDst->hbmImage);
1804 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1805 hdcSrcImage, 0, 0, BLACKNESS);
1806 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1807 hdcSrcImage, nX1, 0, SRCCOPY);
1809 SelectObject (hdcSrcImage, himl2->hbmMask);
1810 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1811 hdcSrcImage, nX2, 0, SRCAND);
1813 SelectObject (hdcSrcImage, himl2->hbmImage);
1814 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1815 hdcSrcImage, nX2, 0, SRCPAINT);
1818 SelectObject (hdcSrcImage, himl1->hbmMask);
1819 SelectObject (hdcDstImage, himlDst->hbmMask);
1820 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1821 hdcSrcImage, 0, 0, WHITENESS);
1822 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1823 hdcSrcImage, nX1, 0, SRCCOPY);
1825 SelectObject (hdcSrcImage, himl2->hbmMask);
1826 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1827 hdcSrcImage, nX2, 0, SRCAND);
1829 DeleteDC (hdcSrcImage);
1830 DeleteDC (hdcDstImage);
1831 himlDst->cCurImage = 1;
1838 /* helper for _read_bitmap currently unused */
1840 static int may_use_dibsection(HDC hdc) {
1841 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1846 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1850 /* helper for ImageList_Read, see comments below */
1851 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1853 BITMAPFILEHEADER bmfh;
1854 BITMAPINFOHEADER bmih;
1855 int bitsperpixel,palspace,longsperline,width,height;
1856 LPBITMAPINFOHEADER bmihc = NULL;
1858 HBITMAP hbitmap = 0;
1859 LPBYTE bits = NULL,nbits = NULL;
1860 int nbytesperline,bytesperline;
1862 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1863 (bmfh.bfType != (('M'<<8)|'B')) ||
1864 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1865 (bmih.biSize != sizeof(bmih))
1869 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1870 if (bitsperpixel<=8)
1871 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1874 width = bmih.biWidth;
1875 height = bmih.biHeight;
1876 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1877 memcpy(bmihc,&bmih,sizeof(bmih));
1878 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1879 bmihc->biSizeImage = (longsperline*height)<<2;
1881 /* read the palette right after the end of the bitmapinfoheader */
1883 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1887 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1888 if ((bitsperpixel>1) &&
1889 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1891 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1894 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1900 int i,nwidth,nheight;
1902 nwidth = width*(height/cy);
1905 if (bitsperpixel==1)
1906 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1908 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1910 /* Might be a bit excessive memory use here */
1911 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1912 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1913 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1916 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1917 /* Do not forget that windows bitmaps are bottom->top */
1918 bytesperline = longsperline*4;
1919 nbytesperline = (height/cy)*bytesperline;
1920 for (i=0;i<height;i++) {
1922 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1923 bits+bytesperline*(height-1-i),
1927 bmihc->biWidth = nwidth;
1928 bmihc->biHeight = nheight;
1929 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1931 LocalFree((HLOCAL)nbits);
1932 LocalFree((HLOCAL)bits);
1936 if (xdc) ReleaseDC(0,xdc);
1937 if (bmihc) LocalFree((HLOCAL)bmihc);
1940 DeleteObject(hbitmap);
1947 /*************************************************************************
1948 * ImageList_Read [COMCTL32.@]
1950 * Reads an image list from a stream.
1953 * pstm [I] pointer to a stream
1956 * Success: handle to image list
1959 * The format is like this:
1960 * ILHEAD ilheadstruct;
1962 * for the color image part:
1963 * BITMAPFILEHEADER bmfh;
1964 * BITMAPINFOHEADER bmih;
1965 * only if it has a palette:
1966 * RGBQUAD rgbs[nr_of_paletted_colors];
1968 * BYTE colorbits[imagesize];
1970 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1971 * BITMAPFILEHEADER bmfh_mask;
1972 * BITMAPINFOHEADER bmih_mask;
1973 * only if it has a palette (it usually does not):
1974 * RGBQUAD rgbs[nr_of_paletted_colors];
1976 * BYTE maskbits[imagesize];
1978 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1979 * _read_bitmap needs to convert them.
1981 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1985 HBITMAP hbmColor=0,hbmMask=0;
1988 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1990 if (ilHead.usMagic != (('L' << 8) | 'I'))
1992 if (ilHead.usVersion != 0x101) /* probably version? */
1996 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1997 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1998 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1999 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2000 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2001 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2002 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2003 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2004 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2005 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2008 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2011 if (ilHead.flags & ILC_MASK) {
2012 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2014 DeleteObject(hbmColor);
2019 himl = ImageList_Create (
2027 DeleteObject(hbmColor);
2028 DeleteObject(hbmMask);
2031 himl->hbmImage = hbmColor;
2032 himl->hbmMask = hbmMask;
2033 himl->cCurImage = ilHead.cCurImage;
2034 himl->cMaxImage = ilHead.cMaxImage;
2036 ImageList_SetBkColor(himl,ilHead.bkcolor);
2038 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2043 /*************************************************************************
2044 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2047 * himl [I] image list handle
2056 ImageList_Remove (HIMAGELIST himl, INT i)
2058 HBITMAP hbmNewImage, hbmNewMask;
2062 TRACE("(himl=%p i=%d)\n", himl, i);
2065 ERR("Invalid image list handle!\n");
2069 if ((i < -1) || (i >= himl->cCurImage)) {
2070 ERR("index out of range! %d\n", i);
2076 if (himl->cCurImage == 0) {
2077 /* remove all on empty ImageList is allowed */
2078 TRACE("remove all on empty ImageList!\n");
2082 himl->cMaxImage = himl->cInitial + himl->cGrow;
2083 himl->cCurImage = 0;
2084 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2085 himl->nOvlIdx[nCount] = -1;
2087 DeleteObject (himl->hbmImage);
2089 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2090 1, himl->uBitsPixel, NULL);
2092 if (himl->hbmMask) {
2093 DeleteObject (himl->hbmMask);
2095 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2100 /* delete one image */
2101 TRACE("Remove single image! %d\n", i);
2103 /* create new bitmap(s) */
2104 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2106 TRACE(" - Number of images: %d / %d (Old/New)\n",
2107 himl->cCurImage, himl->cCurImage - 1);
2108 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2109 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2112 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2115 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2117 hbmNewMask = 0; /* Just to keep compiler happy! */
2119 hdcSrc = CreateCompatibleDC (0);
2120 hdcDst = CreateCompatibleDC (0);
2122 /* copy all images and masks prior to the "removed" image */
2124 TRACE("Pre image copy: Copy %d images\n", i);
2126 SelectObject (hdcSrc, himl->hbmImage);
2127 SelectObject (hdcDst, hbmNewImage);
2128 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2129 hdcSrc, 0, 0, SRCCOPY);
2131 if (himl->hbmMask) {
2132 SelectObject (hdcSrc, himl->hbmMask);
2133 SelectObject (hdcDst, hbmNewMask);
2134 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2135 hdcSrc, 0, 0, SRCCOPY);
2139 /* copy all images and masks behind the removed image */
2140 if (i < himl->cCurImage - 1) {
2141 TRACE("Post image copy!\n");
2142 SelectObject (hdcSrc, himl->hbmImage);
2143 SelectObject (hdcDst, hbmNewImage);
2144 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2145 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2147 if (himl->hbmMask) {
2148 SelectObject (hdcSrc, himl->hbmMask);
2149 SelectObject (hdcDst, hbmNewMask);
2150 BitBlt (hdcDst, i * himl->cx, 0,
2151 (himl->cCurImage - i - 1) * himl->cx,
2152 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2159 /* delete old images and insert new ones */
2160 DeleteObject (himl->hbmImage);
2161 himl->hbmImage = hbmNewImage;
2162 if (himl->hbmMask) {
2163 DeleteObject (himl->hbmMask);
2164 himl->hbmMask = hbmNewMask;
2168 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2175 /*************************************************************************
2176 * ImageList_Replace [COMCTL32.@]
2178 * Replaces an image in an image list with a new image.
2181 * himl [I] handle to image list
2183 * hbmImage [I] handle to image bitmap
2184 * hbmMask [I] handle to mask bitmap. Can be NULL.
2192 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2195 HDC hdcImageList, hdcImage;
2198 TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2201 ERR("Invalid image list handle!\n");
2205 if ((i >= himl->cMaxImage) || (i < 0)) {
2206 ERR("Invalid image index!\n");
2210 hdcImageList = CreateCompatibleDC (0);
2211 hdcImage = CreateCompatibleDC (0);
2212 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2215 SelectObject (hdcImageList, himl->hbmImage);
2216 SelectObject (hdcImage, hbmImage);
2218 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2219 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2224 SelectObject (hdcImageList, himl->hbmMask);
2225 SelectObject (hdcImage, hbmMask);
2227 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2228 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2231 /* Remove the background from the image
2233 SelectObject (hdcImageList, himl->hbmImage);
2234 StretchBlt (hdcImageList,
2235 i*himl->cx, 0, himl->cx, himl->cy,
2237 0, 0, bmp.bmWidth, bmp.bmHeight,
2238 0x220326); /* NOTSRCAND */
2241 DeleteDC (hdcImage);
2242 DeleteDC (hdcImageList);
2248 /*************************************************************************
2249 * ImageList_ReplaceIcon [COMCTL32.@]
2251 * Replaces an image in an image list using an icon.
2254 * himl [I] handle to image list
2256 * hIcon [I] handle to icon
2259 * Success: index of the replaced image
2264 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2266 HDC hdcImageList, hdcImage;
2269 HBITMAP hbmOldSrc, hbmOldDst;
2273 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2277 if ((i >= himl->cMaxImage) || (i < -1))
2280 hBestFitIcon = CopyImage(
2283 LR_COPYFROMRESOURCE);
2285 GetIconInfo (hBestFitIcon, &ii);
2286 if (ii.hbmMask == 0)
2288 if (ii.hbmColor == 0)
2290 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2293 if (himl->cCurImage + 1 > himl->cMaxImage)
2294 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2296 nIndex = himl->cCurImage;
2302 hdcImageList = CreateCompatibleDC (0);
2303 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2304 if (hdcImageList == 0)
2305 ERR("invalid hdcImageList!\n");
2307 hdcImage = CreateCompatibleDC (0);
2308 TRACE("hdcImage=0x%x!\n", hdcImage);
2310 ERR("invalid hdcImage!\n");
2312 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2313 SetTextColor( hdcImageList, RGB(0,0,0));
2314 SetBkColor( hdcImageList, RGB(255,255,255));
2315 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2316 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2317 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2319 if (himl->hbmMask) {
2320 SelectObject (hdcImageList, himl->hbmMask);
2321 SelectObject (hdcImage, ii.hbmMask);
2322 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2323 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2326 SelectObject (hdcImage, hbmOldSrc);
2327 SelectObject (hdcImageList, hbmOldDst);
2330 DestroyIcon(hBestFitIcon);
2332 DeleteDC (hdcImageList);
2334 DeleteDC (hdcImage);
2336 DeleteObject (ii.hbmColor);
2338 DeleteObject (ii.hbmMask);
2344 /*************************************************************************
2345 * ImageList_SetBkColor [COMCTL32.@]
2347 * Sets the background color of an image list.
2350 * himl [I] handle to image list
2351 * clrBk [I] background color
2354 * Success: previous background color
2359 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2366 clrOldBk = himl->clrBk;
2367 himl->clrBk = clrBk;
2372 /*************************************************************************
2373 * ImageList_SetDragCursorImage [COMCTL32.@]
2375 * Combines the specified image with the current drag image
2378 * himlDrag [I] handle to drag image list
2379 * iDrag [I] drag image index
2380 * dxHotspot [I] X position of the hot spot
2381 * dyHotspot [I] Y position of the hot spot
2388 * When this function is called and the drag image is visible, a
2389 * short flickering occurs but this matches the Win9x behavior. It is
2390 * possible to fix the flickering using code like in ImageList_DragMove.
2394 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2395 INT dxHotspot, INT dyHotspot)
2397 HIMAGELIST himlTemp;
2401 if (InternalDrag.himl == NULL)
2404 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2405 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2407 visible = InternalDrag.bShow;
2409 /* Calculate the offset between the origin of the old image and the
2410 * origin of the second image.
2411 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2412 * hotspot) to the origin of the second image.
2413 * See M$DN for details */
2414 if(InternalDrag.bHSPending) {
2417 InternalDrag.bHSPending = FALSE;
2419 dx = InternalDrag.dxHotspot - dxHotspot;
2420 dy = InternalDrag.dyHotspot - dyHotspot;
2422 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2425 /* hide the drag image */
2426 ImageList_DragShowNolock(FALSE);
2428 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2429 (InternalDrag.himl->cy != himlTemp->cy)) {
2430 /* the size of the drag image changed, invalidate the buffer */
2431 DeleteObject(InternalDrag.hbmBg);
2432 InternalDrag.hbmBg = 0;
2435 ImageList_Destroy (InternalDrag.himl);
2436 InternalDrag.himl = himlTemp;
2438 /* update the InternalDragOffset, if the origin of the
2439 * DragImage was changed by ImageList_Merge. */
2441 InternalDrag.dxHotspot = dxHotspot;
2443 InternalDrag.dyHotspot = dyHotspot;
2446 /* show the drag image */
2447 ImageList_DragShowNolock(TRUE);
2454 /*************************************************************************
2455 * ImageList_SetFilter [COMCTL32.@]
2457 * Sets a filter (or does something completely different)!!???
2458 * It removes 12 Bytes from the stack (3 Parameters).
2461 * himl [I] SHOULD be a handle to image list
2462 * i [I] COULD be an index?
2467 * Failure: FALSE ???
2470 * This is an UNDOCUMENTED function!!!!
2475 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2477 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2483 /*************************************************************************
2484 * ImageList_SetFlags [COMCTL32.@]
2491 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2493 FIXME("(%p %08lx):empty stub\n", himl, flags);
2498 /*************************************************************************
2499 * ImageList_SetIconSize [COMCTL32.@]
2501 * Sets the image size of the bitmap and deletes all images.
2504 * himl [I] handle to image list
2505 * cx [I] image width
2506 * cy [I] image height
2514 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2521 /* remove all images */
2522 himl->cMaxImage = himl->cInitial + himl->cGrow;
2523 himl->cCurImage = 0;
2527 /* initialize overlay mask indices */
2528 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2529 himl->nOvlIdx[nCount] = -1;
2531 DeleteObject (himl->hbmImage);
2533 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2534 1, himl->uBitsPixel, NULL);
2536 if (himl->hbmMask) {
2537 DeleteObject (himl->hbmMask);
2539 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2547 /*************************************************************************
2548 * ImageList_SetImageCount [COMCTL32.@]
2550 * Resizes an image list to the specified number of images.
2553 * himl [I] handle to image list
2554 * iImageCount [I] number of images in the image list
2562 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2564 HDC hdcImageList, hdcBitmap;
2565 HBITMAP hbmNewBitmap;
2566 INT nNewCount, nCopyCount;
2568 TRACE("%p %d\n",himl,iImageCount);
2572 if (himl->cCurImage >= iImageCount)
2574 if (himl->cMaxImage > iImageCount)
2576 himl->cCurImage = iImageCount;
2580 nNewCount = iImageCount + himl->cGrow;
2581 nCopyCount = min(himl->cCurImage, iImageCount);
2583 hdcImageList = CreateCompatibleDC (0);
2584 hdcBitmap = CreateCompatibleDC (0);
2586 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2587 1, himl->uBitsPixel, NULL);
2588 if (hbmNewBitmap != 0)
2590 SelectObject (hdcImageList, himl->hbmImage);
2591 SelectObject (hdcBitmap, hbmNewBitmap);
2594 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2595 hdcImageList, 0, 0, SRCCOPY);
2597 /* delete 'empty' image space */
2598 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2599 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2600 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2601 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2603 DeleteObject (himl->hbmImage);
2604 himl->hbmImage = hbmNewBitmap;
2607 ERR("Could not create new image bitmap !\n");
2611 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2613 if (hbmNewBitmap != 0)
2615 SelectObject (hdcImageList, himl->hbmMask);
2616 SelectObject (hdcBitmap, hbmNewBitmap);
2619 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2620 hdcImageList, 0, 0, SRCCOPY);
2622 /* delete 'empty' image space */
2623 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2624 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2625 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2626 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2628 DeleteObject (himl->hbmMask);
2629 himl->hbmMask = hbmNewBitmap;
2632 ERR("Could not create new mask bitmap!\n");
2635 DeleteDC (hdcImageList);
2636 DeleteDC (hdcBitmap);
2638 /* Update max image count and current image count */
2639 himl->cMaxImage = nNewCount;
2640 himl->cCurImage = iImageCount;
2646 /*************************************************************************
2647 * ImageList_SetOverlayImage [COMCTL32.@]
2649 * Assigns an overlay mask index to an existing image in an image list.
2652 * himl [I] handle to image list
2653 * iImage [I] image index
2654 * iOverlay [I] overlay mask index
2662 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2666 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2668 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2670 himl->nOvlIdx[iOverlay - 1] = iImage;
2676 /* helper for ImageList_Write - write bitmap to pstm
2677 * currently everything is written as 24 bit RGB, except masks
2680 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2682 LPBITMAPFILEHEADER bmfh;
2683 LPBITMAPINFOHEADER bmih;
2684 LPBYTE data, lpBits, lpBitsOrg;
2686 INT bitCount, sizeImage, offBits, totalSize;
2687 INT nwidth, nheight, nsizeImage, icount;
2689 BOOL result = FALSE;
2693 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2695 /* XXX is this always correct? */
2696 icount = bm.bmWidth / cx;
2698 nheight = cy * ((icount+3)>>2);
2700 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2701 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2702 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2704 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2706 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2707 offBits = totalSize;
2708 totalSize += nsizeImage;
2710 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2711 bmfh = (LPBITMAPFILEHEADER)data;
2712 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2713 lpBits = data + offBits;
2715 /* setup BITMAPFILEHEADER */
2716 bmfh->bfType = (('M' << 8) | 'B');
2718 bmfh->bfReserved1 = 0;
2719 bmfh->bfReserved2 = 0;
2720 bmfh->bfOffBits = offBits;
2722 /* setup BITMAPINFOHEADER */
2723 bmih->biSize = sizeof(BITMAPINFOHEADER);
2724 bmih->biWidth = bm.bmWidth;
2725 bmih->biHeight = bm.bmHeight;
2727 bmih->biBitCount = bitCount;
2728 bmih->biCompression = BI_RGB;
2729 bmih->biSizeImage = nsizeImage;
2730 bmih->biXPelsPerMeter = 0;
2731 bmih->biYPelsPerMeter = 0;
2732 bmih->biClrUsed = 0;
2733 bmih->biClrImportant = 0;
2735 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2736 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2737 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2741 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2742 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2744 for(i = 0; i < nheight; i++) {
2745 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2746 int noff = (nbpl * (nheight-1-i));
2747 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2751 bmih->biWidth = nwidth;
2752 bmih->biHeight = nheight;
2756 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2757 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2758 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2761 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2768 LocalFree((HLOCAL)lpBitsOrg);
2774 /*************************************************************************
2775 * ImageList_Write [COMCTL32.@]
2777 * Writes an image list to a stream.
2780 * himl [I] handle to image list
2781 * pstm [O] Pointer to a stream.
2792 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2800 ilHead.usMagic = (('L' << 8) | 'I');
2801 ilHead.usVersion = 0x101;
2802 ilHead.cCurImage = himl->cCurImage;
2803 ilHead.cMaxImage = himl->cMaxImage;
2804 ilHead.cGrow = himl->cGrow;
2805 ilHead.cx = himl->cx;
2806 ilHead.cy = himl->cy;
2807 ilHead.bkcolor = himl->clrBk;
2808 ilHead.flags = himl->flags;
2809 for(i = 0; i < 4; i++) {
2810 ilHead.ovls[i] = himl->nOvlIdx[i];
2813 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2816 /* write the bitmap */
2817 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2820 /* write the mask if we have one */
2821 if(himl->flags & ILC_MASK) {
2822 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))