imagelist.c 78.1 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *  ImageList implementation
 *
 *  Copyright 1998 Eric Kohl
5
 *  Copyright 2000 Jason Mawdsley
6
 *  Copyright 2001, 2004 Michael Stefaniuc
7 8
 *  Copyright 2001 Charles Loep for CodeWeavers
 *  Copyright 2002 Dimitrie O. Paun
Alexandre Julliard's avatar
Alexandre Julliard committed
9
 *
10 11 12 13 14 15 16 17 18 19 20 21
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23
 *
24
 * NOTE
25
 *
26 27
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
28
 *
Mike Hearn's avatar
Mike Hearn committed
29
 * Unless otherwise noted, we believe this code to be complete, as per
30 31
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
32
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
33
 *  TODO:
34 35
 *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
 *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
36
 *    - Thread-safe locking
Alexandre Julliard's avatar
Alexandre Julliard committed
37 38
 */

39
#include <stdarg.h>
40
#include <stdlib.h>
41
#include <string.h>
42 43 44

#define COBJMACROS

45
#include "winerror.h"
46
#include "windef.h"
47
#include "winbase.h"
48
#include "objbase.h"
49 50
#include "wingdi.h"
#include "winuser.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
51
#include "commctrl.h"
52
#include "comctl32.h"
53
#include "imagelist.h"
54
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
55

56
WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
57

Alexandre Julliard's avatar
Alexandre Julliard committed
58

Alexandre Julliard's avatar
Alexandre Julliard committed
59 60
#define MAX_OVERLAYIMAGE 15

Alexandre Julliard's avatar
Alexandre Julliard committed
61
/* internal image list data used for Drag & Drop operations */
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
typedef struct
{
    HWND	hwnd;
    HIMAGELIST	himl;
    /* position of the drag image relative to the window */
    INT		x;
    INT		y;
    /* offset of the hotspot relative to the origin of the image */
    INT		dxHotspot;
    INT		dyHotspot;
    /* is the drag image visible */
    BOOL	bShow;
    /* saved background */
    HBITMAP	hbmBg;
} INTERNALDRAG;
Alexandre Julliard's avatar
Alexandre Julliard committed
77

78
static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
Alexandre Julliard's avatar
Alexandre Julliard committed
79

80
static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width);
Alexandre Julliard's avatar
Alexandre Julliard committed
81

82 83 84 85 86
static inline BOOL is_valid(HIMAGELIST himl)
{
    return himl && himl->magic == IMAGELIST_MAGIC;
}

87 88 89 90 91 92 93 94 95 96 97 98 99
/*
 * An imagelist with N images is tiled like this:
 *
 *   N/4 ->
 *
 * 4 048C..
 *   159D..
 * | 26AE.N
 * V 37BF.
 */

#define TILE_COUNT 4

100
static inline UINT imagelist_height( UINT count )
101 102 103 104
{
    return ((count + TILE_COUNT - 1)/TILE_COUNT);
}

105 106
static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
{
107 108
    pt->x = (index%TILE_COUNT) * himl->cx;
    pt->y = (index/TILE_COUNT) * himl->cy;
109
}
Alexandre Julliard's avatar
Alexandre Julliard committed
110

111
static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cx, SIZE *sz )
112
{
113 114
    sz->cx = cx * TILE_COUNT;
    sz->cy = imagelist_height( count ) * himl->cy;
115 116
}

117 118 119 120 121 122
/*
 * imagelist_copy_images()
 *
 * Copies a block of count images from offset src in the list to offset dest.
 * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
 */
123 124 125 126 127
static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
                                          UINT src, UINT count, UINT dest )
{
    POINT ptSrc, ptDest;
    SIZE sz;
128 129 130 131 132 133
    UINT i;

    for ( i=0; i<TILE_COUNT; i++ )
    {
        imagelist_point_from_index( himl, src+i, &ptSrc );
        imagelist_point_from_index( himl, dest+i, &ptDest );
134 135
        sz.cx = himl->cx;
        sz.cy = himl->cy * imagelist_height( count - i );
136 137 138 139

        BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
                hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
    }
140 141
}

Alexandre Julliard's avatar
Alexandre Julliard committed
142
/*************************************************************************
143
 * IMAGELIST_InternalExpandBitmaps [Internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
144 145
 *
 * Expands the bitmaps of an image list by the given number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
146
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
147
 * PARAMS
148 149
 *     himl        [I] handle to image list
 *     nImageCount [I] number of images to add
Alexandre Julliard's avatar
Alexandre Julliard committed
150 151 152 153 154
 *
 * RETURNS
 *     nothing
 *
 * NOTES
155
 *     This function CANNOT be used to reduce the number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
156
 */
157
static void
158
IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
159
{
160 161
    HDC     hdcBitmap;
    HBITMAP hbmNewBitmap, hbmNull;
162
    INT     nNewCount;
163
    SIZE    sz;
Alexandre Julliard's avatar
Alexandre Julliard committed
164

165
    if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
166 167
        && (himl->cy >= cy))
	return;
Alexandre Julliard's avatar
Alexandre Julliard committed
168

169
    if (cx == 0) cx = himl->cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
170
    nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
Alexandre Julliard's avatar
Alexandre Julliard committed
171

172
    imagelist_get_bitmap_size(himl, nNewCount, cx, &sz);
173 174

    TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
175
    hdcBitmap = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
176

177
    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, cx);
178

Alexandre Julliard's avatar
Alexandre Julliard committed
179
    if (hbmNewBitmap == 0)
180
        ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
181 182

    if (himl->cCurImage)
183 184
    {
        hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
185
        BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
186 187 188
                himl->hdcImage, 0, 0, SRCCOPY);
        SelectObject (hdcBitmap, hbmNull);
    }
189
    SelectObject (himl->hdcImage, hbmNewBitmap);
190
    DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
191 192
    himl->hbmImage = hbmNewBitmap;

193 194
    if (himl->flags & ILC_MASK)
    {
195
        hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
196 197

        if (hbmNewBitmap == 0)
198
            ERR("creating new mask bitmap!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
199

200 201 202
	if(himl->cCurImage)
	{
	    hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
203
	    BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
204 205 206
		    himl->hdcMask, 0, 0, SRCCOPY);
	    SelectObject (hdcBitmap, hbmNull);
	}
207
        SelectObject (himl->hdcMask, hbmNewBitmap);
208
        DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
209 210 211
        himl->hbmMask = hbmNewBitmap;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
212 213
    himl->cMaxImage = nNewCount;

214
    DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
215 216 217
}


Alexandre Julliard's avatar
Alexandre Julliard committed
218
/*************************************************************************
219
 * ImageList_Add [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
220 221
 *
 * Add an image or images to an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
222
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
223
 * PARAMS
224 225 226
 *     himl     [I] handle to image list
 *     hbmImage [I] handle to image bitmap
 *     hbmMask  [I] handle to mask bitmap
Alexandre Julliard's avatar
Alexandre Julliard committed
227
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
228 229 230
 * RETURNS
 *     Success: Index of the first new image.
 *     Failure: -1
Alexandre Julliard's avatar
Alexandre Julliard committed
231 232
 */

233 234
INT WINAPI
ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
235
{
236 237
    HDC     hdcBitmap, hdcTemp;
    INT     nFirstIndex, nImageCount, i;
238
    BITMAP  bmp;
239
    HBITMAP hOldBitmap, hOldBitmapTemp;
240
    POINT   pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
241

242
    TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
243
    if (!is_valid(himl))
244
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
245

246 247 248
    if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
        return -1;

Alexandre Julliard's avatar
Alexandre Julliard committed
249 250
    nImageCount = bmp.bmWidth / himl->cx;

251
    IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
Alexandre Julliard's avatar
Alexandre Julliard committed
252

253
    hdcBitmap = CreateCompatibleDC(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
254

255 256
    hOldBitmap = SelectObject(hdcBitmap, hbmImage);

257
    for (i=0; i<nImageCount; i++)
258
    {
259 260 261 262 263 264 265 266 267
        imagelist_point_from_index( himl, himl->cCurImage + i, &pt );

        /* Copy result to the imagelist
        */
        BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                hdcBitmap, i*himl->cx, 0, SRCCOPY );

        if (!himl->hbmMask)
             continue;
268 269

        hdcTemp   = CreateCompatibleDC(0);
270
        hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
271

272 273
        BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
                hdcTemp, i*himl->cx, 0, SRCCOPY );
274 275 276 277 278 279

        SelectObject(hdcTemp, hOldBitmapTemp);
        DeleteDC(hdcTemp);

        /* Remove the background from the image
        */
280 281
        BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
Alexandre Julliard's avatar
Alexandre Julliard committed
282 283
    }

284 285
    SelectObject(hdcBitmap, hOldBitmap);
    DeleteDC(hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
286 287 288 289

    nFirstIndex = himl->cCurImage;
    himl->cCurImage += nImageCount;

Alexandre Julliard's avatar
Alexandre Julliard committed
290
    return nFirstIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
291 292 293
}


Alexandre Julliard's avatar
Alexandre Julliard committed
294
/*************************************************************************
295
 * ImageList_AddIcon [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
296 297 298 299
 *
 * Adds an icon to an image list.
 *
 * PARAMS
300 301
 *     himl  [I] handle to image list
 *     hIcon [I] handle to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
302 303 304 305 306
 *
 * RETURNS
 *     Success: index of the new image
 *     Failure: -1
 */
307 308
#undef ImageList_AddIcon
INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
309
{
310
    return ImageList_ReplaceIcon (himl, -1, hIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
311 312 313
}


Alexandre Julliard's avatar
Alexandre Julliard committed
314
/*************************************************************************
315
 * ImageList_AddMasked [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
316
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
317 318
 * Adds an image or images to an image list and creates a mask from the
 * specified bitmap using the mask color.
Alexandre Julliard's avatar
Alexandre Julliard committed
319
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
320
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
321 322 323
 *     himl    [I] handle to image list.
 *     hBitmap [I] handle to bitmap
 *     clrMask [I] mask color.
Alexandre Julliard's avatar
Alexandre Julliard committed
324 325 326 327
 *
 * RETURNS
 *     Success: Index of the first new image.
 *     Failure: -1
Alexandre Julliard's avatar
Alexandre Julliard committed
328 329
 */

330 331
INT WINAPI
ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
332
{
333
    HDC    hdcMask, hdcBitmap;
334
    INT    i, nIndex, nImageCount;
335
    BITMAP bmp;
336
    HBITMAP hOldBitmap;
337 338
    HBITMAP hMaskBitmap=0;
    COLORREF bkColor;
339
    POINT  pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
340

341
    TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
342
    if (!is_valid(himl))
343
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
344

345
    if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
346
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
347

348 349 350 351
    if (himl->cx > 0)
	nImageCount = bmp.bmWidth / himl->cx;
    else
	nImageCount = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
352

353
    IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355 356 357

    nIndex = himl->cCurImage;
    himl->cCurImage += nImageCount;

358
    hdcBitmap = CreateCompatibleDC(0);
359
    hOldBitmap = SelectObject(hdcBitmap, hBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
360

361 362 363 364
    /* Create a temp Mask so we can remove the background of the Image */
    hdcMask = CreateCompatibleDC(0);
    hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
    SelectObject(hdcMask, hMaskBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
365

366
    /* create monochrome image to the mask bitmap */
367
    bkColor = (clrMask != CLR_DEFAULT) ? clrMask : GetPixel (hdcBitmap, 0, 0);
368
    SetBkColor (hdcBitmap, bkColor);
369
    BitBlt (hdcMask, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
370 371

    SetBkColor(hdcBitmap, RGB(255,255,255));
372

373
    /*
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
     * Remove the background from the image
     *
     * WINDOWS BUG ALERT!!!!!!
     *  The statement below should not be done in common practice
     *  but this is how ImageList_AddMasked works in Windows.
     *  It overwrites the original bitmap passed, this was discovered
     *  by using the same bitmap to iterate the different styles
     *  on windows where it failed (BUT ImageList_Add is OK)
     *  This is here in case some apps rely on this bug
     *
     *  Blt mode 0x220326 is NOTSRCAND
     */
    BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);

    /* Copy result to the imagelist */
    for (i=0; i<nImageCount; i++)
390
    {
391 392 393 394 395
        imagelist_point_from_index( himl, nIndex + i, &pt );
        BitBlt(himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                hdcBitmap, i*himl->cx, 0, SRCCOPY);
        BitBlt(himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
                hdcMask, i*himl->cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397
    }

398 399 400 401 402 403
    /* Clean up */
    SelectObject(hdcBitmap, hOldBitmap);
    DeleteDC(hdcBitmap);
    DeleteObject(hMaskBitmap);
    DeleteDC(hdcMask);

Alexandre Julliard's avatar
Alexandre Julliard committed
404
    return nIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
405 406 407
}


Alexandre Julliard's avatar
Alexandre Julliard committed
408
/*************************************************************************
409
 * ImageList_BeginDrag [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
410
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
411 412
 * Creates a temporary image list that contains one image. It will be used
 * as a drag image.
Alexandre Julliard's avatar
Alexandre Julliard committed
413
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
414
 * PARAMS
415 416
 *     himlTrack [I] handle to the source image list
 *     iTrack    [I] index of the drag image in the source image list
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418 419 420 421 422
 *     dxHotspot [I] X position of the hot spot of the drag image
 *     dyHotspot [I] Y position of the hot spot of the drag image
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
423 424
 */

425 426 427
BOOL WINAPI
ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
	             INT dxHotspot, INT dyHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
428
{
429
    INT cx, cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
430

431 432
    TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
	  dxHotspot, dyHotspot);
Alexandre Julliard's avatar
Alexandre Julliard committed
433

434
    if (!is_valid(himlTrack))
435
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
436

437 438 439
    if (InternalDrag.himl)
        ImageList_EndDrag ();

440 441 442
    cx = himlTrack->cx;
    cy = himlTrack->cy;

443 444
    InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
    if (InternalDrag.himl == NULL) {
445
        WARN("Error creating drag image list!\n");
446
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
447 448
    }

449 450
    InternalDrag.dxHotspot = dxHotspot;
    InternalDrag.dyHotspot = dyHotspot;
Alexandre Julliard's avatar
Alexandre Julliard committed
451 452

    /* copy image */
453
    BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
454 455

    /* copy mask */
456
    BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
457

458
    InternalDrag.himl->cCurImage = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
459

460
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462 463 464
}


/*************************************************************************
465
 * ImageList_Copy [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
466
 *
467
 *  Copies an image of the source image list to an image of the
Alexandre Julliard's avatar
Alexandre Julliard committed
468
 *  destination image list. Images can be copied or swapped.
Alexandre Julliard's avatar
Alexandre Julliard committed
469
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
470
 * PARAMS
471
 *     himlDst [I] handle to the destination image list
Alexandre Julliard's avatar
Alexandre Julliard committed
472
 *     iDst    [I] destination image index.
473
 *     himlSrc [I] handle to the source image list
Alexandre Julliard's avatar
Alexandre Julliard committed
474 475
 *     iSrc    [I] source image index
 *     uFlags  [I] flags for the copy operation
Alexandre Julliard's avatar
Alexandre Julliard committed
476
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
477 478 479 480 481 482
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Copying from one image list to another is possible. The original
483
 *     implementation just copies or swaps within one image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
484
 *     Could this feature become a bug??? ;-)
Alexandre Julliard's avatar
Alexandre Julliard committed
485 486
 */

487 488
BOOL WINAPI
ImageList_Copy (HIMAGELIST himlDst, INT iDst,	HIMAGELIST himlSrc,
489
		INT iSrc, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
490
{
491 492
    POINT ptSrc, ptDst;

493
    TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
494

495
    if (!is_valid(himlSrc) || !is_valid(himlDst))
Eric Kohl's avatar
Eric Kohl committed
496 497 498 499 500
	return FALSE;
    if ((iDst < 0) || (iDst >= himlDst->cCurImage))
	return FALSE;
    if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
501

502 503 504
    imagelist_point_from_index( himlDst, iDst, &ptDst );
    imagelist_point_from_index( himlSrc, iSrc, &ptSrc );

Alexandre Julliard's avatar
Alexandre Julliard committed
505
    if (uFlags & ILCF_SWAP) {
Alexandre Julliard's avatar
Alexandre Julliard committed
506
        /* swap */
507
        HDC     hdcBmp;
508
        HBITMAP hbmTempImage, hbmTempMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
509

510
        hdcBmp = CreateCompatibleDC (0);
511

Alexandre Julliard's avatar
Alexandre Julliard committed
512
        /* create temporary bitmaps */
513
        hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
514
                                       himlSrc->uBitsPixel, NULL);
515
        hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
516
				      1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
517 518 519

        /* copy (and stretch) destination to temporary bitmaps.(save) */
        /* image */
520 521
        SelectObject (hdcBmp, hbmTempImage);
        StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
522
                      himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
523 524
                      SRCCOPY);
        /* mask */
525 526
        SelectObject (hdcBmp, hbmTempMask);
        StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
527
                      himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
528 529 530 531
                      SRCCOPY);

        /* copy (and stretch) source to destination */
        /* image */
532 533
        StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
534 535
                      SRCCOPY);
        /* mask */
536 537
        StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
538 539 540 541
                      SRCCOPY);

        /* copy (without stretching) temporary bitmaps to source (restore) */
        /* mask */
542
        BitBlt       (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
543
                      hdcBmp, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
544

545
        /* image */
546
        BitBlt       (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
547
                      hdcBmp, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
548
        /* delete temporary bitmaps */
549 550
        DeleteObject (hbmTempMask);
        DeleteObject (hbmTempImage);
551
        DeleteDC(hdcBmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
552
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
553
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
554
        /* copy image */
555 556
        StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
557 558 559
                      SRCCOPY);

        /* copy mask */
560 561
        StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
562 563 564
                      SRCCOPY);
    }

Eric Kohl's avatar
Eric Kohl committed
565
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
566 567 568 569
}


/*************************************************************************
570 571 572
 * ImageList_Create [COMCTL32.@]
 *
 * Creates a new image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
573
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
574 575 576 577 578 579
 * PARAMS
 *     cx       [I] image height
 *     cy       [I] image width
 *     flags    [I] creation flags
 *     cInitial [I] initial number of images in the image list
 *     cGrow    [I] number of images by which image list grows
Alexandre Julliard's avatar
Alexandre Julliard committed
580
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
581
 * RETURNS
Eric Kohl's avatar
Eric Kohl committed
582 583
 *     Success: Handle to the created image list
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
584
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
585
HIMAGELIST WINAPI
586 587
ImageList_Create (INT cx, INT cy, UINT flags,
		  INT cInitial, INT cGrow)
Alexandre Julliard's avatar
Alexandre Julliard committed
588 589
{
    HIMAGELIST himl;
590 591
    INT      nCount;
    HBITMAP  hbmTemp;
592
    UINT     ilc = (flags & 0xFE);
593
    static const WORD aBitBlend25[] =
Eric Kohl's avatar
Eric Kohl committed
594 595
        {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};

596
    static const WORD aBitBlend50[] =
Eric Kohl's avatar
Eric Kohl committed
597
        {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
Alexandre Julliard's avatar
Alexandre Julliard committed
598

599
    TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
600

601
    himl = Alloc (sizeof(struct _IMAGELIST));
Alexandre Julliard's avatar
Alexandre Julliard committed
602
    if (!himl)
Eric Kohl's avatar
Eric Kohl committed
603 604
        return NULL;

605 606
    cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;

607
    himl->magic     = IMAGELIST_MAGIC;
Eric Kohl's avatar
Eric Kohl committed
608 609 610
    himl->cx        = cx;
    himl->cy        = cy;
    himl->flags     = flags;
611
    himl->cMaxImage = cInitial + 1;
Eric Kohl's avatar
Eric Kohl committed
612 613 614 615
    himl->cInitial  = cInitial;
    himl->cGrow     = cGrow;
    himl->clrFg     = CLR_DEFAULT;
    himl->clrBk     = CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
616 617

    /* initialize overlay mask indices */
Alexandre Julliard's avatar
Alexandre Julliard committed
618
    for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
Alexandre Julliard's avatar
Alexandre Julliard committed
619 620
        himl->nOvlIdx[nCount] = -1;

621 622 623 624 625 626 627 628 629 630
    /* Create Image & Mask DCs */
    himl->hdcImage = CreateCompatibleDC (0);
    if (!himl->hdcImage)
        goto cleanup;
    if (himl->flags & ILC_MASK){
        himl->hdcMask = CreateCompatibleDC(0);
        if (!himl->hdcMask)
            goto cleanup;
    }

631
    /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
632 633
    if (ilc == ILC_COLOR)
        ilc = ILC_COLOR4;
Alexandre Julliard's avatar
Alexandre Julliard committed
634

635 636 637 638
    if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
        himl->uBitsPixel = ilc;
    else
        himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
Alexandre Julliard's avatar
Alexandre Julliard committed
639

640
    if (himl->cMaxImage > 0) {
641
        himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cx);
642 643
	SelectObject(himl->hdcImage, himl->hbmImage);
    } else
644
        himl->hbmImage = 0;
645

646
    if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
647 648
        SIZE sz;

649
        imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
650
        himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
651
        if (himl->hbmMask == 0) {
652
            ERR("Error creating mask bitmap!\n");
653
            goto cleanup;
Alexandre Julliard's avatar
Alexandre Julliard committed
654
        }
655
        SelectObject(himl->hdcMask, himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
656
    }
657 658
    else
        himl->hbmMask = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
659

Alexandre Julliard's avatar
Alexandre Julliard committed
660
    /* create blending brushes */
661
    hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
662 663
    himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
    DeleteObject (hbmTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
664

665
    hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend50);
666 667
    himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
    DeleteObject (hbmTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
668

669
    TRACE("created imagelist %p\n", himl);
Eric Kohl's avatar
Eric Kohl committed
670
    return himl;
671 672 673 674

cleanup:
    if (himl) ImageList_Destroy(himl);
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
675 676 677
}


Alexandre Julliard's avatar
Alexandre Julliard committed
678
/*************************************************************************
679
 * ImageList_Destroy [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
680 681
 *
 * Destroys an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
682
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
683
 * PARAMS
684
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
685
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
686 687 688
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
689 690
 */

691
BOOL WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
692
ImageList_Destroy (HIMAGELIST himl)
693
{
694
    if (!is_valid(himl))
Eric Kohl's avatar
Eric Kohl committed
695
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
696

Eric Kohl's avatar
Eric Kohl committed
697
    /* delete image bitmaps */
Alexandre Julliard's avatar
Alexandre Julliard committed
698
    if (himl->hbmImage)
699
        DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
700
    if (himl->hbmMask)
701
        DeleteObject (himl->hbmMask);
Eric Kohl's avatar
Eric Kohl committed
702

703 704 705 706 707 708
    /* delete image & mask DCs */
    if (himl->hdcImage)
        DeleteDC(himl->hdcImage);
    if (himl->hdcMask)
        DeleteDC(himl->hdcMask);

Eric Kohl's avatar
Eric Kohl committed
709 710
    /* delete blending brushes */
    if (himl->hbrBlend25)
711
        DeleteObject (himl->hbrBlend25);
Eric Kohl's avatar
Eric Kohl committed
712
    if (himl->hbrBlend50)
713
        DeleteObject (himl->hbrBlend50);
714

715
    ZeroMemory(himl, sizeof(*himl));
716
    Free (himl);
Eric Kohl's avatar
Eric Kohl committed
717 718

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
719 720 721
}


Alexandre Julliard's avatar
Alexandre Julliard committed
722
/*************************************************************************
723
 * ImageList_DragEnter [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
724
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
725 726 727 728 729 730 731 732 733 734 735 736 737 738
 * Locks window update and displays the drag image at the given position.
 *
 * PARAMS
 *     hwndLock [I] handle of the window that owns the drag image.
 *     x        [I] X position of the drag image.
 *     y        [I] Y position of the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     The position of the drag image is relative to the window, not
 *     the client area.
Alexandre Julliard's avatar
Alexandre Julliard committed
739 740
 */

741 742
BOOL WINAPI
ImageList_DragEnter (HWND hwndLock, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
743
{
744
    TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
745

746
    if (!is_valid(InternalDrag.himl))
747
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
748 749

    if (hwndLock)
750
	InternalDrag.hwnd = hwndLock;
Alexandre Julliard's avatar
Alexandre Julliard committed
751
    else
752
	InternalDrag.hwnd = GetDesktopWindow ();
Alexandre Julliard's avatar
Alexandre Julliard committed
753

754 755
    InternalDrag.x = x;
    InternalDrag.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
756

757 758 759 760
    /* draw the drag image and save the background */
    if (!ImageList_DragShowNolock(TRUE)) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
761

762
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
763 764 765 766
}


/*************************************************************************
767
 * ImageList_DragLeave [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
768 769 770 771 772 773 774 775 776
 *
 * Unlocks window update and hides the drag image.
 *
 * PARAMS
 *     hwndLock [I] handle of the window that owns the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
777 778
 */

779 780
BOOL WINAPI
ImageList_DragLeave (HWND hwndLock)
Alexandre Julliard's avatar
Alexandre Julliard committed
781
{
782 783 784
    /* As we don't save drag info in the window this can lead to problems if
       an app does not supply the same window as DragEnter */
    /* if (hwndLock)
785
	InternalDrag.hwnd = hwndLock;
Alexandre Julliard's avatar
Alexandre Julliard committed
786
    else
787 788 789 790 791
	InternalDrag.hwnd = GetDesktopWindow (); */
    if(!hwndLock)
	hwndLock = GetDesktopWindow();
    if(InternalDrag.hwnd != hwndLock)
	FIXME("DragLeave hWnd != DragEnter hWnd\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
792

Alexandre Julliard's avatar
Alexandre Julliard committed
793 794
    ImageList_DragShowNolock (FALSE);

795
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
796 797 798
}


799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
/*************************************************************************
 * ImageList_InternalDragDraw [Internal]
 *
 * Draws the drag image.
 *
 * PARAMS
 *     hdc [I] device context to draw into.
 *     x   [I] X position of the drag image.
 *     y   [I] Y position of the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     The position of the drag image is relative to the window, not
 *     the client area.
 *
 */

static inline void
ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
{
    IMAGELISTDRAWPARAMS imldp;

    ZeroMemory (&imldp, sizeof(imldp));
    imldp.cbSize  = sizeof(imldp);
    imldp.himl    = InternalDrag.himl;
    imldp.i       = 0;
    imldp.hdcDst  = hdc,
    imldp.x       = x;
    imldp.y       = y;
    imldp.rgbBk   = CLR_DEFAULT;
    imldp.rgbFg   = CLR_DEFAULT;
    imldp.fStyle  = ILD_NORMAL;
    imldp.fState  = ILS_ALPHA;
    imldp.Frame   = 128;

837 838
    /* FIXME: instead of using the alpha blending, we should
     * create a 50% mask, and draw it semitransparantly that way */
839 840 841
    ImageList_DrawIndirect (&imldp);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
842
/*************************************************************************
843
 * ImageList_DragMove [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
844 845 846 847 848 849 850 851 852 853 854 855 856 857
 *
 * Moves the drag image.
 *
 * PARAMS
 *     x [I] X position of the drag image.
 *     y [I] Y position of the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     The position of the drag image is relative to the window, not
 *     the client area.
858 859 860
 *
 * BUGS
 *     The drag image should be drawn semitransparent.
Alexandre Julliard's avatar
Alexandre Julliard committed
861 862
 */

863 864
BOOL WINAPI
ImageList_DragMove (INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
865
{
866 867
    TRACE("(x=%d y=%d)\n", x, y);

868
    if (!is_valid(InternalDrag.himl))
869
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
870

871 872 873 874 875 876 877 878 879 880
    /* draw/update the drag image */
    if (InternalDrag.bShow) {
	HDC hdcDrag;
	HDC hdcOffScreen;
	HDC hdcBg;
	HBITMAP hbmOffScreen;
	INT origNewX, origNewY;
	INT origOldX, origOldY;
	INT origRegX, origRegY;
	INT sizeRegX, sizeRegY;
881

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912

	/* calculate the update region */
	origNewX = x - InternalDrag.dxHotspot;
	origNewY = y - InternalDrag.dyHotspot;
	origOldX = InternalDrag.x - InternalDrag.dxHotspot;
	origOldY = InternalDrag.y - InternalDrag.dyHotspot;
	origRegX = min(origNewX, origOldX);
	origRegY = min(origNewY, origOldY);
	sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
	sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);

	hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
   			  DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
    	hdcOffScreen = CreateCompatibleDC(hdcDrag);
    	hdcBg = CreateCompatibleDC(hdcDrag);

	hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
	SelectObject(hdcOffScreen, hbmOffScreen);
	SelectObject(hdcBg, InternalDrag.hbmBg);

	/* get the actual background of the update region */
	BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
	       origRegX, origRegY, SRCCOPY);
	/* erase the old image */
	BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
	       InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
	       SRCCOPY);
	/* save the background */
	BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
	/* draw the image */
913 914
	ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, 
				   origNewY - origRegY);
915 916 917 918 919 920
	/* draw the update region to the screen */
	BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
	       hdcOffScreen, 0, 0, SRCCOPY);

	DeleteDC(hdcBg);
	DeleteDC(hdcOffScreen);
Michael Stefaniuc's avatar
Michael Stefaniuc committed
921
	DeleteObject(hbmOffScreen);
922 923
	ReleaseDC(InternalDrag.hwnd, hdcDrag);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
924

925 926 927
    /* update the image position */
    InternalDrag.x = x;
    InternalDrag.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
928

929
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
930 931 932 933
}


/*************************************************************************
934
 * ImageList_DragShowNolock [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
935 936 937 938 939 940 941 942 943 944
 *
 * Shows or hides the drag image.
 *
 * PARAMS
 *     bShow [I] TRUE shows the drag image, FALSE hides it.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
945 946
 * BUGS
 *     The drag image should be drawn semitransparent.
Alexandre Julliard's avatar
Alexandre Julliard committed
947
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
948

949 950
BOOL WINAPI
ImageList_DragShowNolock (BOOL bShow)
Alexandre Julliard's avatar
Alexandre Julliard committed
951
{
952
    HDC hdcDrag;
953 954
    HDC hdcBg;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
955

956 957 958
    if (!is_valid(InternalDrag.himl))
        return FALSE;
    
959
    TRACE("bShow=0x%X!\n", bShow);
Alexandre Julliard's avatar
Alexandre Julliard committed
960

961 962 963 964
    /* DragImage is already visible/hidden */
    if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
965

966 967 968
    /* position of the origin of the DragImage */
    x = InternalDrag.x - InternalDrag.dxHotspot;
    y = InternalDrag.y - InternalDrag.dyHotspot;
Alexandre Julliard's avatar
Alexandre Julliard committed
969

970 971 972 973
    hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
			 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
    if (!hdcDrag) {
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
974 975
    }

976 977 978 979 980 981
    hdcBg = CreateCompatibleDC(hdcDrag);
    if (!InternalDrag.hbmBg) {
	InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
		    InternalDrag.himl->cx, InternalDrag.himl->cy);
    }
    SelectObject(hdcBg, InternalDrag.hbmBg);
982

983 984 985 986 987
    if (bShow) {
	/* save the background */
	BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcDrag, x, y, SRCCOPY);
	/* show the image */
988
	ImageList_InternalDragDraw(hdcDrag, x, y);
989
    } else {
990 991 992
	/* hide the image */
	BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcBg, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
993 994
    }

995
    InternalDrag.bShow = !InternalDrag.bShow;
Alexandre Julliard's avatar
Alexandre Julliard committed
996

997 998 999
    DeleteDC(hdcBg);
    ReleaseDC (InternalDrag.hwnd, hdcDrag);
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1000 1001 1002 1003
}


/*************************************************************************
1004 1005 1006
 * ImageList_Draw [COMCTL32.@]
 *
 * Draws an image.
Alexandre Julliard's avatar
Alexandre Julliard committed
1007 1008
 *
 * PARAMS
1009
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1010
 *     i      [I] image index
1011
 *     hdc    [I] handle to device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1012 1013 1014 1015 1016 1017 1018 1019 1020
 *     x      [I] x position
 *     y      [I] y position
 *     fStyle [I] drawing flags
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * SEE
1021
 *     ImageList_DrawEx.
Alexandre Julliard's avatar
Alexandre Julliard committed
1022 1023
 */

1024
BOOL WINAPI
1025
ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1026
{
1027 1028
    return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0, 
		             CLR_DEFAULT, CLR_DEFAULT, fStyle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1029 1030 1031 1032
}


/*************************************************************************
1033
 * ImageList_DrawEx [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1034 1035 1036 1037
 *
 * Draws an image and allows to use extended drawing features.
 *
 * PARAMS
1038
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1039
 *     i      [I] image index
1040
 *     hdc    [I] handle to device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1041 1042
 *     x      [I] X position
 *     y      [I] Y position
1043 1044
 *     dx     [I] X offset
 *     dy     [I] Y offset
Alexandre Julliard's avatar
Alexandre Julliard committed
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
 *     rgbBk  [I] background color
 *     rgbFg  [I] foreground color
 *     fStyle [I] drawing flags
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Calls ImageList_DrawIndirect.
 *
 * SEE
 *     ImageList_DrawIndirect.
Alexandre Julliard's avatar
Alexandre Julliard committed
1058 1059
 */

1060 1061 1062 1063
BOOL WINAPI
ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
		  INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
		  UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1064 1065 1066
{
    IMAGELISTDRAWPARAMS imldp;

1067 1068
    ZeroMemory (&imldp, sizeof(imldp));
    imldp.cbSize  = sizeof(imldp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1069 1070 1071 1072 1073
    imldp.himl    = himl;
    imldp.i       = i;
    imldp.hdcDst  = hdc,
    imldp.x       = x;
    imldp.y       = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1074 1075
    imldp.cx      = dx;
    imldp.cy      = dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077 1078 1079
    imldp.rgbBk   = rgbBk;
    imldp.rgbFg   = rgbFg;
    imldp.fStyle  = fStyle;

1080
    return ImageList_DrawIndirect (&imldp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1081 1082 1083 1084
}


/*************************************************************************
1085
 * ImageList_DrawIndirect [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1086
 *
1087
 * Draws an image using various parameters specified in pimldp.
Alexandre Julliard's avatar
Alexandre Julliard committed
1088 1089
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1090
 *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
Alexandre Julliard's avatar
Alexandre Julliard committed
1091 1092
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1095 1096
 */

1097
BOOL WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1098
ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
Alexandre Julliard's avatar
Alexandre Julliard committed
1099
{
1100
    INT cx, cy, nOvlIdx;
1101 1102
    DWORD fState, dwRop;
    UINT fStyle;
1103
    COLORREF oldImageBk, oldImageFg;
1104
    HDC hImageDC, hImageListDC, hMaskListDC;
1105
    HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1106
    BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1107
    HIMAGELIST himl;
1108
    POINT pt;
1109 1110

    if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1111
    if (!is_valid(himl)) return FALSE;
1112
    if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1113

1114 1115 1116
    imagelist_point_from_index( himl, pimldp->i, &pt );
    pt.x += pimldp->xBitmap;
    pt.y += pimldp->yBitmap;
1117

1118 1119 1120 1121
    fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
    fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
    cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
    cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1122 1123 1124 1125 1126 1127 1128 1129

    bIsTransparent = (fStyle & ILD_TRANSPARENT);
    if( pimldp->rgbBk == CLR_NONE )
        bIsTransparent = TRUE;
    if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
        bIsTransparent = TRUE;
    bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
    bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1130

Frank Richter's avatar
Frank Richter committed
1131 1132
    TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
          himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1133

1134
    /* we will use these DCs to access the images and masks in the ImageList */
1135 1136
    hImageListDC = himl->hdcImage;
    hMaskListDC  = himl->hdcMask;
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149

    /* these will accumulate the image and mask for the image we're drawing */
    hImageDC = CreateCompatibleDC( pimldp->hdcDst );
    hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
    hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;

    /* Create a compatible DC. */
    if (!hImageListDC || !hImageDC || !hImageBmp ||
	(bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
	goto cleanup;
    
    hOldImageBmp = SelectObject(hImageDC, hImageBmp);
  
1150
    /*
1151 1152 1153 1154 1155 1156 1157
     * To obtain a transparent look, background color should be set
     * to white and foreground color to black when blting the
     * monochrome mask.
     */
    oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
    oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );

1158
    /*
1159
     * Draw the initial image
1160
     */
1161
    if( bMask ) {
1162
	if (himl->hbmMask) {
1163 1164 1165
            HBRUSH hOldBrush;
            hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
            PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1166
            BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1167 1168 1169 1170 1171 1172 1173
            DeleteObject (SelectObject (hImageDC, hOldBrush));
            if( bIsTransparent )
            {
                BitBlt ( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
                bResult = TRUE;
                goto end;
            }
1174 1175 1176 1177 1178
	} else {
	    HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
	    PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
	    SelectObject(hImageDC, hOldBrush);
	}
1179
    } else {
1180
	/* blend the image with the needed solid background */
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
        COLORREF colour = RGB(0,0,0);
        HBRUSH hOldBrush;

        if( !bIsTransparent )
        {
            colour = pimldp->rgbBk;
            if( colour == CLR_DEFAULT )
                colour = himl->clrBk;
            if( colour == CLR_NONE )
                colour = GetBkColor(pimldp->hdcDst);
        }

        hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1194
        PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1195 1196 1197 1198 1199 1200 1201
        if (himl->hbmMask)
        {
            BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
            BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
        }
        else
            BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1202
        DeleteObject (SelectObject (hImageDC, hOldBrush));
1203
    }
1204

1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
    /* Time for blending, if required */
    if (bBlend) {
	HBRUSH hBlendBrush, hOldBrush;
        COLORREF clrBlend = pimldp->rgbFg;
	HDC hBlendMaskDC = hImageListDC;
	HBITMAP hOldBitmap;

	/* Create the blend Mask */
    	hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
	hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1215
        hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1216 1217 1218 1219 1220
    	PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
    	SelectObject(hBlendMaskDC, hOldBrush);

    	/* Modify the blend mask if an Image Mask exist */
    	if(himl->hbmMask) {
1221
	    BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1222 1223
	    BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
	}
1224

1225 1226 1227
	/* now apply blend to the current image given the BlendMask */
        if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
        else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1228
	hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1229 1230 1231 1232
	BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
	DeleteObject(SelectObject(hImageDC, hOldBrush));
	SelectObject(hBlendMaskDC, hOldBitmap);
    }
1233 1234

    /* Now do the overlay image, if any */
1235 1236
    nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
    if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1237 1238
	nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
	if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1239 1240 1241
            POINT ptOvl;
            imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
            ptOvl.x += pimldp->xBitmap;
1242
	    if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1243 1244
		BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
	    BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1245
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1246 1247
    }

1248 1249 1250
    if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
    if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
    if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
Huw Davies's avatar
Huw Davies committed
1251
    if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1252 1253 1254 1255

    if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
    if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
    if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1256

1257 1258
    /* now copy the image to the screen */
    dwRop = SRCCOPY;
1259
    if (himl->hbmMask && bIsTransparent ) {
1260 1261
	COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
	COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1262
        BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1263 1264 1265 1266 1267 1268 1269 1270
	SetBkColor(pimldp->hdcDst, oldDstBk);
	SetTextColor(pimldp->hdcDst, oldDstFg);
	dwRop = SRCPAINT;
    }
    if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
    BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);

    bResult = TRUE;
1271
end:
1272 1273 1274 1275 1276 1277 1278
    /* cleanup the mess */
    SetBkColor(hImageDC, oldImageBk);
    SetTextColor(hImageDC, oldImageFg);
    SelectObject(hImageDC, hOldImageBmp);
cleanup:
    DeleteObject(hBlendMaskBmp);
    DeleteObject(hImageBmp);
1279
    DeleteDC(hImageDC);
1280 1281

    return bResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1282 1283 1284
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1285
/*************************************************************************
1286 1287 1288
 * ImageList_Duplicate [COMCTL32.@]
 *
 * Duplicates an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1289
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1290 1291
 * PARAMS
 *     himlSrc [I] source image list handle
Alexandre Julliard's avatar
Alexandre Julliard committed
1292
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1293 1294
 * RETURNS
 *     Success: Handle of duplicated image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1295
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1296 1297
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299
HIMAGELIST WINAPI
ImageList_Duplicate (HIMAGELIST himlSrc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1300 1301 1302
{
    HIMAGELIST himlDst;

1303
    if (!is_valid(himlSrc)) {
1304
        ERR("Invalid image list handle!\n");
1305
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1306 1307 1308 1309 1310 1311 1312
    }

    himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
                                himlSrc->cInitial, himlSrc->cGrow);

    if (himlDst)
    {
1313 1314
        SIZE sz;

1315
        imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cx, &sz);
1316
        BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1317
                himlSrc->hdcImage, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1318 1319

        if (himlDst->hbmMask)
1320
            BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1321
                    himlSrc->hdcMask, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1322

1323 1324 1325
	himlDst->cCurImage = himlSrc->cCurImage;
	himlDst->cMaxImage = himlSrc->cMaxImage;
    }
1326
    return himlDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1327 1328 1329
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1330
/*************************************************************************
1331
 * ImageList_EndDrag [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1332 1333
 *
 * Finishes a drag operation.
Alexandre Julliard's avatar
Alexandre Julliard committed
1334
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1335
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1336
 *     no Parameters
Alexandre Julliard's avatar
Alexandre Julliard committed
1337
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1338 1339 1340
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1341 1342
 */

1343
VOID WINAPI
1344
ImageList_EndDrag (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1345
{
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
    /* cleanup the InternalDrag struct */
    InternalDrag.hwnd = 0;
    ImageList_Destroy (InternalDrag.himl);
    InternalDrag.himl = 0;
    InternalDrag.x= 0;
    InternalDrag.y= 0;
    InternalDrag.dxHotspot = 0;
    InternalDrag.dyHotspot = 0;
    InternalDrag.bShow = FALSE;
    DeleteObject(InternalDrag.hbmBg);
    InternalDrag.hbmBg = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1357 1358
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1359

Alexandre Julliard's avatar
Alexandre Julliard committed
1360
/*************************************************************************
1361
 * ImageList_GetBkColor [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1362
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1363
 * Returns the background color of an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1364
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1365 1366 1367 1368
 * PARAMS
 *     himl [I] Image list handle.
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1369 1370
 *     Success: background color
 *     Failure: CLR_NONE
Alexandre Julliard's avatar
Alexandre Julliard committed
1371 1372
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1373 1374
COLORREF WINAPI
ImageList_GetBkColor (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1375
{
1376
    return himl ? himl->clrBk : CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1377 1378 1379
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1380
/*************************************************************************
1381
 * ImageList_GetDragImage [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1382 1383
 *
 * Returns the handle to the internal drag image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1384
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1385 1386 1387
 * PARAMS
 *     ppt        [O] Pointer to the drag position. Can be NULL.
 *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1388
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1389 1390 1391
 * RETURNS
 *     Success: Handle of the drag image list.
 *     Failure: NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1392 1393
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1394
HIMAGELIST WINAPI
1395
ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
1396
{
1397
    if (is_valid(InternalDrag.himl)) {
1398
	if (ppt) {
1399 1400
	    ppt->x = InternalDrag.x;
	    ppt->y = InternalDrag.y;
1401 1402
	}
	if (pptHotspot) {
1403 1404
	    pptHotspot->x = InternalDrag.dxHotspot;
	    pptHotspot->y = InternalDrag.dyHotspot;
1405
	}
1406
        return (InternalDrag.himl);
1407
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1408

1409
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1410 1411 1412
}


1413
/*************************************************************************
1414
 * ImageList_GetFlags [COMCTL32.@]
1415
 *
1416 1417 1418 1419 1420 1421 1422 1423
 * Gets the flags of the specified image list.
 *
 * PARAMS
 *     himl [I] Handle to image list
 *
 * RETURNS
 *     Image list flags.
 *
1424 1425 1426 1427 1428 1429 1430
 * BUGS
 *    Stub.
 */

DWORD WINAPI
ImageList_GetFlags(HIMAGELIST himl)
{
1431 1432 1433
    TRACE("%p\n", himl);

    return is_valid(himl) ? himl->flags : 0;
1434 1435 1436
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1437
/*************************************************************************
1438
 * ImageList_GetIcon [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1439 1440 1441 1442
 *
 * Creates an icon from a masked image of an image list.
 *
 * PARAMS
1443
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1444 1445 1446 1447 1448 1449
 *     i     [I] image index
 *     flags [I] drawing style flags
 *
 * RETURNS
 *     Success: icon handle
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1450 1451
 */

1452 1453
HICON WINAPI
ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1454
{
1455
    ICONINFO ii;
1456 1457 1458
    HICON hIcon;
    HBITMAP hOldDstBitmap;
    HDC hdcDst;
1459
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1460

1461
    TRACE("%p %d %d\n", himl, i, fStyle);
1462
    if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1463

Alexandre Julliard's avatar
Alexandre Julliard committed
1464
    ii.fIcon = TRUE;
1465 1466
    ii.xHotspot = 0;
    ii.yHotspot = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1467

1468 1469 1470 1471 1472 1473 1474
    /* create colour bitmap */
    hdcDst = GetDC(0);
    ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
    ReleaseDC(0, hdcDst);

    hdcDst = CreateCompatibleDC(0);

1475 1476
    imagelist_point_from_index( himl, i, &pt );

Alexandre Julliard's avatar
Alexandre Julliard committed
1477
    /* draw mask*/
1478
    ii.hbmMask  = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1479
    hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1480 1481
    if (himl->hbmMask) {
        BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1482
                himl->hdcMask, pt.x, pt.y, SRCCOPY);
1483 1484 1485
    }
    else
        PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
Alexandre Julliard's avatar
Alexandre Julliard committed
1486 1487

    /* draw image*/
Luc Tourangeau's avatar
Luc Tourangeau committed
1488
    SelectObject (hdcDst, ii.hbmColor);
1489
    BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1490
            himl->hdcImage, pt.x, pt.y, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1491

1492 1493
    /*
     * CreateIconIndirect requires us to deselect the bitmaps from
1494
     * the DCs before calling
1495 1496 1497
     */
    SelectObject(hdcDst, hOldDstBitmap);

1498
    hIcon = CreateIconIndirect (&ii);
Alexandre Julliard's avatar
Alexandre Julliard committed
1499

1500 1501
    DeleteObject (ii.hbmMask);
    DeleteObject (ii.hbmColor);
1502
    DeleteDC (hdcDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
1503

Eric Kohl's avatar
Eric Kohl committed
1504
    return hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
1505 1506 1507
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1508
/*************************************************************************
1509
 * ImageList_GetIconSize [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1510 1511 1512 1513
 *
 * Retrieves the size of an image in an image list.
 *
 * PARAMS
1514
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1515 1516 1517 1518 1519 1520 1521 1522 1523
 *     cx   [O] pointer to the image width.
 *     cy   [O] pointer to the image height.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     All images in an image list have the same size.
Alexandre Julliard's avatar
Alexandre Julliard committed
1524 1525
 */

1526 1527
BOOL WINAPI
ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
{
1529
    if (!is_valid(himl))
Eric Kohl's avatar
Eric Kohl committed
1530 1531 1532
	return FALSE;
    if ((himl->cx <= 0) || (himl->cy <= 0))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1533 1534

    if (cx)
Eric Kohl's avatar
Eric Kohl committed
1535
	*cx = himl->cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1536
    if (cy)
Eric Kohl's avatar
Eric Kohl committed
1537 1538 1539
	*cy = himl->cy;

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1540 1541 1542
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1543
/*************************************************************************
1544
 * ImageList_GetImageCount [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1545 1546 1547 1548
 *
 * Returns the number of images in an image list.
 *
 * PARAMS
1549
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1550 1551 1552
 *
 * RETURNS
 *     Success: Number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
1553
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
1554 1555
 */

1556
INT WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1557
ImageList_GetImageCount (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1558
{
1559
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
1560
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1561

Eric Kohl's avatar
Eric Kohl committed
1562
    return himl->cCurImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
1563 1564 1565
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1566
/*************************************************************************
1567
 * ImageList_GetImageInfo [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1568 1569 1570 1571
 *
 * Returns information about an image in an image list.
 *
 * PARAMS
1572
 *     himl       [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1573
 *     i          [I] image index
1574
 *     pImageInfo [O] pointer to the image information
Alexandre Julliard's avatar
Alexandre Julliard committed
1575 1576 1577 1578
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1579 1580
 */

1581 1582
BOOL WINAPI
ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
1583
{
1584 1585
    POINT pt;

1586
    if (!is_valid(himl) || (pImageInfo == NULL))
Eric Kohl's avatar
Eric Kohl committed
1587 1588 1589
	return FALSE;
    if ((i < 0) || (i >= himl->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1590

Alexandre Julliard's avatar
Alexandre Julliard committed
1591 1592
    pImageInfo->hbmImage = himl->hbmImage;
    pImageInfo->hbmMask  = himl->hbmMask;
1593

1594 1595 1596 1597 1598
    imagelist_point_from_index( himl, i, &pt );
    pImageInfo->rcImage.top    = pt.y;
    pImageInfo->rcImage.bottom = pt.y + himl->cy;
    pImageInfo->rcImage.left   = pt.x;
    pImageInfo->rcImage.right  = pt.x + himl->cx;
1599

Eric Kohl's avatar
Eric Kohl committed
1600
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1601 1602 1603
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1604
/*************************************************************************
1605
 * ImageList_GetImageRect [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1606 1607 1608 1609
 *
 * Retrieves the rectangle of the specified image in an image list.
 *
 * PARAMS
1610
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1611 1612 1613 1614
 *     i      [I] image index
 *     lpRect [O] pointer to the image rectangle
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1615 1616
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1617
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1618 1619
 * NOTES
 *    This is an UNDOCUMENTED function!!!
Alexandre Julliard's avatar
Alexandre Julliard committed
1620
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1621

1622 1623
BOOL WINAPI
ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1624
{
1625 1626
    POINT pt;

1627
    if (!is_valid(himl) || (lpRect == NULL))
Eric Kohl's avatar
Eric Kohl committed
1628 1629 1630
	return FALSE;
    if ((i < 0) || (i >= himl->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1631

1632 1633 1634 1635 1636
    imagelist_point_from_index( himl, i, &pt );
    lpRect->left   = pt.x;
    lpRect->top    = pt.y;
    lpRect->right  = pt.x + himl->cx;
    lpRect->bottom = pt.y + himl->cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1637

Eric Kohl's avatar
Eric Kohl committed
1638
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1639 1640 1641
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1642
/*************************************************************************
1643 1644
 * ImageList_LoadImage  [COMCTL32.@]
 * ImageList_LoadImageA [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1645 1646 1647
 *
 * Creates an image list from a bitmap, icon or cursor.
 *
1648
 * See ImageList_LoadImageW.
Alexandre Julliard's avatar
Alexandre Julliard committed
1649 1650
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1651
HIMAGELIST WINAPI
1652 1653
ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
			COLORREF clrMask, UINT uType, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1654
{
1655 1656 1657
    HIMAGELIST himl;
    LPWSTR lpbmpW;
    DWORD len;
Alexandre Julliard's avatar
Alexandre Julliard committed
1658

1659 1660 1661
    if (!HIWORD(lpbmp))
        return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
                                    uType, uFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1662

1663
    len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1664
    lpbmpW = Alloc(len * sizeof(WCHAR));
1665
    MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1666

1667
    himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1668
    Free (lpbmpW);
1669
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1670 1671 1672
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1673
/*************************************************************************
1674
 * ImageList_LoadImageW [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1675 1676 1677 1678
 *
 * Creates an image list from a bitmap, icon or cursor.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1679 1680 1681 1682 1683 1684 1685
 *     hi      [I] instance handle
 *     lpbmp   [I] name or id of the image
 *     cx      [I] width of each image
 *     cGrow   [I] number of images to expand
 *     clrMask [I] mask color
 *     uType   [I] type of image to load
 *     uFlags  [I] loading flags
Alexandre Julliard's avatar
Alexandre Julliard committed
1686 1687
 *
 * RETURNS
1688
 *     Success: handle to the loaded image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1689 1690 1691 1692
 *     Failure: NULL
 *
 * SEE
 *     LoadImage ()
Alexandre Julliard's avatar
Alexandre Julliard committed
1693 1694
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1695
HIMAGELIST WINAPI
1696
ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1697
                      COLORREF clrMask, UINT uType, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1698 1699
{
    HIMAGELIST himl = NULL;
1700 1701
    HANDLE   handle;
    INT      nImageCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
1702

1703
    handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1704
    if (!handle) {
1705
        WARN("Couldn't load image\n");
1706
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1707
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1708 1709

    if (uType == IMAGE_BITMAP) {
1710
        BITMAP bmp;
1711
        GetObjectW (handle, sizeof(BITMAP), &bmp);
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724

        /* To match windows behavior, if cx is set to zero and
         the flag DI_DEFAULTSIZE is specified, cx becomes the
         system metric value for icons. If the flag is not specified
         the function sets the size to the height of the bitmap */
        if (cx == 0)
        {
            if (uFlags & DI_DEFAULTSIZE)
                cx = GetSystemMetrics (SM_CXICON);
            else
                cx = bmp.bmHeight;
        }

Alexandre Julliard's avatar
Alexandre Julliard committed
1725 1726 1727 1728
        nImageCount = bmp.bmWidth / cx;

        himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
                                 nImageCount, cGrow);
1729 1730 1731 1732
        if (!himl) {
            DeleteObject (handle);
            return NULL;
        }
1733
        ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1734 1735
    }
    else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1736 1737
        ICONINFO ii;
        BITMAP bmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1738

1739
        GetIconInfo (handle, &ii);
1740
        GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1741
        himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
Alexandre Julliard's avatar
Alexandre Julliard committed
1742
                                 ILC_MASK | ILC_COLOR, 1, cGrow);
1743 1744 1745 1746 1747 1748
        if (!himl) {
            DeleteObject (ii.hbmColor);
            DeleteObject (ii.hbmMask);
            DeleteObject (handle);
            return NULL;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1749
        ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1750 1751
        DeleteObject (ii.hbmColor);
        DeleteObject (ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1752 1753
    }

1754
    DeleteObject (handle);
1755

1756
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1757 1758 1759
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1760
/*************************************************************************
1761
 * ImageList_Merge [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1762
 *
1763
 * Create an image list containing a merged image from two image lists.
Alexandre Julliard's avatar
Alexandre Julliard committed
1764 1765
 *
 * PARAMS
1766
 *     himl1 [I] handle to first image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1767
 *     i1    [I] first image index
1768
 *     himl2 [I] handle to second image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1769 1770 1771 1772 1773
 *     i2    [I] second image index
 *     dx    [I] X offset of the second image relative to the first.
 *     dy    [I] Y offset of the second image relative to the first.
 *
 * RETURNS
1774 1775 1776 1777 1778 1779 1780 1781 1782
 *     Success: The newly created image list. It contains a single image
 *              consisting of the second image merged with the first.
 *     Failure: NULL, if either himl1 or himl2 are invalid.
 *
 * NOTES
 *   - The returned image list should be deleted by the caller using
 *     ImageList_Destroy() when it is no longer required.
 *   - If either i1 or i2 are not valid image indices they will be treated
 *     as a blank image.
Alexandre Julliard's avatar
Alexandre Julliard committed
1783
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1784
HIMAGELIST WINAPI
1785 1786
ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
		 INT dx, INT dy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1787 1788
{
    HIMAGELIST himlDst = NULL;
1789 1790
    INT      cxDst, cyDst;
    INT      xOff1, yOff1, xOff2, yOff2;
1791
    POINT    pt1, pt2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1792

1793 1794 1795
    TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
	   i2, dx, dy);

1796
    if (!is_valid(himl1) || !is_valid(himl2))
Eric Kohl's avatar
Eric Kohl committed
1797
	return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1798

Alexandre Julliard's avatar
Alexandre Julliard committed
1799
    if (dx > 0) {
1800
        cxDst = max (himl1->cx, dx + himl2->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1801
        xOff1 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1802
        xOff2 = dx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1803
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1804
    else if (dx < 0) {
1805
        cxDst = max (himl2->cx, himl1->cx - dx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1806
        xOff1 = -dx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1807 1808 1809
        xOff2 = 0;
    }
    else {
1810
        cxDst = max (himl1->cx, himl2->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1811 1812 1813 1814
        xOff1 = 0;
        xOff2 = 0;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1815
    if (dy > 0) {
1816
        cyDst = max (himl1->cy, dy + himl2->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1817
        yOff1 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1818
        yOff2 = dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1819
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1820
    else if (dy < 0) {
1821
        cyDst = max (himl2->cy, himl1->cy - dy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1822
        yOff1 = -dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1823 1824 1825
        yOff2 = 0;
    }
    else {
1826
        cyDst = max (himl1->cy, himl2->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1827 1828 1829 1830 1831 1832
        yOff1 = 0;
        yOff2 = 0;
    }

    himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);

1833 1834
    if (himlDst)
    {
1835 1836
        imagelist_point_from_index( himl1, i1, &pt1 );
        imagelist_point_from_index( himl1, i2, &pt2 );
1837

Alexandre Julliard's avatar
Alexandre Julliard committed
1838
        /* copy image */
1839 1840
        BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
        if (i1 >= 0 && i1 < himl1->cCurImage)
1841
            BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
1842 1843
        if (i2 >= 0 && i2 < himl2->cCurImage)
        {
1844 1845
            BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
            BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
1846
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1847 1848

        /* copy mask */
1849 1850
        BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
        if (i1 >= 0 && i1 < himl1->cCurImage)
1851
            BitBlt (himlDst->hdcMask,  xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask,  pt1.x, pt1.y, SRCCOPY);
1852
        if (i2 >= 0 && i2 < himl2->cCurImage)
1853
            BitBlt (himlDst->hdcMask,  xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask,  pt2.x, pt2.y, SRCAND);
1854

1855
	himlDst->cCurImage = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1856
    }
1857

Eric Kohl's avatar
Eric Kohl committed
1858
    return himlDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1859 1860 1861
}


1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897
/***********************************************************************
 *           DIB_GetDIBWidthBytes
 *
 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
 */
static int DIB_GetDIBWidthBytes( int width, int depth )
{
    int words;

    switch(depth)
    {
    case 1:  words = (width + 31) / 32; break;
    case 4:  words = (width + 7) / 8; break;
    case 8:  words = (width + 3) / 4; break;
    case 15:
    case 16: words = (width + 1) / 2; break;
    case 24: words = (width * 3 + 3)/4; break;

    default:
        WARN("(%d): Unsupported depth\n", depth );
        /* fall through */
    case 32:
        words = width;
        break;
    }
    return 4 * words;
}

/***********************************************************************
 *           DIB_GetDIBImageBytes
 *
 * Return the number of bytes used to hold the image in a DIB bitmap.
 */
static int DIB_GetDIBImageBytes( int width, int height, int depth )
{
    return DIB_GetDIBWidthBytes( width, depth ) * abs( height );
1898
}
1899

1900

1901
/* helper for ImageList_Read, see comments below */
1902
static BOOL _read_bitmap(HDC hdcIml, LPSTREAM pstm)
1903
{
1904
    BITMAPFILEHEADER	bmfh;
1905 1906 1907
    int bitsperpixel, palspace;
    char bmi_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
    LPBITMAPINFO bmi = (LPBITMAPINFO)bmi_buf;
1908
    int                result = FALSE;
1909
    LPBYTE             bits = NULL;
1910

1911
    if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
1912
        return FALSE;
1913 1914

    if (bmfh.bfType != (('M'<<8)|'B'))
1915
        return FALSE;
1916

1917
    if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
1918
        return FALSE;
1919

1920 1921 1922 1923 1924 1925
    if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
        return FALSE;

    TRACE("width %u, height %u, planes %u, bpp %u\n",
          bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
          bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount);
1926

1927
    bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
1928
    if (bitsperpixel<=8)
1929
        palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1930
    else
1931 1932
        palspace = 0;

1933
    bmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, bitsperpixel);
1934 1935

    /* read the palette right after the end of the bitmapinfoheader */
1936
    if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
1937
	goto error;
1938

1939 1940
    bits = Alloc(bmi->bmiHeader.biSizeImage);
    if (!bits)
1941
        goto error;
1942
    if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
1943 1944
        goto error;

1945 1946 1947 1948
    if (!StretchDIBits(hdcIml, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
                  0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
                  bits, bmi, DIB_RGB_COLORS, SRCCOPY))
        goto error;
1949
    result = TRUE;
1950

1951
error:
1952
    Free(bits);
1953
    return result;
1954 1955
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1956
/*************************************************************************
1957
 * ImageList_Read [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1958 1959 1960 1961 1962 1963 1964
 *
 * Reads an image list from a stream.
 *
 * PARAMS
 *     pstm [I] pointer to a stream
 *
 * RETURNS
1965
 *     Success: handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1966
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1967
 *
1968
 * The format is like this:
1969
 *	ILHEAD			ilheadstruct;
1970 1971
 *
 * for the color image part:
1972 1973
 *	BITMAPFILEHEADER	bmfh;
 *	BITMAPINFOHEADER	bmih;
1974
 * only if it has a palette:
1975
 *	RGBQUAD		rgbs[nr_of_paletted_colors];
1976 1977 1978 1979 1980 1981 1982
 *
 *	BYTE			colorbits[imagesize];
 *
 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
 *	BITMAPFILEHEADER	bmfh_mask;
 *	BITMAPINFOHEADER	bmih_mask;
 * only if it has a palette (it usually does not):
1983
 *	RGBQUAD		rgbs[nr_of_paletted_colors];
1984 1985
 *
 *	BYTE			maskbits[imagesize];
Alexandre Julliard's avatar
Alexandre Julliard committed
1986
 */
1987
HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
Alexandre Julliard's avatar
Alexandre Julliard committed
1988
{
1989 1990 1991 1992
    ILHEAD	ilHead;
    HIMAGELIST	himl;
    int		i;

1993 1994
    TRACE("%p\n", pstm);

1995
    if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1996
	return NULL;
1997 1998 1999 2000
    if (ilHead.usMagic != (('L' << 8) | 'I'))
	return NULL;
    if (ilHead.usVersion != 0x101) /* probably version? */
	return NULL;
2001

2002 2003 2004
    TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
          ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);

2005
    himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2006
    if (!himl)
2007
	return NULL;
2008

2009
    if (!_read_bitmap(himl->hdcImage, pstm))
2010
    {
2011
	WARN("failed to read bitmap from stream\n");
2012
	return NULL;
2013
    }
2014 2015
    if (ilHead.flags & ILC_MASK)
    {
2016
        if (!_read_bitmap(himl->hdcMask, pstm))
2017 2018
        {
            WARN("failed to read mask bitmap from stream\n");
2019 2020 2021
	    return NULL;
	}
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2022

2023 2024
    himl->cCurImage = ilHead.cCurImage;
    himl->cMaxImage = ilHead.cMaxImage;
2025

2026 2027
    ImageList_SetBkColor(himl,ilHead.bkcolor);
    for (i=0;i<4;i++)
2028
	ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2029
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
2030 2031 2032
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2033
/*************************************************************************
2034 2035 2036
 * ImageList_Remove [COMCTL32.@]
 *
 * Removes an image from an image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2037 2038 2039 2040 2041 2042 2043 2044
 *
 * PARAMS
 *     himl [I] image list handle
 *     i    [I] image index
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
2045 2046 2047
 *
 * FIXME: as the image list storage test shows, native comctl32 simply shifts
 * images without creating a new bitmap.
Alexandre Julliard's avatar
Alexandre Julliard committed
2048
 */
2049 2050
BOOL WINAPI
ImageList_Remove (HIMAGELIST himl, INT i)
Alexandre Julliard's avatar
Alexandre Julliard committed
2051
{
2052
    HBITMAP hbmNewImage, hbmNewMask;
2053
    HDC     hdcBmp;
2054
    SIZE    sz;
Alexandre Julliard's avatar
Alexandre Julliard committed
2055

2056 2057
    TRACE("(himl=%p i=%d)\n", himl, i);

2058
    if (!is_valid(himl)) {
2059 2060 2061
        ERR("Invalid image list handle!\n");
        return FALSE;
    }
2062

Alexandre Julliard's avatar
Alexandre Julliard committed
2063
    if ((i < -1) || (i >= himl->cCurImage)) {
2064
        TRACE("index out of range! %d\n", i);
Eric Kohl's avatar
Eric Kohl committed
2065
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2066 2067 2068
    }

    if (i == -1) {
2069 2070
        INT nCount;

Alexandre Julliard's avatar
Alexandre Julliard committed
2071
        /* remove all */
2072 2073 2074 2075 2076
	if (himl->cCurImage == 0) {
	    /* remove all on empty ImageList is allowed */
	    TRACE("remove all on empty ImageList!\n");
	    return TRUE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2077

2078
        himl->cMaxImage = himl->cInitial + himl->cGrow - 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2079
        himl->cCurImage = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2080
        for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
Alexandre Julliard's avatar
Alexandre Julliard committed
2081 2082
             himl->nOvlIdx[nCount] = -1;

2083
        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
2084 2085 2086
        SelectObject (himl->hdcImage, hbmNewImage);
        DeleteObject (himl->hbmImage);
        himl->hbmImage = hbmNewImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2087 2088

        if (himl->hbmMask) {
2089

2090
            imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
2091
            hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2092 2093 2094
            SelectObject (himl->hdcMask, hbmNewMask);
            DeleteObject (himl->hbmMask);
            himl->hbmMask = hbmNewMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
2095 2096 2097 2098
        }
    }
    else {
        /* delete one image */
2099
        TRACE("Remove single image! %d\n", i);
Alexandre Julliard's avatar
Alexandre Julliard committed
2100 2101

        /* create new bitmap(s) */
2102
        TRACE(" - Number of images: %d / %d (Old/New)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2103
                 himl->cCurImage, himl->cCurImage - 1);
2104

2105
        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
2106

2107
        imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz );
Alexandre Julliard's avatar
Alexandre Julliard committed
2108
        if (himl->hbmMask)
2109
            hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2110 2111 2112
        else
            hbmNewMask = 0;  /* Just to keep compiler happy! */

2113
        hdcBmp = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2114 2115 2116

        /* copy all images and masks prior to the "removed" image */
        if (i > 0) {
2117
            TRACE("Pre image copy: Copy %d images\n", i);
2118

2119
            SelectObject (hdcBmp, hbmNewImage);
2120
            imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2121 2122

            if (himl->hbmMask) {
2123
                SelectObject (hdcBmp, hbmNewMask);
2124
                imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2125 2126 2127 2128 2129
            }
        }

        /* copy all images and masks behind the removed image */
        if (i < himl->cCurImage - 1) {
2130
            TRACE("Post image copy!\n");
2131

2132
            SelectObject (hdcBmp, hbmNewImage);
2133 2134
            imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
                                   (himl->cCurImage - i), i );
Alexandre Julliard's avatar
Alexandre Julliard committed
2135 2136

            if (himl->hbmMask) {
2137
                SelectObject (hdcBmp, hbmNewMask);
2138 2139
                imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
                                       (himl->cCurImage - i), i );
Alexandre Julliard's avatar
Alexandre Julliard committed
2140 2141 2142
            }
        }

2143
        DeleteDC (hdcBmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
2144 2145

        /* delete old images and insert new ones */
2146
        SelectObject (himl->hdcImage, hbmNewImage);
2147
        DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2148 2149
        himl->hbmImage = hbmNewImage;
        if (himl->hbmMask) {
2150
            SelectObject (himl->hdcMask, hbmNewMask);
2151
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2152 2153 2154 2155 2156 2157
            himl->hbmMask = hbmNewMask;
        }

        himl->cCurImage--;
    }

Eric Kohl's avatar
Eric Kohl committed
2158
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2159 2160 2161
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2162
/*************************************************************************
2163
 * ImageList_Replace [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2164 2165 2166 2167
 *
 * Replaces an image in an image list with a new image.
 *
 * PARAMS
2168
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2169
 *     i        [I] image index
2170 2171
 *     hbmImage [I] handle to image bitmap
 *     hbmMask  [I] handle to mask bitmap. Can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
2172 2173 2174 2175 2176 2177
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2178 2179 2180
BOOL WINAPI
ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
		   HBITMAP hbmMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
2181
{
2182
    HDC hdcImage;
2183
    BITMAP bmp;
2184
    HBITMAP hOldBitmap;
2185
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2186

2187
    TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2188

2189
    if (!is_valid(himl)) {
2190
        ERR("Invalid image list handle!\n");
Eric Kohl's avatar
Eric Kohl committed
2191
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2192
    }
2193

2194
    if ((i >= himl->cMaxImage) || (i < 0)) {
2195
        ERR("Invalid image index!\n");
Eric Kohl's avatar
Eric Kohl committed
2196
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2197
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2198

2199 2200 2201
    if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
        return FALSE;

2202
    hdcImage = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2203 2204

    /* Replace Image */
2205
    hOldBitmap = SelectObject (hdcImage, hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2206

2207 2208
    imagelist_point_from_index(himl, i, &pt);
    StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2209
                  hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2210

Alexandre Julliard's avatar
Alexandre Julliard committed
2211 2212
    if (himl->hbmMask)
    {
2213 2214
        HDC hdcTemp;
        HBITMAP hOldBitmapTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
2215

2216 2217
        hdcTemp   = CreateCompatibleDC(0);
        hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2218

2219
        StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2220 2221 2222
                      hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
        SelectObject(hdcTemp, hOldBitmapTemp);
        DeleteDC(hdcTemp);
2223 2224 2225

        /* Remove the background from the image
        */
2226 2227
        BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
                himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
Alexandre Julliard's avatar
Alexandre Julliard committed
2228 2229
    }

2230
    SelectObject (hdcImage, hOldBitmap);
2231
    DeleteDC (hdcImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2232

Eric Kohl's avatar
Eric Kohl committed
2233
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2234 2235 2236
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2237
/*************************************************************************
2238
 * ImageList_ReplaceIcon [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2239 2240 2241 2242
 *
 * Replaces an image in an image list using an icon.
 *
 * PARAMS
2243
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2244
 *     i     [I] image index
2245
 *     hIcon [I] handle to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
2246 2247 2248 2249 2250 2251
 *
 * RETURNS
 *     Success: index of the replaced image
 *     Failure: -1
 */

2252
INT WINAPI
2253
ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
2254
{
2255
    HDC     hdcImage;
2256
    HICON   hBestFitIcon;
2257
    HBITMAP hbmOldSrc;
2258 2259
    ICONINFO  ii;
    BITMAP  bmp;
2260
    BOOL    ret;
2261
    POINT   pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2262

2263
    TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
2264

2265 2266 2267 2268
    if (!is_valid(himl)) {
        ERR("invalid image list\n");
        return -1;
    }
2269 2270
    if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
        ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2271 2272
        return -1;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2273

2274
    hBestFitIcon = CopyImage(
2275 2276
        hIcon, IMAGE_ICON,
        himl->cx, himl->cy,
2277
        LR_COPYFROMRESOURCE);
2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
    /* the above will fail if the icon wasn't loaded from a resource, so try
     * again without LR_COPYFROMRESOURCE flag */
    if (!hBestFitIcon)
        hBestFitIcon = CopyImage(
            hIcon, IMAGE_ICON,
            himl->cx, himl->cy,
            0);
    if (!hBestFitIcon)
        return -1;

    ret = GetIconInfo (hBestFitIcon, &ii);
    if (!ret) {
        DestroyIcon(hBestFitIcon);
        return -1;
    }
2293

2294 2295 2296 2297 2298 2299 2300 2301 2302 2303
    ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
    if (!ret) {
        ERR("couldn't get mask bitmap info\n");
        if (ii.hbmColor)
            DeleteObject (ii.hbmColor);
        if (ii.hbmMask)
            DeleteObject (ii.hbmMask);
        DestroyIcon(hBestFitIcon);
        return -1;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2304

2305
    if (nIndex == -1) {
2306
        if (himl->cCurImage + 1 > himl->cMaxImage)
2307
            IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2308

Alexandre Julliard's avatar
Alexandre Julliard committed
2309
        nIndex = himl->cCurImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2310
        himl->cCurImage++;
Alexandre Julliard's avatar
Alexandre Julliard committed
2311 2312
    }

2313
    hdcImage = CreateCompatibleDC (0);
2314
    TRACE("hdcImage=%p\n", hdcImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2315
    if (hdcImage == 0)
2316
	ERR("invalid hdcImage!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2317

2318 2319
    imagelist_point_from_index(himl, nIndex, &pt);

2320 2321
    SetTextColor(himl->hdcImage, RGB(0,0,0));
    SetBkColor  (himl->hdcImage, RGB(255,255,255));
2322

2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343
    if (ii.hbmColor)
    {
        hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
        StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
                    hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
        if (himl->hbmMask)
        {
            SelectObject (hdcImage, ii.hbmMask);
            StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
                        hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
        }
    }
    else
    {
        UINT height = bmp.bmHeight / 2;
        hbmOldSrc = SelectObject (hdcImage, ii.hbmMask);
        StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
                    hdcImage, 0, height, bmp.bmWidth, height, SRCCOPY);
        if (himl->hbmMask)
            StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
                        hdcImage, 0, 0, bmp.bmWidth, height, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2344 2345
    }

2346
    SelectObject (hdcImage, hbmOldSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
2347

2348
    DestroyIcon(hBestFitIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
2349
    if (hdcImage)
2350
	DeleteDC (hdcImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2351
    if (ii.hbmColor)
2352
	DeleteObject (ii.hbmColor);
Alexandre Julliard's avatar
Alexandre Julliard committed
2353
    if (ii.hbmMask)
2354
	DeleteObject (ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2355

2356
    TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
Eric Kohl's avatar
Eric Kohl committed
2357
    return nIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
2358 2359 2360
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2361
/*************************************************************************
2362
 * ImageList_SetBkColor [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2363 2364 2365 2366
 *
 * Sets the background color of an image list.
 *
 * PARAMS
2367
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2368 2369 2370 2371 2372 2373 2374 2375 2376
 *     clrBk [I] background color
 *
 * RETURNS
 *     Success: previous background color
 *     Failure: CLR_NONE
 */

COLORREF WINAPI
ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
Alexandre Julliard's avatar
Alexandre Julliard committed
2377 2378 2379
{
    COLORREF clrOldBk;

2380
    if (!is_valid(himl))
Eric Kohl's avatar
Eric Kohl committed
2381
	return CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2382

Alexandre Julliard's avatar
Alexandre Julliard committed
2383 2384
    clrOldBk = himl->clrBk;
    himl->clrBk = clrBk;
Eric Kohl's avatar
Eric Kohl committed
2385
    return clrOldBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
2386 2387 2388
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2389
/*************************************************************************
2390
 * ImageList_SetDragCursorImage [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2391 2392 2393 2394
 *
 * Combines the specified image with the current drag image
 *
 * PARAMS
2395
 *     himlDrag  [I] handle to drag image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2396 2397 2398 2399 2400 2401 2402 2403
 *     iDrag     [I] drag image index
 *     dxHotspot [I] X position of the hot spot
 *     dyHotspot [I] Y position of the hot spot
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
2404
 * NOTES
2405 2406 2407 2408 2409
 *   - The names dxHotspot, dyHotspot are misleading because they have nothing
 *     to do with a hotspot but are only the offset of the origin of the new
 *     image relative to the origin of the old image.
 *
 *   - When this function is called and the drag image is visible, a
2410 2411
 *     short flickering occurs but this matches the Win9x behavior. It is
 *     possible to fix the flickering using code like in ImageList_DragMove.
Alexandre Julliard's avatar
Alexandre Julliard committed
2412 2413
 */

2414 2415 2416
BOOL WINAPI
ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
			      INT dxHotspot, INT dyHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
2417
{
Alexandre Julliard's avatar
Alexandre Julliard committed
2418
    HIMAGELIST himlTemp;
2419
    BOOL visible;
Alexandre Julliard's avatar
Alexandre Julliard committed
2420

2421
    if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
Eric Kohl's avatar
Eric Kohl committed
2422
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2423

2424
    TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2425 2426 2427
	   dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);

    visible = InternalDrag.bShow;
Alexandre Julliard's avatar
Alexandre Julliard committed
2428

2429 2430
    himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
                                dxHotspot, dyHotspot);
Alexandre Julliard's avatar
Alexandre Julliard committed
2431

2432 2433 2434 2435 2436 2437 2438 2439 2440 2441
    if (visible) {
	/* hide the drag image */
	ImageList_DragShowNolock(FALSE);
    }
    if ((InternalDrag.himl->cx != himlTemp->cx) ||
	   (InternalDrag.himl->cy != himlTemp->cy)) {
	/* the size of the drag image changed, invalidate the buffer */
	DeleteObject(InternalDrag.hbmBg);
	InternalDrag.hbmBg = 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2442

2443 2444 2445 2446 2447 2448
    ImageList_Destroy (InternalDrag.himl);
    InternalDrag.himl = himlTemp;

    if (visible) {
	/* show the drag image */
	ImageList_DragShowNolock(TRUE);
2449
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2450

2451
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2452 2453 2454
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2455
/*************************************************************************
2456
 * ImageList_SetFilter [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2457 2458
 *
 * Sets a filter (or does something completely different)!!???
2459
 * It removes 12 Bytes from the stack (3 Parameters).
Alexandre Julliard's avatar
Alexandre Julliard committed
2460 2461
 *
 * PARAMS
2462 2463
 *     himl     [I] SHOULD be a handle to image list
 *     i        [I] COULD be an index?
Alexandre Julliard's avatar
Alexandre Julliard committed
2464 2465 2466
 *     dwFilter [I] ???
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
2467 2468
 *     Success: TRUE ???
 *     Failure: FALSE ???
Alexandre Julliard's avatar
Alexandre Julliard committed
2469 2470
 *
 * BUGS
Alexandre Julliard's avatar
Alexandre Julliard committed
2471
 *     This is an UNDOCUMENTED function!!!!
Alexandre Julliard's avatar
Alexandre Julliard committed
2472 2473 2474
 *     empty stub.
 */

2475 2476
BOOL WINAPI
ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
Alexandre Julliard's avatar
Alexandre Julliard committed
2477
{
2478
    FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
Alexandre Julliard's avatar
Alexandre Julliard committed
2479

Alexandre Julliard's avatar
Alexandre Julliard committed
2480
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2481 2482 2483
}


2484
/*************************************************************************
2485
 * ImageList_SetFlags [COMCTL32.@]
2486
 *
2487 2488 2489 2490 2491 2492 2493 2494 2495
 * Sets the image list flags.
 *
 * PARAMS
 *     himl  [I] Handle to image list
 *     flags [I] Flags to set
 *
 * RETURNS
 *     Old flags?
 *
2496 2497 2498 2499 2500 2501 2502
 * BUGS
 *    Stub.
 */

DWORD WINAPI
ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
{
2503
    FIXME("(%p %08x):empty stub\n", himl, flags);
2504 2505 2506 2507
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2508
/*************************************************************************
2509
 * ImageList_SetIconSize [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2510 2511 2512 2513
 *
 * Sets the image size of the bitmap and deletes all images.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
2514
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2515 2516 2517 2518 2519 2520 2521 2522
 *     cx   [I] image width
 *     cy   [I] image height
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2523 2524
BOOL WINAPI
ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
2525
{
2526
    INT nCount;
2527
    HBITMAP hbmNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
2528

2529
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2530
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2531

2532
    /* remove all images */
2533
    himl->cMaxImage = himl->cInitial + 1;
Eric Kohl's avatar
Eric Kohl committed
2534 2535 2536
    himl->cCurImage = 0;
    himl->cx        = cx;
    himl->cy        = cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2537 2538 2539 2540 2541

    /* initialize overlay mask indices */
    for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
        himl->nOvlIdx[nCount] = -1;

2542
    hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
2543 2544 2545
    SelectObject (himl->hdcImage, hbmNew);
    DeleteObject (himl->hbmImage);
    himl->hbmImage = hbmNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
2546 2547

    if (himl->hbmMask) {
2548
        SIZE sz;
2549
        imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
2550
        hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2551 2552 2553
        SelectObject (himl->hdcMask, hbmNew);
        DeleteObject (himl->hbmMask);
        himl->hbmMask = hbmNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
2554 2555
    }

Eric Kohl's avatar
Eric Kohl committed
2556
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2557 2558 2559
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2560
/*************************************************************************
2561
 * ImageList_SetImageCount [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2562 2563 2564 2565
 *
 * Resizes an image list to the specified number of images.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
2566
 *     himl        [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2567 2568 2569 2570 2571 2572 2573
 *     iImageCount [I] number of images in the image list
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2574
BOOL WINAPI
2575
ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
Alexandre Julliard's avatar
Alexandre Julliard committed
2576
{
2577
    HDC     hdcBitmap;
2578
    HBITMAP hbmNewBitmap, hbmOld;
2579
    INT     nNewCount, nCopyCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2580

2581 2582
    TRACE("%p %d\n",himl,iImageCount);

2583
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2584 2585
	return FALSE;
    if (himl->cMaxImage > iImageCount)
2586 2587
    {
        himl->cCurImage = iImageCount;
2588
        /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
Alexandre Julliard's avatar
Alexandre Julliard committed
2589
	return TRUE;
2590
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2591

Alexandre Julliard's avatar
Alexandre Julliard committed
2592
    nNewCount = iImageCount + himl->cGrow;
2593
    nCopyCount = min(himl->cCurImage, iImageCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
2594

2595
    hdcBitmap = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2596

2597
    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cx);
2598

2599
    if (hbmNewBitmap != 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
2600
    {
2601
        hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2602
        imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2603
        SelectObject (hdcBitmap, hbmOld);
2604 2605

	/* FIXME: delete 'empty' image space? */
Eric Kohl's avatar
Eric Kohl committed
2606

2607
        SelectObject (himl->hdcImage, hbmNewBitmap);
2608
	DeleteObject (himl->hbmImage);
2609
	himl->hbmImage = hbmNewBitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
2610 2611
    }
    else
2612
	ERR("Could not create new image bitmap !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2613 2614 2615

    if (himl->hbmMask)
    {
2616
        SIZE sz;
2617
        imagelist_get_bitmap_size( himl, nNewCount, himl->cx, &sz );
2618
        hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2619 2620
        if (hbmNewBitmap != 0)
        {
2621
            hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2622
            imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
2623
            SelectObject (hdcBitmap, hbmOld);
2624 2625

	    /* FIXME: delete 'empty' image space? */
Eric Kohl's avatar
Eric Kohl committed
2626

2627
            SelectObject (himl->hdcMask, hbmNewBitmap);
2628
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2629 2630 2631
            himl->hbmMask = hbmNewBitmap;
        }
        else
2632
            ERR("Could not create new mask bitmap!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2633 2634
    }

2635
    DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
2636

Alexandre Julliard's avatar
Alexandre Julliard committed
2637 2638
    /* Update max image count and current image count */
    himl->cMaxImage = nNewCount;
2639
    himl->cCurImage = iImageCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2640

Alexandre Julliard's avatar
Alexandre Julliard committed
2641
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2642 2643 2644
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2645
/*************************************************************************
2646
 * ImageList_SetOverlayImage [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2647 2648 2649 2650
 *
 * Assigns an overlay mask index to an existing image in an image list.
 *
 * PARAMS
2651
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2652 2653 2654 2655 2656 2657 2658 2659
 *     iImage   [I] image index
 *     iOverlay [I] overlay mask index
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2660 2661
BOOL WINAPI
ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
Alexandre Julliard's avatar
Alexandre Julliard committed
2662
{
2663
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2664 2665 2666
	return FALSE;
    if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
	return FALSE;
2667
    if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
Alexandre Julliard's avatar
Alexandre Julliard committed
2668
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2669
    himl->nOvlIdx[iOverlay - 1] = iImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2670
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2671 2672
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2673

2674

2675
/* helper for ImageList_Write - write bitmap to pstm
2676 2677
 * currently everything is written as 24 bit RGB, except masks
 */
2678
static BOOL
2679
_write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
2680 2681 2682
{
    LPBITMAPFILEHEADER bmfh;
    LPBITMAPINFOHEADER bmih;
2683
    LPBYTE data = NULL, lpBits;
2684 2685 2686 2687 2688
    BITMAP bm;
    INT bitCount, sizeImage, offBits, totalSize;
    HDC xdc;
    BOOL result = FALSE;

2689
    if (!GetObjectW(hBitmap, sizeof(BITMAP), (LPVOID)&bm))
2690
        return FALSE;
2691 2692

    bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2693
    sizeImage = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, bitCount);
2694 2695 2696 2697 2698

    totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    if(bitCount != 24)
	totalSize += (1 << bitCount) * sizeof(RGBQUAD);
    offBits = totalSize;
2699
    totalSize += sizeImage;
2700

2701
    data = Alloc(totalSize);
2702 2703 2704 2705 2706 2707
    bmfh = (LPBITMAPFILEHEADER)data;
    bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
    lpBits = data + offBits;

    /* setup BITMAPFILEHEADER */
    bmfh->bfType      = (('M' << 8) | 'B');
2708
    bmfh->bfSize      = offBits;
2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
    bmfh->bfReserved1 = 0;
    bmfh->bfReserved2 = 0;
    bmfh->bfOffBits   = offBits;

    /* setup BITMAPINFOHEADER */
    bmih->biSize          = sizeof(BITMAPINFOHEADER);
    bmih->biWidth         = bm.bmWidth;
    bmih->biHeight        = bm.bmHeight;
    bmih->biPlanes        = 1;
    bmih->biBitCount      = bitCount;
    bmih->biCompression   = BI_RGB;
2720
    bmih->biSizeImage     = sizeImage;
2721 2722 2723 2724 2725
    bmih->biXPelsPerMeter = 0;
    bmih->biYPelsPerMeter = 0;
    bmih->biClrUsed       = 0;
    bmih->biClrImportant  = 0;

2726 2727 2728 2729
    xdc = GetDC(0);
    result = GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBits, (BITMAPINFO *)bmih, DIB_RGB_COLORS) == bm.bmHeight;
    ReleaseDC(0, xdc);
    if (!result)
2730
	goto failed;
2731

2732 2733 2734
    TRACE("width %u, height %u, planes %u, bpp %u\n",
          bmih->biWidth, bmih->biHeight,
          bmih->biPlanes, bmih->biBitCount);
2735 2736

    if(bitCount == 1) {
2737
        /* Hack. */
2738 2739 2740 2741 2742
	LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
	inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
	inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
    }

2743
    if(FAILED(IStream_Write(pstm, data, totalSize, NULL)))
2744 2745 2746 2747
	goto failed;

    result = TRUE;

2748 2749
failed:
    Free(data);
2750 2751 2752 2753 2754

    return result;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2755
/*************************************************************************
2756
 * ImageList_Write [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2757 2758 2759 2760
 *
 * Writes an image list to a stream.
 *
 * PARAMS
2761
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2762 2763 2764 2765 2766 2767 2768
 *     pstm [O] Pointer to a stream.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * BUGS
2769
 *     probably.
Alexandre Julliard's avatar
Alexandre Julliard committed
2770 2771
 */

2772 2773
BOOL WINAPI
ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
Alexandre Julliard's avatar
Alexandre Julliard committed
2774
{
2775 2776 2777
    ILHEAD ilHead;
    int i;

2778 2779
    TRACE("%p %p\n", himl, pstm);

2780
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2781
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2782

2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
    ilHead.usMagic   = (('L' << 8) | 'I');
    ilHead.usVersion = 0x101;
    ilHead.cCurImage = himl->cCurImage;
    ilHead.cMaxImage = himl->cMaxImage;
    ilHead.cGrow     = himl->cGrow;
    ilHead.cx        = himl->cx;
    ilHead.cy        = himl->cy;
    ilHead.bkcolor   = himl->clrBk;
    ilHead.flags     = himl->flags;
    for(i = 0; i < 4; i++) {
	ilHead.ovls[i] = himl->nOvlIdx[i];
    }

2796 2797 2798
    TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
          ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);

2799
    if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2800 2801 2802
	return FALSE;

    /* write the bitmap */
2803
    if(!_write_bitmap(himl->hbmImage, pstm))
2804 2805 2806 2807
	return FALSE;

    /* write the mask if we have one */
    if(himl->flags & ILC_MASK) {
2808
	if(!_write_bitmap(himl->hbmMask, pstm))
2809 2810
	    return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2811

2812
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2813
}
2814 2815


2816
static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width)
2817 2818 2819
{
    HBITMAP hbmNewBitmap;
    UINT ilc = (himl->flags & 0xFE);
2820 2821
    SIZE sz;

2822
    imagelist_get_bitmap_size( himl, count, width, &sz );
2823 2824 2825 2826

    if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
    {
        VOID* bits;
2827
        BITMAPINFO *bmi;
2828

2829 2830
        TRACE("Creating DIBSection %d x %d, %d Bits per Pixel\n",
              sz.cx, sz.cy, himl->uBitsPixel);
2831

2832 2833 2834 2835 2836 2837 2838
	if (himl->uBitsPixel <= ILC_COLOR8)
	{
	    LPPALETTEENTRY pal;
	    ULONG i, colors;
	    BYTE temp;

	    colors = 1 << himl->uBitsPixel;
2839
	    bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855
	                    sizeof(PALETTEENTRY) * colors);

	    pal = (LPPALETTEENTRY)bmi->bmiColors;
	    GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);

	    /* Swap colors returned by GetPaletteEntries so we can use them for
	     * CreateDIBSection call. */
	    for (i = 0; i < colors; i++)
	    {
	        temp = pal[i].peBlue;
	        bmi->bmiColors[i].rgbRed = pal[i].peRed;
	        bmi->bmiColors[i].rgbBlue = temp;
	    }
	}
	else
	{
2856
	    bmi = Alloc(sizeof(BITMAPINFOHEADER));
2857 2858 2859
	}

	bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2860 2861
	bmi->bmiHeader.biWidth = sz.cx;
	bmi->bmiHeader.biHeight = sz.cy;
2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
	bmi->bmiHeader.biPlanes = 1;
	bmi->bmiHeader.biBitCount = himl->uBitsPixel;
	bmi->bmiHeader.biCompression = BI_RGB;
	bmi->bmiHeader.biSizeImage = 0;
	bmi->bmiHeader.biXPelsPerMeter = 0;
	bmi->bmiHeader.biYPelsPerMeter = 0;
	bmi->bmiHeader.biClrUsed = 0;
	bmi->bmiHeader.biClrImportant = 0;

	hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);

2873
	Free (bmi);
2874 2875 2876 2877 2878
    }
    else /*if (ilc == ILC_COLORDDB)*/
    {
        TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);

2879
        hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
2880
    }
2881
    TRACE("returning %p\n", hbmNewBitmap);
2882 2883
    return hbmNewBitmap;
}
2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908

/*************************************************************************
 * ImageList_SetColorTable [COMCTL32.@]
 *
 * Sets the color table of an image list.
 *
 * PARAMS
 *     himl        [I] Handle to the image list.
 *     uStartIndex [I] The first index to set.
 *     cEntries    [I] Number of entries to set.
 *     prgb        [I] New color information for color table for the image list.
 *
 * RETURNS
 *     Success: Number of entries in the table that were set.
 *     Failure: Zero.
 *
 * SEE
 *     ImageList_Create(), SetDIBColorTable()
 */

UINT WINAPI
ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
{
    return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
}