Fixed/implemented the ImageList_*Drag* functions.
[wine/multimedia.git] / dlls / comctl32 / imagelist.c
bloba3ee6d3c4282dfa345aaa2fc346fde4db6d5c7e0
1 /*
2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * 2000 Jason Mawdsley.
6 * 2001 Michael Stefaniuc
8 * TODO:
9 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
10 * - Fix ImageList_GetIcon.
11 * - Fix ImageList_Write.
12 * - Fix ImageList_SetFilter (undocumented).
13 * BTW does anybody know anything about this function???
14 * - It removes 12 Bytes from the stack (3 Parameters).
15 * - First parameter SHOULD be a HIMAGELIST.
16 * - Second parameter COULD be an index?????
17 * - Third parameter.... ?????????????????????
19 * Comments:
20 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
21 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
22 * partially implemented, the functions mentioned above will be
23 * limited in functionality too.
26 #include <stdlib.h>
27 #include <string.h>
28 #include "winerror.h"
29 #include "winbase.h"
30 #include "wine/obj_base.h"
31 #include "wine/obj_storage.h"
32 #include "commctrl.h"
33 #include "imagelist.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(imagelist);
39 #define MAX_OVERLAYIMAGE 15
41 /* internal image list data used for Drag & Drop operations */
42 typedef struct
44 HWND hwnd;
45 HIMAGELIST himl;
46 /* position of the drag image relative to the window */
47 INT x;
48 INT y;
49 /* offset of the hotspot relative to the origin of the image */
50 INT dxHotspot;
51 INT dyHotspot;
52 /* is the drag image visible */
53 BOOL bShow;
54 /* saved background */
55 HBITMAP hbmBg;
56 } INTERNALDRAG;
58 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
62 /*************************************************************************
63 * IMAGELIST_InternalExpandBitmaps [Internal]
65 * Expands the bitmaps of an image list by the given number of images.
67 * PARAMS
68 * himl [I] handle to image list
69 * nImageCount [I] number of images to add
71 * RETURNS
72 * nothing
74 * NOTES
75 * This function can NOT be used to reduce the number of images.
77 static VOID
78 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
80 HDC hdcImageList, hdcBitmap;
81 HBITMAP hbmNewBitmap;
82 INT nNewWidth, nNewCount;
84 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
85 && (himl->cy >= cy))
86 return;
88 if (cy == 0) cy = himl->cy;
89 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
90 nNewWidth = nNewCount * himl->cx;
92 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
93 hdcImageList = CreateCompatibleDC (0);
94 hdcBitmap = CreateCompatibleDC (0);
96 hbmNewBitmap =
97 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
98 if (hbmNewBitmap == 0)
99 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
101 SelectObject (hdcImageList, himl->hbmImage);
102 SelectObject (hdcBitmap, hbmNewBitmap);
103 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
104 hdcImageList, 0, 0, SRCCOPY);
106 DeleteObject (himl->hbmImage);
107 himl->hbmImage = hbmNewBitmap;
109 if (himl->hbmMask) {
110 hbmNewBitmap =
111 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
113 if (hbmNewBitmap == 0)
114 ERR("creating new mask bitmap!\n");
116 SelectObject (hdcImageList, himl->hbmMask);
117 SelectObject (hdcBitmap, hbmNewBitmap);
118 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
119 hdcImageList, 0, 0, SRCCOPY);
120 DeleteObject (himl->hbmMask);
121 himl->hbmMask = hbmNewBitmap;
124 himl->cMaxImage = nNewCount;
126 DeleteDC (hdcImageList);
127 DeleteDC (hdcBitmap);
131 /*************************************************************************
132 * IMAGELIST_InternalDraw [Internal]
134 * Draws the image in the ImageList (without the mask)
136 * PARAMS
137 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
138 * cx [I] the width of the image to display
139 * cy............[I] the height of the image to display
141 * RETURNS
142 * nothing
144 * NOTES
145 * This function is used by ImageList_DrawIndirect, when it is
146 * required to draw only the Image (without the mask) to the screen.
148 * Blending and Overlays styles are accomplished by another function
150 static VOID
151 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
153 HDC hImageDC;
154 HBITMAP hOldBitmap;
156 hImageDC = CreateCompatibleDC(0);
157 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
158 BitBlt(pimldp->hdcDst,
159 pimldp->x, pimldp->y, cx, cy,
160 hImageDC,
161 pimldp->himl->cx * pimldp->i, 0,
162 SRCCOPY);
164 SelectObject(hImageDC, hOldBitmap);
165 DeleteDC(hImageDC);
169 /*************************************************************************
170 * IMAGELIST_InternalDrawMask [Internal]
172 * Draws the image in the ImageList with the mask
174 * PARAMS
175 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
176 * cx [I] the width of the image to display
177 * cy............[I] the height of the image to display
179 * RETURNS
180 * nothing
182 * NOTES
183 * This function is used by ImageList_DrawIndirect, when it is
184 * required to draw the Image with the mask to the screen.
186 * Blending and Overlays styles are accomplished by another function.
188 static VOID
189 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
191 BOOL bUseCustomBackground, bBlendFlag;
192 HBRUSH hBrush, hOldBrush;
193 HDC hMaskDC, hImageDC;
194 HBITMAP hOldBitmapImage, hOldBitmapMask;
195 HIMAGELIST himlLocal = pimldp->himl;
196 COLORREF oldBkColor, oldFgColor;
197 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
200 * We need a dc and bitmap to draw on that is
201 * not on the screen.
203 HDC hOffScreenDC = 0;
204 HBITMAP hOffScreenBmp = 0;
206 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
207 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
209 hImageDC = CreateCompatibleDC(0);
210 hMaskDC = CreateCompatibleDC(0);
212 /* Create a compatible DC. */
213 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
215 if ( hOffScreenDC )
217 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
219 if ( hOffScreenBmp )
220 SelectObject( hOffScreenDC, hOffScreenBmp );
221 else
222 goto cleanup;
224 else
225 goto cleanup;
227 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
228 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
231 * Get a copy of the image for the masking operations.
232 * We will use the copy, and this dc for all the various
233 * blitting, and then do one final blit to the screen dc.
234 * This should clean up most of the flickering.
236 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
237 pimldp->y, SRCCOPY);
240 * Draw the Background for the appropriate Styles
242 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
243 || bBlendFlag) )
246 hBrush = CreateSolidBrush (himlLocal->clrBk);
247 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
249 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
251 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
255 * Draw Image Transparently over the current background
257 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
258 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
259 { /*
260 * To obtain a transparent look, background color should be set
261 * to white and foreground color to black when blting the
262 * monochrome mask.
265 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
266 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
268 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
269 0, SRCAND );
271 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
272 0, SRCPAINT );
277 * Draw the image when no Background is specified
279 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
281 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
282 himlLocal->cx * pimldp->i, 0, SRCCOPY);
285 * Draw the mask with or without a background
287 else if(fStyle & ILD_MASK)
289 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
290 0, bUseCustomBackground ? SRCCOPY : SRCAND);
294 * Blit the bitmap to the screen now.
296 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
297 hOffScreenDC, 0, 0, SRCCOPY);
300 SelectObject(hImageDC, hOldBitmapImage);
301 SelectObject(hMaskDC, hOldBitmapMask);
303 cleanup:
305 DeleteDC(hImageDC);
306 DeleteDC(hMaskDC);
308 DeleteDC( hOffScreenDC );
309 DeleteObject( hOffScreenBmp );
311 return;
314 /*************************************************************************
315 * IMAGELIST_InternalDrawBlend [Internal]
317 * Draws the Blend over the current image
319 * PARAMS
320 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
321 * cx [I] the width of the image to display
322 * cy............[I] the height of the image to display
324 * RETURNS
325 * nothing
327 * NOTES
328 * This functions is used by ImageList_DrawIndirect, when it is
329 * required to add the blend to the current image.
332 static VOID
333 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
336 HDC hBlendMaskDC,hMaskDC;
337 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
338 HBITMAP hBlendMaskBitmap, hOldBitmap;
339 COLORREF clrBlend, OldTextColor, OldBkColor;
340 HIMAGELIST himlLocal = pimldp->himl;
342 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
343 if (!(pimldp->rgbFg == CLR_DEFAULT))
345 clrBlend = pimldp->rgbFg;
347 /* Create the blend Mask
349 hBlendMaskDC = CreateCompatibleDC(0);
350 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
351 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
353 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
354 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
356 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
357 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
358 SelectObject(hBlendMaskDC, hOldBrush);
360 /* Modify the blend mask if an Image Mask exist
362 if(pimldp->himl->hbmMask != 0)
364 HBITMAP hOldMaskBitmap;
365 hMaskDC = CreateCompatibleDC(0);
366 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
368 BitBlt(hBlendMaskDC,
369 0,0, cx, cy,
370 hMaskDC,
371 himlLocal->cx * pimldp->i,0,
372 0x220326); /* NOTSRCAND */
374 BitBlt(hBlendMaskDC,
375 0,0, cx, cy,
376 hBlendMaskDC,
377 0,0,
378 NOTSRCCOPY);
380 SelectObject(hMaskDC, hOldMaskBitmap);
381 DeleteDC(hMaskDC);
384 /* Apply blend to the current image given the BlendMask
386 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
387 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
388 hBlendColorBrush = CreateSolidBrush(clrBlend);
389 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
391 BitBlt (pimldp->hdcDst,
392 pimldp->x, pimldp->y, cx, cy,
393 hBlendMaskDC,
394 0, 0,
395 0xB8074A); /* PSDPxax */
397 SelectObject(pimldp->hdcDst, hOldBrush);
398 SetTextColor(pimldp->hdcDst, OldTextColor);
399 SetBkColor(pimldp->hdcDst, OldBkColor);
400 SelectObject(hBlendMaskDC, hOldBitmap);
401 DeleteDC(hBlendMaskDC);
402 DeleteObject(hBlendMaskBitmap);
403 DeleteObject(hBlendColorBrush);
406 /*************************************************************************
407 * IMAGELIST_InternalDrawOverlay [Internal]
409 * Draws the overlay image
411 * PARAMS
412 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
413 * cx [I] the width of the image to display
414 * cy............[I] the height of the image to display
416 * RETURNS
417 * nothing
419 * NOTES
420 * This functions is used by ImageList_DrawIndirect, when it is
421 * required to draw the overlay
425 static VOID
426 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
428 INT nOvlIdx;
429 HDC hImageDC;
430 HBITMAP hOldBitmap;
432 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
433 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
435 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
436 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
438 hImageDC = CreateCompatibleDC(0);
439 if (pimldp->himl->hbmMask)
441 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
442 pimldp->himl->hbmMask);
444 BitBlt (pimldp->hdcDst,
445 pimldp->x, pimldp->y, cx, cy,
446 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
447 SRCAND);
449 SelectObject(hImageDC, hOldBitmap);
451 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
452 pimldp->himl->hbmImage);
454 BitBlt (pimldp->hdcDst,
455 pimldp->x, pimldp->y, cx, cy,
456 hImageDC,
457 pimldp->himl->cx * nOvlIdx, 0,
458 SRCPAINT);
460 SelectObject(hImageDC, hOldBitmap);
461 DeleteDC(hImageDC);
467 /*************************************************************************
468 * ImageList_Add [COMCTL32.40]
470 * Add an image or images to an image list.
472 * PARAMS
473 * himl [I] handle to image list
474 * hbmImage [I] handle to image bitmap
475 * hbmMask [I] handle to mask bitmap
477 * RETURNS
478 * Success: Index of the first new image.
479 * Failure: -1
482 INT WINAPI
483 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
485 HDC hdcImage, hdcBitmap;
486 INT nFirstIndex, nImageCount;
487 INT nStartX;
488 BITMAP bmp;
489 HBITMAP hOldBitmapImage, hOldBitmap;
491 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
492 if (!himl || !hbmImage)
493 return -1;
495 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
496 nImageCount = bmp.bmWidth / himl->cx;
498 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
500 nStartX = himl->cCurImage * himl->cx;
502 hdcImage = CreateCompatibleDC(0);
503 hdcBitmap = CreateCompatibleDC(0);
505 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
506 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
508 /* Copy result to the imagelist
510 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
511 hdcBitmap, 0, 0, SRCCOPY);
513 if(himl->hbmMask)
515 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
517 hdcMask = CreateCompatibleDC (0);
518 hdcTemp = CreateCompatibleDC(0);
519 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
520 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
522 BitBlt (hdcMask,
523 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
524 hdcTemp,
525 0, 0,
526 SRCCOPY);
528 SelectObject(hdcTemp, hOldBitmapTemp);
529 DeleteDC(hdcTemp);
531 /* Remove the background from the image
533 BitBlt (hdcImage,
534 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
535 hdcMask,
536 nStartX, 0,
537 0x220326); /* NOTSRCAND */
539 SelectObject(hdcMask, hOldBitmapMask);
540 DeleteDC(hdcMask);
543 SelectObject(hdcImage, hOldBitmapImage);
544 SelectObject(hdcBitmap, hOldBitmap);
545 DeleteDC(hdcImage);
546 DeleteDC(hdcBitmap);
548 nFirstIndex = himl->cCurImage;
549 himl->cCurImage += nImageCount;
551 return nFirstIndex;
555 /*************************************************************************
556 * ImageList_AddIcon [COMCTL32.41]
558 * Adds an icon to an image list.
560 * PARAMS
561 * himl [I] handle to image list
562 * hIcon [I] handle to icon
564 * RETURNS
565 * Success: index of the new image
566 * Failure: -1
569 INT WINAPI
570 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
572 return ImageList_ReplaceIcon (himl, -1, hIcon);
576 /*************************************************************************
577 * ImageList_AddMasked [COMCTL32.42]
579 * Adds an image or images to an image list and creates a mask from the
580 * specified bitmap using the mask color.
582 * PARAMS
583 * himl [I] handle to image list.
584 * hBitmap [I] handle to bitmap
585 * clrMask [I] mask color.
587 * RETURNS
588 * Success: Index of the first new image.
589 * Failure: -1
592 INT WINAPI
593 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
595 HDC hdcImage, hdcMask, hdcBitmap;
596 INT nIndex, nImageCount, nMaskXOffset=0;
597 BITMAP bmp;
598 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
599 HBITMAP hMaskBitmap=0;
600 COLORREF bkColor;
602 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
603 if (himl == NULL)
604 return -1;
606 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
607 return -1;
609 nImageCount = bmp.bmWidth / himl->cx;
611 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
613 nIndex = himl->cCurImage;
614 himl->cCurImage += nImageCount;
616 hdcMask = CreateCompatibleDC (0);
617 hdcImage = CreateCompatibleDC(0);
618 hdcBitmap = CreateCompatibleDC(0);
621 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
622 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
623 if(himl->hbmMask)
625 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
626 nMaskXOffset = nIndex * himl->cx;
628 else
631 Create a temp Mask so we can remove the background of
632 the Image (Windows does this even if there is no mask)
634 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
635 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
636 nMaskXOffset = 0;
638 /* create monochrome image to the mask bitmap */
639 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
640 GetPixel (hdcBitmap, 0, 0);
641 SetBkColor (hdcBitmap, bkColor);
642 BitBlt (hdcMask,
643 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
644 hdcBitmap, 0, 0,
645 SRCCOPY);
647 SetBkColor(hdcBitmap, RGB(255,255,255));
648 /*Remove the background from the image
651 WINDOWS BUG ALERT!!!!!!
652 The statement below should not be done in common practice
653 but this is how ImageList_AddMasked works in Windows.
654 It overwrites the original bitmap passed, this was discovered
655 by using the same bitmap to iterate the different styles
656 on windows where it failed (BUT ImageList_Add is OK)
657 This is here in case some apps rely on this bug
659 BitBlt(hdcBitmap,
660 0, 0, bmp.bmWidth, bmp.bmHeight,
661 hdcMask,
662 nMaskXOffset, 0,
663 0x220326); /* NOTSRCAND */
664 /* Copy result to the imagelist
666 BitBlt (hdcImage,
667 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
668 hdcBitmap,
669 0, 0,
670 SRCCOPY);
671 /* Clean up
673 SelectObject(hdcMask,hOldBitmapMask);
674 SelectObject(hdcImage, hOldBitmapImage);
675 SelectObject(hdcBitmap, hOldBitmap);
676 DeleteDC(hdcMask);
677 DeleteDC(hdcImage);
678 DeleteDC(hdcBitmap);
679 if(!himl->hbmMask)
681 DeleteObject(hMaskBitmap);
684 return nIndex;
688 /*************************************************************************
689 * ImageList_BeginDrag [COMCTL32.43]
691 * Creates a temporary image list that contains one image. It will be used
692 * as a drag image.
694 * PARAMS
695 * himlTrack [I] handle to the source image list
696 * iTrack [I] index of the drag image in the source image list
697 * dxHotspot [I] X position of the hot spot of the drag image
698 * dyHotspot [I] Y position of the hot spot of the drag image
700 * RETURNS
701 * Success: TRUE
702 * Failure: FALSE
705 BOOL WINAPI
706 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
707 INT dxHotspot, INT dyHotspot)
709 HDC hdcSrc, hdcDst;
710 INT cx, cy;
712 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
713 dxHotspot, dyHotspot);
715 if (himlTrack == NULL)
716 return FALSE;
718 if (InternalDrag.himl)
719 ImageList_EndDrag ();
721 cx = himlTrack->cx;
722 cy = himlTrack->cy;
724 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
725 if (InternalDrag.himl == NULL) {
726 ERR("Error creating drag image list!\n");
727 return FALSE;
730 InternalDrag.dxHotspot = dxHotspot;
731 InternalDrag.dyHotspot = dyHotspot;
733 hdcSrc = CreateCompatibleDC (0);
734 hdcDst = CreateCompatibleDC (0);
736 /* copy image */
737 SelectObject (hdcSrc, himlTrack->hbmImage);
738 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
739 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
741 /* copy mask */
742 SelectObject (hdcSrc, himlTrack->hbmMask);
743 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
744 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
746 DeleteDC (hdcSrc);
747 DeleteDC (hdcDst);
749 InternalDrag.himl->cCurImage = 1;
751 return TRUE;
755 /*************************************************************************
756 * ImageList_Copy [COMCTL32.44]
758 * Copies an image of the source image list to an image of the
759 * destination image list. Images can be copied or swapped.
761 * PARAMS
762 * himlDst [I] handle to the destination image list
763 * iDst [I] destination image index.
764 * himlSrc [I] handle to the source image list
765 * iSrc [I] source image index
766 * uFlags [I] flags for the copy operation
768 * RETURNS
769 * Success: TRUE
770 * Failure: FALSE
772 * NOTES
773 * Copying from one image list to another is possible. The original
774 * implementation just copies or swaps within one image list.
775 * Could this feature become a bug??? ;-)
778 BOOL WINAPI
779 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
780 INT iSrc, INT uFlags)
782 HDC hdcSrc, hdcDst;
784 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
786 if ((himlSrc == NULL) || (himlDst == NULL))
787 return FALSE;
788 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
789 return FALSE;
790 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
791 return FALSE;
793 hdcSrc = CreateCompatibleDC (0);
794 if (himlDst == himlSrc)
795 hdcDst = hdcSrc;
796 else
797 hdcDst = CreateCompatibleDC (0);
799 if (uFlags & ILCF_SWAP) {
800 /* swap */
801 HBITMAP hbmTempImage, hbmTempMask;
803 /* create temporary bitmaps */
804 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
805 himlSrc->uBitsPixel, NULL);
806 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
807 1, NULL);
809 /* copy (and stretch) destination to temporary bitmaps.(save) */
810 /* image */
811 SelectObject (hdcSrc, himlDst->hbmImage);
812 SelectObject (hdcDst, hbmTempImage);
813 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
814 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
815 SRCCOPY);
816 /* mask */
817 SelectObject (hdcSrc, himlDst->hbmMask);
818 SelectObject (hdcDst, hbmTempMask);
819 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
820 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
821 SRCCOPY);
823 /* copy (and stretch) source to destination */
824 /* image */
825 SelectObject (hdcSrc, himlSrc->hbmImage);
826 SelectObject (hdcDst, himlDst->hbmImage);
827 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
828 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
829 SRCCOPY);
830 /* mask */
831 SelectObject (hdcSrc, himlSrc->hbmMask);
832 SelectObject (hdcDst, himlDst->hbmMask);
833 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
834 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
835 SRCCOPY);
837 /* copy (without stretching) temporary bitmaps to source (restore) */
838 /* image */
839 SelectObject (hdcSrc, hbmTempImage);
840 SelectObject (hdcDst, himlSrc->hbmImage);
841 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
842 hdcSrc, 0, 0, SRCCOPY);
843 /* mask */
844 SelectObject (hdcSrc, hbmTempMask);
845 SelectObject (hdcDst, himlSrc->hbmMask);
846 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
847 hdcSrc, 0, 0, SRCCOPY);
849 /* delete temporary bitmaps */
850 DeleteObject (hbmTempMask);
851 DeleteObject (hbmTempImage);
853 else {
854 /* copy image */
855 SelectObject (hdcSrc, himlSrc->hbmImage);
856 if (himlSrc == himlDst)
857 hdcDst = hdcSrc;
858 else
859 SelectObject (hdcDst, himlDst->hbmImage);
860 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
861 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
862 SRCCOPY);
864 /* copy mask */
865 SelectObject (hdcSrc, himlSrc->hbmMask);
866 if (himlSrc == himlDst)
867 hdcDst = hdcSrc;
868 else
869 SelectObject (hdcDst, himlDst->hbmMask);
870 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
871 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
872 SRCCOPY);
875 DeleteDC (hdcSrc);
876 if (himlSrc != himlDst)
877 DeleteDC (hdcDst);
879 return TRUE;
883 /*************************************************************************
884 * ImageList_Create [COMCTL32.45] Creates a new image list.
886 * PARAMS
887 * cx [I] image height
888 * cy [I] image width
889 * flags [I] creation flags
890 * cInitial [I] initial number of images in the image list
891 * cGrow [I] number of images by which image list grows
893 * RETURNS
894 * Success: Handle to the created image list
895 * Failure: NULL
898 HIMAGELIST WINAPI
899 ImageList_Create (INT cx, INT cy, UINT flags,
900 INT cInitial, INT cGrow)
902 HIMAGELIST himl;
903 HDC hdc;
904 INT nCount;
905 HBITMAP hbmTemp;
906 static WORD aBitBlend25[] =
907 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
909 static WORD aBitBlend50[] =
910 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
912 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
914 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
915 if (!himl)
916 return NULL;
918 himl->cx = cx;
919 himl->cy = cy;
920 himl->flags = flags;
921 himl->cMaxImage = cInitial + cGrow;
922 himl->cInitial = cInitial;
923 himl->cGrow = cGrow;
924 himl->cCurImage = 0;
925 himl->clrFg = CLR_DEFAULT;
926 himl->clrBk = CLR_NONE;
928 /* initialize overlay mask indices */
929 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
930 himl->nOvlIdx[nCount] = -1;
932 hdc = CreateCompatibleDC (0);
933 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
934 DeleteDC (hdc);
936 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
938 if (himl->cMaxImage > 0) {
939 himl->hbmImage =
940 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
941 1, himl->uBitsPixel, NULL);
942 if (himl->hbmImage == 0) {
943 ERR("Error creating image bitmap!\n");
944 return NULL;
947 else
948 himl->hbmImage = 0;
950 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
951 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
952 1, 1, NULL);
953 if (himl->hbmMask == 0) {
954 ERR("Error creating mask bitmap!\n");
955 if (himl->hbmImage)
956 DeleteObject (himl->hbmImage);
957 return NULL;
960 else
961 himl->hbmMask = 0;
963 /* create blending brushes */
964 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
965 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
966 DeleteObject (hbmTemp);
968 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
969 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
970 DeleteObject (hbmTemp);
972 TRACE("created imagelist %p\n", himl);
973 return himl;
977 /*************************************************************************
978 * ImageList_Destroy [COMCTL32.46]
980 * Destroys an image list.
982 * PARAMS
983 * himl [I] handle to image list
985 * RETURNS
986 * Success: TRUE
987 * Failure: FALSE
990 BOOL WINAPI
991 ImageList_Destroy (HIMAGELIST himl)
993 if (!himl)
994 return FALSE;
996 /* delete image bitmaps */
997 if (himl->hbmImage)
998 DeleteObject (himl->hbmImage);
999 if (himl->hbmMask)
1000 DeleteObject (himl->hbmMask);
1002 /* delete blending brushes */
1003 if (himl->hbrBlend25)
1004 DeleteObject (himl->hbrBlend25);
1005 if (himl->hbrBlend50)
1006 DeleteObject (himl->hbrBlend50);
1008 COMCTL32_Free (himl);
1010 return TRUE;
1014 /*************************************************************************
1015 * ImageList_DragEnter [COMCTL32.47]
1017 * Locks window update and displays the drag image at the given position.
1019 * PARAMS
1020 * hwndLock [I] handle of the window that owns the drag image.
1021 * x [I] X position of the drag image.
1022 * y [I] Y position of the drag image.
1024 * RETURNS
1025 * Success: TRUE
1026 * Failure: FALSE
1028 * NOTES
1029 * The position of the drag image is relative to the window, not
1030 * the client area.
1033 BOOL WINAPI
1034 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1036 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1038 if (InternalDrag.himl == NULL)
1039 return FALSE;
1041 if (hwndLock)
1042 InternalDrag.hwnd = hwndLock;
1043 else
1044 InternalDrag.hwnd = GetDesktopWindow ();
1046 InternalDrag.x = x;
1047 InternalDrag.y = y;
1049 /* draw the drag image and save the background */
1050 if (!ImageList_DragShowNolock(TRUE)) {
1051 return FALSE;
1054 return TRUE;
1058 /*************************************************************************
1059 * ImageList_DragLeave [COMCTL32.48]
1061 * Unlocks window update and hides the drag image.
1063 * PARAMS
1064 * hwndLock [I] handle of the window that owns the drag image.
1066 * RETURNS
1067 * Success: TRUE
1068 * Failure: FALSE
1071 BOOL WINAPI
1072 ImageList_DragLeave (HWND hwndLock)
1074 if (hwndLock)
1075 InternalDrag.hwnd = hwndLock;
1076 else
1077 InternalDrag.hwnd = GetDesktopWindow ();
1079 ImageList_DragShowNolock (FALSE);
1081 return TRUE;
1085 /*************************************************************************
1086 * ImageList_DragMove [COMCTL32.49]
1088 * Moves the drag image.
1090 * PARAMS
1091 * x [I] X position of the drag image.
1092 * y [I] Y position of the drag image.
1094 * RETURNS
1095 * Success: TRUE
1096 * Failure: FALSE
1098 * NOTES
1099 * The position of the drag image is relative to the window, not
1100 * the client area.
1102 * BUGS
1103 * The drag image should be drawn semitransparent.
1106 BOOL WINAPI
1107 ImageList_DragMove (INT x, INT y)
1109 TRACE("(x=%d y=%d)\n", x, y);
1111 if (!InternalDrag.himl) {
1112 return FALSE;
1115 /* draw/update the drag image */
1116 if (InternalDrag.bShow) {
1117 HDC hdcDrag;
1118 HDC hdcOffScreen;
1119 HDC hdcBg;
1120 HBITMAP hbmOffScreen;
1121 INT origNewX, origNewY;
1122 INT origOldX, origOldY;
1123 INT origRegX, origRegY;
1124 INT sizeRegX, sizeRegY;
1127 /* calculate the update region */
1128 origNewX = x - InternalDrag.dxHotspot;
1129 origNewY = y - InternalDrag.dyHotspot;
1130 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1131 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1132 origRegX = min(origNewX, origOldX);
1133 origRegY = min(origNewY, origOldY);
1134 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1135 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1137 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1138 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1139 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1140 hdcBg = CreateCompatibleDC(hdcDrag);
1142 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1143 SelectObject(hdcOffScreen, hbmOffScreen);
1144 SelectObject(hdcBg, InternalDrag.hbmBg);
1146 /* get the actual background of the update region */
1147 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1148 origRegX, origRegY, SRCCOPY);
1149 /* erase the old image */
1150 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1151 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1152 SRCCOPY);
1153 /* save the background */
1154 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1155 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1156 /* draw the image */
1157 /* FIXME: image should be drawn semitransparent */
1158 ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1159 origNewY - origRegY, ILD_NORMAL);
1160 /* draw the update region to the screen */
1161 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1162 hdcOffScreen, 0, 0, SRCCOPY);
1164 DeleteDC(hdcBg);
1165 DeleteDC(hdcOffScreen);
1166 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1169 /* update the image position */
1170 InternalDrag.x = x;
1171 InternalDrag.y = y;
1173 return TRUE;
1177 /*************************************************************************
1178 * ImageList_DragShowNolock [COMCTL32.50]
1180 * Shows or hides the drag image.
1182 * PARAMS
1183 * bShow [I] TRUE shows the drag image, FALSE hides it.
1185 * RETURNS
1186 * Success: TRUE
1187 * Failure: FALSE
1189 * BUGS
1190 * The drag image should be drawn semitransparent.
1193 BOOL WINAPI
1194 ImageList_DragShowNolock (BOOL bShow)
1196 HDC hdcDrag;
1197 HDC hdcBg;
1198 INT x, y;
1200 TRACE("bShow=0x%X!\n", bShow);
1202 /* DragImage is already visible/hidden */
1203 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1204 return FALSE;
1207 /* position of the origin of the DragImage */
1208 x = InternalDrag.x - InternalDrag.dxHotspot;
1209 y = InternalDrag.y - InternalDrag.dyHotspot;
1211 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1212 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1213 if (!hdcDrag) {
1214 return FALSE;
1217 hdcBg = CreateCompatibleDC(hdcDrag);
1218 if (!InternalDrag.hbmBg) {
1219 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1220 InternalDrag.himl->cx, InternalDrag.himl->cy);
1222 SelectObject(hdcBg, InternalDrag.hbmBg);
1224 if (bShow) {
1225 /* save the background */
1226 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1227 hdcDrag, x, y, SRCCOPY);
1228 /* show the image */
1229 /* FIXME: this should be drawn semitransparent */
1230 ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1231 } else {
1232 /* hide the image */
1233 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1234 hdcBg, 0, 0, SRCCOPY);
1237 InternalDrag.bShow = !InternalDrag.bShow;
1239 DeleteDC(hdcBg);
1240 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1241 return TRUE;
1245 /*************************************************************************
1246 * ImageList_Draw [COMCTL32.51] Draws an image.
1248 * PARAMS
1249 * himl [I] handle to image list
1250 * i [I] image index
1251 * hdc [I] handle to device context
1252 * x [I] x position
1253 * y [I] y position
1254 * fStyle [I] drawing flags
1256 * RETURNS
1257 * Success: TRUE
1258 * Failure: FALSE
1260 * NOTES
1261 * Calls ImageList_DrawIndirect.
1263 * SEE
1264 * ImageList_DrawIndirect.
1267 BOOL WINAPI
1268 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1269 INT x, INT y, UINT fStyle)
1271 IMAGELISTDRAWPARAMS imldp;
1273 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1274 imldp.himl = himl;
1275 imldp.i = i;
1276 imldp.hdcDst = hdc,
1277 imldp.x = x;
1278 imldp.y = y;
1279 imldp.cx = 0;
1280 imldp.cy = 0;
1281 imldp.xBitmap = 0;
1282 imldp.yBitmap = 0;
1283 imldp.rgbBk = CLR_DEFAULT;
1284 imldp.rgbFg = CLR_DEFAULT;
1285 imldp.fStyle = fStyle;
1286 imldp.dwRop = 0;
1288 return ImageList_DrawIndirect (&imldp);
1292 /*************************************************************************
1293 * ImageList_DrawEx [COMCTL32.52]
1295 * Draws an image and allows to use extended drawing features.
1297 * PARAMS
1298 * himl [I] handle to image list
1299 * i [I] image index
1300 * hdc [I] handle to device context
1301 * x [I] X position
1302 * y [I] Y position
1303 * xOffs [I] X offset
1304 * yOffs [I] Y offset
1305 * rgbBk [I] background color
1306 * rgbFg [I] foreground color
1307 * fStyle [I] drawing flags
1309 * RETURNS
1310 * Success: TRUE
1311 * Failure: FALSE
1313 * NOTES
1314 * Calls ImageList_DrawIndirect.
1316 * SEE
1317 * ImageList_DrawIndirect.
1320 BOOL WINAPI
1321 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1322 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1323 UINT fStyle)
1325 IMAGELISTDRAWPARAMS imldp;
1327 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1328 imldp.himl = himl;
1329 imldp.i = i;
1330 imldp.hdcDst = hdc,
1331 imldp.x = x;
1332 imldp.y = y;
1333 imldp.cx = dx;
1334 imldp.cy = dy;
1335 imldp.xBitmap = 0;
1336 imldp.yBitmap = 0;
1337 imldp.rgbBk = rgbBk;
1338 imldp.rgbFg = rgbFg;
1339 imldp.fStyle = fStyle;
1340 imldp.dwRop = 0;
1342 return ImageList_DrawIndirect (&imldp);
1346 /*************************************************************************
1347 * ImageList_DrawIndirect [COMCTL32.53]
1349 * Draws an image using ...
1351 * PARAMS
1352 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1354 * RETURNS
1355 * Success: TRUE
1356 * Failure: FALSE
1359 BOOL WINAPI
1360 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1362 INT cx, cy;
1364 Do some Error Checking
1366 if (pimldp == NULL)
1367 return FALSE;
1368 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1369 return FALSE;
1370 if (pimldp->himl == NULL)
1371 return FALSE;
1372 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1373 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1374 return FALSE;
1377 Get the Height and Width to display
1379 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1380 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1382 Draw the image
1384 if(pimldp->himl->hbmMask != 0)
1386 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1388 else
1390 IMAGELIST_InternalDraw(pimldp, cx, cy);
1393 Apply the blend if needed to the Image
1395 if((pimldp->fStyle & ILD_BLEND50)
1396 || (pimldp->fStyle & ILD_BLEND25))
1398 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1401 Apply the Overlay if needed
1403 if (pimldp->fStyle & ILD_OVERLAYMASK)
1405 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1408 return TRUE;
1412 /*************************************************************************
1413 * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
1415 * PARAMS
1416 * himlSrc [I] source image list handle
1418 * RETURNS
1419 * Success: Handle of duplicated image list.
1420 * Failure: NULL
1423 HIMAGELIST WINAPI
1424 ImageList_Duplicate (HIMAGELIST himlSrc)
1426 HIMAGELIST himlDst;
1427 HDC hdcSrc, hdcDst;
1429 if (himlSrc == NULL) {
1430 ERR("Invalid image list handle!\n");
1431 return NULL;
1434 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1435 himlSrc->cInitial, himlSrc->cGrow);
1437 if (himlDst)
1439 hdcSrc = CreateCompatibleDC (0);
1440 hdcDst = CreateCompatibleDC (0);
1441 SelectObject (hdcSrc, himlSrc->hbmImage);
1442 SelectObject (hdcDst, himlDst->hbmImage);
1443 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1444 hdcSrc, 0, 0, SRCCOPY);
1446 if (himlDst->hbmMask)
1448 SelectObject (hdcSrc, himlSrc->hbmMask);
1449 SelectObject (hdcDst, himlDst->hbmMask);
1450 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1451 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1454 DeleteDC (hdcDst);
1455 DeleteDC (hdcSrc);
1457 himlDst->cCurImage = himlSrc->cCurImage;
1458 himlDst->cMaxImage = himlSrc->cMaxImage;
1460 return himlDst;
1464 /*************************************************************************
1465 * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
1467 * Finishes a drag operation.
1469 * PARAMS
1470 * no Parameters
1472 * RETURNS
1473 * Success: TRUE
1474 * Failure: FALSE
1477 BOOL WINAPI
1478 ImageList_EndDrag (void)
1480 /* hide the drag image */
1481 ImageList_DragShowNolock(FALSE);
1483 /* cleanup the InternalDrag struct */
1484 InternalDrag.hwnd = 0;
1485 ImageList_Destroy (InternalDrag.himl);
1486 InternalDrag.himl = 0;
1487 InternalDrag.x= 0;
1488 InternalDrag.y= 0;
1489 InternalDrag.dxHotspot = 0;
1490 InternalDrag.dyHotspot = 0;
1491 InternalDrag.bShow = FALSE;
1492 DeleteObject(InternalDrag.hbmBg);
1493 InternalDrag.hbmBg = 0;
1495 return TRUE;
1499 /*************************************************************************
1500 * ImageList_GetBkColor [COMCTL32.56]
1502 * Returns the background color of an image list.
1504 * PARAMS
1505 * himl [I] Image list handle.
1507 * RETURNS
1508 * Success: background color
1509 * Failure: CLR_NONE
1512 COLORREF WINAPI
1513 ImageList_GetBkColor (HIMAGELIST himl)
1515 if (himl == NULL)
1516 return CLR_NONE;
1518 return himl->clrBk;
1522 /*************************************************************************
1523 * ImageList_GetDragImage [COMCTL32.57]
1525 * Returns the handle to the internal drag image list.
1527 * PARAMS
1528 * ppt [O] Pointer to the drag position. Can be NULL.
1529 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1531 * RETURNS
1532 * Success: Handle of the drag image list.
1533 * Failure: NULL.
1536 HIMAGELIST WINAPI
1537 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1539 if (InternalDrag.himl) {
1540 if (ppt) {
1541 ppt->x = InternalDrag.x;
1542 ppt->y = InternalDrag.y;
1544 if (pptHotspot) {
1545 pptHotspot->x = InternalDrag.dxHotspot;
1546 pptHotspot->y = InternalDrag.dyHotspot;
1548 return (InternalDrag.himl);
1551 return NULL;
1555 /*************************************************************************
1556 * ImageList_GetIcon [COMCTL32.59]
1558 * Creates an icon from a masked image of an image list.
1560 * PARAMS
1561 * himl [I] handle to image list
1562 * i [I] image index
1563 * flags [I] drawing style flags
1565 * RETURNS
1566 * Success: icon handle
1567 * Failure: NULL
1570 HICON WINAPI
1571 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1573 ICONINFO ii;
1574 HICON hIcon;
1575 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1576 HDC hdcSrc, hdcDst;
1578 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1579 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1580 return 0;
1583 hdcSrc = CreateCompatibleDC(0);
1584 hdcDst = CreateCompatibleDC(0);
1586 ii.fIcon = TRUE;
1587 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1589 /* draw mask*/
1590 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1591 if (himl->hbmMask) {
1592 SelectObject (hdcSrc, himl->hbmMask);
1593 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1594 hdcSrc, i * himl->cx, 0, SRCCOPY);
1596 else
1597 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1599 /* draw image*/
1600 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1601 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1602 SelectObject (hdcDst, ii.hbmColor);
1603 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1604 hdcSrc, i * himl->cx, 0, SRCCOPY);
1607 * CreateIconIndirect requires us to deselect the bitmaps from
1608 * the DCs before calling
1610 SelectObject(hdcSrc, hOldSrcBitmap);
1611 SelectObject(hdcDst, hOldDstBitmap);
1613 hIcon = CreateIconIndirect (&ii);
1615 DeleteDC (hdcSrc);
1616 DeleteDC (hdcDst);
1617 DeleteObject (ii.hbmMask);
1618 DeleteObject (ii.hbmColor);
1620 return hIcon;
1624 /*************************************************************************
1625 * ImageList_GetIconSize [COMCTL32.60]
1627 * Retrieves the size of an image in an image list.
1629 * PARAMS
1630 * himl [I] handle to image list
1631 * cx [O] pointer to the image width.
1632 * cy [O] pointer to the image height.
1634 * RETURNS
1635 * Success: TRUE
1636 * Failure: FALSE
1638 * NOTES
1639 * All images in an image list have the same size.
1642 BOOL WINAPI
1643 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1645 if (himl == NULL)
1646 return FALSE;
1647 if ((himl->cx <= 0) || (himl->cy <= 0))
1648 return FALSE;
1650 if (cx)
1651 *cx = himl->cx;
1652 if (cy)
1653 *cy = himl->cy;
1655 return TRUE;
1659 /*************************************************************************
1660 * ImageList_GetImageCount [COMCTL32.61]
1662 * Returns the number of images in an image list.
1664 * PARAMS
1665 * himl [I] handle to image list
1667 * RETURNS
1668 * Success: Number of images.
1669 * Failure: 0
1672 INT WINAPI
1673 ImageList_GetImageCount (HIMAGELIST himl)
1675 if (himl == NULL)
1676 return 0;
1678 return himl->cCurImage;
1682 /*************************************************************************
1683 * ImageList_GetImageInfo [COMCTL32.62]
1685 * Returns information about an image in an image list.
1687 * PARAMS
1688 * himl [I] handle to image list
1689 * i [I] image index
1690 * pImageInfo [O] pointer to the image information
1692 * RETURNS
1693 * Success: TRUE
1694 * Failure: FALSE
1697 BOOL WINAPI
1698 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1700 if ((himl == NULL) || (pImageInfo == NULL))
1701 return FALSE;
1702 if ((i < 0) || (i >= himl->cCurImage))
1703 return FALSE;
1705 pImageInfo->hbmImage = himl->hbmImage;
1706 pImageInfo->hbmMask = himl->hbmMask;
1708 pImageInfo->rcImage.top = 0;
1709 pImageInfo->rcImage.bottom = himl->cy;
1710 pImageInfo->rcImage.left = i * himl->cx;
1711 pImageInfo->rcImage.right = (i+1) * himl->cx;
1713 return TRUE;
1717 /*************************************************************************
1718 * ImageList_GetImageRect [COMCTL32.63]
1720 * Retrieves the rectangle of the specified image in an image list.
1722 * PARAMS
1723 * himl [I] handle to image list
1724 * i [I] image index
1725 * lpRect [O] pointer to the image rectangle
1727 * RETURNS
1728 * Success: TRUE
1729 * Failure: FALSE
1731 * NOTES
1732 * This is an UNDOCUMENTED function!!!
1735 BOOL WINAPI
1736 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1738 if ((himl == NULL) || (lpRect == NULL))
1739 return FALSE;
1740 if ((i < 0) || (i >= himl->cCurImage))
1741 return FALSE;
1743 lpRect->left = i * himl->cx;
1744 lpRect->top = 0;
1745 lpRect->right = lpRect->left + himl->cx;
1746 lpRect->bottom = himl->cy;
1748 return TRUE;
1752 /*************************************************************************
1753 * ImageList_LoadImage [COMCTL32.64]
1754 * ImageList_LoadImageA [COMCTL32.65]
1756 * Creates an image list from a bitmap, icon or cursor.
1758 * PARAMS
1759 * hi [I] instance handle
1760 * lpbmp [I] name or id of the image
1761 * cx [I] width of each image
1762 * cGrow [I] number of images to expand
1763 * clrMask [I] mask color
1764 * uType [I] type of image to load
1765 * uFlags [I] loading flags
1767 * RETURNS
1768 * Success: handle to the loaded image list
1769 * Failure: NULL
1771 * SEE
1772 * LoadImage ()
1775 HIMAGELIST WINAPI
1776 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1777 COLORREF clrMask, UINT uType, UINT uFlags)
1779 HIMAGELIST himl = NULL;
1780 HANDLE handle;
1781 INT nImageCount;
1783 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1784 if (!handle) {
1785 ERR("Error loading image!\n");
1786 return NULL;
1789 if (uType == IMAGE_BITMAP) {
1790 BITMAP bmp;
1791 GetObjectA (handle, sizeof(BITMAP), &bmp);
1793 /* To match windows behavior, if cx is set to zero and
1794 the flag DI_DEFAULTSIZE is specified, cx becomes the
1795 system metric value for icons. If the flag is not specified
1796 the function sets the size to the height of the bitmap */
1797 if (cx == 0)
1799 if (uFlags & DI_DEFAULTSIZE)
1800 cx = GetSystemMetrics (SM_CXICON);
1801 else
1802 cx = bmp.bmHeight;
1805 nImageCount = bmp.bmWidth / cx;
1807 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1808 nImageCount, cGrow);
1809 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1811 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1812 ICONINFO ii;
1813 BITMAP bmp;
1815 GetIconInfo (handle, &ii);
1816 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1817 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1818 ILC_MASK | ILC_COLOR, 1, cGrow);
1819 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1820 DeleteObject (ii.hbmColor);
1821 DeleteObject (ii.hbmMask);
1824 DeleteObject (handle);
1826 return himl;
1830 /*************************************************************************
1831 * ImageList_LoadImageW [COMCTL32.66]
1833 * Creates an image list from a bitmap, icon or cursor.
1835 * PARAMS
1836 * hi [I] instance handle
1837 * lpbmp [I] name or id of the image
1838 * cx [I] width of each image
1839 * cGrow [I] number of images to expand
1840 * clrMask [I] mask color
1841 * uType [I] type of image to load
1842 * uFlags [I] loading flags
1844 * RETURNS
1845 * Success: handle to the loaded image list
1846 * Failure: NULL
1848 * SEE
1849 * LoadImage ()
1852 HIMAGELIST WINAPI
1853 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1854 COLORREF clrMask, UINT uType, UINT uFlags)
1856 HIMAGELIST himl = NULL;
1857 HANDLE handle;
1858 INT nImageCount;
1860 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1861 if (!handle) {
1862 ERR("Error loading image!\n");
1863 return NULL;
1866 if (uType == IMAGE_BITMAP) {
1867 BITMAP bmp;
1868 GetObjectA (handle, sizeof(BITMAP), &bmp);
1869 nImageCount = bmp.bmWidth / cx;
1871 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1872 nImageCount, cGrow);
1873 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1875 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1876 ICONINFO ii;
1877 BITMAP bmp;
1879 GetIconInfo (handle, &ii);
1880 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1881 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1882 ILC_MASK | ILC_COLOR, 1, cGrow);
1883 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1884 DeleteObject (ii.hbmColor);
1885 DeleteObject (ii.hbmMask);
1888 DeleteObject (handle);
1890 return himl;
1894 /*************************************************************************
1895 * ImageList_Merge [COMCTL32.67]
1897 * Creates a new image list that contains a merged image from the specified
1898 * images of both source image lists.
1900 * PARAMS
1901 * himl1 [I] handle to first image list
1902 * i1 [I] first image index
1903 * himl2 [I] handle to second image list
1904 * i2 [I] second image index
1905 * dx [I] X offset of the second image relative to the first.
1906 * dy [I] Y offset of the second image relative to the first.
1908 * RETURNS
1909 * Success: handle of the merged image list.
1910 * Failure: NULL
1913 HIMAGELIST WINAPI
1914 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1915 INT dx, INT dy)
1917 HIMAGELIST himlDst = NULL;
1918 HDC hdcSrcImage, hdcDstImage;
1919 INT cxDst, cyDst;
1920 INT xOff1, yOff1, xOff2, yOff2;
1921 INT nX1, nX2;
1923 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1924 i2, dx, dy);
1926 if ((himl1 == NULL) || (himl2 == NULL))
1927 return NULL;
1929 /* check indices */
1930 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1931 ERR("Index 1 out of range! %d\n", i1);
1932 return NULL;
1935 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1936 ERR("Index 2 out of range! %d\n", i2);
1937 return NULL;
1940 if (dx > 0) {
1941 cxDst = max (himl1->cx, dx + himl2->cx);
1942 xOff1 = 0;
1943 xOff2 = dx;
1945 else if (dx < 0) {
1946 cxDst = max (himl2->cx, himl1->cx - dx);
1947 xOff1 = -dx;
1948 xOff2 = 0;
1950 else {
1951 cxDst = max (himl1->cx, himl2->cx);
1952 xOff1 = 0;
1953 xOff2 = 0;
1956 if (dy > 0) {
1957 cyDst = max (himl1->cy, dy + himl2->cy);
1958 yOff1 = 0;
1959 yOff2 = dy;
1961 else if (dy < 0) {
1962 cyDst = max (himl2->cy, himl1->cy - dy);
1963 yOff1 = -dy;
1964 yOff2 = 0;
1966 else {
1967 cyDst = max (himl1->cy, himl2->cy);
1968 yOff1 = 0;
1969 yOff2 = 0;
1972 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1974 if (himlDst) {
1975 hdcSrcImage = CreateCompatibleDC (0);
1976 hdcDstImage = CreateCompatibleDC (0);
1977 nX1 = i1 * himl1->cx;
1978 nX2 = i2 * himl2->cx;
1980 /* copy image */
1981 SelectObject (hdcSrcImage, himl1->hbmImage);
1982 SelectObject (hdcDstImage, himlDst->hbmImage);
1983 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1984 hdcSrcImage, 0, 0, BLACKNESS);
1985 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1986 hdcSrcImage, nX1, 0, SRCCOPY);
1988 SelectObject (hdcSrcImage, himl2->hbmMask);
1989 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1990 hdcSrcImage, nX2, 0, SRCAND);
1992 SelectObject (hdcSrcImage, himl2->hbmImage);
1993 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1994 hdcSrcImage, nX2, 0, SRCPAINT);
1996 /* copy mask */
1997 SelectObject (hdcSrcImage, himl1->hbmMask);
1998 SelectObject (hdcDstImage, himlDst->hbmMask);
1999 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2000 hdcSrcImage, 0, 0, WHITENESS);
2001 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2002 hdcSrcImage, nX1, 0, SRCCOPY);
2004 SelectObject (hdcSrcImage, himl2->hbmMask);
2005 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2006 hdcSrcImage, nX2, 0, SRCAND);
2008 DeleteDC (hdcSrcImage);
2009 DeleteDC (hdcDstImage);
2010 himlDst->cCurImage = 1;
2013 return himlDst;
2017 /* helper for _read_bitmap currently unused */
2018 #if 0
2019 static int may_use_dibsection(HDC hdc) {
2020 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2021 if (bitspixel>8)
2022 return TRUE;
2023 if (bitspixel<=4)
2024 return FALSE;
2025 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2027 #endif
2029 /* helper for ImageList_Read, see comments below */
2030 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2031 HDC xdc = 0;
2032 BITMAPFILEHEADER bmfh;
2033 BITMAPINFOHEADER bmih;
2034 int bitsperpixel,palspace,longsperline,width,height;
2035 LPBITMAPINFOHEADER bmihc = NULL;
2036 int result = 0;
2037 HBITMAP hbitmap = 0;
2038 LPBYTE bits = NULL,nbits = NULL;
2039 int nbytesperline,bytesperline;
2041 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
2042 (bmfh.bfType != (('M'<<8)|'B')) ||
2043 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
2044 (bmih.biSize != sizeof(bmih))
2046 return 0;
2048 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2049 if (bitsperpixel<=8)
2050 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2051 else
2052 palspace = 0;
2053 width = bmih.biWidth;
2054 height = bmih.biHeight;
2055 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2056 memcpy(bmihc,&bmih,sizeof(bmih));
2057 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
2058 bmihc->biSizeImage = (longsperline*height)<<2;
2060 /* read the palette right after the end of the bitmapinfoheader */
2061 if (palspace)
2062 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2063 goto ret1;
2065 xdc = GetDC(0);
2066 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2067 if ((bitsperpixel>1) &&
2068 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2070 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2071 if (!hbitmap)
2072 goto ret1;
2073 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2074 goto ret1;
2075 result = 1;
2076 } else
2077 #endif
2079 int i,nwidth,nheight;
2081 nwidth = width*(height/cy);
2082 nheight = cy;
2084 if (bitsperpixel==1)
2085 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2086 else
2087 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2089 /* Might be a bit excessive memory use here */
2090 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2091 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2092 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2093 goto ret1;
2095 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2096 /* Do not forget that windows bitmaps are bottom->top */
2097 bytesperline = longsperline*4;
2098 nbytesperline = (height/cy)*bytesperline;
2099 for (i=0;i<height;i++) {
2100 memcpy(
2101 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2102 bits+bytesperline*(height-1-i),
2103 bytesperline
2106 bmihc->biWidth = nwidth;
2107 bmihc->biHeight = nheight;
2108 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2109 goto ret1;
2110 LocalFree((HLOCAL)nbits);
2111 LocalFree((HLOCAL)bits);
2112 result = 1;
2114 ret1:
2115 if (xdc) ReleaseDC(0,xdc);
2116 if (bmihc) LocalFree((HLOCAL)bmihc);
2117 if (!result) {
2118 if (hbitmap) {
2119 DeleteObject(hbitmap);
2120 hbitmap = 0;
2123 return hbitmap;
2126 /*************************************************************************
2127 * ImageList_Read [COMCTL32.68]
2129 * Reads an image list from a stream.
2131 * PARAMS
2132 * pstm [I] pointer to a stream
2134 * RETURNS
2135 * Success: handle to image list
2136 * Failure: NULL
2138 * The format is like this:
2139 * ILHEAD ilheadstruct;
2141 * for the color image part:
2142 * BITMAPFILEHEADER bmfh;
2143 * BITMAPINFOHEADER bmih;
2144 * only if it has a palette:
2145 * RGBQUAD rgbs[nr_of_paletted_colors];
2147 * BYTE colorbits[imagesize];
2149 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2150 * BITMAPFILEHEADER bmfh_mask;
2151 * BITMAPINFOHEADER bmih_mask;
2152 * only if it has a palette (it usually does not):
2153 * RGBQUAD rgbs[nr_of_paletted_colors];
2155 * BYTE maskbits[imagesize];
2157 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2158 * _read_bitmap needs to convert them.
2160 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2162 ILHEAD ilHead;
2163 HIMAGELIST himl;
2164 HBITMAP hbmColor=0,hbmMask=0;
2165 int i;
2167 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2168 return NULL;
2169 if (ilHead.usMagic != (('L' << 8) | 'I'))
2170 return NULL;
2171 if (ilHead.usVersion != 0x101) /* probably version? */
2172 return NULL;
2174 #if 0
2175 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2176 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2177 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2178 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2179 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2180 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2181 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2182 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2183 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2184 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2185 #endif
2187 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2188 if (!hbmColor)
2189 return NULL;
2190 if (ilHead.flags & ILC_MASK) {
2191 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2192 if (!hbmMask) {
2193 DeleteObject(hbmColor);
2194 return NULL;
2198 himl = ImageList_Create (
2199 ilHead.cx,
2200 ilHead.cy,
2201 ilHead.flags,
2202 1, /* initial */
2203 ilHead.cGrow
2205 if (!himl) {
2206 DeleteObject(hbmColor);
2207 DeleteObject(hbmMask);
2208 return NULL;
2210 himl->hbmImage = hbmColor;
2211 himl->hbmMask = hbmMask;
2212 himl->cCurImage = ilHead.cCurImage;
2213 himl->cMaxImage = ilHead.cMaxImage;
2215 ImageList_SetBkColor(himl,ilHead.bkcolor);
2216 for (i=0;i<4;i++)
2217 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2218 return himl;
2222 /*************************************************************************
2223 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2225 * PARAMS
2226 * himl [I] image list handle
2227 * i [I] image index
2229 * RETURNS
2230 * Success: TRUE
2231 * Failure: FALSE
2234 BOOL WINAPI
2235 ImageList_Remove (HIMAGELIST himl, INT i)
2237 HBITMAP hbmNewImage, hbmNewMask;
2238 HDC hdcSrc, hdcDst;
2239 INT cxNew, nCount;
2241 if (himl == NULL) {
2242 ERR("Invalid image list handle!\n");
2243 return FALSE;
2246 if ((i < -1) || (i >= himl->cCurImage)) {
2247 ERR("index out of range! %d\n", i);
2248 return FALSE;
2251 if (himl->cCurImage == 0) {
2252 ERR("image list is already empty!\n");
2253 return FALSE;
2256 if (i == -1) {
2257 /* remove all */
2258 TRACE("remove all!\n");
2260 himl->cMaxImage = himl->cInitial + himl->cGrow;
2261 himl->cCurImage = 0;
2262 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2263 himl->nOvlIdx[nCount] = -1;
2265 DeleteObject (himl->hbmImage);
2266 himl->hbmImage =
2267 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2268 1, himl->uBitsPixel, NULL);
2270 if (himl->hbmMask) {
2271 DeleteObject (himl->hbmMask);
2272 himl->hbmMask =
2273 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2274 1, 1, NULL);
2277 else {
2278 /* delete one image */
2279 TRACE("Remove single image! %d\n", i);
2281 /* create new bitmap(s) */
2282 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2284 TRACE(" - Number of images: %d / %d (Old/New)\n",
2285 himl->cCurImage, himl->cCurImage - 1);
2286 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2287 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2289 hbmNewImage =
2290 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2292 if (himl->hbmMask)
2293 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2294 else
2295 hbmNewMask = 0; /* Just to keep compiler happy! */
2297 hdcSrc = CreateCompatibleDC (0);
2298 hdcDst = CreateCompatibleDC (0);
2300 /* copy all images and masks prior to the "removed" image */
2301 if (i > 0) {
2302 TRACE("Pre image copy: Copy %d images\n", i);
2304 SelectObject (hdcSrc, himl->hbmImage);
2305 SelectObject (hdcDst, hbmNewImage);
2306 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2307 hdcSrc, 0, 0, SRCCOPY);
2309 if (himl->hbmMask) {
2310 SelectObject (hdcSrc, himl->hbmMask);
2311 SelectObject (hdcDst, hbmNewMask);
2312 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2313 hdcSrc, 0, 0, SRCCOPY);
2317 /* copy all images and masks behind the removed image */
2318 if (i < himl->cCurImage - 1) {
2319 TRACE("Post image copy!\n");
2320 SelectObject (hdcSrc, himl->hbmImage);
2321 SelectObject (hdcDst, hbmNewImage);
2322 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2323 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2325 if (himl->hbmMask) {
2326 SelectObject (hdcSrc, himl->hbmMask);
2327 SelectObject (hdcDst, hbmNewMask);
2328 BitBlt (hdcDst, i * himl->cx, 0,
2329 (himl->cCurImage - i - 1) * himl->cx,
2330 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2334 DeleteDC (hdcSrc);
2335 DeleteDC (hdcDst);
2337 /* delete old images and insert new ones */
2338 DeleteObject (himl->hbmImage);
2339 himl->hbmImage = hbmNewImage;
2340 if (himl->hbmMask) {
2341 DeleteObject (himl->hbmMask);
2342 himl->hbmMask = hbmNewMask;
2345 himl->cCurImage--;
2346 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2349 return TRUE;
2353 /*************************************************************************
2354 * ImageList_Replace [COMCTL32.70]
2356 * Replaces an image in an image list with a new image.
2358 * PARAMS
2359 * himl [I] handle to image list
2360 * i [I] image index
2361 * hbmImage [I] handle to image bitmap
2362 * hbmMask [I] handle to mask bitmap. Can be NULL.
2364 * RETURNS
2365 * Success: TRUE
2366 * Failure: FALSE
2369 BOOL WINAPI
2370 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2371 HBITMAP hbmMask)
2373 HDC hdcImageList, hdcImage;
2374 BITMAP bmp;
2376 if (himl == NULL) {
2377 ERR("Invalid image list handle!\n");
2378 return FALSE;
2381 if ((i >= himl->cMaxImage) || (i < 0)) {
2382 ERR("Invalid image index!\n");
2383 return FALSE;
2386 hdcImageList = CreateCompatibleDC (0);
2387 hdcImage = CreateCompatibleDC (0);
2388 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2390 /* Replace Image */
2391 SelectObject (hdcImageList, himl->hbmImage);
2392 SelectObject (hdcImage, hbmImage);
2394 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2395 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2397 if (himl->hbmMask)
2399 /* Replace Mask */
2400 SelectObject (hdcImageList, himl->hbmMask);
2401 SelectObject (hdcImage, hbmMask);
2403 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2404 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2407 /* Remove the background from the image
2409 SelectObject (hdcImageList, himl->hbmImage);
2410 StretchBlt (hdcImageList,
2411 i*himl->cx, 0, himl->cx, himl->cy,
2412 hdcImage,
2413 0, 0, bmp.bmWidth, bmp.bmHeight,
2414 0x220326); /* NOTSRCAND */
2417 DeleteDC (hdcImage);
2418 DeleteDC (hdcImageList);
2420 return TRUE;
2424 /*************************************************************************
2425 * ImageList_ReplaceIcon [COMCTL32.75]
2427 * Replaces an image in an image list using an icon.
2429 * PARAMS
2430 * himl [I] handle to image list
2431 * i [I] image index
2432 * hIcon [I] handle to icon
2434 * RETURNS
2435 * Success: index of the replaced image
2436 * Failure: -1
2439 INT WINAPI
2440 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2442 HDC hdcImageList, hdcImage;
2443 INT nIndex;
2444 HICON hBestFitIcon;
2445 HBITMAP hbmOldSrc, hbmOldDst;
2446 ICONINFO ii;
2447 BITMAP bmp;
2449 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2451 if (himl == NULL)
2452 return -1;
2453 if ((i >= himl->cMaxImage) || (i < -1))
2454 return -1;
2456 hBestFitIcon = CopyImage(
2457 hIcon, IMAGE_ICON,
2458 himl->cx, himl->cy,
2459 LR_COPYFROMRESOURCE);
2461 GetIconInfo (hBestFitIcon, &ii);
2462 if (ii.hbmMask == 0)
2463 ERR("no mask!\n");
2464 if (ii.hbmColor == 0)
2465 ERR("no color!\n");
2466 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2468 if (i == -1) {
2469 if (himl->cCurImage + 1 > himl->cMaxImage)
2470 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2472 nIndex = himl->cCurImage;
2473 himl->cCurImage++;
2475 else
2476 nIndex = i;
2478 hdcImageList = CreateCompatibleDC (0);
2479 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2480 if (hdcImageList == 0)
2481 ERR("invalid hdcImageList!\n");
2483 hdcImage = CreateCompatibleDC (0);
2484 TRACE("hdcImage=0x%x!\n", hdcImage);
2485 if (hdcImage == 0)
2486 ERR("invalid hdcImage!\n");
2488 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2489 SetTextColor( hdcImageList, RGB(0,0,0));
2490 SetBkColor( hdcImageList, RGB(255,255,255));
2491 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2492 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2493 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2495 if (himl->hbmMask) {
2496 SelectObject (hdcImageList, himl->hbmMask);
2497 SelectObject (hdcImage, ii.hbmMask);
2498 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2499 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2502 SelectObject (hdcImage, hbmOldSrc);
2503 SelectObject (hdcImageList, hbmOldDst);
2505 if(hBestFitIcon)
2506 DestroyIcon(hBestFitIcon);
2507 if (hdcImageList)
2508 DeleteDC (hdcImageList);
2509 if (hdcImage)
2510 DeleteDC (hdcImage);
2511 if (ii.hbmColor)
2512 DeleteObject (ii.hbmColor);
2513 if (ii.hbmMask)
2514 DeleteObject (ii.hbmMask);
2516 return nIndex;
2520 /*************************************************************************
2521 * ImageList_SetBkColor [COMCTL32.76]
2523 * Sets the background color of an image list.
2525 * PARAMS
2526 * himl [I] handle to image list
2527 * clrBk [I] background color
2529 * RETURNS
2530 * Success: previous background color
2531 * Failure: CLR_NONE
2534 COLORREF WINAPI
2535 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2537 COLORREF clrOldBk;
2539 if (himl == NULL)
2540 return CLR_NONE;
2542 clrOldBk = himl->clrBk;
2543 himl->clrBk = clrBk;
2544 return clrOldBk;
2548 /*************************************************************************
2549 * ImageList_SetDragCursorImage [COMCTL32.77]
2551 * Combines the specified image with the current drag image
2553 * PARAMS
2554 * himlDrag [I] handle to drag image list
2555 * iDrag [I] drag image index
2556 * dxHotspot [I] X position of the hot spot
2557 * dyHotspot [I] Y position of the hot spot
2559 * RETURNS
2560 * Success: TRUE
2561 * Failure: FALSE
2563 * NOTES
2564 * When this function is called and the drag image is visible, a
2565 * short flickering occurs but this matches the Win9x behavior. It is
2566 * possible to fix the flickering using code like in ImageList_DragMove.
2569 BOOL WINAPI
2570 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2571 INT dxHotspot, INT dyHotspot)
2573 HIMAGELIST himlTemp;
2574 INT dx, dy;
2575 BOOL visible;
2577 if (InternalDrag.himl == NULL)
2578 return FALSE;
2580 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2581 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2583 visible = InternalDrag.bShow;
2585 /* Calculate the offset between the origin of the old image and the
2586 * origin of the second image.
2587 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2588 * hotspot) to the origin of the second image.
2589 * See M$DN for details */
2590 dx = InternalDrag.dxHotspot - dxHotspot;
2591 dy = InternalDrag.dyHotspot - dyHotspot;
2592 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2594 if (visible) {
2595 /* hide the drag image */
2596 ImageList_DragShowNolock(FALSE);
2598 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2599 (InternalDrag.himl->cy != himlTemp->cy)) {
2600 /* the size of the drag image changed, invalidate the buffer */
2601 DeleteObject(InternalDrag.hbmBg);
2602 InternalDrag.hbmBg = 0;
2605 ImageList_Destroy (InternalDrag.himl);
2606 InternalDrag.himl = himlTemp;
2608 /* update the InternalDragOffset, if the origin of the
2609 * DragImage was changed by ImageList_Merge. */
2610 if (dx > InternalDrag.dxHotspot) {
2611 InternalDrag.dxHotspot = dx;
2613 if (dy > InternalDrag.dyHotspot) {
2614 InternalDrag.dyHotspot = dy;
2617 if (visible) {
2618 /* show the drag image */
2619 ImageList_DragShowNolock(TRUE);
2622 return TRUE;
2626 /*************************************************************************
2627 * ImageList_SetFilter [COMCTL32.78]
2629 * Sets a filter (or does something completely different)!!???
2631 * PARAMS
2632 * himl [I] handle to image list
2633 * i [I] ???
2634 * dwFilter [I] ???
2636 * RETURNS
2637 * Success: TRUE ???
2638 * Failure: FALSE ???
2640 * BUGS
2641 * This is an UNDOCUMENTED function!!!!
2642 * empty stub.
2645 BOOL WINAPI
2646 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2648 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2649 himl, i, dwFilter);
2651 return FALSE;
2655 /*************************************************************************
2656 * ImageList_SetIconSize [COMCTL32.80]
2658 * Sets the image size of the bitmap and deletes all images.
2660 * PARAMS
2661 * himl [I] handle to image list
2662 * cx [I] image width
2663 * cy [I] image height
2665 * RETURNS
2666 * Success: TRUE
2667 * Failure: FALSE
2670 BOOL WINAPI
2671 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2673 INT nCount;
2675 if (!himl)
2676 return FALSE;
2678 /* remove all images */
2679 himl->cMaxImage = himl->cInitial + himl->cGrow;
2680 himl->cCurImage = 0;
2681 himl->cx = cx;
2682 himl->cy = cy;
2684 /* initialize overlay mask indices */
2685 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2686 himl->nOvlIdx[nCount] = -1;
2688 DeleteObject (himl->hbmImage);
2689 himl->hbmImage =
2690 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2691 1, himl->uBitsPixel, NULL);
2693 if (himl->hbmMask) {
2694 DeleteObject (himl->hbmMask);
2695 himl->hbmMask =
2696 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2697 1, 1, NULL);
2700 return TRUE;
2704 /*************************************************************************
2705 * ImageList_SetImageCount [COMCTL32.81]
2707 * Resizes an image list to the specified number of images.
2709 * PARAMS
2710 * himl [I] handle to image list
2711 * iImageCount [I] number of images in the image list
2713 * RETURNS
2714 * Success: TRUE
2715 * Failure: FALSE
2718 BOOL WINAPI
2719 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2721 HDC hdcImageList, hdcBitmap;
2722 HBITMAP hbmNewBitmap;
2723 INT nNewCount, nCopyCount;
2725 if (!himl)
2726 return FALSE;
2727 if (himl->cCurImage >= iImageCount)
2728 return FALSE;
2729 if (himl->cMaxImage > iImageCount)
2730 return TRUE;
2732 nNewCount = iImageCount + himl->cGrow;
2733 nCopyCount = min(himl->cCurImage, iImageCount);
2735 hdcImageList = CreateCompatibleDC (0);
2736 hdcBitmap = CreateCompatibleDC (0);
2738 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2739 1, himl->uBitsPixel, NULL);
2740 if (hbmNewBitmap != 0)
2742 SelectObject (hdcImageList, himl->hbmImage);
2743 SelectObject (hdcBitmap, hbmNewBitmap);
2745 /* copy images */
2746 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2747 hdcImageList, 0, 0, SRCCOPY);
2748 #if 0
2749 /* delete 'empty' image space */
2750 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2751 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2752 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2753 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2754 #endif
2755 DeleteObject (himl->hbmImage);
2756 himl->hbmImage = hbmNewBitmap;
2758 else
2759 ERR("Could not create new image bitmap !\n");
2761 if (himl->hbmMask)
2763 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2764 1, 1, NULL);
2765 if (hbmNewBitmap != 0)
2767 SelectObject (hdcImageList, himl->hbmMask);
2768 SelectObject (hdcBitmap, hbmNewBitmap);
2770 /* copy images */
2771 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2772 hdcImageList, 0, 0, SRCCOPY);
2773 #if 0
2774 /* delete 'empty' image space */
2775 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2776 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2777 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2778 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2779 #endif
2780 DeleteObject (himl->hbmMask);
2781 himl->hbmMask = hbmNewBitmap;
2783 else
2784 ERR("Could not create new mask bitmap!\n");
2787 DeleteDC (hdcImageList);
2788 DeleteDC (hdcBitmap);
2790 /* Update max image count and current image count */
2791 himl->cMaxImage = nNewCount;
2792 if (himl->cCurImage > nCopyCount)
2793 himl->cCurImage = nCopyCount;
2795 return TRUE;
2799 /*************************************************************************
2800 * ImageList_SetOverlayImage [COMCTL32.82]
2802 * Assigns an overlay mask index to an existing image in an image list.
2804 * PARAMS
2805 * himl [I] handle to image list
2806 * iImage [I] image index
2807 * iOverlay [I] overlay mask index
2809 * RETURNS
2810 * Success: TRUE
2811 * Failure: FALSE
2814 BOOL WINAPI
2815 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2817 if (!himl)
2818 return FALSE;
2819 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2820 return FALSE;
2821 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2822 return FALSE;
2823 himl->nOvlIdx[iOverlay - 1] = iImage;
2824 return TRUE;
2828 /*************************************************************************
2829 * ImageList_Write [COMCTL32.83]
2831 * Writes an image list to a stream.
2833 * PARAMS
2834 * himl [I] handle to image list
2835 * pstm [O] Pointer to a stream.
2837 * RETURNS
2838 * Success: TRUE
2839 * Failure: FALSE
2841 * NOTES
2842 * This function can not be implemented yet, because
2843 * IStream32::Write is not implemented.
2845 * BUGS
2846 * empty stub.
2849 BOOL WINAPI
2850 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2852 if (!himl)
2853 return FALSE;
2855 FIXME("empty stub!\n");
2857 return FALSE;