1 /* Unit test suite for imagelist control.
3 * Copyright 2004 Michael Stefaniuc
4 * Copyright 2002 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/test.h"
31 #define WAIT Sleep (1000)
32 #define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
39 static BOOL (WINAPI
*pImageList_DrawIndirect
)(IMAGELISTDRAWPARAMS
*) = NULL
;
42 static HINSTANCE hinst
;
44 /* These macros build cursor/bitmap data in 4x4 pixel blocks */
45 #define B(x,y) ((x?0xf0:0)|(y?0xf:0))
46 #define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
47 #define ROW32(a,b,c,d,e,f,g,h) ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h), \
48 ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h)
49 #define ROW2(a,b,c,d,e,f,g,h,i,j,k,l) ROW1(a,b,c,d,e,f,g,h),B(i,j),B(k,l)
50 #define ROW48(a,b,c,d,e,f,g,h,i,j,k,l) ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \
51 ROW2(a,b,c,d,e,f,g,h,i,j,k,l), ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \
52 ROW2(a,b,c,d,e,f,g,h,i,j,k,l)
54 static const BYTE empty_bits
[48*48/8];
56 static const BYTE icon_bits
[32*32/8] =
58 ROW32(0,0,0,0,0,0,0,0),
59 ROW32(0,0,1,1,1,1,0,0),
60 ROW32(0,1,1,1,1,1,1,0),
61 ROW32(0,1,1,0,0,1,1,0),
62 ROW32(0,1,1,0,0,1,1,0),
63 ROW32(0,1,1,1,1,1,1,0),
64 ROW32(0,0,1,1,1,1,0,0),
65 ROW32(0,0,0,0,0,0,0,0)
68 static const BYTE bitmap_bits
[48*48/8] =
70 ROW48(0,0,0,0,0,0,0,0,0,0,0,0),
71 ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
72 ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
73 ROW48(0,1,0,0,0,0,0,0,1,0,1,0),
74 ROW48(0,1,0,0,0,0,0,1,0,0,1,0),
75 ROW48(0,1,0,0,0,0,1,0,0,0,1,0),
76 ROW48(0,1,0,0,0,1,0,0,0,0,1,0),
77 ROW48(0,1,0,0,1,0,0,0,0,0,1,0),
78 ROW48(0,1,0,1,0,0,0,0,0,0,1,0),
79 ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
80 ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
81 ROW48(0,0,0,0,0,0,0,0,0,0,0,0)
84 static HIMAGELIST
createImageList(int cx
, int cy
)
86 /* Create an ImageList and put an image into it */
87 HIMAGELIST himl
= ImageList_Create(cx
, cy
, ILC_COLOR
, 1, 1);
88 HBITMAP hbm
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
89 ImageList_Add(himl
, hbm
, NULL
);
93 static HWND
create_a_window(void)
95 char className
[] = "bmwnd";
96 char winName
[] = "Test Bitmap";
98 static int registered
= 0;
104 cls
.style
= CS_HREDRAW
| CS_VREDRAW
| CS_GLOBALCLASS
;
105 cls
.lpfnWndProc
= DefWindowProcA
;
109 cls
.hIcon
= LoadIconA (0, (LPSTR
)IDI_APPLICATION
);
110 cls
.hCursor
= LoadCursorA (0, (LPSTR
)IDC_ARROW
);
111 cls
.hbrBackground
= (HBRUSH
) GetStockObject (WHITE_BRUSH
);
112 cls
.lpszMenuName
= 0;
113 cls
.lpszClassName
= className
;
115 RegisterClassA (&cls
);
120 hWnd
= CreateWindowA (className
, winName
,
121 WS_OVERLAPPEDWINDOW
,
122 CW_USEDEFAULT
, CW_USEDEFAULT
, 300, 300, 0,
126 ShowWindow (hWnd
, SW_SHOW
);
134 static HDC
show_image(HWND hwnd
, HIMAGELIST himl
, int idx
, int size
,
135 LPCSTR loc
, BOOL clear
)
139 if (!himl
) return NULL
;
141 SetWindowText(hwnd
, loc
);
143 ImageList_Draw(himl
, idx
, hdc
, 0, 0, ILD_TRANSPARENT
);
150 BitBlt(hdc
, 0, 0, size
, size
, hdc
, size
+1, size
+1, SRCCOPY
);
151 ReleaseDC(hwnd
, hdc
);
158 /* Useful for checking differences */
160 static void dump_bits(const BYTE
*p
, const BYTE
*q
, int size
)
166 for (i
= 0; i
< size
* 2; i
++)
169 for (j
= 0; j
< size
; j
++)
170 printf("%c%c", p
[j
] & 0xf0 ? 'X' : ' ', p
[j
] & 0xf ? 'X' : ' ');
172 for (j
= 0; j
< size
; j
++)
173 printf("%c%c", q
[j
] & 0xf0 ? 'X' : ' ', q
[j
] & 0xf ? 'X' : ' ');
182 static void check_bits(HWND hwnd
, HIMAGELIST himl
, int idx
, int size
,
183 const BYTE
*checkbits
, LPCSTR loc
)
186 BYTE bits
[100*100/8];
193 memset(bits
, 0, sizeof(bits
));
194 hdc
= show_image(hwnd
, himl
, idx
, size
, loc
, FALSE
);
196 c
= GetPixel(hdc
, 0, 0);
198 for (y
= 0; y
< size
; y
++)
200 for (x
= 0; x
< size
; x
++)
203 if (GetPixel(hdc
, x
, y
) != c
) bits
[i
] |= (0x80 >> (x
& 0x7));
207 BitBlt(hdc
, 0, 0, size
, size
, hdc
, size
+1, size
+1, SRCCOPY
);
208 ReleaseDC(hwnd
, hdc
);
210 ok (memcmp(bits
, checkbits
, (size
* size
)/8) == 0,
211 "%s: bits different\n", loc
);
212 if (memcmp(bits
, checkbits
, (size
* size
)/8))
213 dump_bits(bits
, checkbits
, size
);
217 static void testHotspot (void)
228 #define HOTSPOTS_MAX 4 /* Number of entries in hotspots */
229 static const struct hotspot hotspots
[HOTSPOTS_MAX
] = {
236 HIMAGELIST himl1
= createImageList(SIZEX1
, SIZEY1
);
237 HIMAGELIST himl2
= createImageList(SIZEX2
, SIZEY2
);
238 HWND hwnd
= create_a_window();
241 for (i
= 0; i
< HOTSPOTS_MAX
; i
++) {
242 for (j
= 0; j
< HOTSPOTS_MAX
; j
++) {
243 int dx1
= hotspots
[i
].dx
;
244 int dy1
= hotspots
[i
].dy
;
245 int dx2
= hotspots
[j
].dx
;
246 int dy2
= hotspots
[j
].dy
;
247 int correctx
, correcty
, newx
, newy
;
252 ret
= ImageList_BeginDrag(himl1
, 0, dx1
, dy1
);
253 ok(ret
!= 0, "BeginDrag failed for { %d, %d }\n", dx1
, dy1
);
254 sprintf(loc
, "BeginDrag (%d,%d)\n", i
, j
);
255 show_image(hwnd
, himl1
, 0, max(SIZEX1
, SIZEY1
), loc
, TRUE
);
257 /* check merging the dragged image with a second image */
258 ret
= ImageList_SetDragCursorImage(himl2
, 0, dx2
, dy2
);
259 ok(ret
!= 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
261 sprintf(loc
, "SetDragCursorImage (%d,%d)\n", i
, j
);
262 show_image(hwnd
, himl2
, 0, max(SIZEX2
, SIZEY2
), loc
, TRUE
);
264 /* check new hotspot, it should be the same like the old one */
265 himlNew
= ImageList_GetDragImage(NULL
, &ppt
);
266 ok(ppt
.x
== dx1
&& ppt
.y
== dy1
,
267 "Expected drag hotspot [%d,%d] got [%d,%d]\n",
268 dx1
, dy1
, ppt
.x
, ppt
.y
);
269 /* check size of new dragged image */
270 ImageList_GetIconSize(himlNew
, &newx
, &newy
);
271 correctx
= max(SIZEX1
, max(SIZEX2
+ dx2
, SIZEX1
- dx2
));
272 correcty
= max(SIZEY1
, max(SIZEY2
+ dy2
, SIZEY1
- dy2
));
273 ok(newx
== correctx
&& newy
== correcty
,
274 "Expected drag image size [%d,%d] got [%d,%d]\n",
275 correctx
, correcty
, newx
, newy
);
276 sprintf(loc
, "GetDragImage (%d,%d)\n", i
, j
);
277 show_image(hwnd
, himlNew
, 0, max(correctx
, correcty
), loc
, TRUE
);
286 ImageList_Destroy(himl2
);
287 ImageList_Destroy(himl1
);
291 static BOOL
DoTest1(void)
299 /* create an imagelist to play with */
300 himl
= ImageList_Create(84,84,0x10,0,3);
301 ok(himl
!=0,"failed to create imagelist\n");
303 /* load the icons to add to the image list */
304 hicon1
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
305 ok(hicon1
!= 0, "no hicon1\n");
306 hicon2
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
307 ok(hicon2
!= 0, "no hicon2\n");
308 hicon3
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
309 ok(hicon3
!= 0, "no hicon3\n");
311 /* remove when nothing exists */
312 ok(!ImageList_Remove(himl
,0),"removed nonexistent icon\n");
313 /* removing everything from an empty imagelist should succeed */
314 ok(ImageList_RemoveAll(himl
),"removed nonexistent icon\n");
317 ok(0==ImageList_AddIcon(himl
, hicon1
),"failed to add icon1\n");
318 ok(1==ImageList_AddIcon(himl
, hicon2
),"failed to add icon2\n");
319 ok(2==ImageList_AddIcon(himl
, hicon3
),"failed to add icon3\n");
321 /* remove an index out of range */
322 ok(!ImageList_Remove(himl
,4711),"removed nonexistent icon\n");
325 ok(ImageList_Remove(himl
,0),"can't remove 0\n");
326 ok(ImageList_Remove(himl
,0),"can't remove 0\n");
327 ok(ImageList_Remove(himl
,0),"can't remove 0\n");
329 /* remove one extra */
330 ok(!ImageList_Remove(himl
,0),"removed nonexistent icon\n");
332 /* check SetImageCount/GetImageCount */
333 ok(ImageList_SetImageCount(himl
, 3), "couldn't increase image count\n");
334 ok(ImageList_GetImageCount(himl
) == 3, "invalid image count after increase\n");
335 ok(ImageList_SetImageCount(himl
, 1), "couldn't decrease image count\n");
336 ok(ImageList_GetImageCount(himl
) == 1, "invalid image count after decrease to 1\n");
337 ok(ImageList_SetImageCount(himl
, 0), "couldn't decrease image count\n");
338 ok(ImageList_GetImageCount(himl
) == 0, "invalid image count after decrease to 0\n");
341 ok(ImageList_Destroy(himl
),"destroy imagelist failed\n");
343 /* icons should be deleted by the imagelist */
344 ok(!DeleteObject(hicon1
),"icon 1 wasn't deleted\n");
345 ok(!DeleteObject(hicon2
),"icon 2 wasn't deleted\n");
346 ok(!DeleteObject(hicon3
),"icon 3 wasn't deleted\n");
351 static BOOL
DoTest2(void)
359 /* create an imagelist to play with */
360 himl
= ImageList_Create(84,84,0x10,0,3);
361 ok(himl
!=0,"failed to create imagelist\n");
363 /* load the icons to add to the image list */
364 hicon1
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
365 ok(hicon1
!= 0, "no hicon1\n");
366 hicon2
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
367 ok(hicon2
!= 0, "no hicon2\n");
368 hicon3
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
369 ok(hicon3
!= 0, "no hicon3\n");
372 ok(0==ImageList_AddIcon(himl
, hicon1
),"failed to add icon1\n");
373 ok(1==ImageList_AddIcon(himl
, hicon2
),"failed to add icon2\n");
374 ok(2==ImageList_AddIcon(himl
, hicon3
),"failed to add icon3\n");
377 ok(ImageList_Destroy(himl
),"destroy imagelist failed\n");
379 /* icons should be deleted by the imagelist */
380 ok(!DeleteObject(hicon1
),"icon 1 wasn't deleted\n");
381 ok(!DeleteObject(hicon2
),"icon 2 wasn't deleted\n");
382 ok(!DeleteObject(hicon3
),"icon 3 wasn't deleted\n");
387 static BOOL
DoTest3(void)
395 IMAGELISTDRAWPARAMS imldp
;
399 if (!pImageList_DrawIndirect
)
401 HMODULE hComCtl32
= LoadLibraryA("comctl32.dll");
402 pImageList_DrawIndirect
= (void*)GetProcAddress(hComCtl32
, "ImageList_DrawIndirect");
403 if (!pImageList_DrawIndirect
)
405 trace("ImageList_DrawIndirect not available, skipping test\n");
410 hwndfortest
= create_a_window();
411 hdc
= GetDC(hwndfortest
);
412 ok(hdc
!=NULL
, "couldn't get DC\n");
414 /* create an imagelist to play with */
415 himl
= ImageList_Create(48,48,0x10,0,3);
416 ok(himl
!=0,"failed to create imagelist\n");
418 /* load the icons to add to the image list */
419 hbm1
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
420 ok(hbm1
!= 0, "no bitmap 1\n");
421 hbm2
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
422 ok(hbm2
!= 0, "no bitmap 2\n");
423 hbm3
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
424 ok(hbm3
!= 0, "no bitmap 3\n");
427 ok(0==ImageList_Add(himl
, hbm1
, 0),"failed to add bitmap 1\n");
428 ok(1==ImageList_Add(himl
, hbm2
, 0),"failed to add bitmap 2\n");
430 ok(ImageList_SetImageCount(himl
,3),"Setimage count failed\n");
431 /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
432 ok(ImageList_Replace(himl
, 2, hbm3
, 0),"failed to replace bitmap 3\n");
434 memset(&imldp
, 0, sizeof (imldp
));
435 ok(!pImageList_DrawIndirect(&imldp
), "zero data succeeded!\n");
436 imldp
.cbSize
= sizeof (imldp
);
437 ok(!pImageList_DrawIndirect(&imldp
), "zero hdc succeeded!\n");
439 ok(!pImageList_DrawIndirect(&imldp
),"zero himl succeeded!\n");
441 if (!pImageList_DrawIndirect(&imldp
))
443 /* Earlier versions of native comctl32 use a smaller structure */
444 imldp
.cbSize
-= 3 * sizeof(DWORD
);
445 ok(pImageList_DrawIndirect(&imldp
),"DrawIndirect should succeed\n");
450 imldp
.fStyle
= SRCCOPY
;
451 imldp
.rgbBk
= CLR_DEFAULT
;
452 imldp
.rgbFg
= CLR_DEFAULT
;
455 ok(pImageList_DrawIndirect(&imldp
),"should succeed\n");
457 ok(pImageList_DrawIndirect(&imldp
),"should succeed\n");
459 ok(pImageList_DrawIndirect(&imldp
),"should succeed\n");
461 ok(!pImageList_DrawIndirect(&imldp
),"should fail\n");
464 ok(ImageList_Remove(himl
, 0), "removing 1st bitmap\n");
465 ok(ImageList_Remove(himl
, 0), "removing 2nd bitmap\n");
466 ok(ImageList_Remove(himl
, 0), "removing 3rd bitmap\n");
469 ok(ImageList_Destroy(himl
),"destroy imagelist failed\n");
471 /* bitmaps should not be deleted by the imagelist */
472 ok(DeleteObject(hbm1
),"bitmap 1 can't be deleted\n");
473 ok(DeleteObject(hbm2
),"bitmap 2 can't be deleted\n");
474 ok(DeleteObject(hbm3
),"bitmap 3 can't be deleted\n");
476 ReleaseDC(hwndfortest
, hdc
);
477 DestroyWindow(hwndfortest
);
482 static void testMerge(void)
484 HIMAGELIST himl1
, himl2
, hmerge
;
486 HWND hwnd
= create_a_window();
488 himl1
= ImageList_Create(32,32,0,0,3);
489 ok(himl1
!= NULL
,"failed to create himl1\n");
491 himl2
= ImageList_Create(32,32,0,0,3);
492 ok(himl2
!= NULL
,"failed to create himl2\n");
494 hicon1
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
495 ok(hicon1
!= NULL
, "failed to create hicon1\n");
497 if (!himl1
|| !himl2
|| !hicon1
)
500 ok(0==ImageList_AddIcon(himl2
, hicon1
),"add icon1 to himl2 failed\n");
501 check_bits(hwnd
, himl2
, 0, 32, icon_bits
, "add icon1 to himl2");
503 /* If himl1 has no images, merge still succeeds */
504 hmerge
= ImageList_Merge(himl1
, -1, himl2
, 0, 0, 0);
505 ok(hmerge
!= NULL
, "merge himl1,-1 failed\n");
506 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1,-1");
507 if (hmerge
) ImageList_Destroy(hmerge
);
509 hmerge
= ImageList_Merge(himl1
, 0, himl2
, 0, 0, 0);
510 ok(hmerge
!= NULL
,"merge himl1,0 failed\n");
511 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1,0");
512 if (hmerge
) ImageList_Destroy(hmerge
);
514 /* Same happens if himl2 is empty */
515 ImageList_Destroy(himl2
);
516 himl2
= ImageList_Create(32,32,0,0,3);
517 ok(himl2
!= NULL
,"failed to recreate himl2\n");
521 hmerge
= ImageList_Merge(himl1
, -1, himl2
, -1, 0, 0);
522 ok(hmerge
!= NULL
, "merge himl2,-1 failed\n");
523 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl2,-1");
524 if (hmerge
) ImageList_Destroy(hmerge
);
526 hmerge
= ImageList_Merge(himl1
, -1, himl2
, 0, 0, 0);
527 ok(hmerge
!= NULL
, "merge himl2,0 failed\n");
528 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl2,0");
529 if (hmerge
) ImageList_Destroy(hmerge
);
531 /* Now try merging an image with itself */
532 ok(0==ImageList_AddIcon(himl2
, hicon1
),"re-add icon1 to himl2 failed\n");
534 hmerge
= ImageList_Merge(himl2
, 0, himl2
, 0, 0, 0);
535 ok(hmerge
!= NULL
, "merge himl2 with itself failed\n");
536 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl2 with itself");
537 if (hmerge
) ImageList_Destroy(hmerge
);
539 /* Try merging 2 different image lists */
540 ok(0==ImageList_AddIcon(himl1
, hicon1
),"add icon1 to himl1 failed\n");
542 hmerge
= ImageList_Merge(himl1
, 0, himl2
, 0, 0, 0);
543 ok(hmerge
!= NULL
, "merge himl1 with himl2 failed\n");
544 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1 with himl2");
545 if (hmerge
) ImageList_Destroy(hmerge
);
547 hmerge
= ImageList_Merge(himl1
, 0, himl2
, 0, 8, 16);
548 ok(hmerge
!= NULL
, "merge himl1 with himl2 8,16 failed\n");
549 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1 with himl2, 8,16");
550 if (hmerge
) ImageList_Destroy(hmerge
);
552 ImageList_Destroy(himl1
);
553 ImageList_Destroy(himl2
);
554 DeleteObject(hicon1
);
558 START_TEST(imagelist
)
560 desktopDC
=GetDC(NULL
);
561 hinst
= GetModuleHandleA(NULL
);
563 InitCommonControls();