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 /***********************************************************************
50 * PROGRESS_EraseBackground
52 static void PROGRESS_EraseBackground(PROGRESS_INFO *infoPtr, WPARAM wParam)
56 HDC hdc = wParam ? (HDC)wParam : GetDC(infoPtr->Self);
58 /* get the required background brush */
59 if(infoPtr->ColorBk == CLR_DEFAULT)
60 hbrBk = GetSysColorBrush(COLOR_3DFACE);
62 hbrBk = CreateSolidBrush(infoPtr->ColorBk);
64 /* get client rectangle */
65 GetClientRect(infoPtr->Self, &rect);
67 /* draw the background */
68 FillRect(hdc, &rect, hbrBk);
70 /* delete background brush */
71 if(infoPtr->ColorBk != CLR_DEFAULT)
74 if(!wParam) ReleaseDC(infoPtr->Self, hdc);
77 /***********************************************************************
79 * Draws the progress bar.
81 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
84 int rightBar, rightMost, ledWidth;
88 TRACE("(infoPtr=%p, hdc=%x)\n", infoPtr, hdc);
90 /* get the required bar brush */
91 if (infoPtr->ColorBar == CLR_DEFAULT)
92 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
94 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
96 /* get client rectangle */
97 GetClientRect (infoPtr->Self, &rect);
99 InflateRect(&rect, -1, -1);
101 /* get the window style */
102 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
104 /* compute extent of progress bar */
105 if (dwStyle & PBS_VERTICAL) {
106 rightBar = rect.bottom -
107 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
108 rect.bottom - rect.top,
109 infoPtr->MaxVal - infoPtr->MinVal);
110 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
111 rightMost = rect.top;
113 rightBar = rect.left +
114 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
115 rect.right - rect.left,
116 infoPtr->MaxVal - infoPtr->MinVal);
117 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
118 rightMost = rect.right;
121 /* now draw the bar */
122 if (dwStyle & PBS_SMOOTH) {
123 if (dwStyle & PBS_VERTICAL)
126 rect.right = rightBar;
127 FillRect(hdc, &rect, hbrBar);
129 if (dwStyle & PBS_VERTICAL) {
130 while(rect.bottom > rightBar) {
131 rect.top = rect.bottom - ledWidth;
132 if (rect.top < rightMost)
133 rect.top = rightMost;
134 FillRect(hdc, &rect, hbrBar);
135 rect.bottom = rect.top - LED_GAP;
138 while(rect.left < rightBar) {
139 rect.right = rect.left + ledWidth;
140 if (rect.right > rightMost)
141 rect.right = rightMost;
142 FillRect(hdc, &rect, hbrBar);
143 rect.left = rect.right + LED_GAP;
148 /* delete bar brush */
149 if (infoPtr->ColorBar != CLR_DEFAULT)
150 DeleteObject (hbrBar);
156 /***********************************************************************
158 * Draw the progress bar. The background need not be erased.
159 * If dc!=0, it draws on it
161 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
164 if (hdc) return PROGRESS_Draw (infoPtr, hdc);
165 hdc = BeginPaint (infoPtr->Self, &ps);
166 PROGRESS_Draw (infoPtr, hdc);
167 EndPaint (infoPtr->Self, &ps);
172 /***********************************************************************
174 * Makes sure the current position (CurVal) is within bounds.
176 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
178 if(infoPtr->CurVal < infoPtr->MinVal)
179 infoPtr->CurVal = infoPtr->MinVal;
180 if(infoPtr->CurVal > infoPtr->MaxVal)
181 infoPtr->CurVal = infoPtr->MaxVal;
185 /***********************************************************************
187 * Set new Font for progress bar
189 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
191 HFONT hOldFont = infoPtr->Font;
192 infoPtr->Font = hFont;
193 /* Since infoPtr->Font is not used, there is no need for repaint */
197 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
199 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
201 /* if nothing changes, simply return */
202 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
204 infoPtr->MinVal = low;
205 infoPtr->MaxVal = high;
206 PROGRESS_CoercePos(infoPtr);
210 /***********************************************************************
213 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
214 WPARAM wParam, LPARAM lParam)
216 PROGRESS_INFO *infoPtr;
218 TRACE("hwnd=%x msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
220 infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
222 if (!infoPtr && message != WM_CREATE)
223 return DefWindowProcW( hwnd, message, wParam, lParam );
228 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
229 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
230 dwExStyle |= WS_EX_STATICEDGE;
231 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
232 /* Force recalculation of a non-client area */
233 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
234 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
236 /* allocate memory for info struct */
237 infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
238 if (!infoPtr) return -1;
239 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
241 /* initialize the info struct */
242 infoPtr->Self = hwnd;
244 infoPtr->MaxVal = 100;
247 infoPtr->ColorBar = CLR_DEFAULT;
248 infoPtr->ColorBk = CLR_DEFAULT;
250 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
255 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
256 COMCTL32_Free (infoPtr);
257 SetWindowLongW(hwnd, 0, 0);
261 PROGRESS_EraseBackground(infoPtr, wParam);
265 return (LRESULT)infoPtr->Font;
268 return PROGRESS_SetFont (infoPtr, (HFONT)wParam, (BOOL)lParam);
271 return PROGRESS_Paint (infoPtr, (HDC)wParam);
276 if(lParam) UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
277 oldVal = infoPtr->CurVal;
280 infoPtr->CurVal += (INT)wParam;
281 PROGRESS_CoercePos (infoPtr);
282 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
283 bErase = (oldVal > infoPtr->CurVal);
284 InvalidateRect(hwnd, NULL, bErase);
292 if (lParam) UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
293 oldVal = infoPtr->CurVal;
294 if(oldVal != wParam) {
296 infoPtr->CurVal = (INT)wParam;
297 PROGRESS_CoercePos(infoPtr);
298 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
299 bErase = (oldVal > infoPtr->CurVal);
300 InvalidateRect(hwnd, NULL, bErase);
306 if (wParam) UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
307 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
312 if (lParam) UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
313 oldStep = infoPtr->Step;
314 infoPtr->Step = (INT)wParam;
321 if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
322 oldVal = infoPtr->CurVal;
323 infoPtr->CurVal += infoPtr->Step;
324 if(infoPtr->CurVal > infoPtr->MaxVal)
325 infoPtr->CurVal = infoPtr->MinVal;
326 if(oldVal != infoPtr->CurVal)
329 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
330 bErase = (oldVal > infoPtr->CurVal);
331 InvalidateRect(hwnd, NULL, bErase);
337 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
341 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
342 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
344 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
347 if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
348 return infoPtr->CurVal;
350 case PBM_SETBARCOLOR:
351 if (wParam) UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
352 infoPtr->ColorBar = (COLORREF)lParam;
353 InvalidateRect(hwnd, NULL, TRUE);
357 if (wParam) UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
358 infoPtr->ColorBk = (COLORREF)lParam;
359 InvalidateRect(hwnd, NULL, TRUE);
363 if (message >= WM_USER)
364 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
365 return DefWindowProcW( hwnd, message, wParam, lParam );
370 /***********************************************************************
371 * PROGRESS_Register [Internal]
373 * Registers the progress bar window class.
375 VOID PROGRESS_Register (void)
379 ZeroMemory (&wndClass, sizeof(wndClass));
380 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
381 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
382 wndClass.cbClsExtra = 0;
383 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
384 wndClass.hCursor = LoadCursorW (0, IDC_ARROWW);
385 wndClass.lpszClassName = PROGRESS_CLASSW;
387 RegisterClassW (&wndClass);
391 /***********************************************************************
392 * PROGRESS_Unregister [Internal]
394 * Unregisters the progress bar window class.
396 VOID PROGRESS_Unregister (void)
398 UnregisterClassW (PROGRESS_CLASSW, (HINSTANCE)NULL);