Release 980517
[wine] / controls / progress.c
1 /*              
2  * Progress control
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  *
6  * TODO:
7  *   - I do not know what to to on WM_[SG]ET_FONT
8  */
9
10 #include "windows.h"
11 #include "progress.h"
12 #include "commctrl.h"
13 #include "heap.h"
14 #include "win.h"
15 #include "debug.h"
16
17
18 /* Control configuration constants */
19
20 #define LED_GAP    2
21
22 /* Work constants */
23
24 #define UNKNOWN_PARAM(msg, wParam, lParam) WARN(progress, \
25         "Unknown parameter(s) for message " #msg     \
26         "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam); 
27
28 #define PROGRESS_GetInfoPtr(wndPtr) ((PROGRESS_INFO *)wndPtr->wExtra[0])
29
30
31 /***********************************************************************
32  *           PROGRESS_Paint
33  * Draw the arrows. The background need not be erased.
34  * If dc!=0, it draws on it
35  */
36 static void PROGRESS_Paint(WND *wndPtr, HDC32 dc)
37 {
38   PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(wndPtr);
39   HBRUSH32 hbrBar, hbrBk;
40   int rightBar, rightMost, ledWidth;
41   PAINTSTRUCT32 ps;
42   RECT32 rect;
43   HDC32 hdc;
44
45   TRACE(progress, "paint pos=%d min=%d, max=%d\n",
46                infoPtr->CurVal, infoPtr->MinVal, infoPtr->MaxVal);
47
48   /* get a dc */
49   hdc = dc==0 ? BeginPaint32(wndPtr->hwndSelf, &ps) : dc;
50
51   /* get the required bar brush */
52   if (infoPtr->ColorBar == CLR_DEFAULT)
53     hbrBar = GetSysColorBrush32(COLOR_HIGHLIGHT);
54   else
55     hbrBar = CreateSolidBrush32 (infoPtr->ColorBar);
56
57   /* get the required background brush */
58   if (infoPtr->ColorBk == CLR_DEFAULT)
59     hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
60   else
61     hbrBk = CreateSolidBrush32 (infoPtr->ColorBk);
62
63   /* get rect for the bar, adjusted for the border */
64   GetClientRect32 (wndPtr->hwndSelf, &rect);
65
66   /* draw the border */
67   DrawEdge32(hdc, &rect, BDR_SUNKENOUTER, BF_RECT|BF_ADJUST);
68   FillRect32(hdc, &rect, hbrBk);
69
70   rect.left++; rect.right--; rect.top++; rect.bottom--;
71
72   /* compute extent of progress bar */
73   if (wndPtr->dwStyle & PBS_VERTICAL)
74   {
75     rightBar = rect.bottom - 
76       MulDiv32(infoPtr->CurVal-infoPtr->MinVal,
77                rect.bottom - rect.top,
78                infoPtr->MaxVal-infoPtr->MinVal);
79     ledWidth = MulDiv32 ((rect.right - rect.left), 2, 3);
80     rightMost = rect.top;
81   }
82   else
83   {
84     rightBar = rect.left + 
85       MulDiv32(infoPtr->CurVal-infoPtr->MinVal,
86                rect.right - rect.left,
87                infoPtr->MaxVal-infoPtr->MinVal);
88     ledWidth = MulDiv32 ((rect.bottom - rect.top), 2, 3);
89     rightMost = rect.right;
90   }
91
92   /* now draw the bar */
93   if (wndPtr->dwStyle & PBS_SMOOTH)
94   {
95     if (wndPtr->dwStyle & PBS_VERTICAL)
96       rect.top = rightBar;
97     else
98       rect.right = rightBar;
99     FillRect32(hdc, &rect, hbrBar);
100   }
101   else
102   {
103     if (wndPtr->dwStyle & PBS_VERTICAL)
104       while(rect.bottom > rightBar) { 
105         rect.top = rect.bottom-ledWidth;
106         if (rect.top < rightMost)
107           rect.top = rightMost;
108         FillRect32(hdc, &rect, hbrBar);
109         rect.bottom = rect.top-LED_GAP;
110       }
111     else
112       while(rect.left < rightBar) { 
113         rect.right = rect.left+ledWidth;
114         if (rect.right > rightMost)
115           rect.right = rightMost;
116         FillRect32(hdc, &rect, hbrBar);
117         rect.left  = rect.right+LED_GAP;
118       }
119   }
120
121   /* delete bar brush */
122   if (infoPtr->ColorBar != CLR_DEFAULT)
123       DeleteObject32 (hbrBar);
124
125   /* delete background brush */
126   if (infoPtr->ColorBk != CLR_DEFAULT)
127       DeleteObject32 (hbrBk);
128
129   /* clean-up */  
130   if(!dc)
131     EndPaint32(wndPtr->hwndSelf, &ps);
132 }
133
134 /***********************************************************************
135  *           PROGRESS_CoercePos
136  * Makes sure the current position (CUrVal) is within bounds.
137  */
138 static void PROGRESS_CoercePos(WND *wndPtr)
139 {
140   PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(wndPtr); 
141
142   if(infoPtr->CurVal < infoPtr->MinVal)
143     infoPtr->CurVal = infoPtr->MinVal;
144   if(infoPtr->CurVal > infoPtr->MaxVal)
145     infoPtr->CurVal = infoPtr->MaxVal;
146 }
147
148 /***********************************************************************
149  *           ProgressWindowProc
150  */
151 LRESULT WINAPI ProgressWindowProc(HWND32 hwnd, UINT32 message, 
152                                   WPARAM32 wParam, LPARAM lParam)
153 {
154   WND *wndPtr = WIN_FindWndPtr(hwnd);
155   PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(wndPtr); 
156   UINT32 temp;
157
158   switch(message)
159     {
160     case WM_CREATE:
161       /* allocate memory for info struct */
162       wndPtr->wExtra[0] = HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
163                                      sizeof(PROGRESS_INFO));
164       infoPtr = (PROGRESS_INFO *)wndPtr->wExtra[0];
165       /* initialize the info struct */
166       infoPtr->MinVal=0; 
167       infoPtr->MaxVal=100;
168       infoPtr->CurVal=0; 
169       infoPtr->Step=10;
170       infoPtr->ColorBar=CLR_DEFAULT;
171       infoPtr->ColorBk=CLR_DEFAULT;
172       TRACE(updown, "Progress Ctrl creation, hwnd=%04x\n", hwnd);
173       break;
174     
175     case WM_DESTROY:
176       TRACE(updown, "Progress Ctrl destruction, hwnd=%04x\n", hwnd);
177       HeapFree (SystemHeap, 0, infoPtr);
178       break;
179
180     case WM_ERASEBKGND:
181       /* pretend to erase it here, but we will do it in the paint
182          function to avoid flicker */
183       return 1;
184         
185     case WM_GETFONT:
186       /* FIXME: What do we need to do? */
187       break;
188
189     case WM_SETFONT:
190       /* FIXME: What do we need to do? */
191       break;
192
193     case WM_PAINT:
194       PROGRESS_Paint(wndPtr, wParam);
195       break;
196     
197     case PBM_DELTAPOS:
198       if(lParam)
199         UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
200       temp = infoPtr->CurVal;
201       if(wParam != 0){
202         infoPtr->CurVal += (UINT16)wParam;
203         PROGRESS_CoercePos(wndPtr);
204         InvalidateRect32 (hwnd, NULL, FALSE);
205         UpdateWindow32 (hwnd);
206       }
207       return temp;
208
209     case PBM_SETPOS:
210       if (lParam)
211         UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
212       temp = infoPtr->CurVal;
213       if(temp != wParam){
214         infoPtr->CurVal = (UINT16)wParam;
215         PROGRESS_CoercePos(wndPtr);
216         InvalidateRect32 (hwnd, NULL, FALSE);
217         UpdateWindow32 (hwnd);
218       }
219       return temp;          
220       
221     case PBM_SETRANGE:
222       if (wParam)
223         UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
224       temp = MAKELONG(infoPtr->MinVal, infoPtr->MaxVal);
225       if(temp != lParam){
226         infoPtr->MinVal = LOWORD(lParam); 
227         infoPtr->MaxVal = HIWORD(lParam);
228         if(infoPtr->MaxVal <= infoPtr->MinVal)
229           infoPtr->MaxVal = infoPtr->MinVal+1;
230         PROGRESS_CoercePos(wndPtr);
231         InvalidateRect32 (hwnd, NULL, FALSE);
232         UpdateWindow32 (hwnd);
233       }
234       return temp;
235
236     case PBM_SETSTEP:
237       if (lParam)
238         UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
239       temp = infoPtr->Step;   
240       infoPtr->Step = (UINT16)wParam;   
241       return temp;
242
243     case PBM_STEPIT:
244       if (wParam || lParam)
245         UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
246       temp = infoPtr->CurVal;   
247       infoPtr->CurVal += infoPtr->Step;
248       if(infoPtr->CurVal > infoPtr->MaxVal)
249         infoPtr->CurVal = infoPtr->MinVal;
250       if(temp != infoPtr->CurVal)
251       {
252         InvalidateRect32 (hwnd, NULL, FALSE);
253         UpdateWindow32 (hwnd);
254       }
255       return temp;
256
257     case PBM_SETRANGE32:
258       temp = MAKELONG(infoPtr->MinVal, infoPtr->MaxVal);
259       if((infoPtr->MinVal != (INT32)wParam) ||
260          (infoPtr->MaxVal != (INT32)lParam)) {
261         infoPtr->MinVal = (INT32)wParam;
262         infoPtr->MaxVal = (INT32)lParam;
263         if(infoPtr->MaxVal <= infoPtr->MinVal)
264           infoPtr->MaxVal = infoPtr->MinVal+1;
265         PROGRESS_CoercePos(wndPtr);
266         InvalidateRect32 (hwnd, NULL, FALSE);
267         UpdateWindow32 (hwnd);
268       }
269       return temp;
270     
271     case PBM_GETRANGE:
272       if (lParam){
273         ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
274         ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
275       }
276       return (wParam) ? infoPtr->MinVal : infoPtr->MaxVal;
277
278     case PBM_GETPOS:
279       if (wParam || lParam)
280         UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
281       return (infoPtr->CurVal);
282
283     case PBM_SETBARCOLOR:
284       if (wParam)
285         UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
286       infoPtr->ColorBar = (COLORREF)lParam;     
287       InvalidateRect32 (hwnd, NULL, FALSE);
288       UpdateWindow32 (hwnd);
289       break;
290
291     case PBM_SETBKCOLOR:
292       if (wParam)
293         UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
294       infoPtr->ColorBk = (COLORREF)lParam;
295       InvalidateRect32 (hwnd, NULL, FALSE);
296       UpdateWindow32 (hwnd);
297       break;
298
299     default: 
300       if (message >= WM_USER) 
301         ERR(progress, "unknown msg %04x wp=%04x lp=%08lx\n", 
302                     message, wParam, lParam );
303       return DefWindowProc32A( hwnd, message, wParam, lParam ); 
304     } 
305
306     return 0;
307 }
308
309
310 /***********************************************************************
311  *           PROGRESS_Register [Internal]
312  *
313  * Registers the progress bar window class.
314  * 
315  */
316 void PROGRESS_Register(void)
317 {
318     WNDCLASS32A wndClass;
319
320     if( GlobalFindAtom32A( PROGRESS_CLASS32A ) ) return;
321
322     ZeroMemory( &wndClass, sizeof( WNDCLASS32A ) );
323     wndClass.style         = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
324     wndClass.lpfnWndProc   = (WNDPROC32)ProgressWindowProc;
325     wndClass.cbClsExtra    = 0;
326     wndClass.cbWndExtra    = sizeof(PROGRESS_INFO *);
327     wndClass.hCursor       = LoadCursor32A( 0, IDC_ARROW32A );
328     wndClass.lpszClassName = PROGRESS_CLASS32A;
329
330     RegisterClass32A( &wndClass );
331 }
332