4 * Copyright 1997, 2002 Dimitrie O. Paun
5 * Copyright 1998, 1999 Eric Kohl
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.
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.
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
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.
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.
31 * --support PBS_MARQUE
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(progress
);
49 HWND Self
; /* The window handle for this control */
50 INT CurVal
; /* Current progress value */
51 INT MinVal
; /* Minimum progress value */
52 INT MaxVal
; /* Maximum progress value */
53 INT Step
; /* Step to use on PMB_STEPIT */
54 COLORREF ColorBar
; /* Bar color */
55 COLORREF ColorBk
; /* Background color */
56 HFONT Font
; /* Handle to font (not unused) */
59 /* Control configuration constants */
63 /***********************************************************************
66 * Invalide the range between old and new pos.
68 static void PROGRESS_Invalidate( PROGRESS_INFO
*infoPtr
, INT old
, INT
new )
70 LONG style
= GetWindowLongW (infoPtr
->Self
, GWL_STYLE
);
72 int oldPos
, newPos
, ledWidth
;
74 GetClientRect (infoPtr
->Self
, &rect
);
75 InflateRect(&rect
, -1, -1);
77 if (style
& PBS_VERTICAL
)
79 oldPos
= rect
.bottom
- MulDiv (old
- infoPtr
->MinVal
, rect
.bottom
- rect
.top
,
80 infoPtr
->MaxVal
- infoPtr
->MinVal
);
81 newPos
= rect
.bottom
- MulDiv (new - infoPtr
->MinVal
, rect
.bottom
- rect
.top
,
82 infoPtr
->MaxVal
- infoPtr
->MinVal
);
83 ledWidth
= MulDiv (rect
.right
- rect
.left
, 2, 3);
84 rect
.top
= min( oldPos
, newPos
);
85 rect
.bottom
= max( oldPos
, newPos
);
86 if (!(style
& PBS_SMOOTH
)) rect
.top
-= ledWidth
;
87 InvalidateRect( infoPtr
->Self
, &rect
, oldPos
< newPos
);
91 oldPos
= rect
.left
+ MulDiv (old
- infoPtr
->MinVal
, rect
.right
- rect
.left
,
92 infoPtr
->MaxVal
- infoPtr
->MinVal
);
93 newPos
= rect
.left
+ MulDiv (new - infoPtr
->MinVal
, rect
.right
- rect
.left
,
94 infoPtr
->MaxVal
- infoPtr
->MinVal
);
95 ledWidth
= MulDiv (rect
.bottom
- rect
.top
, 2, 3);
96 rect
.left
= min( oldPos
, newPos
);
97 rect
.right
= max( oldPos
, newPos
);
98 if (!(style
& PBS_SMOOTH
)) rect
.right
+= ledWidth
;
99 InvalidateRect( infoPtr
->Self
, &rect
, oldPos
> newPos
);
104 /***********************************************************************
106 * Draws the progress bar.
108 static LRESULT
PROGRESS_Draw (PROGRESS_INFO
*infoPtr
, HDC hdc
)
110 HBRUSH hbrBar
, hbrBk
;
111 int rightBar
, rightMost
, ledWidth
;
115 TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr
, hdc
);
117 /* get the required bar brush */
118 if (infoPtr
->ColorBar
== CLR_DEFAULT
)
119 hbrBar
= GetSysColorBrush(COLOR_HIGHLIGHT
);
121 hbrBar
= CreateSolidBrush (infoPtr
->ColorBar
);
123 if (infoPtr
->ColorBk
== CLR_DEFAULT
)
124 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
126 hbrBk
= CreateSolidBrush(infoPtr
->ColorBk
);
128 /* get client rectangle */
129 GetClientRect (infoPtr
->Self
, &rect
);
130 FrameRect( hdc
, &rect
, hbrBk
);
131 InflateRect(&rect
, -1, -1);
133 /* get the window style */
134 dwStyle
= GetWindowLongW (infoPtr
->Self
, GWL_STYLE
);
136 /* compute extent of progress bar */
137 if (dwStyle
& PBS_VERTICAL
) {
138 rightBar
= rect
.bottom
-
139 MulDiv (infoPtr
->CurVal
- infoPtr
->MinVal
,
140 rect
.bottom
- rect
.top
,
141 infoPtr
->MaxVal
- infoPtr
->MinVal
);
142 ledWidth
= MulDiv (rect
.right
- rect
.left
, 2, 3);
143 rightMost
= rect
.top
;
145 rightBar
= rect
.left
+
146 MulDiv (infoPtr
->CurVal
- infoPtr
->MinVal
,
147 rect
.right
- rect
.left
,
148 infoPtr
->MaxVal
- infoPtr
->MinVal
);
149 ledWidth
= MulDiv (rect
.bottom
- rect
.top
, 2, 3);
150 rightMost
= rect
.right
;
153 /* now draw the bar */
154 if (dwStyle
& PBS_SMOOTH
)
156 if (dwStyle
& PBS_VERTICAL
)
158 INT old_top
= rect
.top
;
160 FillRect(hdc
, &rect
, hbrBar
);
161 rect
.bottom
= rect
.top
;
163 FillRect(hdc
, &rect
, hbrBk
);
167 INT old_right
= rect
.right
;
168 rect
.right
= rightBar
;
169 FillRect(hdc
, &rect
, hbrBar
);
170 rect
.left
= rect
.right
;
171 rect
.right
= old_right
;
172 FillRect(hdc
, &rect
, hbrBk
);
175 if (dwStyle
& PBS_VERTICAL
) {
176 while(rect
.bottom
> rightBar
) {
177 rect
.top
= rect
.bottom
- ledWidth
;
178 if (rect
.top
< rightMost
)
179 rect
.top
= rightMost
;
180 FillRect(hdc
, &rect
, hbrBar
);
181 rect
.bottom
= rect
.top
;
183 if (rect
.top
<= rightBar
) break;
184 FillRect(hdc
, &rect
, hbrBk
);
185 rect
.bottom
= rect
.top
;
187 rect
.top
= rightMost
;
188 FillRect(hdc
, &rect
, hbrBk
);
190 while(rect
.left
< rightBar
) {
191 rect
.right
= rect
.left
+ ledWidth
;
192 if (rect
.right
> rightMost
)
193 rect
.right
= rightMost
;
194 FillRect(hdc
, &rect
, hbrBar
);
195 rect
.left
= rect
.right
;
196 rect
.right
+= LED_GAP
;
197 if (rect
.right
>= rightBar
) break;
198 FillRect(hdc
, &rect
, hbrBk
);
199 rect
.left
= rect
.right
;
201 rect
.right
= rightMost
;
202 FillRect(hdc
, &rect
, hbrBk
);
206 /* delete bar brush */
207 if (infoPtr
->ColorBar
!= CLR_DEFAULT
) DeleteObject (hbrBar
);
208 if (infoPtr
->ColorBk
!= CLR_DEFAULT
) DeleteObject (hbrBk
);
214 /***********************************************************************
216 * Draw the progress bar. The background need not be erased.
217 * If dc!=0, it draws on it
219 static LRESULT
PROGRESS_Paint (PROGRESS_INFO
*infoPtr
, HDC hdc
)
222 if (hdc
) return PROGRESS_Draw (infoPtr
, hdc
);
223 hdc
= BeginPaint (infoPtr
->Self
, &ps
);
224 PROGRESS_Draw (infoPtr
, hdc
);
225 EndPaint (infoPtr
->Self
, &ps
);
230 /***********************************************************************
232 * Makes sure the current position (CurVal) is within bounds.
234 static void PROGRESS_CoercePos(PROGRESS_INFO
*infoPtr
)
236 if(infoPtr
->CurVal
< infoPtr
->MinVal
)
237 infoPtr
->CurVal
= infoPtr
->MinVal
;
238 if(infoPtr
->CurVal
> infoPtr
->MaxVal
)
239 infoPtr
->CurVal
= infoPtr
->MaxVal
;
243 /***********************************************************************
245 * Set new Font for progress bar
247 static HFONT
PROGRESS_SetFont (PROGRESS_INFO
*infoPtr
, HFONT hFont
, BOOL bRedraw
)
249 HFONT hOldFont
= infoPtr
->Font
;
250 infoPtr
->Font
= hFont
;
251 /* Since infoPtr->Font is not used, there is no need for repaint */
255 static DWORD
PROGRESS_SetRange (PROGRESS_INFO
*infoPtr
, int low
, int high
)
257 DWORD res
= MAKELONG(LOWORD(infoPtr
->MinVal
), LOWORD(infoPtr
->MaxVal
));
259 /* if nothing changes, simply return */
260 if(infoPtr
->MinVal
== low
&& infoPtr
->MaxVal
== high
) return res
;
262 infoPtr
->MinVal
= low
;
263 infoPtr
->MaxVal
= high
;
264 PROGRESS_CoercePos(infoPtr
);
265 InvalidateRect(infoPtr
->Self
, NULL
, TRUE
);
269 /***********************************************************************
272 static LRESULT WINAPI
ProgressWindowProc(HWND hwnd
, UINT message
,
273 WPARAM wParam
, LPARAM lParam
)
275 PROGRESS_INFO
*infoPtr
;
277 TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd
, message
, wParam
, lParam
);
279 infoPtr
= (PROGRESS_INFO
*)GetWindowLongW(hwnd
, 0);
281 if (!infoPtr
&& message
!= WM_CREATE
)
282 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
287 DWORD dwExStyle
= GetWindowLongW (hwnd
, GWL_EXSTYLE
);
288 dwExStyle
&= ~(WS_EX_CLIENTEDGE
| WS_EX_WINDOWEDGE
);
289 dwExStyle
|= WS_EX_STATICEDGE
;
290 SetWindowLongW (hwnd
, GWL_EXSTYLE
, dwExStyle
);
291 /* Force recalculation of a non-client area */
292 SetWindowPos(hwnd
, 0, 0, 0, 0, 0,
293 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
295 /* allocate memory for info struct */
296 infoPtr
= (PROGRESS_INFO
*)COMCTL32_Alloc (sizeof(PROGRESS_INFO
));
297 if (!infoPtr
) return -1;
298 SetWindowLongW (hwnd
, 0, (DWORD
)infoPtr
);
300 /* initialize the info struct */
301 infoPtr
->Self
= hwnd
;
303 infoPtr
->MaxVal
= 100;
306 infoPtr
->ColorBar
= CLR_DEFAULT
;
307 infoPtr
->ColorBk
= CLR_DEFAULT
;
309 TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd
);
314 TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd
);
315 COMCTL32_Free (infoPtr
);
316 SetWindowLongW(hwnd
, 0, 0);
320 return (LRESULT
)infoPtr
->Font
;
323 return (LRESULT
)PROGRESS_SetFont(infoPtr
, (HFONT
)wParam
, (BOOL
)lParam
);
326 return PROGRESS_Paint (infoPtr
, (HDC
)wParam
);
331 oldVal
= infoPtr
->CurVal
;
333 infoPtr
->CurVal
+= (INT
)wParam
;
334 PROGRESS_CoercePos (infoPtr
);
335 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal
, infoPtr
->CurVal
);
336 PROGRESS_Invalidate( infoPtr
, oldVal
, infoPtr
->CurVal
);
344 oldVal
= infoPtr
->CurVal
;
345 if(oldVal
!= wParam
) {
346 infoPtr
->CurVal
= (INT
)wParam
;
347 PROGRESS_CoercePos(infoPtr
);
348 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal
, infoPtr
->CurVal
);
349 PROGRESS_Invalidate( infoPtr
, oldVal
, infoPtr
->CurVal
);
355 return PROGRESS_SetRange (infoPtr
, (int)LOWORD(lParam
), (int)HIWORD(lParam
));
360 oldStep
= infoPtr
->Step
;
361 infoPtr
->Step
= (INT
)wParam
;
368 oldVal
= infoPtr
->CurVal
;
369 infoPtr
->CurVal
+= infoPtr
->Step
;
370 if(infoPtr
->CurVal
> infoPtr
->MaxVal
)
371 infoPtr
->CurVal
= infoPtr
->MinVal
;
372 if(oldVal
!= infoPtr
->CurVal
)
374 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal
, infoPtr
->CurVal
);
375 PROGRESS_Invalidate( infoPtr
, oldVal
, infoPtr
->CurVal
);
381 return PROGRESS_SetRange (infoPtr
, (int)wParam
, (int)lParam
);
385 ((PPBRANGE
)lParam
)->iLow
= infoPtr
->MinVal
;
386 ((PPBRANGE
)lParam
)->iHigh
= infoPtr
->MaxVal
;
388 return wParam
? infoPtr
->MinVal
: infoPtr
->MaxVal
;
391 return infoPtr
->CurVal
;
393 case PBM_SETBARCOLOR
:
394 infoPtr
->ColorBar
= (COLORREF
)lParam
;
395 InvalidateRect(hwnd
, NULL
, TRUE
);
399 infoPtr
->ColorBk
= (COLORREF
)lParam
;
400 InvalidateRect(hwnd
, NULL
, TRUE
);
404 if ((message
>= WM_USER
) && (message
< WM_APP
))
405 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message
, wParam
, lParam
);
406 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
411 /***********************************************************************
412 * PROGRESS_Register [Internal]
414 * Registers the progress bar window class.
416 VOID
PROGRESS_Register (void)
420 ZeroMemory (&wndClass
, sizeof(wndClass
));
421 wndClass
.style
= CS_GLOBALCLASS
| CS_VREDRAW
| CS_HREDRAW
;
422 wndClass
.lpfnWndProc
= (WNDPROC
)ProgressWindowProc
;
423 wndClass
.cbClsExtra
= 0;
424 wndClass
.cbWndExtra
= sizeof (PROGRESS_INFO
*);
425 wndClass
.hCursor
= LoadCursorW (0, IDC_ARROWW
);
426 wndClass
.lpszClassName
= PROGRESS_CLASSW
;
428 RegisterClassW (&wndClass
);
432 /***********************************************************************
433 * PROGRESS_Unregister [Internal]
435 * Unregisters the progress bar window class.
437 VOID
PROGRESS_Unregister (void)
439 UnregisterClassW (PROGRESS_CLASSW
, NULL
);