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

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

trackbar buddy fix, tooltip enhancements

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