Slightly improve keyboard tracking in combobox.
[wine/testsucceed.git] / dlls / comctl32 / progress.c
blob0163694f9a640556900488d25fb151d7d18863f6
1 /*
2 * Progress control
4 * Copyright 1997 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 INT CurVal; /* Current progress value */
19 INT MinVal; /* Minimum progress value */
20 INT MaxVal; /* Maximum progress value */
21 INT Step; /* Step to use on PMB_STEPIT */
22 COLORREF ColorBar; /* Bar color */
23 COLORREF ColorBk; /* Background color */
24 HFONT hFont; /* Handle to font (not unused) */
25 } PROGRESS_INFO;
27 /* Control configuration constants */
29 #define LED_GAP 2
31 /* Work constants */
33 #define UNKNOWN_PARAM(msg, wParam, lParam) WARN(\
34 "Unknown parameter(s) for message " #msg \
35 "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam);
37 #define PROGRESS_GetInfoPtr(hwnd) ((PROGRESS_INFO *)GetWindowLongA(hwnd, 0))
40 /***********************************************************************
41 * PROGRESS_Draw
42 * Draws the progress bar.
44 static void
45 PROGRESS_Draw (HWND hwnd, HDC hdc)
47 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
48 HBRUSH hbrBar, hbrBk;
49 int rightBar, rightMost, ledWidth;
50 RECT rect;
51 DWORD dwStyle;
53 TRACE("refresh pos=%d min=%d, max=%d\n",
54 infoPtr->CurVal, infoPtr->MinVal, infoPtr->MaxVal);
56 /* get the required bar brush */
57 if (infoPtr->ColorBar == CLR_DEFAULT)
58 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
59 else
60 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
62 /* get the required background brush */
63 if (infoPtr->ColorBk == CLR_DEFAULT)
64 hbrBk = GetSysColorBrush (COLOR_3DFACE);
65 else
66 hbrBk = CreateSolidBrush (infoPtr->ColorBk);
68 /* get client rectangle */
69 GetClientRect (hwnd, &rect);
71 /* draw the background */
72 FillRect(hdc, &rect, hbrBk);
74 rect.left++; rect.right--; rect.top++; rect.bottom--;
76 /* get the window style */
77 dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
79 /* compute extent of progress bar */
80 if (dwStyle & PBS_VERTICAL)
82 rightBar = rect.bottom -
83 MulDiv(infoPtr->CurVal-infoPtr->MinVal,
84 rect.bottom - rect.top,
85 infoPtr->MaxVal-infoPtr->MinVal);
86 ledWidth = MulDiv ((rect.right - rect.left), 2, 3);
87 rightMost = rect.top;
89 else
91 rightBar = rect.left +
92 MulDiv(infoPtr->CurVal-infoPtr->MinVal,
93 rect.right - rect.left,
94 infoPtr->MaxVal-infoPtr->MinVal);
95 ledWidth = MulDiv ((rect.bottom - rect.top), 2, 3);
96 rightMost = rect.right;
99 /* now draw the bar */
100 if (dwStyle & PBS_SMOOTH)
102 if (dwStyle & PBS_VERTICAL)
103 rect.top = rightBar;
104 else
105 rect.right = rightBar;
106 FillRect(hdc, &rect, hbrBar);
108 else
110 if (dwStyle & PBS_VERTICAL)
112 while(rect.bottom > rightBar) {
113 rect.top = rect.bottom-ledWidth;
114 if (rect.top < rightMost)
115 rect.top = rightMost;
116 FillRect(hdc, &rect, hbrBar);
117 rect.bottom = rect.top-LED_GAP;
120 else {
121 while(rect.left < rightBar) {
122 rect.right = rect.left+ledWidth;
123 if (rect.right > rightMost)
124 rect.right = rightMost;
125 FillRect(hdc, &rect, hbrBar);
126 rect.left = rect.right+LED_GAP;
131 /* delete bar brush */
132 if (infoPtr->ColorBar != CLR_DEFAULT)
133 DeleteObject (hbrBar);
135 /* delete background brush */
136 if (infoPtr->ColorBk != CLR_DEFAULT)
137 DeleteObject (hbrBk);
140 /***********************************************************************
141 * PROGRESS_Refresh
142 * Draw the progress bar. The background need not be erased.
144 static void
145 PROGRESS_Refresh (HWND hwnd)
147 HDC hdc;
149 hdc = GetDC (hwnd);
150 PROGRESS_Draw (hwnd, hdc);
151 ReleaseDC (hwnd, hdc);
154 /***********************************************************************
155 * PROGRESS_Paint
156 * Draw the progress bar. The background need not be erased.
157 * If dc!=0, it draws on it
159 static void
160 PROGRESS_Paint (HWND hwnd)
162 PAINTSTRUCT ps;
163 HDC hdc;
165 hdc = BeginPaint (hwnd, &ps);
166 PROGRESS_Draw (hwnd, hdc);
167 EndPaint (hwnd, &ps);
171 /***********************************************************************
172 * PROGRESS_CoercePos
173 * Makes sure the current position (CUrVal) is within bounds.
175 static void PROGRESS_CoercePos(HWND hwnd)
177 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
179 if(infoPtr->CurVal < infoPtr->MinVal)
180 infoPtr->CurVal = infoPtr->MinVal;
181 if(infoPtr->CurVal > infoPtr->MaxVal)
182 infoPtr->CurVal = infoPtr->MaxVal;
186 /***********************************************************************
187 * PROGRESS_SetFont
188 * Set new Font for progress bar
190 static HFONT
191 PROGRESS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
193 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
194 HFONT hOldFont = infoPtr->hFont;
196 infoPtr->hFont = (HFONT)wParam;
197 if (LOWORD(lParam))
198 PROGRESS_Refresh (hwnd);
199 return hOldFont;
203 /***********************************************************************
204 * ProgressWindowProc
206 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
207 WPARAM wParam, LPARAM lParam)
209 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
210 UINT temp;
211 if (!infoPtr && (message != WM_CREATE))
212 return DefWindowProcA( hwnd, message, wParam, lParam );
213 switch(message)
215 case WM_NCCREATE:
217 DWORD dwExStyle;
218 dwExStyle = GetWindowLongA (hwnd, GWL_EXSTYLE);
219 SetWindowLongA (hwnd, GWL_EXSTYLE, dwExStyle | WS_EX_STATICEDGE);
221 return TRUE;
223 case WM_CREATE:
224 /* allocate memory for info struct */
225 infoPtr =
226 (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
227 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
229 /* initialize the info struct */
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->hFont=(HANDLE)NULL;
237 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
238 break;
240 case WM_DESTROY:
241 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
242 COMCTL32_Free (infoPtr);
243 SetWindowLongA(hwnd, 0, 0);
244 break;
246 case WM_ERASEBKGND:
247 /* pretend to erase it here, but we will do it in the paint
248 function to avoid flicker */
249 return 1;
251 case WM_GETFONT:
252 return (LRESULT)infoPtr->hFont;
254 case WM_SETFONT:
255 return PROGRESS_SetFont (hwnd, wParam, lParam);
257 case WM_PAINT:
258 PROGRESS_Paint (hwnd);
259 break;
261 case PBM_DELTAPOS:
262 if(lParam)
263 UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
264 temp = infoPtr->CurVal;
265 if(wParam != 0){
266 infoPtr->CurVal += (WORD)wParam;
267 PROGRESS_CoercePos (hwnd);
268 PROGRESS_Refresh (hwnd);
270 return temp;
272 case PBM_SETPOS:
273 if (lParam)
274 UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
275 temp = infoPtr->CurVal;
276 if(temp != wParam){
277 infoPtr->CurVal = (WORD)wParam;
278 PROGRESS_CoercePos(hwnd);
279 PROGRESS_Refresh (hwnd);
281 return temp;
283 case PBM_SETRANGE:
284 if (wParam)
285 UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
286 temp = MAKELONG(infoPtr->MinVal, infoPtr->MaxVal);
287 if(temp != lParam){
288 infoPtr->MinVal = LOWORD(lParam);
289 infoPtr->MaxVal = HIWORD(lParam);
290 if(infoPtr->MaxVal <= infoPtr->MinVal)
291 infoPtr->MaxVal = infoPtr->MinVal+1;
292 PROGRESS_CoercePos(hwnd);
293 PROGRESS_Refresh (hwnd);
295 return temp;
297 case PBM_SETSTEP:
298 if (lParam)
299 UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
300 temp = infoPtr->Step;
301 infoPtr->Step = (WORD)wParam;
302 return temp;
304 case PBM_STEPIT:
305 if (wParam || lParam)
306 UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
307 temp = infoPtr->CurVal;
308 infoPtr->CurVal += infoPtr->Step;
309 if(infoPtr->CurVal > infoPtr->MaxVal)
310 infoPtr->CurVal = infoPtr->MinVal;
311 if(temp != infoPtr->CurVal)
312 PROGRESS_Refresh (hwnd);
313 return temp;
315 case PBM_SETRANGE32:
316 temp = MAKELONG(infoPtr->MinVal, infoPtr->MaxVal);
317 if((infoPtr->MinVal != (INT)wParam) ||
318 (infoPtr->MaxVal != (INT)lParam)) {
319 infoPtr->MinVal = (INT)wParam;
320 infoPtr->MaxVal = (INT)lParam;
321 if(infoPtr->MaxVal <= infoPtr->MinVal)
322 infoPtr->MaxVal = infoPtr->MinVal+1;
323 PROGRESS_CoercePos(hwnd);
324 PROGRESS_Refresh (hwnd);
326 return temp;
328 case PBM_GETRANGE:
329 if (lParam){
330 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
331 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
333 return (wParam) ? infoPtr->MinVal : infoPtr->MaxVal;
335 case PBM_GETPOS:
336 if (wParam || lParam)
337 UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
338 return (infoPtr->CurVal);
340 case PBM_SETBARCOLOR:
341 if (wParam)
342 UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
343 infoPtr->ColorBar = (COLORREF)lParam;
344 PROGRESS_Refresh (hwnd);
345 break;
347 case PBM_SETBKCOLOR:
348 if (wParam)
349 UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
350 infoPtr->ColorBk = (COLORREF)lParam;
351 PROGRESS_Refresh (hwnd);
352 break;
354 default:
355 if (message >= WM_USER)
356 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
357 message, wParam, lParam );
358 return DefWindowProcA( hwnd, message, wParam, lParam );
361 return 0;
365 /***********************************************************************
366 * PROGRESS_Register [Internal]
368 * Registers the progress bar window class.
371 VOID
372 PROGRESS_Register (void)
374 WNDCLASSA wndClass;
376 ZeroMemory (&wndClass, sizeof( WNDCLASSA));
377 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
378 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
379 wndClass.cbClsExtra = 0;
380 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
381 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
382 wndClass.lpszClassName = PROGRESS_CLASSA;
384 RegisterClassA (&wndClass);
388 /***********************************************************************
389 * PROGRESS_Unregister [Internal]
391 * Unregisters the progress bar window class.
394 VOID
395 PROGRESS_Unregister (void)
397 UnregisterClassA (PROGRESS_CLASSA, (HINSTANCE)NULL);