Remove PROGRESS_Refresh, always do InvalidateRect() to repaint.
[wine/gsoc_dplay.git] / dlls / comctl32 / progress.c
blob5708150f6f5085e22e1998a2edbacdb1e242a62b
1 /*
2 * Progress control
4 * Copyright 1997, 2002 Dimitrie O. Paun
5 * Copyright 1998, 1999 Eric Kohl
7 */
9 #include <string.h>
10 #include "winbase.h"
11 #include "commctrl.h"
12 #include "debugtools.h"
14 DEFAULT_DEBUG_CHANNEL(progress);
16 typedef struct
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) */
26 } PROGRESS_INFO;
28 /* Control configuration constants */
30 #define LED_GAP 2
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 /***********************************************************************
37 * PROGRESS_EraseBackground
39 static void PROGRESS_EraseBackground(PROGRESS_INFO *infoPtr, WPARAM wParam)
41 RECT rect;
42 HBRUSH hbrBk;
43 HDC hdc = wParam ? (HDC)wParam : GetDC(infoPtr->Self);
45 /* get the required background brush */
46 if(infoPtr->ColorBk == CLR_DEFAULT)
47 hbrBk = GetSysColorBrush(COLOR_3DFACE);
48 else
49 hbrBk = CreateSolidBrush(infoPtr->ColorBk);
51 /* get client rectangle */
52 GetClientRect(infoPtr->Self, &rect);
54 /* draw the background */
55 FillRect(hdc, &rect, hbrBk);
57 /* delete background brush */
58 if(infoPtr->ColorBk != CLR_DEFAULT)
59 DeleteObject (hbrBk);
61 if(!wParam) ReleaseDC(infoPtr->Self, hdc);
64 /***********************************************************************
65 * PROGRESS_Draw
66 * Draws the progress bar.
68 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
70 HBRUSH hbrBar;
71 int rightBar, rightMost, ledWidth;
72 RECT rect;
73 DWORD dwStyle;
75 TRACE("(infoPtr=%p, hdc=%x)\n", infoPtr, hdc);
77 /* get the required bar brush */
78 if (infoPtr->ColorBar == CLR_DEFAULT)
79 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
80 else
81 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
83 /* get client rectangle */
84 GetClientRect (infoPtr->Self, &rect);
86 InflateRect(&rect, -1, -1);
88 /* get the window style */
89 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
91 /* compute extent of progress bar */
92 if (dwStyle & PBS_VERTICAL) {
93 rightBar = rect.bottom -
94 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
95 rect.bottom - rect.top,
96 infoPtr->MaxVal - infoPtr->MinVal);
97 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
98 rightMost = rect.top;
99 } else {
100 rightBar = rect.left +
101 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
102 rect.right - rect.left,
103 infoPtr->MaxVal - infoPtr->MinVal);
104 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
105 rightMost = rect.right;
108 /* now draw the bar */
109 if (dwStyle & PBS_SMOOTH) {
110 if (dwStyle & PBS_VERTICAL)
111 rect.top = rightBar;
112 else
113 rect.right = rightBar;
114 FillRect(hdc, &rect, hbrBar);
115 } else {
116 if (dwStyle & PBS_VERTICAL) {
117 while(rect.bottom > rightBar) {
118 rect.top = rect.bottom - ledWidth;
119 if (rect.top < rightMost)
120 rect.top = rightMost;
121 FillRect(hdc, &rect, hbrBar);
122 rect.bottom = rect.top - LED_GAP;
124 } else {
125 while(rect.left < rightBar) {
126 rect.right = rect.left + ledWidth;
127 if (rect.right > rightMost)
128 rect.right = rightMost;
129 FillRect(hdc, &rect, hbrBar);
130 rect.left = rect.right + LED_GAP;
135 /* delete bar brush */
136 if (infoPtr->ColorBar != CLR_DEFAULT)
137 DeleteObject (hbrBar);
139 return 0;
143 /***********************************************************************
144 * PROGRESS_Paint
145 * Draw the progress bar. The background need not be erased.
146 * If dc!=0, it draws on it
148 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
150 PAINTSTRUCT ps;
151 if (hdc) return PROGRESS_Draw (infoPtr, hdc);
152 hdc = BeginPaint (infoPtr->Self, &ps);
153 PROGRESS_Draw (infoPtr, hdc);
154 EndPaint (infoPtr->Self, &ps);
155 return 0;
159 /***********************************************************************
160 * PROGRESS_CoercePos
161 * Makes sure the current position (CurVal) is within bounds.
163 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
165 if(infoPtr->CurVal < infoPtr->MinVal)
166 infoPtr->CurVal = infoPtr->MinVal;
167 if(infoPtr->CurVal > infoPtr->MaxVal)
168 infoPtr->CurVal = infoPtr->MaxVal;
172 /***********************************************************************
173 * PROGRESS_SetFont
174 * Set new Font for progress bar
176 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
178 HFONT hOldFont = infoPtr->Font;
179 infoPtr->Font = hFont;
180 /* Since infoPtr->Font is not used, there is no need for repaint */
181 return hOldFont;
184 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
186 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
188 /* if nothing changes, simply return */
189 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
191 infoPtr->MinVal = low;
192 infoPtr->MaxVal = high;
193 PROGRESS_CoercePos(infoPtr);
194 return res;
197 /***********************************************************************
198 * ProgressWindowProc
200 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
201 WPARAM wParam, LPARAM lParam)
203 PROGRESS_INFO *infoPtr;
205 TRACE("hwnd=%x msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
207 infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
209 if (!infoPtr && message != WM_CREATE)
210 return DefWindowProcW( hwnd, message, wParam, lParam );
212 switch(message) {
213 case WM_CREATE:
215 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
216 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
217 dwExStyle |= WS_EX_STATICEDGE;
218 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle | WS_EX_STATICEDGE);
219 /* Force recalculation of a non-client area */
220 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
221 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
223 /* allocate memory for info struct */
224 infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
225 if (!infoPtr) return -1;
226 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
228 /* initialize the info struct */
229 infoPtr->Self = hwnd;
230 infoPtr->MinVal = 0;
231 infoPtr->MaxVal = 100;
232 infoPtr->CurVal = 0;
233 infoPtr->Step = 10;
234 infoPtr->ColorBar = CLR_DEFAULT;
235 infoPtr->ColorBk = CLR_DEFAULT;
236 infoPtr->Font = 0;
237 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
238 return 0;
241 case WM_DESTROY:
242 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
243 COMCTL32_Free (infoPtr);
244 SetWindowLongW(hwnd, 0, 0);
245 return 0;
247 case WM_ERASEBKGND:
248 PROGRESS_EraseBackground(infoPtr, wParam);
249 return TRUE;
251 case WM_GETFONT:
252 return (LRESULT)infoPtr->Font;
254 case WM_SETFONT:
255 return PROGRESS_SetFont (infoPtr, (HFONT)wParam, (BOOL)lParam);
257 case WM_PAINT:
258 return PROGRESS_Paint (infoPtr, (HDC)wParam);
260 case PBM_DELTAPOS:
262 INT oldVal;
263 if(lParam) UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
264 oldVal = infoPtr->CurVal;
265 if(wParam != 0) {
266 BOOL bErase;
267 infoPtr->CurVal += (INT)wParam;
268 PROGRESS_CoercePos (infoPtr);
269 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
270 bErase = (oldVal > infoPtr->CurVal);
271 InvalidateRect(hwnd, NULL, bErase);
273 return oldVal;
276 case PBM_SETPOS:
278 INT oldVal;
279 if (lParam) UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
280 oldVal = infoPtr->CurVal;
281 if(oldVal != wParam) {
282 BOOL bErase;
283 infoPtr->CurVal = (INT)wParam;
284 PROGRESS_CoercePos(infoPtr);
285 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
286 bErase = (oldVal > infoPtr->CurVal);
287 InvalidateRect(hwnd, NULL, bErase);
289 return oldVal;
292 case PBM_SETRANGE:
293 if (wParam) UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
294 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
296 case PBM_SETSTEP:
298 INT oldStep;
299 if (lParam) UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
300 oldStep = infoPtr->Step;
301 infoPtr->Step = (INT)wParam;
302 return oldStep;
305 case PBM_STEPIT:
307 INT oldVal;
308 if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
309 oldVal = infoPtr->CurVal;
310 infoPtr->CurVal += infoPtr->Step;
311 if(infoPtr->CurVal > infoPtr->MaxVal)
312 infoPtr->CurVal = infoPtr->MinVal;
313 if(oldVal != infoPtr->CurVal)
315 BOOL bErase;
316 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
317 bErase = (oldVal > infoPtr->CurVal);
318 InvalidateRect(hwnd, NULL, bErase);
320 return oldVal;
323 case PBM_SETRANGE32:
324 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
326 case PBM_GETRANGE:
327 if (lParam) {
328 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
329 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
331 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
333 case PBM_GETPOS:
334 if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
335 return infoPtr->CurVal;
337 case PBM_SETBARCOLOR:
338 if (wParam) UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
339 infoPtr->ColorBar = (COLORREF)lParam;
340 InvalidateRect(hwnd, NULL, TRUE);
341 return 0;
343 case PBM_SETBKCOLOR:
344 if (wParam) UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
345 infoPtr->ColorBk = (COLORREF)lParam;
346 InvalidateRect(hwnd, NULL, TRUE);
347 return 0;
349 default:
350 if (message >= WM_USER)
351 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
352 return DefWindowProcW( hwnd, message, wParam, lParam );
357 /***********************************************************************
358 * PROGRESS_Register [Internal]
360 * Registers the progress bar window class.
362 VOID PROGRESS_Register (void)
364 WNDCLASSW wndClass;
366 ZeroMemory (&wndClass, sizeof(wndClass));
367 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
368 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
369 wndClass.cbClsExtra = 0;
370 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
371 wndClass.hCursor = LoadCursorW (0, IDC_ARROWW);
372 wndClass.lpszClassName = PROGRESS_CLASSW;
374 RegisterClassW (&wndClass);
378 /***********************************************************************
379 * PROGRESS_Unregister [Internal]
381 * Unregisters the progress bar window class.
383 VOID PROGRESS_Unregister (void)
385 UnregisterClassW (PROGRESS_CLASSW, (HINSTANCE)NULL);