source: trunk/src/comctl32/imagelist.c

Last change on this file was 10097, checked in by sandervl, 22 years ago

Wine resync

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