imagelist.c 80.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *  ImageList implementation
 *
 *  Copyright 1998 Eric Kohl
5
 *            2000 Jason Mawdsley.
6
 *            2001 Michael Stefaniuc
7
 *            2001 Charles Loep for CodeWeavers
Alexandre Julliard's avatar
Alexandre Julliard committed
8
 *
9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
23
 *  TODO:
Eric Kohl's avatar
Eric Kohl committed
24
 *    - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
Alexandre Julliard's avatar
Alexandre Julliard committed
25
 *    - Fix ImageList_GetIcon.
Alexandre Julliard's avatar
Alexandre Julliard committed
26
 *    - Fix ImageList_SetFilter (undocumented).
Alexandre Julliard's avatar
Alexandre Julliard committed
27 28 29 30 31 32 33 34 35
 *      BTW does anybody know anything about this function???
 *        - It removes 12 Bytes from the stack (3 Parameters).
 *        - First parameter SHOULD be a HIMAGELIST.
 *        - Second parameter COULD be an index?????
 *        - Third parameter.... ?????????????????????
 *
 *  Comments:
 *    - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
 *      ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
Andreas Mohr's avatar
Andreas Mohr committed
36
 *      partially implemented, the functions mentioned above will be 
Alexandre Julliard's avatar
Alexandre Julliard committed
37
 *      limited in functionality too.
38 39 40 41 42
 *
 *    - Hotspot handling still not correct. The Hotspot passed to BeginDrag
 *	is the offset of the image position relative to the actual mouse pointer
 *	position. However the Hotspot passed to SetDragCursorImage is the
 *	offset of the mouse messages sent to the application...
Alexandre Julliard's avatar
Alexandre Julliard committed
43 44
 */

45
#include <stdlib.h>
46
#include <string.h>
47 48
#include "winerror.h"
#include "winbase.h"
49 50
#include "wine/obj_base.h"
#include "wine/obj_storage.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
51
#include "commctrl.h"
52
#include "imagelist.h"
53
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
54

55
WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
56

Alexandre Julliard's avatar
Alexandre Julliard committed
57

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

Alexandre Julliard's avatar
Alexandre Julliard committed
60
/* internal image list data used for Drag & Drop operations */
61 62 63 64 65 66 67 68 69 70 71 72 73 74
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;
75
    BOOL	bHSPending;
76
} INTERNALDRAG;
Alexandre Julliard's avatar
Alexandre Julliard committed
77

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


Alexandre Julliard's avatar
Alexandre Julliard committed
81

Alexandre Julliard's avatar
Alexandre Julliard committed
82
/*************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
83 84 85
 * IMAGELIST_InternalExpandBitmaps [Internal] 
 *
 * Expands the bitmaps of an image list by the given number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
86
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
87
 * PARAMS
88 89
 *     himl        [I] handle to image list
 *     nImageCount [I] number of images to add
Alexandre Julliard's avatar
Alexandre Julliard committed
90 91 92 93 94 95
 *
 * RETURNS
 *     nothing
 *
 * NOTES
 *     This function can NOT be used to reduce the number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
96
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
97
static VOID
98
IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
99
{
100 101 102
    HDC     hdcImageList, hdcBitmap;
    HBITMAP hbmNewBitmap;
    INT     nNewWidth, nNewCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
103

104
    if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
105 106
        && (himl->cy >= cy))
	return;
Alexandre Julliard's avatar
Alexandre Julliard committed
107

108
    if (cy == 0) cy = himl->cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
109 110
    nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
    nNewWidth = nNewCount * himl->cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
111

112
    TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
113 114
    hdcImageList = CreateCompatibleDC (0);
    hdcBitmap = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
115 116

    hbmNewBitmap =
117
        CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
118
    if (hbmNewBitmap == 0)
119
        ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
120

121 122
    SelectObject (hdcImageList, himl->hbmImage);
    SelectObject (hdcBitmap, hbmNewBitmap);
123
    BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
124 125
              hdcImageList, 0, 0, SRCCOPY);

126
    DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
127 128 129 130
    himl->hbmImage = hbmNewBitmap;

    if (himl->hbmMask) {
        hbmNewBitmap = 
131
            CreateBitmap (nNewWidth, cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
132 133

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

136 137
        SelectObject (hdcImageList, himl->hbmMask);
        SelectObject (hdcBitmap, hbmNewBitmap);
138
        BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
139
                  hdcImageList, 0, 0, SRCCOPY);
140
        DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
141 142 143
        himl->hbmMask = hbmNewBitmap;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
144 145
    himl->cMaxImage = nNewCount;

146 147
    DeleteDC (hdcImageList);
    DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
148 149 150
}


151 152 153 154 155 156 157 158 159 160 161 162 163 164
/*************************************************************************
 * IMAGELIST_InternalDraw [Internal] 
 *
 * Draws the image in the ImageList (without the mask)
 *
 * PARAMS
 *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
 *     cx            [I] the width of the image to display
 *     cy............[I] the height of the image to display
 *
 * RETURNS
 *     nothing
 *
 * NOTES
165
 *     This function is used by ImageList_DrawIndirect, when it is 
166 167
 *     required to draw only the Image (without the mask) to the screen.
 *
168
 *     Blending and Overlays styles are accomplished by another function
169 170 171 172 173 174
 */
static VOID
IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
{
    HDC hImageDC;
    HBITMAP hOldBitmap;
175

176 177 178 179 180 181 182 183 184 185 186 187 188
    hImageDC = CreateCompatibleDC(0);
    hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
    BitBlt(pimldp->hdcDst, 
        pimldp->x, pimldp->y, cx, cy,
        hImageDC, 
        pimldp->himl->cx * pimldp->i, 0, 
        SRCCOPY);

    SelectObject(hImageDC, hOldBitmap);
    DeleteDC(hImageDC);
}


189 190 191
/*************************************************************************
 * IMAGELIST_InternalDrawMask [Internal] 
 *
192
 * Draws the image in the ImageList with the mask
193 194 195 196 197 198 199 200 201 202
 *
 * PARAMS
 *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
 *     cx            [I] the width of the image to display
 *     cy............[I] the height of the image to display
 *
 * RETURNS
 *     nothing
 *
 * NOTES
203
 *     This function is used by ImageList_DrawIndirect, when it is 
204 205
 *     required to draw the Image with the mask to the screen.
 *
206
 *     Blending and Overlays styles are accomplished by another function.
207 208 209 210 211 212
 */
static VOID
IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
{
    BOOL bUseCustomBackground, bBlendFlag;
    HBRUSH hBrush, hOldBrush;
213
    HDC     hMaskDC, hImageDC;
214 215
    HBITMAP hOldBitmapImage, hOldBitmapMask;
    HIMAGELIST himlLocal = pimldp->himl;
216
    COLORREF oldBkColor, oldFgColor;
217
    UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
218

219 220 221 222 223 224 225
    /* 
     * We need a dc and bitmap to draw on that is 
     * not on the screen.
     */
    HDC hOffScreenDC = 0;
    HBITMAP hOffScreenBmp = 0;

226
    bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
227
    bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
228 229 230 231

    hImageDC = CreateCompatibleDC(0);
    hMaskDC = CreateCompatibleDC(0);

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
    /* Create a compatible DC. */
    hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );

    if ( hOffScreenDC ) 
    {
        hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );

        if ( hOffScreenBmp ) 
            SelectObject( hOffScreenDC, hOffScreenBmp  );
        else
            goto cleanup;
    }
    else
        goto cleanup;

247 248
    hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
    hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    
    /* 
     * Get a copy of the image for the masking operations. 
     * We will use the copy, and this dc for all the various
     * blitting, and then do one final blit to the screen dc.
     * This should clean up most of the flickering.
     */
    BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x, 
            pimldp->y, SRCCOPY);

    /* 
     * Draw the Background for the appropriate Styles
     */
    if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE 
         || bBlendFlag) )
264
    {
265
        
266 267
        hBrush = CreateSolidBrush (himlLocal->clrBk);
        hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
268 269
        
        PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
270 271 272 273

        DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
    }

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
    /* 
     * Draw Image Transparently over the current background
     */
    if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) || 
       ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag) 
    {   /* 
         * To obtain a transparent look, background color should be set
         * to white and foreground color to black when blting the 
         * monochrome mask. 
         */
        
        oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) ); 
        oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );

        BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
                0, SRCAND );

        BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
                0, SRCPAINT );
    
294
    }
295 296 297 298
    
    /*
     * Draw the image when no Background is specified
     */
299
    else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
300
    {
301 302
        BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC, 
                himlLocal->cx * pimldp->i, 0, SRCCOPY);
303
    }
304 305 306
    /* 
     * Draw the mask with or without a background
     */
307
    else if(fStyle & ILD_MASK)
308
    {
309 310
        BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
                0, bUseCustomBackground ? SRCCOPY : SRCAND);
311
    }
312 313 314 315 316 317 318 319
    
    /*
     * Blit the bitmap to the screen now.
     */
    BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
            hOffScreenDC, 0, 0, SRCCOPY);

    
320 321
    SelectObject(hImageDC, hOldBitmapImage);
    SelectObject(hMaskDC, hOldBitmapMask);
322 323 324
    
cleanup:
    
325 326
    DeleteDC(hImageDC);
    DeleteDC(hMaskDC);
327 328 329 330 331
    
    DeleteDC( hOffScreenDC );
    DeleteObject( hOffScreenBmp );
    
    return;
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
}

/*************************************************************************
 * IMAGELIST_InternalDrawBlend [Internal] 
 *
 * Draws the Blend over the current image 
 *
 * PARAMS
 *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
 *     cx            [I] the width of the image to display
 *     cy............[I] the height of the image to display
 *
 * RETURNS
 *     nothing
 *
 * NOTES
 *     This functions is used by ImageList_DrawIndirect, when it is 
 *     required to add the blend to the current image.  
 *     
 */
static VOID
IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
{

    HDC         hBlendMaskDC,hMaskDC;
    HBRUSH      hBlendColorBrush, hBlendBrush, hOldBrush;
    HBITMAP     hBlendMaskBitmap, hOldBitmap;
    COLORREF    clrBlend, OldTextColor, OldBkColor;
    HIMAGELIST  himlLocal = pimldp->himl;

    clrBlend = GetSysColor (COLOR_HIGHLIGHT);
    if (!(pimldp->rgbFg == CLR_DEFAULT))
    {
        clrBlend = pimldp->rgbFg;
    }
    /* Create the blend Mask
    */
    hBlendMaskDC = CreateCompatibleDC(0);
    hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
        himlLocal->hbrBlend50 : himlLocal->hbrBlend25;

    hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
    hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);

    hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
    PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
    SelectObject(hBlendMaskDC, hOldBrush);

    /* Modify the blend mask if an Image Mask exist
    */
    if(pimldp->himl->hbmMask != 0)
    {
        HBITMAP hOldMaskBitmap;
        hMaskDC = CreateCompatibleDC(0);
        hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);

        BitBlt(hBlendMaskDC,
            0,0, cx, cy, 
            hMaskDC,
            himlLocal->cx * pimldp->i,0,
            0x220326); /* NOTSRCAND */

        BitBlt(hBlendMaskDC,
            0,0, cx, cy, 
            hBlendMaskDC,
            0,0, 
            NOTSRCCOPY);

        SelectObject(hMaskDC, hOldMaskBitmap);
        DeleteDC(hMaskDC);

    }
    /* Apply blend to the current image given the BlendMask
    */
    OldTextColor = SetTextColor(pimldp->hdcDst, 0);
    OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
    hBlendColorBrush = CreateSolidBrush(clrBlend);
    hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);

    BitBlt (pimldp->hdcDst, 
        pimldp->x, pimldp->y, cx, cy, 
        hBlendMaskDC, 
        0, 0, 
        0xB8074A); /* PSDPxax */

    SelectObject(pimldp->hdcDst, hOldBrush);
    SetTextColor(pimldp->hdcDst, OldTextColor);
    SetBkColor(pimldp->hdcDst, OldBkColor);
    SelectObject(hBlendMaskDC, hOldBitmap);
    DeleteDC(hBlendMaskDC);
    DeleteObject(hBlendMaskBitmap);
    DeleteObject(hBlendColorBrush);
}

/*************************************************************************
 * IMAGELIST_InternalDrawOverlay [Internal] 
 *
 * Draws the overlay image 
 *
 * PARAMS
 *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
 *     cx            [I] the width of the image to display
 *     cy............[I] the height of the image to display
 *
 * RETURNS
 *     nothing
 *
 * NOTES
 *     This functions is used by ImageList_DrawIndirect, when it is 
 *     required to draw the overlay
 *
 *     
 */
static VOID 
IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
{
    INT     nOvlIdx;
    HDC     hImageDC;
    HBITMAP hOldBitmap;

452
    nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
    {
        nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
        if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
        {
            hImageDC = CreateCompatibleDC(0);
            if (pimldp->himl->hbmMask)
            {
                hOldBitmap = (HBITMAP) SelectObject (hImageDC, 
                    pimldp->himl->hbmMask);

                BitBlt (pimldp->hdcDst, 
                    pimldp->x, pimldp->y, cx, cy,
                    hImageDC, pimldp->himl->cx * nOvlIdx, 0,
                    SRCAND);

                SelectObject(hImageDC, hOldBitmap);
            }
            hOldBitmap = (HBITMAP) SelectObject (hImageDC, 
                pimldp->himl->hbmImage);

            BitBlt (pimldp->hdcDst, 
                pimldp->x, pimldp->y, cx, cy, 
                hImageDC,
                pimldp->himl->cx * nOvlIdx, 0,
                SRCPAINT);

            SelectObject(hImageDC, hOldBitmap);
            DeleteDC(hImageDC);
        }
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
487
/*************************************************************************
488
 * ImageList_Add [COMCTL32.40]
Alexandre Julliard's avatar
Alexandre Julliard committed
489 490
 *
 * Add an image or images to an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
491
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
492
 * PARAMS
493 494 495
 *     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
496
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
497 498 499
 * RETURNS
 *     Success: Index of the first new image.
 *     Failure: -1
Alexandre Julliard's avatar
Alexandre Julliard committed
500 501
 */

502 503
INT WINAPI
ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
504
{
505 506 507 508 509
    HDC     hdcImage, hdcBitmap;
    INT     nFirstIndex, nImageCount;
    INT     nStartX;
    BITMAP  bmp;
    HBITMAP hOldBitmapImage, hOldBitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
510

511
    TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
512
    if (!himl || !hbmImage)
513
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
514

515
    GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
516 517
    nImageCount = bmp.bmWidth / himl->cx;

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

Alexandre Julliard's avatar
Alexandre Julliard committed
520 521
    nStartX = himl->cCurImage * himl->cx;

522 523
    hdcImage  = CreateCompatibleDC(0);
    hdcBitmap = CreateCompatibleDC(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
524

525 526 527 528 529
    hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
    hOldBitmap = SelectObject(hdcBitmap, hbmImage);

    /* Copy result to the imagelist
    */
530
    BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
531 532 533 534 535 536 537 538 539 540 541 542
        hdcBitmap, 0, 0, SRCCOPY);

    if(himl->hbmMask)
    {
        HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;

        hdcMask   = CreateCompatibleDC (0);
        hdcTemp   = CreateCompatibleDC(0);
        hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
        hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);

        BitBlt (hdcMask, 
543
            nStartX, 0, bmp.bmWidth, bmp.bmHeight,
544 545 546 547 548 549 550 551 552 553
            hdcTemp, 
            0, 0, 
            SRCCOPY);

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

        /* Remove the background from the image
        */
        BitBlt (hdcImage, 
554
            nStartX, 0, bmp.bmWidth, bmp.bmHeight,
555 556 557 558 559 560
            hdcMask, 
            nStartX, 0, 
            0x220326); /* NOTSRCAND */

        SelectObject(hdcMask, hOldBitmapMask);
        DeleteDC(hdcMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
561 562
    }

563 564 565 566
    SelectObject(hdcImage, hOldBitmapImage);
    SelectObject(hdcBitmap, hOldBitmap);
    DeleteDC(hdcImage);
    DeleteDC(hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
567 568 569 570

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

Alexandre Julliard's avatar
Alexandre Julliard committed
571
    return nFirstIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
572 573 574
}


Alexandre Julliard's avatar
Alexandre Julliard committed
575
/*************************************************************************
576
 * ImageList_AddIcon [COMCTL32.41]
Alexandre Julliard's avatar
Alexandre Julliard committed
577 578 579 580
 *
 * Adds an icon to an image list.
 *
 * PARAMS
581 582
 *     himl  [I] handle to image list
 *     hIcon [I] handle to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
583 584 585 586 587 588
 *
 * RETURNS
 *     Success: index of the new image
 *     Failure: -1
 */

589 590
INT WINAPI
ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
591
{
592
    return ImageList_ReplaceIcon (himl, -1, hIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
593 594 595
}


Alexandre Julliard's avatar
Alexandre Julliard committed
596
/*************************************************************************
597
 * ImageList_AddMasked [COMCTL32.42] 
Alexandre Julliard's avatar
Alexandre Julliard committed
598
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
599 600
 * 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
601
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
602
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
603 604 605
 *     himl    [I] handle to image list.
 *     hBitmap [I] handle to bitmap
 *     clrMask [I] mask color.
Alexandre Julliard's avatar
Alexandre Julliard committed
606 607 608 609
 *
 * RETURNS
 *     Success: Index of the first new image.
 *     Failure: -1
Alexandre Julliard's avatar
Alexandre Julliard committed
610 611
 */

612 613
INT WINAPI
ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
614
{
615
    HDC    hdcImage, hdcMask, hdcBitmap;
616
    INT    nIndex, nImageCount, nMaskXOffset=0;
617
    BITMAP bmp;
618 619 620
    HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
    HBITMAP hMaskBitmap=0;
    COLORREF bkColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
621

622
    TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
623
    if (himl == NULL)
624
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
625

626
    if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
627
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
628

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

631
    IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
Alexandre Julliard's avatar
Alexandre Julliard committed
632 633 634 635

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

636 637 638
    hdcMask   = CreateCompatibleDC (0);
    hdcImage  = CreateCompatibleDC(0);
    hdcBitmap = CreateCompatibleDC(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
639 640


641 642 643 644 645 646 647 648 649 650 651 652 653
    hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
    hOldBitmap = SelectObject(hdcBitmap, hBitmap);
    if(himl->hbmMask)
    {
        hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
        nMaskXOffset = nIndex * himl->cx;
    }
    else
    {
        /*
            Create a temp Mask so we can remove the background of
            the Image (Windows does this even if there is no mask)
        */
654
        hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
655 656 657 658 659 660 661 662
        hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
        nMaskXOffset = 0;
    }
    /* create monochrome image to the mask bitmap */
    bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
        GetPixel (hdcBitmap, 0, 0);
    SetBkColor (hdcBitmap, bkColor);
    BitBlt (hdcMask, 
663
        nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
664 665 666 667 668 669 670 671 672 673 674
        hdcBitmap, 0, 0, 
        SRCCOPY);

    SetBkColor(hdcBitmap, RGB(255,255,255));
    /*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
675
        by using the same bitmap to iterate the different styles
676
        on windows where it failed (BUT ImageList_Add is OK)
677
        This is here in case some apps rely on this bug
678 679
    */
    BitBlt(hdcBitmap, 
680
        0, 0, bmp.bmWidth, bmp.bmHeight,
681 682 683 684 685 686
        hdcMask, 
        nMaskXOffset, 0, 
        0x220326); /* NOTSRCAND */
    /* Copy result to the imagelist
    */
    BitBlt (hdcImage, 
687
        nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
688 689 690 691 692 693 694 695 696 697 698 699 700 701
        hdcBitmap, 
        0, 0, 
        SRCCOPY);
    /* Clean up
    */
    SelectObject(hdcMask,hOldBitmapMask);
    SelectObject(hdcImage, hOldBitmapImage);
    SelectObject(hdcBitmap, hOldBitmap);
    DeleteDC(hdcMask);
    DeleteDC(hdcImage);
    DeleteDC(hdcBitmap);
    if(!himl->hbmMask)
    {
        DeleteObject(hMaskBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
702 703
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
704
    return nIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
705 706 707
}


Alexandre Julliard's avatar
Alexandre Julliard committed
708
/*************************************************************************
709
 * ImageList_BeginDrag [COMCTL32.43] 
Alexandre Julliard's avatar
Alexandre Julliard committed
710
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
711 712
 * Creates a temporary image list that contains one image. It will be used
 * as a drag image.
Alexandre Julliard's avatar
Alexandre Julliard committed
713
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
714
 * PARAMS
715 716
 *     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
717 718 719 720 721 722
 *     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
723 724
 */

725 726 727
BOOL WINAPI
ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
	             INT dxHotspot, INT dyHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
728
{
729
    HDC hdcSrc, hdcDst;
730
    INT cx, cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
731

732 733
    TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
	  dxHotspot, dyHotspot);
Alexandre Julliard's avatar
Alexandre Julliard committed
734 735

    if (himlTrack == NULL)
736
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
737

738 739 740
    if (InternalDrag.himl)
        ImageList_EndDrag ();

741 742 743
    cx = himlTrack->cx;
    cy = himlTrack->cy;

744 745
    InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
    if (InternalDrag.himl == NULL) {
746
        ERR("Error creating drag image list!\n");
747
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
748 749
    }

750 751
    InternalDrag.dxHotspot = dxHotspot;
    InternalDrag.dyHotspot = dyHotspot;
Alexandre Julliard's avatar
Alexandre Julliard committed
752

753 754
    hdcSrc = CreateCompatibleDC (0);
    hdcDst = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
755 756

    /* copy image */
757
    SelectObject (hdcSrc, himlTrack->hbmImage);
758
    SelectObject (hdcDst, InternalDrag.himl->hbmImage);
759
    BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
760 761

    /* copy mask */
762
    SelectObject (hdcSrc, himlTrack->hbmMask);
763
    SelectObject (hdcDst, InternalDrag.himl->hbmMask);
764
    BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
765

766 767
    DeleteDC (hdcSrc);
    DeleteDC (hdcDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
768

769
    InternalDrag.himl->cCurImage = 1;
770
    InternalDrag.bHSPending = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
771

772
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
773 774 775 776
}


/*************************************************************************
777
 * ImageList_Copy [COMCTL32.44] 
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779 780
 *
 *  Copies an image of the source image list to an image of the 
 *  destination image list. Images can be copied or swapped.
Alexandre Julliard's avatar
Alexandre Julliard committed
781
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
782
 * PARAMS
783
 *     himlDst [I] handle to the destination image list
Alexandre Julliard's avatar
Alexandre Julliard committed
784
 *     iDst    [I] destination image index.
785
 *     himlSrc [I] handle to the source image list
Alexandre Julliard's avatar
Alexandre Julliard committed
786 787
 *     iSrc    [I] source image index
 *     uFlags  [I] flags for the copy operation
Alexandre Julliard's avatar
Alexandre Julliard committed
788
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
789 790 791 792 793 794
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Copying from one image list to another is possible. The original
795
 *     implementation just copies or swaps within one image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
796
 *     Could this feature become a bug??? ;-)
Alexandre Julliard's avatar
Alexandre Julliard committed
797 798
 */

799 800 801
BOOL WINAPI
ImageList_Copy (HIMAGELIST himlDst, INT iDst,	HIMAGELIST himlSrc,
		INT iSrc, INT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
802
{
803
    HDC hdcSrc, hdcDst;    
Alexandre Julliard's avatar
Alexandre Julliard committed
804

805
    TRACE("iDst=%d  iSrc=%d\n", iDst, iSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
806

Eric Kohl's avatar
Eric Kohl committed
807 808 809 810 811 812
    if ((himlSrc == NULL) || (himlDst == NULL))
	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
813

814
    hdcSrc = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
815 816 817
    if (himlDst == himlSrc)
        hdcDst = hdcSrc;
    else
818
        hdcDst = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
819

Alexandre Julliard's avatar
Alexandre Julliard committed
820
    if (uFlags & ILCF_SWAP) {
Alexandre Julliard's avatar
Alexandre Julliard committed
821
        /* swap */
822
        HBITMAP hbmTempImage, hbmTempMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
823 824

        /* create temporary bitmaps */
825
        hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
826
                                       himlSrc->uBitsPixel, NULL);
827
        hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
828
				      1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
829 830 831

        /* copy (and stretch) destination to temporary bitmaps.(save) */
        /* image */
832 833 834
        SelectObject (hdcSrc, himlDst->hbmImage);
        SelectObject (hdcDst, hbmTempImage);
        StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
835 836 837
                      hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
                      SRCCOPY);
        /* mask */
838 839 840
        SelectObject (hdcSrc, himlDst->hbmMask);
        SelectObject (hdcDst, hbmTempMask);
        StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
841 842 843 844 845
                      hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
                      SRCCOPY);

        /* copy (and stretch) source to destination */
        /* image */
846 847 848
        SelectObject (hdcSrc, himlSrc->hbmImage);
        SelectObject (hdcDst, himlDst->hbmImage);
        StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
849 850 851
                      hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
                      SRCCOPY);
        /* mask */
852 853 854
        SelectObject (hdcSrc, himlSrc->hbmMask);
        SelectObject (hdcDst, himlDst->hbmMask);
        StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
855 856 857 858 859
                      hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
                      SRCCOPY);

        /* copy (without stretching) temporary bitmaps to source (restore) */
        /* image */
860 861 862
        SelectObject (hdcSrc, hbmTempImage);
        SelectObject (hdcDst, himlSrc->hbmImage);
        BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
863 864
                  hdcSrc, 0, 0, SRCCOPY);
        /* mask */
865 866 867
        SelectObject (hdcSrc, hbmTempMask);
        SelectObject (hdcDst, himlSrc->hbmMask);
        BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
868 869 870
                  hdcSrc, 0, 0, SRCCOPY);

        /* delete temporary bitmaps */
871 872
        DeleteObject (hbmTempMask);
        DeleteObject (hbmTempImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
873
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
874
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
875
        /* copy image */
876
        SelectObject (hdcSrc, himlSrc->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
877 878 879
        if (himlSrc == himlDst)
            hdcDst = hdcSrc;
        else
880 881
            SelectObject (hdcDst, himlDst->hbmImage);
        StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
882 883 884 885
                      hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
                      SRCCOPY);

        /* copy mask */
886
        SelectObject (hdcSrc, himlSrc->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
887 888 889
        if (himlSrc == himlDst)
            hdcDst = hdcSrc;
        else
890 891
            SelectObject (hdcDst, himlDst->hbmMask);
        StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
892 893 894 895
                      hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
                      SRCCOPY);
    }

896
    DeleteDC (hdcSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
897
    if (himlSrc != himlDst)
898
        DeleteDC (hdcDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
899

Eric Kohl's avatar
Eric Kohl committed
900
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
901 902 903 904
}


/*************************************************************************
905
 * ImageList_Create [COMCTL32.45]  Creates a new image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
906
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
907 908 909 910 911 912
 * 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
913
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
914
 * RETURNS
Eric Kohl's avatar
Eric Kohl committed
915 916
 *     Success: Handle to the created image list
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
917 918
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
919
HIMAGELIST WINAPI
920 921
ImageList_Create (INT cx, INT cy, UINT flags,
		  INT cInitial, INT cGrow)
Alexandre Julliard's avatar
Alexandre Julliard committed
922 923
{
    HIMAGELIST himl;
924 925 926
    HDC      hdc;
    INT      nCount;
    HBITMAP  hbmTemp;
Eric Kohl's avatar
Eric Kohl committed
927 928 929 930 931
    static WORD aBitBlend25[] = 
        {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};

    static WORD aBitBlend50[] =
        {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
Alexandre Julliard's avatar
Alexandre Julliard committed
932

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

Eric Kohl's avatar
Eric Kohl committed
935
    himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
Alexandre Julliard's avatar
Alexandre Julliard committed
936
    if (!himl)
Eric Kohl's avatar
Eric Kohl committed
937 938 939 940 941
        return NULL;

    himl->cx        = cx;
    himl->cy        = cy;
    himl->flags     = flags;
Alexandre Julliard's avatar
Alexandre Julliard committed
942
    himl->cMaxImage = cInitial + cGrow;
Eric Kohl's avatar
Eric Kohl committed
943 944
    himl->cInitial  = cInitial;
    himl->cGrow     = cGrow;
Alexandre Julliard's avatar
Alexandre Julliard committed
945
    himl->cCurImage = 0;
Eric Kohl's avatar
Eric Kohl committed
946 947
    himl->clrFg     = CLR_DEFAULT;
    himl->clrBk     = CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
948 949

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

953 954 955
    hdc = CreateCompatibleDC (0);
    himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
    DeleteDC (hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
956

957
    TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
Alexandre Julliard's avatar
Alexandre Julliard committed
958

959 960 961
    if (himl->cMaxImage > 0) {
        himl->hbmImage =
	  CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
962
                        1, himl->uBitsPixel, NULL);
963 964 965 966
	if (himl->hbmImage == 0) {
	    ERR("Error creating image bitmap!\n");
	    return NULL;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
967
    }
968 969 970 971
    else
        himl->hbmImage = 0;
    
    if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
972
        himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
973
					1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
974
        if (himl->hbmMask == 0) {
975
            ERR("Error creating mask bitmap!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
976
            if (himl->hbmImage)
977
                DeleteObject (himl->hbmImage);
Eric Kohl's avatar
Eric Kohl committed
978
            return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
979 980
        }
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
981 982 983
    else
        himl->hbmMask = 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
984
    /* create blending brushes */
985 986 987
    hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
    himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
    DeleteObject (hbmTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
988

989 990 991
    hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
    himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
    DeleteObject (hbmTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
992

993
    TRACE("created imagelist %p\n", himl);
Eric Kohl's avatar
Eric Kohl committed
994
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
995 996 997
}


Alexandre Julliard's avatar
Alexandre Julliard committed
998
/*************************************************************************
999
 * ImageList_Destroy [COMCTL32.46] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1000 1001
 *
 * Destroys an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1002
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1003
 * PARAMS
1004
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1005
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1006 1007 1008
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1009 1010
 */

1011
BOOL WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1012
ImageList_Destroy (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1013
{ 
Eric Kohl's avatar
Eric Kohl committed
1014 1015
    if (!himl)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1016

Eric Kohl's avatar
Eric Kohl committed
1017
    /* delete image bitmaps */
Alexandre Julliard's avatar
Alexandre Julliard committed
1018
    if (himl->hbmImage)
1019
        DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
    if (himl->hbmMask)
1021
        DeleteObject (himl->hbmMask);
Eric Kohl's avatar
Eric Kohl committed
1022 1023 1024

    /* delete blending brushes */
    if (himl->hbrBlend25)
1025
        DeleteObject (himl->hbrBlend25);
Eric Kohl's avatar
Eric Kohl committed
1026
    if (himl->hbrBlend50)
1027
        DeleteObject (himl->hbrBlend50);
Alexandre Julliard's avatar
Alexandre Julliard committed
1028
        
Eric Kohl's avatar
Eric Kohl committed
1029 1030 1031
    COMCTL32_Free (himl);

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1032 1033 1034
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1035
/*************************************************************************
1036
 * ImageList_DragEnter [COMCTL32.47] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1037
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
 * 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
1052 1053
 */

1054 1055
BOOL WINAPI
ImageList_DragEnter (HWND hwndLock, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1056
{
1057 1058
    TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);

1059
    if (InternalDrag.himl == NULL)
1060
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1061 1062

    if (hwndLock)
1063
	InternalDrag.hwnd = hwndLock;
Alexandre Julliard's avatar
Alexandre Julliard committed
1064
    else
1065
	InternalDrag.hwnd = GetDesktopWindow ();
Alexandre Julliard's avatar
Alexandre Julliard committed
1066

1067 1068
    InternalDrag.x = x;
    InternalDrag.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1069

1070 1071 1072 1073
    /* draw the drag image and save the background */
    if (!ImageList_DragShowNolock(TRUE)) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1074

1075
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077 1078 1079
}


/*************************************************************************
1080
 * ImageList_DragLeave [COMCTL32.48] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1081 1082 1083 1084 1085 1086 1087 1088 1089
 *
 * 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
1090 1091
 */

1092 1093
BOOL WINAPI
ImageList_DragLeave (HWND hwndLock)
Alexandre Julliard's avatar
Alexandre Julliard committed
1094
{
1095 1096 1097
    /* 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)
1098
	InternalDrag.hwnd = hwndLock;
Alexandre Julliard's avatar
Alexandre Julliard committed
1099
    else
1100 1101 1102 1103 1104
	InternalDrag.hwnd = GetDesktopWindow (); */
    if(!hwndLock)
	hwndLock = GetDesktopWindow();
    if(InternalDrag.hwnd != hwndLock)
	FIXME("DragLeave hWnd != DragEnter hWnd\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1105

Alexandre Julliard's avatar
Alexandre Julliard committed
1106 1107
    ImageList_DragShowNolock (FALSE);

1108
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1109 1110 1111 1112
}


/*************************************************************************
1113
 * ImageList_DragMove [COMCTL32.49] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
 *
 * 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.
1128 1129 1130
 *
 * BUGS
 *     The drag image should be drawn semitransparent.
Alexandre Julliard's avatar
Alexandre Julliard committed
1131 1132
 */

1133 1134
BOOL WINAPI
ImageList_DragMove (INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1135
{
1136 1137
    TRACE("(x=%d y=%d)\n", x, y);

1138 1139 1140
    if (!InternalDrag.himl) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1141

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
    /* 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;
	

	/* 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 */
	/* FIXME: image should be drawn semitransparent */
	ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
		       origNewY - origRegY, ILD_NORMAL);
	/* 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
1193
	DeleteObject(hbmOffScreen);
1194 1195
	ReleaseDC(InternalDrag.hwnd, hdcDrag);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1196

1197 1198 1199
    /* update the image position */
    InternalDrag.x = x;
    InternalDrag.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1200

1201
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1202 1203 1204 1205
}


/*************************************************************************
1206
 * ImageList_DragShowNolock [COMCTL32.50] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
 *
 * Shows or hides the drag image.
 *
 * PARAMS
 *     bShow [I] TRUE shows the drag image, FALSE hides it.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
1217 1218
 * BUGS
 *     The drag image should be drawn semitransparent.
Alexandre Julliard's avatar
Alexandre Julliard committed
1219
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1220

1221 1222
BOOL WINAPI
ImageList_DragShowNolock (BOOL bShow)
Alexandre Julliard's avatar
Alexandre Julliard committed
1223
{
1224
    HDC hdcDrag;
1225 1226
    HDC hdcBg;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1227

1228
    TRACE("bShow=0x%X!\n", bShow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1229

1230 1231 1232 1233
    /* DragImage is already visible/hidden */
    if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1234

1235 1236 1237
    /* position of the origin of the DragImage */
    x = InternalDrag.x - InternalDrag.dxHotspot;
    y = InternalDrag.y - InternalDrag.dyHotspot;
Alexandre Julliard's avatar
Alexandre Julliard committed
1238

1239 1240 1241 1242
    hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
			 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
    if (!hdcDrag) {
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1243 1244
    }

1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
    hdcBg = CreateCompatibleDC(hdcDrag);
    if (!InternalDrag.hbmBg) {
	InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
		    InternalDrag.himl->cx, InternalDrag.himl->cy);
    }
    SelectObject(hdcBg, InternalDrag.hbmBg);
    
    if (bShow) {
	/* save the background */
	BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcDrag, x, y, SRCCOPY);
	/* show the image */
	/* FIXME: this should be drawn semitransparent */
	ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
    } else { 
	/* hide the image */
	BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcBg, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1263 1264
    }

1265
    InternalDrag.bShow = !InternalDrag.bShow;
Alexandre Julliard's avatar
Alexandre Julliard committed
1266

1267 1268 1269
    DeleteDC(hdcBg);
    ReleaseDC (InternalDrag.hwnd, hdcDrag);
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1270 1271 1272 1273
}


/*************************************************************************
1274
 * ImageList_Draw [COMCTL32.51] Draws an image.
Alexandre Julliard's avatar
Alexandre Julliard committed
1275 1276
 *
 * PARAMS
1277
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1278
 *     i      [I] image index
1279
 *     hdc    [I] handle to device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
 *     x      [I] x position
 *     y      [I] y position
 *     fStyle [I] drawing flags
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Calls ImageList_DrawIndirect.
 *
 * SEE
 *     ImageList_DrawIndirect.
Alexandre Julliard's avatar
Alexandre Julliard committed
1293 1294
 */

1295 1296 1297
BOOL WINAPI
ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
		INT x, INT y, UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
{
    IMAGELISTDRAWPARAMS imldp;

    imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
    imldp.himl    = himl;
    imldp.i       = i;
    imldp.hdcDst  = hdc,
    imldp.x       = x;
    imldp.y       = y;
    imldp.cx      = 0;
    imldp.cy      = 0;
    imldp.xBitmap = 0;
    imldp.yBitmap = 0;
    imldp.rgbBk   = CLR_DEFAULT;
    imldp.rgbFg   = CLR_DEFAULT;
    imldp.fStyle  = fStyle;
    imldp.dwRop   = 0;

1316
    return ImageList_DrawIndirect (&imldp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1317 1318 1319 1320
}


/*************************************************************************
1321
 * ImageList_DrawEx [COMCTL32.52]
Alexandre Julliard's avatar
Alexandre Julliard committed
1322 1323 1324 1325
 *
 * Draws an image and allows to use extended drawing features.
 *
 * PARAMS
1326
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1327
 *     i      [I] image index
1328
 *     hdc    [I] handle to device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1329 1330
 *     x      [I] X position
 *     y      [I] Y position
Alexandre Julliard's avatar
Alexandre Julliard committed
1331 1332
 *     xOffs  [I] X offset
 *     yOffs  [I] Y offset
Alexandre Julliard's avatar
Alexandre Julliard committed
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
 *     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
1346 1347
 */

1348 1349 1350 1351
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
1352 1353 1354 1355 1356 1357 1358 1359 1360
{
    IMAGELISTDRAWPARAMS imldp;

    imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
    imldp.himl    = himl;
    imldp.i       = i;
    imldp.hdcDst  = hdc,
    imldp.x       = x;
    imldp.y       = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1361 1362
    imldp.cx      = dx;
    imldp.cy      = dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1363 1364 1365 1366 1367 1368 1369
    imldp.xBitmap = 0;
    imldp.yBitmap = 0;
    imldp.rgbBk   = rgbBk;
    imldp.rgbFg   = rgbFg;
    imldp.fStyle  = fStyle;
    imldp.dwRop   = 0;

1370
    return ImageList_DrawIndirect (&imldp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1371 1372 1373 1374
}


/*************************************************************************
1375
 * ImageList_DrawIndirect [COMCTL32.53] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1376 1377 1378 1379
 *
 * Draws an image using ...
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1380
 *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
Alexandre Julliard's avatar
Alexandre Julliard committed
1381 1382
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1383 1384
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1385 1386
 */

1387
BOOL WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1388
ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
Alexandre Julliard's avatar
Alexandre Julliard committed
1389
{
1390 1391 1392 1393
    INT      cx, cy;    
    /* 
        Do some Error Checking
    */
Eric Kohl's avatar
Eric Kohl committed
1394
    if (pimldp == NULL)
1395
        return FALSE;
Eric Kohl's avatar
Eric Kohl committed
1396
    if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1397
        return FALSE;
Eric Kohl's avatar
Eric Kohl committed
1398
    if (pimldp->himl == NULL)
1399
        return FALSE;
1400 1401
    if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
	ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1402
        return FALSE;
1403
    }
1404 1405 1406 1407 1408 1409 1410 1411 1412
    /*
        Get the Height and Width to display
    */
    cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
    cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
    /*
        Draw the image
    */
    if(pimldp->himl->hbmMask != 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1413
    {
1414
        IMAGELIST_InternalDrawMask(pimldp, cx, cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1415
    }
1416
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
1417
    {
1418
        IMAGELIST_InternalDraw(pimldp, cx, cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1419
    }
1420 1421 1422 1423 1424
    /* 
        Apply the blend if needed to the Image
    */
    if((pimldp->fStyle & ILD_BLEND50)
        || (pimldp->fStyle & ILD_BLEND25))
Alexandre Julliard's avatar
Alexandre Julliard committed
1425
    {
1426
        IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1427
    }
1428 1429 1430
    /*
        Apply the Overlay if needed
    */
1431
    if (pimldp->fStyle & ILD_OVERLAYMASK)
Alexandre Julliard's avatar
Alexandre Julliard committed
1432
    {
1433
        IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1434 1435
    }

1436
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1437 1438 1439
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1440
/*************************************************************************
1441
 * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1442
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1443 1444
 * PARAMS
 *     himlSrc [I] source image list handle
Alexandre Julliard's avatar
Alexandre Julliard committed
1445
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1446 1447
 * RETURNS
 *     Success: Handle of duplicated image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1448
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1449 1450
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1451 1452
HIMAGELIST WINAPI
ImageList_Duplicate (HIMAGELIST himlSrc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1453 1454
{
    HIMAGELIST himlDst;
1455
    HDC hdcSrc, hdcDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1456 1457

    if (himlSrc == NULL) {
1458
        ERR("Invalid image list handle!\n");
1459
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1460 1461 1462 1463 1464 1465 1466
    }

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

    if (himlDst)
    {
1467 1468 1469 1470 1471
        hdcSrc = CreateCompatibleDC (0);
        hdcDst = CreateCompatibleDC (0);
        SelectObject (hdcSrc, himlSrc->hbmImage);
        SelectObject (hdcDst, himlDst->hbmImage);
        BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
1472 1473 1474 1475
                  hdcSrc, 0, 0, SRCCOPY);

        if (himlDst->hbmMask)
        {
1476 1477 1478
            SelectObject (hdcSrc, himlSrc->hbmMask);
            SelectObject (hdcDst, himlDst->hbmMask);
            BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
Alexandre Julliard's avatar
Alexandre Julliard committed
1479 1480 1481
                      himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
        }

1482 1483
        DeleteDC (hdcDst);
        DeleteDC (hdcSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1484

1485 1486 1487
	himlDst->cCurImage = himlSrc->cCurImage;
	himlDst->cMaxImage = himlSrc->cMaxImage;
    }
1488
    return himlDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1489 1490 1491
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1492
/*************************************************************************
1493
 * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
Alexandre Julliard's avatar
Alexandre Julliard committed
1494 1495
 *
 * Finishes a drag operation.
Alexandre Julliard's avatar
Alexandre Julliard committed
1496
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1497
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1498
 *     no Parameters
Alexandre Julliard's avatar
Alexandre Julliard committed
1499
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1500 1501 1502
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1503 1504
 */

1505
BOOL WINAPI
1506
ImageList_EndDrag (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1507
{
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
    /* 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;
1519
    InternalDrag.bHSPending = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1520

1521
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1522 1523
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1524

Alexandre Julliard's avatar
Alexandre Julliard committed
1525
/*************************************************************************
1526
 * ImageList_GetBkColor [COMCTL32.56]
Alexandre Julliard's avatar
Alexandre Julliard committed
1527
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
 * Returns the background color of an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1529
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1530 1531 1532 1533
 * PARAMS
 *     himl [I] Image list handle.
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1534 1535
 *     Success: background color
 *     Failure: CLR_NONE
Alexandre Julliard's avatar
Alexandre Julliard committed
1536 1537
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1538 1539
COLORREF WINAPI
ImageList_GetBkColor (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1540
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1541 1542
    if (himl == NULL)
	return CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1543

1544
    return himl->clrBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
1545 1546 1547
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1548
/*************************************************************************
1549
 * ImageList_GetDragImage [COMCTL32.57]
Alexandre Julliard's avatar
Alexandre Julliard committed
1550 1551
 *
 * Returns the handle to the internal drag image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1552
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1553 1554 1555
 * 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
1556
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1557 1558 1559
 * RETURNS
 *     Success: Handle of the drag image list.
 *     Failure: NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1562
HIMAGELIST WINAPI
1563
ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
1564
{
1565
    if (InternalDrag.himl) {
1566
	if (ppt) {
1567 1568
	    ppt->x = InternalDrag.x;
	    ppt->y = InternalDrag.y;
1569 1570
	}
	if (pptHotspot) {
1571 1572
	    pptHotspot->x = InternalDrag.dxHotspot;
	    pptHotspot->y = InternalDrag.dyHotspot;
1573
	}
1574
        return (InternalDrag.himl);
1575
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1576

1577
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1578 1579 1580
}


1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
/*************************************************************************
 * ImageList_GetFlags [COMCTL32.58]
 *
 * BUGS
 *    Stub.
 */

DWORD WINAPI
ImageList_GetFlags(HIMAGELIST himl)
{
    FIXME("(%p):empty stub\n", himl);
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1596
/*************************************************************************
1597
 * ImageList_GetIcon [COMCTL32.59] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1598 1599 1600 1601
 *
 * Creates an icon from a masked image of an image list.
 *
 * PARAMS
1602
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1603 1604 1605 1606 1607 1608
 *     i     [I] image index
 *     flags [I] drawing style flags
 *
 * RETURNS
 *     Success: icon handle
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1609 1610
 */

1611 1612
HICON WINAPI
ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1613
{
1614 1615
    ICONINFO ii;
    HICON  hIcon;
1616
    HBITMAP hOldSrcBitmap,hOldDstBitmap;
1617
    HDC    hdcSrc, hdcDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1618

1619 1620
    if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
	FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
Eric Kohl's avatar
Eric Kohl committed
1621
	return 0;
1622
   }
Alexandre Julliard's avatar
Alexandre Julliard committed
1623

1624 1625
    hdcSrc = CreateCompatibleDC(0);
    hdcDst = CreateCompatibleDC(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1626

Alexandre Julliard's avatar
Alexandre Julliard committed
1627
    ii.fIcon = TRUE;
1628
    ii.hbmMask  = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1629 1630

    /* draw mask*/
1631
    hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1632
    if (himl->hbmMask) {
1633
	SelectObject (hdcSrc, himl->hbmMask);
1634
	BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
1635 1636 1637
		  hdcSrc, i * himl->cx, 0, SRCCOPY);
    }
    else
1638
	PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
Alexandre Julliard's avatar
Alexandre Julliard committed
1639 1640

    /* draw image*/
1641
    hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
Luc Tourangeau's avatar
Luc Tourangeau committed
1642 1643
    ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
    SelectObject (hdcDst, ii.hbmColor);
1644
    BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
1645
	      hdcSrc, i * himl->cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1646

1647 1648 1649 1650 1651 1652 1653
    /*
     * CreateIconIndirect requires us to deselect the bitmaps from
     * the DCs before calling 
     */
    SelectObject(hdcSrc, hOldSrcBitmap);
    SelectObject(hdcDst, hOldDstBitmap);

Alexandre Julliard's avatar
Alexandre Julliard committed
1654 1655
    hIcon = CreateIconIndirect (&ii);    

1656 1657 1658 1659
    DeleteDC (hdcSrc);
    DeleteDC (hdcDst);
    DeleteObject (ii.hbmMask);
    DeleteObject (ii.hbmColor);
Alexandre Julliard's avatar
Alexandre Julliard committed
1660

Eric Kohl's avatar
Eric Kohl committed
1661
    return hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
1662 1663 1664
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1665
/*************************************************************************
1666
 * ImageList_GetIconSize [COMCTL32.60]
Alexandre Julliard's avatar
Alexandre Julliard committed
1667 1668 1669 1670
 *
 * Retrieves the size of an image in an image list.
 *
 * PARAMS
1671
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1672 1673 1674 1675 1676 1677 1678 1679 1680
 *     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
1681 1682
 */

1683 1684
BOOL WINAPI
ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1685
{
Eric Kohl's avatar
Eric Kohl committed
1686 1687 1688 1689
    if (himl == NULL)
	return FALSE;
    if ((himl->cx <= 0) || (himl->cy <= 0))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1690 1691

    if (cx)
Eric Kohl's avatar
Eric Kohl committed
1692
	*cx = himl->cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1693
    if (cy)
Eric Kohl's avatar
Eric Kohl committed
1694 1695 1696
	*cy = himl->cy;

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1697 1698 1699
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1700
/*************************************************************************
1701
 * ImageList_GetImageCount [COMCTL32.61]
Alexandre Julliard's avatar
Alexandre Julliard committed
1702 1703 1704 1705
 *
 * Returns the number of images in an image list.
 *
 * PARAMS
1706
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1707 1708 1709
 *
 * RETURNS
 *     Success: Number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
1710
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
1711 1712
 */

1713
INT WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1714
ImageList_GetImageCount (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1715
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1716 1717
    if (himl == NULL)
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1718

Eric Kohl's avatar
Eric Kohl committed
1719
    return himl->cCurImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
1720 1721 1722
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1723
/*************************************************************************
1724
 * ImageList_GetImageInfo [COMCTL32.62]
Alexandre Julliard's avatar
Alexandre Julliard committed
1725 1726 1727 1728
 *
 * Returns information about an image in an image list.
 *
 * PARAMS
1729
 *     himl       [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1730
 *     i          [I] image index
1731
 *     pImageInfo [O] pointer to the image information
Alexandre Julliard's avatar
Alexandre Julliard committed
1732 1733 1734 1735
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1736 1737
 */

1738 1739
BOOL WINAPI
ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
1740
{
Eric Kohl's avatar
Eric Kohl committed
1741 1742 1743 1744
    if ((himl == NULL) || (pImageInfo == NULL))
	return FALSE;
    if ((i < 0) || (i >= himl->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1745

Alexandre Julliard's avatar
Alexandre Julliard committed
1746 1747 1748 1749 1750 1751 1752 1753
    pImageInfo->hbmImage = himl->hbmImage;
    pImageInfo->hbmMask  = himl->hbmMask;
    
    pImageInfo->rcImage.top    = 0;
    pImageInfo->rcImage.bottom = himl->cy;
    pImageInfo->rcImage.left   = i * himl->cx;
    pImageInfo->rcImage.right  = (i+1) * himl->cx;
    
Eric Kohl's avatar
Eric Kohl committed
1754
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1755 1756 1757
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1758
/*************************************************************************
1759
 * ImageList_GetImageRect [COMCTL32.63] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1760 1761 1762 1763
 *
 * Retrieves the rectangle of the specified image in an image list.
 *
 * PARAMS
1764
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1765 1766 1767 1768
 *     i      [I] image index
 *     lpRect [O] pointer to the image rectangle
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1769 1770
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1771
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1772 1773
 * NOTES
 *    This is an UNDOCUMENTED function!!!
Alexandre Julliard's avatar
Alexandre Julliard committed
1774
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1775

1776 1777
BOOL WINAPI
ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1778
{
Eric Kohl's avatar
Eric Kohl committed
1779 1780 1781 1782
    if ((himl == NULL) || (lpRect == NULL))
	return FALSE;
    if ((i < 0) || (i >= himl->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1783

Eric Kohl's avatar
Eric Kohl committed
1784 1785 1786
    lpRect->left   = i * himl->cx;
    lpRect->top    = 0;
    lpRect->right  = lpRect->left + himl->cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1787 1788
    lpRect->bottom = himl->cy;

Eric Kohl's avatar
Eric Kohl committed
1789
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1790 1791 1792
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1793
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1794
 * ImageList_LoadImage  [COMCTL32.64]
1795
 * ImageList_LoadImageA [COMCTL32.65]
Alexandre Julliard's avatar
Alexandre Julliard committed
1796 1797 1798 1799
 *
 * Creates an image list from a bitmap, icon or cursor.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1800 1801 1802 1803 1804 1805 1806
 *     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
1807 1808
 *
 * RETURNS
1809
 *     Success: handle to the loaded image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1810 1811 1812 1813
 *     Failure: NULL
 *
 * SEE
 *     LoadImage ()
Alexandre Julliard's avatar
Alexandre Julliard committed
1814 1815
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1816
HIMAGELIST WINAPI
1817 1818
ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
			COLORREF clrMask, UINT uType, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1819 1820
{
    HIMAGELIST himl = NULL;
1821 1822
    HANDLE   handle;
    INT      nImageCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
1823

1824
    handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1825
    if (!handle) {
1826
        ERR("Error loading image!\n");
1827 1828
        return NULL;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1829 1830

    if (uType == IMAGE_BITMAP) {
1831 1832
        BITMAP bmp;
        GetObjectA (handle, sizeof(BITMAP), &bmp);
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845

        /* 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
1846 1847 1848 1849
        nImageCount = bmp.bmWidth / cx;

        himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
                                 nImageCount, cGrow);
1850
        ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1851 1852
    }
    else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1853 1854
        ICONINFO ii;
        BITMAP bmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1855

1856 1857
        GetIconInfo (handle, &ii);
        GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1858 1859
        himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
                                 ILC_MASK | ILC_COLOR, 1, cGrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1860
        ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1861 1862
        DeleteObject (ii.hbmColor);
        DeleteObject (ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1863 1864
    }

1865
    DeleteObject (handle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1866
    
1867
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1868 1869 1870
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1871
/*************************************************************************
1872
 * ImageList_LoadImageW [COMCTL32.66]
Alexandre Julliard's avatar
Alexandre Julliard committed
1873 1874 1875 1876
 *
 * Creates an image list from a bitmap, icon or cursor.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1877 1878 1879 1880 1881 1882 1883
 *     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
1884 1885
 *
 * RETURNS
1886
 *     Success: handle to the loaded image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1887 1888 1889 1890
 *     Failure: NULL
 *
 * SEE
 *     LoadImage ()
Alexandre Julliard's avatar
Alexandre Julliard committed
1891 1892
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1893
HIMAGELIST WINAPI
1894 1895
ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
			COLORREF clrMask, UINT uType,	UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1896 1897
{
    HIMAGELIST himl = NULL;
1898 1899
    HANDLE   handle;
    INT      nImageCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
1900

1901
    handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1902
    if (!handle) {
1903
        ERR("Error loading image!\n");
1904
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1905
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1906 1907

    if (uType == IMAGE_BITMAP) {
1908 1909
        BITMAP bmp;
        GetObjectA (handle, sizeof(BITMAP), &bmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1910 1911 1912 1913
        nImageCount = bmp.bmWidth / cx;

        himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
                                 nImageCount, cGrow);
1914
        ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1915 1916
    }
    else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1917 1918
        ICONINFO ii;
        BITMAP bmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1919

1920 1921
        GetIconInfo (handle, &ii);
        GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1922 1923
        himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
                                 ILC_MASK | ILC_COLOR, 1, cGrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1924
        ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1925 1926
        DeleteObject (ii.hbmColor);
        DeleteObject (ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
1927 1928
    }

1929
    DeleteObject (handle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1930
    
1931
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1932 1933 1934
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1935
/*************************************************************************
1936
 * ImageList_Merge [COMCTL32.67] 
Alexandre Julliard's avatar
Alexandre Julliard committed
1937 1938 1939 1940 1941
 *
 * Creates a new image list that contains a merged image from the specified
 * images of both source image lists.
 *
 * PARAMS
1942
 *     himl1 [I] handle to first image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1943
 *     i1    [I] first image index
1944
 *     himl2 [I] handle to second image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1945 1946 1947 1948 1949
 *     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
Alexandre Julliard's avatar
Alexandre Julliard committed
1950 1951
 *     Success: handle of the merged image list.
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1952 1953
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1954
HIMAGELIST WINAPI
1955 1956
ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
		 INT dx, INT dy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1957 1958
{
    HIMAGELIST himlDst = NULL;
1959 1960 1961 1962
    HDC      hdcSrcImage, hdcDstImage;
    INT      cxDst, cyDst;
    INT      xOff1, yOff1, xOff2, yOff2;
    INT      nX1, nX2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1963

1964 1965 1966
    TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
	   i2, dx, dy);

Eric Kohl's avatar
Eric Kohl committed
1967 1968
    if ((himl1 == NULL) || (himl2 == NULL))
	return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1969 1970

    /* check indices */
Alexandre Julliard's avatar
Alexandre Julliard committed
1971
    if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1972
        ERR("Index 1 out of range! %d\n", i1);
Eric Kohl's avatar
Eric Kohl committed
1973
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1974
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1975

Alexandre Julliard's avatar
Alexandre Julliard committed
1976
    if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1977
        ERR("Index 2 out of range! %d\n", i2);
Eric Kohl's avatar
Eric Kohl committed
1978
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1979
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1980

Alexandre Julliard's avatar
Alexandre Julliard committed
1981
    if (dx > 0) {
1982
        cxDst = max (himl1->cx, dx + himl2->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1983
        xOff1 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1984
        xOff2 = dx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1985
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1986
    else if (dx < 0) {
1987
        cxDst = max (himl2->cx, himl1->cx - dx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1988
        xOff1 = -dx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1989 1990 1991
        xOff2 = 0;
    }
    else {
1992
        cxDst = max (himl1->cx, himl2->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1993 1994 1995 1996
        xOff1 = 0;
        xOff2 = 0;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1997
    if (dy > 0) {
1998
        cyDst = max (himl1->cy, dy + himl2->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
1999
        yOff1 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2000
        yOff2 = dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2001
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2002
    else if (dy < 0) {
2003
        cyDst = max (himl2->cy, himl1->cy - dy);
Alexandre Julliard's avatar
Alexandre Julliard committed
2004
        yOff1 = -dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2005 2006 2007
        yOff2 = 0;
    }
    else {
2008
        cyDst = max (himl1->cy, himl2->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
2009 2010 2011 2012 2013 2014
        yOff1 = 0;
        yOff2 = 0;
    }

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

Alexandre Julliard's avatar
Alexandre Julliard committed
2015
    if (himlDst) {
2016 2017
        hdcSrcImage = CreateCompatibleDC (0);
        hdcDstImage = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2018 2019 2020 2021
        nX1 = i1 * himl1->cx;
        nX2 = i2 * himl2->cx;
        
        /* copy image */
2022 2023 2024
        SelectObject (hdcSrcImage, himl1->hbmImage);
        SelectObject (hdcDstImage, himlDst->hbmImage);
        BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2025
                  hdcSrcImage, 0, 0, BLACKNESS);
2026
        BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2027
                  hdcSrcImage, nX1, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2028

2029 2030
        SelectObject (hdcSrcImage, himl2->hbmMask);
        BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2031 2032
                  hdcSrcImage, nX2, 0, SRCAND);

2033 2034
        SelectObject (hdcSrcImage, himl2->hbmImage);
        BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2035 2036 2037
                  hdcSrcImage, nX2, 0, SRCPAINT);

        /* copy mask */
2038 2039 2040
        SelectObject (hdcSrcImage, himl1->hbmMask);
        SelectObject (hdcDstImage, himlDst->hbmMask);
        BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2041
                  hdcSrcImage, 0, 0, WHITENESS);
2042
        BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2043 2044
                  hdcSrcImage, nX1, 0, SRCCOPY);

2045 2046
        SelectObject (hdcSrcImage, himl2->hbmMask);
        BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2047 2048
                  hdcSrcImage, nX2, 0, SRCAND);

2049 2050
        DeleteDC (hdcSrcImage);
        DeleteDC (hdcDstImage);
2051
	himlDst->cCurImage = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2052 2053
    }
   
Eric Kohl's avatar
Eric Kohl committed
2054
    return himlDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
2055 2056 2057
}


2058
/* helper for _read_bitmap currently unused */
2059
#if 0
2060 2061 2062 2063 2064 2065
static int may_use_dibsection(HDC hdc) {
    int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
    if (bitspixel>8)
	return TRUE;
    if (bitspixel<=4)
	return FALSE;
2066
    return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2067
}
2068
#endif
2069

2070 2071
/* helper for ImageList_Read, see comments below */
static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2072 2073 2074 2075 2076 2077 2078
    HDC			xdc = 0;
    BITMAPFILEHEADER	bmfh;
    BITMAPINFOHEADER	bmih;
    int			bitsperpixel,palspace,longsperline,width,height;
    LPBITMAPINFOHEADER	bmihc = NULL;
    int			result = 0;
    HBITMAP		hbitmap = 0;
2079 2080
    LPBYTE		bits = NULL,nbits = NULL;
    int			nbytesperline,bytesperline;
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101

    if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))	||
    	(bmfh.bfType != (('M'<<8)|'B'))					||
    	!SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))	||
    	(bmih.biSize != sizeof(bmih))
    )
	return 0;

    bitsperpixel = bmih.biPlanes * bmih.biBitCount;
    if (bitsperpixel<=8)
    	palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
    else
    	palspace = 0;
    width = bmih.biWidth;
    height = bmih.biHeight;
    bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
    memcpy(bmihc,&bmih,sizeof(bmih));
    longsperline	= ((width*bitsperpixel+31)&~0x1f)>>5;
    bmihc->biSizeImage	= (longsperline*height)<<2;

    /* read the palette right after the end of the bitmapinfoheader */
2102 2103 2104
    if (palspace)
	if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
	    goto ret1;
2105 2106

    xdc = GetDC(0);
2107
#if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2108
    if ((bitsperpixel>1) &&
2109
	((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2110 2111 2112 2113 2114 2115 2116
     ) {
	hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
	if (!hbitmap)
	    goto ret1;
	if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
	    goto ret1;
	result = 1;
2117 2118 2119 2120 2121 2122 2123 2124
    } else
#endif
    {
	int i,nwidth,nheight;

	nwidth	= width*(height/cy);
	nheight	= cy;

2125
	if (bitsperpixel==1)
2126
	    hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2127
	else
2128
	    hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2129 2130

	/* Might be a bit excessive memory use here */
2131 2132 2133
	bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
	nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
	if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2134
		goto ret1;
2135 2136 2137 2138 2139 2140 2141

	/* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
	/* Do not forget that windows bitmaps are bottom->top */
	bytesperline	= longsperline*4;
	nbytesperline	= (height/cy)*bytesperline;
	for (i=0;i<height;i++) {
	    memcpy(
2142 2143
		nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
		bits+bytesperline*(height-1-i),
2144 2145 2146 2147 2148 2149
		bytesperline
	    );
	}
	bmihc->biWidth	= nwidth;
	bmihc->biHeight	= nheight;
	if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2150
		goto ret1;
2151 2152
	LocalFree((HLOCAL)nbits);
	LocalFree((HLOCAL)bits);
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166
	result = 1;
    }
ret1:
    if (xdc)	ReleaseDC(0,xdc);
    if (bmihc)	LocalFree((HLOCAL)bmihc);
    if (!result) {
	if (hbitmap) {
	    DeleteObject(hbitmap);
	    hbitmap = 0;
	}
    }
    return hbitmap;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2167
/*************************************************************************
2168
 * ImageList_Read [COMCTL32.68]
Alexandre Julliard's avatar
Alexandre Julliard committed
2169 2170 2171 2172 2173 2174 2175
 *
 * Reads an image list from a stream.
 *
 * PARAMS
 *     pstm [I] pointer to a stream
 *
 * RETURNS
2176
 *     Success: handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2177
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
2178
 *
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199
 * The format is like this:
 * 	ILHEAD 			ilheadstruct;
 *
 * for the color image part:
 * 	BITMAPFILEHEADER	bmfh; 
 * 	BITMAPINFOHEADER	bmih;
 * only if it has a palette:
 *	RGBQUAD		rgbs[nr_of_paletted_colors]; 
 *
 *	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):
 *	RGBQUAD		rgbs[nr_of_paletted_colors]; 
 *
 *	BYTE			maskbits[imagesize];
 *
 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
 *         _read_bitmap needs to convert them.
Alexandre Julliard's avatar
Alexandre Julliard committed
2200
 */
2201
HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
Alexandre Julliard's avatar
Alexandre Julliard committed
2202
{
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
    ILHEAD	ilHead;
    HIMAGELIST	himl;
    HBITMAP	hbmColor=0,hbmMask=0;
    int		i;

    if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
    	return NULL;
    if (ilHead.usMagic != (('L' << 8) | 'I'))
	return NULL;
    if (ilHead.usVersion != 0x101) /* probably version? */
	return NULL;
2214

2215 2216 2217
#if 0
    FIXME("	ilHead.cCurImage = %d\n",ilHead.cCurImage);
    FIXME("	ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2218
    FIXME("	ilHead.cGrow = %d\n",ilHead.cGrow);
2219 2220 2221 2222 2223 2224 2225 2226 2227
    FIXME("	ilHead.cx = %d\n",ilHead.cx);
    FIXME("	ilHead.cy = %d\n",ilHead.cy);
    FIXME("	ilHead.flags = %x\n",ilHead.flags);
    FIXME("	ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
    FIXME("	ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
    FIXME("	ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
    FIXME("	ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
#endif

2228
    hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2229 2230
    if (!hbmColor)
	return NULL;
2231 2232
    if (ilHead.flags & ILC_MASK) {
	hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2233 2234 2235 2236 2237
	if (!hbmMask) {
	    DeleteObject(hbmColor);
	    return NULL;
	}
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2238

2239 2240 2241 2242 2243
    himl = ImageList_Create (
		    ilHead.cx,
		    ilHead.cy,
		    ilHead.flags,
		    1,		/* initial */
2244
		    ilHead.cGrow
2245 2246 2247 2248 2249
    );
    if (!himl) {
	DeleteObject(hbmColor);
	DeleteObject(hbmMask);
	return NULL;
2250
    }
2251 2252
    himl->hbmImage = hbmColor;
    himl->hbmMask = hbmMask;
2253 2254
    himl->cCurImage = ilHead.cCurImage;
    himl->cMaxImage = ilHead.cMaxImage;
2255

2256 2257 2258
    ImageList_SetBkColor(himl,ilHead.bkcolor);
    for (i=0;i<4;i++)
    	ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2259
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
2260 2261 2262
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2263
/*************************************************************************
2264
 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274
 *
 * PARAMS
 *     himl [I] image list handle
 *     i    [I] image index
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2275 2276
BOOL WINAPI
ImageList_Remove (HIMAGELIST himl, INT i)
Alexandre Julliard's avatar
Alexandre Julliard committed
2277
{
2278 2279 2280
    HBITMAP hbmNewImage, hbmNewMask;
    HDC     hdcSrc, hdcDst;
    INT     cxNew, nCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2281

2282 2283 2284 2285 2286
    if (himl == NULL) {
        ERR("Invalid image list handle!\n");
        return FALSE;
    }
    
Alexandre Julliard's avatar
Alexandre Julliard committed
2287
    if ((i < -1) || (i >= himl->cCurImage)) {
2288
        ERR("index out of range! %d\n", i);
Eric Kohl's avatar
Eric Kohl committed
2289
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2290 2291 2292
    }

    if (himl->cCurImage == 0) {
2293
        ERR("image list is already empty!\n");
Eric Kohl's avatar
Eric Kohl committed
2294
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2295 2296 2297 2298
    }

    if (i == -1) {
        /* remove all */
2299
        TRACE("remove all!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2300 2301 2302

        himl->cMaxImage = himl->cInitial + himl->cGrow;
        himl->cCurImage = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2303
        for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
Alexandre Julliard's avatar
Alexandre Julliard committed
2304 2305
             himl->nOvlIdx[nCount] = -1;

2306
        DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2307
        himl->hbmImage =
2308
            CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2309 2310 2311
                            1, himl->uBitsPixel, NULL);

        if (himl->hbmMask) {
2312
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2313
            himl->hbmMask =
2314
                CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2315
                                1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2316 2317 2318 2319
        }
    }
    else {
        /* delete one image */
2320
        TRACE("Remove single image! %d\n", i);
Alexandre Julliard's avatar
Alexandre Julliard committed
2321 2322 2323 2324

        /* create new bitmap(s) */
        cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;

2325
        TRACE(" - Number of images: %d / %d (Old/New)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2326
                 himl->cCurImage, himl->cCurImage - 1);
2327
        TRACE(" - Max. number of images: %d / %d (Old/New)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2328 2329 2330
                 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
        
        hbmNewImage =
2331
            CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2332 2333

        if (himl->hbmMask)
2334
            hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2335 2336 2337
        else
            hbmNewMask = 0;  /* Just to keep compiler happy! */

2338 2339
        hdcSrc = CreateCompatibleDC (0);
        hdcDst = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2340 2341 2342

        /* copy all images and masks prior to the "removed" image */
        if (i > 0) {
2343
            TRACE("Pre image copy: Copy %d images\n", i);
Alexandre Julliard's avatar
Alexandre Julliard committed
2344
       
2345 2346 2347
            SelectObject (hdcSrc, himl->hbmImage);
            SelectObject (hdcDst, hbmNewImage);
            BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2348 2349 2350
                      hdcSrc, 0, 0, SRCCOPY);

            if (himl->hbmMask) {
2351 2352 2353
                SelectObject (hdcSrc, himl->hbmMask);
                SelectObject (hdcDst, hbmNewMask);
                BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2354 2355 2356 2357 2358 2359
                          hdcSrc, 0, 0, SRCCOPY);
            }
        }

        /* copy all images and masks behind the removed image */
        if (i < himl->cCurImage - 1) {
2360
            TRACE("Post image copy!\n");
2361 2362 2363
            SelectObject (hdcSrc, himl->hbmImage);
            SelectObject (hdcDst, hbmNewImage);
            BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
Alexandre Julliard's avatar
Alexandre Julliard committed
2364 2365 2366
                      himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);

            if (himl->hbmMask) {
2367 2368 2369
                SelectObject (hdcSrc, himl->hbmMask);
                SelectObject (hdcDst, hbmNewMask);
                BitBlt (hdcDst, i * himl->cx, 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
2370 2371 2372 2373 2374
                          (himl->cCurImage - i - 1) * himl->cx,
                          himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
            }
        }

2375 2376
        DeleteDC (hdcSrc);
        DeleteDC (hdcDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
2377 2378

        /* delete old images and insert new ones */
2379
        DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2380 2381
        himl->hbmImage = hbmNewImage;
        if (himl->hbmMask) {
2382
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2383 2384 2385 2386 2387 2388 2389
            himl->hbmMask = hbmNewMask;
        }

        himl->cCurImage--;
        himl->cMaxImage = himl->cCurImage + himl->cGrow;
    }

Eric Kohl's avatar
Eric Kohl committed
2390
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2391 2392 2393
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2394
/*************************************************************************
2395
 * ImageList_Replace [COMCTL32.70] 
Alexandre Julliard's avatar
Alexandre Julliard committed
2396 2397 2398 2399
 *
 * Replaces an image in an image list with a new image.
 *
 * PARAMS
2400
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2401
 *     i        [I] image index
2402 2403
 *     hbmImage [I] handle to image bitmap
 *     hbmMask  [I] handle to mask bitmap. Can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
2404 2405 2406 2407 2408 2409
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2410 2411 2412
BOOL WINAPI
ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
		   HBITMAP hbmMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
2413
{
2414 2415
    HDC hdcImageList, hdcImage;
    BITMAP bmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
2416

Alexandre Julliard's avatar
Alexandre Julliard committed
2417
    if (himl == NULL) {
2418
        ERR("Invalid image list handle!\n");
Eric Kohl's avatar
Eric Kohl committed
2419
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2420 2421
    }
    
2422
    if ((i >= himl->cMaxImage) || (i < 0)) {
2423
        ERR("Invalid image index!\n");
Eric Kohl's avatar
Eric Kohl committed
2424
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2425
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2426

2427 2428 2429
    hdcImageList = CreateCompatibleDC (0);
    hdcImage = CreateCompatibleDC (0);
    GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
2430 2431

    /* Replace Image */
2432 2433
    SelectObject (hdcImageList, himl->hbmImage);
    SelectObject (hdcImage, hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2434

2435
    StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2436
                  hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2437

Alexandre Julliard's avatar
Alexandre Julliard committed
2438 2439
    if (himl->hbmMask)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2440
        /* Replace Mask */
2441 2442
        SelectObject (hdcImageList, himl->hbmMask);
        SelectObject (hdcImage, hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2443

2444
        StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2445
                      hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2446 2447 2448 2449 2450 2451 2452 2453 2454 2455


        /* Remove the background from the image
        */
        SelectObject (hdcImageList, himl->hbmImage);
        StretchBlt (hdcImageList, 
            i*himl->cx, 0, himl->cx, himl->cy,
            hdcImage, 
            0, 0, bmp.bmWidth, bmp.bmHeight, 
            0x220326); /* NOTSRCAND */
Alexandre Julliard's avatar
Alexandre Julliard committed
2456 2457
    }

2458 2459
    DeleteDC (hdcImage);
    DeleteDC (hdcImageList);
Alexandre Julliard's avatar
Alexandre Julliard committed
2460

Eric Kohl's avatar
Eric Kohl committed
2461
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2462 2463 2464
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2465
/*************************************************************************
2466
 * ImageList_ReplaceIcon [COMCTL32.75]
Alexandre Julliard's avatar
Alexandre Julliard committed
2467 2468 2469 2470
 *
 * Replaces an image in an image list using an icon.
 *
 * PARAMS
2471
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2472
 *     i     [I] image index
2473
 *     hIcon [I] handle to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
2474 2475 2476 2477 2478 2479
 *
 * RETURNS
 *     Success: index of the replaced image
 *     Failure: -1
 */

2480 2481
INT WINAPI
ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
2482
{
2483 2484
    HDC     hdcImageList, hdcImage;
    INT     nIndex;
2485
    HICON   hBestFitIcon;
2486 2487 2488
    HBITMAP hbmOldSrc, hbmOldDst;
    ICONINFO  ii;
    BITMAP  bmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
2489

2490
    TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
2491

Eric Kohl's avatar
Eric Kohl committed
2492 2493
    if (himl == NULL)
	return -1;
2494
    if ((i >= himl->cMaxImage) || (i < -1))
Eric Kohl's avatar
Eric Kohl committed
2495
	return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2496

2497 2498 2499 2500 2501 2502
    hBestFitIcon = CopyImage(
        hIcon, IMAGE_ICON, 
        himl->cx, himl->cy, 
        LR_COPYFROMRESOURCE);

    GetIconInfo (hBestFitIcon, &ii);
Alexandre Julliard's avatar
Alexandre Julliard committed
2503
    if (ii.hbmMask == 0)
2504
	ERR("no mask!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2505
    if (ii.hbmColor == 0)
2506
	ERR("no color!\n");
2507
    GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
2508 2509

    if (i == -1) {
2510
        if (himl->cCurImage + 1 > himl->cMaxImage)
2511
            IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2512

Alexandre Julliard's avatar
Alexandre Julliard committed
2513
        nIndex = himl->cCurImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2514
        himl->cCurImage++;
Alexandre Julliard's avatar
Alexandre Julliard committed
2515 2516 2517 2518
    }
    else
        nIndex = i;

2519
    hdcImageList = CreateCompatibleDC (0);
2520
    TRACE("hdcImageList=0x%x!\n", hdcImageList);
Alexandre Julliard's avatar
Alexandre Julliard committed
2521
    if (hdcImageList == 0)
2522
	ERR("invalid hdcImageList!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2523

2524
    hdcImage = CreateCompatibleDC (0);
2525
    TRACE("hdcImage=0x%x!\n", hdcImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2526
    if (hdcImage == 0)
2527
	ERR("invalid hdcImage!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2528

2529 2530 2531 2532 2533
    hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
    SetTextColor( hdcImageList, RGB(0,0,0));
    SetBkColor( hdcImageList, RGB(255,255,255));
    hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
    StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2534
                  hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2535 2536

    if (himl->hbmMask) {
2537 2538 2539
        SelectObject (hdcImageList, himl->hbmMask);
        SelectObject (hdcImage, ii.hbmMask);
        StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2540
                      hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2541 2542
    }

2543 2544
    SelectObject (hdcImage, hbmOldSrc);
    SelectObject (hdcImageList, hbmOldDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
2545

2546 2547
    if(hBestFitIcon)
	DestroyIcon(hBestFitIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
2548
    if (hdcImageList)
2549
	DeleteDC (hdcImageList);
Alexandre Julliard's avatar
Alexandre Julliard committed
2550
    if (hdcImage)
2551
	DeleteDC (hdcImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2552
    if (ii.hbmColor)
2553
	DeleteObject (ii.hbmColor);
Alexandre Julliard's avatar
Alexandre Julliard committed
2554
    if (ii.hbmMask)
2555
	DeleteObject (ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2556

Eric Kohl's avatar
Eric Kohl committed
2557
    return nIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
2558 2559 2560
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2561
/*************************************************************************
2562
 * ImageList_SetBkColor [COMCTL32.76] 
Alexandre Julliard's avatar
Alexandre Julliard committed
2563 2564 2565 2566
 *
 * Sets the background color of an image list.
 *
 * PARAMS
2567
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2568 2569 2570 2571 2572 2573 2574 2575 2576
 *     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
2577 2578 2579
{
    COLORREF clrOldBk;

Alexandre Julliard's avatar
Alexandre Julliard committed
2580
    if (himl == NULL)
Eric Kohl's avatar
Eric Kohl committed
2581
	return CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2582

Alexandre Julliard's avatar
Alexandre Julliard committed
2583 2584
    clrOldBk = himl->clrBk;
    himl->clrBk = clrBk;
Eric Kohl's avatar
Eric Kohl committed
2585
    return clrOldBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
2586 2587 2588
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2589
/*************************************************************************
2590
 * ImageList_SetDragCursorImage [COMCTL32.77]
Alexandre Julliard's avatar
Alexandre Julliard committed
2591 2592 2593 2594
 *
 * Combines the specified image with the current drag image
 *
 * PARAMS
2595
 *     himlDrag  [I] handle to drag image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2596 2597 2598 2599 2600 2601 2602 2603
 *     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
 *
2604 2605 2606 2607
 * NOTES
 *     When this function is called and the drag image is visible, a
 *     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
2608 2609
 */

2610 2611 2612
BOOL WINAPI
ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
			      INT dxHotspot, INT dyHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
2613
{
Alexandre Julliard's avatar
Alexandre Julliard committed
2614
    HIMAGELIST himlTemp;
2615
    INT dx, dy;
2616
    BOOL visible;
Alexandre Julliard's avatar
Alexandre Julliard committed
2617

2618
    if (InternalDrag.himl == NULL)
Eric Kohl's avatar
Eric Kohl committed
2619
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2620

2621
    TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2622 2623 2624
	   dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);

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

2626 2627 2628
    /* Calculate the offset between the origin of the old image and the
     * origin of the second image.
     * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2629
     * hotspot) to the origin of the second image.
2630
     * See M$DN for details */
2631 2632 2633 2634 2635 2636 2637 2638
    if(InternalDrag.bHSPending) {
	dx = 0;
	dy = 0;
	InternalDrag.bHSPending = FALSE;
    } else {
	dx = InternalDrag.dxHotspot - dxHotspot;
	dy = InternalDrag.dyHotspot - dyHotspot;
    }
2639
    himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
Alexandre Julliard's avatar
Alexandre Julliard committed
2640

2641 2642 2643 2644 2645 2646 2647 2648 2649 2650
    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
2651

2652 2653 2654 2655
    ImageList_Destroy (InternalDrag.himl);
    InternalDrag.himl = himlTemp;

    /* update the InternalDragOffset, if the origin of the
2656
     * DragImage was changed by ImageList_Merge. */
2657 2658 2659 2660
    if (dx <= 0)
	InternalDrag.dxHotspot = dxHotspot;
    if (dy <= 0)
	InternalDrag.dyHotspot = dyHotspot;
2661 2662 2663 2664

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

2667
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2668 2669 2670
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2671
/*************************************************************************
2672
 * ImageList_SetFilter [COMCTL32.78] 
Alexandre Julliard's avatar
Alexandre Julliard committed
2673 2674 2675 2676
 *
 * Sets a filter (or does something completely different)!!???
 *
 * PARAMS
2677
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2678 2679 2680 2681
 *     i        [I] ???
 *     dwFilter [I] ???
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
2682 2683
 *     Success: TRUE ???
 *     Failure: FALSE ???
Alexandre Julliard's avatar
Alexandre Julliard committed
2684 2685
 *
 * BUGS
Alexandre Julliard's avatar
Alexandre Julliard committed
2686
 *     This is an UNDOCUMENTED function!!!!
Alexandre Julliard's avatar
Alexandre Julliard committed
2687 2688 2689
 *     empty stub.
 */

2690 2691
BOOL WINAPI
ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
Alexandre Julliard's avatar
Alexandre Julliard committed
2692
{
2693
    FIXME("(%p 0x%x 0x%lx):empty stub!\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2694
	   himl, i, dwFilter);
Alexandre Julliard's avatar
Alexandre Julliard committed
2695

Alexandre Julliard's avatar
Alexandre Julliard committed
2696
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2697 2698 2699
}


2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714
/*************************************************************************
 * ImageList_SetFlags [COMCTL32.79]
 *
 * BUGS
 *    Stub.
 */

DWORD WINAPI
ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
{
    FIXME("(%p %08lx):empty stub\n", himl, flags);
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2715
/*************************************************************************
2716
 * ImageList_SetIconSize [COMCTL32.80]
Alexandre Julliard's avatar
Alexandre Julliard committed
2717 2718 2719 2720
 *
 * Sets the image size of the bitmap and deletes all images.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
2721
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2722 2723 2724 2725 2726 2727 2728 2729
 *     cx   [I] image width
 *     cy   [I] image height
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2730 2731
BOOL WINAPI
ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
2732
{
2733
    INT nCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2734

Alexandre Julliard's avatar
Alexandre Julliard committed
2735 2736
    if (!himl)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2737

2738
    /* remove all images */
Eric Kohl's avatar
Eric Kohl committed
2739 2740 2741 2742
    himl->cMaxImage = himl->cInitial + himl->cGrow;
    himl->cCurImage = 0;
    himl->cx        = cx;
    himl->cy        = cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2743 2744 2745 2746 2747

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

2748
    DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2749
    himl->hbmImage =
2750
        CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2751 2752 2753
                        1, himl->uBitsPixel, NULL);

    if (himl->hbmMask) {
2754
        DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2755
        himl->hbmMask =
2756
            CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2757
                            1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2758 2759
    }

Eric Kohl's avatar
Eric Kohl committed
2760
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2761 2762 2763
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2764
/*************************************************************************
2765
 * ImageList_SetImageCount [COMCTL32.81]
Alexandre Julliard's avatar
Alexandre Julliard committed
2766 2767 2768 2769
 *
 * Resizes an image list to the specified number of images.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
2770
 *     himl        [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2771 2772 2773 2774 2775 2776 2777
 *     iImageCount [I] number of images in the image list
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2778 2779
BOOL WINAPI
ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
Alexandre Julliard's avatar
Alexandre Julliard committed
2780
{
2781 2782 2783
    HDC     hdcImageList, hdcBitmap;
    HBITMAP hbmNewBitmap;
    INT     nNewCount, nCopyCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2784

Alexandre Julliard's avatar
Alexandre Julliard committed
2785 2786
    if (!himl)
	return FALSE;
2787
    if (himl->cCurImage >= iImageCount)
Alexandre Julliard's avatar
Alexandre Julliard committed
2788 2789 2790
	return FALSE;
    if (himl->cMaxImage > iImageCount)
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2791

Alexandre Julliard's avatar
Alexandre Julliard committed
2792
    nNewCount = iImageCount + himl->cGrow;
2793
    nCopyCount = min(himl->cCurImage, iImageCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
2794

2795 2796
    hdcImageList = CreateCompatibleDC (0);
    hdcBitmap = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2797

2798
    hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2799
                                   1, himl->uBitsPixel, NULL);
2800
    if (hbmNewBitmap != 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
2801
    {
2802 2803
        SelectObject (hdcImageList, himl->hbmImage);
        SelectObject (hdcBitmap, hbmNewBitmap);
Eric Kohl's avatar
Eric Kohl committed
2804 2805

	/* copy images */
2806
        BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2807
                  hdcImageList, 0, 0, SRCCOPY);
2808
#if 0
Eric Kohl's avatar
Eric Kohl committed
2809
	/* delete 'empty' image space */
2810 2811 2812
	SetBkColor (hdcBitmap, RGB(255, 255, 255));
	SetTextColor (hdcBitmap, RGB(0, 0, 0));
	PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
Eric Kohl's avatar
Eric Kohl committed
2813
		  (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2814
#endif
2815
	DeleteObject (himl->hbmImage);
2816
	himl->hbmImage = hbmNewBitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
2817 2818
    }
    else
2819
	ERR("Could not create new image bitmap !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2820 2821 2822

    if (himl->hbmMask)
    {
2823
        hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2824
                                       1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2825 2826
        if (hbmNewBitmap != 0)
        {
2827 2828
            SelectObject (hdcImageList, himl->hbmMask);
            SelectObject (hdcBitmap, hbmNewBitmap);
Eric Kohl's avatar
Eric Kohl committed
2829 2830

	    /* copy images */
2831
            BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2832
                      hdcImageList, 0, 0, SRCCOPY);
2833
#if 0
Eric Kohl's avatar
Eric Kohl committed
2834
	    /* delete 'empty' image space */
2835 2836 2837
	    SetBkColor (hdcBitmap, RGB(255, 255, 255));
	    SetTextColor (hdcBitmap, RGB(0, 0, 0));
            PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
Eric Kohl's avatar
Eric Kohl committed
2838
		      (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2839
#endif
2840
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2841 2842 2843
            himl->hbmMask = hbmNewBitmap;
        }
        else
2844
            ERR("Could not create new mask bitmap!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2845 2846
    }

2847 2848
    DeleteDC (hdcImageList);
    DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
2849

Alexandre Julliard's avatar
Alexandre Julliard committed
2850 2851 2852 2853
    /* Update max image count and current image count */
    himl->cMaxImage = nNewCount;
    if (himl->cCurImage > nCopyCount)
        himl->cCurImage = nCopyCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2854

Alexandre Julliard's avatar
Alexandre Julliard committed
2855
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2856 2857 2858
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2859
/*************************************************************************
2860
 * ImageList_SetOverlayImage [COMCTL32.82]
Alexandre Julliard's avatar
Alexandre Julliard committed
2861 2862 2863 2864
 *
 * Assigns an overlay mask index to an existing image in an image list.
 *
 * PARAMS
2865
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2866 2867 2868 2869 2870 2871 2872 2873
 *     iImage   [I] image index
 *     iOverlay [I] overlay mask index
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2874 2875
BOOL WINAPI
ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
Alexandre Julliard's avatar
Alexandre Julliard committed
2876
{
Alexandre Julliard's avatar
Alexandre Julliard committed
2877 2878 2879 2880
    if (!himl)
	return FALSE;
    if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
	return FALSE;
2881
    if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
Alexandre Julliard's avatar
Alexandre Julliard committed
2882
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2883
    himl->nOvlIdx[iOverlay - 1] = iImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2884
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2885 2886
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2887

2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986

/* helper for ImageList_Write - write bitmap to pstm 
 * currently everything is written as 24 bit RGB, except masks
 */
static BOOL 
_write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
{
    LPBITMAPFILEHEADER bmfh;
    LPBITMAPINFOHEADER bmih;
    LPBYTE data, lpBits, lpBitsOrg;
    BITMAP bm;
    INT bitCount, sizeImage, offBits, totalSize;
    INT nwidth, nheight, nsizeImage, icount;
    HDC xdc;
    BOOL result = FALSE;


    xdc = GetDC(0);
    GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
    
    /* XXX is this always correct? */
    icount = bm.bmWidth / cx;
    nwidth = cx << 2;
    nheight = cy * ((icount+3)>>2);

    bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
    sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
    nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;

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

    data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
    bmfh = (LPBITMAPFILEHEADER)data;
    bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
    lpBits = data + offBits;

    /* setup BITMAPFILEHEADER */
    bmfh->bfType      = (('M' << 8) | 'B');
    bmfh->bfSize      = 0;
    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;
    bmih->biSizeImage     = nsizeImage;
    bmih->biXPelsPerMeter = 0;
    bmih->biYPelsPerMeter = 0;
    bmih->biClrUsed       = 0;
    bmih->biClrImportant  = 0;

    lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
    if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg, 
		  (BITMAPINFO *)bmih, DIB_RGB_COLORS))
	goto failed;
    else {
	int i;
	int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
	int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
        	
	for(i = 0; i < nheight; i++) {
	    int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
	    int noff = (nbpl * (nheight-1-i));
	    memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
	}
    }
    
    bmih->biWidth  = nwidth;
    bmih->biHeight = nheight;

    if(bitCount == 1) {
	//Hack.
	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;
    }

    if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
	goto failed;

    result = TRUE;

    failed:
    ReleaseDC(0, xdc);
    LocalFree((HLOCAL)lpBitsOrg);

    return result;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2987
/*************************************************************************
2988
 * ImageList_Write [COMCTL32.83]
Alexandre Julliard's avatar
Alexandre Julliard committed
2989 2990 2991 2992
 *
 * Writes an image list to a stream.
 *
 * PARAMS
2993
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2994 2995 2996 2997 2998 2999 3000
 *     pstm [O] Pointer to a stream.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * BUGS
3001
 *     probably.
Alexandre Julliard's avatar
Alexandre Julliard committed
3002 3003
 */

3004 3005
BOOL WINAPI
ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
Alexandre Julliard's avatar
Alexandre Julliard committed
3006
{
3007 3008 3009
    ILHEAD ilHead;
    int i;

Alexandre Julliard's avatar
Alexandre Julliard committed
3010 3011
    if (!himl)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3012

3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037
    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];
    }

    if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
	return FALSE;

    /* write the bitmap */
    if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
	return FALSE;

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

3039
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3040
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3041