source: trunk/src/comctl32/progress.cpp@ 3830

Last change on this file since 3830 was 3415, checked in by cbratschi, 25 years ago

* empty log message *

File size: 14.5 KB
Line 
1/* $Id: progress.cpp,v 1.3 2000-04-17 17:04:13 cbratschi Exp $ */
2/*
3 * Progress control
4 *
5 * Copyright 1997 Dimitrie O. Paun
6 * Copyright 1998, 1999 Eric Kohl
7 * Copyright 1999 Achim Hasenmueller
8 * Copyright 1999 Christoph Bratschi (cbratschi@datacomm.ch)
9 *
10 * Status: complete
11 * Version: 5.80
12 */
13
14#include "winbase.h"
15#include "commctrl.h"
16#include "ccbase.h"
17#include "progress.h"
18#include "comctl32.h"
19
20/* Control configuration constants */
21
22#define LED_GAP 2
23#define BORDER_WIDTH 1
24
25#define PROGRESS_GetInfoPtr(hwnd) ((PROGRESS_INFO*)getInfoPtr(hwnd))
26
27
28/***********************************************************************
29 * PROGRESS_Draw
30 * Draws the progress bar.
31 */
32static void
33PROGRESS_Draw (HWND hwnd, HDC hdc, INT lastVal, BOOL inUpdate)
34{
35 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
36 HBRUSH hbrBar,hbrBk,hbrLight,hbrShadow,hbrOld;
37 int rightBar, rightMost, ledWidth;
38 int lastBar;
39 RECT rect;
40 DWORD dwStyle;
41
42 if (infoPtr->MinVal == infoPtr->MaxVal) return; //Prevent division through 0
43
44 /* get the required bar brush */
45 if (infoPtr->ColorBar == CLR_DEFAULT) hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
46 else hbrBar = CreateSolidBrush (infoPtr->ColorBar);
47
48 /* get the required background brush */
49 if (infoPtr->ColorBk == CLR_DEFAULT) hbrBk = GetSysColorBrush(COLOR_3DFACE);
50 else hbrBk = CreateSolidBrush(infoPtr->ColorBk);
51
52 /* get client rectangle */
53 GetClientRect (hwnd, &rect);
54
55 /* draw the background */
56 if (!inUpdate) FillRect(hdc, &rect, hbrBk);
57
58 rect.left += BORDER_WIDTH;
59 rect.right -= BORDER_WIDTH;
60 rect.top += BORDER_WIDTH;
61 rect.bottom -= BORDER_WIDTH;
62
63 /* get the window style */
64 dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
65
66 /* compute extent of progress bar */
67 if (dwStyle & PBS_VERTICAL)
68 {
69 rightBar = rect.bottom-MulDiv(infoPtr->CurVal-infoPtr->MinVal,rect.bottom-rect.top,infoPtr->MaxVal-infoPtr->MinVal);
70 if (inUpdate) lastBar = rect.bottom-MulDiv(lastVal-infoPtr->MinVal,rect.bottom-rect.top,infoPtr->MaxVal-infoPtr->MinVal);
71 ledWidth = MulDiv ((rect.right - rect.left), 2, 3);
72 rightMost = rect.top;
73 }
74 else
75 {
76 rightBar = rect.left+MulDiv(infoPtr->CurVal-infoPtr->MinVal,rect.right-rect.left,infoPtr->MaxVal-infoPtr->MinVal);
77 if (inUpdate) lastBar = rect.left+MulDiv(lastVal-infoPtr->MinVal,rect.right-rect.left,infoPtr->MaxVal-infoPtr->MinVal);
78 ledWidth = MulDiv ((rect.bottom - rect.top), 2, 3);
79 rightMost = rect.right;
80 }
81
82 /* now draw the bar */
83 if (dwStyle & PBS_SMOOTH)
84 {
85 if (dwStyle & PBS_VERTICAL)
86 {
87 if (inUpdate)
88 {
89 if (infoPtr->CurVal > lastVal)
90 {
91 rect.top = rightBar;
92 rect.bottom = lastBar;
93 FillRect(hdc,&rect,hbrBar);
94 } else if (infoPtr->CurVal < lastVal)
95 {
96 rect.top = lastBar;
97 rect.bottom = rightBar;
98 FillRect(hdc,&rect,hbrBk);
99 }
100 } else
101 {
102 rect.top = rightBar;
103 FillRect(hdc,&rect,hbrBar);
104 }
105 } else //Horizontal
106 {
107 if (inUpdate)
108 {
109 if (infoPtr->CurVal > lastVal)
110 {
111 rect.left = lastBar;
112 rect.right = rightBar;
113 FillRect(hdc,&rect,hbrBar);
114 } else if (infoPtr->CurVal < lastVal)
115 {
116 rect.left = rightBar;
117 rect.right = lastBar;
118 FillRect(hdc,&rect,hbrBk);
119 }
120 } else
121 {
122 rect.right = rightBar;
123 FillRect(hdc,&rect,hbrBar);
124 }
125 }
126 } else
127 {
128 if (dwStyle & PBS_VERTICAL)
129 {
130 if (inUpdate)
131 {
132 if (infoPtr->CurVal > lastVal)
133 {
134 rect.bottom -= ((int)(rect.bottom-lastBar)/(ledWidth+LED_GAP))*(ledWidth+LED_GAP);
135 while(rect.bottom > rightBar)
136 {
137 rect.top = rect.bottom-ledWidth;
138 if (rect.top < rightMost) rect.top = rightMost;
139 FillRect(hdc,&rect,hbrBar);
140 rect.bottom = rect.top-LED_GAP;
141 }
142 } else if (infoPtr->CurVal < lastVal)
143 {
144 rect.top = rect.bottom-((int)(rect.bottom-lastBar)/(ledWidth+LED_GAP))*(ledWidth+LED_GAP)-ledWidth;
145 if (rect.top < rightMost) rect.top = rightMost;
146 rect.bottom -= ((int)(rect.bottom-rightBar)/(ledWidth+LED_GAP))*(ledWidth+LED_GAP);
147 FillRect(hdc,&rect,hbrBk);
148 }
149 } else
150 {
151 while(rect.bottom > rightBar)
152 {
153 rect.top = rect.bottom-ledWidth;
154 if (rect.top < rightMost) rect.top = rightMost;
155 FillRect(hdc,&rect,hbrBar);
156 rect.bottom = rect.top-LED_GAP;
157 }
158 }
159 } else //Horizontal
160 {
161 if (inUpdate)
162 {
163 if (infoPtr->CurVal > lastVal)
164 {
165 rect.left += ((int)(lastBar-rect.left)/(ledWidth+LED_GAP))*(ledWidth+LED_GAP);
166 while(rect.left < rightBar)
167 {
168 rect.right = rect.left+ledWidth;
169 if (rect.right > rightMost) rect.right = rightMost;
170 FillRect(hdc,&rect,hbrBar);
171 rect.left = rect.right+LED_GAP;
172 }
173 } else if (infoPtr->CurVal < lastVal)
174 {
175 rect.right = rect.left+((int)(lastBar-rect.left)/(ledWidth+LED_GAP))*(ledWidth+LED_GAP)+ledWidth;
176 if (rect.right > rightMost) rect.right = rightMost;
177 rect.left += ((int)(rightBar-rect.left)/(ledWidth+LED_GAP))*(ledWidth+LED_GAP);
178 FillRect(hdc,&rect,hbrBk);
179 }
180 } else
181 {
182 while(rect.left < rightBar)
183 {
184 rect.right = rect.left+ledWidth;
185 if (rect.right > rightMost) rect.right = rightMost;
186 FillRect(hdc,&rect,hbrBar);
187 rect.left = rect.right+LED_GAP;
188 }
189 }
190 }
191 }
192
193 /* delete bar brush */
194 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar);
195
196 /* delete background brush */
197 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk);
198}
199
200/***********************************************************************
201 * PROGRESS_Update (prototype, todo)
202 * Updates only the changed pixels -> faster, no flickering
203 */
204static void PROGRESS_Update(HWND hwnd,INT lastVal)
205{
206 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
207 HDC hdc;
208
209 if (lastVal != infoPtr->CurVal) //Only update if really necessary
210 {
211 hdc = GetDC(hwnd);
212 PROGRESS_Draw(hwnd,hdc,lastVal,TRUE);
213 ReleaseDC(hwnd,hdc);
214 }
215}
216
217/***********************************************************************
218 * PROGRESS_Refresh
219 * Draw the progress bar. The background need not be erased.
220 */
221static void
222PROGRESS_Refresh (HWND hwnd)
223{
224 HDC hdc;
225
226 hdc = GetDC (hwnd);
227 PROGRESS_Draw (hwnd, hdc, 0, FALSE);
228 ReleaseDC (hwnd, hdc);
229}
230
231/***********************************************************************
232 * PROGRESS_Paint
233 * Draw the progress bar. The background need not be erased.
234 * If dc!=0, it draws on it
235 */
236static void
237PROGRESS_Paint (HWND hwnd)
238{
239 PAINTSTRUCT ps;
240 HDC hdc;
241
242 hdc = BeginPaint (hwnd, &ps);
243 PROGRESS_Draw (hwnd, hdc, 0, FALSE);
244 EndPaint (hwnd, &ps);
245}
246
247
248/***********************************************************************
249 * PROGRESS_CoercePos
250 * Makes sure the current position (CUrVal) is within bounds.
251 */
252static void PROGRESS_CoercePos(HWND hwnd)
253{
254 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
255
256 if(infoPtr->CurVal < infoPtr->MinVal)
257 infoPtr->CurVal = infoPtr->MinVal;
258 if(infoPtr->CurVal > infoPtr->MaxVal)
259 infoPtr->CurVal = infoPtr->MaxVal;
260}
261
262
263static LRESULT PROGRESS_NCCreate(HWND hwnd,WPARAM wParam,LPARAM lParam)
264{
265 DWORD dwExStyle;
266
267 dwExStyle = GetWindowLongA(hwnd,GWL_EXSTYLE);
268 SetWindowLongA(hwnd,GWL_EXSTYLE,dwExStyle | WS_EX_STATICEDGE);
269
270 return TRUE;
271}
272
273static LRESULT PROGRESS_Create(HWND hwnd,WPARAM wParam,LPARAM lParam)
274{
275 PROGRESS_INFO *infoPtr;
276
277 /* allocate memory for info struct */
278 infoPtr = (PROGRESS_INFO*)initControl(hwnd,sizeof(PROGRESS_INFO));
279 SetWindowLongA(hwnd,0,(DWORD)infoPtr);
280
281 /* initialize the info struct */
282 infoPtr->MinVal = 0;
283 infoPtr->MaxVal = 100;
284 infoPtr->CurVal = 0;
285 infoPtr->Step = 10;
286 infoPtr->ColorBar = CLR_DEFAULT;
287 infoPtr->ColorBk = CLR_DEFAULT;
288 infoPtr->hFont = (HANDLE)NULL;
289
290 return 0;
291}
292
293static LRESULT PROGRESS_Destroy(HWND hwnd,WPARAM wParam,LPARAM lParam)
294{
295 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
296
297 doneControl(hwnd);
298
299 return 0;
300}
301
302static LRESULT PROGRESS_GetFont(HWND hwnd,WPARAM wParam,LPARAM lParam)
303{
304 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
305
306 return (LRESULT)infoPtr->hFont;
307}
308
309/***********************************************************************
310 * PROGRESS_SetFont
311 * Set new Font for progress bar
312 */
313static HFONT PROGRESS_SetFont (HWND hwnd,WPARAM wParam,LPARAM lParam)
314{
315 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
316 HFONT hOldFont = infoPtr->hFont;
317
318 infoPtr->hFont = (HFONT)wParam;
319 if (LOWORD(lParam)) PROGRESS_Refresh (hwnd);
320
321 return hOldFont;
322}
323
324static LRESULT PROGRESS_DeltaPos(HWND hwnd,WPARAM wParam,LPARAM lParam)
325{
326 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
327 INT temp;
328
329 temp = infoPtr->CurVal;
330 if (wParam != 0)
331 {
332 infoPtr->CurVal += (INT)wParam;
333 PROGRESS_CoercePos(hwnd);
334 PROGRESS_Update(hwnd,temp);
335 }
336
337 return temp;
338}
339
340static LRESULT PROGRESS_SetPos(HWND hwnd,WPARAM wParam,LPARAM lParam)
341{
342 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
343 INT temp;
344
345 temp = infoPtr->CurVal;
346 if (temp != wParam)
347 {
348 infoPtr->CurVal = (UINT16)wParam; //CB: 0..65535 allowed
349 PROGRESS_CoercePos(hwnd);
350 PROGRESS_Update(hwnd,temp);
351 }
352
353 return temp;
354}
355
356static LRESULT PROGRESS_SetRange(HWND hwnd,WPARAM wParam,LPARAM lParam)
357{
358 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
359 INT temp;
360
361 temp = MAKELONG(infoPtr->MinVal,infoPtr->MaxVal);
362 if (temp != lParam)
363 {
364 infoPtr->MinVal = LOWORD(lParam);
365 infoPtr->MaxVal = HIWORD(lParam);
366 if (infoPtr->MaxVal <= infoPtr->MinVal) infoPtr->MaxVal = infoPtr->MinVal+1;
367 PROGRESS_CoercePos(hwnd);
368 PROGRESS_Refresh(hwnd);
369 }
370
371 return temp;
372}
373
374static LRESULT PROGRESS_SetStep(HWND hwnd,WPARAM wParam,LPARAM lParam)
375{
376 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
377 INT temp;
378
379 temp = infoPtr->Step;
380 infoPtr->Step = (INT)wParam; //CB: negative steps allowed
381
382 return temp;
383}
384
385static LRESULT PROGRESS_StepIt(HWND hwnd,WPARAM wParam,LPARAM lParam)
386{
387 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
388 INT temp;
389
390 temp = infoPtr->CurVal;
391 infoPtr->CurVal += infoPtr->Step;
392 if(infoPtr->CurVal > infoPtr->MaxVal) infoPtr->CurVal = infoPtr->MinVal;
393 if(temp != infoPtr->CurVal) PROGRESS_Update (hwnd,temp);
394
395 return temp;
396}
397
398static LRESULT PROGRESS_SetRange32(HWND hwnd,WPARAM wParam,LPARAM lParam)
399{
400 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
401 INT temp;
402
403 temp = MAKELONG(infoPtr->MinVal,infoPtr->MaxVal);
404 if((infoPtr->MinVal != (INT)wParam) || (infoPtr->MaxVal != (INT)lParam))
405 {
406 infoPtr->MinVal = (INT)wParam;
407 infoPtr->MaxVal = (INT)lParam;
408 if(infoPtr->MaxVal <= infoPtr->MinVal) infoPtr->MaxVal = infoPtr->MinVal+1;
409 PROGRESS_CoercePos(hwnd);
410 PROGRESS_Refresh(hwnd);
411 }
412
413 return temp;
414}
415
416static LRESULT PROGRESS_GetRange(HWND hwnd,WPARAM wParam,LPARAM lParam)
417{
418 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
419
420 if (lParam)
421 {
422 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
423 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
424 }
425
426 return (wParam) ? infoPtr->MinVal : infoPtr->MaxVal;
427}
428
429static LRESULT PROGRESS_GetPos(HWND hwnd,WPARAM wParam,LPARAM lParam)
430{
431 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
432
433 return (infoPtr->CurVal);
434}
435
436static LRESULT PROGRESS_SetBarColor(HWND hwnd,WPARAM wParam,LPARAM lParam)
437{
438 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
439 COLORREF oldColorBar = infoPtr->ColorBar;
440
441 infoPtr->ColorBar = (COLORREF)lParam;
442 if (infoPtr->ColorBar != oldColorBar) PROGRESS_Refresh(hwnd);
443
444 return 0;
445}
446
447static LRESULT PROGRESS_SetBkColor(HWND hwnd,WPARAM wParam,LPARAM lParam)
448{
449 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
450 COLORREF oldColorBk = infoPtr->ColorBk;
451
452 infoPtr->ColorBk = (COLORREF)lParam;
453 if (infoPtr->ColorBk != oldColorBk) PROGRESS_Refresh (hwnd);
454
455 return 0;
456}
457
458/***********************************************************************
459 * ProgressWindowProc
460 */
461static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
462 WPARAM wParam, LPARAM lParam)
463{
464 switch(message)
465 {
466 case WM_NCCREATE:
467 return PROGRESS_NCCreate(hwnd,wParam,lParam);
468
469 case WM_CREATE:
470 return PROGRESS_Create(hwnd,wParam,lParam);
471
472 case WM_DESTROY:
473 return PROGRESS_Destroy(hwnd,wParam,lParam);
474
475 case WM_ERASEBKGND:
476 /* pretend to erase it here, but we will do it in the paint
477 function to avoid flicker */
478 return 1;
479
480 case WM_GETFONT:
481 return PROGRESS_GetFont(hwnd,wParam,lParam);
482
483 case WM_SETFONT:
484 return PROGRESS_SetFont (hwnd,wParam,lParam);
485
486 case WM_PAINT:
487 PROGRESS_Paint(hwnd);
488 break;
489
490 case PBM_DELTAPOS:
491 return PROGRESS_DeltaPos(hwnd,wParam,lParam);
492
493 case PBM_SETPOS:
494 return PROGRESS_SetPos(hwnd,wParam,lParam);
495
496 case PBM_SETRANGE:
497 return PROGRESS_SetRange(hwnd,wParam,lParam);
498
499 case PBM_SETSTEP:
500 return PROGRESS_SetStep(hwnd,wParam,lParam);
501
502 case PBM_STEPIT:
503 return PROGRESS_StepIt(hwnd,wParam,lParam);
504
505 case PBM_SETRANGE32:
506 return PROGRESS_SetRange32(hwnd,wParam,lParam);
507
508 case PBM_GETRANGE:
509 return PROGRESS_GetRange(hwnd,wParam,lParam);
510
511 case PBM_GETPOS:
512 return PROGRESS_GetPos(hwnd,wParam,lParam);
513
514 case PBM_SETBARCOLOR:
515 return PROGRESS_SetBarColor(hwnd,wParam,lParam);
516
517 case PBM_SETBKCOLOR:
518 return PROGRESS_SetBkColor(hwnd,wParam,lParam);
519
520 default:
521 //if (message >= WM_USER)
522 //ERR(progress, "unknown msg %04x wp=%04x lp=%08lx\n",
523 // message, wParam, lParam );
524 return defComCtl32ProcA( hwnd, message, wParam, lParam );
525 }
526
527 return 0;
528}
529
530
531/***********************************************************************
532 * PROGRESS_Register [Internal]
533 *
534 * Registers the progress bar window class.
535 */
536
537VOID
538PROGRESS_Register (VOID)
539{
540 WNDCLASSA wndClass;
541
542 ZeroMemory (&wndClass, sizeof( WNDCLASSA));
543 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
544 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
545 wndClass.cbClsExtra = 0;
546 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
547 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
548 wndClass.lpszClassName = PROGRESS_CLASSA;
549
550 RegisterClassA(&wndClass);
551}
552
553
554/***********************************************************************
555 * PROGRESS_Unregister [Internal]
556 *
557 * Unregisters the progress bar window class.
558 */
559
560VOID
561PROGRESS_Unregister (VOID)
562{
563 UnregisterClassA(PROGRESS_CLASSA, (HINSTANCE)NULL);
564}
565
Note: See TracBrowser for help on using the repository browser.