497cb47d3c3514683e2741176aaf9c2f3e99a788
[reactos.git] / modules / rostests / winetests / comctl32 / progress.c
1 /* Unit tests for the progress bar control.
2 *
3 * Copyright 2005 Michael Kaufmann
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 <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winuser.h"
26 #include "commctrl.h"
27
28 #include "wine/test.h"
29
30 #include "v6util.h"
31
32 static HWND hProgressParentWnd;
33 static const char progressTestClass[] = "ProgressBarTestClass";
34 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
35
36 static HWND create_progress(DWORD style)
37 {
38 return CreateWindowExA(0, PROGRESS_CLASSA, "", WS_VISIBLE | style,
39 0, 0, 100, 20, NULL, NULL, GetModuleHandleA(NULL), 0);
40 }
41
42 /* try to make sure pending X events have been processed before continuing */
43 static void flush_events(void)
44 {
45 MSG msg;
46 int diff = 100;
47 DWORD time = GetTickCount() + diff;
48
49 while (diff > 0)
50 {
51 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(10,diff), QS_ALLINPUT ) == WAIT_TIMEOUT) break;
52 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
53 diff = time - GetTickCount();
54 }
55 }
56
57 static LRESULT CALLBACK progress_test_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
58 {
59 switch(msg) {
60
61 case WM_DESTROY:
62 PostQuitMessage(0);
63 break;
64
65 default:
66 return DefWindowProcA(hWnd, msg, wParam, lParam);
67 }
68
69 return 0L;
70 }
71
72 static WNDPROC progress_wndproc;
73 static BOOL erased;
74 static RECT last_paint_rect;
75
76 static LRESULT CALLBACK progress_subclass_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
77 {
78 if (msg == WM_PAINT)
79 {
80 GetUpdateRect(hWnd, &last_paint_rect, FALSE);
81 }
82 else if (msg == WM_ERASEBKGND)
83 {
84 erased = TRUE;
85 }
86 return CallWindowProcA(progress_wndproc, hWnd, msg, wParam, lParam);
87 }
88
89
90 static void update_window(HWND hWnd)
91 {
92 UpdateWindow(hWnd);
93 ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n");
94 }
95
96
97 static void init(void)
98 {
99 WNDCLASSA wc;
100 RECT rect;
101 BOOL ret;
102
103 wc.style = CS_HREDRAW | CS_VREDRAW;
104 wc.cbClsExtra = 0;
105 wc.cbWndExtra = 0;
106 wc.hInstance = GetModuleHandleA(NULL);
107 wc.hIcon = NULL;
108 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
109 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
110 wc.lpszMenuName = NULL;
111 wc.lpszClassName = progressTestClass;
112 wc.lpfnWndProc = progress_test_wnd_proc;
113 RegisterClassA(&wc);
114
115 SetRect(&rect, 0, 0, 400, 20);
116 ret = AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
117 ok(ret, "got %d\n", ret);
118
119 hProgressParentWnd = CreateWindowExA(0, progressTestClass, "Progress Bar Test", WS_OVERLAPPEDWINDOW,
120 CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0);
121 ok(hProgressParentWnd != NULL, "failed to create parent wnd\n");
122
123 }
124
125 static void cleanup(void)
126 {
127 MSG msg;
128
129 PostMessageA(hProgressParentWnd, WM_CLOSE, 0, 0);
130 while (GetMessageA(&msg,0,0,0)) {
131 TranslateMessage(&msg);
132 DispatchMessageA(&msg);
133 }
134
135 UnregisterClassA(progressTestClass, GetModuleHandleA(NULL));
136 }
137
138
139 /*
140 * Tests if a progress bar repaints itself immediately when it receives
141 * some specific messages.
142 */
143 static void test_redraw(void)
144 {
145 RECT client_rect, rect;
146 HWND hProgressWnd;
147 LRESULT ret;
148
149 GetClientRect(hProgressParentWnd, &rect);
150 hProgressWnd = CreateWindowExA(0, PROGRESS_CLASSA, "", WS_CHILD | WS_VISIBLE,
151 0, 0, rect.right, rect.bottom, hProgressParentWnd, NULL, GetModuleHandleA(NULL), 0);
152 ok(hProgressWnd != NULL, "Failed to create progress bar.\n");
153 progress_wndproc = (WNDPROC)SetWindowLongPtrA(hProgressWnd, GWLP_WNDPROC, (LPARAM)progress_subclass_proc);
154
155 ShowWindow(hProgressParentWnd, SW_SHOWNORMAL);
156 ok(GetUpdateRect(hProgressParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n");
157 flush_events();
158 update_window(hProgressParentWnd);
159
160 SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
161 SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
162 SendMessageA(hProgressWnd, PBM_SETSTEP, 20, 0);
163 update_window(hProgressWnd);
164
165 /* PBM_SETPOS */
166 ok(SendMessageA(hProgressWnd, PBM_SETPOS, 50, 0) == 10, "PBM_SETPOS must return the previous position\n");
167 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
168
169 /* PBM_DELTAPOS */
170 ok(SendMessageA(hProgressWnd, PBM_DELTAPOS, 15, 0) == 50, "PBM_DELTAPOS must return the previous position\n");
171 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_DELTAPOS: The progress bar should be redrawn immediately\n");
172
173 /* PBM_SETPOS */
174 ok(SendMessageA(hProgressWnd, PBM_SETPOS, 80, 0) == 65, "PBM_SETPOS must return the previous position\n");
175 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
176
177 /* PBM_STEPIT */
178 ok(SendMessageA(hProgressWnd, PBM_STEPIT, 0, 0) == 80, "PBM_STEPIT must return the previous position\n");
179 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_STEPIT: The progress bar should be redrawn immediately\n");
180 ret = SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0);
181 if (ret == 0)
182 win_skip("PBM_GETPOS needs comctl32 > 4.70\n");
183 else
184 ok(ret == 100, "PBM_GETPOS returned a wrong position : %d\n", (UINT)ret);
185
186 /* PBM_SETRANGE and PBM_SETRANGE32:
187 Usually the progress bar doesn't repaint itself immediately. If the
188 position is not in the new range, it does.
189 Don't test this, it may change in future Windows versions. */
190
191 SendMessageA(hProgressWnd, PBM_SETPOS, 0, 0);
192 update_window(hProgressWnd);
193
194 /* increase to 10 - no background erase required */
195 erased = FALSE;
196 SetRectEmpty(&last_paint_rect);
197 SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
198 GetClientRect(hProgressWnd, &client_rect);
199 ok(EqualRect(&last_paint_rect, &client_rect), "last_paint_rect was %s instead of %s\n",
200 wine_dbgstr_rect(&last_paint_rect), wine_dbgstr_rect(&client_rect));
201 update_window(hProgressWnd);
202 ok(!erased, "Progress bar shouldn't have erased the background\n");
203
204 /* decrease to 0 - background erase will be required */
205 erased = FALSE;
206 SetRectEmpty(&last_paint_rect);
207 SendMessageA(hProgressWnd, PBM_SETPOS, 0, 0);
208 GetClientRect(hProgressWnd, &client_rect);
209 ok(EqualRect(&last_paint_rect, &client_rect), "last_paint_rect was %s instead of %s\n",
210 wine_dbgstr_rect(&last_paint_rect), wine_dbgstr_rect(&client_rect));
211 update_window(hProgressWnd);
212 ok(erased, "Progress bar should have erased the background\n");
213
214 DestroyWindow(hProgressWnd);
215 }
216
217 static void test_setcolors(void)
218 {
219 HWND progress;
220 COLORREF clr;
221
222 progress = create_progress(PBS_SMOOTH);
223
224 clr = SendMessageA(progress, PBM_SETBARCOLOR, 0, 0);
225 ok(clr == CLR_DEFAULT, "got %x\n", clr);
226
227 clr = SendMessageA(progress, PBM_SETBARCOLOR, 0, RGB(0, 255, 0));
228 ok(clr == 0, "got %x\n", clr);
229
230 clr = SendMessageA(progress, PBM_SETBARCOLOR, 0, CLR_DEFAULT);
231 ok(clr == RGB(0, 255, 0), "got %x\n", clr);
232
233 clr = SendMessageA(progress, PBM_SETBKCOLOR, 0, 0);
234 ok(clr == CLR_DEFAULT, "got %x\n", clr);
235
236 clr = SendMessageA(progress, PBM_SETBKCOLOR, 0, RGB(255, 0, 0));
237 ok(clr == 0, "got %x\n", clr);
238
239 clr = SendMessageA(progress, PBM_SETBKCOLOR, 0, CLR_DEFAULT);
240 ok(clr == RGB(255, 0, 0), "got %x\n", clr);
241
242 DestroyWindow(progress);
243 }
244
245 static void test_PBM_STEPIT(void)
246 {
247 struct stepit_test
248 {
249 int min;
250 int max;
251 int step;
252 } stepit_tests[] =
253 {
254 { 3, 15, 5 },
255 { 3, 15, -5 },
256 { 3, 15, 50 },
257 };
258 HWND progress;
259 int i, j;
260
261 for (i = 0; i < ARRAY_SIZE(stepit_tests); i++)
262 {
263 struct stepit_test *test = &stepit_tests[i];
264 LRESULT ret;
265
266 progress = create_progress(0);
267
268 ret = SendMessageA(progress, PBM_SETRANGE32, test->min, test->max);
269 ok(ret != 0, "Unexpected return value.\n");
270
271 SendMessageA(progress, PBM_SETPOS, test->min, 0);
272 SendMessageA(progress, PBM_SETSTEP, test->step, 0);
273
274 for (j = 0; j < test->max; j++)
275 {
276 int pos = SendMessageA(progress, PBM_GETPOS, 0, 0);
277 int current;
278
279 pos += test->step;
280 if (pos > test->max)
281 pos = (pos - test->min) % (test->max - test->min) + test->min;
282 if (pos < test->min)
283 pos = (pos - test->min) % (test->max - test->min) + test->max;
284
285 SendMessageA(progress, PBM_STEPIT, 0, 0);
286
287 current = SendMessageA(progress, PBM_GETPOS, 0, 0);
288 ok(current == pos, "Unexpected position %d, expected %d.\n", current, pos);
289 }
290
291 DestroyWindow(progress);
292 }
293 }
294
295 static void init_functions(void)
296 {
297 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
298
299 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
300 X(InitCommonControlsEx);
301 #undef X
302 }
303
304 START_TEST(progress)
305 {
306 INITCOMMONCONTROLSEX iccex;
307 ULONG_PTR ctx_cookie;
308 HANDLE hCtx;
309
310 init_functions();
311
312 iccex.dwSize = sizeof(iccex);
313 iccex.dwICC = ICC_PROGRESS_CLASS;
314 pInitCommonControlsEx(&iccex);
315
316 init();
317
318 test_redraw();
319 test_setcolors();
320 test_PBM_STEPIT();
321
322 if (!load_v6_module(&ctx_cookie, &hCtx))
323 return;
324
325 test_setcolors();
326 test_PBM_STEPIT();
327
328 unload_v6_module(ctx_cookie, hCtx);
329
330 cleanup();
331 }