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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 [%ld,%ld]\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
);
289 static BOOL
DoTest1(void)
297 /* create an imagelist to play with */
298 himl
= ImageList_Create(84,84,0x10,0,3);
299 ok(himl
!=0,"failed to create imagelist\n");
301 /* load the icons to add to the image list */
302 hicon1
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
303 ok(hicon1
!= 0, "no hicon1\n");
304 hicon2
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
305 ok(hicon2
!= 0, "no hicon2\n");
306 hicon3
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
307 ok(hicon3
!= 0, "no hicon3\n");
309 /* remove when nothing exists */
310 ok(!ImageList_Remove(himl
,0),"removed nonexistent icon\n");
311 /* removing everything from an empty imagelist should succeed */
312 ok(ImageList_RemoveAll(himl
),"removed nonexistent icon\n");
315 ok(0==ImageList_AddIcon(himl
, hicon1
),"failed to add icon1\n");
316 ok(1==ImageList_AddIcon(himl
, hicon2
),"failed to add icon2\n");
317 ok(2==ImageList_AddIcon(himl
, hicon3
),"failed to add icon3\n");
319 /* remove an index out of range */
320 ok(!ImageList_Remove(himl
,4711),"removed nonexistent icon\n");
323 ok(ImageList_Remove(himl
,0),"can't remove 0\n");
324 ok(ImageList_Remove(himl
,0),"can't remove 0\n");
325 ok(ImageList_Remove(himl
,0),"can't remove 0\n");
327 /* remove one extra */
328 ok(!ImageList_Remove(himl
,0),"removed nonexistent icon\n");
331 ok(ImageList_Destroy(himl
),"destroy imagelist failed\n");
333 /* icons should be deleted by the imagelist */
334 ok(!DeleteObject(hicon1
),"icon 1 wasn't deleted\n");
335 ok(!DeleteObject(hicon2
),"icon 2 wasn't deleted\n");
336 ok(!DeleteObject(hicon3
),"icon 3 wasn't deleted\n");
341 static BOOL
DoTest2(void)
349 /* create an imagelist to play with */
350 himl
= ImageList_Create(84,84,0x10,0,3);
351 ok(himl
!=0,"failed to create imagelist\n");
353 /* load the icons to add to the image list */
354 hicon1
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
355 ok(hicon1
!= 0, "no hicon1\n");
356 hicon2
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
357 ok(hicon2
!= 0, "no hicon2\n");
358 hicon3
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
359 ok(hicon3
!= 0, "no hicon3\n");
362 ok(0==ImageList_AddIcon(himl
, hicon1
),"failed to add icon1\n");
363 ok(1==ImageList_AddIcon(himl
, hicon2
),"failed to add icon2\n");
364 ok(2==ImageList_AddIcon(himl
, hicon3
),"failed to add icon3\n");
367 ok(ImageList_Destroy(himl
),"destroy imagelist failed\n");
369 /* icons should be deleted by the imagelist */
370 ok(!DeleteObject(hicon1
),"icon 1 wasn't deleted\n");
371 ok(!DeleteObject(hicon2
),"icon 2 wasn't deleted\n");
372 ok(!DeleteObject(hicon3
),"icon 3 wasn't deleted\n");
377 static BOOL
DoTest3(void)
385 IMAGELISTDRAWPARAMS imldp
;
389 if (!pImageList_DrawIndirect
)
391 HMODULE hComCtl32
= LoadLibraryA("comctl32.dll");
392 pImageList_DrawIndirect
= (void*)GetProcAddress(hComCtl32
, "ImageList_DrawIndirect");
393 if (!pImageList_DrawIndirect
)
395 trace("ImageList_DrawIndirect not available, skipping test\n");
400 hwndfortest
= create_a_window();
401 hdc
= GetDC(hwndfortest
);
402 ok(hdc
!=NULL
, "couldn't get DC\n");
404 /* create an imagelist to play with */
405 himl
= ImageList_Create(48,48,0x10,0,3);
406 ok(himl
!=0,"failed to create imagelist\n");
408 /* load the icons to add to the image list */
409 hbm1
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
410 ok(hbm1
!= 0, "no bitmap 1\n");
411 hbm2
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
412 ok(hbm2
!= 0, "no bitmap 2\n");
413 hbm3
= CreateBitmap(48, 48, 1, 1, bitmap_bits
);
414 ok(hbm3
!= 0, "no bitmap 3\n");
417 ok(0==ImageList_Add(himl
, hbm1
, 0),"failed to add bitmap 1\n");
418 ok(1==ImageList_Add(himl
, hbm2
, 0),"failed to add bitmap 2\n");
420 ok(ImageList_SetImageCount(himl
,3),"Setimage count failed\n");
421 /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
422 ok(ImageList_Replace(himl
, 2, hbm3
, 0),"failed to replace bitmap 3\n");
424 memset(&imldp
, 0, sizeof (imldp
));
425 ok(!pImageList_DrawIndirect(&imldp
), "zero data succeeded!\n");
426 imldp
.cbSize
= sizeof (imldp
);
427 ok(!pImageList_DrawIndirect(&imldp
), "zero hdc succeeded!\n");
429 ok(!pImageList_DrawIndirect(&imldp
),"zero himl succeeded!\n");
431 if (!pImageList_DrawIndirect(&imldp
))
433 /* Earlier versions of native comctl32 use a smaller structure */
434 imldp
.cbSize
-= 3 * sizeof(DWORD
);
435 ok(pImageList_DrawIndirect(&imldp
),"DrawIndirect should succeed\n");
440 imldp
.fStyle
= SRCCOPY
;
441 imldp
.rgbBk
= CLR_DEFAULT
;
442 imldp
.rgbFg
= CLR_DEFAULT
;
445 ok(pImageList_DrawIndirect(&imldp
),"should succeed\n");
447 ok(pImageList_DrawIndirect(&imldp
),"should succeed\n");
449 ok(pImageList_DrawIndirect(&imldp
),"should succeed\n");
451 ok(!pImageList_DrawIndirect(&imldp
),"should fail\n");
454 ok(ImageList_Remove(himl
, 0), "removing 1st bitmap\n");
455 ok(ImageList_Remove(himl
, 0), "removing 2nd bitmap\n");
456 ok(ImageList_Remove(himl
, 0), "removing 3rd bitmap\n");
459 ok(ImageList_Destroy(himl
),"destroy imagelist failed\n");
461 /* bitmaps should not be deleted by the imagelist */
462 ok(DeleteObject(hbm1
),"bitmap 1 can't be deleted\n");
463 ok(DeleteObject(hbm2
),"bitmap 2 can't be deleted\n");
464 ok(DeleteObject(hbm3
),"bitmap 3 can't be deleted\n");
466 ReleaseDC(hwndfortest
, hdc
);
467 DestroyWindow(hwndfortest
);
472 static void testMerge(void)
474 HIMAGELIST himl1
, himl2
, hmerge
;
476 HWND hwnd
= create_a_window();
478 himl1
= ImageList_Create(32,32,0,0,3);
479 ok(himl1
!= NULL
,"failed to create himl1\n");
481 himl2
= ImageList_Create(32,32,0,0,3);
482 ok(himl2
!= NULL
,"failed to create himl2\n");
484 hicon1
= CreateIcon(hinst
, 32, 32, 1, 1, icon_bits
, icon_bits
);
485 ok(hicon1
!= NULL
, "failed to create hicon1\n");
487 if (!himl1
|| !himl2
|| !hicon1
)
490 ok(0==ImageList_AddIcon(himl2
, hicon1
),"add icon1 to himl2 failed\n");
491 check_bits(hwnd
, himl2
, 0, 32, icon_bits
, "add icon1 to himl2");
493 /* If himl1 has no images, merge still succeeds */
494 hmerge
= ImageList_Merge(himl1
, -1, himl2
, 0, 0, 0);
495 ok(hmerge
!= NULL
, "merge himl1,-1 failed\n");
496 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1,-1");
497 if (hmerge
) ImageList_Destroy(hmerge
);
499 hmerge
= ImageList_Merge(himl1
, 0, himl2
, 0, 0, 0);
500 ok(hmerge
!= NULL
,"merge himl1,0 failed\n");
501 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1,0");
502 if (hmerge
) ImageList_Destroy(hmerge
);
504 /* Same happens if himl2 is empty */
505 ImageList_Destroy(himl2
);
506 himl2
= ImageList_Create(32,32,0,0,3);
507 ok(himl2
!= NULL
,"failed to recreate himl2\n");
511 hmerge
= ImageList_Merge(himl1
, -1, himl2
, -1, 0, 0);
512 ok(hmerge
!= NULL
, "merge himl2,-1 failed\n");
513 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl2,-1");
514 if (hmerge
) ImageList_Destroy(hmerge
);
516 hmerge
= ImageList_Merge(himl1
, -1, himl2
, 0, 0, 0);
517 ok(hmerge
!= NULL
, "merge himl2,0 failed\n");
518 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl2,0");
519 if (hmerge
) ImageList_Destroy(hmerge
);
521 /* Now try merging an image with itself */
522 ok(0==ImageList_AddIcon(himl2
, hicon1
),"re-add icon1 to himl2 failed\n");
524 hmerge
= ImageList_Merge(himl2
, 0, himl2
, 0, 0, 0);
525 ok(hmerge
!= NULL
, "merge himl2 with itself failed\n");
526 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl2 with itself");
527 if (hmerge
) ImageList_Destroy(hmerge
);
529 /* Try merging 2 different image lists */
530 ok(0==ImageList_AddIcon(himl1
, hicon1
),"add icon1 to himl1 failed\n");
532 hmerge
= ImageList_Merge(himl1
, 0, himl2
, 0, 0, 0);
533 ok(hmerge
!= NULL
, "merge himl1 with himl2 failed\n");
534 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1 with himl2");
535 if (hmerge
) ImageList_Destroy(hmerge
);
537 hmerge
= ImageList_Merge(himl1
, 0, himl2
, 0, 8, 16);
538 ok(hmerge
!= NULL
, "merge himl1 with himl2 8,16 failed\n");
539 check_bits(hwnd
, hmerge
, 0, 32, empty_bits
, "merge himl1 with himl2, 8,16");
540 if (hmerge
) ImageList_Destroy(hmerge
);
542 ImageList_Destroy(himl1
);
543 ImageList_Destroy(himl2
);
544 DeleteObject(hicon1
);
548 START_TEST(imagelist
)
550 desktopDC
=GetDC(NULL
);
551 hinst
= GetModuleHandleA(NULL
);
553 InitCommonControls();