root/dwt/widgets/ProgressBar.d

Revision 320:da968414c383, 16.3 kB (checked in by Frank Benoit <benoit@tionex.de>, 1 month ago)

Merge changes SWT 3.4.1

Line 
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module dwt.widgets.ProgressBar;
14
15 import dwt.widgets.Control;
16
17 import dwt.DWT;
18 import dwt.DWTException;
19 import dwt.graphics.Point;
20 import dwt.internal.win32.OS;
21
22 import dwt.widgets.Composite;
23
24 import dwt.dwthelper.utils;
25
26 /**
27  * Instances of the receiver represent an unselectable
28  * user interface object that is used to display progress,
29  * typically in the form of a bar.
30  * <dl>
31  * <dt><b>Styles:</b></dt>
32  * <dd>SMOOTH, HORIZONTAL, VERTICAL, INDETERMINATE</dd>
33  * <dt><b>Events:</b></dt>
34  * <dd>(none)</dd>
35  * </dl>
36  * <p>
37  * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
38  * </p><p>
39  * IMPORTANT: This class is intended to be subclassed <em>only</em>
40  * within the DWT implementation.
41  * </p>
42  *
43  * @see <a href="http://www.eclipse.org/swt/snippets/#progressbar">ProgressBar snippets</a>
44  * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: ControlExample</a>
45  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
46  */
47 public class ProgressBar : Control {
48
49     alias Control.computeSize computeSize;
50     alias Control.windowProc windowProc;
51
52     static const int DELAY = 100;
53     static const int TIMER_ID = 100;
54     static const int MINIMUM_WIDTH = 100;
55     private static /+const+/ WNDPROC ProgressBarProc;
56     static const TCHAR[] ProgressBarClass = OS.PROGRESS_CLASS;
57
58     private static bool static_this_completed = false;
59     private static void static_this() {
60         if( static_this_completed ){
61             return;
62         }
63         synchronized {
64             if( static_this_completed ){
65                 return;
66             }
67             WNDCLASS lpWndClass;
68             OS.GetClassInfo (null, ProgressBarClass.ptr, &lpWndClass);
69             ProgressBarProc = lpWndClass.lpfnWndProc;
70             /*
71             * Feature in Windows.  The progress bar window class
72             * does not include CS_DBLCLKS.  This means that these
73             * controls will not get double click messages such as
74             * WM_LBUTTONDBLCLK.  The fix is to register a new
75             * window class with CS_DBLCLKS.
76             *
77             * NOTE:  Screen readers look for the exact class name
78             * of the control in order to provide the correct kind
79             * of assistance.  Therefore, it is critical that the
80             * new window class have the same name.  It is possible
81             * to register a local window class with the same name
82             * as a global class.  Since bits that affect the class
83             * are being changed, it is possible that other native
84             * code, other than DWT, could create a control with
85             * this class name, and fail unexpectedly.
86             */
87             auto hInstance = OS.GetModuleHandle (null);
88             auto hHeap = OS.GetProcessHeap ();
89             lpWndClass.hInstance = hInstance;
90             lpWndClass.style &= ~OS.CS_GLOBALCLASS;
91             lpWndClass.style |= OS.CS_DBLCLKS;
92             int byteCount = (ProgressBarClass.length+1) * TCHAR.sizeof;
93             TCHAR* lpszClassName = cast(TCHAR*) OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
94             OS.MoveMemory (lpszClassName, ProgressBarClass.ptr, byteCount);
95             lpWndClass.lpszClassName = lpszClassName;
96             OS.RegisterClass (&lpWndClass);
97             OS.HeapFree (hHeap, 0, lpszClassName);
98             static_this_completed = true;
99         }
100     }
101
102 /**
103  * Constructs a new instance of this class given its parent
104  * and a style value describing its behavior and appearance.
105  * <p>
106  * The style value is either one of the style constants defined in
107  * class <code>DWT</code> which is applicable to instances of this
108  * class, or must be built by <em>bitwise OR</em>'ing together
109  * (that is, using the <code>int</code> "|" operator) two or more
110  * of those <code>DWT</code> style constants. The class description
111  * lists the style constants that are applicable to the class.
112  * Style bits are also inherited from superclasses.
113  * </p>
114  *
115  * @param parent a composite control which will be the parent of the new instance (cannot be null)
116  * @param style the style of control to construct
117  *
118  * @exception IllegalArgumentException <ul>
119  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
120  * </ul>
121  * @exception DWTException <ul>
122  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
123  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
124  * </ul>
125  *
126  * @see DWT#SMOOTH
127  * @see DWT#HORIZONTAL
128  * @see DWT#VERTICAL
129  * @see Widget#checkSubclass
130  * @see Widget#getStyle
131  */
132 public this (Composite parent, int style) {
133     static_this();
134     super (parent, checkStyle (style));
135 }
136
137 override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) {
138     if (handle is null) return 0;
139     return OS.CallWindowProc (ProgressBarProc, hwnd, msg, wParam, lParam);
140 }
141
142 static int checkStyle (int style) {
143     style |= DWT.NO_FOCUS;
144     return checkBits (style, DWT.HORIZONTAL, DWT.VERTICAL, 0, 0, 0, 0);
145 }
146
147 override public Point computeSize (int wHint, int hHint, bool changed) {
148     checkWidget ();
149     int border = getBorderWidth ();
150     int width = border * 2, height = border * 2;
151     if ((style & DWT.HORIZONTAL) !is 0) {
152         width += OS.GetSystemMetrics (OS.SM_CXHSCROLL) * 10;
153         height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
154     } else {
155         width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
156         height += OS.GetSystemMetrics (OS.SM_CYVSCROLL) * 10;
157     }
158     if (wHint !is DWT.DEFAULT) width = wHint + (border * 2);
159     if (hHint !is DWT.DEFAULT) height = hHint + (border * 2);
160     return new Point (width, height);
161 }
162
163 override void createHandle () {
164     super.createHandle ();
165     startTimer ();
166 }
167
168 override int defaultForeground () {
169     return OS.GetSysColor (OS.COLOR_HIGHLIGHT);
170 }
171
172 /**
173  * Returns the maximum value which the receiver will allow.
174  *
175  * @return the maximum
176  *
177  * @exception DWTException <ul>
178  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
179  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
180  * </ul>
181  */
182 public int getMaximum () {
183     checkWidget ();
184     return OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0);
185 }
186
187 /**
188  * Returns the minimum value which the receiver will allow.
189  *
190  * @return the minimum
191  *
192  * @exception DWTException <ul>
193  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
194  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
195  * </ul>
196  */
197 public int getMinimum () {
198     checkWidget ();
199     return OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
200 }
201
202 /**
203  * Returns the single 'selection' that is the receiver's position.
204  *
205  * @return the selection
206  *
207  * @exception DWTException <ul>
208  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
209  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
210  * </ul>
211  */
212 public int getSelection () {
213     checkWidget ();
214     return OS.SendMessage (handle, OS.PBM_GETPOS, 0, 0);
215 }
216
217 /**
218  * Returns the state of the receiver. The value will be one of:
219  * <ul>
220  *  <li>{@link DWT#NORMAL}</li>
221  *  <li>{@link DWT#ERROR}</li>
222  *  <li>{@link DWT#PAUSED}</li>
223  * </ul>
224  *
225  * @return the state
226  *
227  * @exception DWTException <ul>
228  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
229  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
230  * </ul>
231  *
232  * @since 3.4
233  */
234 public int getState () {
235     checkWidget ();
236     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
237         int state = OS.SendMessage (handle, OS.PBM_GETSTATE, 0, 0);
238         switch (state) {
239             case OS.PBST_NORMAL: return DWT.NORMAL;
240             case OS.PBST_ERROR: return DWT.ERROR;
241             case OS.PBST_PAUSED: return DWT.PAUSED;
242             default:
243         }
244     }
245     return DWT.NORMAL;
246 }
247
248 override void releaseWidget () {
249     super.releaseWidget ();
250     stopTimer ();
251 }
252
253 void startTimer () {
254     if ((style & DWT.INDETERMINATE) !is 0) {
255         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
256         if (OS.COMCTL32_MAJOR < 6 || (bits & OS.PBS_MARQUEE) is 0) {
257             OS.SetTimer (handle, TIMER_ID, DELAY, null);
258         } else {
259             OS.SendMessage (handle, OS.PBM_SETMARQUEE, 1, DELAY);
260         }
261     }
262 }
263
264 void stopTimer () {
265     if ((style & DWT.INDETERMINATE) !is 0) {
266         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
267         if (OS.COMCTL32_MAJOR < 6 || (bits & OS.PBS_MARQUEE) is 0) {
268             OS.KillTimer (handle, TIMER_ID);
269         } else {
270             OS.SendMessage (handle, OS.PBM_SETMARQUEE, 0, 0);
271         }
272     }
273 }
274
275 override void setBackgroundPixel (int pixel) {
276     if (pixel is -1) pixel = OS.CLR_DEFAULT;
277     OS.SendMessage (handle, OS.PBM_SETBKCOLOR, 0, pixel);
278 }
279
280 override void setForegroundPixel (int pixel) {
281     if (pixel is -1) pixel = OS.CLR_DEFAULT;
282     OS.SendMessage (handle, OS.PBM_SETBARCOLOR, 0, pixel);
283 }
284
285 /**
286  * Sets the maximum value that the receiver will allow.  This new
287  * value will be ignored if it is not greater than the receiver's current
288  * minimum value.  If the new maximum is applied then the receiver's
289  * selection value will be adjusted if necessary to fall within its new range.
290  *
291  * @param value the new maximum, which must be greater than the current minimum
292  *
293  * @exception DWTException <ul>
294  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
295  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
296  * </ul>
297  */
298 public void setMaximum (int value) {
299     checkWidget ();
300     int minimum = OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
301     if (0 <= minimum && minimum < value) {
302         OS.SendMessage (handle, OS.PBM_SETRANGE32, minimum, value);
303     }
304 }
305
306 /**
307  * Sets the minimum value that the receiver will allow.  This new
308  * value will be ignored if it is negative or is not less than the receiver's
309  * current maximum value.  If the new minimum is applied then the receiver's
310  * selection value will be adjusted if necessary to fall within its new range.
311  *
312  * @param value the new minimum, which must be nonnegative and less than the current maximum
313  *
314  * @exception DWTException <ul>
315  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
316  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
317  * </ul>
318  */
319 public void setMinimum (int value) {
320     checkWidget ();
321     int maximum = OS.SendMessage (handle, OS.PBM_GETRANGE, 0, 0);
322     if (0 <= value && value < maximum) {
323         OS.SendMessage (handle, OS.PBM_SETRANGE32, value, maximum);
324     }
325 }
326
327 /**
328  * Sets the single 'selection' that is the receiver's
329  * position to the argument which must be greater than or equal
330  * to zero.
331  *
332  * @param value the new selection (must be zero or greater)
333  *
334  * @exception DWTException <ul>
335  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
336  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
337  * </ul>
338  */
339 public void setSelection (int value) {
340     checkWidget ();
341     /*
342     * Feature in Vista.  When the progress bar is not in
343     * a normal state, PBM_SETPOS does not set the position
344     * of the bar when the selection is equal to the minimum.
345     * This is undocumented.  The fix is to temporarily
346     * set the state to PBST_NORMAL, set the position, then
347     * reset the state.
348     */
349     int /*long*/ state = 0;
350     bool fixSelection = false;
351     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
352         int /*long*/ minumum = OS.SendMessage (handle, OS.PBM_GETRANGE, 1, 0);
353         int /*long*/ selection = OS.SendMessage (handle, OS.PBM_GETPOS, 0, 0);
354         if (selection is minumum) {
355             fixSelection = true;
356             state = OS.SendMessage (handle, OS.PBM_GETSTATE, 0, 0);
357             OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_NORMAL, 0);
358         }
359     }
360     OS.SendMessage (handle, OS.PBM_SETPOS, value, 0);
361     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
362         if (fixSelection) OS.SendMessage (handle, OS.PBM_SETSTATE, state, 0);
363     }
364 }
365
366 /**
367  * Sets the state of the receiver. The state must be one of these values:
368  * <ul>
369  *  <li>{@link DWT#NORMAL}</li>
370  *  <li>{@link DWT#ERROR}</li>
371  *  <li>{@link DWT#PAUSED}</li>
372  * </ul>
373  *
374  * @param state the new state
375  *
376  * @exception DWTException <ul>
377  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
378  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
379  * </ul>
380  *
381  * @since 3.4
382  */
383 public void setState (int state) {
384     checkWidget ();
385     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
386         switch (state) {
387             case DWT.NORMAL:
388                 OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_NORMAL, 0);
389                 break;
390             case DWT.ERROR:
391                 OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_ERROR, 0);
392                 break;
393             case DWT.PAUSED:
394                 OS.SendMessage (handle, OS.PBM_SETSTATE, OS.PBST_PAUSED, 0);
395                 break;
396             default:
397         }
398     }
399 }
400
401 override int widgetStyle () {
402     int bits = super.widgetStyle ();
403     if ((style & DWT.SMOOTH) !is 0) bits |= OS.PBS_SMOOTH;
404     if ((style & DWT.VERTICAL) !is 0) bits |= OS.PBS_VERTICAL;
405     if ((style & DWT.INDETERMINATE) !is 0) bits |= OS.PBS_MARQUEE;
406     return bits;
407 }
408
409 override String windowClass () {
410     return TCHARsToStr( ProgressBarClass );
411 }
412
413 override int windowProc () {
414     return cast(int) ProgressBarProc;
415 }
416
417 override LRESULT WM_GETDLGCODE (int wParam, int lParam) {
418     LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
419     if (result !is null) return result;
420     /*
421     * Feature in Windows.  The progress bar does
422     * not implement WM_GETDLGCODE.  As a result,
423     * a progress bar takes focus and takes part
424     * in tab traversal.  This behavior, while
425     * unspecified, is unwanted.  The fix is to
426     * implement WM_GETDLGCODE to behave like a
427     * STATIC control.
428     */
429     return new LRESULT (OS.DLGC_STATIC);
430 }
431
432 override LRESULT WM_SIZE (int wParam, int lParam) {
433     LRESULT result = super.WM_SIZE (wParam, lParam);
434     if (result !is null) return result;
435     /*
436     * Feature in Windows.  When a progress bar with the style
437     * PBS_MARQUEE becomes too small, the animation (currently
438     * a small bar moving from right to left) does not have
439     * enough space to draw.  The result is that the progress
440     * bar does not appear to be moving.  The fix is to detect
441     * this case, clear the PBS_MARQUEE style and emulate the
442     * animation using PBM_STEPIT.
443     *
444     * NOTE:  This only happens on Window XP.
445     */
446     if ((style & DWT.INDETERMINATE) !is 0) {
447         if (OS.COMCTL32_MAJOR >= 6) {
448             forceResize ();
449             RECT rect;
450             OS.GetClientRect (handle, &rect);
451             int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE);
452             int newBits = oldBits;
453             if (rect.right - rect.left < MINIMUM_WIDTH) {
454                 newBits &= ~OS.PBS_MARQUEE;
455             } else {
456                 newBits |= OS.PBS_MARQUEE;
457             }
458             if (newBits !is oldBits) {
459                 stopTimer ();
460                 OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
461                 startTimer ();
462             }
463         }
464     }
465     return result;
466 }
467
468 override LRESULT WM_TIMER (int wParam, int lParam) {
469     LRESULT result = super.WM_TIMER (wParam, lParam);
470     if (result !is null) return result;
471     if ((style & DWT.INDETERMINATE) !is 0) {
472         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
473         if (OS.COMCTL32_MAJOR < 6 || (bits & OS.PBS_MARQUEE) is 0) {
474             if (wParam is TIMER_ID) {
475                 OS.SendMessage (handle, OS.PBM_STEPIT, 0, 0);
476             }
477         }
478     }
479     return result;
480 }
481
482 }
Note: See TracBrowser for help on using the browser.