comctl32/tests: Call InitCommonControlsEx() if available, fall back to InitCommonCont...
[wine] / dlls / comctl32 / tests / rebar.c
1 /* Unit tests for rebar.
2  *
3  * Copyright 2007 Mikolaj Zalewski
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #include <windows.h>
24 #include <commctrl.h>
25 #include <uxtheme.h>
26
27 #include "wine/test.h"
28
29 RECT height_change_notify_rect;
30 static HWND hMainWnd;
31 static HWND hRebar;
32
33
34 #define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
35     val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \
36     val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom);
37
38 #define check_rect_no_top(name, val, exp) { \
39         ok((val.bottom - val.top == exp.bottom - exp.top) && \
40             val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d), ignoring top\n", \
41             val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom); \
42     }
43
44 #define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
45
46 #define expect_eq(expr, value, type, format) { type ret = expr; ok((value) == ret, #expr " expected " format "  got " format "\n", (value), (ret)); }
47
48 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
49 {
50     return 0;
51 }
52
53 static BOOL is_font_installed(const char *name)
54 {
55     HDC hdc = GetDC(0);
56     BOOL ret = FALSE;
57
58     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
59         ret = TRUE;
60
61     ReleaseDC(0, hdc);
62     return ret;
63 }
64
65 static void rebuild_rebar(HWND *hRebar)
66 {
67     if (*hRebar)
68         DestroyWindow(*hRebar);
69
70     *hRebar = CreateWindow(REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
71         hMainWnd, (HMENU)17, GetModuleHandle(NULL), NULL);
72     SendMessageA(*hRebar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
73 }
74
75 static HWND build_toolbar(int nr, HWND hParent)
76 {
77     TBBUTTON btns[8];
78     HWND hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE, 0, 0, 0, 0,
79         hParent, (HMENU)5, GetModuleHandle(NULL), NULL);
80     int iBitmapId = 0;
81     int i;
82
83     ok(hToolbar != NULL, "Toolbar creation problem\n");
84     ok(SendMessage(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
85     ok(SendMessage(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
86     ok(SendMessage(hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
87
88     for (i=0; i<5+nr; i++)
89     {
90         btns[i].iBitmap = i;
91         btns[i].idCommand = i;
92         btns[i].fsStyle = BTNS_BUTTON;
93         btns[i].fsState = TBSTATE_ENABLED;
94         btns[i].iString = 0;
95     }
96
97     switch (nr)
98     {
99         case 0: iBitmapId = IDB_HIST_SMALL_COLOR; break;
100         case 1: iBitmapId = IDB_VIEW_SMALL_COLOR; break;
101         case 2: iBitmapId = IDB_STD_SMALL_COLOR; break;
102     }
103     ok(SendMessage(hToolbar, TB_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGE failed\n");
104     ok(SendMessage(hToolbar, TB_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n");
105     return hToolbar;
106 }
107
108 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
109 {
110     switch (msg)
111     {
112         case WM_NOTIFY:
113             {
114                 NMHDR *lpnm = (NMHDR *)lParam;
115                 if (lpnm->code == RBN_HEIGHTCHANGE)
116                     GetClientRect(hRebar, &height_change_notify_rect);
117             }
118             break;
119     }
120     return DefWindowProcA(hWnd, msg, wParam, lParam);
121 }
122
123 #if 0  /* use this to generate more tests*/
124
125 static void dump_sizes(HWND hRebar)
126 {
127     SIZE sz;
128     RECT r;
129     int count;
130     int i, h;
131
132     GetClientRect(hRebar, &r);
133     count = SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0);
134     printf("  { {%d, %d, %d, %d}, %d, %d, {", r.left, r.top, r.right, r.bottom,
135         SendMessageA(hRebar, RB_GETBARHEIGHT, 0, 0), count);
136     if (count == 0)
137         printf("0, ");
138     for (i = 0; i < count; i++)  /* rows */
139         printf("%d, ", SendMessageA(hRebar, RB_GETROWHEIGHT, i, 0));
140     printf("}, ");
141
142     count = SendMessageA(hRebar, RB_GETBANDCOUNT, 0, 0);
143     printf("%d, {", count);
144     if (count == 0)
145         printf("{{0, 0, 0, 0}, 0, 0},");
146     for (i=0; i<count; i++)
147     {
148         REBARBANDINFO rbi;
149         rbi.cbSize = sizeof(REBARBANDINFO);
150         rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE;
151         ok(SendMessageA(hRebar, RB_GETBANDINFOA, i, (LPARAM)&rbi), "RB_GETBANDINFO failed\n");
152         ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&r), "RB_GETRECT failed\n");
153         printf("%s{ {%3d, %3d, %3d, %3d}, 0x%02x, %d}, ", (i%2==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom,
154             rbi.fStyle, rbi.cx);
155     }
156     printf("\n  }, }, \n");
157 }
158
159 #define check_sizes() dump_sizes(hRebar);
160 #define check_sizes_todo(todomask) dump_sizes(hRebar);
161
162 #else
163
164 typedef struct {
165     RECT rc;
166     DWORD fStyle;
167     INT cx;
168 } rbband_result_t;
169
170 typedef struct {
171     RECT rcClient;
172     int cyBarHeight;
173     int nRows;
174     int cyRowHeights[50];
175     int nBands;
176     rbband_result_t bands[50];
177 } rbsize_result_t;
178
179 rbsize_result_t rbsize_results[] = {
180   { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
181   }, },
182   { {0, 0, 672, 4}, 4, 1, {4, }, 1, {
183     { {  0,   0, 672,   4}, 0x00, 200},
184   }, },
185   { {0, 0, 672, 4}, 4, 1, {4, }, 2, {
186     { {  0,   0, 200,   4}, 0x00, 200}, { {200,   0, 672,   4}, 0x04, 200},
187   }, },
188   { {0, 0, 672, 30}, 30, 1, {30, }, 3, {
189     { {  0,   0, 200,  30}, 0x00, 200}, { {200,   0, 400,  30}, 0x04, 200},
190     { {400,   0, 672,  30}, 0x00, 200},
191   }, },
192   { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
193     { {  0,   0, 200,  34}, 0x00, 200}, { {200,   0, 400,  34}, 0x04, 200},
194     { {400,   0, 604,  34}, 0x00, 200}, { {604,   0, 672,  34}, 0x04, 68},
195   }, },
196   { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
197     { {  0,   0, 200,  34}, 0x00, 200}, { {200,   0, 400,  34}, 0x04, 200},
198     { {400,   0, 604,  34}, 0x00, 200}, { {604,   0, 672,  34}, 0x04, 68},
199   }, },
200   { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
201     { {  0,   0, 200,  34}, 0x00, 200}, { {202,   0, 402,  34}, 0x04, 200},
202     { {404,   0, 604,  34}, 0x00, 200}, { {606,   0, 672,  34}, 0x04, 66},
203   }, },
204   { {0, 0, 672, 70}, 70, 2, {34, 34, }, 5, {
205     { {  0,   0, 142,  34}, 0x00, 200}, { {144,   0, 557,  34}, 0x00, 200},
206     { {559,   0, 672,  34}, 0x04, 200}, { {  0,  36, 200,  70}, 0x00, 200},
207     { {202,  36, 672,  70}, 0x04, 66},
208   }, },
209   { {0, 0, 672, 34}, 34, 1, {34, }, 5, {
210     { {  0,   0, 167,  34}, 0x00, 200}, { {169,   0, 582,  34}, 0x00, 200},
211     { {559,   0, 759,  34}, 0x08, 200}, { {584,   0, 627,  34}, 0x00, 200},
212     { {629,   0, 672,  34}, 0x04, 66},
213   }, },
214   { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
215     { {  0,   0, 167,  34}, 0x00, 200}, { {169,   0, 582,  34}, 0x00, 200},
216     { {584,   0, 627,  34}, 0x00, 200}, { {629,   0, 672,  34}, 0x04, 66},
217   }, },
218   { {0, 0, 672, 34}, 34, 1, {34, }, 3, {
219     { {  0,   0, 413,  34}, 0x00, 200}, { {415,   0, 615,  34}, 0x00, 200},
220     { {617,   0, 672,  34}, 0x04, 66},
221   }, },
222   { {0, 0, 672, 34}, 34, 1, {34, }, 2, {
223     { {  0,   0, 604,  34}, 0x00, 200}, { {606,   0, 672,  34}, 0x04, 66},
224   }, },
225   { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
226     { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 184,  20}, 0x00, 70},
227     { {184,   0, 424,  20}, 0x00, 240}, { {424,   0, 672,  20}, 0x00, 60},
228     { {  0,  20, 672,  40}, 0x00, 200},
229   }, },
230   { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
231     { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 227,  20}, 0x00, 113},
232     { {227,   0, 424,  20}, 0x00, 197}, { {424,   0, 672,  20}, 0x00, 60},
233     { {  0,  20, 672,  40}, 0x00, 200},
234   }, },
235   { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
236     { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 328,  20}, 0x00, 214},
237     { {328,   0, 511,  20}, 0x00, 183}, { {511,   0, 672,  20}, 0x00, 161},
238     { {  0,  20, 672,  40}, 0x00, 200},
239   }, },
240   { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
241     { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 167,  20}, 0x00, 53},
242     { {167,   0, 511,  20}, 0x00, 344}, { {511,   0, 672,  20}, 0x00, 161},
243     { {  0,  20, 672,  40}, 0x00, 200},
244   }, },
245   { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
246     { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 328,  20}, 0x00, 214},
247     { {328,   0, 511,  20}, 0x00, 183}, { {511,   0, 672,  20}, 0x00, 161},
248     { {  0,  20, 672,  40}, 0x00, 200},
249   }, },
250   { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
251     { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 328,  20}, 0x00, 214},
252     { {328,   0, 511,  20}, 0x00, 183}, { {511,   0, 672,  20}, 0x00, 161},
253     { {  0,  20, 672,  40}, 0x00, 200},
254   }, },
255   { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
256   }, },
257   { {0, 0, 672, 65}, 65, 1, {65, }, 3, {
258     { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 180,  65}, 0x40, 90},
259     { {180,   0, 672,  65}, 0x40, 90},
260   }, },
261   { {0, 0, 0, 226}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
262   }, },
263   { {0, 0, 65, 226}, 65, 1, {65, }, 1, {
264     { {  0,   0, 226,  65}, 0x40, 90},
265   }, },
266   { {0, 0, 65, 226}, 65, 1, {65, }, 2, {
267     { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 226,  65}, 0x40, 90},
268   }, },
269   { {0, 0, 65, 226}, 65, 1, {65, }, 3, {
270     { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 163,  65}, 0x40, 90},
271     { {163,   0, 226,  65}, 0x40, 90},
272   }, },
273 };
274
275 static int rbsize_numtests = 0;
276
277 #define check_sizes_todo(todomask) { \
278         RECT rc; \
279         REBARBANDINFO rbi; \
280         int count, i/*, mask=(todomask)*/; \
281         rbsize_result_t *res = &rbsize_results[rbsize_numtests]; \
282         assert(rbsize_numtests < sizeof(rbsize_results)/sizeof(rbsize_results[0])); \
283         GetClientRect(hRebar, &rc); \
284         check_rect("client", rc, res->rcClient); \
285         count = SendMessage(hRebar, RB_GETROWCOUNT, 0, 0); \
286         compare(count, res->nRows, "%d"); \
287         for (i=0; i<min(count, res->nRows); i++) { \
288             int height = SendMessageA(hRebar, RB_GETROWHEIGHT, 0, 0);\
289             ok(height == res->cyRowHeights[i], "Height mismatch for row %d - %d vs %d\n", i, res->cyRowHeights[i], height); \
290         } \
291         count = SendMessage(hRebar, RB_GETBANDCOUNT, 0, 0); \
292         compare(count, res->nBands, "%d"); \
293         for (i=0; i<min(count, res->nBands); i++) { \
294             ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_ITEMRECT\n"); \
295             if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \
296                 check_rect("band", rc, res->bands[i].rc); \
297             rbi.cbSize = sizeof(REBARBANDINFO); \
298             rbi.fMask = RBBIM_STYLE | RBBIM_SIZE; \
299             ok(SendMessageA(hRebar, RB_GETBANDINFO,  i, (LPARAM)&rbi) == 1, "RB_GETBANDINFO\n"); \
300             compare(rbi.fStyle, res->bands[i].fStyle, "%x"); \
301             compare(rbi.cx, res->bands[i].cx, "%d"); \
302         } \
303         rbsize_numtests++; \
304     }
305
306 #define check_sizes() check_sizes_todo(0)
307
308 #endif
309
310 static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal)
311 {
312     CHAR buffer[MAX_PATH];
313     REBARBANDINFO rbi;
314
315     if (lpszText != NULL)
316         strcpy(buffer, lpszText);
317     rbi.cbSize = sizeof(rbi);
318     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT;
319     rbi.cx = cx;
320     rbi.cxMinChild = cxMinChild;
321     rbi.cxIdeal = cxIdeal;
322     rbi.cyMinChild = 20;
323     rbi.hwndChild = build_toolbar(1, hRebar);
324     rbi.lpText = (lpszText ? buffer : NULL);
325     SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
326 }
327
328 static void layout_test(void)
329 {
330     HWND hRebar = NULL;
331     REBARBANDINFO rbi;
332
333     rebuild_rebar(&hRebar);
334     check_sizes();
335     rbi.cbSize = sizeof(rbi);
336     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
337     rbi.cx = 200;
338     rbi.cxMinChild = 100;
339     rbi.cyMinChild = 30;
340     rbi.hwndChild = NULL;
341     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
342     check_sizes();
343
344     rbi.fMask |= RBBIM_STYLE;
345     rbi.fStyle = RBBS_CHILDEDGE;
346     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
347     check_sizes();
348
349     rbi.fStyle = 0;
350     rbi.cx = 200;
351     rbi.cxMinChild = 30;
352     rbi.cyMinChild = 30;
353     rbi.hwndChild = build_toolbar(0, hRebar);
354     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
355     check_sizes();
356
357     rbi.fStyle = RBBS_CHILDEDGE;
358     rbi.cx = 68;
359     rbi.hwndChild = build_toolbar(0, hRebar);
360     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
361     check_sizes();
362
363     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_BANDBORDERS);
364     check_sizes();      /* a style change won't start a relayout */
365     rbi.fMask = RBBIM_SIZE;
366     rbi.cx = 66;
367     SendMessageA(hRebar, RB_SETBANDINFO, 3, (LPARAM)&rbi);
368     check_sizes();      /* here it will be relayouted */
369
370     /* this will force a new row */
371     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
372     rbi.cx = 200;
373     rbi.cxMinChild = 400;
374     rbi.cyMinChild = 30;
375     rbi.hwndChild = build_toolbar(0, hRebar);
376     SendMessageA(hRebar, RB_INSERTBAND, 1, (LPARAM)&rbi);
377     check_sizes();
378
379     rbi.fMask = RBBIM_STYLE;
380     rbi.fStyle = RBBS_HIDDEN;
381     SendMessageA(hRebar, RB_SETBANDINFO, 2, (LPARAM)&rbi);
382     check_sizes();
383
384     SendMessageA(hRebar, RB_DELETEBAND, 2, 0);
385     check_sizes();
386     SendMessageA(hRebar, RB_DELETEBAND, 0, 0);
387     check_sizes();
388     SendMessageA(hRebar, RB_DELETEBAND, 1, 0);
389     check_sizes();
390
391     rebuild_rebar(&hRebar);
392     add_band_w(hRebar, "ABC",     70,  40, 100);
393     add_band_w(hRebar, NULL,      40,  70, 100);
394     add_band_w(hRebar, NULL,     170, 240, 100);
395     add_band_w(hRebar, "MMMMMMM", 60,  60, 100);
396     add_band_w(hRebar, NULL,     200, 200, 100);
397     check_sizes();
398     SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE);
399     check_sizes();
400     SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE);
401     check_sizes();
402     SendMessageA(hRebar, RB_MAXIMIZEBAND, 2, FALSE);
403     check_sizes();
404     SendMessageA(hRebar, RB_MINIMIZEBAND, 2, 0);
405     check_sizes();
406     SendMessageA(hRebar, RB_MINIMIZEBAND, 0, 0);
407     check_sizes();
408
409     /* VARHEIGHT resizing test on a horizontal rebar */
410     rebuild_rebar(&hRebar);
411     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
412     check_sizes();
413     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
414     rbi.fStyle = RBBS_VARIABLEHEIGHT;
415     rbi.cxMinChild = 50;
416     rbi.cyMinChild = 10;
417     rbi.cyIntegral = 11;
418     rbi.cyChild = 70;
419     rbi.cyMaxChild = 200;
420     rbi.cx = 90;
421     rbi.hwndChild = build_toolbar(0, hRebar);
422     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
423
424     rbi.cyChild = 50;
425     rbi.hwndChild = build_toolbar(0, hRebar);
426     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
427
428     rbi.cyMinChild = 40;
429     rbi.cyChild = 50;
430     rbi.cyIntegral = 5;
431     rbi.hwndChild = build_toolbar(0, hRebar);
432     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
433     check_sizes();
434
435     /* VARHEIGHT resizing on a vertical rebar */
436     rebuild_rebar(&hRebar);
437     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE);
438     check_sizes();
439     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
440     rbi.fStyle = RBBS_VARIABLEHEIGHT;
441     rbi.cxMinChild = 50;
442     rbi.cyMinChild = 10;
443     rbi.cyIntegral = 11;
444     rbi.cyChild = 70;
445     rbi.cyMaxChild = 90;
446     rbi.cx = 90;
447     rbi.hwndChild = build_toolbar(0, hRebar);
448     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
449     check_sizes();
450
451     rbi.cyChild = 50;
452     rbi.hwndChild = build_toolbar(0, hRebar);
453     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
454     check_sizes();
455
456     rbi.cyMinChild = 40;
457     rbi.cyChild = 50;
458     rbi.cyIntegral = 5;
459     rbi.hwndChild = build_toolbar(0, hRebar);
460     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
461     check_sizes();
462
463     DestroyWindow(hRebar);
464 }
465
466 #if 0       /* use this to generate more tests */
467
468 static void dump_client(HWND hRebar)
469 {
470     RECT r;
471     BOOL notify;
472     GetWindowRect(hRebar, &r);
473     MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
474     if (height_change_notify_rect.top != -1)
475     {
476         RECT rcClient;
477         GetClientRect(hRebar, &rcClient);
478         assert(EqualRect(&rcClient, &height_change_notify_rect));
479         notify = TRUE;
480     }
481     else
482         notify = FALSE;
483     printf("    {{%d, %d, %d, %d}, %d, %s},\n", r.left, r.top, r.right, r.bottom, SendMessage(hRebar, RB_GETROWCOUNT, 0, 0),
484         notify ? "TRUE" : "FALSE");
485     SetRect(&height_change_notify_rect, -1, -1, -1, -1);
486 }
487
488 #define comment(fmt, arg1) printf("/* " fmt " */\n", arg1);
489 #define check_client() dump_client(hRebar)
490
491 #else
492
493 typedef struct {
494     RECT rc;
495     INT iNumRows;
496     BOOL heightNotify;
497 } rbresize_test_result_t;
498
499 rbresize_test_result_t resize_results[] = {
500 /* style 00000001 */
501     {{0, 2, 672, 2}, 0, FALSE},
502     {{0, 2, 672, 22}, 1, TRUE},
503     {{0, 2, 672, 22}, 1, FALSE},
504     {{0, 2, 672, 22}, 1, FALSE},
505     {{0, 2, 672, 22}, 1, FALSE},
506     {{0, 2, 672, 22}, 0, FALSE},
507 /* style 00000041 */
508     {{0, 0, 672, 0}, 0, FALSE},
509     {{0, 0, 672, 20}, 1, TRUE},
510     {{0, 0, 672, 20}, 1, FALSE},
511     {{0, 0, 672, 20}, 1, FALSE},
512     {{0, 0, 672, 20}, 1, FALSE},
513     {{0, 0, 672, 20}, 0, FALSE},
514 /* style 00000003 */
515     {{0, 226, 672, 226}, 0, FALSE},
516     {{0, 206, 672, 226}, 1, TRUE},
517     {{0, 206, 672, 226}, 1, FALSE},
518     {{0, 206, 672, 226}, 1, FALSE},
519     {{0, 206, 672, 226}, 1, FALSE},
520     {{0, 206, 672, 226}, 0, FALSE},
521 /* style 00000043 */
522     {{0, 226, 672, 226}, 0, FALSE},
523     {{0, 206, 672, 226}, 1, TRUE},
524     {{0, 206, 672, 226}, 1, FALSE},
525     {{0, 206, 672, 226}, 1, FALSE},
526     {{0, 206, 672, 226}, 1, FALSE},
527     {{0, 206, 672, 226}, 0, FALSE},
528 /* style 00000080 */
529     {{2, 0, 2, 226}, 0, FALSE},
530     {{2, 0, 22, 226}, 1, TRUE},
531     {{2, 0, 22, 226}, 1, FALSE},
532     {{2, 0, 22, 226}, 1, FALSE},
533     {{2, 0, 22, 226}, 1, FALSE},
534     {{2, 0, 22, 226}, 0, FALSE},
535 /* style 00000083 */
536     {{672, 0, 672, 226}, 0, FALSE},
537     {{652, 0, 672, 226}, 1, TRUE},
538     {{652, 0, 672, 226}, 1, FALSE},
539     {{652, 0, 672, 226}, 1, FALSE},
540     {{652, 0, 672, 226}, 1, FALSE},
541     {{652, 0, 672, 226}, 0, FALSE},
542 /* style 00000008 */
543     {{10, 11, 510, 11}, 0, FALSE},
544     {{10, 15, 510, 35}, 1, TRUE},
545     {{10, 17, 510, 37}, 1, FALSE},
546     {{10, 14, 110, 54}, 2, TRUE},
547     {{0, 4, 0, 44}, 2, FALSE},
548     {{0, 6, 0, 46}, 2, FALSE},
549     {{0, 8, 0, 48}, 2, FALSE},
550     {{0, 12, 0, 32}, 1, TRUE},
551     {{0, 4, 100, 24}, 0, FALSE},
552 /* style 00000048 */
553     {{10, 5, 510, 5}, 0, FALSE},
554     {{10, 5, 510, 25}, 1, TRUE},
555     {{10, 5, 510, 25}, 1, FALSE},
556     {{10, 10, 110, 50}, 2, TRUE},
557     {{0, 0, 0, 40}, 2, FALSE},
558     {{0, 0, 0, 40}, 2, FALSE},
559     {{0, 0, 0, 40}, 2, FALSE},
560     {{0, 0, 0, 20}, 1, TRUE},
561     {{0, 0, 100, 20}, 0, FALSE},
562 /* style 00000004 */
563     {{10, 5, 510, 20}, 0, FALSE},
564     {{10, 5, 510, 20}, 1, TRUE},
565     {{10, 10, 110, 110}, 2, TRUE},
566     {{0, 0, 0, 0}, 2, FALSE},
567     {{0, 0, 0, 0}, 2, FALSE},
568     {{0, 0, 0, 0}, 2, FALSE},
569     {{0, 0, 0, 0}, 1, TRUE},
570     {{0, 0, 100, 100}, 0, FALSE},
571 /* style 00000002 */
572     {{0, 5, 672, 5}, 0, FALSE},
573     {{0, 5, 672, 25}, 1, TRUE},
574     {{0, 10, 672, 30}, 1, FALSE},
575     {{0, 0, 672, 20}, 1, FALSE},
576     {{0, 0, 672, 20}, 1, FALSE},
577     {{0, 0, 672, 20}, 0, FALSE},
578 /* style 00000082 */
579     {{10, 0, 10, 226}, 0, FALSE},
580     {{10, 0, 30, 226}, 1, TRUE},
581     {{10, 0, 30, 226}, 1, FALSE},
582     {{0, 0, 20, 226}, 1, FALSE},
583     {{0, 0, 20, 226}, 1, FALSE},
584     {{0, 0, 20, 226}, 0, FALSE},
585 /* style 00800001 */
586     {{-2, 0, 674, 4}, 0, FALSE},
587     {{-2, 0, 674, 24}, 1, TRUE},
588     {{-2, 0, 674, 24}, 1, FALSE},
589     {{-2, 0, 674, 24}, 1, FALSE},
590     {{-2, 0, 674, 24}, 1, FALSE},
591     {{-2, 0, 674, 24}, 0, FALSE},
592 /* style 00800048 */
593     {{10, 5, 510, 9}, 0, FALSE},
594     {{10, 5, 510, 29}, 1, TRUE},
595     {{10, 5, 510, 29}, 1, FALSE},
596     {{10, 10, 110, 54}, 2, TRUE},
597     {{0, 0, 0, 44}, 2, FALSE},
598     {{0, 0, 0, 44}, 2, FALSE},
599     {{0, 0, 0, 44}, 2, FALSE},
600     {{0, 0, 0, 24}, 1, TRUE},
601     {{0, 0, 100, 24}, 0, FALSE},
602 /* style 00800004 */
603     {{10, 5, 510, 20}, 0, FALSE},
604     {{10, 5, 510, 20}, 1, TRUE},
605     {{10, 10, 110, 110}, 2, TRUE},
606     {{0, 0, 0, 0}, 2, FALSE},
607     {{0, 0, 0, 0}, 2, FALSE},
608     {{0, 0, 0, 0}, 2, FALSE},
609     {{0, 0, 0, 0}, 1, TRUE},
610     {{0, 0, 100, 100}, 0, FALSE},
611 /* style 00800002 */
612     {{-2, 5, 674, 9}, 0, FALSE},
613     {{-2, 5, 674, 29}, 1, TRUE},
614     {{-2, 10, 674, 34}, 1, FALSE},
615     {{-2, 0, 674, 24}, 1, FALSE},
616     {{-2, 0, 674, 24}, 1, FALSE},
617     {{-2, 0, 674, 24}, 0, FALSE},
618 };
619
620 static int resize_numtests = 0;
621
622 #define comment(fmt, arg1)
623 #define check_client() { \
624         RECT r; \
625         rbresize_test_result_t *res = &resize_results[resize_numtests++]; \
626         assert(resize_numtests <= sizeof(resize_results)/sizeof(resize_results[0])); \
627         GetWindowRect(hRebar, &r); \
628         MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); \
629         if ((dwStyles[i] & (CCS_NOPARENTALIGN|CCS_NODIVIDER)) == CCS_NOPARENTALIGN) {\
630             check_rect_no_top("client", r, res->rc); /* the top coordinate changes after every layout and is very implementation-dependent */ \
631         } else { \
632             check_rect("client", r, res->rc); \
633         } \
634         expect_eq((int)SendMessage(hRebar, RB_GETROWCOUNT, 0, 0), res->iNumRows, int, "%d"); \
635         if (res->heightNotify) { \
636             RECT rcClient; \
637             GetClientRect(hRebar, &rcClient); \
638             check_rect("notify", height_change_notify_rect, rcClient); \
639         } else ok(height_change_notify_rect.top == -1, "Unexpected RBN_HEIGHTCHANGE received\n"); \
640         SetRect(&height_change_notify_rect, -1, -1, -1, -1); \
641     }
642
643 #endif
644
645 static void resize_test(void)
646 {
647     DWORD dwStyles[] = {CCS_TOP, CCS_TOP | CCS_NODIVIDER, CCS_BOTTOM, CCS_BOTTOM | CCS_NODIVIDER, CCS_VERT, CCS_RIGHT,
648         CCS_NOPARENTALIGN, CCS_NOPARENTALIGN | CCS_NODIVIDER, CCS_NORESIZE, CCS_NOMOVEY, CCS_NOMOVEY | CCS_VERT,
649         CCS_TOP | WS_BORDER, CCS_NOPARENTALIGN | CCS_NODIVIDER | WS_BORDER, CCS_NORESIZE | WS_BORDER,
650         CCS_NOMOVEY | WS_BORDER};
651
652     const int styles_count = sizeof(dwStyles) / sizeof(dwStyles[0]);
653     int i;
654
655     for (i = 0; i < styles_count; i++)
656     {
657         comment("style %08x", dwStyles[i]);
658         SetRect(&height_change_notify_rect, -1, -1, -1, -1);
659         hRebar = CreateWindow(REBARCLASSNAME, "A", dwStyles[i] | WS_CHILD | WS_VISIBLE, 10, 5, 500, 15, hMainWnd, NULL, GetModuleHandle(NULL), 0);
660         check_client();
661         add_band_w(hRebar, NULL, 70, 100, 0);
662         if (dwStyles[i] & CCS_NOPARENTALIGN)  /* the window drifts downward for CCS_NOPARENTALIGN without CCS_NODIVIDER */
663             check_client();
664         add_band_w(hRebar, NULL, 70, 100, 0);
665         check_client();
666         MoveWindow(hRebar, 10, 10, 100, 100, TRUE);
667         check_client();
668         MoveWindow(hRebar, 0, 0, 0, 0, TRUE);
669         check_client();
670         /* try to fool the rebar by sending invalid width/height - won't work */
671         if (dwStyles[i] & (CCS_NORESIZE | CCS_NOPARENTALIGN))
672         {
673             WINDOWPOS pos;
674             pos.hwnd = hRebar;
675             pos.hwndInsertAfter = NULL;
676             pos.cx = 500;
677             pos.cy = 500;
678             pos.x = 10;
679             pos.y = 10;
680             pos.flags = 0;
681             SendMessage(hRebar, WM_WINDOWPOSCHANGING, 0, (LPARAM)&pos);
682             SendMessage(hRebar, WM_WINDOWPOSCHANGED, 0, (LPARAM)&pos);
683             check_client();
684             SendMessage(hRebar, WM_SIZE, SIZE_RESTORED, MAKELONG(500, 500));
685             check_client();
686         }
687         SendMessage(hRebar, RB_DELETEBAND, 0, 0);
688         check_client();
689         SendMessage(hRebar, RB_DELETEBAND, 0, 0);
690         MoveWindow(hRebar, 0, 0, 100, 100, TRUE);
691         check_client();
692         DestroyWindow(hRebar);
693     }
694 }
695
696 static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore,
697     COLORREF clrBack, LPCSTR lpText, int iImage, HWND hwndChild,
698     INT cxMinChild, INT cyMinChild, INT cx, HBITMAP hbmBack, INT wID,
699     INT cyChild, INT cyMaxChild, INT cyIntegral, INT cxIdeal, LPARAM lParam,
700     INT cxHeader)
701 {
702     CHAR buf[MAX_PATH] = "abc";
703     REBARBANDINFO rb;
704
705     memset(&rb, 0xdd, sizeof(rb));
706     rb.cbSize = sizeof(rb);
707     rb.fMask = RBBIM_BACKGROUND | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_COLORS
708         | RBBIM_HEADERSIZE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_IMAGE | RBBIM_LPARAM
709         | RBBIM_SIZE | RBBIM_STYLE | RBBIM_TEXT;
710     rb.lpText = buf;
711     rb.cch = MAX_PATH;
712     ok(SendMessageA(hRebar, RB_GETBANDINFOA, uBand, (LPARAM)&rb), "RB_GETBANDINFO failed\n");
713     expect_eq(rb.fStyle, fStyle, int, "%x");
714     todo_wine expect_eq(rb.clrFore, clrFore, COLORREF, "%x");
715     todo_wine expect_eq(rb.clrBack, clrBack, unsigned, "%x");
716     expect_eq(strcmp(rb.lpText, lpText), 0, int, "%d");
717     expect_eq(rb.iImage, iImage, int, "%x");
718     expect_eq(rb.hwndChild, hwndChild, HWND, "%p");
719     expect_eq(rb.cxMinChild, cxMinChild, int, "%d");
720     expect_eq(rb.cyMinChild, cyMinChild, int, "%d");
721     expect_eq(rb.cx, cx, int, "%d");
722     expect_eq(rb.hbmBack, hbmBack, HBITMAP, "%p");
723     expect_eq(rb.wID, wID, int, "%d");
724     /* the values of cyChild, cyMaxChild and cyIntegral can't be read unless the band is RBBS_VARIABLEHEIGHT */
725     expect_eq(rb.cyChild, cyChild, int, "%x");
726     expect_eq(rb.cyMaxChild, cyMaxChild, int, "%x");
727     expect_eq(rb.cyIntegral, cyIntegral, int, "%x");
728     expect_eq(rb.cxIdeal, cxIdeal, int, "%d");
729     expect_eq(rb.lParam, lParam, LPARAM, "%ld");
730     expect_eq(rb.cxHeader, cxHeader, int, "%d");
731 }
732
733 static void bandinfo_test(void)
734 {
735     REBARBANDINFOA rb;
736     CHAR szABC[] = "ABC";
737     CHAR szABCD[] = "ABCD";
738
739     rebuild_rebar(&hRebar);
740     rb.cbSize = sizeof(REBARBANDINFO);
741     rb.fMask = 0;
742     ok(SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
743     expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0);
744
745     rb.fMask = RBBIM_CHILDSIZE;
746     rb.cxMinChild = 15;
747     rb.cyMinChild = 20;
748     rb.cyChild = 30;
749     rb.cyMaxChild = 20;
750     rb.cyIntegral = 10;
751     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
752     expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0);
753
754     rb.fMask = RBBIM_TEXT;
755     rb.lpText = szABC;
756     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
757     expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 35);
758
759     rb.cbSize = sizeof(REBARBANDINFO);
760     rb.fMask = 0;
761     ok(SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rb), "RB_INSERTBAND failed\n");
762     expect_band_content(1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9);
763     expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 40);
764
765     rb.fMask = RBBIM_HEADERSIZE;
766     rb.cxHeader = 50;
767     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
768     expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50);
769
770     rb.cxHeader = 5;
771     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
772     expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5);
773
774     rb.fMask = RBBIM_TEXT;
775     rb.lpText = szABCD;
776     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
777     expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5);
778     rb.fMask = RBBIM_STYLE | RBBIM_TEXT;
779     rb.fStyle = RBBS_VARIABLEHEIGHT;
780     rb.lpText = szABC;
781     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
782     expect_band_content(0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 40);
783
784     DestroyWindow(hRebar);
785 }
786
787 START_TEST(rebar)
788 {
789     HMODULE hComctl32;
790     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
791     INITCOMMONCONTROLSEX iccex;
792     WNDCLASSA wc;
793     MSG msg;
794     RECT rc;
795
796     hComctl32 = GetModuleHandleA("comctl32.dll");
797     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
798     if (!pInitCommonControlsEx)
799     {
800         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
801         return;
802     }
803     iccex.dwSize = sizeof(iccex);
804     iccex.dwICC = ICC_COOL_CLASSES;
805     pInitCommonControlsEx(&iccex);
806
807     wc.style = CS_HREDRAW | CS_VREDRAW;
808     wc.cbClsExtra = 0;
809     wc.cbWndExtra = 0;
810     wc.hInstance = GetModuleHandleA(NULL);
811     wc.hIcon = NULL;
812     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
813     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
814     wc.lpszMenuName = NULL;
815     wc.lpszClassName = "MyTestWnd";
816     wc.lpfnWndProc = MyWndProc;
817     RegisterClassA(&wc);
818     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
819       CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
820       226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
821       NULL, NULL, GetModuleHandleA(NULL), 0);
822     GetClientRect(hMainWnd, &rc);
823     ShowWindow(hMainWnd, SW_SHOW);
824
825     bandinfo_test();
826
827     if(is_font_installed("System") && is_font_installed("Tahoma"))
828     {
829         layout_test();
830         resize_test();
831     } else
832         skip("Missing System or Tahoma font\n");
833
834     PostQuitMessage(0);
835     while(GetMessageA(&msg,0,0,0)) {
836         TranslateMessage(&msg);
837         DispatchMessageA(&msg);
838     }
839     DestroyWindow(hMainWnd);
840 }