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