Added location of local application data.
[wine] / dlls / comctl32 / progress.c
1 /*              
2  * Progress control
3  *
4  * Copyright 1997, 2002 Dimitrie O. Paun
5  * Copyright 1998, 1999 Eric Kohl
6  *
7  */
8
9 #include <string.h>
10 #include "winbase.h"
11 #include "commctrl.h"
12 #include "debugtools.h"
13
14 DEFAULT_DEBUG_CHANNEL(progress);
15
16 typedef struct
17 {
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;
27
28 /* Control configuration constants */
29
30 #define LED_GAP    2
31
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); 
35
36 /***********************************************************************
37  * PROGRESS_Draw
38  * Draws the progress bar.
39  */
40 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
41 {
42     HBRUSH hbrBar, hbrBk;
43     int rightBar, rightMost, ledWidth;
44     RECT rect;
45     DWORD dwStyle;
46
47     TRACE("(infoPtr=%p, hdc=%x)\n", infoPtr, hdc);
48
49     /* get the required bar brush */
50     if (infoPtr->ColorBar == CLR_DEFAULT)
51         hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
52     else
53         hbrBar = CreateSolidBrush (infoPtr->ColorBar);
54
55     /* get the required background brush */
56     if (infoPtr->ColorBk == CLR_DEFAULT)
57         hbrBk = GetSysColorBrush (COLOR_3DFACE);
58     else
59         hbrBk = CreateSolidBrush (infoPtr->ColorBk);
60
61     /* get client rectangle */
62     GetClientRect (infoPtr->Self, &rect);
63
64     /* draw the background */
65     FillRect(hdc, &rect, hbrBk);
66
67     rect.left++; rect.right--; rect.top++; rect.bottom--;
68
69     /* get the window style */
70     dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
71
72     /* compute extent of progress bar */
73     if (dwStyle & PBS_VERTICAL) {
74         rightBar  = rect.bottom - 
75                     MulDiv (infoPtr->CurVal - infoPtr->MinVal,
76                             rect.bottom - rect.top,
77                             infoPtr->MaxVal - infoPtr->MinVal);
78         ledWidth  = MulDiv (rect.right - rect.left, 2, 3);
79         rightMost = rect.top;
80     } else {
81         rightBar = rect.left + 
82                    MulDiv (infoPtr->CurVal - infoPtr->MinVal,
83                            rect.right - rect.left,
84                            infoPtr->MaxVal - infoPtr->MinVal);
85         ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
86         rightMost = rect.right;
87     }
88
89     /* now draw the bar */
90     if (dwStyle & PBS_SMOOTH) {
91         if (dwStyle & PBS_VERTICAL) 
92             rect.top = rightBar;
93         else 
94             rect.right = rightBar;
95         FillRect(hdc, &rect, hbrBar);
96     } else {
97         if (dwStyle & PBS_VERTICAL) {
98             while(rect.bottom > rightBar) { 
99                 rect.top = rect.bottom - ledWidth;
100                 if (rect.top < rightMost)
101                     rect.top = rightMost;
102                 FillRect(hdc, &rect, hbrBar);
103                 rect.bottom = rect.top - LED_GAP;
104             }
105         } else {
106             while(rect.left < rightBar) { 
107                 rect.right = rect.left + ledWidth;
108                 if (rect.right > rightMost)
109                     rect.right = rightMost;
110                 FillRect(hdc, &rect, hbrBar);
111                 rect.left  = rect.right + LED_GAP;
112             }
113         }
114     }
115
116     /* delete bar brush */
117     if (infoPtr->ColorBar != CLR_DEFAULT)
118         DeleteObject (hbrBar);
119
120     /* delete background brush */
121     if (infoPtr->ColorBk != CLR_DEFAULT)
122         DeleteObject (hbrBk);
123
124     return 0;
125 }
126
127 /***********************************************************************
128  * PROGRESS_Refresh
129  * Draw the progress bar. The background need not be erased.
130  */
131 static LRESULT PROGRESS_Refresh (PROGRESS_INFO *infoPtr)
132 {
133     HDC hdc = GetDC (infoPtr->Self);
134     LRESULT res = PROGRESS_Draw (infoPtr, hdc);
135     ReleaseDC (infoPtr->Self, hdc);
136     return res;
137 }
138
139 /***********************************************************************
140  * PROGRESS_Paint
141  * Draw the progress bar. The background need not be erased.
142  * If dc!=0, it draws on it
143  */
144 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
145 {
146     PAINTSTRUCT ps;
147     if (hdc) return PROGRESS_Draw (infoPtr, hdc);
148     hdc = BeginPaint (infoPtr->Self, &ps);
149     PROGRESS_Draw (infoPtr, hdc);
150     EndPaint (infoPtr->Self, &ps);
151     return 0;
152 }
153
154
155 /***********************************************************************
156  *           PROGRESS_CoercePos
157  * Makes sure the current position (CurVal) is within bounds.
158  */
159 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
160 {
161     if(infoPtr->CurVal < infoPtr->MinVal)
162         infoPtr->CurVal = infoPtr->MinVal;
163     if(infoPtr->CurVal > infoPtr->MaxVal)
164         infoPtr->CurVal = infoPtr->MaxVal;
165 }
166
167
168 /***********************************************************************
169  *           PROGRESS_SetFont
170  * Set new Font for progress bar
171  */
172 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
173 {
174     HFONT hOldFont = infoPtr->Font;
175     infoPtr->Font = hFont;
176     if (bRedraw) PROGRESS_Refresh (infoPtr);
177     return hOldFont;
178 }
179
180 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
181 {
182     DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
183
184     /* if nothing changes, simply return */
185     if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
186     
187     /* if things are different, adjust values and repaint the control */
188     if (high <= low) high = low + 1;
189     infoPtr->MinVal = low;
190     infoPtr->MaxVal = high;
191     PROGRESS_CoercePos(infoPtr);
192     PROGRESS_Refresh (infoPtr);
193     return res;
194 }
195
196 /***********************************************************************
197  *           ProgressWindowProc
198  */
199 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message, 
200                                   WPARAM wParam, LPARAM lParam)
201 {
202     PROGRESS_INFO *infoPtr = (PROGRESS_INFO *)GetWindowLongW(hwnd, 0);
203     DWORD dwExStyle;
204     UINT temp;
205   
206     if (!infoPtr && message != WM_CREATE && message != WM_NCCREATE)
207         return DefWindowProcW( hwnd, message, wParam, lParam ); 
208   
209     switch(message) {
210     case WM_NCCREATE:
211         dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
212         SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle | WS_EX_STATICEDGE);
213         return TRUE;
214
215     case WM_CREATE:
216         /* allocate memory for info struct */
217         infoPtr = (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
218         if (!infoPtr) return -1;
219         SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
220
221         /* initialize the info struct */
222         infoPtr->Self = hwnd;
223         infoPtr->MinVal = 0; 
224         infoPtr->MaxVal = 100;
225         infoPtr->CurVal = 0; 
226         infoPtr->Step = 10;
227         infoPtr->ColorBar = CLR_DEFAULT;
228         infoPtr->ColorBk = CLR_DEFAULT;
229         infoPtr->Font = 0;
230         TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
231         return 0;
232     
233     case WM_DESTROY:
234         TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
235         COMCTL32_Free (infoPtr);
236         SetWindowLongW(hwnd, 0, 0);
237         return 0;
238
239     case WM_ERASEBKGND:
240         /* pretend to erase it here, but we will do it in the paint
241            function to avoid flicker */
242         return TRUE;
243         
244     case WM_GETFONT:
245         return (LRESULT)infoPtr->Font;
246
247     case WM_SETFONT:
248         return PROGRESS_SetFont (infoPtr, (HFONT)wParam, (BOOL)lParam);
249
250     case WM_PAINT:
251         return PROGRESS_Paint (infoPtr, (HDC)wParam);
252     
253     case PBM_DELTAPOS:
254         if(lParam) UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
255         temp = infoPtr->CurVal;
256         if(wParam != 0) {
257             infoPtr->CurVal += (WORD)wParam;
258             PROGRESS_CoercePos (infoPtr);
259             PROGRESS_Refresh (infoPtr);
260         }
261         return temp;
262
263     case PBM_SETPOS:
264         if (lParam) UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
265         temp = infoPtr->CurVal;
266         if(temp != wParam) {
267             infoPtr->CurVal = (WORD)wParam;
268             PROGRESS_CoercePos(infoPtr);
269             PROGRESS_Refresh (infoPtr);
270         }
271         return temp;          
272       
273     case PBM_SETRANGE:
274         if (wParam) UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
275         return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
276
277     case PBM_SETSTEP:
278         if (lParam) UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
279         temp = infoPtr->Step;   
280         infoPtr->Step = (WORD)wParam;   
281         return temp;
282
283     case PBM_STEPIT:
284         if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
285         temp = infoPtr->CurVal;   
286         infoPtr->CurVal += infoPtr->Step;
287         if(infoPtr->CurVal > infoPtr->MaxVal)
288             infoPtr->CurVal = infoPtr->MinVal;
289         if(temp != infoPtr->CurVal)
290             PROGRESS_Refresh (infoPtr);
291         return temp;
292
293     case PBM_SETRANGE32:
294         return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
295     
296     case PBM_GETRANGE:
297         if (lParam) {
298             ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
299             ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
300         }
301         return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
302
303     case PBM_GETPOS:
304         if (wParam || lParam) UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
305         return infoPtr->CurVal;
306
307     case PBM_SETBARCOLOR:
308         if (wParam) UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
309         infoPtr->ColorBar = (COLORREF)lParam;     
310         return PROGRESS_Refresh (infoPtr);
311
312     case PBM_SETBKCOLOR:
313         if (wParam) UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
314         infoPtr->ColorBk = (COLORREF)lParam;
315         return PROGRESS_Refresh (infoPtr);
316
317     default: 
318         if (message >= WM_USER) 
319             ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
320         return DefWindowProcW( hwnd, message, wParam, lParam ); 
321     } 
322 }
323
324
325 /***********************************************************************
326  * PROGRESS_Register [Internal]
327  *
328  * Registers the progress bar window class.
329  */
330 VOID PROGRESS_Register (void)
331 {
332     WNDCLASSW wndClass;
333
334     ZeroMemory (&wndClass, sizeof(wndClass));
335     wndClass.style         = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
336     wndClass.lpfnWndProc   = (WNDPROC)ProgressWindowProc;
337     wndClass.cbClsExtra    = 0;
338     wndClass.cbWndExtra    = sizeof (PROGRESS_INFO *);
339     wndClass.hCursor       = LoadCursorW (0, IDC_ARROWW);
340     wndClass.lpszClassName = PROGRESS_CLASSW;
341
342     RegisterClassW (&wndClass);
343 }
344
345
346 /***********************************************************************
347  * PROGRESS_Unregister [Internal]
348  *
349  * Unregisters the progress bar window class.
350  */
351 VOID PROGRESS_Unregister (void)
352 {
353     UnregisterClassW (PROGRESS_CLASSW, (HINSTANCE)NULL);
354 }
355