source: trunk/src/comctl32/progress.c@ 9370

Last change on this file since 9370 was 9370, checked in by sandervl, 23 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 return res;
261}
262
263/***********************************************************************
264 * ProgressWindowProc
265 */
266static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
267 WPARAM wParam, LPARAM lParam)
268{
269 PROGRESS_INFO *infoPtr;
270
271 TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
272
273 infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
274
275 if (!infoPtr && message != WM_CREATE)
276 return DefWindowProcW( hwnd, message, wParam, lParam );
277
278 switch(message) {
279 case WM_CREATE:
280 {
281 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
282 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
283 dwExStyle |= WS_EX_STATICEDGE;
284 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
285 /* Force recalculation of a non-client area */
286 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
287 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
288
289 /* allocate memory for info struct */
290 infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
291 if (!infoPtr) return -1;
292 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
293
294 /* initialize the info struct */
295 infoPtr->Self = hwnd;
296 infoPtr->MinVal = 0;
297 infoPtr->MaxVal = 100;
298 infoPtr->CurVal = 0;
299 infoPtr->Step = 10;
300 infoPtr->ColorBar = CLR_DEFAULT;
301 infoPtr->ColorBk = CLR_DEFAULT;
302 infoPtr->Font = 0;
303 TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd);
304 return 0;
305 }
306
307 case WM_DESTROY:
308 TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd);
309 COMCTL32_Free (infoPtr);
310 SetWindowLongW(hwnd, 0, 0);
311 return 0;
312
313 case WM_GETFONT:
314 return (LRESULT)infoPtr->Font;
315
316 case WM_SETFONT:
317 return (LRESULT)PROGRESS_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
318
319 case WM_PAINT:
320 return PROGRESS_Paint (infoPtr, (HDC)wParam);
321
322 case PBM_DELTAPOS:
323 {
324 INT oldVal;
325 oldVal = infoPtr->CurVal;
326 if(wParam != 0) {
327 infoPtr->CurVal += (INT)wParam;
328 PROGRESS_CoercePos (infoPtr);
329 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
330 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
331 }
332 return oldVal;
333 }
334
335 case PBM_SETPOS:
336 {
337 INT oldVal;
338 oldVal = infoPtr->CurVal;
339 if(oldVal != wParam) {
340 infoPtr->CurVal = (INT)wParam;
341 PROGRESS_CoercePos(infoPtr);
342 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
343 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
344 }
345 return oldVal;
346 }
347
348 case PBM_SETRANGE:
349 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
350
351 case PBM_SETSTEP:
352 {
353 INT oldStep;
354 oldStep = infoPtr->Step;
355 infoPtr->Step = (INT)wParam;
356 return oldStep;
357 }
358
359 case PBM_STEPIT:
360 {
361 INT oldVal;
362 oldVal = infoPtr->CurVal;
363 infoPtr->CurVal += infoPtr->Step;
364 if(infoPtr->CurVal > infoPtr->MaxVal)
365 infoPtr->CurVal = infoPtr->MinVal;
366 if(oldVal != infoPtr->CurVal)
367 {
368 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
369 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
370 }
371 return oldVal;
372 }
373
374 case PBM_SETRANGE32:
375 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
376
377 case PBM_GETRANGE:
378 if (lParam) {
379 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
380 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
381 }
382 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
383
384 case PBM_GETPOS:
385 return infoPtr->CurVal;
386
387 case PBM_SETBARCOLOR:
388 infoPtr->ColorBar = (COLORREF)lParam;
389 InvalidateRect(hwnd, NULL, TRUE);
390 return 0;
391
392 case PBM_SETBKCOLOR:
393 infoPtr->ColorBk = (COLORREF)lParam;
394 InvalidateRect(hwnd, NULL, TRUE);
395 return 0;
396
397 default:
398 if ((message >= WM_USER) && (message < WM_APP))
399 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
400 return DefWindowProcW( hwnd, message, wParam, lParam );
401 }
402}
403
404
405/***********************************************************************
406 * PROGRESS_Register [Internal]
407 *
408 * Registers the progress bar window class.
409 */
410VOID PROGRESS_Register (void)
411{
412 WNDCLASSW wndClass;
413
414 ZeroMemory (&wndClass, sizeof(wndClass));
415 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
416 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
417 wndClass.cbClsExtra = 0;
418 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
419 wndClass.hCursor = LoadCursorW (0, IDC_ARROWW);
420 wndClass.lpszClassName = PROGRESS_CLASSW;
421
422 RegisterClassW (&wndClass);
423}
424
425
426/***********************************************************************
427 * PROGRESS_Unregister [Internal]
428 *
429 * Unregisters the progress bar window class.
430 */
431VOID PROGRESS_Unregister (void)
432{
433 UnregisterClassW (PROGRESS_CLASSW, (HINSTANCE)NULL);
434}
Note: See TracBrowser for help on using the repository browser.