Removed trailing whitespace.
[wine/wine-gecko.git] / dlls / comctl32 / imagelist.c
blob9697813b5593074310c2d14326938e39a96ae8a4
1 /*
2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * 2000 Jason Mawdsley.
6 * 2001 Michael Stefaniuc
7 * 2001 Charles Loep for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * TODO:
24 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
25 * - Fix ImageList_GetIcon.
26 * - Fix ImageList_SetFilter (undocumented).
27 * BTW does anybody know anything about this function???
28 * - It removes 12 Bytes from the stack (3 Parameters).
29 * - First parameter SHOULD be a HIMAGELIST.
30 * - Second parameter COULD be an index?????
31 * - Third parameter.... ?????????????????????
33 * Comments:
34 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
35 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
36 * partially implemented, the functions mentioned above will be
37 * limited in functionality too.
39 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
40 * is the offset of the image position relative to the actual mouse pointer
41 * position. However the Hotspot passed to SetDragCursorImage is the
42 * offset of the mouse messages sent to the application...
45 #include <stdlib.h>
46 #include <string.h>
47 #include "winerror.h"
48 #include "winbase.h"
49 #include "wine/obj_base.h"
50 #include "wine/obj_storage.h"
51 #include "commctrl.h"
52 #include "imagelist.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
58 #define MAX_OVERLAYIMAGE 15
60 /* internal image list data used for Drag & Drop operations */
61 typedef struct
63 HWND hwnd;
64 HIMAGELIST himl;
65 /* position of the drag image relative to the window */
66 INT x;
67 INT y;
68 /* offset of the hotspot relative to the origin of the image */
69 INT dxHotspot;
70 INT dyHotspot;
71 /* is the drag image visible */
72 BOOL bShow;
73 /* saved background */
74 HBITMAP hbmBg;
75 BOOL bHSPending;
76 } INTERNALDRAG;
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
82 /*************************************************************************
83 * IMAGELIST_InternalExpandBitmaps [Internal]
85 * Expands the bitmaps of an image list by the given number of images.
87 * PARAMS
88 * himl [I] handle to image list
89 * nImageCount [I] number of images to add
91 * RETURNS
92 * nothing
94 * NOTES
95 * This function can NOT be used to reduce the number of images.
97 static VOID
98 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
100 HDC hdcImageList, hdcBitmap;
101 HBITMAP hbmNewBitmap;
102 INT nNewWidth, nNewCount;
104 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
105 && (himl->cy >= cy))
106 return;
108 if (cy == 0) cy = himl->cy;
109 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
110 nNewWidth = nNewCount * himl->cx;
112 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
113 hdcImageList = CreateCompatibleDC (0);
114 hdcBitmap = CreateCompatibleDC (0);
116 hbmNewBitmap =
117 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
118 if (hbmNewBitmap == 0)
119 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
121 SelectObject (hdcImageList, himl->hbmImage);
122 SelectObject (hdcBitmap, hbmNewBitmap);
123 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
124 hdcImageList, 0, 0, SRCCOPY);
126 DeleteObject (himl->hbmImage);
127 himl->hbmImage = hbmNewBitmap;
129 if (himl->hbmMask) {
130 hbmNewBitmap =
131 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
133 if (hbmNewBitmap == 0)
134 ERR("creating new mask bitmap!\n");
136 SelectObject (hdcImageList, himl->hbmMask);
137 SelectObject (hdcBitmap, hbmNewBitmap);
138 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
139 hdcImageList, 0, 0, SRCCOPY);
140 DeleteObject (himl->hbmMask);
141 himl->hbmMask = hbmNewBitmap;
144 himl->cMaxImage = nNewCount;
146 DeleteDC (hdcImageList);
147 DeleteDC (hdcBitmap);
151 /*************************************************************************
152 * IMAGELIST_InternalDraw [Internal]
154 * Draws the image in the ImageList (without the mask)
156 * PARAMS
157 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
158 * cx [I] the width of the image to display
159 * cy............[I] the height of the image to display
161 * RETURNS
162 * nothing
164 * NOTES
165 * This function is used by ImageList_DrawIndirect, when it is
166 * required to draw only the Image (without the mask) to the screen.
168 * Blending and Overlays styles are accomplished by another function
170 static VOID
171 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
173 HDC hImageDC;
174 HBITMAP hOldBitmap;
176 hImageDC = CreateCompatibleDC(0);
177 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
178 BitBlt(pimldp->hdcDst,
179 pimldp->x, pimldp->y, cx, cy,
180 hImageDC,
181 pimldp->himl->cx * pimldp->i, 0,
182 SRCCOPY);
184 SelectObject(hImageDC, hOldBitmap);
185 DeleteDC(hImageDC);
189 /*************************************************************************
190 * IMAGELIST_InternalDrawMask [Internal]
192 * Draws the image in the ImageList with the mask
194 * PARAMS
195 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
196 * cx [I] the width of the image to display
197 * cy............[I] the height of the image to display
199 * RETURNS
200 * nothing
202 * NOTES
203 * This function is used by ImageList_DrawIndirect, when it is
204 * required to draw the Image with the mask to the screen.
206 * Blending and Overlays styles are accomplished by another function.
208 static VOID
209 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
211 BOOL bUseCustomBackground, bBlendFlag;
212 HBRUSH hBrush, hOldBrush;
213 HDC hMaskDC, hImageDC;
214 HBITMAP hOldBitmapImage, hOldBitmapMask;
215 HIMAGELIST himlLocal = pimldp->himl;
216 COLORREF oldBkColor, oldFgColor;
217 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
220 * We need a dc and bitmap to draw on that is
221 * not on the screen.
223 HDC hOffScreenDC = 0;
224 HBITMAP hOffScreenBmp = 0;
226 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
227 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
229 hImageDC = CreateCompatibleDC(0);
230 hMaskDC = CreateCompatibleDC(0);
232 /* Create a compatible DC. */
233 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
235 if ( hOffScreenDC )
237 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
239 if ( hOffScreenBmp )
240 SelectObject( hOffScreenDC, hOffScreenBmp );
241 else
242 goto cleanup;
244 else
245 goto cleanup;
247 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
248 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
251 * Get a copy of the image for the masking operations.
252 * We will use the copy, and this dc for all the various
253 * blitting, and then do one final blit to the screen dc.
254 * This should clean up most of the flickering.
256 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
257 pimldp->y, SRCCOPY);
260 * Draw the Background for the appropriate Styles
262 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
263 || bBlendFlag) )
266 hBrush = CreateSolidBrush (himlLocal->clrBk);
267 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
269 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
271 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
275 * Draw Image Transparently over the current background
277 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
278 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
279 { /*
280 * To obtain a transparent look, background color should be set
281 * to white and foreground color to black when blting the
282 * monochrome mask.
285 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
286 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
288 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
289 0, SRCAND );
291 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
292 0, SRCPAINT );
297 * Draw the image when no Background is specified
299 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
301 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
302 himlLocal->cx * pimldp->i, 0, SRCCOPY);
305 * Draw the mask with or without a background
307 else if(fStyle & ILD_MASK)
309 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
310 0, bUseCustomBackground ? SRCCOPY : SRCAND);
314 * Blit the bitmap to the screen now.
316 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
317 hOffScreenDC, 0, 0, SRCCOPY);
320 SelectObject(hImageDC, hOldBitmapImage);
321 SelectObject(hMaskDC, hOldBitmapMask);
323 cleanup:
325 DeleteDC(hImageDC);
326 DeleteDC(hMaskDC);
328 DeleteDC( hOffScreenDC );
329 DeleteObject( hOffScreenBmp );
331 return;
334 /*************************************************************************
335 * IMAGELIST_InternalDrawBlend [Internal]
337 * Draws the Blend over the current image
339 * PARAMS
340 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
341 * cx [I] the width of the image to display
342 * cy............[I] the height of the image to display
344 * RETURNS
345 * nothing
347 * NOTES
348 * This functions is used by ImageList_DrawIndirect, when it is
349 * required to add the blend to the current image.
352 static VOID
353 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
356 HDC hBlendMaskDC,hMaskDC;
357 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
358 HBITMAP hBlendMaskBitmap, hOldBitmap;
359 COLORREF clrBlend, OldTextColor, OldBkColor;
360 HIMAGELIST himlLocal = pimldp->himl;
362 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
363 if (!(pimldp->rgbFg == CLR_DEFAULT))
365 clrBlend = pimldp->rgbFg;
367 /* Create the blend Mask
369 hBlendMaskDC = CreateCompatibleDC(0);
370 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
371 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
373 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
374 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
376 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
377 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
378 SelectObject(hBlendMaskDC, hOldBrush);
380 /* Modify the blend mask if an Image Mask exist
382 if(pimldp->himl->hbmMask != 0)
384 HBITMAP hOldMaskBitmap;
385 hMaskDC = CreateCompatibleDC(0);
386 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
388 BitBlt(hBlendMaskDC,
389 0,0, cx, cy,
390 hMaskDC,
391 himlLocal->cx * pimldp->i,0,
392 0x220326); /* NOTSRCAND */
394 BitBlt(hBlendMaskDC,
395 0,0, cx, cy,
396 hBlendMaskDC,
397 0,0,
398 NOTSRCCOPY);
400 SelectObject(hMaskDC, hOldMaskBitmap);
401 DeleteDC(hMaskDC);
404 /* Apply blend to the current image given the BlendMask
406 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
407 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
408 hBlendColorBrush = CreateSolidBrush(clrBlend);
409 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
411 BitBlt (pimldp->hdcDst,
412 pimldp->x, pimldp->y, cx, cy,
413 hBlendMaskDC,
414 0, 0,
415 0xB8074A); /* PSDPxax */
417 SelectObject(pimldp->hdcDst, hOldBrush);
418 SetTextColor(pimldp->hdcDst, OldTextColor);
419 SetBkColor(pimldp->hdcDst, OldBkColor);
420 SelectObject(hBlendMaskDC, hOldBitmap);
421 DeleteDC(hBlendMaskDC);
422 DeleteObject(hBlendMaskBitmap);
423 DeleteObject(hBlendColorBrush);
426 /*************************************************************************
427 * IMAGELIST_InternalDrawOverlay [Internal]
429 * Draws the overlay image
431 * PARAMS
432 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
433 * cx [I] the width of the image to display
434 * cy............[I] the height of the image to display
436 * RETURNS
437 * nothing
439 * NOTES
440 * This functions is used by ImageList_DrawIndirect, when it is
441 * required to draw the overlay
445 static VOID
446 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
448 INT nOvlIdx;
449 HDC hImageDC;
450 HBITMAP hOldBitmap;
452 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
453 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
455 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
456 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
458 hImageDC = CreateCompatibleDC(0);
459 if (pimldp->himl->hbmMask)
461 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
462 pimldp->himl->hbmMask);
464 BitBlt (pimldp->hdcDst,
465 pimldp->x, pimldp->y, cx, cy,
466 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
467 SRCAND);
469 SelectObject(hImageDC, hOldBitmap);
471 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
472 pimldp->himl->hbmImage);
474 BitBlt (pimldp->hdcDst,
475 pimldp->x, pimldp->y, cx, cy,
476 hImageDC,
477 pimldp->himl->cx * nOvlIdx, 0,
478 SRCPAINT);
480 SelectObject(hImageDC, hOldBitmap);
481 DeleteDC(hImageDC);
487 /*************************************************************************
488 * ImageList_Add [COMCTL32.40]
490 * Add an image or images to an image list.
492 * PARAMS
493 * himl [I] handle to image list
494 * hbmImage [I] handle to image bitmap
495 * hbmMask [I] handle to mask bitmap
497 * RETURNS
498 * Success: Index of the first new image.
499 * Failure: -1
502 INT WINAPI
503 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
505 HDC hdcImage, hdcBitmap;
506 INT nFirstIndex, nImageCount;
507 INT nStartX;
508 BITMAP bmp;
509 HBITMAP hOldBitmapImage, hOldBitmap;
511 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
512 if (!himl || !hbmImage)
513 return -1;
515 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
516 nImageCount = bmp.bmWidth / himl->cx;
518 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
520 nStartX = himl->cCurImage * himl->cx;
522 hdcImage = CreateCompatibleDC(0);
523 hdcBitmap = CreateCompatibleDC(0);
525 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
526 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
528 /* Copy result to the imagelist
530 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
531 hdcBitmap, 0, 0, SRCCOPY);
533 if(himl->hbmMask)
535 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
537 hdcMask = CreateCompatibleDC (0);
538 hdcTemp = CreateCompatibleDC(0);
539 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
540 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
542 BitBlt (hdcMask,
543 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
544 hdcTemp,
545 0, 0,
546 SRCCOPY);
548 SelectObject(hdcTemp, hOldBitmapTemp);
549 DeleteDC(hdcTemp);
551 /* Remove the background from the image
553 BitBlt (hdcImage,
554 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
555 hdcMask,
556 nStartX, 0,
557 0x220326); /* NOTSRCAND */
559 SelectObject(hdcMask, hOldBitmapMask);
560 DeleteDC(hdcMask);
563 SelectObject(hdcImage, hOldBitmapImage);
564 SelectObject(hdcBitmap, hOldBitmap);
565 DeleteDC(hdcImage);
566 DeleteDC(hdcBitmap);
568 nFirstIndex = himl->cCurImage;
569 himl->cCurImage += nImageCount;
571 return nFirstIndex;
575 /*************************************************************************
576 * ImageList_AddIcon [COMCTL32.41]
578 * Adds an icon to an image list.
580 * PARAMS
581 * himl [I] handle to image list
582 * hIcon [I] handle to icon
584 * RETURNS
585 * Success: index of the new image
586 * Failure: -1
589 INT WINAPI
590 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
592 return ImageList_ReplaceIcon (himl, -1, hIcon);
596 /*************************************************************************
597 * ImageList_AddMasked [COMCTL32.42]
599 * Adds an image or images to an image list and creates a mask from the
600 * specified bitmap using the mask color.
602 * PARAMS
603 * himl [I] handle to image list.
604 * hBitmap [I] handle to bitmap
605 * clrMask [I] mask color.
607 * RETURNS
608 * Success: Index of the first new image.
609 * Failure: -1
612 INT WINAPI
613 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
615 HDC hdcImage, hdcMask, hdcBitmap;
616 INT nIndex, nImageCount, nMaskXOffset=0;
617 BITMAP bmp;
618 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
619 HBITMAP hMaskBitmap=0;
620 COLORREF bkColor;
622 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
623 if (himl == NULL)
624 return -1;
626 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
627 return -1;
629 nImageCount = bmp.bmWidth / himl->cx;
631 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
633 nIndex = himl->cCurImage;
634 himl->cCurImage += nImageCount;
636 hdcMask = CreateCompatibleDC (0);
637 hdcImage = CreateCompatibleDC(0);
638 hdcBitmap = CreateCompatibleDC(0);
641 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
642 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
643 if(himl->hbmMask)
645 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
646 nMaskXOffset = nIndex * himl->cx;
648 else
651 Create a temp Mask so we can remove the background of
652 the Image (Windows does this even if there is no mask)
654 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
655 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
656 nMaskXOffset = 0;
658 /* create monochrome image to the mask bitmap */
659 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
660 GetPixel (hdcBitmap, 0, 0);
661 SetBkColor (hdcBitmap, bkColor);
662 BitBlt (hdcMask,
663 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
664 hdcBitmap, 0, 0,
665 SRCCOPY);
667 SetBkColor(hdcBitmap, RGB(255,255,255));
668 /*Remove the background from the image
671 WINDOWS BUG ALERT!!!!!!
672 The statement below should not be done in common practice
673 but this is how ImageList_AddMasked works in Windows.
674 It overwrites the original bitmap passed, this was discovered
675 by using the same bitmap to iterate the different styles
676 on windows where it failed (BUT ImageList_Add is OK)
677 This is here in case some apps rely on this bug
679 BitBlt(hdcBitmap,
680 0, 0, bmp.bmWidth, bmp.bmHeight,
681 hdcMask,
682 nMaskXOffset, 0,
683 0x220326); /* NOTSRCAND */
684 /* Copy result to the imagelist
686 BitBlt (hdcImage,
687 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
688 hdcBitmap,
689 0, 0,
690 SRCCOPY);
691 /* Clean up
693 SelectObject(hdcMask,hOldBitmapMask);
694 SelectObject(hdcImage, hOldBitmapImage);
695 SelectObject(hdcBitmap, hOldBitmap);
696 DeleteDC(hdcMask);
697 DeleteDC(hdcImage);
698 DeleteDC(hdcBitmap);
699 if(!himl->hbmMask)
701 DeleteObject(hMaskBitmap);
704 return nIndex;
708 /*************************************************************************
709 * ImageList_BeginDrag [COMCTL32.43]
711 * Creates a temporary image list that contains one image. It will be used
712 * as a drag image.
714 * PARAMS
715 * himlTrack [I] handle to the source image list
716 * iTrack [I] index of the drag image in the source image list
717 * dxHotspot [I] X position of the hot spot of the drag image
718 * dyHotspot [I] Y position of the hot spot of the drag image
720 * RETURNS
721 * Success: TRUE
722 * Failure: FALSE
725 BOOL WINAPI
726 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
727 INT dxHotspot, INT dyHotspot)
729 HDC hdcSrc, hdcDst;
730 INT cx, cy;
732 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
733 dxHotspot, dyHotspot);
735 if (himlTrack == NULL)
736 return FALSE;
738 if (InternalDrag.himl)
739 ImageList_EndDrag ();
741 cx = himlTrack->cx;
742 cy = himlTrack->cy;
744 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
745 if (InternalDrag.himl == NULL) {
746 ERR("Error creating drag image list!\n");
747 return FALSE;
750 InternalDrag.dxHotspot = dxHotspot;
751 InternalDrag.dyHotspot = dyHotspot;
753 hdcSrc = CreateCompatibleDC (0);
754 hdcDst = CreateCompatibleDC (0);
756 /* copy image */
757 SelectObject (hdcSrc, himlTrack->hbmImage);
758 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
759 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
761 /* copy mask */
762 SelectObject (hdcSrc, himlTrack->hbmMask);
763 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
764 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
766 DeleteDC (hdcSrc);
767 DeleteDC (hdcDst);
769 InternalDrag.himl->cCurImage = 1;
770 InternalDrag.bHSPending = TRUE;
772 return TRUE;
776 /*************************************************************************
777 * ImageList_Copy [COMCTL32.44]
779 * Copies an image of the source image list to an image of the
780 * destination image list. Images can be copied or swapped.
782 * PARAMS
783 * himlDst [I] handle to the destination image list
784 * iDst [I] destination image index.
785 * himlSrc [I] handle to the source image list
786 * iSrc [I] source image index
787 * uFlags [I] flags for the copy operation
789 * RETURNS
790 * Success: TRUE
791 * Failure: FALSE
793 * NOTES
794 * Copying from one image list to another is possible. The original
795 * implementation just copies or swaps within one image list.
796 * Could this feature become a bug??? ;-)
799 BOOL WINAPI
800 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
801 INT iSrc, INT uFlags)
803 HDC hdcSrc, hdcDst;
805 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
807 if ((himlSrc == NULL) || (himlDst == NULL))
808 return FALSE;
809 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
810 return FALSE;
811 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
812 return FALSE;
814 hdcSrc = CreateCompatibleDC (0);
815 if (himlDst == himlSrc)
816 hdcDst = hdcSrc;
817 else
818 hdcDst = CreateCompatibleDC (0);
820 if (uFlags & ILCF_SWAP) {
821 /* swap */
822 HBITMAP hbmTempImage, hbmTempMask;
824 /* create temporary bitmaps */
825 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
826 himlSrc->uBitsPixel, NULL);
827 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
828 1, NULL);
830 /* copy (and stretch) destination to temporary bitmaps.(save) */
831 /* image */
832 SelectObject (hdcSrc, himlDst->hbmImage);
833 SelectObject (hdcDst, hbmTempImage);
834 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
835 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
836 SRCCOPY);
837 /* mask */
838 SelectObject (hdcSrc, himlDst->hbmMask);
839 SelectObject (hdcDst, hbmTempMask);
840 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
841 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
842 SRCCOPY);
844 /* copy (and stretch) source to destination */
845 /* image */
846 SelectObject (hdcSrc, himlSrc->hbmImage);
847 SelectObject (hdcDst, himlDst->hbmImage);
848 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
849 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
850 SRCCOPY);
851 /* mask */
852 SelectObject (hdcSrc, himlSrc->hbmMask);
853 SelectObject (hdcDst, himlDst->hbmMask);
854 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
855 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
856 SRCCOPY);
858 /* copy (without stretching) temporary bitmaps to source (restore) */
859 /* image */
860 SelectObject (hdcSrc, hbmTempImage);
861 SelectObject (hdcDst, himlSrc->hbmImage);
862 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
863 hdcSrc, 0, 0, SRCCOPY);
864 /* mask */
865 SelectObject (hdcSrc, hbmTempMask);
866 SelectObject (hdcDst, himlSrc->hbmMask);
867 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
868 hdcSrc, 0, 0, SRCCOPY);
870 /* delete temporary bitmaps */
871 DeleteObject (hbmTempMask);
872 DeleteObject (hbmTempImage);
874 else {
875 /* copy image */
876 SelectObject (hdcSrc, himlSrc->hbmImage);
877 if (himlSrc == himlDst)
878 hdcDst = hdcSrc;
879 else
880 SelectObject (hdcDst, himlDst->hbmImage);
881 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
882 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
883 SRCCOPY);
885 /* copy mask */
886 SelectObject (hdcSrc, himlSrc->hbmMask);
887 if (himlSrc == himlDst)
888 hdcDst = hdcSrc;
889 else
890 SelectObject (hdcDst, himlDst->hbmMask);
891 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
892 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
893 SRCCOPY);
896 DeleteDC (hdcSrc);
897 if (himlSrc != himlDst)
898 DeleteDC (hdcDst);
900 return TRUE;
904 /*************************************************************************
905 * ImageList_Create [COMCTL32.45] Creates a new image list.
907 * PARAMS
908 * cx [I] image height
909 * cy [I] image width
910 * flags [I] creation flags
911 * cInitial [I] initial number of images in the image list
912 * cGrow [I] number of images by which image list grows
914 * RETURNS
915 * Success: Handle to the created image list
916 * Failure: NULL
919 HIMAGELIST WINAPI
920 ImageList_Create (INT cx, INT cy, UINT flags,
921 INT cInitial, INT cGrow)
923 HIMAGELIST himl;
924 HDC hdc;
925 INT nCount;
926 HBITMAP hbmTemp;
927 static WORD aBitBlend25[] =
928 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
930 static WORD aBitBlend50[] =
931 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
933 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
935 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
936 if (!himl)
937 return NULL;
939 himl->cx = cx;
940 himl->cy = cy;
941 himl->flags = flags;
942 himl->cMaxImage = cInitial + cGrow;
943 himl->cInitial = cInitial;
944 himl->cGrow = cGrow;
945 himl->cCurImage = 0;
946 himl->clrFg = CLR_DEFAULT;
947 himl->clrBk = CLR_NONE;
949 /* initialize overlay mask indices */
950 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
951 himl->nOvlIdx[nCount] = -1;
953 hdc = CreateCompatibleDC (0);
954 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
955 DeleteDC (hdc);
957 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
959 if (himl->cMaxImage > 0) {
960 himl->hbmImage =
961 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
962 1, himl->uBitsPixel, NULL);
963 if (himl->hbmImage == 0) {
964 ERR("Error creating image bitmap!\n");
965 return NULL;
968 else
969 himl->hbmImage = 0;
971 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
972 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
973 1, 1, NULL);
974 if (himl->hbmMask == 0) {
975 ERR("Error creating mask bitmap!\n");
976 if (himl->hbmImage)
977 DeleteObject (himl->hbmImage);
978 return NULL;
981 else
982 himl->hbmMask = 0;
984 /* create blending brushes */
985 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
986 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
987 DeleteObject (hbmTemp);
989 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
990 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
991 DeleteObject (hbmTemp);
993 TRACE("created imagelist %p\n", himl);
994 return himl;
998 /*************************************************************************
999 * ImageList_Destroy [COMCTL32.46]
1001 * Destroys an image list.
1003 * PARAMS
1004 * himl [I] handle to image list
1006 * RETURNS
1007 * Success: TRUE
1008 * Failure: FALSE
1011 BOOL WINAPI
1012 ImageList_Destroy (HIMAGELIST himl)
1014 if (!himl)
1015 return FALSE;
1017 /* delete image bitmaps */
1018 if (himl->hbmImage)
1019 DeleteObject (himl->hbmImage);
1020 if (himl->hbmMask)
1021 DeleteObject (himl->hbmMask);
1023 /* delete blending brushes */
1024 if (himl->hbrBlend25)
1025 DeleteObject (himl->hbrBlend25);
1026 if (himl->hbrBlend50)
1027 DeleteObject (himl->hbrBlend50);
1029 COMCTL32_Free (himl);
1031 return TRUE;
1035 /*************************************************************************
1036 * ImageList_DragEnter [COMCTL32.47]
1038 * Locks window update and displays the drag image at the given position.
1040 * PARAMS
1041 * hwndLock [I] handle of the window that owns the drag image.
1042 * x [I] X position of the drag image.
1043 * y [I] Y position of the drag image.
1045 * RETURNS
1046 * Success: TRUE
1047 * Failure: FALSE
1049 * NOTES
1050 * The position of the drag image is relative to the window, not
1051 * the client area.
1054 BOOL WINAPI
1055 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1057 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1059 if (InternalDrag.himl == NULL)
1060 return FALSE;
1062 if (hwndLock)
1063 InternalDrag.hwnd = hwndLock;
1064 else
1065 InternalDrag.hwnd = GetDesktopWindow ();
1067 InternalDrag.x = x;
1068 InternalDrag.y = y;
1070 /* draw the drag image and save the background */
1071 if (!ImageList_DragShowNolock(TRUE)) {
1072 return FALSE;
1075 return TRUE;
1079 /*************************************************************************
1080 * ImageList_DragLeave [COMCTL32.48]
1082 * Unlocks window update and hides the drag image.
1084 * PARAMS
1085 * hwndLock [I] handle of the window that owns the drag image.
1087 * RETURNS
1088 * Success: TRUE
1089 * Failure: FALSE
1092 BOOL WINAPI
1093 ImageList_DragLeave (HWND hwndLock)
1095 /* As we don't save drag info in the window this can lead to problems if
1096 an app does not supply the same window as DragEnter */
1097 /* if (hwndLock)
1098 InternalDrag.hwnd = hwndLock;
1099 else
1100 InternalDrag.hwnd = GetDesktopWindow (); */
1101 if(!hwndLock)
1102 hwndLock = GetDesktopWindow();
1103 if(InternalDrag.hwnd != hwndLock)
1104 FIXME("DragLeave hWnd != DragEnter hWnd\n");
1106 ImageList_DragShowNolock (FALSE);
1108 return TRUE;
1112 /*************************************************************************
1113 * ImageList_DragMove [COMCTL32.49]
1115 * Moves the drag image.
1117 * PARAMS
1118 * x [I] X position of the drag image.
1119 * y [I] Y position of the drag image.
1121 * RETURNS
1122 * Success: TRUE
1123 * Failure: FALSE
1125 * NOTES
1126 * The position of the drag image is relative to the window, not
1127 * the client area.
1129 * BUGS
1130 * The drag image should be drawn semitransparent.
1133 BOOL WINAPI
1134 ImageList_DragMove (INT x, INT y)
1136 TRACE("(x=%d y=%d)\n", x, y);
1138 if (!InternalDrag.himl) {
1139 return FALSE;
1142 /* draw/update the drag image */
1143 if (InternalDrag.bShow) {
1144 HDC hdcDrag;
1145 HDC hdcOffScreen;
1146 HDC hdcBg;
1147 HBITMAP hbmOffScreen;
1148 INT origNewX, origNewY;
1149 INT origOldX, origOldY;
1150 INT origRegX, origRegY;
1151 INT sizeRegX, sizeRegY;
1154 /* calculate the update region */
1155 origNewX = x - InternalDrag.dxHotspot;
1156 origNewY = y - InternalDrag.dyHotspot;
1157 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1158 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1159 origRegX = min(origNewX, origOldX);
1160 origRegY = min(origNewY, origOldY);
1161 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1162 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1164 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1165 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1166 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1167 hdcBg = CreateCompatibleDC(hdcDrag);
1169 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1170 SelectObject(hdcOffScreen, hbmOffScreen);
1171 SelectObject(hdcBg, InternalDrag.hbmBg);
1173 /* get the actual background of the update region */
1174 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1175 origRegX, origRegY, SRCCOPY);
1176 /* erase the old image */
1177 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1178 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1179 SRCCOPY);
1180 /* save the background */
1181 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1182 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1183 /* draw the image */
1184 /* FIXME: image should be drawn semitransparent */
1185 ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1186 origNewY - origRegY, ILD_NORMAL);
1187 /* draw the update region to the screen */
1188 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1189 hdcOffScreen, 0, 0, SRCCOPY);
1191 DeleteDC(hdcBg);
1192 DeleteDC(hdcOffScreen);
1193 DeleteObject(hbmOffScreen);
1194 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1197 /* update the image position */
1198 InternalDrag.x = x;
1199 InternalDrag.y = y;
1201 return TRUE;
1205 /*************************************************************************
1206 * ImageList_DragShowNolock [COMCTL32.50]
1208 * Shows or hides the drag image.
1210 * PARAMS
1211 * bShow [I] TRUE shows the drag image, FALSE hides it.
1213 * RETURNS
1214 * Success: TRUE
1215 * Failure: FALSE
1217 * BUGS
1218 * The drag image should be drawn semitransparent.
1221 BOOL WINAPI
1222 ImageList_DragShowNolock (BOOL bShow)
1224 HDC hdcDrag;
1225 HDC hdcBg;
1226 INT x, y;
1228 TRACE("bShow=0x%X!\n", bShow);
1230 /* DragImage is already visible/hidden */
1231 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1232 return FALSE;
1235 /* position of the origin of the DragImage */
1236 x = InternalDrag.x - InternalDrag.dxHotspot;
1237 y = InternalDrag.y - InternalDrag.dyHotspot;
1239 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1240 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1241 if (!hdcDrag) {
1242 return FALSE;
1245 hdcBg = CreateCompatibleDC(hdcDrag);
1246 if (!InternalDrag.hbmBg) {
1247 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1248 InternalDrag.himl->cx, InternalDrag.himl->cy);
1250 SelectObject(hdcBg, InternalDrag.hbmBg);
1252 if (bShow) {
1253 /* save the background */
1254 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1255 hdcDrag, x, y, SRCCOPY);
1256 /* show the image */
1257 /* FIXME: this should be drawn semitransparent */
1258 ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1259 } else {
1260 /* hide the image */
1261 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1262 hdcBg, 0, 0, SRCCOPY);
1265 InternalDrag.bShow = !InternalDrag.bShow;
1267 DeleteDC(hdcBg);
1268 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1269 return TRUE;
1273 /*************************************************************************
1274 * ImageList_Draw [COMCTL32.51] Draws an image.
1276 * PARAMS
1277 * himl [I] handle to image list
1278 * i [I] image index
1279 * hdc [I] handle to device context
1280 * x [I] x position
1281 * y [I] y position
1282 * fStyle [I] drawing flags
1284 * RETURNS
1285 * Success: TRUE
1286 * Failure: FALSE
1288 * NOTES
1289 * Calls ImageList_DrawIndirect.
1291 * SEE
1292 * ImageList_DrawIndirect.
1295 BOOL WINAPI
1296 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1297 INT x, INT y, UINT fStyle)
1299 IMAGELISTDRAWPARAMS imldp;
1301 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1302 imldp.himl = himl;
1303 imldp.i = i;
1304 imldp.hdcDst = hdc,
1305 imldp.x = x;
1306 imldp.y = y;
1307 imldp.cx = 0;
1308 imldp.cy = 0;
1309 imldp.xBitmap = 0;
1310 imldp.yBitmap = 0;
1311 imldp.rgbBk = CLR_DEFAULT;
1312 imldp.rgbFg = CLR_DEFAULT;
1313 imldp.fStyle = fStyle;
1314 imldp.dwRop = 0;
1316 return ImageList_DrawIndirect (&imldp);
1320 /*************************************************************************
1321 * ImageList_DrawEx [COMCTL32.52]
1323 * Draws an image and allows to use extended drawing features.
1325 * PARAMS
1326 * himl [I] handle to image list
1327 * i [I] image index
1328 * hdc [I] handle to device context
1329 * x [I] X position
1330 * y [I] Y position
1331 * xOffs [I] X offset
1332 * yOffs [I] Y offset
1333 * rgbBk [I] background color
1334 * rgbFg [I] foreground color
1335 * fStyle [I] drawing flags
1337 * RETURNS
1338 * Success: TRUE
1339 * Failure: FALSE
1341 * NOTES
1342 * Calls ImageList_DrawIndirect.
1344 * SEE
1345 * ImageList_DrawIndirect.
1348 BOOL WINAPI
1349 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1350 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1351 UINT fStyle)
1353 IMAGELISTDRAWPARAMS imldp;
1355 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1356 imldp.himl = himl;
1357 imldp.i = i;
1358 imldp.hdcDst = hdc,
1359 imldp.x = x;
1360 imldp.y = y;
1361 imldp.cx = dx;
1362 imldp.cy = dy;
1363 imldp.xBitmap = 0;
1364 imldp.yBitmap = 0;
1365 imldp.rgbBk = rgbBk;
1366 imldp.rgbFg = rgbFg;
1367 imldp.fStyle = fStyle;
1368 imldp.dwRop = 0;
1370 return ImageList_DrawIndirect (&imldp);
1374 /*************************************************************************
1375 * ImageList_DrawIndirect [COMCTL32.53]
1377 * Draws an image using ...
1379 * PARAMS
1380 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1382 * RETURNS
1383 * Success: TRUE
1384 * Failure: FALSE
1387 BOOL WINAPI
1388 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1390 INT cx, cy;
1392 Do some Error Checking
1394 if (pimldp == NULL)
1395 return FALSE;
1396 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1397 return FALSE;
1398 if (pimldp->himl == NULL)
1399 return FALSE;
1400 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1401 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1402 return FALSE;
1405 Get the Height and Width to display
1407 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1408 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1410 Draw the image
1412 if(pimldp->himl->hbmMask != 0)
1414 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1416 else
1418 IMAGELIST_InternalDraw(pimldp, cx, cy);
1421 Apply the blend if needed to the Image
1423 if((pimldp->fStyle & ILD_BLEND50)
1424 || (pimldp->fStyle & ILD_BLEND25))
1426 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1429 Apply the Overlay if needed
1431 if (pimldp->fStyle & ILD_OVERLAYMASK)
1433 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1436 return TRUE;
1440 /*************************************************************************
1441 * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
1443 * PARAMS
1444 * himlSrc [I] source image list handle
1446 * RETURNS
1447 * Success: Handle of duplicated image list.
1448 * Failure: NULL
1451 HIMAGELIST WINAPI
1452 ImageList_Duplicate (HIMAGELIST himlSrc)
1454 HIMAGELIST himlDst;
1455 HDC hdcSrc, hdcDst;
1457 if (himlSrc == NULL) {
1458 ERR("Invalid image list handle!\n");
1459 return NULL;
1462 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1463 himlSrc->cInitial, himlSrc->cGrow);
1465 if (himlDst)
1467 hdcSrc = CreateCompatibleDC (0);
1468 hdcDst = CreateCompatibleDC (0);
1469 SelectObject (hdcSrc, himlSrc->hbmImage);
1470 SelectObject (hdcDst, himlDst->hbmImage);
1471 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1472 hdcSrc, 0, 0, SRCCOPY);
1474 if (himlDst->hbmMask)
1476 SelectObject (hdcSrc, himlSrc->hbmMask);
1477 SelectObject (hdcDst, himlDst->hbmMask);
1478 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1479 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1482 DeleteDC (hdcDst);
1483 DeleteDC (hdcSrc);
1485 himlDst->cCurImage = himlSrc->cCurImage;
1486 himlDst->cMaxImage = himlSrc->cMaxImage;
1488 return himlDst;
1492 /*************************************************************************
1493 * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
1495 * Finishes a drag operation.
1497 * PARAMS
1498 * no Parameters
1500 * RETURNS
1501 * Success: TRUE
1502 * Failure: FALSE
1505 BOOL WINAPI
1506 ImageList_EndDrag (void)
1508 /* cleanup the InternalDrag struct */
1509 InternalDrag.hwnd = 0;
1510 ImageList_Destroy (InternalDrag.himl);
1511 InternalDrag.himl = 0;
1512 InternalDrag.x= 0;
1513 InternalDrag.y= 0;
1514 InternalDrag.dxHotspot = 0;
1515 InternalDrag.dyHotspot = 0;
1516 InternalDrag.bShow = FALSE;
1517 DeleteObject(InternalDrag.hbmBg);
1518 InternalDrag.hbmBg = 0;
1519 InternalDrag.bHSPending = FALSE;
1521 return TRUE;
1525 /*************************************************************************
1526 * ImageList_GetBkColor [COMCTL32.56]
1528 * Returns the background color of an image list.
1530 * PARAMS
1531 * himl [I] Image list handle.
1533 * RETURNS
1534 * Success: background color
1535 * Failure: CLR_NONE
1538 COLORREF WINAPI
1539 ImageList_GetBkColor (HIMAGELIST himl)
1541 if (himl == NULL)
1542 return CLR_NONE;
1544 return himl->clrBk;
1548 /*************************************************************************
1549 * ImageList_GetDragImage [COMCTL32.57]
1551 * Returns the handle to the internal drag image list.
1553 * PARAMS
1554 * ppt [O] Pointer to the drag position. Can be NULL.
1555 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1557 * RETURNS
1558 * Success: Handle of the drag image list.
1559 * Failure: NULL.
1562 HIMAGELIST WINAPI
1563 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1565 if (InternalDrag.himl) {
1566 if (ppt) {
1567 ppt->x = InternalDrag.x;
1568 ppt->y = InternalDrag.y;
1570 if (pptHotspot) {
1571 pptHotspot->x = InternalDrag.dxHotspot;
1572 pptHotspot->y = InternalDrag.dyHotspot;
1574 return (InternalDrag.himl);
1577 return NULL;
1581 /*************************************************************************
1582 * ImageList_GetFlags [COMCTL32.58]
1584 * BUGS
1585 * Stub.
1588 DWORD WINAPI
1589 ImageList_GetFlags(HIMAGELIST himl)
1591 FIXME("(%p):empty stub\n", himl);
1592 return 0;
1596 /*************************************************************************
1597 * ImageList_GetIcon [COMCTL32.59]
1599 * Creates an icon from a masked image of an image list.
1601 * PARAMS
1602 * himl [I] handle to image list
1603 * i [I] image index
1604 * flags [I] drawing style flags
1606 * RETURNS
1607 * Success: icon handle
1608 * Failure: NULL
1611 HICON WINAPI
1612 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1614 ICONINFO ii;
1615 HICON hIcon;
1616 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1617 HDC hdcSrc, hdcDst;
1619 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1620 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1621 return 0;
1624 hdcSrc = CreateCompatibleDC(0);
1625 hdcDst = CreateCompatibleDC(0);
1627 ii.fIcon = TRUE;
1628 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1630 /* draw mask*/
1631 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1632 if (himl->hbmMask) {
1633 SelectObject (hdcSrc, himl->hbmMask);
1634 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1635 hdcSrc, i * himl->cx, 0, SRCCOPY);
1637 else
1638 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1640 /* draw image*/
1641 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1642 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1643 SelectObject (hdcDst, ii.hbmColor);
1644 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1645 hdcSrc, i * himl->cx, 0, SRCCOPY);
1648 * CreateIconIndirect requires us to deselect the bitmaps from
1649 * the DCs before calling
1651 SelectObject(hdcSrc, hOldSrcBitmap);
1652 SelectObject(hdcDst, hOldDstBitmap);
1654 hIcon = CreateIconIndirect (&ii);
1656 DeleteDC (hdcSrc);
1657 DeleteDC (hdcDst);
1658 DeleteObject (ii.hbmMask);
1659 DeleteObject (ii.hbmColor);
1661 return hIcon;
1665 /*************************************************************************
1666 * ImageList_GetIconSize [COMCTL32.60]
1668 * Retrieves the size of an image in an image list.
1670 * PARAMS
1671 * himl [I] handle to image list
1672 * cx [O] pointer to the image width.
1673 * cy [O] pointer to the image height.
1675 * RETURNS
1676 * Success: TRUE
1677 * Failure: FALSE
1679 * NOTES
1680 * All images in an image list have the same size.
1683 BOOL WINAPI
1684 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1686 if (himl == NULL)
1687 return FALSE;
1688 if ((himl->cx <= 0) || (himl->cy <= 0))
1689 return FALSE;
1691 if (cx)
1692 *cx = himl->cx;
1693 if (cy)
1694 *cy = himl->cy;
1696 return TRUE;
1700 /*************************************************************************
1701 * ImageList_GetImageCount [COMCTL32.61]
1703 * Returns the number of images in an image list.
1705 * PARAMS
1706 * himl [I] handle to image list
1708 * RETURNS
1709 * Success: Number of images.
1710 * Failure: 0
1713 INT WINAPI
1714 ImageList_GetImageCount (HIMAGELIST himl)
1716 if (himl == NULL)
1717 return 0;
1719 return himl->cCurImage;
1723 /*************************************************************************
1724 * ImageList_GetImageInfo [COMCTL32.62]
1726 * Returns information about an image in an image list.
1728 * PARAMS
1729 * himl [I] handle to image list
1730 * i [I] image index
1731 * pImageInfo [O] pointer to the image information
1733 * RETURNS
1734 * Success: TRUE
1735 * Failure: FALSE
1738 BOOL WINAPI
1739 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1741 if ((himl == NULL) || (pImageInfo == NULL))
1742 return FALSE;
1743 if ((i < 0) || (i >= himl->cCurImage))
1744 return FALSE;
1746 pImageInfo->hbmImage = himl->hbmImage;
1747 pImageInfo->hbmMask = himl->hbmMask;
1749 pImageInfo->rcImage.top = 0;
1750 pImageInfo->rcImage.bottom = himl->cy;
1751 pImageInfo->rcImage.left = i * himl->cx;
1752 pImageInfo->rcImage.right = (i+1) * himl->cx;
1754 return TRUE;
1758 /*************************************************************************
1759 * ImageList_GetImageRect [COMCTL32.63]
1761 * Retrieves the rectangle of the specified image in an image list.
1763 * PARAMS
1764 * himl [I] handle to image list
1765 * i [I] image index
1766 * lpRect [O] pointer to the image rectangle
1768 * RETURNS
1769 * Success: TRUE
1770 * Failure: FALSE
1772 * NOTES
1773 * This is an UNDOCUMENTED function!!!
1776 BOOL WINAPI
1777 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1779 if ((himl == NULL) || (lpRect == NULL))
1780 return FALSE;
1781 if ((i < 0) || (i >= himl->cCurImage))
1782 return FALSE;
1784 lpRect->left = i * himl->cx;
1785 lpRect->top = 0;
1786 lpRect->right = lpRect->left + himl->cx;
1787 lpRect->bottom = himl->cy;
1789 return TRUE;
1793 /*************************************************************************
1794 * ImageList_LoadImage [COMCTL32.64]
1795 * ImageList_LoadImageA [COMCTL32.65]
1797 * Creates an image list from a bitmap, icon or cursor.
1799 * PARAMS
1800 * hi [I] instance handle
1801 * lpbmp [I] name or id of the image
1802 * cx [I] width of each image
1803 * cGrow [I] number of images to expand
1804 * clrMask [I] mask color
1805 * uType [I] type of image to load
1806 * uFlags [I] loading flags
1808 * RETURNS
1809 * Success: handle to the loaded image list
1810 * Failure: NULL
1812 * SEE
1813 * LoadImage ()
1816 HIMAGELIST WINAPI
1817 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1818 COLORREF clrMask, UINT uType, UINT uFlags)
1820 HIMAGELIST himl = NULL;
1821 HANDLE handle;
1822 INT nImageCount;
1824 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1825 if (!handle) {
1826 ERR("Error loading image!\n");
1827 return NULL;
1830 if (uType == IMAGE_BITMAP) {
1831 BITMAP bmp;
1832 GetObjectA (handle, sizeof(BITMAP), &bmp);
1834 /* To match windows behavior, if cx is set to zero and
1835 the flag DI_DEFAULTSIZE is specified, cx becomes the
1836 system metric value for icons. If the flag is not specified
1837 the function sets the size to the height of the bitmap */
1838 if (cx == 0)
1840 if (uFlags & DI_DEFAULTSIZE)
1841 cx = GetSystemMetrics (SM_CXICON);
1842 else
1843 cx = bmp.bmHeight;
1846 nImageCount = bmp.bmWidth / cx;
1848 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1849 nImageCount, cGrow);
1850 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1852 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1853 ICONINFO ii;
1854 BITMAP bmp;
1856 GetIconInfo (handle, &ii);
1857 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1858 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1859 ILC_MASK | ILC_COLOR, 1, cGrow);
1860 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1861 DeleteObject (ii.hbmColor);
1862 DeleteObject (ii.hbmMask);
1865 DeleteObject (handle);
1867 return himl;
1871 /*************************************************************************
1872 * ImageList_LoadImageW [COMCTL32.66]
1874 * Creates an image list from a bitmap, icon or cursor.
1876 * PARAMS
1877 * hi [I] instance handle
1878 * lpbmp [I] name or id of the image
1879 * cx [I] width of each image
1880 * cGrow [I] number of images to expand
1881 * clrMask [I] mask color
1882 * uType [I] type of image to load
1883 * uFlags [I] loading flags
1885 * RETURNS
1886 * Success: handle to the loaded image list
1887 * Failure: NULL
1889 * SEE
1890 * LoadImage ()
1893 HIMAGELIST WINAPI
1894 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1895 COLORREF clrMask, UINT uType, UINT uFlags)
1897 HIMAGELIST himl = NULL;
1898 HANDLE handle;
1899 INT nImageCount;
1901 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1902 if (!handle) {
1903 ERR("Error loading image!\n");
1904 return NULL;
1907 if (uType == IMAGE_BITMAP) {
1908 BITMAP bmp;
1909 GetObjectA (handle, sizeof(BITMAP), &bmp);
1911 /* To match windows behavior, if cx is set to zero and
1912 the flag DI_DEFAULTSIZE is specified, cx becomes the
1913 system metric value for icons. If the flag is not specified
1914 the function sets the size to the height of the bitmap */
1915 if (cx == 0)
1917 if (uFlags & DI_DEFAULTSIZE)
1918 cx = GetSystemMetrics (SM_CXICON);
1919 else
1920 cx = bmp.bmHeight;
1923 nImageCount = bmp.bmWidth / cx;
1925 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1926 nImageCount, cGrow);
1927 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1929 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1930 ICONINFO ii;
1931 BITMAP bmp;
1933 GetIconInfo (handle, &ii);
1934 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1935 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1936 ILC_MASK | ILC_COLOR, 1, cGrow);
1937 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1938 DeleteObject (ii.hbmColor);
1939 DeleteObject (ii.hbmMask);
1942 DeleteObject (handle);
1944 return himl;
1948 /*************************************************************************
1949 * ImageList_Merge [COMCTL32.67]
1951 * Creates a new image list that contains a merged image from the specified
1952 * images of both source image lists.
1954 * PARAMS
1955 * himl1 [I] handle to first image list
1956 * i1 [I] first image index
1957 * himl2 [I] handle to second image list
1958 * i2 [I] second image index
1959 * dx [I] X offset of the second image relative to the first.
1960 * dy [I] Y offset of the second image relative to the first.
1962 * RETURNS
1963 * Success: handle of the merged image list.
1964 * Failure: NULL
1967 HIMAGELIST WINAPI
1968 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1969 INT dx, INT dy)
1971 HIMAGELIST himlDst = NULL;
1972 HDC hdcSrcImage, hdcDstImage;
1973 INT cxDst, cyDst;
1974 INT xOff1, yOff1, xOff2, yOff2;
1975 INT nX1, nX2;
1977 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1978 i2, dx, dy);
1980 if ((himl1 == NULL) || (himl2 == NULL))
1981 return NULL;
1983 /* check indices */
1984 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1985 ERR("Index 1 out of range! %d\n", i1);
1986 return NULL;
1989 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1990 ERR("Index 2 out of range! %d\n", i2);
1991 return NULL;
1994 if (dx > 0) {
1995 cxDst = max (himl1->cx, dx + himl2->cx);
1996 xOff1 = 0;
1997 xOff2 = dx;
1999 else if (dx < 0) {
2000 cxDst = max (himl2->cx, himl1->cx - dx);
2001 xOff1 = -dx;
2002 xOff2 = 0;
2004 else {
2005 cxDst = max (himl1->cx, himl2->cx);
2006 xOff1 = 0;
2007 xOff2 = 0;
2010 if (dy > 0) {
2011 cyDst = max (himl1->cy, dy + himl2->cy);
2012 yOff1 = 0;
2013 yOff2 = dy;
2015 else if (dy < 0) {
2016 cyDst = max (himl2->cy, himl1->cy - dy);
2017 yOff1 = -dy;
2018 yOff2 = 0;
2020 else {
2021 cyDst = max (himl1->cy, himl2->cy);
2022 yOff1 = 0;
2023 yOff2 = 0;
2026 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2028 if (himlDst) {
2029 hdcSrcImage = CreateCompatibleDC (0);
2030 hdcDstImage = CreateCompatibleDC (0);
2031 nX1 = i1 * himl1->cx;
2032 nX2 = i2 * himl2->cx;
2034 /* copy image */
2035 SelectObject (hdcSrcImage, himl1->hbmImage);
2036 SelectObject (hdcDstImage, himlDst->hbmImage);
2037 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2038 hdcSrcImage, 0, 0, BLACKNESS);
2039 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2040 hdcSrcImage, nX1, 0, SRCCOPY);
2042 SelectObject (hdcSrcImage, himl2->hbmMask);
2043 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2044 hdcSrcImage, nX2, 0, SRCAND);
2046 SelectObject (hdcSrcImage, himl2->hbmImage);
2047 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2048 hdcSrcImage, nX2, 0, SRCPAINT);
2050 /* copy mask */
2051 SelectObject (hdcSrcImage, himl1->hbmMask);
2052 SelectObject (hdcDstImage, himlDst->hbmMask);
2053 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2054 hdcSrcImage, 0, 0, WHITENESS);
2055 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2056 hdcSrcImage, nX1, 0, SRCCOPY);
2058 SelectObject (hdcSrcImage, himl2->hbmMask);
2059 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2060 hdcSrcImage, nX2, 0, SRCAND);
2062 DeleteDC (hdcSrcImage);
2063 DeleteDC (hdcDstImage);
2064 himlDst->cCurImage = 1;
2067 return himlDst;
2071 /* helper for _read_bitmap currently unused */
2072 #if 0
2073 static int may_use_dibsection(HDC hdc) {
2074 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2075 if (bitspixel>8)
2076 return TRUE;
2077 if (bitspixel<=4)
2078 return FALSE;
2079 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2081 #endif
2083 /* helper for ImageList_Read, see comments below */
2084 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2085 HDC xdc = 0;
2086 BITMAPFILEHEADER bmfh;
2087 BITMAPINFOHEADER bmih;
2088 int bitsperpixel,palspace,longsperline,width,height;
2089 LPBITMAPINFOHEADER bmihc = NULL;
2090 int result = 0;
2091 HBITMAP hbitmap = 0;
2092 LPBYTE bits = NULL,nbits = NULL;
2093 int nbytesperline,bytesperline;
2095 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
2096 (bmfh.bfType != (('M'<<8)|'B')) ||
2097 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
2098 (bmih.biSize != sizeof(bmih))
2100 return 0;
2102 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2103 if (bitsperpixel<=8)
2104 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2105 else
2106 palspace = 0;
2107 width = bmih.biWidth;
2108 height = bmih.biHeight;
2109 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2110 memcpy(bmihc,&bmih,sizeof(bmih));
2111 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
2112 bmihc->biSizeImage = (longsperline*height)<<2;
2114 /* read the palette right after the end of the bitmapinfoheader */
2115 if (palspace)
2116 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2117 goto ret1;
2119 xdc = GetDC(0);
2120 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2121 if ((bitsperpixel>1) &&
2122 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2124 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2125 if (!hbitmap)
2126 goto ret1;
2127 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2128 goto ret1;
2129 result = 1;
2130 } else
2131 #endif
2133 int i,nwidth,nheight;
2135 nwidth = width*(height/cy);
2136 nheight = cy;
2138 if (bitsperpixel==1)
2139 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2140 else
2141 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2143 /* Might be a bit excessive memory use here */
2144 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2145 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2146 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2147 goto ret1;
2149 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2150 /* Do not forget that windows bitmaps are bottom->top */
2151 bytesperline = longsperline*4;
2152 nbytesperline = (height/cy)*bytesperline;
2153 for (i=0;i<height;i++) {
2154 memcpy(
2155 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2156 bits+bytesperline*(height-1-i),
2157 bytesperline
2160 bmihc->biWidth = nwidth;
2161 bmihc->biHeight = nheight;
2162 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2163 goto ret1;
2164 LocalFree((HLOCAL)nbits);
2165 LocalFree((HLOCAL)bits);
2166 result = 1;
2168 ret1:
2169 if (xdc) ReleaseDC(0,xdc);
2170 if (bmihc) LocalFree((HLOCAL)bmihc);
2171 if (!result) {
2172 if (hbitmap) {
2173 DeleteObject(hbitmap);
2174 hbitmap = 0;
2177 return hbitmap;
2180 /*************************************************************************
2181 * ImageList_Read [COMCTL32.68]
2183 * Reads an image list from a stream.
2185 * PARAMS
2186 * pstm [I] pointer to a stream
2188 * RETURNS
2189 * Success: handle to image list
2190 * Failure: NULL
2192 * The format is like this:
2193 * ILHEAD ilheadstruct;
2195 * for the color image part:
2196 * BITMAPFILEHEADER bmfh;
2197 * BITMAPINFOHEADER bmih;
2198 * only if it has a palette:
2199 * RGBQUAD rgbs[nr_of_paletted_colors];
2201 * BYTE colorbits[imagesize];
2203 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2204 * BITMAPFILEHEADER bmfh_mask;
2205 * BITMAPINFOHEADER bmih_mask;
2206 * only if it has a palette (it usually does not):
2207 * RGBQUAD rgbs[nr_of_paletted_colors];
2209 * BYTE maskbits[imagesize];
2211 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2212 * _read_bitmap needs to convert them.
2214 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2216 ILHEAD ilHead;
2217 HIMAGELIST himl;
2218 HBITMAP hbmColor=0,hbmMask=0;
2219 int i;
2221 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2222 return NULL;
2223 if (ilHead.usMagic != (('L' << 8) | 'I'))
2224 return NULL;
2225 if (ilHead.usVersion != 0x101) /* probably version? */
2226 return NULL;
2228 #if 0
2229 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2230 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2231 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2232 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2233 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2234 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2235 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2236 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2237 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2238 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2239 #endif
2241 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2242 if (!hbmColor)
2243 return NULL;
2244 if (ilHead.flags & ILC_MASK) {
2245 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2246 if (!hbmMask) {
2247 DeleteObject(hbmColor);
2248 return NULL;
2252 himl = ImageList_Create (
2253 ilHead.cx,
2254 ilHead.cy,
2255 ilHead.flags,
2256 1, /* initial */
2257 ilHead.cGrow
2259 if (!himl) {
2260 DeleteObject(hbmColor);
2261 DeleteObject(hbmMask);
2262 return NULL;
2264 himl->hbmImage = hbmColor;
2265 himl->hbmMask = hbmMask;
2266 himl->cCurImage = ilHead.cCurImage;
2267 himl->cMaxImage = ilHead.cMaxImage;
2269 ImageList_SetBkColor(himl,ilHead.bkcolor);
2270 for (i=0;i<4;i++)
2271 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2272 return himl;
2276 /*************************************************************************
2277 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2279 * PARAMS
2280 * himl [I] image list handle
2281 * i [I] image index
2283 * RETURNS
2284 * Success: TRUE
2285 * Failure: FALSE
2288 BOOL WINAPI
2289 ImageList_Remove (HIMAGELIST himl, INT i)
2291 HBITMAP hbmNewImage, hbmNewMask;
2292 HDC hdcSrc, hdcDst;
2293 INT cxNew, nCount;
2295 if (himl == NULL) {
2296 ERR("Invalid image list handle!\n");
2297 return FALSE;
2300 if ((i < -1) || (i >= himl->cCurImage)) {
2301 ERR("index out of range! %d\n", i);
2302 return FALSE;
2305 if (himl->cCurImage == 0) {
2306 ERR("image list is already empty!\n");
2307 return FALSE;
2310 if (i == -1) {
2311 /* remove all */
2312 TRACE("remove all!\n");
2314 himl->cMaxImage = himl->cInitial + himl->cGrow;
2315 himl->cCurImage = 0;
2316 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2317 himl->nOvlIdx[nCount] = -1;
2319 DeleteObject (himl->hbmImage);
2320 himl->hbmImage =
2321 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2322 1, himl->uBitsPixel, NULL);
2324 if (himl->hbmMask) {
2325 DeleteObject (himl->hbmMask);
2326 himl->hbmMask =
2327 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2328 1, 1, NULL);
2331 else {
2332 /* delete one image */
2333 TRACE("Remove single image! %d\n", i);
2335 /* create new bitmap(s) */
2336 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2338 TRACE(" - Number of images: %d / %d (Old/New)\n",
2339 himl->cCurImage, himl->cCurImage - 1);
2340 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2341 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2343 hbmNewImage =
2344 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2346 if (himl->hbmMask)
2347 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2348 else
2349 hbmNewMask = 0; /* Just to keep compiler happy! */
2351 hdcSrc = CreateCompatibleDC (0);
2352 hdcDst = CreateCompatibleDC (0);
2354 /* copy all images and masks prior to the "removed" image */
2355 if (i > 0) {
2356 TRACE("Pre image copy: Copy %d images\n", i);
2358 SelectObject (hdcSrc, himl->hbmImage);
2359 SelectObject (hdcDst, hbmNewImage);
2360 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2361 hdcSrc, 0, 0, SRCCOPY);
2363 if (himl->hbmMask) {
2364 SelectObject (hdcSrc, himl->hbmMask);
2365 SelectObject (hdcDst, hbmNewMask);
2366 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2367 hdcSrc, 0, 0, SRCCOPY);
2371 /* copy all images and masks behind the removed image */
2372 if (i < himl->cCurImage - 1) {
2373 TRACE("Post image copy!\n");
2374 SelectObject (hdcSrc, himl->hbmImage);
2375 SelectObject (hdcDst, hbmNewImage);
2376 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2377 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2379 if (himl->hbmMask) {
2380 SelectObject (hdcSrc, himl->hbmMask);
2381 SelectObject (hdcDst, hbmNewMask);
2382 BitBlt (hdcDst, i * himl->cx, 0,
2383 (himl->cCurImage - i - 1) * himl->cx,
2384 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2388 DeleteDC (hdcSrc);
2389 DeleteDC (hdcDst);
2391 /* delete old images and insert new ones */
2392 DeleteObject (himl->hbmImage);
2393 himl->hbmImage = hbmNewImage;
2394 if (himl->hbmMask) {
2395 DeleteObject (himl->hbmMask);
2396 himl->hbmMask = hbmNewMask;
2399 himl->cCurImage--;
2400 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2403 return TRUE;
2407 /*************************************************************************
2408 * ImageList_Replace [COMCTL32.70]
2410 * Replaces an image in an image list with a new image.
2412 * PARAMS
2413 * himl [I] handle to image list
2414 * i [I] image index
2415 * hbmImage [I] handle to image bitmap
2416 * hbmMask [I] handle to mask bitmap. Can be NULL.
2418 * RETURNS
2419 * Success: TRUE
2420 * Failure: FALSE
2423 BOOL WINAPI
2424 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2425 HBITMAP hbmMask)
2427 HDC hdcImageList, hdcImage;
2428 BITMAP bmp;
2430 if (himl == NULL) {
2431 ERR("Invalid image list handle!\n");
2432 return FALSE;
2435 if ((i >= himl->cMaxImage) || (i < 0)) {
2436 ERR("Invalid image index!\n");
2437 return FALSE;
2440 hdcImageList = CreateCompatibleDC (0);
2441 hdcImage = CreateCompatibleDC (0);
2442 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2444 /* Replace Image */
2445 SelectObject (hdcImageList, himl->hbmImage);
2446 SelectObject (hdcImage, hbmImage);
2448 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2449 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2451 if (himl->hbmMask)
2453 /* Replace Mask */
2454 SelectObject (hdcImageList, himl->hbmMask);
2455 SelectObject (hdcImage, hbmMask);
2457 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2458 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2461 /* Remove the background from the image
2463 SelectObject (hdcImageList, himl->hbmImage);
2464 StretchBlt (hdcImageList,
2465 i*himl->cx, 0, himl->cx, himl->cy,
2466 hdcImage,
2467 0, 0, bmp.bmWidth, bmp.bmHeight,
2468 0x220326); /* NOTSRCAND */
2471 DeleteDC (hdcImage);
2472 DeleteDC (hdcImageList);
2474 return TRUE;
2478 /*************************************************************************
2479 * ImageList_ReplaceIcon [COMCTL32.75]
2481 * Replaces an image in an image list using an icon.
2483 * PARAMS
2484 * himl [I] handle to image list
2485 * i [I] image index
2486 * hIcon [I] handle to icon
2488 * RETURNS
2489 * Success: index of the replaced image
2490 * Failure: -1
2493 INT WINAPI
2494 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2496 HDC hdcImageList, hdcImage;
2497 INT nIndex;
2498 HICON hBestFitIcon;
2499 HBITMAP hbmOldSrc, hbmOldDst;
2500 ICONINFO ii;
2501 BITMAP bmp;
2503 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2505 if (himl == NULL)
2506 return -1;
2507 if ((i >= himl->cMaxImage) || (i < -1))
2508 return -1;
2510 hBestFitIcon = CopyImage(
2511 hIcon, IMAGE_ICON,
2512 himl->cx, himl->cy,
2513 LR_COPYFROMRESOURCE);
2515 GetIconInfo (hBestFitIcon, &ii);
2516 if (ii.hbmMask == 0)
2517 ERR("no mask!\n");
2518 if (ii.hbmColor == 0)
2519 ERR("no color!\n");
2520 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2522 if (i == -1) {
2523 if (himl->cCurImage + 1 > himl->cMaxImage)
2524 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2526 nIndex = himl->cCurImage;
2527 himl->cCurImage++;
2529 else
2530 nIndex = i;
2532 hdcImageList = CreateCompatibleDC (0);
2533 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2534 if (hdcImageList == 0)
2535 ERR("invalid hdcImageList!\n");
2537 hdcImage = CreateCompatibleDC (0);
2538 TRACE("hdcImage=0x%x!\n", hdcImage);
2539 if (hdcImage == 0)
2540 ERR("invalid hdcImage!\n");
2542 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2543 SetTextColor( hdcImageList, RGB(0,0,0));
2544 SetBkColor( hdcImageList, RGB(255,255,255));
2545 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2546 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2547 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2549 if (himl->hbmMask) {
2550 SelectObject (hdcImageList, himl->hbmMask);
2551 SelectObject (hdcImage, ii.hbmMask);
2552 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2553 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2556 SelectObject (hdcImage, hbmOldSrc);
2557 SelectObject (hdcImageList, hbmOldDst);
2559 if(hBestFitIcon)
2560 DestroyIcon(hBestFitIcon);
2561 if (hdcImageList)
2562 DeleteDC (hdcImageList);
2563 if (hdcImage)
2564 DeleteDC (hdcImage);
2565 if (ii.hbmColor)
2566 DeleteObject (ii.hbmColor);
2567 if (ii.hbmMask)
2568 DeleteObject (ii.hbmMask);
2570 return nIndex;
2574 /*************************************************************************
2575 * ImageList_SetBkColor [COMCTL32.76]
2577 * Sets the background color of an image list.
2579 * PARAMS
2580 * himl [I] handle to image list
2581 * clrBk [I] background color
2583 * RETURNS
2584 * Success: previous background color
2585 * Failure: CLR_NONE
2588 COLORREF WINAPI
2589 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2591 COLORREF clrOldBk;
2593 if (himl == NULL)
2594 return CLR_NONE;
2596 clrOldBk = himl->clrBk;
2597 himl->clrBk = clrBk;
2598 return clrOldBk;
2602 /*************************************************************************
2603 * ImageList_SetDragCursorImage [COMCTL32.77]
2605 * Combines the specified image with the current drag image
2607 * PARAMS
2608 * himlDrag [I] handle to drag image list
2609 * iDrag [I] drag image index
2610 * dxHotspot [I] X position of the hot spot
2611 * dyHotspot [I] Y position of the hot spot
2613 * RETURNS
2614 * Success: TRUE
2615 * Failure: FALSE
2617 * NOTES
2618 * When this function is called and the drag image is visible, a
2619 * short flickering occurs but this matches the Win9x behavior. It is
2620 * possible to fix the flickering using code like in ImageList_DragMove.
2623 BOOL WINAPI
2624 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2625 INT dxHotspot, INT dyHotspot)
2627 HIMAGELIST himlTemp;
2628 INT dx, dy;
2629 BOOL visible;
2631 if (InternalDrag.himl == NULL)
2632 return FALSE;
2634 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2635 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2637 visible = InternalDrag.bShow;
2639 /* Calculate the offset between the origin of the old image and the
2640 * origin of the second image.
2641 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2642 * hotspot) to the origin of the second image.
2643 * See M$DN for details */
2644 if(InternalDrag.bHSPending) {
2645 dx = 0;
2646 dy = 0;
2647 InternalDrag.bHSPending = FALSE;
2648 } else {
2649 dx = InternalDrag.dxHotspot - dxHotspot;
2650 dy = InternalDrag.dyHotspot - dyHotspot;
2652 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2654 if (visible) {
2655 /* hide the drag image */
2656 ImageList_DragShowNolock(FALSE);
2658 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2659 (InternalDrag.himl->cy != himlTemp->cy)) {
2660 /* the size of the drag image changed, invalidate the buffer */
2661 DeleteObject(InternalDrag.hbmBg);
2662 InternalDrag.hbmBg = 0;
2665 ImageList_Destroy (InternalDrag.himl);
2666 InternalDrag.himl = himlTemp;
2668 /* update the InternalDragOffset, if the origin of the
2669 * DragImage was changed by ImageList_Merge. */
2670 if (dx <= 0)
2671 InternalDrag.dxHotspot = dxHotspot;
2672 if (dy <= 0)
2673 InternalDrag.dyHotspot = dyHotspot;
2675 if (visible) {
2676 /* show the drag image */
2677 ImageList_DragShowNolock(TRUE);
2680 return TRUE;
2684 /*************************************************************************
2685 * ImageList_SetFilter [COMCTL32.78]
2687 * Sets a filter (or does something completely different)!!???
2689 * PARAMS
2690 * himl [I] handle to image list
2691 * i [I] ???
2692 * dwFilter [I] ???
2694 * RETURNS
2695 * Success: TRUE ???
2696 * Failure: FALSE ???
2698 * BUGS
2699 * This is an UNDOCUMENTED function!!!!
2700 * empty stub.
2703 BOOL WINAPI
2704 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2706 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2707 himl, i, dwFilter);
2709 return FALSE;
2713 /*************************************************************************
2714 * ImageList_SetFlags [COMCTL32.79]
2716 * BUGS
2717 * Stub.
2720 DWORD WINAPI
2721 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2723 FIXME("(%p %08lx):empty stub\n", himl, flags);
2724 return 0;
2728 /*************************************************************************
2729 * ImageList_SetIconSize [COMCTL32.80]
2731 * Sets the image size of the bitmap and deletes all images.
2733 * PARAMS
2734 * himl [I] handle to image list
2735 * cx [I] image width
2736 * cy [I] image height
2738 * RETURNS
2739 * Success: TRUE
2740 * Failure: FALSE
2743 BOOL WINAPI
2744 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2746 INT nCount;
2748 if (!himl)
2749 return FALSE;
2751 /* remove all images */
2752 himl->cMaxImage = himl->cInitial + himl->cGrow;
2753 himl->cCurImage = 0;
2754 himl->cx = cx;
2755 himl->cy = cy;
2757 /* initialize overlay mask indices */
2758 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2759 himl->nOvlIdx[nCount] = -1;
2761 DeleteObject (himl->hbmImage);
2762 himl->hbmImage =
2763 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2764 1, himl->uBitsPixel, NULL);
2766 if (himl->hbmMask) {
2767 DeleteObject (himl->hbmMask);
2768 himl->hbmMask =
2769 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2770 1, 1, NULL);
2773 return TRUE;
2777 /*************************************************************************
2778 * ImageList_SetImageCount [COMCTL32.81]
2780 * Resizes an image list to the specified number of images.
2782 * PARAMS
2783 * himl [I] handle to image list
2784 * iImageCount [I] number of images in the image list
2786 * RETURNS
2787 * Success: TRUE
2788 * Failure: FALSE
2791 BOOL WINAPI
2792 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2794 HDC hdcImageList, hdcBitmap;
2795 HBITMAP hbmNewBitmap;
2796 INT nNewCount, nCopyCount;
2798 if (!himl)
2799 return FALSE;
2800 if (himl->cCurImage >= iImageCount)
2801 return FALSE;
2802 if (himl->cMaxImage > iImageCount)
2803 return TRUE;
2805 nNewCount = iImageCount + himl->cGrow;
2806 nCopyCount = min(himl->cCurImage, iImageCount);
2808 hdcImageList = CreateCompatibleDC (0);
2809 hdcBitmap = CreateCompatibleDC (0);
2811 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2812 1, himl->uBitsPixel, NULL);
2813 if (hbmNewBitmap != 0)
2815 SelectObject (hdcImageList, himl->hbmImage);
2816 SelectObject (hdcBitmap, hbmNewBitmap);
2818 /* copy images */
2819 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2820 hdcImageList, 0, 0, SRCCOPY);
2821 #if 0
2822 /* delete 'empty' image space */
2823 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2824 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2825 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2826 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2827 #endif
2828 DeleteObject (himl->hbmImage);
2829 himl->hbmImage = hbmNewBitmap;
2831 else
2832 ERR("Could not create new image bitmap !\n");
2834 if (himl->hbmMask)
2836 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2837 1, 1, NULL);
2838 if (hbmNewBitmap != 0)
2840 SelectObject (hdcImageList, himl->hbmMask);
2841 SelectObject (hdcBitmap, hbmNewBitmap);
2843 /* copy images */
2844 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2845 hdcImageList, 0, 0, SRCCOPY);
2846 #if 0
2847 /* delete 'empty' image space */
2848 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2849 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2850 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2851 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2852 #endif
2853 DeleteObject (himl->hbmMask);
2854 himl->hbmMask = hbmNewBitmap;
2856 else
2857 ERR("Could not create new mask bitmap!\n");
2860 DeleteDC (hdcImageList);
2861 DeleteDC (hdcBitmap);
2863 /* Update max image count and current image count */
2864 himl->cMaxImage = nNewCount;
2865 if (himl->cCurImage > nCopyCount)
2866 himl->cCurImage = nCopyCount;
2868 return TRUE;
2872 /*************************************************************************
2873 * ImageList_SetOverlayImage [COMCTL32.82]
2875 * Assigns an overlay mask index to an existing image in an image list.
2877 * PARAMS
2878 * himl [I] handle to image list
2879 * iImage [I] image index
2880 * iOverlay [I] overlay mask index
2882 * RETURNS
2883 * Success: TRUE
2884 * Failure: FALSE
2887 BOOL WINAPI
2888 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2890 if (!himl)
2891 return FALSE;
2892 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2893 return FALSE;
2894 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2895 return FALSE;
2896 himl->nOvlIdx[iOverlay - 1] = iImage;
2897 return TRUE;
2902 /* helper for ImageList_Write - write bitmap to pstm
2903 * currently everything is written as 24 bit RGB, except masks
2905 static BOOL
2906 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2908 LPBITMAPFILEHEADER bmfh;
2909 LPBITMAPINFOHEADER bmih;
2910 LPBYTE data, lpBits, lpBitsOrg;
2911 BITMAP bm;
2912 INT bitCount, sizeImage, offBits, totalSize;
2913 INT nwidth, nheight, nsizeImage, icount;
2914 HDC xdc;
2915 BOOL result = FALSE;
2918 xdc = GetDC(0);
2919 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2921 /* XXX is this always correct? */
2922 icount = bm.bmWidth / cx;
2923 nwidth = cx << 2;
2924 nheight = cy * ((icount+3)>>2);
2926 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2927 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2928 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2930 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2931 if(bitCount != 24)
2932 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2933 offBits = totalSize;
2934 totalSize += nsizeImage;
2936 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2937 bmfh = (LPBITMAPFILEHEADER)data;
2938 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2939 lpBits = data + offBits;
2941 /* setup BITMAPFILEHEADER */
2942 bmfh->bfType = (('M' << 8) | 'B');
2943 bmfh->bfSize = 0;
2944 bmfh->bfReserved1 = 0;
2945 bmfh->bfReserved2 = 0;
2946 bmfh->bfOffBits = offBits;
2948 /* setup BITMAPINFOHEADER */
2949 bmih->biSize = sizeof(BITMAPINFOHEADER);
2950 bmih->biWidth = bm.bmWidth;
2951 bmih->biHeight = bm.bmHeight;
2952 bmih->biPlanes = 1;
2953 bmih->biBitCount = bitCount;
2954 bmih->biCompression = BI_RGB;
2955 bmih->biSizeImage = nsizeImage;
2956 bmih->biXPelsPerMeter = 0;
2957 bmih->biYPelsPerMeter = 0;
2958 bmih->biClrUsed = 0;
2959 bmih->biClrImportant = 0;
2961 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2962 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2963 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2964 goto failed;
2965 else {
2966 int i;
2967 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2968 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2970 for(i = 0; i < nheight; i++) {
2971 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2972 int noff = (nbpl * (nheight-1-i));
2973 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2977 bmih->biWidth = nwidth;
2978 bmih->biHeight = nheight;
2980 if(bitCount == 1) {
2981 /* Hack. */
2982 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2983 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2984 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2987 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2988 goto failed;
2990 result = TRUE;
2992 failed:
2993 ReleaseDC(0, xdc);
2994 LocalFree((HLOCAL)lpBitsOrg);
2996 return result;
3000 /*************************************************************************
3001 * ImageList_Write [COMCTL32.83]
3003 * Writes an image list to a stream.
3005 * PARAMS
3006 * himl [I] handle to image list
3007 * pstm [O] Pointer to a stream.
3009 * RETURNS
3010 * Success: TRUE
3011 * Failure: FALSE
3013 * BUGS
3014 * probably.
3017 BOOL WINAPI
3018 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
3020 ILHEAD ilHead;
3021 int i;
3023 if (!himl)
3024 return FALSE;
3026 ilHead.usMagic = (('L' << 8) | 'I');
3027 ilHead.usVersion = 0x101;
3028 ilHead.cCurImage = himl->cCurImage;
3029 ilHead.cMaxImage = himl->cMaxImage;
3030 ilHead.cGrow = himl->cGrow;
3031 ilHead.cx = himl->cx;
3032 ilHead.cy = himl->cy;
3033 ilHead.bkcolor = himl->clrBk;
3034 ilHead.flags = himl->flags;
3035 for(i = 0; i < 4; i++) {
3036 ilHead.ovls[i] = himl->nOvlIdx[i];
3039 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3040 return FALSE;
3042 /* write the bitmap */
3043 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3044 return FALSE;
3046 /* write the mask if we have one */
3047 if(himl->flags & ILC_MASK) {
3048 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
3049 return FALSE;
3052 return TRUE;