Prepare dlls/{comctl32,gdi,msvideo,setupapi,shell32,twain,winmm} for
[wine] / dlls / comctl32 / imagelist.c
1 /*
2  *  ImageList implementation
3  *
4  *  Copyright 1998 Eric Kohl
5  *            2000 Jason Mawdsley.
6  *            2001 Michael Stefaniuc
7  *            2001 Charles Loep for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  *  TODO:
24  *    - Fix ImageList_DrawIndirect (dwRop).
25  *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
26  *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
27  *
28  *  Comments:
29  *    - Hotspot handling still not correct. The Hotspot passed to BeginDrag
30  *      is the offset of the image position relative to the actual mouse pointer
31  *      position. However the Hotspot passed to SetDragCursorImage is the
32  *      offset of the mouse messages sent to the application...
33  */
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include "winerror.h"
38 #include "winbase.h"
39 #include "wine/obj_base.h"
40 #include "wine/obj_storage.h"
41 #include "commctrl.h"
42 #include "imagelist.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
46
47
48 #define MAX_OVERLAYIMAGE 15
49
50 /* internal image list data used for Drag & Drop operations */
51 typedef struct
52 {
53     HWND        hwnd;
54     HIMAGELIST  himl;
55     /* position of the drag image relative to the window */
56     INT         x;
57     INT         y;
58     /* offset of the hotspot relative to the origin of the image */
59     INT         dxHotspot;
60     INT         dyHotspot;
61     /* is the drag image visible */
62     BOOL        bShow;
63     /* saved background */
64     HBITMAP     hbmBg;
65     BOOL        bHSPending;
66 } INTERNALDRAG;
67
68 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
69
70
71
72 /*************************************************************************
73  * IMAGELIST_InternalExpandBitmaps [Internal]
74  *
75  * Expands the bitmaps of an image list by the given number of images.
76  *
77  * PARAMS
78  *     himl        [I] handle to image list
79  *     nImageCount [I] number of images to add
80  *
81  * RETURNS
82  *     nothing
83  *
84  * NOTES
85  *     This function can NOT be used to reduce the number of images.
86  */
87 static void
88 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
89 {
90     HDC     hdcImageList, hdcBitmap;
91     HBITMAP hbmNewBitmap;
92     INT     nNewWidth, nNewCount;
93
94     if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
95         && (himl->cy >= cy))
96         return;
97
98     if (cy == 0) cy = himl->cy;
99     nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
100     nNewWidth = nNewCount * himl->cx;
101
102     TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
103     hdcImageList = CreateCompatibleDC (0);
104     hdcBitmap = CreateCompatibleDC (0);
105
106     hbmNewBitmap =
107         CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
108     if (hbmNewBitmap == 0)
109         ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
110
111     SelectObject (hdcImageList, himl->hbmImage);
112     SelectObject (hdcBitmap, hbmNewBitmap);
113     BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
114               hdcImageList, 0, 0, SRCCOPY);
115
116     DeleteObject (himl->hbmImage);
117     himl->hbmImage = hbmNewBitmap;
118
119     if (himl->hbmMask) {
120         hbmNewBitmap =
121             CreateBitmap (nNewWidth, cy, 1, 1, NULL);
122
123         if (hbmNewBitmap == 0)
124             ERR("creating new mask bitmap!\n");
125
126         SelectObject (hdcImageList, himl->hbmMask);
127         SelectObject (hdcBitmap, hbmNewBitmap);
128         BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
129                   hdcImageList, 0, 0, SRCCOPY);
130         DeleteObject (himl->hbmMask);
131         himl->hbmMask = hbmNewBitmap;
132     }
133
134     himl->cMaxImage = nNewCount;
135
136     DeleteDC (hdcImageList);
137     DeleteDC (hdcBitmap);
138 }
139
140
141 /*************************************************************************
142  * IMAGELIST_InternalDraw [Internal]
143  *
144  * Draws the image in the ImageList (without the mask)
145  *
146  * PARAMS
147  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
148  *     cx            [I] the width of the image to display
149  *     cy            [I] the height of the image to display
150  *
151  * RETURNS
152  *     nothing
153  *
154  * NOTES
155  *     This function is used by ImageList_DrawIndirect, when it is
156  *     required to draw only the Image (without the mask) to the screen.
157  *
158  *     Blending and Overlays styles are accomplished by another function
159  */
160 static void
161 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
162 {
163     HDC hImageDC;
164     HBITMAP hOldBitmap;
165
166     hImageDC = CreateCompatibleDC(0);
167     hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
168     BitBlt(pimldp->hdcDst,
169         pimldp->x, pimldp->y, cx, cy,
170         hImageDC,
171         pimldp->himl->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
172         SRCCOPY);
173
174     SelectObject(hImageDC, hOldBitmap);
175     DeleteDC(hImageDC);
176 }
177
178
179 /*************************************************************************
180  * IMAGELIST_InternalDrawMask [Internal]
181  *
182  * Draws the image in the ImageList with the mask
183  *
184  * PARAMS
185  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
186  *     cx            [I] the width of the image to display
187  *     cy            [I] the height of the image to display
188  *
189  * RETURNS
190  *     nothing
191  *
192  * NOTES
193  *     This function is used by ImageList_DrawIndirect, when it is
194  *     required to draw the Image with the mask to the screen.
195  *
196  *     Blending and Overlays styles are accomplished by another function.
197  */
198 static void
199 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
200 {
201     HBITMAP hOldBitmapImage, hOldBitmapMask;
202     HIMAGELIST himlLocal = pimldp->himl;
203     UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
204     COLORREF clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himlLocal->clrBk : pimldp->rgbBk;
205
206     /*
207      * We need a dc and bitmap to draw on that is
208      * not on the screen.
209      */
210     HDC hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
211     HBITMAP hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
212
213     BOOL bUseCustomBackground = (clrBk != CLR_NONE) &&
214                                 !((fStyle & ILD_TRANSPARENT) && himlLocal->hbmMask);
215     BOOL bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
216
217     HDC hImageDC = CreateCompatibleDC(0);
218     HDC hMaskDC = CreateCompatibleDC(0);
219
220     /* Create a compatible DC. */
221     if (!hOffScreenDC || !hOffScreenBmp || !hImageDC || !hMaskDC) goto cleanup;
222     SelectObject( hOffScreenDC, hOffScreenBmp  );
223
224     hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
225     hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
226
227     /*
228      * Get a copy of the image for the masking operations.
229      * We will use the copy, and this dc for all the various
230      * blitting, and then do one final blit to the screen dc.
231      * This should clean up most of the flickering.
232      */
233     BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
234             pimldp->y, SRCCOPY);
235
236     /*
237      * Draw the Background for the appropriate Styles
238      */
239     if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
240          || bBlendFlag) )
241     {
242
243         HBRUSH hBrush = CreateSolidBrush (clrBk);
244         HBRUSH hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
245
246         PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
247
248         DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
249     }
250
251     /*
252      * Draw Image Transparently over the current background
253      */
254     if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
255        ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
256     {   /*
257          * To obtain a transparent look, background color should be set
258          * to white and foreground color to black when blting the
259          * monochrome mask.
260          */
261
262         COLORREF oldBk = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
263         COLORREF oldFg = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
264
265         BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC,
266                 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
267                 SRCAND );
268
269         BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
270                 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
271                 SRCPAINT );
272
273         SetBkColor( hOffScreenDC, oldBk);
274         SetBkColor( hOffScreenDC, oldFg);
275     }
276
277     /*
278      * Draw the image when no Background is specified
279      */
280     else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
281     {
282         BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
283                 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
284                 SRCCOPY);
285     }
286     /*
287      * Draw the mask with or without a background
288      */
289     else if(fStyle & ILD_MASK)
290     {
291         BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC,
292                 himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
293                 bUseCustomBackground ? SRCCOPY : SRCAND);
294     }
295
296     /*
297      * Blit the bitmap to the screen now.
298      */
299     BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
300             hOffScreenDC, 0, 0, SRCCOPY);
301
302
303     SelectObject(hImageDC, hOldBitmapImage);
304     SelectObject(hMaskDC, hOldBitmapMask);
305
306 cleanup:
307
308     DeleteDC(hImageDC);
309     DeleteDC(hMaskDC);
310
311     DeleteDC( hOffScreenDC );
312     DeleteObject( hOffScreenBmp );
313 }
314
315 /*************************************************************************
316  * IMAGELIST_InternalDrawBlend [Internal]
317  *
318  * Draws the Blend over the current image
319  *
320  * PARAMS
321  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
322  *     cx            [I] the width of the image to display
323  *     cy            [I] the height of the image to display
324  *
325  * RETURNS
326  *     nothing
327  *
328  * NOTES
329  *     This functions is used by ImageList_DrawIndirect, when it is
330  *     required to add the blend to the current image.
331  *
332  */
333 static void
334 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
335 {
336
337     HDC         hBlendMaskDC;
338     HBRUSH      hBlendColorBrush, hBlendBrush, hOldBrush;
339     HBITMAP     hBlendMaskBitmap, hOldBitmap;
340     COLORREF    clrBlend, oldFgColor, oldBkColor;
341     HIMAGELIST  himlLocal = pimldp->himl;
342
343     clrBlend = pimldp->rgbFg;
344     if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
345     else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
346
347     /* Create the blend Mask
348     */
349     hBlendMaskDC = CreateCompatibleDC(0);
350     hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
351         himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
352
353     hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
354     hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
355
356     hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
357     PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
358     SelectObject(hBlendMaskDC, hOldBrush);
359
360     /* Modify the blend mask if an Image Mask exist
361     */
362     if(pimldp->himl->hbmMask != 0)
363     {
364         HBITMAP hOldMaskBitmap;
365         HDC hMaskDC = CreateCompatibleDC(0);
366         hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
367
368         BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskDC,
369                himlLocal->cx * pimldp->i + pimldp->xBitmap, pimldp->yBitmap,
370                0x220326); /* NOTSRCAND */
371
372         BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC,
373                0, 0,
374                NOTSRCCOPY);
375
376         SelectObject(hMaskDC, hOldMaskBitmap);
377         DeleteDC(hMaskDC);
378
379     }
380     /* Apply blend to the current image given the BlendMask
381     */
382     oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 0));
383     oldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
384     hBlendColorBrush = CreateSolidBrush(clrBlend);
385     hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
386
387     BitBlt (pimldp->hdcDst,
388         pimldp->x, pimldp->y, cx, cy,
389         hBlendMaskDC,
390         0, 0,
391         0xB8074A); /* PSDPxax */
392
393     SelectObject(pimldp->hdcDst, hOldBrush);
394     SetTextColor(pimldp->hdcDst, oldFgColor);
395     SetBkColor(pimldp->hdcDst, oldBkColor);
396     SelectObject(hBlendMaskDC, hOldBitmap);
397     DeleteDC(hBlendMaskDC);
398     DeleteObject(hBlendMaskBitmap);
399     DeleteObject(hBlendColorBrush);
400 }
401
402 /*************************************************************************
403  * IMAGELIST_InternalDrawOverlay [Internal]
404  *
405  * Draws the overlay image
406  *
407  * PARAMS
408  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
409  *     cx            [I] the width of the image to display
410  *     cy            [I] the height of the image to display
411  *
412  * RETURNS
413  *     nothing
414  *
415  * NOTES
416  *     This functions is used by ImageList_DrawIndirect, when it is
417  *     required to draw the overlay
418  *
419  *
420  */
421 static void
422 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
423 {
424     INT nOvlIdx;
425     HDC hImageDC;
426     HBITMAP hOldBitmap;
427
428     nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
429     if ( (nOvlIdx < 1) || (nOvlIdx > MAX_OVERLAYIMAGE)) return;
430
431     nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
432     if ((nOvlIdx < 0) || (nOvlIdx > pimldp->himl->cCurImage)) return;
433
434     if (!(hImageDC = CreateCompatibleDC(0))) return;
435
436     if (pimldp->himl->hbmMask) {
437         hOldBitmap = (HBITMAP) SelectObject (hImageDC, pimldp->himl->hbmMask);
438
439         BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC,
440                 pimldp->himl->cx * nOvlIdx + pimldp->xBitmap, pimldp->yBitmap,
441                 SRCAND);
442
443         SelectObject(hImageDC, hOldBitmap);
444     }
445
446     hOldBitmap = (HBITMAP) SelectObject (hImageDC, pimldp->himl->hbmImage);
447
448     BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC,
449             pimldp->himl->cx * nOvlIdx + pimldp->xBitmap, pimldp->yBitmap,
450             SRCPAINT);
451
452     SelectObject(hImageDC, hOldBitmap);
453     DeleteDC(hImageDC);
454 }
455
456
457 /*************************************************************************
458  * ImageList_Add [COMCTL32.@]
459  *
460  * Add an image or images to an image list.
461  *
462  * PARAMS
463  *     himl     [I] handle to image list
464  *     hbmImage [I] handle to image bitmap
465  *     hbmMask  [I] handle to mask bitmap
466  *
467  * RETURNS
468  *     Success: Index of the first new image.
469  *     Failure: -1
470  */
471
472 INT WINAPI
473 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
474 {
475     HDC     hdcImage, hdcBitmap;
476     INT     nFirstIndex, nImageCount;
477     INT     nStartX;
478     BITMAP  bmp;
479     HBITMAP hOldBitmapImage, hOldBitmap;
480
481     TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
482     if (!himl || !hbmImage)
483         return -1;
484
485     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
486     nImageCount = bmp.bmWidth / himl->cx;
487
488     IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
489
490     nStartX = himl->cCurImage * himl->cx;
491
492     hdcImage  = CreateCompatibleDC(0);
493     hdcBitmap = CreateCompatibleDC(0);
494
495     hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
496     hOldBitmap = SelectObject(hdcBitmap, hbmImage);
497
498     /* Copy result to the imagelist
499     */
500     BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
501         hdcBitmap, 0, 0, SRCCOPY);
502
503     if(himl->hbmMask)
504     {
505         HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
506
507         hdcMask   = CreateCompatibleDC (0);
508         hdcTemp   = CreateCompatibleDC(0);
509         hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
510         hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
511
512         BitBlt (hdcMask,
513             nStartX, 0, bmp.bmWidth, bmp.bmHeight,
514             hdcTemp,
515             0, 0,
516             SRCCOPY);
517
518         SelectObject(hdcTemp, hOldBitmapTemp);
519         DeleteDC(hdcTemp);
520
521         /* Remove the background from the image
522         */
523         BitBlt (hdcImage,
524             nStartX, 0, bmp.bmWidth, bmp.bmHeight,
525             hdcMask,
526             nStartX, 0,
527             0x220326); /* NOTSRCAND */
528
529         SelectObject(hdcMask, hOldBitmapMask);
530         DeleteDC(hdcMask);
531     }
532
533     SelectObject(hdcImage, hOldBitmapImage);
534     SelectObject(hdcBitmap, hOldBitmap);
535     DeleteDC(hdcImage);
536     DeleteDC(hdcBitmap);
537
538     nFirstIndex = himl->cCurImage;
539     himl->cCurImage += nImageCount;
540
541     return nFirstIndex;
542 }
543
544
545 /*************************************************************************
546  * ImageList_AddIcon [COMCTL32.@]
547  *
548  * Adds an icon to an image list.
549  *
550  * PARAMS
551  *     himl  [I] handle to image list
552  *     hIcon [I] handle to icon
553  *
554  * RETURNS
555  *     Success: index of the new image
556  *     Failure: -1
557  */
558
559 INT WINAPI
560 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
561 {
562     return ImageList_ReplaceIcon (himl, -1, hIcon);
563 }
564
565
566 /*************************************************************************
567  * ImageList_AddMasked [COMCTL32.@]
568  *
569  * Adds an image or images to an image list and creates a mask from the
570  * specified bitmap using the mask color.
571  *
572  * PARAMS
573  *     himl    [I] handle to image list.
574  *     hBitmap [I] handle to bitmap
575  *     clrMask [I] mask color.
576  *
577  * RETURNS
578  *     Success: Index of the first new image.
579  *     Failure: -1
580  */
581
582 INT WINAPI
583 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
584 {
585     HDC    hdcImage, hdcMask, hdcBitmap;
586     INT    nIndex, nImageCount, nMaskXOffset=0;
587     BITMAP bmp;
588     HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
589     HBITMAP hMaskBitmap=0;
590     COLORREF bkColor;
591
592     TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
593     if (himl == NULL)
594         return -1;
595
596     if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
597         return -1;
598
599     nImageCount = bmp.bmWidth / himl->cx;
600
601     IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
602
603     nIndex = himl->cCurImage;
604     himl->cCurImage += nImageCount;
605
606     hdcMask   = CreateCompatibleDC (0);
607     hdcImage  = CreateCompatibleDC(0);
608     hdcBitmap = CreateCompatibleDC(0);
609
610
611     hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
612     hOldBitmap = SelectObject(hdcBitmap, hBitmap);
613     if(himl->hbmMask)
614     {
615         hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
616         nMaskXOffset = nIndex * himl->cx;
617     }
618     else
619     {
620         /*
621             Create a temp Mask so we can remove the background of
622             the Image (Windows does this even if there is no mask)
623         */
624         hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
625         hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
626         nMaskXOffset = 0;
627     }
628     /* create monochrome image to the mask bitmap */
629     bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
630         GetPixel (hdcBitmap, 0, 0);
631     SetBkColor (hdcBitmap, bkColor);
632     BitBlt (hdcMask,
633         nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
634         hdcBitmap, 0, 0,
635         SRCCOPY);
636
637     SetBkColor(hdcBitmap, RGB(255,255,255));
638     /*Remove the background from the image
639     */
640     /*
641         WINDOWS BUG ALERT!!!!!!
642         The statement below should not be done in common practice
643         but this is how ImageList_AddMasked works in Windows.
644         It overwrites the original bitmap passed, this was discovered
645         by using the same bitmap to iterate the different styles
646         on windows where it failed (BUT ImageList_Add is OK)
647         This is here in case some apps rely on this bug
648     */
649     BitBlt(hdcBitmap,
650         0, 0, bmp.bmWidth, bmp.bmHeight,
651         hdcMask,
652         nMaskXOffset, 0,
653         0x220326); /* NOTSRCAND */
654     /* Copy result to the imagelist
655     */
656     BitBlt (hdcImage,
657         nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
658         hdcBitmap,
659         0, 0,
660         SRCCOPY);
661     /* Clean up
662     */
663     SelectObject(hdcMask,hOldBitmapMask);
664     SelectObject(hdcImage, hOldBitmapImage);
665     SelectObject(hdcBitmap, hOldBitmap);
666     DeleteDC(hdcMask);
667     DeleteDC(hdcImage);
668     DeleteDC(hdcBitmap);
669     if(!himl->hbmMask)
670     {
671         DeleteObject(hMaskBitmap);
672     }
673
674     return nIndex;
675 }
676
677
678 /*************************************************************************
679  * ImageList_BeginDrag [COMCTL32.@]
680  *
681  * Creates a temporary image list that contains one image. It will be used
682  * as a drag image.
683  *
684  * PARAMS
685  *     himlTrack [I] handle to the source image list
686  *     iTrack    [I] index of the drag image in the source image list
687  *     dxHotspot [I] X position of the hot spot of the drag image
688  *     dyHotspot [I] Y position of the hot spot of the drag image
689  *
690  * RETURNS
691  *     Success: TRUE
692  *     Failure: FALSE
693  */
694
695 BOOL WINAPI
696 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
697                      INT dxHotspot, INT dyHotspot)
698 {
699     HDC hdcSrc, hdcDst;
700     INT cx, cy;
701
702     TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
703           dxHotspot, dyHotspot);
704
705     if (himlTrack == NULL)
706         return FALSE;
707
708     if (InternalDrag.himl)
709         ImageList_EndDrag ();
710
711     cx = himlTrack->cx;
712     cy = himlTrack->cy;
713
714     InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
715     if (InternalDrag.himl == NULL) {
716         WARN("Error creating drag image list!\n");
717         return FALSE;
718     }
719
720     InternalDrag.dxHotspot = dxHotspot;
721     InternalDrag.dyHotspot = dyHotspot;
722
723     hdcSrc = CreateCompatibleDC (0);
724     hdcDst = CreateCompatibleDC (0);
725
726     /* copy image */
727     SelectObject (hdcSrc, himlTrack->hbmImage);
728     SelectObject (hdcDst, InternalDrag.himl->hbmImage);
729     BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
730
731     /* copy mask */
732     SelectObject (hdcSrc, himlTrack->hbmMask);
733     SelectObject (hdcDst, InternalDrag.himl->hbmMask);
734     BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
735
736     DeleteDC (hdcSrc);
737     DeleteDC (hdcDst);
738
739     InternalDrag.himl->cCurImage = 1;
740     InternalDrag.bHSPending = TRUE;
741
742     return TRUE;
743 }
744
745
746 /*************************************************************************
747  * ImageList_Copy [COMCTL32.@]
748  *
749  *  Copies an image of the source image list to an image of the
750  *  destination image list. Images can be copied or swapped.
751  *
752  * PARAMS
753  *     himlDst [I] handle to the destination image list
754  *     iDst    [I] destination image index.
755  *     himlSrc [I] handle to the source image list
756  *     iSrc    [I] source image index
757  *     uFlags  [I] flags for the copy operation
758  *
759  * RETURNS
760  *     Success: TRUE
761  *     Failure: FALSE
762  *
763  * NOTES
764  *     Copying from one image list to another is possible. The original
765  *     implementation just copies or swaps within one image list.
766  *     Could this feature become a bug??? ;-)
767  */
768
769 BOOL WINAPI
770 ImageList_Copy (HIMAGELIST himlDst, INT iDst,   HIMAGELIST himlSrc,
771                 INT iSrc, INT uFlags)
772 {
773     HDC hdcSrc, hdcDst;
774
775     TRACE("iDst=%d  iSrc=%d\n", iDst, iSrc);
776
777     if ((himlSrc == NULL) || (himlDst == NULL))
778         return FALSE;
779     if ((iDst < 0) || (iDst >= himlDst->cCurImage))
780         return FALSE;
781     if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
782         return FALSE;
783
784     hdcSrc = CreateCompatibleDC (0);
785     if (himlDst == himlSrc)
786         hdcDst = hdcSrc;
787     else
788         hdcDst = CreateCompatibleDC (0);
789
790     if (uFlags & ILCF_SWAP) {
791         /* swap */
792         HBITMAP hbmTempImage, hbmTempMask;
793
794         /* create temporary bitmaps */
795         hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
796                                        himlSrc->uBitsPixel, NULL);
797         hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
798                                       1, NULL);
799
800         /* copy (and stretch) destination to temporary bitmaps.(save) */
801         /* image */
802         SelectObject (hdcSrc, himlDst->hbmImage);
803         SelectObject (hdcDst, hbmTempImage);
804         StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
805                       hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
806                       SRCCOPY);
807         /* mask */
808         SelectObject (hdcSrc, himlDst->hbmMask);
809         SelectObject (hdcDst, hbmTempMask);
810         StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
811                       hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
812                       SRCCOPY);
813
814         /* copy (and stretch) source to destination */
815         /* image */
816         SelectObject (hdcSrc, himlSrc->hbmImage);
817         SelectObject (hdcDst, himlDst->hbmImage);
818         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
819                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
820                       SRCCOPY);
821         /* mask */
822         SelectObject (hdcSrc, himlSrc->hbmMask);
823         SelectObject (hdcDst, himlDst->hbmMask);
824         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
825                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
826                       SRCCOPY);
827
828         /* copy (without stretching) temporary bitmaps to source (restore) */
829         /* image */
830         SelectObject (hdcSrc, hbmTempImage);
831         SelectObject (hdcDst, himlSrc->hbmImage);
832         BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
833                   hdcSrc, 0, 0, SRCCOPY);
834         /* mask */
835         SelectObject (hdcSrc, hbmTempMask);
836         SelectObject (hdcDst, himlSrc->hbmMask);
837         BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
838                   hdcSrc, 0, 0, SRCCOPY);
839
840         /* delete temporary bitmaps */
841         DeleteObject (hbmTempMask);
842         DeleteObject (hbmTempImage);
843     }
844     else {
845         /* copy image */
846         SelectObject (hdcSrc, himlSrc->hbmImage);
847         if (himlSrc == himlDst)
848             hdcDst = hdcSrc;
849         else
850             SelectObject (hdcDst, himlDst->hbmImage);
851         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
852                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
853                       SRCCOPY);
854
855         /* copy mask */
856         SelectObject (hdcSrc, himlSrc->hbmMask);
857         if (himlSrc == himlDst)
858             hdcDst = hdcSrc;
859         else
860             SelectObject (hdcDst, himlDst->hbmMask);
861         StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
862                       hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
863                       SRCCOPY);
864     }
865
866     DeleteDC (hdcSrc);
867     if (himlSrc != himlDst)
868         DeleteDC (hdcDst);
869
870     return TRUE;
871 }
872
873
874 /*************************************************************************
875  * ImageList_Create [COMCTL32.@]  Creates a new image list.
876  *
877  * PARAMS
878  *     cx       [I] image height
879  *     cy       [I] image width
880  *     flags    [I] creation flags
881  *     cInitial [I] initial number of images in the image list
882  *     cGrow    [I] number of images by which image list grows
883  *
884  * RETURNS
885  *     Success: Handle to the created image list
886  *     Failure: NULL
887  */
888
889 HIMAGELIST WINAPI
890 ImageList_Create (INT cx, INT cy, UINT flags,
891                   INT cInitial, INT cGrow)
892 {
893     HIMAGELIST himl;
894     HDC      hdc;
895     INT      nCount;
896     HBITMAP  hbmTemp;
897     static WORD aBitBlend25[] =
898         {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
899
900     static WORD aBitBlend50[] =
901         {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
902
903     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
904
905     himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
906     if (!himl)
907         return NULL;
908
909     himl->cx        = cx;
910     himl->cy        = cy;
911     himl->flags     = flags;
912     himl->cMaxImage = cInitial + cGrow;
913     himl->cInitial  = cInitial;
914     himl->cGrow     = cGrow;
915     himl->cCurImage = 0;
916     himl->clrFg     = CLR_DEFAULT;
917     himl->clrBk     = CLR_NONE;
918
919     /* initialize overlay mask indices */
920     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
921         himl->nOvlIdx[nCount] = -1;
922
923     hdc = CreateCompatibleDC (0);
924     himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
925     DeleteDC (hdc);
926
927     TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
928
929     if (himl->cMaxImage > 0) {
930         himl->hbmImage =
931           CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
932                         1, himl->uBitsPixel, NULL);
933         if (himl->hbmImage == 0) {
934             ERR("Error creating image bitmap!\n");
935             return NULL;
936         }
937     }
938     else
939         himl->hbmImage = 0;
940
941     if ( (himl->flags & ILC_MASK)) {
942         int images = himl->cMaxImage;
943         if (images <= 0)
944             images = 1;
945
946         himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
947                                         1, 1, NULL);
948         if (himl->hbmMask == 0) {
949             ERR("Error creating mask bitmap!\n");
950             if (himl->hbmImage)
951                 DeleteObject (himl->hbmImage);
952             return NULL;
953         }
954     }
955     else
956         himl->hbmMask = 0;
957
958     /* create blending brushes */
959     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
960     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
961     DeleteObject (hbmTemp);
962
963     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
964     himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
965     DeleteObject (hbmTemp);
966
967     TRACE("created imagelist %p\n", himl);
968     return himl;
969 }
970
971
972 /*************************************************************************
973  * ImageList_Destroy [COMCTL32.@]
974  *
975  * Destroys an image list.
976  *
977  * PARAMS
978  *     himl [I] handle to image list
979  *
980  * RETURNS
981  *     Success: TRUE
982  *     Failure: FALSE
983  */
984
985 BOOL WINAPI
986 ImageList_Destroy (HIMAGELIST himl)
987 {
988     if (!himl)
989         return FALSE;
990
991     /* delete image bitmaps */
992     if (himl->hbmImage)
993         DeleteObject (himl->hbmImage);
994     if (himl->hbmMask)
995         DeleteObject (himl->hbmMask);
996
997     /* delete blending brushes */
998     if (himl->hbrBlend25)
999         DeleteObject (himl->hbrBlend25);
1000     if (himl->hbrBlend50)
1001         DeleteObject (himl->hbrBlend50);
1002
1003     COMCTL32_Free (himl);
1004
1005     return TRUE;
1006 }
1007
1008
1009 /*************************************************************************
1010  * ImageList_DragEnter [COMCTL32.@]
1011  *
1012  * Locks window update and displays the drag image at the given position.
1013  *
1014  * PARAMS
1015  *     hwndLock [I] handle of the window that owns the drag image.
1016  *     x        [I] X position of the drag image.
1017  *     y        [I] Y position of the drag image.
1018  *
1019  * RETURNS
1020  *     Success: TRUE
1021  *     Failure: FALSE
1022  *
1023  * NOTES
1024  *     The position of the drag image is relative to the window, not
1025  *     the client area.
1026  */
1027
1028 BOOL WINAPI
1029 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1030 {
1031     TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1032
1033     if (InternalDrag.himl == NULL)
1034         return FALSE;
1035
1036     if (hwndLock)
1037         InternalDrag.hwnd = hwndLock;
1038     else
1039         InternalDrag.hwnd = GetDesktopWindow ();
1040
1041     InternalDrag.x = x;
1042     InternalDrag.y = y;
1043
1044     /* draw the drag image and save the background */
1045     if (!ImageList_DragShowNolock(TRUE)) {
1046         return FALSE;
1047     }
1048
1049     return TRUE;
1050 }
1051
1052
1053 /*************************************************************************
1054  * ImageList_DragLeave [COMCTL32.@]
1055  *
1056  * Unlocks window update and hides the drag image.
1057  *
1058  * PARAMS
1059  *     hwndLock [I] handle of the window that owns the drag image.
1060  *
1061  * RETURNS
1062  *     Success: TRUE
1063  *     Failure: FALSE
1064  */
1065
1066 BOOL WINAPI
1067 ImageList_DragLeave (HWND hwndLock)
1068 {
1069     /* As we don't save drag info in the window this can lead to problems if
1070        an app does not supply the same window as DragEnter */
1071     /* if (hwndLock)
1072         InternalDrag.hwnd = hwndLock;
1073     else
1074         InternalDrag.hwnd = GetDesktopWindow (); */
1075     if(!hwndLock)
1076         hwndLock = GetDesktopWindow();
1077     if(InternalDrag.hwnd != hwndLock)
1078         FIXME("DragLeave hWnd != DragEnter hWnd\n");
1079
1080     ImageList_DragShowNolock (FALSE);
1081
1082     return TRUE;
1083 }
1084
1085
1086 /*************************************************************************
1087  * ImageList_DragMove [COMCTL32.@]
1088  *
1089  * Moves the drag image.
1090  *
1091  * PARAMS
1092  *     x [I] X position of the drag image.
1093  *     y [I] Y position of the drag image.
1094  *
1095  * RETURNS
1096  *     Success: TRUE
1097  *     Failure: FALSE
1098  *
1099  * NOTES
1100  *     The position of the drag image is relative to the window, not
1101  *     the client area.
1102  *
1103  * BUGS
1104  *     The drag image should be drawn semitransparent.
1105  */
1106
1107 BOOL WINAPI
1108 ImageList_DragMove (INT x, INT y)
1109 {
1110     TRACE("(x=%d y=%d)\n", x, y);
1111
1112     if (!InternalDrag.himl) {
1113         return FALSE;
1114     }
1115
1116     /* draw/update the drag image */
1117     if (InternalDrag.bShow) {
1118         HDC hdcDrag;
1119         HDC hdcOffScreen;
1120         HDC hdcBg;
1121         HBITMAP hbmOffScreen;
1122         INT origNewX, origNewY;
1123         INT origOldX, origOldY;
1124         INT origRegX, origRegY;
1125         INT sizeRegX, sizeRegY;
1126
1127
1128         /* calculate the update region */
1129         origNewX = x - InternalDrag.dxHotspot;
1130         origNewY = y - InternalDrag.dyHotspot;
1131         origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1132         origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1133         origRegX = min(origNewX, origOldX);
1134         origRegY = min(origNewY, origOldY);
1135         sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1136         sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1137
1138         hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1139                           DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1140         hdcOffScreen = CreateCompatibleDC(hdcDrag);
1141         hdcBg = CreateCompatibleDC(hdcDrag);
1142
1143         hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1144         SelectObject(hdcOffScreen, hbmOffScreen);
1145         SelectObject(hdcBg, InternalDrag.hbmBg);
1146
1147         /* get the actual background of the update region */
1148         BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1149                origRegX, origRegY, SRCCOPY);
1150         /* erase the old image */
1151         BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1152                InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1153                SRCCOPY);
1154         /* save the background */
1155         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1156                hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1157         /* draw the image */
1158         /* FIXME: image should be drawn semitransparent */
1159         ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1160                        origNewY - origRegY, ILD_NORMAL);
1161         /* draw the update region to the screen */
1162         BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1163                hdcOffScreen, 0, 0, SRCCOPY);
1164
1165         DeleteDC(hdcBg);
1166         DeleteDC(hdcOffScreen);
1167         DeleteObject(hbmOffScreen);
1168         ReleaseDC(InternalDrag.hwnd, hdcDrag);
1169     }
1170
1171     /* update the image position */
1172     InternalDrag.x = x;
1173     InternalDrag.y = y;
1174
1175     return TRUE;
1176 }
1177
1178
1179 /*************************************************************************
1180  * ImageList_DragShowNolock [COMCTL32.@]
1181  *
1182  * Shows or hides the drag image.
1183  *
1184  * PARAMS
1185  *     bShow [I] TRUE shows the drag image, FALSE hides it.
1186  *
1187  * RETURNS
1188  *     Success: TRUE
1189  *     Failure: FALSE
1190  *
1191  * BUGS
1192  *     The drag image should be drawn semitransparent.
1193  */
1194
1195 BOOL WINAPI
1196 ImageList_DragShowNolock (BOOL bShow)
1197 {
1198     HDC hdcDrag;
1199     HDC hdcBg;
1200     INT x, y;
1201
1202     TRACE("bShow=0x%X!\n", bShow);
1203
1204     /* DragImage is already visible/hidden */
1205     if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1206         return FALSE;
1207     }
1208
1209     /* position of the origin of the DragImage */
1210     x = InternalDrag.x - InternalDrag.dxHotspot;
1211     y = InternalDrag.y - InternalDrag.dyHotspot;
1212
1213     hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1214                          DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1215     if (!hdcDrag) {
1216         return FALSE;
1217     }
1218
1219     hdcBg = CreateCompatibleDC(hdcDrag);
1220     if (!InternalDrag.hbmBg) {
1221         InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1222                     InternalDrag.himl->cx, InternalDrag.himl->cy);
1223     }
1224     SelectObject(hdcBg, InternalDrag.hbmBg);
1225
1226     if (bShow) {
1227         /* save the background */
1228         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1229                hdcDrag, x, y, SRCCOPY);
1230         /* show the image */
1231         /* FIXME: this should be drawn semitransparent */
1232         ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1233     } else {
1234         /* hide the image */
1235         BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1236                hdcBg, 0, 0, SRCCOPY);
1237     }
1238
1239     InternalDrag.bShow = !InternalDrag.bShow;
1240
1241     DeleteDC(hdcBg);
1242     ReleaseDC (InternalDrag.hwnd, hdcDrag);
1243     return TRUE;
1244 }
1245
1246
1247 /*************************************************************************
1248  * ImageList_Draw [COMCTL32.@] Draws an image.
1249  *
1250  * PARAMS
1251  *     himl   [I] handle to image list
1252  *     i      [I] image index
1253  *     hdc    [I] handle to device context
1254  *     x      [I] x position
1255  *     y      [I] y position
1256  *     fStyle [I] drawing flags
1257  *
1258  * RETURNS
1259  *     Success: TRUE
1260  *     Failure: FALSE
1261  *
1262  * NOTES
1263  *     Calls ImageList_DrawIndirect.
1264  *
1265  * SEE
1266  *     ImageList_DrawIndirect.
1267  */
1268
1269 BOOL WINAPI
1270 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1271                 INT x, INT y, UINT fStyle)
1272 {
1273     IMAGELISTDRAWPARAMS imldp;
1274
1275     imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
1276     imldp.himl    = himl;
1277     imldp.i       = i;
1278     imldp.hdcDst  = hdc,
1279     imldp.x       = x;
1280     imldp.y       = y;
1281     imldp.cx      = 0;
1282     imldp.cy      = 0;
1283     imldp.xBitmap = 0;
1284     imldp.yBitmap = 0;
1285     imldp.rgbBk   = CLR_DEFAULT;
1286     imldp.rgbFg   = CLR_DEFAULT;
1287     imldp.fStyle  = fStyle;
1288     imldp.dwRop   = 0;
1289
1290     return ImageList_DrawIndirect (&imldp);
1291 }
1292
1293
1294 /*************************************************************************
1295  * ImageList_DrawEx [COMCTL32.@]
1296  *
1297  * Draws an image and allows to use extended drawing features.
1298  *
1299  * PARAMS
1300  *     himl   [I] handle to image list
1301  *     i      [I] image index
1302  *     hdc    [I] handle to device context
1303  *     x      [I] X position
1304  *     y      [I] Y position
1305  *     dx     [I] X offset
1306  *     dy     [I] Y offset
1307  *     rgbBk  [I] background color
1308  *     rgbFg  [I] foreground color
1309  *     fStyle [I] drawing flags
1310  *
1311  * RETURNS
1312  *     Success: TRUE
1313  *     Failure: FALSE
1314  *
1315  * NOTES
1316  *     Calls ImageList_DrawIndirect.
1317  *
1318  * SEE
1319  *     ImageList_DrawIndirect.
1320  */
1321
1322 BOOL WINAPI
1323 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1324                   INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1325                   UINT fStyle)
1326 {
1327     IMAGELISTDRAWPARAMS imldp;
1328
1329     imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
1330     imldp.himl    = himl;
1331     imldp.i       = i;
1332     imldp.hdcDst  = hdc,
1333     imldp.x       = x;
1334     imldp.y       = y;
1335     imldp.cx      = dx;
1336     imldp.cy      = dy;
1337     imldp.xBitmap = 0;
1338     imldp.yBitmap = 0;
1339     imldp.rgbBk   = rgbBk;
1340     imldp.rgbFg   = rgbFg;
1341     imldp.fStyle  = fStyle;
1342     imldp.dwRop   = 0;
1343
1344     return ImageList_DrawIndirect (&imldp);
1345 }
1346
1347
1348 /*************************************************************************
1349  * ImageList_DrawIndirect [COMCTL32.@]
1350  *
1351  * Draws an image using ...
1352  *
1353  * PARAMS
1354  *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1355  *
1356  * RETURNS
1357  *     Success: TRUE
1358  *     Failure: FALSE
1359  */
1360
1361 BOOL WINAPI
1362 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1363 {
1364     INT      cx, cy;
1365     /*
1366         Do some Error Checking
1367     */
1368     if (pimldp == NULL)
1369         return FALSE;
1370     if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1371         return FALSE;
1372     if (pimldp->himl == NULL)
1373         return FALSE;
1374     if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1375         return FALSE;
1376     }
1377     /*
1378         Get the Height and Width to display
1379     */
1380     cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1381     cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1382     /*
1383         Draw the image
1384     */
1385
1386     TRACE("hbmMask(0x%08x) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1387         pimldp->himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1388
1389     if(pimldp->himl->hbmMask != 0)
1390     {
1391         IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1392     }
1393     else
1394     {
1395         IMAGELIST_InternalDraw(pimldp, cx, cy);
1396     }
1397     /*
1398         Apply the blend if needed to the Image
1399     */
1400     if((pimldp->fStyle & ILD_BLEND50)
1401         || (pimldp->fStyle & ILD_BLEND25))
1402     {
1403         IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1404     }
1405     /*
1406         Apply the Overlay if needed
1407     */
1408     if (pimldp->fStyle & ILD_OVERLAYMASK)
1409     {
1410         IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1411     }
1412
1413     return TRUE;
1414 }
1415
1416
1417 /*************************************************************************
1418  * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1419  *
1420  * PARAMS
1421  *     himlSrc [I] source image list handle
1422  *
1423  * RETURNS
1424  *     Success: Handle of duplicated image list.
1425  *     Failure: NULL
1426  */
1427
1428 HIMAGELIST WINAPI
1429 ImageList_Duplicate (HIMAGELIST himlSrc)
1430 {
1431     HIMAGELIST himlDst;
1432     HDC hdcSrc, hdcDst;
1433
1434     if (himlSrc == NULL) {
1435         ERR("Invalid image list handle!\n");
1436         return NULL;
1437     }
1438
1439     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1440                                 himlSrc->cInitial, himlSrc->cGrow);
1441
1442     if (himlDst)
1443     {
1444         hdcSrc = CreateCompatibleDC (0);
1445         hdcDst = CreateCompatibleDC (0);
1446         SelectObject (hdcSrc, himlSrc->hbmImage);
1447         SelectObject (hdcDst, himlDst->hbmImage);
1448         BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1449                   hdcSrc, 0, 0, SRCCOPY);
1450
1451         if (himlDst->hbmMask)
1452         {
1453             SelectObject (hdcSrc, himlSrc->hbmMask);
1454             SelectObject (hdcDst, himlDst->hbmMask);
1455             BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1456                       himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1457         }
1458
1459         DeleteDC (hdcDst);
1460         DeleteDC (hdcSrc);
1461
1462         himlDst->cCurImage = himlSrc->cCurImage;
1463         himlDst->cMaxImage = himlSrc->cMaxImage;
1464     }
1465     return himlDst;
1466 }
1467
1468
1469 /*************************************************************************
1470  * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1471  *
1472  * Finishes a drag operation.
1473  *
1474  * PARAMS
1475  *     no Parameters
1476  *
1477  * RETURNS
1478  *     Success: TRUE
1479  *     Failure: FALSE
1480  */
1481
1482 BOOL WINAPI
1483 ImageList_EndDrag (void)
1484 {
1485     /* cleanup the InternalDrag struct */
1486     InternalDrag.hwnd = 0;
1487     ImageList_Destroy (InternalDrag.himl);
1488     InternalDrag.himl = 0;
1489     InternalDrag.x= 0;
1490     InternalDrag.y= 0;
1491     InternalDrag.dxHotspot = 0;
1492     InternalDrag.dyHotspot = 0;
1493     InternalDrag.bShow = FALSE;
1494     DeleteObject(InternalDrag.hbmBg);
1495     InternalDrag.hbmBg = 0;
1496     InternalDrag.bHSPending = FALSE;
1497
1498     return TRUE;
1499 }
1500
1501
1502 /*************************************************************************
1503  * ImageList_GetBkColor [COMCTL32.@]
1504  *
1505  * Returns the background color of an image list.
1506  *
1507  * PARAMS
1508  *     himl [I] Image list handle.
1509  *
1510  * RETURNS
1511  *     Success: background color
1512  *     Failure: CLR_NONE
1513  */
1514
1515 COLORREF WINAPI
1516 ImageList_GetBkColor (HIMAGELIST himl)
1517 {
1518     return himl ? himl->clrBk : CLR_NONE;
1519 }
1520
1521
1522 /*************************************************************************
1523  * ImageList_GetDragImage [COMCTL32.@]
1524  *
1525  * Returns the handle to the internal drag image list.
1526  *
1527  * PARAMS
1528  *     ppt        [O] Pointer to the drag position. Can be NULL.
1529  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1530  *
1531  * RETURNS
1532  *     Success: Handle of the drag image list.
1533  *     Failure: NULL.
1534  */
1535
1536 HIMAGELIST WINAPI
1537 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1538 {
1539     if (InternalDrag.himl) {
1540         if (ppt) {
1541             ppt->x = InternalDrag.x;
1542             ppt->y = InternalDrag.y;
1543         }
1544         if (pptHotspot) {
1545             pptHotspot->x = InternalDrag.dxHotspot;
1546             pptHotspot->y = InternalDrag.dyHotspot;
1547         }
1548         return (InternalDrag.himl);
1549     }
1550
1551     return NULL;
1552 }
1553
1554
1555 /*************************************************************************
1556  * ImageList_GetFlags [COMCTL32.@]
1557  *
1558  * BUGS
1559  *    Stub.
1560  */
1561
1562 DWORD WINAPI
1563 ImageList_GetFlags(HIMAGELIST himl)
1564 {
1565     FIXME("(%p):empty stub\n", himl);
1566     return 0;
1567 }
1568
1569
1570 /*************************************************************************
1571  * ImageList_GetIcon [COMCTL32.@]
1572  *
1573  * Creates an icon from a masked image of an image list.
1574  *
1575  * PARAMS
1576  *     himl  [I] handle to image list
1577  *     i     [I] image index
1578  *     flags [I] drawing style flags
1579  *
1580  * RETURNS
1581  *     Success: icon handle
1582  *     Failure: NULL
1583  */
1584
1585 HICON WINAPI
1586 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1587 {
1588     ICONINFO ii;
1589     HICON hIcon;
1590     HBITMAP hOldDstBitmap;
1591     HDC hdcDst;
1592
1593     if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1594
1595     hdcDst = CreateCompatibleDC(0);
1596
1597     ii.fIcon = TRUE;
1598
1599     /* draw mask*/
1600     ii.hbmMask  = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1601     hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1602     ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1603
1604     /* draw image*/
1605     SelectObject (hdcDst, himl->hbmImage);
1606     ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1607     SelectObject (hdcDst, ii.hbmColor);
1608     ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1609
1610     /*
1611      * CreateIconIndirect requires us to deselect the bitmaps from
1612      * the DCs before calling
1613      */
1614     SelectObject(hdcDst, hOldDstBitmap);
1615
1616     hIcon = CreateIconIndirect (&ii);
1617
1618     DeleteObject (ii.hbmMask);
1619     DeleteObject (ii.hbmColor);
1620     DeleteDC (hdcDst);
1621
1622     return hIcon;
1623 }
1624
1625
1626 /*************************************************************************
1627  * ImageList_GetIconSize [COMCTL32.@]
1628  *
1629  * Retrieves the size of an image in an image list.
1630  *
1631  * PARAMS
1632  *     himl [I] handle to image list
1633  *     cx   [O] pointer to the image width.
1634  *     cy   [O] pointer to the image height.
1635  *
1636  * RETURNS
1637  *     Success: TRUE
1638  *     Failure: FALSE
1639  *
1640  * NOTES
1641  *     All images in an image list have the same size.
1642  */
1643
1644 BOOL WINAPI
1645 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1646 {
1647     if (himl == NULL)
1648         return FALSE;
1649     if ((himl->cx <= 0) || (himl->cy <= 0))
1650         return FALSE;
1651
1652     if (cx)
1653         *cx = himl->cx;
1654     if (cy)
1655         *cy = himl->cy;
1656
1657     return TRUE;
1658 }
1659
1660
1661 /*************************************************************************
1662  * ImageList_GetImageCount [COMCTL32.@]
1663  *
1664  * Returns the number of images in an image list.
1665  *
1666  * PARAMS
1667  *     himl [I] handle to image list
1668  *
1669  * RETURNS
1670  *     Success: Number of images.
1671  *     Failure: 0
1672  */
1673
1674 INT WINAPI
1675 ImageList_GetImageCount (HIMAGELIST himl)
1676 {
1677     if (himl == NULL)
1678         return 0;
1679
1680     return himl->cCurImage;
1681 }
1682
1683
1684 /*************************************************************************
1685  * ImageList_GetImageInfo [COMCTL32.@]
1686  *
1687  * Returns information about an image in an image list.
1688  *
1689  * PARAMS
1690  *     himl       [I] handle to image list
1691  *     i          [I] image index
1692  *     pImageInfo [O] pointer to the image information
1693  *
1694  * RETURNS
1695  *     Success: TRUE
1696  *     Failure: FALSE
1697  */
1698
1699 BOOL WINAPI
1700 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1701 {
1702     if ((himl == NULL) || (pImageInfo == NULL))
1703         return FALSE;
1704     if ((i < 0) || (i >= himl->cCurImage))
1705         return FALSE;
1706
1707     pImageInfo->hbmImage = himl->hbmImage;
1708     pImageInfo->hbmMask  = himl->hbmMask;
1709
1710     pImageInfo->rcImage.top    = 0;
1711     pImageInfo->rcImage.bottom = himl->cy;
1712     pImageInfo->rcImage.left   = i * himl->cx;
1713     pImageInfo->rcImage.right  = (i+1) * himl->cx;
1714
1715     return TRUE;
1716 }
1717
1718
1719 /*************************************************************************
1720  * ImageList_GetImageRect [COMCTL32.@]
1721  *
1722  * Retrieves the rectangle of the specified image in an image list.
1723  *
1724  * PARAMS
1725  *     himl   [I] handle to image list
1726  *     i      [I] image index
1727  *     lpRect [O] pointer to the image rectangle
1728  *
1729  * RETURNS
1730  *    Success: TRUE
1731  *    Failure: FALSE
1732  *
1733  * NOTES
1734  *    This is an UNDOCUMENTED function!!!
1735  */
1736
1737 BOOL WINAPI
1738 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1739 {
1740     if ((himl == NULL) || (lpRect == NULL))
1741         return FALSE;
1742     if ((i < 0) || (i >= himl->cCurImage))
1743         return FALSE;
1744
1745     lpRect->left   = i * himl->cx;
1746     lpRect->top    = 0;
1747     lpRect->right  = lpRect->left + himl->cx;
1748     lpRect->bottom = himl->cy;
1749
1750     return TRUE;
1751 }
1752
1753
1754 /*************************************************************************
1755  * ImageList_LoadImage  [COMCTL32.@]
1756  * ImageList_LoadImageA [COMCTL32.@]
1757  *
1758  * Creates an image list from a bitmap, icon or cursor.
1759  *
1760  * PARAMS
1761  *     hi      [I] instance handle
1762  *     lpbmp   [I] name or id of the image
1763  *     cx      [I] width of each image
1764  *     cGrow   [I] number of images to expand
1765  *     clrMask [I] mask color
1766  *     uType   [I] type of image to load
1767  *     uFlags  [I] loading flags
1768  *
1769  * RETURNS
1770  *     Success: handle to the loaded image list
1771  *     Failure: NULL
1772  *
1773  * SEE
1774  *     LoadImage ()
1775  */
1776
1777 HIMAGELIST WINAPI
1778 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1779                         COLORREF clrMask, UINT uType, UINT uFlags)
1780 {
1781     HIMAGELIST himl = NULL;
1782     HANDLE   handle;
1783     INT      nImageCount;
1784
1785     handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1786     if (!handle) {
1787         ERR("Error loading image!\n");
1788         return NULL;
1789     }
1790
1791     if (uType == IMAGE_BITMAP) {
1792         BITMAP bmp;
1793         GetObjectA (handle, sizeof(BITMAP), &bmp);
1794
1795         /* To match windows behavior, if cx is set to zero and
1796          the flag DI_DEFAULTSIZE is specified, cx becomes the
1797          system metric value for icons. If the flag is not specified
1798          the function sets the size to the height of the bitmap */
1799         if (cx == 0)
1800         {
1801             if (uFlags & DI_DEFAULTSIZE)
1802                 cx = GetSystemMetrics (SM_CXICON);
1803             else
1804                 cx = bmp.bmHeight;
1805         }
1806
1807         nImageCount = bmp.bmWidth / cx;
1808
1809         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1810                                  nImageCount, cGrow);
1811         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1812     }
1813     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1814         ICONINFO ii;
1815         BITMAP bmp;
1816
1817         GetIconInfo (handle, &ii);
1818         GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1819         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1820                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1821         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1822         DeleteObject (ii.hbmColor);
1823         DeleteObject (ii.hbmMask);
1824     }
1825
1826     DeleteObject (handle);
1827
1828     return himl;
1829 }
1830
1831
1832 /*************************************************************************
1833  * ImageList_LoadImageW [COMCTL32.@]
1834  *
1835  * Creates an image list from a bitmap, icon or cursor.
1836  *
1837  * PARAMS
1838  *     hi      [I] instance handle
1839  *     lpbmp   [I] name or id of the image
1840  *     cx      [I] width of each image
1841  *     cGrow   [I] number of images to expand
1842  *     clrMask [I] mask color
1843  *     uType   [I] type of image to load
1844  *     uFlags  [I] loading flags
1845  *
1846  * RETURNS
1847  *     Success: handle to the loaded image list
1848  *     Failure: NULL
1849  *
1850  * SEE
1851  *     LoadImage ()
1852  */
1853
1854 HIMAGELIST WINAPI
1855 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1856                         COLORREF clrMask, UINT uType,   UINT uFlags)
1857 {
1858     HIMAGELIST himl = NULL;
1859     HANDLE   handle;
1860     INT      nImageCount;
1861
1862     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1863     if (!handle) {
1864         ERR("Error loading image!\n");
1865         return NULL;
1866     }
1867
1868     if (uType == IMAGE_BITMAP) {
1869         BITMAP bmp;
1870         GetObjectA (handle, sizeof(BITMAP), &bmp);
1871
1872         /* To match windows behavior, if cx is set to zero and
1873          the flag DI_DEFAULTSIZE is specified, cx becomes the
1874          system metric value for icons. If the flag is not specified
1875          the function sets the size to the height of the bitmap */
1876         if (cx == 0)
1877         {
1878             if (uFlags & DI_DEFAULTSIZE)
1879                 cx = GetSystemMetrics (SM_CXICON);
1880             else
1881                 cx = bmp.bmHeight;
1882         }
1883
1884         nImageCount = bmp.bmWidth / cx;
1885
1886         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1887                                  nImageCount, cGrow);
1888         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1889     }
1890     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1891         ICONINFO ii;
1892         BITMAP bmp;
1893
1894         GetIconInfo (handle, &ii);
1895         GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1896         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1897                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1898         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1899         DeleteObject (ii.hbmColor);
1900         DeleteObject (ii.hbmMask);
1901     }
1902
1903     DeleteObject (handle);
1904
1905     return himl;
1906 }
1907
1908
1909 /*************************************************************************
1910  * ImageList_Merge [COMCTL32.@]
1911  *
1912  * Creates a new image list that contains a merged image from the specified
1913  * images of both source image lists.
1914  *
1915  * PARAMS
1916  *     himl1 [I] handle to first image list
1917  *     i1    [I] first image index
1918  *     himl2 [I] handle to second image list
1919  *     i2    [I] second image index
1920  *     dx    [I] X offset of the second image relative to the first.
1921  *     dy    [I] Y offset of the second image relative to the first.
1922  *
1923  * RETURNS
1924  *     Success: handle of the merged image list.
1925  *     Failure: NULL
1926  */
1927
1928 HIMAGELIST WINAPI
1929 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1930                  INT dx, INT dy)
1931 {
1932     HIMAGELIST himlDst = NULL;
1933     HDC      hdcSrcImage, hdcDstImage;
1934     INT      cxDst, cyDst;
1935     INT      xOff1, yOff1, xOff2, yOff2;
1936     INT      nX1, nX2;
1937
1938     TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1939            i2, dx, dy);
1940
1941     if ((himl1 == NULL) || (himl2 == NULL))
1942         return NULL;
1943
1944     /* check indices */
1945     if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1946         ERR("Index 1 out of range! %d\n", i1);
1947         return NULL;
1948     }
1949
1950     if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1951         ERR("Index 2 out of range! %d\n", i2);
1952         return NULL;
1953     }
1954
1955     if (dx > 0) {
1956         cxDst = max (himl1->cx, dx + himl2->cx);
1957         xOff1 = 0;
1958         xOff2 = dx;
1959     }
1960     else if (dx < 0) {
1961         cxDst = max (himl2->cx, himl1->cx - dx);
1962         xOff1 = -dx;
1963         xOff2 = 0;
1964     }
1965     else {
1966         cxDst = max (himl1->cx, himl2->cx);
1967         xOff1 = 0;
1968         xOff2 = 0;
1969     }
1970
1971     if (dy > 0) {
1972         cyDst = max (himl1->cy, dy + himl2->cy);
1973         yOff1 = 0;
1974         yOff2 = dy;
1975     }
1976     else if (dy < 0) {
1977         cyDst = max (himl2->cy, himl1->cy - dy);
1978         yOff1 = -dy;
1979         yOff2 = 0;
1980     }
1981     else {
1982         cyDst = max (himl1->cy, himl2->cy);
1983         yOff1 = 0;
1984         yOff2 = 0;
1985     }
1986
1987     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1988
1989     if (himlDst) {
1990         hdcSrcImage = CreateCompatibleDC (0);
1991         hdcDstImage = CreateCompatibleDC (0);
1992         nX1 = i1 * himl1->cx;
1993         nX2 = i2 * himl2->cx;
1994
1995         /* copy image */
1996         SelectObject (hdcSrcImage, himl1->hbmImage);
1997         SelectObject (hdcDstImage, himlDst->hbmImage);
1998         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1999                   hdcSrcImage, 0, 0, BLACKNESS);
2000         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2001                   hdcSrcImage, nX1, 0, SRCCOPY);
2002
2003         SelectObject (hdcSrcImage, himl2->hbmMask);
2004         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2005                   hdcSrcImage, nX2, 0, SRCAND);
2006
2007         SelectObject (hdcSrcImage, himl2->hbmImage);
2008         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2009                   hdcSrcImage, nX2, 0, SRCPAINT);
2010
2011         /* copy mask */
2012         SelectObject (hdcSrcImage, himl1->hbmMask);
2013         SelectObject (hdcDstImage, himlDst->hbmMask);
2014         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2015                   hdcSrcImage, 0, 0, WHITENESS);
2016         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2017                   hdcSrcImage, nX1, 0, SRCCOPY);
2018
2019         SelectObject (hdcSrcImage, himl2->hbmMask);
2020         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2021                   hdcSrcImage, nX2, 0, SRCAND);
2022
2023         DeleteDC (hdcSrcImage);
2024         DeleteDC (hdcDstImage);
2025         himlDst->cCurImage = 1;
2026     }
2027
2028     return himlDst;
2029 }
2030
2031
2032 /* helper for _read_bitmap currently unused */
2033 #if 0
2034 static int may_use_dibsection(HDC hdc) {
2035     int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2036     if (bitspixel>8)
2037         return TRUE;
2038     if (bitspixel<=4)
2039         return FALSE;
2040     return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2041 }
2042 #endif
2043
2044 /* helper for ImageList_Read, see comments below */
2045 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2046     HDC                 xdc = 0;
2047     BITMAPFILEHEADER    bmfh;
2048     BITMAPINFOHEADER    bmih;
2049     int                 bitsperpixel,palspace,longsperline,width,height;
2050     LPBITMAPINFOHEADER  bmihc = NULL;
2051     int                 result = 0;
2052     HBITMAP             hbitmap = 0;
2053     LPBYTE              bits = NULL,nbits = NULL;
2054     int                 nbytesperline,bytesperline;
2055
2056     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
2057         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
2058         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
2059         (bmih.biSize != sizeof(bmih))
2060     )
2061         return 0;
2062
2063     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2064     if (bitsperpixel<=8)
2065         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2066     else
2067         palspace = 0;
2068     width = bmih.biWidth;
2069     height = bmih.biHeight;
2070     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2071     memcpy(bmihc,&bmih,sizeof(bmih));
2072     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
2073     bmihc->biSizeImage  = (longsperline*height)<<2;
2074
2075     /* read the palette right after the end of the bitmapinfoheader */
2076     if (palspace)
2077         if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2078             goto ret1;
2079
2080     xdc = GetDC(0);
2081 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2082     if ((bitsperpixel>1) &&
2083         ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2084      ) {
2085         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2086         if (!hbitmap)
2087             goto ret1;
2088         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2089             goto ret1;
2090         result = 1;
2091     } else
2092 #endif
2093     {
2094         int i,nwidth,nheight;
2095
2096         nwidth  = width*(height/cy);
2097         nheight = cy;
2098
2099         if (bitsperpixel==1)
2100             hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2101         else
2102             hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2103
2104         /* Might be a bit excessive memory use here */
2105         bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2106         nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2107         if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2108                 goto ret1;
2109
2110         /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2111         /* Do not forget that windows bitmaps are bottom->top */
2112         bytesperline    = longsperline*4;
2113         nbytesperline   = (height/cy)*bytesperline;
2114         for (i=0;i<height;i++) {
2115             memcpy(
2116                 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2117                 bits+bytesperline*(height-1-i),
2118                 bytesperline
2119             );
2120         }
2121         bmihc->biWidth  = nwidth;
2122         bmihc->biHeight = nheight;
2123         if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2124                 goto ret1;
2125         LocalFree((HLOCAL)nbits);
2126         LocalFree((HLOCAL)bits);
2127         result = 1;
2128     }
2129 ret1:
2130     if (xdc)    ReleaseDC(0,xdc);
2131     if (bmihc)  LocalFree((HLOCAL)bmihc);
2132     if (!result) {
2133         if (hbitmap) {
2134             DeleteObject(hbitmap);
2135             hbitmap = 0;
2136         }
2137     }
2138     return hbitmap;
2139 }
2140
2141 /*************************************************************************
2142  * ImageList_Read [COMCTL32.@]
2143  *
2144  * Reads an image list from a stream.
2145  *
2146  * PARAMS
2147  *     pstm [I] pointer to a stream
2148  *
2149  * RETURNS
2150  *     Success: handle to image list
2151  *     Failure: NULL
2152  *
2153  * The format is like this:
2154  *      ILHEAD                  ilheadstruct;
2155  *
2156  * for the color image part:
2157  *      BITMAPFILEHEADER        bmfh;
2158  *      BITMAPINFOHEADER        bmih;
2159  * only if it has a palette:
2160  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2161  *
2162  *      BYTE                    colorbits[imagesize];
2163  *
2164  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2165  *      BITMAPFILEHEADER        bmfh_mask;
2166  *      BITMAPINFOHEADER        bmih_mask;
2167  * only if it has a palette (it usually does not):
2168  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2169  *
2170  *      BYTE                    maskbits[imagesize];
2171  *
2172  * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2173  *         _read_bitmap needs to convert them.
2174  */
2175 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2176 {
2177     ILHEAD      ilHead;
2178     HIMAGELIST  himl;
2179     HBITMAP     hbmColor=0,hbmMask=0;
2180     int         i;
2181
2182     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2183         return NULL;
2184     if (ilHead.usMagic != (('L' << 8) | 'I'))
2185         return NULL;
2186     if (ilHead.usVersion != 0x101) /* probably version? */
2187         return NULL;
2188
2189 #if 0
2190     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
2191     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2192     FIXME("     ilHead.cGrow = %d\n",ilHead.cGrow);
2193     FIXME("     ilHead.cx = %d\n",ilHead.cx);
2194     FIXME("     ilHead.cy = %d\n",ilHead.cy);
2195     FIXME("     ilHead.flags = %x\n",ilHead.flags);
2196     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2197     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2198     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2199     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2200 #endif
2201
2202     hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2203     if (!hbmColor)
2204         return NULL;
2205     if (ilHead.flags & ILC_MASK) {
2206         hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2207         if (!hbmMask) {
2208             DeleteObject(hbmColor);
2209             return NULL;
2210         }
2211     }
2212
2213     himl = ImageList_Create (
2214                     ilHead.cx,
2215                     ilHead.cy,
2216                     ilHead.flags,
2217                     1,          /* initial */
2218                     ilHead.cGrow
2219     );
2220     if (!himl) {
2221         DeleteObject(hbmColor);
2222         DeleteObject(hbmMask);
2223         return NULL;
2224     }
2225     himl->hbmImage = hbmColor;
2226     himl->hbmMask = hbmMask;
2227     himl->cCurImage = ilHead.cCurImage;
2228     himl->cMaxImage = ilHead.cMaxImage;
2229
2230     ImageList_SetBkColor(himl,ilHead.bkcolor);
2231     for (i=0;i<4;i++)
2232         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2233     return himl;
2234 }
2235
2236
2237 /*************************************************************************
2238  * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2239  *
2240  * PARAMS
2241  *     himl [I] image list handle
2242  *     i    [I] image index
2243  *
2244  * RETURNS
2245  *     Success: TRUE
2246  *     Failure: FALSE
2247  */
2248
2249 BOOL WINAPI
2250 ImageList_Remove (HIMAGELIST himl, INT i)
2251 {
2252     HBITMAP hbmNewImage, hbmNewMask;
2253     HDC     hdcSrc, hdcDst;
2254     INT     cxNew, nCount;
2255
2256     TRACE("(himl=%p i=%d)\n", himl, i);
2257
2258     if (himl == NULL) {
2259         ERR("Invalid image list handle!\n");
2260         return FALSE;
2261     }
2262
2263     if ((i < -1) || (i >= himl->cCurImage)) {
2264         ERR("index out of range! %d\n", i);
2265         return FALSE;
2266     }
2267
2268     if (i == -1) {
2269         /* remove all */
2270         if (himl->cCurImage == 0) {
2271             /* remove all on empty ImageList is allowed */
2272             TRACE("remove all on empty ImageList!\n");
2273             return TRUE;
2274         }
2275
2276         himl->cMaxImage = himl->cInitial + himl->cGrow;
2277         himl->cCurImage = 0;
2278         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2279              himl->nOvlIdx[nCount] = -1;
2280
2281         DeleteObject (himl->hbmImage);
2282         himl->hbmImage =
2283             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2284                             1, himl->uBitsPixel, NULL);
2285
2286         if (himl->hbmMask) {
2287             DeleteObject (himl->hbmMask);
2288             himl->hbmMask =
2289                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2290                                 1, 1, NULL);
2291         }
2292     }
2293     else {
2294         /* delete one image */
2295         TRACE("Remove single image! %d\n", i);
2296
2297         /* create new bitmap(s) */
2298         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2299
2300         TRACE(" - Number of images: %d / %d (Old/New)\n",
2301                  himl->cCurImage, himl->cCurImage - 1);
2302         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2303                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2304
2305         hbmNewImage =
2306             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2307
2308         if (himl->hbmMask)
2309             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2310         else
2311             hbmNewMask = 0;  /* Just to keep compiler happy! */
2312
2313         hdcSrc = CreateCompatibleDC (0);
2314         hdcDst = CreateCompatibleDC (0);
2315
2316         /* copy all images and masks prior to the "removed" image */
2317         if (i > 0) {
2318             TRACE("Pre image copy: Copy %d images\n", i);
2319
2320             SelectObject (hdcSrc, himl->hbmImage);
2321             SelectObject (hdcDst, hbmNewImage);
2322             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2323                       hdcSrc, 0, 0, SRCCOPY);
2324
2325             if (himl->hbmMask) {
2326                 SelectObject (hdcSrc, himl->hbmMask);
2327                 SelectObject (hdcDst, hbmNewMask);
2328                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2329                           hdcSrc, 0, 0, SRCCOPY);
2330             }
2331         }
2332
2333         /* copy all images and masks behind the removed image */
2334         if (i < himl->cCurImage - 1) {
2335             TRACE("Post image copy!\n");
2336             SelectObject (hdcSrc, himl->hbmImage);
2337             SelectObject (hdcDst, hbmNewImage);
2338             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2339                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2340
2341             if (himl->hbmMask) {
2342                 SelectObject (hdcSrc, himl->hbmMask);
2343                 SelectObject (hdcDst, hbmNewMask);
2344                 BitBlt (hdcDst, i * himl->cx, 0,
2345                           (himl->cCurImage - i - 1) * himl->cx,
2346                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2347             }
2348         }
2349
2350         DeleteDC (hdcSrc);
2351         DeleteDC (hdcDst);
2352
2353         /* delete old images and insert new ones */
2354         DeleteObject (himl->hbmImage);
2355         himl->hbmImage = hbmNewImage;
2356         if (himl->hbmMask) {
2357             DeleteObject (himl->hbmMask);
2358             himl->hbmMask = hbmNewMask;
2359         }
2360
2361         himl->cCurImage--;
2362         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2363     }
2364
2365     return TRUE;
2366 }
2367
2368
2369 /*************************************************************************
2370  * ImageList_Replace [COMCTL32.@]
2371  *
2372  * Replaces an image in an image list with a new image.
2373  *
2374  * PARAMS
2375  *     himl     [I] handle to image list
2376  *     i        [I] image index
2377  *     hbmImage [I] handle to image bitmap
2378  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2379  *
2380  * RETURNS
2381  *     Success: TRUE
2382  *     Failure: FALSE
2383  */
2384
2385 BOOL WINAPI
2386 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2387                    HBITMAP hbmMask)
2388 {
2389     HDC hdcImageList, hdcImage;
2390     BITMAP bmp;
2391
2392     TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2393
2394     if (himl == NULL) {
2395         ERR("Invalid image list handle!\n");
2396         return FALSE;
2397     }
2398
2399     if ((i >= himl->cMaxImage) || (i < 0)) {
2400         ERR("Invalid image index!\n");
2401         return FALSE;
2402     }
2403
2404     hdcImageList = CreateCompatibleDC (0);
2405     hdcImage = CreateCompatibleDC (0);
2406     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2407
2408     /* Replace Image */
2409     SelectObject (hdcImageList, himl->hbmImage);
2410     SelectObject (hdcImage, hbmImage);
2411
2412     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2413                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2414
2415     if (himl->hbmMask)
2416     {
2417         /* Replace Mask */
2418         SelectObject (hdcImageList, himl->hbmMask);
2419         SelectObject (hdcImage, hbmMask);
2420
2421         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2422                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2423
2424
2425         /* Remove the background from the image
2426         */
2427         SelectObject (hdcImageList, himl->hbmImage);
2428         StretchBlt (hdcImageList,
2429             i*himl->cx, 0, himl->cx, himl->cy,
2430             hdcImage,
2431             0, 0, bmp.bmWidth, bmp.bmHeight,
2432             0x220326); /* NOTSRCAND */
2433     }
2434
2435     DeleteDC (hdcImage);
2436     DeleteDC (hdcImageList);
2437
2438     return TRUE;
2439 }
2440
2441
2442 /*************************************************************************
2443  * ImageList_ReplaceIcon [COMCTL32.@]
2444  *
2445  * Replaces an image in an image list using an icon.
2446  *
2447  * PARAMS
2448  *     himl  [I] handle to image list
2449  *     i     [I] image index
2450  *     hIcon [I] handle to icon
2451  *
2452  * RETURNS
2453  *     Success: index of the replaced image
2454  *     Failure: -1
2455  */
2456
2457 INT WINAPI
2458 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2459 {
2460     HDC     hdcImageList, hdcImage;
2461     INT     nIndex;
2462     HICON   hBestFitIcon;
2463     HBITMAP hbmOldSrc, hbmOldDst;
2464     ICONINFO  ii;
2465     BITMAP  bmp;
2466
2467     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2468
2469     if (himl == NULL)
2470         return -1;
2471     if ((i >= himl->cMaxImage) || (i < -1))
2472         return -1;
2473
2474     hBestFitIcon = CopyImage(
2475         hIcon, IMAGE_ICON,
2476         himl->cx, himl->cy,
2477         LR_COPYFROMRESOURCE);
2478
2479     GetIconInfo (hBestFitIcon, &ii);
2480     if (ii.hbmMask == 0)
2481         ERR("no mask!\n");
2482     if (ii.hbmColor == 0)
2483         ERR("no color!\n");
2484     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2485
2486     if (i == -1) {
2487         if (himl->cCurImage + 1 > himl->cMaxImage)
2488             IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2489
2490         nIndex = himl->cCurImage;
2491         himl->cCurImage++;
2492     }
2493     else
2494         nIndex = i;
2495
2496     hdcImageList = CreateCompatibleDC (0);
2497     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2498     if (hdcImageList == 0)
2499         ERR("invalid hdcImageList!\n");
2500
2501     hdcImage = CreateCompatibleDC (0);
2502     TRACE("hdcImage=0x%x!\n", hdcImage);
2503     if (hdcImage == 0)
2504         ERR("invalid hdcImage!\n");
2505
2506     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2507     SetTextColor( hdcImageList, RGB(0,0,0));
2508     SetBkColor( hdcImageList, RGB(255,255,255));
2509     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2510     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2511                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2512
2513     if (himl->hbmMask) {
2514         SelectObject (hdcImageList, himl->hbmMask);
2515         SelectObject (hdcImage, ii.hbmMask);
2516         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2517                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2518     }
2519
2520     SelectObject (hdcImage, hbmOldSrc);
2521     SelectObject (hdcImageList, hbmOldDst);
2522
2523     if(hBestFitIcon)
2524         DestroyIcon(hBestFitIcon);
2525     if (hdcImageList)
2526         DeleteDC (hdcImageList);
2527     if (hdcImage)
2528         DeleteDC (hdcImage);
2529     if (ii.hbmColor)
2530         DeleteObject (ii.hbmColor);
2531     if (ii.hbmMask)
2532         DeleteObject (ii.hbmMask);
2533
2534     return nIndex;
2535 }
2536
2537
2538 /*************************************************************************
2539  * ImageList_SetBkColor [COMCTL32.@]
2540  *
2541  * Sets the background color of an image list.
2542  *
2543  * PARAMS
2544  *     himl  [I] handle to image list
2545  *     clrBk [I] background color
2546  *
2547  * RETURNS
2548  *     Success: previous background color
2549  *     Failure: CLR_NONE
2550  */
2551
2552 COLORREF WINAPI
2553 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2554 {
2555     COLORREF clrOldBk;
2556
2557     if (himl == NULL)
2558         return CLR_NONE;
2559
2560     clrOldBk = himl->clrBk;
2561     himl->clrBk = clrBk;
2562     return clrOldBk;
2563 }
2564
2565
2566 /*************************************************************************
2567  * ImageList_SetDragCursorImage [COMCTL32.@]
2568  *
2569  * Combines the specified image with the current drag image
2570  *
2571  * PARAMS
2572  *     himlDrag  [I] handle to drag image list
2573  *     iDrag     [I] drag image index
2574  *     dxHotspot [I] X position of the hot spot
2575  *     dyHotspot [I] Y position of the hot spot
2576  *
2577  * RETURNS
2578  *     Success: TRUE
2579  *     Failure: FALSE
2580  *
2581  * NOTES
2582  *     When this function is called and the drag image is visible, a
2583  *     short flickering occurs but this matches the Win9x behavior. It is
2584  *     possible to fix the flickering using code like in ImageList_DragMove.
2585  */
2586
2587 BOOL WINAPI
2588 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2589                               INT dxHotspot, INT dyHotspot)
2590 {
2591     HIMAGELIST himlTemp;
2592     INT dx, dy;
2593     BOOL visible;
2594
2595     if (InternalDrag.himl == NULL)
2596         return FALSE;
2597
2598     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2599            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2600
2601     visible = InternalDrag.bShow;
2602
2603     /* Calculate the offset between the origin of the old image and the
2604      * origin of the second image.
2605      * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2606      * hotspot) to the origin of the second image.
2607      * See M$DN for details */
2608     if(InternalDrag.bHSPending) {
2609         dx = 0;
2610         dy = 0;
2611         InternalDrag.bHSPending = FALSE;
2612     } else {
2613         dx = InternalDrag.dxHotspot - dxHotspot;
2614         dy = InternalDrag.dyHotspot - dyHotspot;
2615     }
2616     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2617
2618     if (visible) {
2619         /* hide the drag image */
2620         ImageList_DragShowNolock(FALSE);
2621     }
2622     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2623            (InternalDrag.himl->cy != himlTemp->cy)) {
2624         /* the size of the drag image changed, invalidate the buffer */
2625         DeleteObject(InternalDrag.hbmBg);
2626         InternalDrag.hbmBg = 0;
2627     }
2628
2629     ImageList_Destroy (InternalDrag.himl);
2630     InternalDrag.himl = himlTemp;
2631
2632     /* update the InternalDragOffset, if the origin of the
2633      * DragImage was changed by ImageList_Merge. */
2634     if (dx <= 0)
2635         InternalDrag.dxHotspot = dxHotspot;
2636     if (dy <= 0)
2637         InternalDrag.dyHotspot = dyHotspot;
2638
2639     if (visible) {
2640         /* show the drag image */
2641         ImageList_DragShowNolock(TRUE);
2642     }
2643
2644     return TRUE;
2645 }
2646
2647
2648 /*************************************************************************
2649  * ImageList_SetFilter [COMCTL32.@]
2650  *
2651  * Sets a filter (or does something completely different)!!???
2652  * It removes 12 Bytes from the stack (3 Parameters).
2653  *
2654  * PARAMS
2655  *     himl     [I] SHOULD be a handle to image list
2656  *     i        [I] COULD be an index?
2657  *     dwFilter [I] ???
2658  *
2659  * RETURNS
2660  *     Success: TRUE ???
2661  *     Failure: FALSE ???
2662  *
2663  * BUGS
2664  *     This is an UNDOCUMENTED function!!!!
2665  *     empty stub.
2666  */
2667
2668 BOOL WINAPI
2669 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2670 {
2671     FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2672
2673     return FALSE;
2674 }
2675
2676
2677 /*************************************************************************
2678  * ImageList_SetFlags [COMCTL32.@]
2679  *
2680  * BUGS
2681  *    Stub.
2682  */
2683
2684 DWORD WINAPI
2685 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2686 {
2687     FIXME("(%p %08lx):empty stub\n", himl, flags);
2688     return 0;
2689 }
2690
2691
2692 /*************************************************************************
2693  * ImageList_SetIconSize [COMCTL32.@]
2694  *
2695  * Sets the image size of the bitmap and deletes all images.
2696  *
2697  * PARAMS
2698  *     himl [I] handle to image list
2699  *     cx   [I] image width
2700  *     cy   [I] image height
2701  *
2702  * RETURNS
2703  *     Success: TRUE
2704  *     Failure: FALSE
2705  */
2706
2707 BOOL WINAPI
2708 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2709 {
2710     INT nCount;
2711
2712     if (!himl)
2713         return FALSE;
2714
2715     /* remove all images */
2716     himl->cMaxImage = himl->cInitial + himl->cGrow;
2717     himl->cCurImage = 0;
2718     himl->cx        = cx;
2719     himl->cy        = cy;
2720
2721     /* initialize overlay mask indices */
2722     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2723         himl->nOvlIdx[nCount] = -1;
2724
2725     DeleteObject (himl->hbmImage);
2726     himl->hbmImage =
2727         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2728                         1, himl->uBitsPixel, NULL);
2729
2730     if (himl->hbmMask) {
2731         DeleteObject (himl->hbmMask);
2732         himl->hbmMask =
2733             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2734                             1, 1, NULL);
2735     }
2736
2737     return TRUE;
2738 }
2739
2740
2741 /*************************************************************************
2742  * ImageList_SetImageCount [COMCTL32.@]
2743  *
2744  * Resizes an image list to the specified number of images.
2745  *
2746  * PARAMS
2747  *     himl        [I] handle to image list
2748  *     iImageCount [I] number of images in the image list
2749  *
2750  * RETURNS
2751  *     Success: TRUE
2752  *     Failure: FALSE
2753  */
2754
2755 BOOL WINAPI
2756 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2757 {
2758     HDC     hdcImageList, hdcBitmap;
2759     HBITMAP hbmNewBitmap;
2760     INT     nNewCount, nCopyCount;
2761
2762     TRACE("%p %d\n",himl,iImageCount);
2763
2764     if (!himl)
2765         return FALSE;
2766     if (himl->cCurImage >= iImageCount)
2767         return FALSE;
2768     if (himl->cMaxImage > iImageCount)
2769     {
2770         himl->cCurImage = iImageCount;
2771         return TRUE;
2772     }
2773
2774     nNewCount = iImageCount + himl->cGrow;
2775     nCopyCount = min(himl->cCurImage, iImageCount);
2776
2777     hdcImageList = CreateCompatibleDC (0);
2778     hdcBitmap = CreateCompatibleDC (0);
2779
2780     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2781                                    1, himl->uBitsPixel, NULL);
2782     if (hbmNewBitmap != 0)
2783     {
2784         SelectObject (hdcImageList, himl->hbmImage);
2785         SelectObject (hdcBitmap, hbmNewBitmap);
2786
2787         /* copy images */
2788         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2789                   hdcImageList, 0, 0, SRCCOPY);
2790 #if 0
2791         /* delete 'empty' image space */
2792         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2793         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2794         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2795                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2796 #endif
2797         DeleteObject (himl->hbmImage);
2798         himl->hbmImage = hbmNewBitmap;
2799     }
2800     else
2801         ERR("Could not create new image bitmap !\n");
2802
2803     if (himl->hbmMask)
2804     {
2805         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2806                                        1, 1, NULL);
2807         if (hbmNewBitmap != 0)
2808         {
2809             SelectObject (hdcImageList, himl->hbmMask);
2810             SelectObject (hdcBitmap, hbmNewBitmap);
2811
2812             /* copy images */
2813             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2814                       hdcImageList, 0, 0, SRCCOPY);
2815 #if 0
2816             /* delete 'empty' image space */
2817             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2818             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2819             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2820                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2821 #endif
2822             DeleteObject (himl->hbmMask);
2823             himl->hbmMask = hbmNewBitmap;
2824         }
2825         else
2826             ERR("Could not create new mask bitmap!\n");
2827     }
2828
2829     DeleteDC (hdcImageList);
2830     DeleteDC (hdcBitmap);
2831
2832     /* Update max image count and current image count */
2833     himl->cMaxImage = nNewCount;
2834     himl->cCurImage = iImageCount;
2835
2836     return TRUE;
2837 }
2838
2839
2840 /*************************************************************************
2841  * ImageList_SetOverlayImage [COMCTL32.@]
2842  *
2843  * Assigns an overlay mask index to an existing image in an image list.
2844  *
2845  * PARAMS
2846  *     himl     [I] handle to image list
2847  *     iImage   [I] image index
2848  *     iOverlay [I] overlay mask index
2849  *
2850  * RETURNS
2851  *     Success: TRUE
2852  *     Failure: FALSE
2853  */
2854
2855 BOOL WINAPI
2856 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2857 {
2858     if (!himl)
2859         return FALSE;
2860     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2861         return FALSE;
2862     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2863         return FALSE;
2864     himl->nOvlIdx[iOverlay - 1] = iImage;
2865     return TRUE;
2866 }
2867
2868
2869
2870 /* helper for ImageList_Write - write bitmap to pstm
2871  * currently everything is written as 24 bit RGB, except masks
2872  */
2873 static BOOL
2874 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2875 {
2876     LPBITMAPFILEHEADER bmfh;
2877     LPBITMAPINFOHEADER bmih;
2878     LPBYTE data, lpBits, lpBitsOrg;
2879     BITMAP bm;
2880     INT bitCount, sizeImage, offBits, totalSize;
2881     INT nwidth, nheight, nsizeImage, icount;
2882     HDC xdc;
2883     BOOL result = FALSE;
2884
2885
2886     xdc = GetDC(0);
2887     GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2888
2889     /* XXX is this always correct? */
2890     icount = bm.bmWidth / cx;
2891     nwidth = cx << 2;
2892     nheight = cy * ((icount+3)>>2);
2893
2894     bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2895     sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2896     nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2897
2898     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2899     if(bitCount != 24)
2900         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2901     offBits = totalSize;
2902     totalSize += nsizeImage;
2903
2904     data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2905     bmfh = (LPBITMAPFILEHEADER)data;
2906     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2907     lpBits = data + offBits;
2908
2909     /* setup BITMAPFILEHEADER */
2910     bmfh->bfType      = (('M' << 8) | 'B');
2911     bmfh->bfSize      = 0;
2912     bmfh->bfReserved1 = 0;
2913     bmfh->bfReserved2 = 0;
2914     bmfh->bfOffBits   = offBits;
2915
2916     /* setup BITMAPINFOHEADER */
2917     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2918     bmih->biWidth         = bm.bmWidth;
2919     bmih->biHeight        = bm.bmHeight;
2920     bmih->biPlanes        = 1;
2921     bmih->biBitCount      = bitCount;
2922     bmih->biCompression   = BI_RGB;
2923     bmih->biSizeImage     = nsizeImage;
2924     bmih->biXPelsPerMeter = 0;
2925     bmih->biYPelsPerMeter = 0;
2926     bmih->biClrUsed       = 0;
2927     bmih->biClrImportant  = 0;
2928
2929     lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2930     if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2931                   (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2932         goto failed;
2933     else {
2934         int i;
2935         int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2936         int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2937
2938         for(i = 0; i < nheight; i++) {
2939             int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2940             int noff = (nbpl * (nheight-1-i));
2941             memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2942         }
2943     }
2944
2945     bmih->biWidth  = nwidth;
2946     bmih->biHeight = nheight;
2947
2948     if(bitCount == 1) {
2949         /* Hack. */
2950         LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2951         inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2952         inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2953     }
2954
2955     if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2956         goto failed;
2957
2958     result = TRUE;
2959
2960     failed:
2961     ReleaseDC(0, xdc);
2962     LocalFree((HLOCAL)lpBitsOrg);
2963
2964     return result;
2965 }
2966
2967
2968 /*************************************************************************
2969  * ImageList_Write [COMCTL32.@]
2970  *
2971  * Writes an image list to a stream.
2972  *
2973  * PARAMS
2974  *     himl [I] handle to image list
2975  *     pstm [O] Pointer to a stream.
2976  *
2977  * RETURNS
2978  *     Success: TRUE
2979  *     Failure: FALSE
2980  *
2981  * BUGS
2982  *     probably.
2983  */
2984
2985 BOOL WINAPI
2986 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2987 {
2988     ILHEAD ilHead;
2989     int i;
2990
2991     if (!himl)
2992         return FALSE;
2993
2994     ilHead.usMagic   = (('L' << 8) | 'I');
2995     ilHead.usVersion = 0x101;
2996     ilHead.cCurImage = himl->cCurImage;
2997     ilHead.cMaxImage = himl->cMaxImage;
2998     ilHead.cGrow     = himl->cGrow;
2999     ilHead.cx        = himl->cx;
3000     ilHead.cy        = himl->cy;
3001     ilHead.bkcolor   = himl->clrBk;
3002     ilHead.flags     = himl->flags;
3003     for(i = 0; i < 4; i++) {
3004         ilHead.ovls[i] = himl->nOvlIdx[i];
3005     }
3006
3007     if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3008         return FALSE;
3009
3010     /* write the bitmap */
3011     if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3012         return FALSE;
3013
3014     /* write the mask if we have one */
3015     if(himl->flags & ILC_MASK) {
3016         if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
3017             return FALSE;
3018     }
3019
3020     return TRUE;
3021 }