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