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
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(progress);
31 HWND Self; /* The window handle for this control */
32 INT CurVal; /* Current progress value */
33 INT MinVal; /* Minimum progress value */
34 INT MaxVal; /* Maximum progress value */
35 INT Step; /* Step to use on PMB_STEPIT */
36 COLORREF ColorBar; /* Bar color */
37 COLORREF ColorBk; /* Background color */
38 HFONT Font; /* Handle to font (not unused) */
41 /* Control configuration constants */
45 /***********************************************************************
48 * Invalide the range between old and new pos.
50 static void PROGRESS_Invalidate( PROGRESS_INFO *infoPtr, INT old, INT new )
52 LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE);
54 int oldPos, newPos, ledWidth;
56 GetClientRect (infoPtr->Self, &rect);
57 InflateRect(&rect, -1, -1);
59 if (style & PBS_VERTICAL)
61 oldPos = rect.bottom - MulDiv (old - infoPtr->MinVal, rect.bottom - rect.top,
62 infoPtr->MaxVal - infoPtr->MinVal);
63 newPos = rect.bottom - MulDiv (new - infoPtr->MinVal, rect.bottom - rect.top,
64 infoPtr->MaxVal - infoPtr->MinVal);
65 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
66 rect.top = min( oldPos, newPos );
67 rect.bottom = max( oldPos, newPos );
68 if (!(style & PBS_SMOOTH)) rect.top -= ledWidth;
69 InvalidateRect( infoPtr->Self, &rect, oldPos < newPos );
73 oldPos = rect.left + MulDiv (old - infoPtr->MinVal, rect.right - rect.left,
74 infoPtr->MaxVal - infoPtr->MinVal);
75 newPos = rect.left + MulDiv (new - infoPtr->MinVal, rect.right - rect.left,
76 infoPtr->MaxVal - infoPtr->MinVal);
77 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
78 rect.left = min( oldPos, newPos );
79 rect.right = max( oldPos, newPos );
80 if (!(style & PBS_SMOOTH)) rect.right += ledWidth;
81 InvalidateRect( infoPtr->Self, &rect, oldPos > newPos );
86 /***********************************************************************
88 * Draws the progress bar.
90 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
93 int rightBar, rightMost, ledWidth;
97 TRACE("(infoPtr=%p, hdc=%x)\n", infoPtr, hdc);
99 /* get the required bar brush */
100 if (infoPtr->ColorBar == CLR_DEFAULT)
101 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
103 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
105 if (infoPtr->ColorBk == CLR_DEFAULT)
106 hbrBk = GetSysColorBrush(COLOR_3DFACE);
108 hbrBk = CreateSolidBrush(infoPtr->ColorBk);
110 /* get client rectangle */
111 GetClientRect (infoPtr->Self, &rect);
112 FrameRect( hdc, &rect, hbrBk );
113 InflateRect(&rect, -1, -1);
115 /* get the window style */
116 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
118 /* compute extent of progress bar */
119 if (dwStyle & PBS_VERTICAL) {
120 rightBar = rect.bottom -
121 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
122 rect.bottom - rect.top,
123 infoPtr->MaxVal - infoPtr->MinVal);
124 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
125 rightMost = rect.top;
127 rightBar = rect.left +
128 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
129 rect.right - rect.left,
130 infoPtr->MaxVal - infoPtr->MinVal);
131 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
132 rightMost = rect.right;
135 /* now draw the bar */
136 if (dwStyle & PBS_SMOOTH)
138 if (dwStyle & PBS_VERTICAL)
140 INT old_top = rect.top;
142 FillRect(hdc, &rect, hbrBar);
143 rect.bottom = rect.top;
145 FillRect(hdc, &rect, hbrBk);
149 INT old_right = rect.right;
150 rect.right = rightBar;
151 FillRect(hdc, &rect, hbrBar);
152 rect.left = rect.right;
153 rect.right = old_right;
154 FillRect(hdc, &rect, hbrBk);
157 if (dwStyle & PBS_VERTICAL) {
158 while(rect.bottom > rightBar) {
159 rect.top = rect.bottom - ledWidth;
160 if (rect.top < rightMost)
161 rect.top = rightMost;
162 FillRect(hdc, &rect, hbrBar);
163 rect.bottom = rect.top;
165 if (rect.top <= rightBar) break;
166 FillRect(hdc, &rect, hbrBk);
167 rect.bottom = rect.top;
169 rect.top = rightMost;
170 FillRect(hdc, &rect, hbrBk);
172 while(rect.left < rightBar) {
173 rect.right = rect.left + ledWidth;
174 if (rect.right > rightMost)
175 rect.right = rightMost;
176 FillRect(hdc, &rect, hbrBar);
177 rect.left = rect.right;
178 rect.right += LED_GAP;
179 if (rect.right >= rightBar) break;
180 FillRect(hdc, &rect, hbrBk);
181 rect.left = rect.right;
183 rect.right = rightMost;
184 FillRect(hdc, &rect, hbrBk);
188 /* delete bar brush */
189 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar);
190 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk);
196 /***********************************************************************
198 * Draw the progress bar. The background need not be erased.
199 * If dc!=0, it draws on it
201 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
204 if (hdc) return PROGRESS_Draw (infoPtr, hdc);
205 hdc = BeginPaint (infoPtr->Self, &ps);
206 PROGRESS_Draw (infoPtr, hdc);
207 EndPaint (infoPtr->Self, &ps);
212 /***********************************************************************
214 * Makes sure the current position (CurVal) is within bounds.
216 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
218 if(infoPtr->CurVal < infoPtr->MinVal)
219 infoPtr->CurVal = infoPtr->MinVal;
220 if(infoPtr->CurVal > infoPtr->MaxVal)
221 infoPtr->CurVal = infoPtr->MaxVal;
225 /***********************************************************************
227 * Set new Font for progress bar
229 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
231 HFONT hOldFont = infoPtr->Font;
232 infoPtr->Font = hFont;
233 /* Since infoPtr->Font is not used, there is no need for repaint */
237 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
239 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
241 /* if nothing changes, simply return */
242 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
244 infoPtr->MinVal = low;
245 infoPtr->MaxVal = high;
246 PROGRESS_CoercePos(infoPtr);
250 /***********************************************************************
253 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
254 WPARAM wParam, LPARAM lParam)
256 PROGRESS_INFO *infoPtr;
258 TRACE("hwnd=%x msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
260 infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
262 if (!infoPtr && message != WM_CREATE)
263 return DefWindowProcW( hwnd, message, wParam, lParam );
268 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
269 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
270 dwExStyle |= WS_EX_STATICEDGE;
271 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
272 /* Force recalculation of a non-client area */
273 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
274 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
276 /* allocate memory for info struct */
277 infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
278 if (!infoPtr) return -1;
279 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
281 /* initialize the info struct */
282 infoPtr->Self = hwnd;
284 infoPtr->MaxVal = 100;
287 infoPtr->ColorBar = CLR_DEFAULT;
288 infoPtr->ColorBk = CLR_DEFAULT;
290 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
295 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
296 COMCTL32_Free (infoPtr);
297 SetWindowLongW(hwnd, 0, 0);
301 return (LRESULT)infoPtr->Font;
304 return PROGRESS_SetFont (infoPtr, (HFONT)wParam, (BOOL)lParam);
307 return PROGRESS_Paint (infoPtr, (HDC)wParam);
312 oldVal = infoPtr->CurVal;
314 infoPtr->CurVal += (INT)wParam;
315 PROGRESS_CoercePos (infoPtr);
316 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
317 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
325 oldVal = infoPtr->CurVal;
326 if(oldVal != wParam) {
327 infoPtr->CurVal = (INT)wParam;
328 PROGRESS_CoercePos(infoPtr);
329 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
330 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
336 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
341 oldStep = infoPtr->Step;
342 infoPtr->Step = (INT)wParam;
349 oldVal = infoPtr->CurVal;
350 infoPtr->CurVal += infoPtr->Step;
351 if(infoPtr->CurVal > infoPtr->MaxVal)
352 infoPtr->CurVal = infoPtr->MinVal;
353 if(oldVal != infoPtr->CurVal)
355 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
356 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
362 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
366 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
367 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
369 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
372 return infoPtr->CurVal;
374 case PBM_SETBARCOLOR:
375 infoPtr->ColorBar = (COLORREF)lParam;
376 InvalidateRect(hwnd, NULL, TRUE);
380 infoPtr->ColorBk = (COLORREF)lParam;
381 InvalidateRect(hwnd, NULL, TRUE);
385 if ((message >= WM_USER) && (message < WM_APP))
386 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
387 return DefWindowProcW( hwnd, message, wParam, lParam );
392 /***********************************************************************
393 * PROGRESS_Register [Internal]
395 * Registers the progress bar window class.
397 VOID PROGRESS_Register (void)
401 ZeroMemory (&wndClass, sizeof(wndClass));
402 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
403 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
404 wndClass.cbClsExtra = 0;
405 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
406 wndClass.hCursor = LoadCursorW (0, IDC_ARROWW);
407 wndClass.lpszClassName = PROGRESS_CLASSW;
409 RegisterClassW (&wndClass);
413 /***********************************************************************
414 * PROGRESS_Unregister [Internal]
416 * Unregisters the progress bar window class.
418 VOID PROGRESS_Unregister (void)
420 UnregisterClassW (PROGRESS_CLASSW, (HINSTANCE)NULL);