4 * Copyright 1997, 2002 Dimitrie O. Paun
5 * Copyright 1998, 1999 Eric Kohl
12 #include "debugtools.h"
14 DEFAULT_DEBUG_CHANNEL(progress
);
18 HWND Self
; /* The window handle for this control */
19 INT CurVal
; /* Current progress value */
20 INT MinVal
; /* Minimum progress value */
21 INT MaxVal
; /* Maximum progress value */
22 INT Step
; /* Step to use on PMB_STEPIT */
23 COLORREF ColorBar
; /* Bar color */
24 COLORREF ColorBk
; /* Background color */
25 HFONT Font
; /* Handle to font (not unused) */
28 /* Control configuration constants */
32 #define UNKNOWN_PARAM(msg, wParam, lParam) WARN( \
33 "Unknown parameter(s) for message " #msg \
34 "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam);
36 /***********************************************************************
38 * Draws the progress bar.
40 static LRESULT
PROGRESS_Draw (PROGRESS_INFO
*infoPtr
, HDC hdc
)
43 int rightBar
, rightMost
, ledWidth
;
47 TRACE("(infoPtr=%p, hdc=%x)\n", infoPtr
, hdc
);
49 /* get the required bar brush */
50 if (infoPtr
->ColorBar
== CLR_DEFAULT
)
51 hbrBar
= GetSysColorBrush(COLOR_HIGHLIGHT
);
53 hbrBar
= CreateSolidBrush (infoPtr
->ColorBar
);
55 /* get the required background brush */
56 if (infoPtr
->ColorBk
== CLR_DEFAULT
)
57 hbrBk
= GetSysColorBrush (COLOR_3DFACE
);
59 hbrBk
= CreateSolidBrush (infoPtr
->ColorBk
);
61 /* get client rectangle */
62 GetClientRect (infoPtr
->Self
, &rect
);
64 /* draw the background */
65 FillRect(hdc
, &rect
, hbrBk
);
67 InflateRect(&rect
, -1, -1);
69 /* get the window style */
70 dwStyle
= GetWindowLongW (infoPtr
->Self
, GWL_STYLE
);
72 /* compute extent of progress bar */
73 if (dwStyle
& PBS_VERTICAL
) {
74 rightBar
= rect
.bottom
-
75 MulDiv (infoPtr
->CurVal
- infoPtr
->MinVal
,
76 rect
.bottom
- rect
.top
,
77 infoPtr
->MaxVal
- infoPtr
->MinVal
);
78 ledWidth
= MulDiv (rect
.right
- rect
.left
, 2, 3);
81 rightBar
= rect
.left
+
82 MulDiv (infoPtr
->CurVal
- infoPtr
->MinVal
,
83 rect
.right
- rect
.left
,
84 infoPtr
->MaxVal
- infoPtr
->MinVal
);
85 ledWidth
= MulDiv (rect
.bottom
- rect
.top
, 2, 3);
86 rightMost
= rect
.right
;
89 /* now draw the bar */
90 if (dwStyle
& PBS_SMOOTH
) {
91 if (dwStyle
& PBS_VERTICAL
)
94 rect
.right
= rightBar
;
95 FillRect(hdc
, &rect
, hbrBar
);
97 if (dwStyle
& PBS_VERTICAL
) {
98 while(rect
.bottom
> rightBar
) {
99 rect
.top
= rect
.bottom
- ledWidth
;
100 if (rect
.top
< rightMost
)
101 rect
.top
= rightMost
;
102 FillRect(hdc
, &rect
, hbrBar
);
103 rect
.bottom
= rect
.top
- LED_GAP
;
106 while(rect
.left
< rightBar
) {
107 rect
.right
= rect
.left
+ ledWidth
;
108 if (rect
.right
> rightMost
)
109 rect
.right
= rightMost
;
110 FillRect(hdc
, &rect
, hbrBar
);
111 rect
.left
= rect
.right
+ LED_GAP
;
116 /* delete bar brush */
117 if (infoPtr
->ColorBar
!= CLR_DEFAULT
)
118 DeleteObject (hbrBar
);
120 /* delete background brush */
121 if (infoPtr
->ColorBk
!= CLR_DEFAULT
)
122 DeleteObject (hbrBk
);
127 /***********************************************************************
129 * Draw the progress bar. The background need not be erased.
131 static LRESULT
PROGRESS_Refresh (PROGRESS_INFO
*infoPtr
)
133 HDC hdc
= GetDC (infoPtr
->Self
);
134 LRESULT res
= PROGRESS_Draw (infoPtr
, hdc
);
135 ReleaseDC (infoPtr
->Self
, hdc
);
139 /***********************************************************************
141 * Draw the progress bar. The background need not be erased.
142 * If dc!=0, it draws on it
144 static LRESULT
PROGRESS_Paint (PROGRESS_INFO
*infoPtr
, HDC hdc
)
147 if (hdc
) return PROGRESS_Draw (infoPtr
, hdc
);
148 hdc
= BeginPaint (infoPtr
->Self
, &ps
);
149 PROGRESS_Draw (infoPtr
, hdc
);
150 EndPaint (infoPtr
->Self
, &ps
);
155 /***********************************************************************
157 * Makes sure the current position (CurVal) is within bounds.
159 static void PROGRESS_CoercePos(PROGRESS_INFO
*infoPtr
)
161 if(infoPtr
->CurVal
< infoPtr
->MinVal
)
162 infoPtr
->CurVal
= infoPtr
->MinVal
;
163 if(infoPtr
->CurVal
> infoPtr
->MaxVal
)
164 infoPtr
->CurVal
= infoPtr
->MaxVal
;
168 /***********************************************************************
170 * Set new Font for progress bar
172 static HFONT
PROGRESS_SetFont (PROGRESS_INFO
*infoPtr
, HFONT hFont
, BOOL bRedraw
)
174 HFONT hOldFont
= infoPtr
->Font
;
175 infoPtr
->Font
= hFont
;
176 if (bRedraw
) PROGRESS_Refresh (infoPtr
);
180 static DWORD
PROGRESS_SetRange (PROGRESS_INFO
*infoPtr
, int low
, int high
)
182 DWORD res
= MAKELONG(LOWORD(infoPtr
->MinVal
), LOWORD(infoPtr
->MaxVal
));
184 /* if nothing changes, simply return */
185 if(infoPtr
->MinVal
== low
&& infoPtr
->MaxVal
== high
) return res
;
187 /* if things are different, adjust values and repaint the control */
188 if (high
<= low
) high
= low
+ 1;
189 infoPtr
->MinVal
= low
;
190 infoPtr
->MaxVal
= high
;
191 PROGRESS_CoercePos(infoPtr
);
192 PROGRESS_Refresh (infoPtr
);
196 /***********************************************************************
199 static LRESULT WINAPI
ProgressWindowProc(HWND hwnd
, UINT message
,
200 WPARAM wParam
, LPARAM lParam
)
202 PROGRESS_INFO
*infoPtr
= (PROGRESS_INFO
*)GetWindowLongW(hwnd
, 0);
206 if (!infoPtr
&& message
!= WM_CREATE
)
207 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
211 dwExStyle
= GetWindowLongW (hwnd
, GWL_EXSTYLE
);
212 dwExStyle
&= ~(WS_EX_CLIENTEDGE
| WS_EX_WINDOWEDGE
);
213 dwExStyle
|= WS_EX_STATICEDGE
;
214 SetWindowLongW (hwnd
, GWL_EXSTYLE
, dwExStyle
| WS_EX_STATICEDGE
);
215 /* Force recalculation of a non-client area */
216 SetWindowPos(hwnd
, 0, 0, 0, 0, 0,
217 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
219 /* allocate memory for info struct */
220 infoPtr
= (PROGRESS_INFO
*)COMCTL32_Alloc (sizeof(PROGRESS_INFO
));
221 if (!infoPtr
) return -1;
222 SetWindowLongW (hwnd
, 0, (DWORD
)infoPtr
);
224 /* initialize the info struct */
225 infoPtr
->Self
= hwnd
;
227 infoPtr
->MaxVal
= 100;
230 infoPtr
->ColorBar
= CLR_DEFAULT
;
231 infoPtr
->ColorBk
= CLR_DEFAULT
;
233 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd
);
237 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd
);
238 COMCTL32_Free (infoPtr
);
239 SetWindowLongW(hwnd
, 0, 0);
243 /* pretend to erase it here, but we will do it in the paint
244 function to avoid flicker */
248 return (LRESULT
)infoPtr
->Font
;
251 return PROGRESS_SetFont (infoPtr
, (HFONT
)wParam
, (BOOL
)lParam
);
254 return PROGRESS_Paint (infoPtr
, (HDC
)wParam
);
257 if(lParam
) UNKNOWN_PARAM(PBM_DELTAPOS
, wParam
, lParam
);
258 temp
= infoPtr
->CurVal
;
260 infoPtr
->CurVal
+= (WORD
)wParam
;
261 PROGRESS_CoercePos (infoPtr
);
262 PROGRESS_Refresh (infoPtr
);
267 if (lParam
) UNKNOWN_PARAM(PBM_SETPOS
, wParam
, lParam
);
268 temp
= infoPtr
->CurVal
;
270 infoPtr
->CurVal
= (WORD
)wParam
;
271 PROGRESS_CoercePos(infoPtr
);
272 PROGRESS_Refresh (infoPtr
);
277 if (wParam
) UNKNOWN_PARAM(PBM_SETRANGE
, wParam
, lParam
);
278 return PROGRESS_SetRange (infoPtr
, (int)LOWORD(lParam
), (int)HIWORD(lParam
));
281 if (lParam
) UNKNOWN_PARAM(PBM_SETSTEP
, wParam
, lParam
);
282 temp
= infoPtr
->Step
;
283 infoPtr
->Step
= (WORD
)wParam
;
287 if (wParam
|| lParam
) UNKNOWN_PARAM(PBM_STEPIT
, wParam
, lParam
);
288 temp
= infoPtr
->CurVal
;
289 infoPtr
->CurVal
+= infoPtr
->Step
;
290 if(infoPtr
->CurVal
> infoPtr
->MaxVal
)
291 infoPtr
->CurVal
= infoPtr
->MinVal
;
292 if(temp
!= infoPtr
->CurVal
)
293 PROGRESS_Refresh (infoPtr
);
297 return PROGRESS_SetRange (infoPtr
, (int)wParam
, (int)lParam
);
301 ((PPBRANGE
)lParam
)->iLow
= infoPtr
->MinVal
;
302 ((PPBRANGE
)lParam
)->iHigh
= infoPtr
->MaxVal
;
304 return wParam
? infoPtr
->MinVal
: infoPtr
->MaxVal
;
307 if (wParam
|| lParam
) UNKNOWN_PARAM(PBM_STEPIT
, wParam
, lParam
);
308 return infoPtr
->CurVal
;
310 case PBM_SETBARCOLOR
:
311 if (wParam
) UNKNOWN_PARAM(PBM_SETBARCOLOR
, wParam
, lParam
);
312 infoPtr
->ColorBar
= (COLORREF
)lParam
;
313 return PROGRESS_Refresh (infoPtr
);
316 if (wParam
) UNKNOWN_PARAM(PBM_SETBKCOLOR
, wParam
, lParam
);
317 infoPtr
->ColorBk
= (COLORREF
)lParam
;
318 return PROGRESS_Refresh (infoPtr
);
321 if (message
>= WM_USER
)
322 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message
, wParam
, lParam
);
323 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
328 /***********************************************************************
329 * PROGRESS_Register [Internal]
331 * Registers the progress bar window class.
333 VOID
PROGRESS_Register (void)
337 ZeroMemory (&wndClass
, sizeof(wndClass
));
338 wndClass
.style
= CS_GLOBALCLASS
| CS_VREDRAW
| CS_HREDRAW
;
339 wndClass
.lpfnWndProc
= (WNDPROC
)ProgressWindowProc
;
340 wndClass
.cbClsExtra
= 0;
341 wndClass
.cbWndExtra
= sizeof (PROGRESS_INFO
*);
342 wndClass
.hCursor
= LoadCursorW (0, IDC_ARROWW
);
343 wndClass
.lpszClassName
= PROGRESS_CLASSW
;
345 RegisterClassW (&wndClass
);
349 /***********************************************************************
350 * PROGRESS_Unregister [Internal]
352 * Unregisters the progress bar window class.
354 VOID
PROGRESS_Unregister (void)
356 UnregisterClassW (PROGRESS_CLASSW
, (HINSTANCE
)NULL
);