comctl32: Replace malloc() with HeapAlloc().
[wine] / dlls / comctl32 / tests / toolbar.c
1 /* Unit tests for treeview.
2  *
3  * Copyright 2005 Krzysztof Foltman
4  * Copyright 2007 Mikolaj Zalewski
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <assert.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "commctrl.h" 
31
32 #include "resources.h"
33
34 #include "wine/test.h"
35
36 static HWND hMainWnd;
37 static BOOL g_fBlockHotItemChange;
38 static BOOL g_fReceivedHotItemChange;
39 static BOOL g_fExpectedHotItemOld;
40 static BOOL g_fExpectedHotItemNew;
41
42 #define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
43     val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \
44     val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom);
45  
46 #define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
47
48 static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
49   p->iBitmap = -2;
50   p->idCommand = idCommand;
51   p->fsState = TBSTATE_ENABLED;
52   p->fsStyle = fsStyle;
53   p->iString = nString;
54 }
55
56 static LRESULT MyWnd_Notify(LPARAM lParam)
57 {
58     NMHDR *hdr = (NMHDR *)lParam;
59     NMTBHOTITEM *nmhi;
60     switch (hdr->code)
61     {
62         case TBN_HOTITEMCHANGE:
63             nmhi = (NMTBHOTITEM *)lParam;
64             g_fReceivedHotItemChange = TRUE;
65             if (g_fExpectedHotItemOld != g_fExpectedHotItemNew)
66             {
67                 compare(nmhi->idOld, g_fExpectedHotItemOld, "%d");
68                 compare(nmhi->idNew, g_fExpectedHotItemNew, "%d");
69             }
70             if (g_fBlockHotItemChange)
71                 return 1;
72             break;
73     }
74     return 0;
75 }
76
77 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
78 {
79     switch (msg)
80     {
81         case WM_NOTIFY:
82             return MyWnd_Notify(lParam);
83     }
84     return DefWindowProcA(hWnd, msg, wParam, lParam);
85 }
86
87 static void basic_test(void)
88 {
89     TBBUTTON buttons[9];
90     HWND hToolbar;
91     int i;
92     for (i=0; i<9; i++)
93         MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
94     MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
95     MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
96
97     hToolbar = CreateToolbarEx(hMainWnd,
98         WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
99         WS_CHILD | TBSTYLE_LIST,
100         100,
101         0, NULL, (UINT)0,
102         buttons, sizeof(buttons)/sizeof(buttons[0]),
103         0, 0, 20, 16, sizeof(TBBUTTON));
104     ok(hToolbar != NULL, "Toolbar creation\n");
105     SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
106
107     /* test for exclusion working inside a separator-separated :-) group */
108     SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
109     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
110     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
111
112     SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
113     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
114     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
115
116     SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
117     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
118     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
119
120     /* test for inter-group crosstalk, ie. two radio groups interfering with each other */
121     SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
122     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
123     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
124     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
125
126     SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
127     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
128     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
129     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
130
131     SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
132     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
133     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
134     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
135     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
136     DestroyWindow(hToolbar);
137 }
138
139 static void rebuild_toolbar(HWND *hToolbar)
140 {
141     if (*hToolbar != NULL)
142         DestroyWindow(*hToolbar);
143     *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
144         hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
145     ok(*hToolbar != NULL, "Toolbar creation problem\n");
146     ok(SendMessage(*hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
147     ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
148     ok(SendMessage(*hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
149 }
150
151 static void rebuild_toolbar_with_buttons(HWND *hToolbar)
152 {
153     TBBUTTON buttons[5];
154     rebuild_toolbar(hToolbar);
155     
156     ZeroMemory(&buttons, sizeof(buttons));
157     buttons[0].idCommand = 1;
158     buttons[0].fsStyle = BTNS_BUTTON;
159     buttons[0].fsState = TBSTATE_ENABLED;
160     buttons[0].iString = -1;
161     buttons[1].idCommand = 3;
162     buttons[1].fsStyle = BTNS_BUTTON;
163     buttons[1].fsState = TBSTATE_ENABLED;
164     buttons[1].iString = -1;
165     buttons[2].idCommand = 5;
166     buttons[2].fsStyle = BTNS_SEP;
167     buttons[2].fsState = TBSTATE_ENABLED;
168     buttons[2].iString = -1;
169     buttons[3].idCommand = 7;
170     buttons[3].fsStyle = BTNS_BUTTON;
171     buttons[3].fsState = TBSTATE_ENABLED;
172     buttons[3].iString = -1;
173     buttons[4].idCommand = 9;
174     buttons[4].fsStyle = BTNS_BUTTON;
175     buttons[4].fsState = 0;  /* disabled */
176     buttons[4].iString = -1;
177     ok(SendMessage(*hToolbar, TB_ADDBUTTONS, 5, (LPARAM)buttons) == 1, "TB_ADDBUTTONS failed\n");
178     ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
179 }
180
181
182 #define CHECK_IMAGELIST(count, dx, dy) { \
183     int cx, cy; \
184     HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
185     ok(himl != NULL, "No image list\n"); \
186     if (himl != NULL) {\
187         ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \
188         ImageList_GetIconSize(himl, &cx, &cy); \
189         ok(cx == dx && cy == dy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
190     } \
191 }
192
193 static void test_add_bitmap(void)
194 {
195     HWND hToolbar = NULL;
196     TBADDBITMAP bmp128;
197     TBADDBITMAP bmp80;
198     TBADDBITMAP stdsmall;
199     TBADDBITMAP addbmp;
200     HIMAGELIST himl;
201     INT ret;
202
203     /* empty 128x15 bitmap */
204     bmp128.hInst = GetModuleHandle(NULL);
205     bmp128.nID = IDB_BITMAP_128x15;
206
207     /* empty 80x15 bitmap */
208     bmp80.hInst = GetModuleHandle(NULL);
209     bmp80.nID = IDB_BITMAP_80x15;
210
211     /* standard bitmap - 240x15 pixels */
212     stdsmall.hInst = HINST_COMMCTRL;
213     stdsmall.nID = IDB_STD_SMALL_COLOR;
214
215     rebuild_toolbar(&hToolbar);
216     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
217     CHECK_IMAGELIST(8, 16, 16);
218     
219     /* adding more bitmaps */
220     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 8, "TB_ADDBITMAP - unexpected return\n");
221     CHECK_IMAGELIST(13, 16, 16);
222     /* adding the same bitmap will simply return the index of the already loaded block */
223     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128);
224     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
225     CHECK_IMAGELIST(13, 16, 16);
226     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
227     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
228     CHECK_IMAGELIST(13, 16, 16);
229     /* even if we increase the wParam */
230     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 55, (LPARAM)&bmp80);
231     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
232     CHECK_IMAGELIST(13, 16, 16);
233
234     /* when the wParam is smaller than the bitmaps count but non-zero, all the bitmaps will be added*/
235     rebuild_toolbar(&hToolbar);
236     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
237     CHECK_IMAGELIST(8, 16, 16);
238     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
239     ok(ret == 3, "TB_ADDBITMAP - unexpected return %d\n", ret);
240     /* the returned value is misleading - id 8 is the id of the first icon from bmp80 */
241     CHECK_IMAGELIST(13, 16, 16);
242
243     /* the same for negative wParam */
244     rebuild_toolbar(&hToolbar);
245     ret = SendMessageA(hToolbar, TB_ADDBITMAP, -143, (LPARAM)&bmp128);
246     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
247     CHECK_IMAGELIST(8, 16, 16);
248     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
249     ok(ret == -143, "TB_ADDBITMAP - unexpected return %d\n", ret);
250     CHECK_IMAGELIST(13, 16, 16);
251
252     /* for zero only one bitmap will be added */
253     rebuild_toolbar(&hToolbar);
254     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&bmp80);
255     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
256     CHECK_IMAGELIST(1, 16, 16);
257
258     /* if wParam is larger than the amount of icons, the list is grown */
259     rebuild_toolbar(&hToolbar);
260     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
261     CHECK_IMAGELIST(100, 16, 16);
262     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128);
263     ok(ret == 100, "TB_ADDBITMAP - unexpected return %d\n", ret);
264     CHECK_IMAGELIST(200, 16, 16);
265
266     /* adding built-in items - the wParam is ignored */
267     rebuild_toolbar(&hToolbar);
268     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
269     CHECK_IMAGELIST(5, 16, 16);
270     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 5, "TB_ADDBITMAP - unexpected return\n");
271     CHECK_IMAGELIST(20, 16, 16);
272     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 20, "TB_ADDBITMAP - unexpected return\n");
273     CHECK_IMAGELIST(28, 16, 16);
274
275     /* when we increase the bitmap size, less icons will be created */
276     rebuild_toolbar(&hToolbar);
277     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)) == TRUE, "TB_SETBITMAPSIZE failed\n");
278     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
279     CHECK_IMAGELIST(6, 20, 20);
280     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
281     ok(ret == 1, "TB_ADDBITMAP - unexpected return %d\n", ret);
282     CHECK_IMAGELIST(10, 20, 20);
283     /* the icons can be resized - an UpdateWindow is needed as this probably happens during WM_PAINT */
284     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
285     UpdateWindow(hToolbar);
286     CHECK_IMAGELIST(26, 8, 8);
287     /* loading a standard bitmaps automatically resizes the icons */
288     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&stdsmall) == 2, "TB_ADDBITMAP - unexpected return\n");
289     UpdateWindow(hToolbar);
290     CHECK_IMAGELIST(28, 16, 16);
291
292     /* two more SETBITMAPSIZE tests */
293     rebuild_toolbar(&hToolbar);
294     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
295     CHECK_IMAGELIST(100, 16, 16);
296     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 100, "TB_ADDBITMAP - unexpected return\n");
297     CHECK_IMAGELIST(200, 16, 16);
298     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
299     UpdateWindow(hToolbar);
300     CHECK_IMAGELIST(200, 8, 8);
301     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
302     UpdateWindow(hToolbar);
303     CHECK_IMAGELIST(200, 30, 30);
304     rebuild_toolbar(&hToolbar);
305     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
306     CHECK_IMAGELIST(8, 16, 16);
307     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp80) == 5, "TB_ADDBITMAP - unexpected return\n");
308     CHECK_IMAGELIST(13, 16, 16);
309     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
310     UpdateWindow(hToolbar);
311     CHECK_IMAGELIST(8, 30, 30);
312     /* when the width or height is zero, set it to 1 */
313     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
314     UpdateWindow(hToolbar);
315     CHECK_IMAGELIST(208, 1, 1);
316     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 5)) == TRUE, "TB_SETBITMAPSIZE failed\n");
317     UpdateWindow(hToolbar);
318     CHECK_IMAGELIST(208, 1, 5);
319     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(5, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
320     UpdateWindow(hToolbar);
321     CHECK_IMAGELIST(41, 5, 1);
322
323     /* the control can add bitmaps to an existing image list */
324     rebuild_toolbar(&hToolbar);
325     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
326     ok(himl != NULL, "failed to create imagelist\n");
327     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
328     CHECK_IMAGELIST(4, 20, 15);
329     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
330     CHECK_IMAGELIST(10, 20, 15);
331     /* however TB_SETBITMAPSIZE/add std bitmap won't change the image size (the button size does change) */
332     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
333     UpdateWindow(hToolbar);
334     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(15, 14), "%x");
335     CHECK_IMAGELIST(10, 20, 15);
336     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 1, "TB_SETBITMAPSIZE failed\n");
337     UpdateWindow(hToolbar);
338     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
339     CHECK_IMAGELIST(22, 20, 15);
340
341     /* check standard bitmaps */
342     addbmp.hInst = HINST_COMMCTRL;
343     addbmp.nID = IDB_STD_SMALL_COLOR;
344     rebuild_toolbar(&hToolbar);
345     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
346     CHECK_IMAGELIST(15, 16, 16);
347     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
348     addbmp.nID = IDB_STD_LARGE_COLOR;
349     rebuild_toolbar(&hToolbar);
350     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
351     CHECK_IMAGELIST(15, 24, 24);
352     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(31, 30), "%x");
353
354     addbmp.nID = IDB_VIEW_SMALL_COLOR;
355     rebuild_toolbar(&hToolbar);
356     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
357     CHECK_IMAGELIST(12, 16, 16);
358     addbmp.nID = IDB_VIEW_LARGE_COLOR;
359     rebuild_toolbar(&hToolbar);
360     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
361     CHECK_IMAGELIST(12, 24, 24);
362
363     addbmp.nID = IDB_HIST_SMALL_COLOR;
364     rebuild_toolbar(&hToolbar);
365     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
366     CHECK_IMAGELIST(5, 16, 16);
367     addbmp.nID = IDB_HIST_LARGE_COLOR;
368     rebuild_toolbar(&hToolbar);
369     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
370     CHECK_IMAGELIST(5, 24, 24);
371
372
373     DestroyWindow(hToolbar);
374 }
375
376 #define CHECK_STRING_TABLE(count, tab) { \
377         INT _i; \
378         CHAR _buf[260]; \
379         for (_i = 0; _i < (count); _i++) {\
380             ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, _i), (LPARAM)_buf); \
381             ok(ret >= 0, "TB_GETSTRING - unexpected return %d while checking string %d\n", ret, _i); \
382             if (ret >= 0) \
383                 ok(strcmp(_buf, (tab)[_i]) == 0, "Invalid string #%d - '%s' vs '%s'\n", _i, (tab)[_i], _buf); \
384         } \
385         ok(SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, (count)), (LPARAM)_buf) == -1, \
386             "Too many string in table\n"); \
387     }
388
389 static void test_add_string(void)
390 {
391     LPCSTR test1 = "a\0b\0";
392     LPCSTR test2 = "|a|b||\0";
393     LPCSTR ret1[] = {"a", "b"};
394     LPCSTR ret2[] = {"a", "b", "|a|b||"};
395     LPCSTR ret3[] = {"a", "b", "|a|b||", "p", "q"};
396     LPCSTR ret4[] = {"a", "b", "|a|b||", "p", "q", "p"};
397     LPCSTR ret5[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q"};
398     LPCSTR ret6[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q"};
399     LPCSTR ret7[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q", "br", "c", "d"};
400     HWND hToolbar = NULL;
401     TBBUTTON button;
402     int ret;
403
404     rebuild_toolbar(&hToolbar);
405     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
406     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
407     CHECK_STRING_TABLE(2, ret1);
408     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
409     ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
410     CHECK_STRING_TABLE(3, ret2);
411
412     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD1);
413     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
414     CHECK_STRING_TABLE(3, ret2);
415     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD2);
416     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
417     CHECK_STRING_TABLE(5, ret3);
418     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD3);
419     ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret);
420     CHECK_STRING_TABLE(6, ret4);
421     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD4);
422     ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret);
423     CHECK_STRING_TABLE(8, ret5);
424     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD5);
425     ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret);
426     CHECK_STRING_TABLE(11, ret6);
427     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD7);
428     ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret);
429     CHECK_STRING_TABLE(14, ret7);
430
431     ZeroMemory(&button, sizeof(button));
432     button.iString = (UINT_PTR)"Test";
433     SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button);
434     CHECK_STRING_TABLE(14, ret7);
435     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button);
436     CHECK_STRING_TABLE(14, ret7);
437
438     DestroyWindow(hToolbar);
439 }
440
441 static void expect_hot_notify(int idold, int idnew)
442 {
443     g_fExpectedHotItemOld = idold;
444     g_fExpectedHotItemNew = idnew;
445     g_fReceivedHotItemChange = FALSE;
446 }
447
448 #define check_hot_notify() \
449     ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \
450     g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0;
451
452 static void test_hotitem(void)
453 {
454     HWND hToolbar = NULL;
455     TBBUTTONINFO tbinfo;
456     LRESULT ret;
457
458     g_fBlockHotItemChange = FALSE;
459
460     rebuild_toolbar_with_buttons(&hToolbar);
461     /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars.
462      * comctl6 doesn't have this requirement even when theme == NULL */
463     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLong(hToolbar, GWL_STYLE));
464     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
465     ok(ret == -1, "Hot item: %ld, expected -1\n", ret);
466     ret = SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
467     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
468     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
469     ok(ret == 1, "Hot item: %ld, expected 1\n", ret);
470     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
471     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
472
473     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeef, 0);
474     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
475     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
476     ok(ret == 2, "Hot item: %lx, expected 2\n", ret);
477     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeef, 0);
478     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
479     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
480     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
481
482     expect_hot_notify(0, 7);
483     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
484     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
485     check_hot_notify();
486     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
487     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
488     g_fBlockHotItemChange = TRUE;
489     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
490     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
491     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
492     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
493     g_fBlockHotItemChange = FALSE;
494
495     g_fReceivedHotItemChange = FALSE;
496     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeaf, 0);
497     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
498     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n");
499
500     g_fReceivedHotItemChange = FALSE;
501     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
502     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
503     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n");
504
505     expect_hot_notify(7, 0);
506     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeaf, 0);
507     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
508     check_hot_notify();
509     SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
510
511     /* setting disabled buttons will generate a notify with the button id but no button will be hot */
512     expect_hot_notify(7, 9);
513     ret = SendMessage(hToolbar, TB_SETHOTITEM, 4, 0);
514     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
515     check_hot_notify();
516     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
517     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
518     /* enabling the button won't change that */
519     SendMessage(hToolbar, TB_ENABLEBUTTON, 9, TRUE);
520     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
521     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
522
523     /* disabling a hot button works */
524     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
525     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
526     g_fReceivedHotItemChange = FALSE;
527     SendMessage(hToolbar, TB_ENABLEBUTTON, 7, FALSE);
528     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
529     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
530     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
531
532     SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
533     tbinfo.cbSize = sizeof(TBBUTTONINFO);
534     tbinfo.dwMask = TBIF_STATE;
535     tbinfo.fsState = 0;  /* disabled */
536     g_fReceivedHotItemChange = FALSE;
537     ok(SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFO failed\n");
538     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
539     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
540     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
541
542     DestroyWindow(hToolbar);
543 }
544
545 #if 0  /* use this to generate more tests*/
546
547 static void dump_sizes(HWND hToolbar)
548 {
549     SIZE sz;
550     RECT r;
551     int count = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0);
552     int i;
553
554     GetClientRect(hToolbar, &r);
555     SendMessageA(hToolbar, TB_GETMAXSIZE, 0, &sz);
556     printf("  { {%d, %d, %d, %d}, {%d, %d}, %d, {", r.left, r.top, r.right, r.bottom,
557         sz.cx, sz.cy, count);
558     for (i=0; i<count; i++)
559     {
560         SendMessageA(hToolbar, TB_GETITEMRECT, i, &r);
561         printf("%s{%3d, %3d, %3d, %3d}, ", (i%3==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom);
562     }
563     printf("\n  }, }, \n");
564 }
565
566 #define check_sizes() dump_sizes(hToolbar);
567 #define check_sizes_todo(todomask) dump_sizes(hToolbar);
568
569 #else
570
571 typedef struct
572 {
573     RECT rcClient;
574     SIZE szMin;
575     INT nButtons;
576     RECT rcButtons[100];
577 } tbsize_result_t;
578
579 static tbsize_result_t tbsize_results[] =
580 {
581   { {0, 0, 672, 26}, {100, 22}, 5, {
582     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
583     { 54,   2,  77,  24}, { 77,   2, 100,  24},
584   }, },
585   { {0, 0, 672, 26}, {146, 22}, 7, {
586     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
587     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
588     {  0,  24,  23,  46},
589   }, },
590   { {0, 0, 672, 48}, {146, 22}, 7, {
591     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
592     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
593     {  0,  24,  23,  46},
594   }, },
595   { {0, 0, 672, 26}, {146, 22}, 7, {
596     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
597     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
598     {123,   2, 146,  24},
599   }, },
600   { {0, 0, 672, 26}, {192, 22}, 9, {
601     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
602     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
603     {123,   2, 146,  24}, {146,   2, 169,  24}, {169,   2, 192,  24},
604   }, },
605   { {0, 0, 672, 92}, {882, 22}, 39, {
606     {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,   2,   8,  29},
607     {  0,  29,  23,  51}, { 23,  29,  46,  51}, { 46,  29,  69,  51},
608     { 69,  29,  92,  51}, { 92,  29, 115,  51}, {115,  29, 138,  51},
609     {138,  29, 161,  51}, {161,  29, 184,  51}, {184,  29, 207,  51},
610     {207,  29, 230,  51}, {230,  29, 253,  51}, {253,  29, 276,  51},
611     {276,  29, 299,  51}, {299,  29, 322,  51}, {322,  29, 345,  51},
612     {345,  29, 368,  51}, {368,  29, 391,  51}, {391,  29, 414,  51},
613     {414,  29, 437,  51}, {437,  29, 460,  51}, {460,  29, 483,  51},
614     {483,  29, 506,  51}, {506,  29, 529,  51}, {529,  29, 552,  51},
615     {552,  29, 575,  51}, {575,  29, 598,  51}, {598,  29, 621,  51},
616     {621,  29, 644,  51}, {644,  29, 667,  51}, {  0,  51,  23,  73},
617     { 23,  51,  46,  73}, { 46,  51,  69,  73}, { 69,  51,  92,  73},
618     { 92,  51, 115,  73}, {115,  51, 138,  73}, {138,  51, 161,  73},
619   }, },
620   { {0, 0, 48, 226}, {23, 140}, 7, {
621     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  94,  24},
622     { 94,   2, 117,  24}, {117,   2, 140,  24}, {140,   2, 163,  24},
623     {  0,  24,  23,  46},
624   }, },
625   { {0, 0, 92, 226}, {23, 140}, 7, {
626     {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,  24,  92,  32},
627     {  0,  32,  23,  54}, { 23,  32,  46,  54}, { 46,  32,  69,  54},
628     { 69,  32,  92,  54},
629   }, },
630   { {0, 0, 672, 26}, {194, 30}, 7, {
631     {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
632     { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
633     {  0,  32,  31,  62},
634   }, },
635   { {0, 0, 672, 64}, {194, 30}, 7, {
636     {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
637     { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
638     {  0,  32,  31,  62},
639   }, },
640   { {0, 0, 672, 64}, {194, 30}, 7, {
641     {  0,   0,  31,  30}, { 31,   0,  62,  30}, { 62,   0,  70,  30},
642     { 70,   0, 101,  30}, {101,   0, 132,  30}, {132,   0, 163,  30},
643     {  0,  30,  31,  60},
644   }, },
645   { {0, 0, 124, 226}, {31, 188}, 7, {
646     {  0,   0,  31,  30}, { 31,   0,  62,  30}, {  0,  30, 124,  38},
647     {  0,  38,  31,  68}, { 31,  38,  62,  68}, { 62,  38,  93,  68},
648     { 93,  38, 124,  68},
649   }, },
650   { {0, 0, 672, 26}, {146, 22}, 7, {
651     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
652     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
653     {123,   2, 146,  24},
654   }, },
655   { {0, 0, 672, 26}, {146, 100}, 7, {
656     {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
657     { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
658     {123,   0, 146, 100},
659   }, },
660   { {0, 0, 672, 26}, {215, 100}, 10, {
661     {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
662     { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
663     {123,   0, 146, 100}, {146,   0, 169, 100}, {169,   0, 192, 100},
664     {192,   0, 215, 100},
665   }, },
666   { {0, 0, 672, 26}, {238, 39}, 11, {
667     {  0,   0,  23,  39}, { 23,   0,  46,  39}, { 46,   0,  54,  39},
668     { 54,   0,  77,  39}, { 77,   0, 100,  39}, {100,   0, 123,  39},
669     {123,   0, 146,  39}, {146,   0, 169,  39}, {169,   0, 192,  39},
670     {192,   0, 215,  39}, {215,   0, 238,  39},
671   }, },
672   { {0, 0, 672, 26}, {238, 22}, 11, {
673     {  0,   0,  23,  22}, { 23,   0,  46,  22}, { 46,   0,  54,  22},
674     { 54,   0,  77,  22}, { 77,   0, 100,  22}, {100,   0, 123,  22},
675     {123,   0, 146,  22}, {146,   0, 169,  22}, {169,   0, 192,  22},
676     {192,   0, 215,  22}, {215,   0, 238,  22},
677   }, },
678   { {0, 0, 672, 26}, {489, 39}, 3, {
679     {  0,   2, 163,  41}, {163,   2, 330,  41}, {330,   2, 493,  41},
680   }, },
681   { {0, 0, 672, 104}, {978, 24}, 6, {
682     {  0,   2, 163,  26}, {163,   2, 326,  26}, {326,   2, 489,  26},
683     {489,   2, 652,  26}, {652,   2, 819,  26}, {819,   2, 850,  26},
684   }, },
685   { {0, 0, 672, 28}, {978, 38}, 6, {
686     {  0,   0, 163,  38}, {163,   0, 326,  38}, {326,   0, 489,  38},
687     {489,   0, 652,  38}, {652,   0, 819,  38}, {819,   0, 850,  38},
688   }, },
689 };
690
691 static int tbsize_numtests = 0;
692
693 #define check_sizes_todo(todomask) { \
694         RECT rc; \
695         int buttonCount, i, mask=(todomask); \
696         tbsize_result_t *res = &tbsize_results[tbsize_numtests]; \
697         assert(tbsize_numtests < sizeof(tbsize_results)/sizeof(tbsize_results[0])); \
698         GetClientRect(hToolbar, &rc); \
699         /*check_rect("client", rc, res->rcClient);*/ \
700         buttonCount = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0); \
701         compare(buttonCount, res->nButtons, "%d"); \
702         for (i=0; i<min(buttonCount, res->nButtons); i++) { \
703             ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \
704             if (!(mask&1)) { \
705                 check_rect("button", rc, res->rcButtons[i]); \
706             } else {\
707                 todo_wine { check_rect("button", rc, res->rcButtons[i]); } \
708             } \
709             mask >>= 1; \
710         } \
711         tbsize_numtests++; \
712     }
713
714 #define check_sizes() check_sizes_todo(0)
715
716 #endif
717
718 static TBBUTTON buttons1[] = {
719     {0, 10, TBSTATE_WRAP|TBSTATE_ENABLED, 0, {0, }, 0, -1},
720     {0, 11, 0, 0, {0, }, 0, -1},
721 };
722 static TBBUTTON buttons2[] = {
723     {0, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
724     {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
725 };
726 static TBBUTTON buttons3[] = {
727     {0, 30, TBSTATE_ENABLED, 0, {0, }, 0, 0},
728     {0, 31, TBSTATE_ENABLED, 0, {0, }, 0, 1},
729     {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1},
730     {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)"Tst"}
731 };
732
733 static void test_sizes(void)
734 {
735     HWND hToolbar = NULL;
736     HIMAGELIST himl;
737     int style;
738     int i;
739
740     rebuild_toolbar_with_buttons(&hToolbar);
741     style = GetWindowLong(hToolbar, GWL_STYLE);
742     ok(style == (WS_CHILD|WS_VISIBLE|CCS_TOP), "Invalid style %x\n", style);
743     check_sizes();
744     /* the TBSTATE_WRAP makes a second row */
745     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
746     check_sizes();
747     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
748     check_sizes();
749     /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */
750     SetWindowLong(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE);
751     check_sizes();
752     /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */
753     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
754     check_sizes();
755     /* only after adding enough buttons the bar will be wrapped on a
756      * separator and then on the first button */
757     for (i=0; i<15; i++)
758         SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
759     check_sizes_todo(0x4);
760
761     rebuild_toolbar_with_buttons(&hToolbar);
762     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
763     /* setting the buttons vertical will only change the window client size */
764     SetWindowLong(hToolbar, GWL_STYLE, style | CCS_VERT);
765     SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
766     check_sizes_todo(0x3c);
767     /* with a TBSTYLE_WRAPABLE a wrapping will occur on the separator */
768     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE | CCS_VERT);
769     SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
770     check_sizes_todo(0x7c);
771
772     rebuild_toolbar_with_buttons(&hToolbar);
773     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
774     /* a TB_SETBITMAPSIZE changes button sizes*/
775     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
776     check_sizes();
777
778     /* setting a TBSTYLE_FLAT doesn't change anything - even after a TB_AUTOSIZE */
779     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
780     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
781     check_sizes();
782     /* but after a TB_SETBITMAPSIZE the top margins is changed */
783     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20));
784     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
785     check_sizes();
786     /* some vertical toolbar sizes */
787     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_VERT);
788     check_sizes_todo(0x7c);
789
790     rebuild_toolbar_with_buttons(&hToolbar);
791     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
792     /* newly added buttons will be use the previous margin */
793     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
794     check_sizes();
795     /* TB_SETBUTTONSIZE can't be used to reduce the size of a button below the default */
796     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
797     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(22, 21))==1, "TB_SETBUTTONSIZE\n");
798     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
799     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
800     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
801     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3))==1, "TB_SETBUTTONSIZE\n");
802     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
803     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
804     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
805     check_sizes();
806     /* add some buttons with non-default sizes */
807     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
808     SendMessageA(hToolbar, TB_INSERTBUTTON, -1, (LPARAM)&buttons2[0]);
809     check_sizes();
810     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
811     /* TB_ADDSTRING resets the size */
812     SendMessageA(hToolbar, TB_ADDSTRING, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
813     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
814     check_sizes();
815     /* TB_SETBUTTONSIZE can be used to crop the text */
816     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
817     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
818     check_sizes();
819     /* the default size is bitmap size + padding */
820     SendMessageA(hToolbar, TB_SETPADDING, 0, MAKELONG(1, 1));
821     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
822     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(17, 17), "Unexpected button size\n");
823     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(3, 3));
824     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
825     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(4, 4), "Unexpected button size\n");
826
827     rebuild_toolbar(&hToolbar);
828     /* sending a TB_SETBITMAPSIZE with the same sizes is enough to make the button smaller */
829     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
830     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15));
831     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 21), "Unexpected button size\n");
832
833     rebuild_toolbar(&hToolbar);
834     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
835     /* the height is increased after a TB_ADDSTRING */
836     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
837     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
838     /* if a string is in the pool, even adding a button without a string resets the size */
839     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]);
840     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
841     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
842     /* an BTNS_AUTOSIZE button is also considered when computing the new size */
843     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]);
844     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
845     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
846     check_sizes();
847     /* delete button doesn't change the buttons size */
848     SendMessageA(hToolbar, TB_DELETEBUTTON, 2, 0);
849     SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0);
850     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
851     /* TB_INSERTBUTTONS will */
852     SendMessageA(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons2[0]);
853     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
854
855     /* TB_HIDEBUTTON and TB_MOVEBUTTON doesn't force a recalc */
856     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
857     ok(SendMessageA(hToolbar, TB_MOVEBUTTON, 0, 1), "TB_MOVEBUTTON failed\n");
858     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
859     ok(SendMessageA(hToolbar, TB_HIDEBUTTON, 20, TRUE), "TB_HIDEBUTTON failed\n");
860     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
861     /* however changing the hidden flag with TB_SETSTATE does */
862     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED|TBSTATE_HIDDEN), "TB_SETSTATE failed\n");
863     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
864     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED), "TB_SETSTATE failed\n");
865     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
866
867     /* TB_SETIMAGELIST always changes the height but the width only if necessary */
868     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
869     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
870     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
871     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 21), "Unexpected button size\n");
872     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
873     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
874     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
875     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
876     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
877     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 7), "Unexpected button size\n");
878     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
879     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(8, 7), "Unexpected button size\n");
880     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
881     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
882     /* the text is taken into account */
883     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
884     SendMessageA(hToolbar, TB_ADDBUTTONS, 4, (LPARAM)buttons3);
885     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 38), "Unexpected button size\n");
886     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
887     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 24), "Unexpected button size\n");
888     /* the style change also comes into effect */
889     check_sizes();
890     SetWindowLong(hToolbar, GWL_STYLE, GetWindowLong(hToolbar, GWL_STYLE) | TBSTYLE_FLAT);
891     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
892     check_sizes_todo(0x30);     /* some small problems with BTNS_AUTOSIZE button sizes */
893
894     rebuild_toolbar(&hToolbar);
895     ImageList_Destroy(himl);
896
897     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]);
898     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
899     SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0);
900     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
901
902     DestroyWindow(hToolbar);
903 }
904
905 static void test_getbuttoninfo(void)
906 {
907     HWND hToolbar = NULL;
908     int i;
909
910     rebuild_toolbar_with_buttons(&hToolbar);
911     for (i = 0; i < 128; i++)
912     {
913         TBBUTTONINFO tbi;
914         int ret;
915
916         tbi.cbSize = i;
917         tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
918         ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi);
919         if (i == sizeof(TBBUTTONINFO)) {
920             compare(ret, 0, "%d");
921         } else {
922             compare(ret, -1, "%d");
923         }
924     }
925     DestroyWindow(hToolbar);
926 }
927
928 static void test_createtoolbarex()
929 {
930     HWND hToolbar;
931     TBBUTTON btns[3];
932     ZeroMemory(&btns, sizeof(btns));
933
934     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
935         3, 20, 20, 16, 16, sizeof(TBBUTTON));
936     CHECK_IMAGELIST(16, 20, 20);
937     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x1a001b, "%x");
938     DestroyWindow(hToolbar);
939
940     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
941         3, 4, 4, 16, 16, sizeof(TBBUTTON));
942     CHECK_IMAGELIST(32, 4, 4);
943     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xa000b, "%x");
944     DestroyWindow(hToolbar);
945
946     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
947         3, 0, 8, 12, 12, sizeof(TBBUTTON));
948     CHECK_IMAGELIST(16, 12, 12);
949     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x120013, "%x");
950     DestroyWindow(hToolbar);
951
952     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
953         3, -1, 8, 12, 12, sizeof(TBBUTTON));
954     CHECK_IMAGELIST(16, 12, 8);
955     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0013, "%x");
956     DestroyWindow(hToolbar);
957
958     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
959         3, -1, 8, -1, 12, sizeof(TBBUTTON));
960     CHECK_IMAGELIST(16, 16, 8);
961     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0017, "%x");
962     DestroyWindow(hToolbar);
963
964     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
965         3, 0, 0, 12, -1, sizeof(TBBUTTON));
966     CHECK_IMAGELIST(16, 12, 16);
967     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160013, "%x");
968     DestroyWindow(hToolbar);
969
970     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
971         3, 0, 0, 0, 12, sizeof(TBBUTTON));
972     CHECK_IMAGELIST(16, 16, 16);
973     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160017, "%x");
974     DestroyWindow(hToolbar);
975 }
976
977
978 START_TEST(toolbar)
979 {
980     WNDCLASSA wc;
981     MSG msg;
982     RECT rc;
983   
984     InitCommonControls();
985   
986     wc.style = CS_HREDRAW | CS_VREDRAW;
987     wc.cbClsExtra = 0;
988     wc.cbWndExtra = 0;
989     wc.hInstance = GetModuleHandleA(NULL);
990     wc.hIcon = NULL;
991     wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
992     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
993     wc.lpszMenuName = NULL;
994     wc.lpszClassName = "MyTestWnd";
995     wc.lpfnWndProc = MyWndProc;
996     RegisterClassA(&wc);
997     
998     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
999       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
1000     GetClientRect(hMainWnd, &rc);
1001     ShowWindow(hMainWnd, SW_SHOW);
1002
1003     basic_test();
1004     test_add_bitmap();
1005     test_add_string();
1006     test_hotitem();
1007     test_sizes();
1008     test_getbuttoninfo();
1009     test_createtoolbarex();
1010
1011     PostQuitMessage(0);
1012     while(GetMessageA(&msg,0,0,0)) {
1013         TranslateMessage(&msg);
1014         DispatchMessageA(&msg);
1015     }
1016     DestroyWindow(hMainWnd);
1017 }