- first 'dummy' implementation of ImageList_Read
[wine] / dlls / comctl32 / imagelist.c
1 /*
2  *  ImageList implementation
3  *
4  *  Copyright 1998 Eric Kohl
5  *
6  *  TODO:
7  *    - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
8  *    - Fix ImageList_GetIcon.
9  *    - Fix drag functions.
10  *    - Fix ImageList_Read and ImageList_Write.
11  *    - Fix ImageList_SetFilter (undocumented).
12  *      BTW does anybody know anything about this function???
13  *        - It removes 12 Bytes from the stack (3 Parameters).
14  *        - First parameter SHOULD be a HIMAGELIST.
15  *        - Second parameter COULD be an index?????
16  *        - Third parameter.... ?????????????????????
17  *
18  *  Comments:
19  *    - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
20  *      ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
21  *      partially imlemented, the functions mentioned above will be 
22  *      limited in functionality too.
23  */
24
25 /* This must be defined because the HIMAGELIST type is just a pointer
26  * to the _IMAGELIST data structure. But M$ does not want us to know
27  * anything about its contents. Applications just see a pointer to
28  * an empty structure. It's just to keep compatibility.
29  */
30 #define __WINE_IMAGELIST_C
31
32  
33 #include "wine/obj_base.h"
34 #include "wine/obj_storage.h"
35 #include "imagelist.h"
36 #include "commctrl.h"
37 #include "debugtools.h"
38 #include "winerror.h"
39
40 DEFAULT_DEBUG_CHANNEL(imagelist)
41
42
43 #define _MAX(a,b) (((a)>(b))?(a):(b))
44 #define _MIN(a,b) (((a)>(b))?(b):(a))
45
46 #define MAX_OVERLAYIMAGE 15
47
48
49 /* internal image list data used for Drag & Drop operations */
50
51 static HIMAGELIST himlInternalDrag = NULL;
52 static INT      nInternalDragHotspotX = 0;
53 static INT      nInternalDragHotspotY = 0;
54
55 static HWND     hwndInternalDrag = 0;
56 static INT      xInternalPos = 0;
57 static INT      yInternalPos = 0;
58
59 static HDC      hdcBackBuffer = 0;
60 static HBITMAP  hbmBackBuffer = 0;
61
62
63 /*************************************************************************
64  * IMAGELIST_InternalExpandBitmaps [Internal] 
65  *
66  * Expands the bitmaps of an image list by the given number of images.
67  *
68  * PARAMS
69  *     himl        [I] handle to image list
70  *     nImageCount [I] number of images to add
71  *
72  * RETURNS
73  *     nothing
74  *
75  * NOTES
76  *     This function can NOT be used to reduce the number of images.
77  */
78 static VOID
79 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount)
80 {
81     HDC     hdcImageList, hdcBitmap;
82     HBITMAP hbmNewBitmap;
83     INT     nNewWidth, nNewCount;
84
85     TRACE("Create expanded bitmaps!\n");
86
87     nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
88     nNewWidth = nNewCount * himl->cx;
89
90     hdcImageList = CreateCompatibleDC (0);
91     hdcBitmap = CreateCompatibleDC (0);
92
93     hbmNewBitmap =
94         CreateBitmap (nNewWidth, himl->cy, 1, himl->uBitsPixel, NULL);
95     if (hbmNewBitmap == 0)
96         ERR("creating new image bitmap!\n");
97
98     SelectObject (hdcImageList, himl->hbmImage);
99     SelectObject (hdcBitmap, hbmNewBitmap);
100     BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, himl->cy,
101               hdcImageList, 0, 0, SRCCOPY);
102
103     DeleteObject (himl->hbmImage);
104     himl->hbmImage = hbmNewBitmap;
105
106     if (himl->hbmMask) {
107         hbmNewBitmap = 
108             CreateBitmap (nNewWidth, himl->cy, 1, 1, NULL);
109
110         if (hbmNewBitmap == 0)
111             ERR("creating new mask bitmap!");
112
113         SelectObject (hdcImageList, himl->hbmMask);
114         SelectObject (hdcBitmap, hbmNewBitmap);
115         BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, himl->cy,
116                   hdcImageList, 0, 0, SRCCOPY);
117         DeleteObject (himl->hbmMask);
118         himl->hbmMask = hbmNewBitmap;
119     }
120
121     himl->cMaxImage = nNewCount;
122
123     DeleteDC (hdcImageList);
124     DeleteDC (hdcBitmap);
125 }
126
127
128 /*************************************************************************
129  * IMAGELIST_InternalDraw [Internal] 
130  *
131  * Draws the image in the ImageList (without the mask)
132  *
133  * PARAMS
134  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
135  *     cx            [I] the width of the image to display
136  *     cy............[I] the height of the image to display
137  *
138  * RETURNS
139  *     nothing
140  *
141  * NOTES
142  *     This functions is used by ImageList_DrawIndirect, when it is 
143  *     required to draw only the Image (without the mask) to the screen.
144  *
145  *     Blending and Overlays styles are accomplised by another function
146  */
147 static VOID
148 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
149 {
150     HDC hImageDC;
151     HBITMAP hOldBitmap;
152     hImageDC = CreateCompatibleDC(0);
153     hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
154     BitBlt(pimldp->hdcDst, 
155         pimldp->x, pimldp->y, cx, cy,
156         hImageDC, 
157         pimldp->himl->cx * pimldp->i, 0, 
158         SRCCOPY);
159
160     SelectObject(hImageDC, hOldBitmap);
161     DeleteDC(hImageDC);
162 }
163
164
165 /*************************************************************************
166  * IMAGELIST_InternalDrawMask [Internal] 
167  *
168  * Draws the image in the ImageList witht the mask
169  *
170  * PARAMS
171  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
172  *     cx            [I] the width of the image to display
173  *     cy............[I] the height of the image to display
174  *
175  * RETURNS
176  *     nothing
177  *
178  * NOTES
179  *     This functions is used by ImageList_DrawIndirect, when it is 
180  *     required to draw the Image with the mask to the screen.
181  *
182  *     Blending and Overlays styles are accomplised by another function.
183  */
184 static VOID
185 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
186 {
187     HDC     hMaskDC, hImageDC;
188     BOOL bUseCustomBackground, bBlendFlag;
189     HBRUSH hBrush, hOldBrush;
190     HBITMAP hOldBitmapImage, hOldBitmapMask;
191     HIMAGELIST himlLocal = pimldp->himl;
192     COLORREF oldBkColor, oldFgColor;
193
194     bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
195     bBlendFlag = (pimldp->fStyle & ILD_BLEND50 ) 
196         || (pimldp->fStyle & ILD_BLEND25);
197
198     hImageDC = CreateCompatibleDC(0);
199     hMaskDC = CreateCompatibleDC(0);
200
201     hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
202     hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
203     /* Draw the Background for the appropriate Styles
204     */
205     if( bUseCustomBackground && (pimldp->fStyle == ILD_NORMAL 
206           || pimldp->fStyle & ILD_IMAGE 
207           || bBlendFlag))
208     {
209         hBrush = CreateSolidBrush (himlLocal->clrBk);
210         hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
211         PatBlt (pimldp->hdcDst, 
212             pimldp->x, pimldp->y, cx, cy, 
213             PATCOPY);
214
215         DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
216     }
217
218     /* Draw Image Transparently over the current background
219     */
220     if(pimldp->fStyle == ILD_NORMAL
221         || pimldp->fStyle & ILD_TRANSPARENT
222         || ((pimldp->fStyle & ILD_IMAGE) && bUseCustomBackground)
223         || bBlendFlag)
224     {
225         /* to obtain a transparent look, background color should be set
226            to white and foreground color to black when blting the 
227            monochrome mask. */
228         oldBkColor = SetBkColor(pimldp->hdcDst, RGB(0xff, 0xff, 0xff)); 
229         oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 0));
230
231         BitBlt(pimldp->hdcDst, 
232             pimldp->x, pimldp->y, cx, cy,
233             hMaskDC, 
234             himlLocal->cx * pimldp->i, 0, 
235             SRCAND);
236
237         BitBlt(pimldp->hdcDst, 
238             pimldp->x, pimldp->y, cx, cy,
239             hImageDC, 
240             himlLocal->cx * pimldp->i, 0, 
241             SRCPAINT);
242
243         SetBkColor(pimldp->hdcDst, oldBkColor); 
244         SetTextColor(pimldp->hdcDst, oldFgColor);
245     }
246     /* Draw the image when no Background is specified
247     */
248     else if(pimldp->fStyle & ILD_IMAGE && !bUseCustomBackground)
249     {
250         BitBlt(pimldp->hdcDst, 
251             pimldp->x, pimldp->y, cx, cy,
252             hImageDC, 
253             himlLocal->cx * pimldp->i, 0, 
254             SRCCOPY);
255     }
256     /* Draw the mask with or without a background
257     */
258     else if(pimldp->fStyle & ILD_MASK)
259     {
260         BitBlt(pimldp->hdcDst, 
261             pimldp->x, pimldp->y, cx, cy,
262             hMaskDC, 
263             himlLocal->cx * pimldp->i, 0,
264             bUseCustomBackground ? SRCCOPY : SRCAND);
265     }
266     SelectObject(hImageDC, hOldBitmapImage);
267     SelectObject(hMaskDC, hOldBitmapMask);
268     DeleteDC(hImageDC);
269     DeleteDC(hMaskDC);
270 }
271
272 /*************************************************************************
273  * IMAGELIST_InternalDrawBlend [Internal] 
274  *
275  * Draws the Blend over the current image 
276  *
277  * PARAMS
278  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
279  *     cx            [I] the width of the image to display
280  *     cy............[I] the height of the image to display
281  *
282  * RETURNS
283  *     nothing
284  *
285  * NOTES
286  *     This functions is used by ImageList_DrawIndirect, when it is 
287  *     required to add the blend to the current image.  
288  *     
289  */
290 static VOID
291 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
292 {
293
294     HDC         hBlendMaskDC,hMaskDC;
295     HBRUSH      hBlendColorBrush, hBlendBrush, hOldBrush;
296     HBITMAP     hBlendMaskBitmap, hOldBitmap;
297     COLORREF    clrBlend, OldTextColor, OldBkColor;
298     HIMAGELIST  himlLocal = pimldp->himl;
299
300     clrBlend = GetSysColor (COLOR_HIGHLIGHT);
301     if (!(pimldp->rgbFg == CLR_DEFAULT))
302     {
303         clrBlend = pimldp->rgbFg;
304     }
305     /* Create the blend Mask
306     */
307     hBlendMaskDC = CreateCompatibleDC(0);
308     hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
309         himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
310
311     hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
312     hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
313
314     hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
315     PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
316     SelectObject(hBlendMaskDC, hOldBrush);
317
318     /* Modify the blend mask if an Image Mask exist
319     */
320     if(pimldp->himl->hbmMask != 0)
321     {
322         HBITMAP hOldMaskBitmap;
323         hMaskDC = CreateCompatibleDC(0);
324         hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
325
326         BitBlt(hBlendMaskDC,
327             0,0, cx, cy, 
328             hMaskDC,
329             himlLocal->cx * pimldp->i,0,
330             0x220326); /* NOTSRCAND */
331
332         BitBlt(hBlendMaskDC,
333             0,0, cx, cy, 
334             hBlendMaskDC,
335             0,0, 
336             NOTSRCCOPY);
337
338         SelectObject(hMaskDC, hOldMaskBitmap);
339         DeleteDC(hMaskDC);
340
341     }
342     /* Apply blend to the current image given the BlendMask
343     */
344     OldTextColor = SetTextColor(pimldp->hdcDst, 0);
345     OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
346     hBlendColorBrush = CreateSolidBrush(clrBlend);
347     hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
348
349     BitBlt (pimldp->hdcDst, 
350         pimldp->x, pimldp->y, cx, cy, 
351         hBlendMaskDC, 
352         0, 0, 
353         0xB8074A); /* PSDPxax */
354
355     SelectObject(pimldp->hdcDst, hOldBrush);
356     SetTextColor(pimldp->hdcDst, OldTextColor);
357     SetBkColor(pimldp->hdcDst, OldBkColor);
358     SelectObject(hBlendMaskDC, hOldBitmap);
359     DeleteDC(hBlendMaskDC);
360     DeleteObject(hBlendMaskBitmap);
361     DeleteObject(hBlendColorBrush);
362 }
363
364 /*************************************************************************
365  * IMAGELIST_InternalDrawOverlay [Internal] 
366  *
367  * Draws the overlay image 
368  *
369  * PARAMS
370  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
371  *     cx            [I] the width of the image to display
372  *     cy............[I] the height of the image to display
373  *
374  * RETURNS
375  *     nothing
376  *
377  * NOTES
378  *     This functions is used by ImageList_DrawIndirect, when it is 
379  *     required to draw the overlay
380  *
381  *     
382  */
383 static VOID 
384 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
385 {
386     INT     nOvlIdx;
387     HDC     hImageDC;
388     HBITMAP hOldBitmap;
389
390     nOvlIdx = (pimldp->fStyle & 0x0700) >> 8;
391     if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
392     {
393         nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
394         if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
395         {
396             hImageDC = CreateCompatibleDC(0);
397             if (pimldp->himl->hbmMask)
398             {
399                 hOldBitmap = (HBITMAP) SelectObject (hImageDC, 
400                     pimldp->himl->hbmMask);
401
402                 BitBlt (pimldp->hdcDst, 
403                     pimldp->x, pimldp->y, cx, cy,
404                     hImageDC, pimldp->himl->cx * nOvlIdx, 0,
405                     SRCAND);
406
407                 SelectObject(hImageDC, hOldBitmap);
408             }
409             hOldBitmap = (HBITMAP) SelectObject (hImageDC, 
410                 pimldp->himl->hbmImage);
411
412             BitBlt (pimldp->hdcDst, 
413                 pimldp->x, pimldp->y, cx, cy, 
414                 hImageDC,
415                 pimldp->himl->cx * nOvlIdx, 0,
416                 SRCPAINT);
417
418             SelectObject(hImageDC, hOldBitmap);
419             DeleteDC(hImageDC);
420         }
421     }
422 }
423
424
425
426
427
428 /*************************************************************************
429  * ImageList_Add [COMCTL32.39]
430  *
431  * Add an image or images to an image list.
432  *
433  * PARAMS
434  *     himl     [I] handle to image list
435  *     hbmImage [I] handle to image bitmap
436  *     hbmMask  [I] handle to mask bitmap
437  *
438  * RETURNS
439  *     Success: Index of the first new image.
440  *     Failure: -1
441  */
442
443 INT WINAPI
444 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
445 {
446     HDC     hdcImage, hdcBitmap;
447     INT     nFirstIndex, nImageCount;
448     INT     nStartX;
449     BITMAP  bmp;
450     HBITMAP hOldBitmapImage, hOldBitmap;
451
452     if (!himl || !hbmImage)
453         return -1;
454
455     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
456     nImageCount = bmp.bmWidth / himl->cx;
457
458     if (himl->cCurImage + nImageCount >= himl->cMaxImage)
459         IMAGELIST_InternalExpandBitmaps (himl, nImageCount);
460
461     nStartX = himl->cCurImage * himl->cx;
462
463     hdcImage  = CreateCompatibleDC(0);
464     hdcBitmap = CreateCompatibleDC(0);
465
466     hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
467     hOldBitmap = SelectObject(hdcBitmap, hbmImage);
468
469     /* Copy result to the imagelist
470     */
471     BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, himl->cy,
472         hdcBitmap, 0, 0, SRCCOPY);
473
474     if(himl->hbmMask)
475     {
476         HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
477
478         hdcMask   = CreateCompatibleDC (0);
479         hdcTemp   = CreateCompatibleDC(0);
480         hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
481         hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
482
483         BitBlt (hdcMask, 
484             nStartX, 0, bmp.bmWidth, himl->cy,
485             hdcTemp, 
486             0, 0, 
487             SRCCOPY);
488
489         SelectObject(hdcTemp, hOldBitmapTemp);
490         DeleteDC(hdcTemp);
491
492         /* Remove the background from the image
493         */
494         BitBlt (hdcImage, 
495             nStartX, 0, bmp.bmWidth, himl->cy,
496             hdcMask, 
497             nStartX, 0, 
498             0x220326); /* NOTSRCAND */
499
500         SelectObject(hdcMask, hOldBitmapMask);
501         DeleteDC(hdcMask);
502     }
503
504     SelectObject(hdcImage, hOldBitmapImage);
505     SelectObject(hdcBitmap, hOldBitmap);
506     DeleteDC(hdcImage);
507     DeleteDC(hdcBitmap);
508
509     nFirstIndex = himl->cCurImage;
510     himl->cCurImage += nImageCount;
511
512     return nFirstIndex;
513 }
514
515
516 /*************************************************************************
517  * ImageList_AddIcon [COMCTL32.40]
518  *
519  * Adds an icon to an image list.
520  *
521  * PARAMS
522  *     himl  [I] handle to image list
523  *     hIcon [I] handle to icon
524  *
525  * RETURNS
526  *     Success: index of the new image
527  *     Failure: -1
528  */
529
530 INT WINAPI
531 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
532 {
533     return ImageList_ReplaceIcon (himl, -1, hIcon);
534 }
535
536
537 /*************************************************************************
538  * ImageList_AddMasked [COMCTL32.41] 
539  *
540  * Adds an image or images to an image list and creates a mask from the
541  * specified bitmap using the mask color.
542  *
543  * PARAMS
544  *     himl    [I] handle to image list.
545  *     hBitmap [I] handle to bitmap
546  *     clrMask [I] mask color.
547  *
548  * RETURNS
549  *     Success: Index of the first new image.
550  *     Failure: -1
551  */
552
553 INT WINAPI
554 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
555 {
556     HDC    hdcImage, hdcMask, hdcBitmap;
557     INT    nIndex, nImageCount, nMaskXOffset=0;
558     BITMAP bmp;
559     HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
560     HBITMAP hMaskBitmap=0;
561     COLORREF bkColor;
562
563     if (himl == NULL)
564         return -1;
565
566     if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
567         return -1;
568
569     nImageCount = bmp.bmWidth / himl->cx;
570
571     if (himl->cCurImage + nImageCount >= himl->cMaxImage)
572     {
573         IMAGELIST_InternalExpandBitmaps (himl, nImageCount);
574     }
575
576     nIndex = himl->cCurImage;
577     himl->cCurImage += nImageCount;
578
579     hdcMask   = CreateCompatibleDC (0);
580     hdcImage  = CreateCompatibleDC(0);
581     hdcBitmap = CreateCompatibleDC(0);
582
583
584     hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
585     hOldBitmap = SelectObject(hdcBitmap, hBitmap);
586     if(himl->hbmMask)
587     {
588         hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
589         nMaskXOffset = nIndex * himl->cx;
590     }
591     else
592     {
593         /*
594             Create a temp Mask so we can remove the background of
595             the Image (Windows does this even if there is no mask)
596         */
597         hMaskBitmap = CreateBitmap(bmp.bmWidth, himl->cy, 1, 1, NULL);
598         hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
599         nMaskXOffset = 0;
600     }
601     /* create monochrome image to the mask bitmap */
602     bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
603         GetPixel (hdcBitmap, 0, 0);
604     SetBkColor (hdcBitmap, bkColor);
605     BitBlt (hdcMask, 
606         nMaskXOffset, 0, bmp.bmWidth, himl->cy,
607         hdcBitmap, 0, 0, 
608         SRCCOPY);
609
610     SetBkColor(hdcBitmap, RGB(255,255,255));
611     /*Remove the background from the image
612     */
613     /*
614         WINDOWS BUG ALERT!!!!!!
615         The statement below should not be done in common practice
616         but this is how ImageList_AddMasked works in Windows.
617         It overwrites the original bitmap passed, this was discovered
618         by using the same bitmap to itterated the different styles
619         on windows where it failed (BUT ImageList_Add is OK)
620         This is here in case some apps really on this bug
621     */
622     BitBlt(hdcBitmap, 
623         0, 0, bmp.bmWidth, himl->cy,
624         hdcMask, 
625         nMaskXOffset, 0, 
626         0x220326); /* NOTSRCAND */
627     /* Copy result to the imagelist
628     */
629     BitBlt (hdcImage, 
630         nIndex * himl->cx, 0, bmp.bmWidth, himl->cy,
631         hdcBitmap, 
632         0, 0, 
633         SRCCOPY);
634     /* Clean up
635     */
636     SelectObject(hdcMask,hOldBitmapMask);
637     SelectObject(hdcImage, hOldBitmapImage);
638     SelectObject(hdcBitmap, hOldBitmap);
639     DeleteDC(hdcMask);
640     DeleteDC(hdcImage);
641     DeleteDC(hdcBitmap);
642     if(!himl->hbmMask)
643     {
644         DeleteObject(hMaskBitmap);
645     }
646
647     return nIndex;
648 }
649
650
651 /*************************************************************************
652  * ImageList_BeginDrag [COMCTL32.42] 
653  *
654  * Creates a temporary image list that contains one image. It will be used
655  * as a drag image.
656  *
657  * PARAMS
658  *     himlTrack [I] handle to the source image list
659  *     iTrack    [I] index of the drag image in the source image list
660  *     dxHotspot [I] X position of the hot spot of the drag image
661  *     dyHotspot [I] Y position of the hot spot of the drag image
662  *
663  * RETURNS
664  *     Success: TRUE
665  *     Failure: FALSE
666  */
667
668 BOOL WINAPI
669 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
670                      INT dxHotspot, INT dyHotspot)
671 {
672     HDC hdcSrc, hdcDst;
673
674     FIXME("partially implemented!\n");
675
676     if (himlTrack == NULL)
677         return FALSE;
678
679     if (himlInternalDrag)
680         ImageList_EndDrag ();
681
682     himlInternalDrag =
683         ImageList_Create (himlTrack->cx, himlTrack->cy,
684                           himlTrack->flags, 1, 1);
685     if (himlInternalDrag == NULL) {
686         ERR("Error creating drag image list!\n");
687         return FALSE;
688     }
689
690     nInternalDragHotspotX = dxHotspot;
691     nInternalDragHotspotY = dyHotspot;
692
693     hdcSrc = CreateCompatibleDC (0);
694     hdcDst = CreateCompatibleDC (0);
695
696     /* copy image */
697     SelectObject (hdcSrc, himlTrack->hbmImage);
698     SelectObject (hdcDst, himlInternalDrag->hbmImage);
699     StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
700                   iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
701
702     /* copy mask */
703     SelectObject (hdcSrc, himlTrack->hbmMask);
704     SelectObject (hdcDst, himlInternalDrag->hbmMask);
705     StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
706                   iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
707
708     DeleteDC (hdcSrc);
709     DeleteDC (hdcDst);
710
711     himlInternalDrag->cCurImage = 1;
712
713     return TRUE;
714 }
715
716
717 /*************************************************************************
718  * ImageList_Copy [COMCTL32.43] 
719  *
720  *  Copies an image of the source image list to an image of the 
721  *  destination image list. Images can be copied or swapped.
722  *
723  * PARAMS
724  *     himlDst [I] handle to the destination image list
725  *     iDst    [I] destination image index.
726  *     himlSrc [I] handle to the source image list
727  *     iSrc    [I] source image index
728  *     uFlags  [I] flags for the copy operation
729  *
730  * RETURNS
731  *     Success: TRUE
732  *     Failure: FALSE
733  *
734  * NOTES
735  *     Copying from one image list to another is possible. The original
736  *     implementation just copies or swapps within one image list.
737  *     Could this feature become a bug??? ;-)
738  */
739
740 BOOL WINAPI
741 ImageList_Copy (HIMAGELIST himlDst, INT iDst,   HIMAGELIST himlSrc,
742                 INT iSrc, INT uFlags)
743 {
744     HDC hdcSrc, hdcDst;    
745
746     TRACE("iDst=%d  iSrc=%d\n", iDst, iSrc);
747
748     if ((himlSrc == NULL) || (himlDst == NULL))
749         return FALSE;
750     if ((iDst < 0) || (iDst >= himlDst->cCurImage))
751         return FALSE;
752     if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
753         return FALSE;
754
755     hdcSrc = CreateCompatibleDC (0);
756     if (himlDst == himlSrc)
757         hdcDst = hdcSrc;
758     else
759         hdcDst = CreateCompatibleDC (0);
760
761     if (uFlags & ILCF_SWAP) {
762         /* swap */
763         HBITMAP hbmTempImage, hbmTempMask;
764
765         /* create temporary bitmaps */
766         hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
767                                        himlSrc->uBitsPixel, NULL);
768         hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
769                                       1, NULL);
770
771         /* copy (and stretch) destination to temporary bitmaps.(save) */
772         /* image */
773         SelectObject (hdcSrc, himlDst->hbmImage);
774         SelectObject (hdcDst, hbmTempImage);
775         StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
776                       hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
777                       SRCCOPY);
778         /* mask */
779         SelectObject (hdcSrc, himlDst->hbmMask);
780         SelectObject (hdcDst, hbmTempMask);
781         StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
782                       hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
783                       SRCCOPY);
784
785         /* copy (and stretch) source to destination */
786         /* image */
787         SelectObject (hdcSrc, himlSrc->hbmImage);
788         SelectObject (hdcDst, himlDst->hbmImage);
789         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
790                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
791                       SRCCOPY);
792         /* mask */
793         SelectObject (hdcSrc, himlSrc->hbmMask);
794         SelectObject (hdcDst, himlDst->hbmMask);
795         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
796                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
797                       SRCCOPY);
798
799         /* copy (without stretching) temporary bitmaps to source (restore) */
800         /* image */
801         SelectObject (hdcSrc, hbmTempImage);
802         SelectObject (hdcDst, himlSrc->hbmImage);
803         BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
804                   hdcSrc, 0, 0, SRCCOPY);
805         /* mask */
806         SelectObject (hdcSrc, hbmTempMask);
807         SelectObject (hdcDst, himlSrc->hbmMask);
808         BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
809                   hdcSrc, 0, 0, SRCCOPY);
810
811         /* delete temporary bitmaps */
812         DeleteObject (hbmTempMask);
813         DeleteObject (hbmTempImage);
814     }
815     else {
816         /* copy image */
817         SelectObject (hdcSrc, himlSrc->hbmImage);
818         if (himlSrc == himlDst)
819             hdcDst = hdcSrc;
820         else
821             SelectObject (hdcDst, himlDst->hbmImage);
822         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
823                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
824                       SRCCOPY);
825
826         /* copy mask */
827         SelectObject (hdcSrc, himlSrc->hbmMask);
828         if (himlSrc == himlDst)
829             hdcDst = hdcSrc;
830         else
831             SelectObject (hdcDst, himlDst->hbmMask);
832         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
833                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
834                       SRCCOPY);
835     }
836
837     DeleteDC (hdcSrc);
838     if (himlSrc != himlDst)
839         DeleteDC (hdcDst);
840
841     return TRUE;
842 }
843
844
845 /*************************************************************************
846  * ImageList_Create [COMCTL32.44]  Creates a new image list.
847  *
848  * PARAMS
849  *     cx       [I] image height
850  *     cy       [I] image width
851  *     flags    [I] creation flags
852  *     cInitial [I] initial number of images in the image list
853  *     cGrow    [I] number of images by which image list grows
854  *
855  * RETURNS
856  *     Success: Handle to the created image list
857  *     Failure: NULL
858  */
859
860 HIMAGELIST WINAPI
861 ImageList_Create (INT cx, INT cy, UINT flags,
862                   INT cInitial, INT cGrow)
863 {
864     HIMAGELIST himl;
865     HDC      hdc;
866     INT      nCount;
867     HBITMAP  hbmTemp;
868     static WORD aBitBlend25[] = 
869         {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
870
871     static WORD aBitBlend50[] =
872         {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
873
874     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
875
876     himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
877     if (!himl)
878         return NULL;
879
880     himl->cx        = cx;
881     himl->cy        = cy;
882     himl->flags     = flags;
883     himl->cMaxImage = cInitial + cGrow;
884     himl->cInitial  = cInitial;
885     himl->cGrow     = cGrow;
886     himl->cCurImage = 0;
887     himl->clrFg     = CLR_DEFAULT;
888     himl->clrBk     = CLR_NONE;
889
890     /* initialize overlay mask indices */
891     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
892         himl->nOvlIdx[nCount] = -1;
893
894     hdc = CreateCompatibleDC (0);
895     himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
896     DeleteDC (hdc);
897
898     TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
899
900     if (himl->cMaxImage > 0) {
901         himl->hbmImage =
902           CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
903                         1, himl->uBitsPixel, NULL);
904         if (himl->hbmImage == 0) {
905             ERR("Error creating image bitmap!\n");
906             return NULL;
907         }
908     }
909     else
910         himl->hbmImage = 0;
911     
912     if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
913         himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
914                                         1, 1, NULL);
915         if (himl->hbmMask == 0) {
916             ERR("Error creating mask bitmap!\n");
917             if (himl->hbmImage)
918                 DeleteObject (himl->hbmImage);
919             return NULL;
920         }
921     }
922     else
923         himl->hbmMask = 0;
924
925     /* create blending brushes */
926     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
927     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
928     DeleteObject (hbmTemp);
929
930     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
931     himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
932     DeleteObject (hbmTemp);
933
934     return himl;
935 }
936
937
938 /*************************************************************************
939  * ImageList_Destroy [COMCTL32.45] 
940  *
941  * Destroys an image list.
942  *
943  * PARAMS
944  *     himl [I] handle to image list
945  *
946  * RETURNS
947  *     Success: TRUE
948  *     Failure: FALSE
949  */
950
951 BOOL WINAPI
952 ImageList_Destroy (HIMAGELIST himl)
953
954     if (!himl)
955         return FALSE;
956
957     /* delete image bitmaps */
958     if (himl->hbmImage)
959         DeleteObject (himl->hbmImage);
960     if (himl->hbmMask)
961         DeleteObject (himl->hbmMask);
962
963     /* delete blending brushes */
964     if (himl->hbrBlend25)
965         DeleteObject (himl->hbrBlend25);
966     if (himl->hbrBlend50)
967         DeleteObject (himl->hbrBlend50);
968         
969     COMCTL32_Free (himl);
970
971     return TRUE;
972 }
973
974
975 /*************************************************************************
976  * ImageList_DragEnter [COMCTL32.46] 
977  *
978  * Locks window update and displays the drag image at the given position.
979  *
980  * PARAMS
981  *     hwndLock [I] handle of the window that owns the drag image.
982  *     x        [I] X position of the drag image.
983  *     y        [I] Y position of the drag image.
984  *
985  * RETURNS
986  *     Success: TRUE
987  *     Failure: FALSE
988  *
989  * NOTES
990  *     The position of the drag image is relative to the window, not
991  *     the client area.
992  */
993
994 BOOL WINAPI
995 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
996 {
997     if (himlInternalDrag == NULL)
998         return FALSE;
999
1000     if (hwndLock)
1001         hwndInternalDrag = hwndLock;
1002     else
1003         hwndInternalDrag = GetDesktopWindow ();
1004
1005     xInternalPos = x;
1006     yInternalPos = y;
1007
1008     hdcBackBuffer = CreateCompatibleDC (0);
1009     hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1010                 himlInternalDrag->cx, himlInternalDrag->cy);
1011
1012     ImageList_DragShowNolock (TRUE);
1013
1014     return FALSE;
1015 }
1016
1017
1018 /*************************************************************************
1019  * ImageList_DragLeave [COMCTL32.47] 
1020  *
1021  * Unlocks window update and hides the drag image.
1022  *
1023  * PARAMS
1024  *     hwndLock [I] handle of the window that owns the drag image.
1025  *
1026  * RETURNS
1027  *     Success: TRUE
1028  *     Failure: FALSE
1029  */
1030
1031 BOOL WINAPI
1032 ImageList_DragLeave (HWND hwndLock)
1033 {
1034     if (hwndLock)
1035         hwndInternalDrag = hwndLock;
1036     else
1037         hwndInternalDrag = GetDesktopWindow ();
1038
1039     ImageList_DragShowNolock (FALSE);
1040
1041     DeleteDC (hdcBackBuffer);
1042     DeleteObject (hbmBackBuffer);
1043
1044     return TRUE;
1045 }
1046
1047
1048 /*************************************************************************
1049  * ImageList_DragMove [COMCTL32.48] 
1050  *
1051  * Moves the drag image.
1052  *
1053  * PARAMS
1054  *     x [I] X position of the drag image.
1055  *     y [I] Y position of the drag image.
1056  *
1057  * RETURNS
1058  *     Success: TRUE
1059  *     Failure: FALSE
1060  *
1061  * NOTES
1062  *     The position of the drag image is relative to the window, not
1063  *     the client area.
1064  */
1065
1066 BOOL WINAPI
1067 ImageList_DragMove (INT x, INT y)
1068 {
1069     ImageList_DragShowNolock (FALSE);
1070
1071     xInternalPos = x;
1072     yInternalPos = y;
1073
1074     ImageList_DragShowNolock (TRUE);
1075
1076     return FALSE;
1077 }
1078
1079
1080 /*************************************************************************
1081  * ImageList_DragShowNolock [COMCTL32.49] 
1082  *
1083  * Shows or hides the drag image.
1084  *
1085  * PARAMS
1086  *     bShow [I] TRUE shows the drag image, FALSE hides it.
1087  *
1088  * RETURNS
1089  *     Success: TRUE
1090  *     Failure: FALSE
1091  *
1092  * FIXME
1093  *     semi-stub.
1094  */
1095
1096 BOOL WINAPI
1097 ImageList_DragShowNolock (BOOL bShow)
1098 {
1099     HDC hdcDrag;
1100
1101     FIXME("semi-stub!\n");
1102     TRACE("bShow=0x%X!\n", bShow);
1103
1104     hdcDrag = GetDCEx (hwndInternalDrag, 0,
1105                          DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1106
1107     if (bShow) {
1108         /* show drag image */
1109
1110         /* save background */
1111
1112         /* draw drag image */
1113
1114     }
1115     else {
1116         /* hide drag image */
1117
1118         /* restore background */
1119
1120     }
1121
1122     ReleaseDC (hwndInternalDrag, hdcDrag);
1123
1124     return FALSE;
1125 }
1126
1127
1128 /*************************************************************************
1129  * ImageList_Draw [COMCTL32.50] Draws an image.
1130  *
1131  * PARAMS
1132  *     himl   [I] handle to image list
1133  *     i      [I] image index
1134  *     hdc    [I] handle to device context
1135  *     x      [I] x position
1136  *     y      [I] y position
1137  *     fStyle [I] drawing flags
1138  *
1139  * RETURNS
1140  *     Success: TRUE
1141  *     Failure: FALSE
1142  *
1143  * NOTES
1144  *     Calls ImageList_DrawIndirect.
1145  *
1146  * SEE
1147  *     ImageList_DrawIndirect.
1148  */
1149
1150 BOOL WINAPI
1151 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1152                 INT x, INT y, UINT fStyle)
1153 {
1154     IMAGELISTDRAWPARAMS imldp;
1155
1156     imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
1157     imldp.himl    = himl;
1158     imldp.i       = i;
1159     imldp.hdcDst  = hdc,
1160     imldp.x       = x;
1161     imldp.y       = y;
1162     imldp.cx      = 0;
1163     imldp.cy      = 0;
1164     imldp.xBitmap = 0;
1165     imldp.yBitmap = 0;
1166     imldp.rgbBk   = CLR_DEFAULT;
1167     imldp.rgbFg   = CLR_DEFAULT;
1168     imldp.fStyle  = fStyle;
1169     imldp.dwRop   = 0;
1170
1171     return ImageList_DrawIndirect (&imldp);
1172 }
1173
1174
1175 /*************************************************************************
1176  * ImageList_DrawEx [COMCTL32.51]
1177  *
1178  * Draws an image and allows to use extended drawing features.
1179  *
1180  * PARAMS
1181  *     himl   [I] handle to image list
1182  *     i      [I] image index
1183  *     hdc    [I] handle to device context
1184  *     x      [I] X position
1185  *     y      [I] Y position
1186  *     xOffs  [I] X offset
1187  *     yOffs  [I] Y offset
1188  *     rgbBk  [I] background color
1189  *     rgbFg  [I] foreground color
1190  *     fStyle [I] drawing flags
1191  *
1192  * RETURNS
1193  *     Success: TRUE
1194  *     Failure: FALSE
1195  *
1196  * NOTES
1197  *     Calls ImageList_DrawIndirect.
1198  *
1199  * SEE
1200  *     ImageList_DrawIndirect.
1201  */
1202
1203 BOOL WINAPI
1204 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1205                   INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1206                   UINT fStyle)
1207 {
1208     IMAGELISTDRAWPARAMS imldp;
1209
1210     imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
1211     imldp.himl    = himl;
1212     imldp.i       = i;
1213     imldp.hdcDst  = hdc,
1214     imldp.x       = x;
1215     imldp.y       = y;
1216     imldp.cx      = dx;
1217     imldp.cy      = dy;
1218     imldp.xBitmap = 0;
1219     imldp.yBitmap = 0;
1220     imldp.rgbBk   = rgbBk;
1221     imldp.rgbFg   = rgbFg;
1222     imldp.fStyle  = fStyle;
1223     imldp.dwRop   = 0;
1224
1225     return ImageList_DrawIndirect (&imldp);
1226 }
1227
1228
1229 /*************************************************************************
1230  * ImageList_DrawIndirect [COMCTL32.52] 
1231  *
1232  * Draws an image using ...
1233  *
1234  * PARAMS
1235  *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1236  *
1237  * RETURNS
1238  *     Success: TRUE
1239  *     Failure: FALSE
1240  */
1241
1242 BOOL WINAPI
1243 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1244 {
1245     INT      cx, cy;    
1246     /* 
1247         Do some Error Checking
1248     */
1249     if (pimldp == NULL)
1250         return FALSE;
1251     if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1252         return FALSE;
1253     if (pimldp->himl == NULL)
1254         return FALSE;
1255     if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage))
1256         return FALSE;
1257     /*
1258         Get the Height and Width to display
1259     */
1260     cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1261     cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1262     /*
1263         Draw the image
1264     */
1265     if(pimldp->himl->hbmMask != 0)
1266     {
1267         IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1268     }
1269     else
1270     {
1271         IMAGELIST_InternalDraw(pimldp, cx, cy);
1272     }
1273     /* 
1274         Apply the blend if needed to the Image
1275     */
1276     if((pimldp->fStyle & ILD_BLEND50)
1277         || (pimldp->fStyle & ILD_BLEND25))
1278     {
1279         IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1280     }
1281     /*
1282         Apply the Overlay if needed
1283     */
1284     if (pimldp->fStyle & 0x0700)
1285     {
1286         IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1287     }
1288
1289     return TRUE;
1290 }
1291
1292
1293 /*************************************************************************
1294  * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1295  *
1296  * PARAMS
1297  *     himlSrc [I] source image list handle
1298  *
1299  * RETURNS
1300  *     Success: Handle of duplicated image list.
1301  *     Failure: NULL
1302  */
1303
1304 HIMAGELIST WINAPI
1305 ImageList_Duplicate (HIMAGELIST himlSrc)
1306 {
1307     HIMAGELIST himlDst;
1308     HDC hdcSrc, hdcDst;
1309
1310     if (himlSrc == NULL) {
1311         ERR("Invalid image list handle!\n");
1312         return NULL;
1313     }
1314
1315     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1316                                 himlSrc->cInitial, himlSrc->cGrow);
1317
1318     if (himlDst)
1319     {
1320         hdcSrc = CreateCompatibleDC (0);
1321         hdcDst = CreateCompatibleDC (0);
1322         SelectObject (hdcSrc, himlSrc->hbmImage);
1323         SelectObject (hdcDst, himlDst->hbmImage);
1324         BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1325                   hdcSrc, 0, 0, SRCCOPY);
1326
1327         if (himlDst->hbmMask)
1328         {
1329             SelectObject (hdcSrc, himlSrc->hbmMask);
1330             SelectObject (hdcDst, himlDst->hbmMask);
1331             BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1332                       himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1333         }
1334
1335         DeleteDC (hdcDst);
1336         DeleteDC (hdcSrc);
1337     }
1338
1339     return himlDst;
1340 }
1341
1342
1343 /*************************************************************************
1344  * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1345  *
1346  * Finishes a drag operation.
1347  *
1348  * PARAMS
1349  *     no Parameters
1350  *
1351  * RETURNS
1352  *     Success: TRUE
1353  *     Failure: FALSE
1354  *
1355  * BUGS
1356  *     semi-stub.
1357  */
1358
1359 BOOL WINAPI
1360 ImageList_EndDrag (void)
1361 {
1362     FIXME("semi-stub!\n");
1363
1364     if (himlInternalDrag)
1365     {
1366
1367         ImageList_Destroy (himlInternalDrag);
1368         himlInternalDrag = NULL;
1369
1370         nInternalDragHotspotX = 0;
1371         nInternalDragHotspotY = 0;
1372
1373     }
1374
1375     return TRUE;
1376 }
1377
1378
1379 /*************************************************************************
1380  * ImageList_GetBkColor [COMCTL32.55]
1381  *
1382  * Returns the background color of an image list.
1383  *
1384  * PARAMS
1385  *     himl [I] Image list handle.
1386  *
1387  * RETURNS
1388  *     Success: background color
1389  *     Failure: CLR_NONE
1390  */
1391
1392 COLORREF WINAPI
1393 ImageList_GetBkColor (HIMAGELIST himl)
1394 {
1395     if (himl == NULL)
1396         return CLR_NONE;
1397
1398     return himl->clrBk;
1399 }
1400
1401
1402 /*************************************************************************
1403  * ImageList_GetDragImage [COMCTL32.56]
1404  *
1405  * Returns the handle to the internal drag image list.
1406  *
1407  * PARAMS
1408  *     ppt        [O] Pointer to the drag position. Can be NULL.
1409  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1410  *
1411  * RETURNS
1412  *     Success: Handle of the drag image list.
1413  *     Failure: NULL.
1414  *
1415  * BUGS
1416  *     semi-stub.
1417  */
1418
1419 HIMAGELIST WINAPI
1420 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1421 {
1422     FIXME("semi-stub!\n");
1423
1424     if (himlInternalDrag)
1425         return (himlInternalDrag);
1426
1427     return NULL;
1428 }
1429
1430
1431 /*************************************************************************
1432  * ImageList_GetIcon [COMCTL32.57] 
1433  *
1434  * Creates an icon from a masked image of an image list.
1435  *
1436  * PARAMS
1437  *     himl  [I] handle to image list
1438  *     i     [I] image index
1439  *     flags [I] drawing style flags
1440  *
1441  * RETURNS
1442  *     Success: icon handle
1443  *     Failure: NULL
1444  */
1445
1446 HICON WINAPI
1447 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1448 {
1449     ICONINFO ii;
1450     HICON  hIcon;
1451     HBITMAP hOldSrcBitmap,hOldDstBitmap;
1452     HDC    hdcSrc, hdcDst;
1453
1454     if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage))
1455         return 0;
1456
1457     hdcSrc = CreateCompatibleDC(0);
1458     hdcDst = CreateCompatibleDC(0);
1459
1460     ii.fIcon = TRUE;
1461     ii.hbmMask  = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1462
1463     /* draw mask*/
1464     hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1465     if (himl->hbmMask) {
1466         SelectObject (hdcSrc, himl->hbmMask);
1467         BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1468                   hdcSrc, i * himl->cx, 0, SRCCOPY);
1469     }
1470     else
1471         PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1472
1473     /* draw image*/
1474     hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1475     ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1476     SelectObject (hdcDst, ii.hbmColor);
1477     BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1478               hdcSrc, i * himl->cx, 0, SRCCOPY);
1479
1480     /*
1481      * CreateIconIndirect requires us to deselect the bitmaps from
1482      * the DCs before calling 
1483      */
1484     SelectObject(hdcSrc, hOldSrcBitmap);
1485     SelectObject(hdcDst, hOldDstBitmap);
1486
1487     hIcon = CreateIconIndirect (&ii);    
1488
1489     DeleteDC (hdcSrc);
1490     DeleteDC (hdcDst);
1491     DeleteObject (ii.hbmMask);
1492     DeleteObject (ii.hbmColor);
1493
1494     return hIcon;
1495 }
1496
1497
1498 /*************************************************************************
1499  * ImageList_GetIconSize [COMCTL32.58]
1500  *
1501  * Retrieves the size of an image in an image list.
1502  *
1503  * PARAMS
1504  *     himl [I] handle to image list
1505  *     cx   [O] pointer to the image width.
1506  *     cy   [O] pointer to the image height.
1507  *
1508  * RETURNS
1509  *     Success: TRUE
1510  *     Failure: FALSE
1511  *
1512  * NOTES
1513  *     All images in an image list have the same size.
1514  */
1515
1516 BOOL WINAPI
1517 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1518 {
1519     if (himl == NULL)
1520         return FALSE;
1521     if ((himl->cx <= 0) || (himl->cy <= 0))
1522         return FALSE;
1523
1524     if (cx)
1525         *cx = himl->cx;
1526     if (cy)
1527         *cy = himl->cy;
1528
1529     return TRUE;
1530 }
1531
1532
1533 /*************************************************************************
1534  * ImageList_GetImageCount [COMCTL32.59]
1535  *
1536  * Returns the number of images in an image list.
1537  *
1538  * PARAMS
1539  *     himl [I] handle to image list
1540  *
1541  * RETURNS
1542  *     Success: Number of images.
1543  *     Failure: 0
1544  */
1545
1546 INT WINAPI
1547 ImageList_GetImageCount (HIMAGELIST himl)
1548 {
1549     if (himl == NULL)
1550         return 0;
1551
1552     return himl->cCurImage;
1553 }
1554
1555
1556 /*************************************************************************
1557  * ImageList_GetImageInfo [COMCTL32.60]
1558  *
1559  * Returns information about an image in an image list.
1560  *
1561  * PARAMS
1562  *     himl       [I] handle to image list
1563  *     i          [I] image index
1564  *     pImageInfo [O] pointer to the image information
1565  *
1566  * RETURNS
1567  *     Success: TRUE
1568  *     Failure: FALSE
1569  */
1570
1571 BOOL WINAPI
1572 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1573 {
1574     if ((himl == NULL) || (pImageInfo == NULL))
1575         return FALSE;
1576     if ((i < 0) || (i >= himl->cCurImage))
1577         return FALSE;
1578
1579     pImageInfo->hbmImage = himl->hbmImage;
1580     pImageInfo->hbmMask  = himl->hbmMask;
1581     
1582     pImageInfo->rcImage.top    = 0;
1583     pImageInfo->rcImage.bottom = himl->cy;
1584     pImageInfo->rcImage.left   = i * himl->cx;
1585     pImageInfo->rcImage.right  = (i+1) * himl->cx;
1586     
1587     return TRUE;
1588 }
1589
1590
1591 /*************************************************************************
1592  * ImageList_GetImageRect [COMCTL32.61] 
1593  *
1594  * Retrieves the rectangle of the specified image in an image list.
1595  *
1596  * PARAMS
1597  *     himl   [I] handle to image list
1598  *     i      [I] image index
1599  *     lpRect [O] pointer to the image rectangle
1600  *
1601  * RETURNS
1602  *    Success: TRUE
1603  *    Failure: FALSE
1604  *
1605  * NOTES
1606  *    This is an UNDOCUMENTED function!!!
1607  */
1608
1609 BOOL WINAPI
1610 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1611 {
1612     if ((himl == NULL) || (lpRect == NULL))
1613         return FALSE;
1614     if ((i < 0) || (i >= himl->cCurImage))
1615         return FALSE;
1616
1617     lpRect->left   = i * himl->cx;
1618     lpRect->top    = 0;
1619     lpRect->right  = lpRect->left + himl->cx;
1620     lpRect->bottom = himl->cy;
1621
1622     return TRUE;
1623 }
1624
1625
1626 /*************************************************************************
1627  * ImageList_LoadImage32A [COMCTL32.63][COMCTL32.62]
1628  *
1629  * Creates an image list from a bitmap, icon or cursor.
1630  *
1631  * PARAMS
1632  *     hi      [I] instance handle
1633  *     lpbmp   [I] name or id of the image
1634  *     cx      [I] width of each image
1635  *     cGrow   [I] number of images to expand
1636  *     clrMask [I] mask color
1637  *     uType   [I] type of image to load
1638  *     uFlags  [I] loading flags
1639  *
1640  * RETURNS
1641  *     Success: handle to the loaded image list
1642  *     Failure: NULL
1643  *
1644  * SEE
1645  *     LoadImage ()
1646  */
1647
1648 HIMAGELIST WINAPI
1649 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx,       INT cGrow,
1650                         COLORREF clrMask, UINT uType,   UINT uFlags)
1651 {
1652     HIMAGELIST himl = NULL;
1653     HANDLE   handle;
1654     INT      nImageCount;
1655
1656     handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1657     if (!handle) {
1658         ERR("Error loading image!\n");
1659         return NULL;
1660     }
1661
1662     if (uType == IMAGE_BITMAP) {
1663         BITMAP bmp;
1664         GetObjectA (handle, sizeof(BITMAP), &bmp);
1665
1666         /* To match windows behavior, if cx is set to zero and
1667          the flag DI_DEFAULTSIZE is specified, cx becomes the
1668          system metric value for icons. If the flag is not specified
1669          the function sets the size to the height of the bitmap */
1670         if (cx == 0)
1671         {
1672             if (uFlags & DI_DEFAULTSIZE)
1673                 cx = GetSystemMetrics (SM_CXICON);
1674             else
1675                 cx = bmp.bmHeight;
1676         }
1677
1678         nImageCount = bmp.bmWidth / cx;
1679
1680         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1681                                  nImageCount, cGrow);
1682         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1683     }
1684     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1685         ICONINFO ii;
1686         BITMAP bmp;
1687
1688         GetIconInfo (handle, &ii);
1689         GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1690         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
1691                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1692         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1693         DeleteObject (ii.hbmColor);
1694         DeleteObject (ii.hbmMask);
1695     }
1696
1697     DeleteObject (handle);
1698     
1699     return himl;
1700 }
1701
1702
1703 /*************************************************************************
1704  * ImageList_LoadImage32W [COMCTL32.64]
1705  *
1706  * Creates an image list from a bitmap, icon or cursor.
1707  *
1708  * PARAMS
1709  *     hi      [I] instance handle
1710  *     lpbmp   [I] name or id of the image
1711  *     cx      [I] width of each image
1712  *     cGrow   [I] number of images to expand
1713  *     clrMask [I] mask color
1714  *     uType   [I] type of image to load
1715  *     uFlags  [I] loading flags
1716  *
1717  * RETURNS
1718  *     Success: handle to the loaded image list
1719  *     Failure: NULL
1720  *
1721  * SEE
1722  *     LoadImage ()
1723  */
1724
1725 HIMAGELIST WINAPI
1726 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1727                         COLORREF clrMask, UINT uType,   UINT uFlags)
1728 {
1729     HIMAGELIST himl = NULL;
1730     HANDLE   handle;
1731     INT      nImageCount;
1732
1733     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1734     if (!handle) {
1735         ERR("Error loading image!\n");
1736         return NULL;
1737     }
1738
1739     if (uType == IMAGE_BITMAP) {
1740         BITMAP bmp;
1741         GetObjectA (handle, sizeof(BITMAP), &bmp);
1742         nImageCount = bmp.bmWidth / cx;
1743
1744         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1745                                  nImageCount, cGrow);
1746         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1747     }
1748     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1749         ICONINFO ii;
1750         BITMAP bmp;
1751
1752         GetIconInfo (handle, &ii);
1753         GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1754         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
1755                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1756         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1757         DeleteObject (ii.hbmColor);
1758         DeleteObject (ii.hbmMask);
1759     }
1760
1761     DeleteObject (handle);
1762     
1763     return himl;
1764 }
1765
1766
1767 /*************************************************************************
1768  * ImageList_Merge [COMCTL32.65] 
1769  *
1770  * Creates a new image list that contains a merged image from the specified
1771  * images of both source image lists.
1772  *
1773  * PARAMS
1774  *     himl1 [I] handle to first image list
1775  *     i1    [I] first image index
1776  *     himl2 [I] handle to second image list
1777  *     i2    [I] second image index
1778  *     dx    [I] X offset of the second image relative to the first.
1779  *     dy    [I] Y offset of the second image relative to the first.
1780  *
1781  * RETURNS
1782  *     Success: handle of the merged image list.
1783  *     Failure: NULL
1784  */
1785
1786 HIMAGELIST WINAPI
1787 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1788                  INT dx, INT dy)
1789 {
1790     HIMAGELIST himlDst = NULL;
1791     HDC      hdcSrcImage, hdcDstImage;
1792     INT      cxDst, cyDst;
1793     INT      xOff1, yOff1, xOff2, yOff2;
1794     INT      nX1, nX2;
1795
1796     if ((himl1 == NULL) || (himl2 == NULL))
1797         return NULL;
1798
1799     /* check indices */
1800     if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1801         ERR("Index 1 out of range! %d\n", i1);
1802         return NULL;
1803     }
1804
1805     if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1806         ERR("Index 2 out of range! %d\n", i2);
1807         return NULL;
1808     }
1809
1810     if (dx > 0) {
1811         cxDst = _MAX (himl1->cx, dx + himl2->cx);
1812         xOff1 = 0;
1813         xOff2 = dx;
1814     }
1815     else if (dx < 0) {
1816         cxDst = _MAX (himl2->cx, himl1->cx - dx);
1817         xOff1 = -dx;
1818         xOff2 = 0;
1819     }
1820     else {
1821         cxDst = _MAX (himl1->cx, himl2->cx);
1822         xOff1 = 0;
1823         xOff2 = 0;
1824     }
1825
1826     if (dy > 0) {
1827         cyDst = _MAX (himl1->cy, dy + himl2->cy);
1828         yOff1 = 0;
1829         yOff2 = dy;
1830     }
1831     else if (dy < 0) {
1832         cyDst = _MAX (himl2->cy, himl1->cy - dy);
1833         yOff1 = -dy;
1834         yOff2 = 0;
1835     }
1836     else {
1837         cyDst = _MAX (himl1->cy, himl2->cy);
1838         yOff1 = 0;
1839         yOff2 = 0;
1840     }
1841
1842     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1843
1844     if (himlDst) {
1845         hdcSrcImage = CreateCompatibleDC (0);
1846         hdcDstImage = CreateCompatibleDC (0);
1847         nX1 = i1 * himl1->cx;
1848         nX2 = i2 * himl2->cx;
1849         
1850         /* copy image */
1851         SelectObject (hdcSrcImage, himl1->hbmImage);
1852         SelectObject (hdcDstImage, himlDst->hbmImage);
1853         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
1854                   hdcSrcImage, 0, 0, BLACKNESS);
1855         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
1856                   hdcSrcImage, nX1, 0, SRCCOPY);
1857
1858         SelectObject (hdcSrcImage, himl2->hbmMask);
1859         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
1860                   hdcSrcImage, nX2, 0, SRCAND);
1861
1862         SelectObject (hdcSrcImage, himl2->hbmImage);
1863         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
1864                   hdcSrcImage, nX2, 0, SRCPAINT);
1865
1866         /* copy mask */
1867         SelectObject (hdcSrcImage, himl1->hbmMask);
1868         SelectObject (hdcDstImage, himlDst->hbmMask);
1869         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
1870                   hdcSrcImage, 0, 0, WHITENESS);
1871         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
1872                   hdcSrcImage, nX1, 0, SRCCOPY);
1873
1874         SelectObject (hdcSrcImage, himl2->hbmMask);
1875         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
1876                   hdcSrcImage, nX2, 0, SRCAND);
1877
1878         DeleteDC (hdcSrcImage);
1879         DeleteDC (hdcDstImage);
1880     }
1881    
1882     return himlDst;
1883 }
1884
1885
1886 /*************************************************************************
1887  * ImageList_Read [COMCTL32.66]
1888  *
1889  * Reads an image list from a stream.
1890  *
1891  * PARAMS
1892  *     pstm [I] pointer to a stream
1893  *
1894  * RETURNS
1895  *     Success: handle to image list
1896  *     Failure: NULL
1897  *
1898  * NOTES
1899  *     This function can not be implemented yet, because
1900  *     IStream32::Read is not implemented yet.
1901  *
1902  * BUGS
1903  *     empty stub.
1904  */
1905
1906 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1907 {
1908     HRESULT errCode;
1909     ULONG ulRead;
1910     ILHEAD ilHead;
1911     HIMAGELIST himl;
1912
1913
1914     FIXME("empty stub!\n");
1915
1916     errCode = IStream_Read (pstm, &ilHead, sizeof(ILHEAD), &ulRead);
1917     if (errCode != S_OK)
1918     return NULL;
1919
1920     FIXME("Magic: 0x%x\n", ilHead.usMagic);
1921
1922     himl = ImageList_Create (32, 32, ILD_NORMAL, 2, 2);
1923
1924     return himl;
1925 }
1926
1927
1928 /*************************************************************************
1929  * ImageList_Remove [COMCTL32.67] Removes an image from an image list
1930  *
1931  * PARAMS
1932  *     himl [I] image list handle
1933  *     i    [I] image index
1934  *
1935  * RETURNS
1936  *     Success: TRUE
1937  *     Failure: FALSE
1938  */
1939
1940 BOOL WINAPI
1941 ImageList_Remove (HIMAGELIST himl, INT i)
1942 {
1943     HBITMAP hbmNewImage, hbmNewMask;
1944     HDC     hdcSrc, hdcDst;
1945     INT     cxNew, nCount;
1946
1947     if ((i < -1) || (i >= himl->cCurImage)) {
1948         ERR("index out of range! %d\n", i);
1949         return FALSE;
1950     }
1951
1952     if (himl->cCurImage == 0) {
1953         ERR("image list is already empty!\n");
1954         return FALSE;
1955     }
1956
1957     if (i == -1) {
1958         /* remove all */
1959         TRACE("remove all!\n");
1960
1961         himl->cMaxImage = himl->cInitial + himl->cGrow;
1962         himl->cCurImage = 0;
1963         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
1964              himl->nOvlIdx[nCount] = -1;
1965
1966         DeleteObject (himl->hbmImage);
1967         himl->hbmImage =
1968             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
1969                             1, himl->uBitsPixel, NULL);
1970
1971         if (himl->hbmMask) {
1972             DeleteObject (himl->hbmMask);
1973             himl->hbmMask =
1974                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
1975                                 1, 1, NULL);
1976         }
1977     }
1978     else {
1979         /* delete one image */
1980         TRACE("Remove single image! %d\n", i);
1981
1982         /* create new bitmap(s) */
1983         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
1984
1985         TRACE(" - Number of images: %d / %d (Old/New)\n",
1986                  himl->cCurImage, himl->cCurImage - 1);
1987         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
1988                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
1989         
1990         hbmNewImage =
1991             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
1992
1993         if (himl->hbmMask)
1994             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
1995         else
1996             hbmNewMask = 0;  /* Just to keep compiler happy! */
1997
1998         hdcSrc = CreateCompatibleDC (0);
1999         hdcDst = CreateCompatibleDC (0);
2000
2001         /* copy all images and masks prior to the "removed" image */
2002         if (i > 0) {
2003             TRACE("Pre image copy: Copy %d images\n", i);
2004        
2005             SelectObject (hdcSrc, himl->hbmImage);
2006             SelectObject (hdcDst, hbmNewImage);
2007             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2008                       hdcSrc, 0, 0, SRCCOPY);
2009
2010             if (himl->hbmMask) {
2011                 SelectObject (hdcSrc, himl->hbmMask);
2012                 SelectObject (hdcDst, hbmNewMask);
2013                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2014                           hdcSrc, 0, 0, SRCCOPY);
2015             }
2016         }
2017
2018         /* copy all images and masks behind the removed image */
2019         if (i < himl->cCurImage - 1) {
2020             TRACE("Post image copy!\n");
2021             SelectObject (hdcSrc, himl->hbmImage);
2022             SelectObject (hdcDst, hbmNewImage);
2023             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2024                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2025
2026             if (himl->hbmMask) {
2027                 SelectObject (hdcSrc, himl->hbmMask);
2028                 SelectObject (hdcDst, hbmNewMask);
2029                 BitBlt (hdcDst, i * himl->cx, 0,
2030                           (himl->cCurImage - i - 1) * himl->cx,
2031                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2032             }
2033         }
2034
2035         DeleteDC (hdcSrc);
2036         DeleteDC (hdcDst);
2037
2038         /* delete old images and insert new ones */
2039         DeleteObject (himl->hbmImage);
2040         himl->hbmImage = hbmNewImage;
2041         if (himl->hbmMask) {
2042             DeleteObject (himl->hbmMask);
2043             himl->hbmMask = hbmNewMask;
2044         }
2045
2046         himl->cCurImage--;
2047         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2048     }
2049
2050     return TRUE;
2051 }
2052
2053
2054 /*************************************************************************
2055  * ImageList_Replace [COMCTL32.68] 
2056  *
2057  * Replaces an image in an image list with a new image.
2058  *
2059  * PARAMS
2060  *     himl     [I] handle to image list
2061  *     i        [I] image index
2062  *     hbmImage [I] handle to image bitmap
2063  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2064  *
2065  * RETURNS
2066  *     Success: TRUE
2067  *     Failure: FALSE
2068  */
2069
2070 BOOL WINAPI
2071 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2072                    HBITMAP hbmMask)
2073 {
2074     HDC hdcImageList, hdcImage;
2075     BITMAP bmp;
2076
2077     if (himl == NULL) {
2078         ERR("Invalid image list handle!\n");
2079         return FALSE;
2080     }
2081     
2082     if ((i >= himl->cCurImage) || (i < 0)) {
2083         ERR("Invalid image index!\n");
2084         return FALSE;
2085     }
2086
2087     hdcImageList = CreateCompatibleDC (0);
2088     hdcImage = CreateCompatibleDC (0);
2089     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2090
2091     /* Replace Image */
2092     SelectObject (hdcImageList, himl->hbmImage);
2093     SelectObject (hdcImage, hbmImage);
2094
2095     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2096                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2097
2098     if (himl->hbmMask)
2099     {
2100         /* Replace Mask */
2101         SelectObject (hdcImageList, himl->hbmMask);
2102         SelectObject (hdcImage, hbmMask);
2103
2104         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2105                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2106     }
2107
2108     DeleteDC (hdcImage);
2109     DeleteDC (hdcImageList);
2110
2111     return TRUE;
2112 }
2113
2114
2115 /*************************************************************************
2116  * ImageList_ReplaceIcon [COMCTL32.69]
2117  *
2118  * Replaces an image in an image list using an icon.
2119  *
2120  * PARAMS
2121  *     himl  [I] handle to image list
2122  *     i     [I] image index
2123  *     hIcon [I] handle to icon
2124  *
2125  * RETURNS
2126  *     Success: index of the replaced image
2127  *     Failure: -1
2128  */
2129
2130 INT WINAPI
2131 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2132 {
2133     HDC     hdcImageList, hdcImage;
2134     INT     nIndex;
2135     HICON   hBestFitIcon;
2136     HBITMAP hbmOldSrc, hbmOldDst;
2137     ICONINFO  ii;
2138     BITMAP  bmp;
2139
2140     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2141
2142     if (himl == NULL)
2143         return -1;
2144     if ((i >= himl->cCurImage) || (i < -1))
2145         return -1;
2146
2147     hBestFitIcon = CopyImage(
2148         hIcon, IMAGE_ICON, 
2149         himl->cx, himl->cy, 
2150         LR_COPYFROMRESOURCE);
2151
2152     GetIconInfo (hBestFitIcon, &ii);
2153     if (ii.hbmMask == 0)
2154         ERR("no mask!\n");
2155     if (ii.hbmColor == 0)
2156         ERR("no color!\n");
2157     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2158
2159     if (i == -1) {
2160         if (himl->cCurImage + 1 >= himl->cMaxImage)
2161             IMAGELIST_InternalExpandBitmaps (himl, 1);
2162
2163         nIndex = himl->cCurImage;
2164         himl->cCurImage++;
2165     }
2166     else
2167         nIndex = i;
2168
2169     hdcImageList = CreateCompatibleDC (0);
2170     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2171     if (hdcImageList == 0)
2172         ERR("invalid hdcImageList!\n");
2173
2174     hdcImage = CreateCompatibleDC (0);
2175     TRACE("hdcImage=0x%x!\n", hdcImage);
2176     if (hdcImage == 0)
2177         ERR("invalid hdcImage!\n");
2178
2179     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2180     SetTextColor( hdcImageList, RGB(0,0,0));
2181     SetBkColor( hdcImageList, RGB(255,255,255));
2182     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2183     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2184                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2185
2186     if (himl->hbmMask) {
2187         SelectObject (hdcImageList, himl->hbmMask);
2188         SelectObject (hdcImage, ii.hbmMask);
2189         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2190                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2191     }
2192
2193     SelectObject (hdcImage, hbmOldSrc);
2194     SelectObject (hdcImageList, hbmOldDst);
2195
2196     if(hBestFitIcon)
2197         DestroyIcon(hBestFitIcon);
2198     if (hdcImageList)
2199         DeleteDC (hdcImageList);
2200     if (hdcImage)
2201         DeleteDC (hdcImage);
2202     if (ii.hbmColor)
2203         DeleteObject (ii.hbmColor);
2204     if (ii.hbmMask)
2205         DeleteObject (ii.hbmMask);
2206
2207     return nIndex;
2208 }
2209
2210
2211 /*************************************************************************
2212  * ImageList_SetBkColor [COMCTL32.70] 
2213  *
2214  * Sets the background color of an image list.
2215  *
2216  * PARAMS
2217  *     himl  [I] handle to image list
2218  *     clrBk [I] background color
2219  *
2220  * RETURNS
2221  *     Success: previous background color
2222  *     Failure: CLR_NONE
2223  */
2224
2225 COLORREF WINAPI
2226 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2227 {
2228     COLORREF clrOldBk;
2229
2230     if (himl == NULL)
2231         return CLR_NONE;
2232
2233     clrOldBk = himl->clrBk;
2234     himl->clrBk = clrBk;
2235     return clrOldBk;
2236 }
2237
2238
2239 /*************************************************************************
2240  * ImageList_SetDragCursorImage [COMCTL32.75]
2241  *
2242  * Combines the specified image with the current drag image
2243  *
2244  * PARAMS
2245  *     himlDrag  [I] handle to drag image list
2246  *     iDrag     [I] drag image index
2247  *     dxHotspot [I] X position of the hot spot
2248  *     dyHotspot [I] Y position of the hot spot
2249  *
2250  * RETURNS
2251  *     Success: TRUE
2252  *     Failure: FALSE
2253  *
2254  * BUGS
2255  *     semi-stub.
2256  */
2257
2258 BOOL WINAPI
2259 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2260                               INT dxHotspot, INT dyHotspot)
2261 {
2262     HIMAGELIST himlTemp;
2263
2264     FIXME("semi-stub!\n");
2265
2266     if (himlInternalDrag == NULL)
2267         return FALSE;
2268
2269     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2270            dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2271
2272     himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2273                                 dxHotspot, dyHotspot);
2274
2275     ImageList_Destroy (himlInternalDrag);
2276     himlInternalDrag = himlTemp;
2277
2278     nInternalDragHotspotX = dxHotspot;
2279     nInternalDragHotspotY = dyHotspot;
2280
2281     return FALSE;
2282 }
2283
2284
2285 /*************************************************************************
2286  * ImageList_SetFilter [COMCTL32.76] 
2287  *
2288  * Sets a filter (or does something completely different)!!???
2289  *
2290  * PARAMS
2291  *     himl     [I] handle to image list
2292  *     i        [I] ???
2293  *     dwFilter [I] ???
2294  *
2295  * RETURNS
2296  *     Success: TRUE ???
2297  *     Failure: FALSE ???
2298  *
2299  * BUGS
2300  *     This is an UNDOCUMENTED function!!!!
2301  *     empty stub.
2302  */
2303
2304 BOOL WINAPI
2305 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2306 {
2307     FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2308            himl, i, dwFilter);
2309
2310     return FALSE;
2311 }
2312
2313
2314 /*************************************************************************
2315  * ImageList_SetIconSize [COMCTL32.77]
2316  *
2317  * Sets the image size of the bitmap and deletes all images.
2318  *
2319  * PARAMS
2320  *     himl [I] handle to image list
2321  *     cx   [I] image width
2322  *     cy   [I] image height
2323  *
2324  * RETURNS
2325  *     Success: TRUE
2326  *     Failure: FALSE
2327  */
2328
2329 BOOL WINAPI
2330 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2331 {
2332     INT nCount;
2333
2334     if (!himl)
2335         return FALSE;
2336
2337     /* remove all images*/
2338     himl->cMaxImage = himl->cInitial + himl->cGrow;
2339     himl->cCurImage = 0;
2340     himl->cx        = cx;
2341     himl->cy        = cy;
2342
2343     /* initialize overlay mask indices */
2344     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2345         himl->nOvlIdx[nCount] = -1;
2346
2347     DeleteObject (himl->hbmImage);
2348     himl->hbmImage =
2349         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2350                         1, himl->uBitsPixel, NULL);
2351
2352     if (himl->hbmMask) {
2353         DeleteObject (himl->hbmMask);
2354         himl->hbmMask =
2355             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2356                             1, 1, NULL);
2357     }
2358
2359     return TRUE;
2360 }
2361
2362
2363 /*************************************************************************
2364  * ImageList_SetImageCount [COMCTL32.78]
2365  *
2366  * Resizes an image list to the specified number of images.
2367  *
2368  * PARAMS
2369  *     himl        [I] handle to image list
2370  *     iImageCount [I] number of images in the image list
2371  *
2372  * RETURNS
2373  *     Success: TRUE
2374  *     Failure: FALSE
2375  */
2376
2377 BOOL WINAPI
2378 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2379 {
2380     HDC     hdcImageList, hdcBitmap;
2381     HBITMAP hbmNewBitmap;
2382     INT     nNewCount, nCopyCount;
2383
2384     if (!himl)
2385         return FALSE;
2386     if (himl->cCurImage >= iImageCount)
2387         return FALSE;
2388     if (himl->cMaxImage > iImageCount)
2389         return TRUE;
2390
2391     nNewCount = iImageCount + himl->cGrow;
2392     nCopyCount = _MIN(himl->cCurImage, iImageCount);
2393
2394     hdcImageList = CreateCompatibleDC (0);
2395     hdcBitmap = CreateCompatibleDC (0);
2396
2397     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2398                                    1, himl->uBitsPixel, NULL);
2399     if (hbmNewBitmap != 0)
2400     {
2401         SelectObject (hdcImageList, himl->hbmImage);
2402         SelectObject (hdcBitmap, hbmNewBitmap);
2403
2404         /* copy images */
2405         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2406                   hdcImageList, 0, 0, SRCCOPY);
2407 #if 0
2408         /* delete 'empty' image space */
2409         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2410         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2411         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2412                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2413 #endif
2414         DeleteObject (himl->hbmImage);
2415         himl->hbmImage = hbmNewBitmap;
2416     }
2417     else
2418         ERR("Could not create new image bitmap !\n");
2419
2420     if (himl->hbmMask)
2421     {
2422         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2423                                        1, 1, NULL);
2424         if (hbmNewBitmap != 0)
2425         {
2426             SelectObject (hdcImageList, himl->hbmMask);
2427             SelectObject (hdcBitmap, hbmNewBitmap);
2428
2429             /* copy images */
2430             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2431                       hdcImageList, 0, 0, SRCCOPY);
2432 #if 0
2433             /* delete 'empty' image space */
2434             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2435             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2436             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2437                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2438 #endif
2439             DeleteObject (himl->hbmMask);
2440             himl->hbmMask = hbmNewBitmap;
2441         }
2442         else
2443             ERR("Could not create new mask bitmap!\n");
2444     }
2445
2446     DeleteDC (hdcImageList);
2447     DeleteDC (hdcBitmap);
2448
2449     /* Update max image count and current image count */
2450     himl->cMaxImage = nNewCount;
2451     if (himl->cCurImage > nCopyCount)
2452         himl->cCurImage = nCopyCount;
2453
2454     return TRUE;
2455 }
2456
2457
2458 /*************************************************************************
2459  * ImageList_SetOverlayImage [COMCTL32.79]
2460  *
2461  * Assigns an overlay mask index to an existing image in an image list.
2462  *
2463  * PARAMS
2464  *     himl     [I] handle to image list
2465  *     iImage   [I] image index
2466  *     iOverlay [I] overlay mask index
2467  *
2468  * RETURNS
2469  *     Success: TRUE
2470  *     Failure: FALSE
2471  */
2472
2473 BOOL WINAPI
2474 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2475 {
2476     if (!himl)
2477         return FALSE;
2478     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2479         return FALSE;
2480     if ((iImage < 0) || (iImage > himl->cCurImage))
2481         return FALSE;
2482     
2483     himl->nOvlIdx[iOverlay - 1] = iImage;
2484     return TRUE;
2485 }
2486
2487
2488 /*************************************************************************
2489  * ImageList_Write [COMCTL32.80]
2490  *
2491  * Writes an image list to a stream.
2492  *
2493  * PARAMS
2494  *     himl [I] handle to image list
2495  *     pstm [O] Pointer to a stream.
2496  *
2497  * RETURNS
2498  *     Success: TRUE
2499  *     Failure: FALSE
2500  *
2501  * NOTES
2502  *     This function can not be implemented yet, because
2503  *     IStream32::Write is not implemented.
2504  *
2505  * BUGS
2506  *     empty stub.
2507  */
2508
2509 BOOL WINAPI
2510 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2511 {
2512     if (!himl)
2513         return FALSE;
2514
2515     FIXME("empty stub!\n");
2516
2517     return FALSE;
2518 }
2519