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 #define UNKNOWN_PARAM(msg, wParam, lParam) WARN( \
46 "Unknown parameter(s) for message " #msg \
47 "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam);
49 /***********************************************************************
52 * Invalide the range between old and new pos.
54 static void PROGRESS_Invalidate( PROGRESS_INFO *infoPtr, INT old, INT new )
56 LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE);
58 int oldPos, newPos, ledWidth;
60 GetClientRect (infoPtr->Self, &rect);
61 InflateRect(&rect, -1, -1);
63 if (style & PBS_VERTICAL)
65 oldPos = rect.bottom - MulDiv (old - infoPtr->MinVal, rect.bottom - rect.top,
66 infoPtr->MaxVal - infoPtr->MinVal);
67 newPos = rect.bottom - MulDiv (new - infoPtr->MinVal, rect.bottom - rect.top,
68 infoPtr->MaxVal - infoPtr->MinVal);
69 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
70 rect.top = min( oldPos, newPos );
71 rect.bottom = max( oldPos, newPos );
72 if (!(style & PBS_SMOOTH)) rect.top -= ledWidth;
73 InvalidateRect( infoPtr->Self, &rect, oldPos < newPos );
77 oldPos = rect.left + MulDiv (old - infoPtr->MinVal, rect.right - rect.left,
78 infoPtr->MaxVal - infoPtr->MinVal);
79 newPos = rect.left + MulDiv (new - infoPtr->MinVal, rect.right - rect.left,
80 infoPtr->MaxVal - infoPtr->MinVal);
81 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
82 rect.left = min( oldPos, newPos );
83 rect.right = max( oldPos, newPos );
84 if (!(style & PBS_SMOOTH)) rect.right += ledWidth;
85 InvalidateRect( infoPtr->Self, &rect, oldPos > newPos );
90 /***********************************************************************
92 * Draws the progress bar.
94 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
97 int rightBar, rightMost, ledWidth;
101 TRACE("(infoPtr=%p, hdc=%x)\n", infoPtr, hdc);
103 /* get the required bar brush */
104 if (infoPtr->ColorBar == CLR_DEFAULT)
105 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
107 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
109 if (infoPtr->ColorBk == CLR_DEFAULT)
110 hbrBk = GetSysColorBrush(COLOR_3DFACE);
112 hbrBk = CreateSolidBrush(infoPtr->ColorBk);
114 /* get client rectangle */
115 GetClientRect (infoPtr->Self, &rect);
116 FrameRect( hdc, &rect, hbrBk );
117 InflateRect(&rect, -1, -1);
119 /* get the window style */
120 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
122 /* compute extent of progress bar */
123 if (dwStyle & PBS_VERTICAL) {
124 rightBar = rect.bottom -
125 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
126 rect.bottom - rect.top,
127 infoPtr->MaxVal - infoPtr->MinVal);
128 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
129 rightMost = rect.top;
131 rightBar = rect.left +
132 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
133 rect.right - rect.left,
134 infoPtr->MaxVal - infoPtr->MinVal);
135 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
136 rightMost = rect.right;
139 /* now draw the bar */
140 if (dwStyle & PBS_SMOOTH)
142 if (dwStyle & PBS_VERTICAL)
144 INT old_top = rect.top;
146 FillRect(hdc, &rect, hbrBar);
147 rect.bottom = rect.top;
149 FillRect(hdc, &rect, hbrBk);
153 INT old_right = rect.right;
154 rect.right = rightBar;
155 FillRect(hdc, &rect, hbrBar);
156 rect.left = rect.right;
157 rect.right = old_right;
158 FillRect(hdc, &rect, hbrBk);
161 if (dwStyle & PBS_VERTICAL) {
162 while(rect.bottom > rightBar) {
163 rect.top = rect.bottom - ledWidth;
164 if (rect.top < rightMost)
165 rect.top = rightMost;
166 FillRect(hdc, &rect, hbrBar);
167 rect.bottom = rect.top;
169 if (rect.top <= rightBar) break;
170 FillRect(hdc, &rect, hbrBk);
171 rect.bottom = rect.top;
173 rect.top = rightMost;
174 FillRect(hdc, &rect, hbrBk);
176 while(rect.left < rightBar) {
177 rect.right = rect.left + ledWidth;
178 if (rect.right > rightMost)
179 rect.right = rightMost;
180 FillRect(hdc, &rect, hbrBar);
181 rect.left = rect.right;
182 rect.right += LED_GAP;
183 if (rect.right >= rightBar) break;
184 FillRect(hdc, &rect, hbrBk);
185 rect.left = rect.right;
187 rect.right = rightMost;
188 FillRect(hdc, &rect, hbrBk);
192 /* delete bar brush */
193 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar);
194 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk);
200 /***********************************************************************
202 * Draw the progress bar. The background need not be erased.
203 * If dc!=0, it draws on it
205 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
208 if (hdc) return PROGRESS_Draw (infoPtr, hdc);
209 hdc = BeginPaint (infoPtr->Self, &ps);
210 PROGRESS_Draw (infoPtr, hdc);
211 EndPaint (infoPtr->Self, &ps);
216 /***********************************************************************
218 * Makes sure the current position (CurVal) is within bounds.
220 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
222 if(infoPtr->CurVal < infoPtr->MinVal)
223 infoPtr->CurVal = infoPtr->MinVal;
224 if(infoPtr->CurVal > infoPtr->MaxVal)
225 infoPtr->CurVal = infoPtr->MaxVal;
229 /***********************************************************************
231 * Set new Font for progress bar
233 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
235 HFONT hOldFont = infoPtr->Font;
236 infoPtr->Font = hFont;
237 /* Since infoPtr->Font is not used, there is no need for repaint */
241 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
243 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
245 /* if nothing changes, simply return */
246 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
248 infoPtr->MinVal = low;
249 infoPtr->MaxVal = high;
250 PROGRESS_CoercePos(infoPtr);
254 /***********************************************************************
257 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
258 WPARAM wParam, LPARAM lParam)
260 PROGRESS_INFO *infoPtr;
262 TRACE("hwnd=%x msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
264 infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
266 if (!infoPtr && message != WM_CREATE)
267 return DefWindowProcW( hwnd, message, wParam, lParam );
272 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
273 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
274 dwExStyle |= WS_EX_STATICEDGE;
275 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
276 /* Force recalculation of a non-client area */
277 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
278 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
280 /* allocate memory for info struct */
281 infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
282 if (!infoPtr) return -1;
283 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
285 /* initialize the info struct */
286 infoPtr->Self = hwnd;
288 infoPtr->MaxVal = 100;
291 infoPtr->ColorBar = CLR_DEFAULT;
292 infoPtr->ColorBk = CLR_DEFAULT;
294 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
299 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
300 COMCTL32_Free (infoPtr);
301 SetWindowLongW(hwnd, 0, 0);
305 return (LRESULT)infoPtr->Font;
308 return PROGRESS_SetFont (infoPtr, (HFONT)wParam, (BOOL)lParam);
311 return PROGRESS_Paint (infoPtr, (HDC)wParam);
316 if(lParam) UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
317 oldVal = infoPtr->CurVal;
319 infoPtr->CurVal += (INT)wParam;
320 PROGRESS_CoercePos (infoPtr);
321 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
322 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
330 if (lParam) UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
331 oldVal = infoPtr->CurVal;
332 if(oldVal != wParam) {
333 infoPtr->CurVal = (INT)wParam;
334 PROGRESS_CoercePos(infoPtr);
335 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
336 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
342 if (wParam) UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
343 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
348 if (lParam) UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
349 oldStep = infoPtr->Step;
350 infoPtr->Step = (INT)wParam;
357 if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
358 oldVal = infoPtr->CurVal;
359 infoPtr->CurVal += infoPtr->Step;
360 if(infoPtr->CurVal > infoPtr->MaxVal)
361 infoPtr->CurVal = infoPtr->MinVal;
362 if(oldVal != infoPtr->CurVal)
364 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
365 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
371 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
375 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
376 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
378 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
381 if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
382 return infoPtr->CurVal;
384 case PBM_SETBARCOLOR:
385 if (wParam) UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
386 infoPtr->ColorBar = (COLORREF)lParam;
387 InvalidateRect(hwnd, NULL, TRUE);
391 if (wParam) UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
392 infoPtr->ColorBk = (COLORREF)lParam;
393 InvalidateRect(hwnd, NULL, TRUE);
397 if ((message >= WM_USER) && (message < WM_APP))
398 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
399 return DefWindowProcW( hwnd, message, wParam, lParam );
404 /***********************************************************************
405 * PROGRESS_Register [Internal]
407 * Registers the progress bar window class.
409 VOID PROGRESS_Register (void)
413 ZeroMemory (&wndClass, sizeof(wndClass));
414 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
415 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
416 wndClass.cbClsExtra = 0;
417 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
418 wndClass.hCursor = LoadCursorW (0, IDC_ARROWW);
419 wndClass.lpszClassName = PROGRESS_CLASSW;
421 RegisterClassW (&wndClass);
425 /***********************************************************************
426 * PROGRESS_Unregister [Internal]
428 * Unregisters the progress bar window class.
430 VOID PROGRESS_Unregister (void)
432 UnregisterClassW (PROGRESS_CLASSW, (HINSTANCE)NULL);