source: trunk/src/comctl32/progress.c

Last change on this file was 10098, checked in by sandervl, 22 years ago

Wine resync

File size: 13.4 KB
Line 
1/*
2 * Progress control
3 *
4 * Copyright 1997, 2002 Dimitrie O. Paun
5 * Copyright 1998, 1999 Eric Kohl
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * NOTE
22 *
23 * This code was audited for completeness against the documented features
24 * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun.
25 *
26 * Unless otherwise noted, we belive this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features, or bugs, please note them below.
29 *
30 * TODO
31 * --support PBS_MARQUE
32 *
33 */
34
35#include <string.h>
36#include "winbase.h"
37#include "commctrl.h"
38#include "wine/debug.h"
39
40WINE_DEFAULT_DEBUG_CHANNEL(progress);
41
42typedef struct
43{
44 HWND Self; /* The window handle for this control */
45 INT CurVal; /* Current progress value */
46 INT MinVal; /* Minimum progress value */
47 INT MaxVal; /* Maximum progress value */
48 INT Step; /* Step to use on PMB_STEPIT */
49 COLORREF ColorBar; /* Bar color */
50 COLORREF ColorBk; /* Background color */
51 HFONT Font; /* Handle to font (not unused) */
52} PROGRESS_INFO;
53
54/* Control configuration constants */
55
56#define LED_GAP 2
57
58/***********************************************************************
59 * PROGRESS_Invalidate
60 *
61 * Invalide the range between old and new pos.
62 */
63static void PROGRESS_Invalidate( PROGRESS_INFO *infoPtr, INT old, INT new )
64{
65 LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE);
66 RECT rect;
67 int oldPos, newPos, ledWidth;
68
69 GetClientRect (infoPtr->Self, &rect);
70 InflateRect(&rect, -1, -1);
71
72 if (style & PBS_VERTICAL)
73 {
74 oldPos = rect.bottom - MulDiv (old - infoPtr->MinVal, rect.bottom - rect.top,
75 infoPtr->MaxVal - infoPtr->MinVal);
76 newPos = rect.bottom - MulDiv (new - infoPtr->MinVal, rect.bottom - rect.top,
77 infoPtr->MaxVal - infoPtr->MinVal);
78 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
79 rect.top = min( oldPos, newPos );
80 rect.bottom = max( oldPos, newPos );
81 if (!(style & PBS_SMOOTH)) rect.top -= ledWidth;
82 InvalidateRect( infoPtr->Self, &rect, oldPos < newPos );
83 }
84 else
85 {
86 oldPos = rect.left + MulDiv (old - infoPtr->MinVal, rect.right - rect.left,
87 infoPtr->MaxVal - infoPtr->MinVal);
88 newPos = rect.left + MulDiv (new - infoPtr->MinVal, rect.right - rect.left,
89 infoPtr->MaxVal - infoPtr->MinVal);
90 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
91 rect.left = min( oldPos, newPos );
92 rect.right = max( oldPos, newPos );
93 if (!(style & PBS_SMOOTH)) rect.right += ledWidth;
94 InvalidateRect( infoPtr->Self, &rect, oldPos > newPos );
95 }
96}
97
98
99/***********************************************************************
100 * PROGRESS_Draw
101 * Draws the progress bar.
102 */
103static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
104{
105 HBRUSH hbrBar, hbrBk;
106 int rightBar, rightMost, ledWidth;
107 RECT rect;
108 DWORD dwStyle;
109
110 TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr, hdc);
111
112 /* get the required bar brush */
113 if (infoPtr->ColorBar == CLR_DEFAULT)
114 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
115 else
116 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
117
118 if (infoPtr->ColorBk == CLR_DEFAULT)
119 hbrBk = GetSysColorBrush(COLOR_3DFACE);
120 else
121 hbrBk = CreateSolidBrush(infoPtr->ColorBk);
122
123 /* get client rectangle */
124 GetClientRect (infoPtr->Self, &rect);
125 FrameRect( hdc, &rect, hbrBk );
126 InflateRect(&rect, -1, -1);
127
128 /* get the window style */
129 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
130
131 /* compute extent of progress bar */
132 if (dwStyle & PBS_VERTICAL) {
133 rightBar = rect.bottom -
134 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
135 rect.bottom - rect.top,
136 infoPtr->MaxVal - infoPtr->MinVal);
137 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
138 rightMost = rect.top;
139 } else {
140 rightBar = rect.left +
141 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
142 rect.right - rect.left,
143 infoPtr->MaxVal - infoPtr->MinVal);
144 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
145 rightMost = rect.right;
146 }
147
148 /* now draw the bar */
149 if (dwStyle & PBS_SMOOTH)
150 {
151 if (dwStyle & PBS_VERTICAL)
152 {
153 INT old_top = rect.top;
154 rect.top = rightBar;
155 FillRect(hdc, &rect, hbrBar);
156 rect.bottom = rect.top;
157 rect.top = old_top;
158 FillRect(hdc, &rect, hbrBk);
159 }
160 else
161 {
162 INT old_right = rect.right;
163 rect.right = rightBar;
164 FillRect(hdc, &rect, hbrBar);
165 rect.left = rect.right;
166 rect.right = old_right;
167 FillRect(hdc, &rect, hbrBk);
168 }
169 } else {
170 if (dwStyle & PBS_VERTICAL) {
171 while(rect.bottom > rightBar) {
172 rect.top = rect.bottom - ledWidth;
173 if (rect.top < rightMost)
174 rect.top = rightMost;
175 FillRect(hdc, &rect, hbrBar);
176 rect.bottom = rect.top;
177 rect.top -= LED_GAP;
178 if (rect.top <= rightBar) break;
179 FillRect(hdc, &rect, hbrBk);
180 rect.bottom = rect.top;
181 }
182 rect.top = rightMost;
183 FillRect(hdc, &rect, hbrBk);
184 } else {
185 while(rect.left < rightBar) {
186 rect.right = rect.left + ledWidth;
187 if (rect.right > rightMost)
188 rect.right = rightMost;
189 FillRect(hdc, &rect, hbrBar);
190 rect.left = rect.right;
191 rect.right += LED_GAP;
192 if (rect.right >= rightBar) break;
193 FillRect(hdc, &rect, hbrBk);
194 rect.left = rect.right;
195 }
196 rect.right = rightMost;
197 FillRect(hdc, &rect, hbrBk);
198 }
199 }
200
201 /* delete bar brush */
202 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar);
203 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk);
204
205 return 0;
206}
207
208
209/***********************************************************************
210 * PROGRESS_Paint
211 * Draw the progress bar. The background need not be erased.
212 * If dc!=0, it draws on it
213 */
214static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
215{
216 PAINTSTRUCT ps;
217 if (hdc) return PROGRESS_Draw (infoPtr, hdc);
218 hdc = BeginPaint (infoPtr->Self, &ps);
219 PROGRESS_Draw (infoPtr, hdc);
220 EndPaint (infoPtr->Self, &ps);
221 return 0;
222}
223
224
225/***********************************************************************
226 * PROGRESS_CoercePos
227 * Makes sure the current position (CurVal) is within bounds.
228 */
229static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
230{
231 if(infoPtr->CurVal < infoPtr->MinVal)
232 infoPtr->CurVal = infoPtr->MinVal;
233 if(infoPtr->CurVal > infoPtr->MaxVal)
234 infoPtr->CurVal = infoPtr->MaxVal;
235}
236
237
238/***********************************************************************
239 * PROGRESS_SetFont
240 * Set new Font for progress bar
241 */
242static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
243{
244 HFONT hOldFont = infoPtr->Font;
245 infoPtr->Font = hFont;
246 /* Since infoPtr->Font is not used, there is no need for repaint */
247 return hOldFont;
248}
249
250static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
251{
252 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
253
254 /* if nothing changes, simply return */
255 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
256
257 infoPtr->MinVal = low;
258 infoPtr->MaxVal = high;
259 PROGRESS_CoercePos(infoPtr);
260 InvalidateRect(infoPtr->Self, NULL, TRUE);
261 return res;
262}
263
264/***********************************************************************
265 * ProgressWindowProc
266 */
267static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
268 WPARAM wParam, LPARAM lParam)
269{
270 PROGRESS_INFO *infoPtr;
271
272 TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
273
274 infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
275
276 if (!infoPtr && message != WM_CREATE)
277 return DefWindowProcW( hwnd, message, wParam, lParam );
278
279 switch(message) {
280 case WM_CREATE:
281 {
282 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
283 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
284 dwExStyle |= WS_EX_STATICEDGE;
285 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
286 /* Force recalculation of a non-client area */
287 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
288 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
289
290 /* allocate memory for info struct */
291 infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
292 if (!infoPtr) return -1;
293 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
294
295 /* initialize the info struct */
296 infoPtr->Self = hwnd;
297 infoPtr->MinVal = 0;
298 infoPtr->MaxVal = 100;
299 infoPtr->CurVal = 0;
300 infoPtr->Step = 10;
301 infoPtr->ColorBar = CLR_DEFAULT;
302 infoPtr->ColorBk = CLR_DEFAULT;
303 infoPtr->Font = 0;
304 TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd);
305 return 0;
306 }
307
308 case WM_DESTROY:
309 TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd);
310 COMCTL32_Free (infoPtr);
311 SetWindowLongW(hwnd, 0, 0);
312 return 0;
313
314 case WM_GETFONT:
315 return (LRESULT)infoPtr->Font;
316
317 case WM_SETFONT:
318 return (LRESULT)PROGRESS_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
319
320 case WM_PAINT:
321 return PROGRESS_Paint (infoPtr, (HDC)wParam);
322
323 case PBM_DELTAPOS:
324 {
325 INT oldVal;
326 oldVal = infoPtr->CurVal;
327 if(wParam != 0) {
328 infoPtr->CurVal += (INT)wParam;
329 PROGRESS_CoercePos (infoPtr);
330 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
331 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
332 }
333 return oldVal;
334 }
335
336 case PBM_SETPOS:
337 {
338 UINT oldVal;
339 oldVal = infoPtr->CurVal;
340 if(oldVal != wParam) {
341 infoPtr->CurVal = (INT)wParam;
342 PROGRESS_CoercePos(infoPtr);
343 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
344 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
345 }
346 return oldVal;
347 }
348
349 case PBM_SETRANGE:
350 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
351
352 case PBM_SETSTEP:
353 {
354 INT oldStep;
355 oldStep = infoPtr->Step;
356 infoPtr->Step = (INT)wParam;
357 return oldStep;
358 }
359
360 case PBM_STEPIT:
361 {
362 INT oldVal;
363 oldVal = infoPtr->CurVal;
364 infoPtr->CurVal += infoPtr->Step;
365 if(infoPtr->CurVal > infoPtr->MaxVal)
366 infoPtr->CurVal = infoPtr->MinVal;
367 if(oldVal != infoPtr->CurVal)
368 {
369 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
370 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
371 }
372 return oldVal;
373 }
374
375 case PBM_SETRANGE32:
376 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
377
378 case PBM_GETRANGE:
379 if (lParam) {
380 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
381 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
382 }
383 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
384
385 case PBM_GETPOS:
386 return infoPtr->CurVal;
387
388 case PBM_SETBARCOLOR:
389 infoPtr->ColorBar = (COLORREF)lParam;
390 InvalidateRect(hwnd, NULL, TRUE);
391 return 0;
392
393 case PBM_SETBKCOLOR:
394 infoPtr->ColorBk = (COLORREF)lParam;
395 InvalidateRect(hwnd, NULL, TRUE);
396 return 0;
397
398 default:
399 if ((message >= WM_USER) && (message < WM_APP))
400 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
401 return DefWindowProcW( hwnd, message, wParam, lParam );
402 }
403}
404
405
406/***********************************************************************
407 * PROGRESS_Register [Internal]
408 *
409 * Registers the progress bar window class.
410 */
411VOID PROGRESS_Register (void)
412{
413 WNDCLASSW wndClass;
414
415 ZeroMemory (&wndClass, sizeof(wndClass));
416 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
417 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
418 wndClass.cbClsExtra = 0;
419 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
420 wndClass.hCursor = LoadCursorW (0, IDC_ARROWW);
421 wndClass.lpszClassName = PROGRESS_CLASSW;
422
423 RegisterClassW (&wndClass);
424}
425
426
427/***********************************************************************
428 * PROGRESS_Unregister [Internal]
429 *
430 * Unregisters the progress bar window class.
431 */
432VOID PROGRESS_Unregister (void)
433{
434 UnregisterClassW (PROGRESS_CLASSW, NULL);
435}
Note: See TracBrowser for help on using the repository browser.