root/dwt/widgets/ScrollBar.d

Revision 246:fd9c62a2998e, 32.2 kB (checked in by Frank Benoit <benoit@tionex.de>, 5 months ago)

Updater SWT 3.4M7 to 3.4

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.ScrollBar;
14
15 import dwt.DWT;
16 import dwt.DWTException;
17 import dwt.events.SelectionEvent;
18 import dwt.events.SelectionListener;
19 import dwt.graphics.Point;
20 import dwt.graphics.Rectangle;
21 import dwt.internal.win32.OS;
22
23 import dwt.widgets.Widget;
24 import dwt.widgets.TypedListener;
25 import dwt.widgets.Event;
26 import dwt.widgets.Scrollable;
27
28 import dwt.dwthelper.utils;
29 import tango.util.log.Trace;
30 void trc( long line ){
31     //Trace.formatln( "ScrollBar {}", line );
32 }
33
34 /**
35  * Instances of this class are selectable user interface
36  * objects that represent a range of positive, numeric values.
37  * <p>
38  * At any given moment, a given scroll bar will have a
39  * single 'selection' that is considered to be its
40  * value, which is constrained to be within the range of
41  * values the scroll bar represents (that is, between its
42  * <em>minimum</em> and <em>maximum</em> values).
43  * </p><p>
44  * Typically, scroll bars will be made up of five areas:
45  * <ol>
46  * <li>an arrow button for decrementing the value</li>
47  * <li>a page decrement area for decrementing the value by a larger amount</li>
48  * <li>a <em>thumb</em> for modifying the value by mouse dragging</li>
49  * <li>a page increment area for incrementing the value by a larger amount</li>
50  * <li>an arrow button for incrementing the value</li>
51  * </ol>
52  * Based on their style, scroll bars are either <code>HORIZONTAL</code>
53  * (which have a left facing button for decrementing the value and a
54  * right facing button for incrementing it) or <code>VERTICAL</code>
55  * (which have an upward facing button for decrementing the value
56  * and a downward facing buttons for incrementing it).
57  * </p><p>
58  * On some platforms, the size of the scroll bar's thumb can be
59  * varied relative to the magnitude of the range of values it
60  * represents (that is, relative to the difference between its
61  * maximum and minimum values). Typically, this is used to
62  * indicate some proportional value such as the ratio of the
63  * visible area of a document to the total amount of space that
64  * it would take to display it. DWT supports setting the thumb
65  * size even if the underlying platform does not, but in this
66  * case the appearance of the scroll bar will not change.
67  * </p><p>
68  * Scroll bars are created by specifying either <code>H_SCROLL</code>,
69  * <code>V_SCROLL</code> or both when creating a <code>Scrollable</code>.
70  * They are accessed from the <code>Scrollable</code> using
71  * <code>getHorizontalBar</code> and <code>getVerticalBar</code>.
72  * </p><p>
73  * Note: Scroll bars are not Controls.  On some platforms, scroll bars
74  * that appear as part of some standard controls such as a text or list
75  * have no operating system resources and are not children of the control.
76  * For this reason, scroll bars are treated specially.  To create a control
77  * that looks like a scroll bar but has operating system resources, use
78  * <code>Slider</code>.
79  * </p>
80  * <dl>
81  * <dt><b>Styles:</b></dt>
82  * <dd>HORIZONTAL, VERTICAL</dd>
83  * <dt><b>Events:</b></dt>
84  * <dd>Selection</dd>
85  * </dl>
86  * <p>
87  * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
88  * </p><p>
89  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
90  * </p>
91  *
92  * @see Slider
93  * @see Scrollable
94  * @see Scrollable#getHorizontalBar
95  * @see Scrollable#getVerticalBar
96  * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: ControlExample</a>
97  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
98  */
99
100 public class ScrollBar : Widget {
101     Scrollable parent;
102     int increment, pageIncrement;
103
104 /**
105  * Constructs a new instance of this class given its parent
106  * and a style value describing its behavior and appearance.
107  * <p>
108  * The style value is either one of the style constants defined in
109  * class <code>DWT</code> which is applicable to instances of this
110  * class, or must be built by <em>bitwise OR</em>'ing together
111  * (that is, using the <code>int</code> "|" operator) two or more
112  * of those <code>DWT</code> style constants. The class description
113  * lists the style constants that are applicable to the class.
114  * Style bits are also inherited from superclasses.
115  * </p>
116  *
117  * @param parent a composite control which will be the parent of the new instance (cannot be null)
118  * @param style the style of control to construct
119  *
120  * @exception IllegalArgumentException <ul>
121  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
122  * </ul>
123  * @exception DWTException <ul>
124  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
125  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
126  * </ul>
127  *
128  * @see DWT#HORIZONTAL
129  * @see DWT#VERTICAL
130  * @see Widget#checkSubclass
131  * @see Widget#getStyle
132  */
133 this (Scrollable parent, int style) {
134     super (parent, checkStyle (style));
135     this.parent = parent;
136     createWidget ();
137 }
138
139 /**
140  * Adds the listener to the collection of listeners who will
141  * be notified when the user changes the receiver's value, by sending
142  * it one of the messages defined in the <code>SelectionListener</code>
143  * interface.
144  * <p>
145  * When <code>widgetSelected</code> is called, the event object detail field contains one of the following values:
146  * <code>DWT.NONE</code> - for the end of a drag.
147  * <code>DWT.DRAG</code>.
148  * <code>DWT.HOME</code>.
149  * <code>DWT.END</code>.
150  * <code>DWT.ARROW_DOWN</code>.
151  * <code>DWT.ARROW_UP</code>.
152  * <code>DWT.PAGE_DOWN</code>.
153  * <code>DWT.PAGE_UP</code>.
154  * <code>widgetDefaultSelected</code> is not called.
155  * </p>
156  *
157  * @param listener the listener which should be notified when the user changes the receiver's value
158  *
159  * @exception IllegalArgumentException <ul>
160  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
161  * </ul>
162  * @exception DWTException <ul>
163  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
164  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
165  * </ul>
166  *
167  * @see SelectionListener
168  * @see #removeSelectionListener
169  * @see SelectionEvent
170  */
171 public void addSelectionListener (SelectionListener listener) {
172     checkWidget();
173     if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
174     TypedListener typedListener = new TypedListener(listener);
175     addListener (DWT.Selection,typedListener);
176     addListener (DWT.DefaultSelection,typedListener);
177 }
178
179 static int checkStyle (int style) {
180     return checkBits (style, DWT.HORIZONTAL, DWT.VERTICAL, 0, 0, 0, 0);
181 }
182
183 void createWidget () {
184     increment = 1;
185     pageIncrement = 10;
186     /*
187     * Do not set the initial values of the maximum
188     * or the thumb.  These values normally default
189     * to 100 and 10 but may have been set already
190     * by the widget that owns the scroll bar.  For
191     * example, a scroll bar that is created for a
192     * list widget, setting these defaults would
193     * override the initial values provided by the
194     * list widget.
195     */
196 }
197
198 override void destroyWidget () {
199     auto hwnd = hwndScrollBar ();
200     auto type = scrollBarType ();
201     static if (OS.IsWinCE) {
202         SCROLLINFO info;
203         info.cbSize = SCROLLINFO.sizeof;
204         info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
205         info.nPage = 101;
206         info.nMax = 100;
207         info.nMin = 0;
208         OS.SetScrollInfo (hwnd, type, &info, true);
209     } else {
210         OS.ShowScrollBar (hwnd, type, false);
211     }
212     parent.destroyScrollBar (style);
213     releaseHandle ();
214     //This code is intentionally commented
215     //parent.sendEvent (DWT.Resize);
216 }
217
218 Rectangle getBounds () {
219 //  checkWidget ();
220     parent.forceResize ();
221     RECT rect;
222     OS.GetClientRect (parent.scrolledHandle (), &rect);
223     int x = 0, y = 0, width, height;
224     if ((style & DWT.HORIZONTAL) !is 0) {
225         y = rect.bottom - rect.top;
226         width = rect.right - rect.left;
227         height = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
228     } else {
229         x = rect.right - rect.left;
230         width = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
231         height = rect.bottom - rect.top;
232     }
233     return new Rectangle (x, y, width, height);
234 }
235
236 /**
237  * Returns <code>true</code> if the receiver is enabled, and
238  * <code>false</code> otherwise. A disabled control is typically
239  * not selectable from the user interface and draws with an
240  * inactive or "grayed" look.
241  *
242  * @return the receiver's enabled state
243  *
244  * @exception DWTException <ul>
245  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
246  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
247  * </ul>
248  *
249  * @see #isEnabled
250  */
251 public bool getEnabled () {
252     checkWidget();
253     return (state & DISABLED) is 0;
254 }
255
256 /**
257  * Returns the amount that the receiver's value will be
258  * modified by when the up/down (or right/left) arrows
259  * are pressed.
260  *
261  * @return the increment
262  *
263  * @exception DWTException <ul>
264  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
265  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
266  * </ul>
267  */
268 public int getIncrement () {
269     checkWidget();
270     return increment;
271 }
272
273 /**
274  * Returns the maximum value which the receiver will allow.
275  *
276  * @return the maximum
277  *
278  * @exception DWTException <ul>
279  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
280  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
281  * </ul>
282  */
283 public int getMaximum () {
284     checkWidget();
285     SCROLLINFO info;
286     info.cbSize = SCROLLINFO.sizeof;
287     info.fMask = OS.SIF_RANGE;
288     auto hwnd = hwndScrollBar ();
289     auto type = scrollBarType ();
290     OS.GetScrollInfo (hwnd, type, &info);
291     return info.nMax;
292 }
293
294 /**
295  * Returns the minimum value which the receiver will allow.
296  *
297  * @return the minimum
298  *
299  * @exception DWTException <ul>
300  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
301  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
302  * </ul>
303  */
304 public int getMinimum () {
305     checkWidget();
306     SCROLLINFO info;
307     info.cbSize = SCROLLINFO.sizeof;
308     info.fMask = OS.SIF_RANGE;
309     auto hwnd = hwndScrollBar ();
310     auto type = scrollBarType ();
311     OS.GetScrollInfo (hwnd, type, &info);
312     return info.nMin;
313 }
314
315 /**
316  * Returns the amount that the receiver's value will be
317  * modified by when the page increment/decrement areas
318  * are selected.
319  *
320  * @return the page increment
321  *
322  * @exception DWTException <ul>
323  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
324  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
325  * </ul>
326  */
327 public int getPageIncrement () {
328     checkWidget();
329     return pageIncrement;
330 }
331
332 /**
333  * Returns the receiver's parent, which must be a Scrollable.
334  *
335  * @return the receiver's parent
336  *
337  * @exception DWTException <ul>
338  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
339  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
340  * </ul>
341  */
342 public Scrollable getParent () {
343     checkWidget();
344     return parent;
345 }
346
347 /**
348  * Returns the single 'selection' that is the receiver's value.
349  *
350  * @return the selection
351  *
352  * @exception DWTException <ul>
353  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
354  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
355  * </ul>
356  */
357 public int getSelection () {
358     checkWidget();
359     SCROLLINFO info;
360     info.cbSize = SCROLLINFO.sizeof;
361     info.fMask = OS.SIF_POS;
362     auto hwnd = hwndScrollBar ();
363     auto type = scrollBarType ();
364     OS.GetScrollInfo (hwnd, type, &info);
365     return info.nPos;
366 }
367
368 /**
369  * Returns a point describing the receiver's size. The
370  * x coordinate of the result is the width of the receiver.
371  * The y coordinate of the result is the height of the
372  * receiver.
373  *
374  * @return the receiver's size
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 public Point getSize () {
382     checkWidget();
383     parent.forceResize ();
384     RECT rect;
385     OS.GetClientRect (parent.scrolledHandle (), &rect);
386     int width, height;
387     if ((style & DWT.HORIZONTAL) !is 0) {
388         width = rect.right - rect.left;
389         height = OS.GetSystemMetrics (OS.SM_CYHSCROLL);
390     } else {
391         width = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
392         height = rect.bottom - rect.top;
393     }
394     return new Point (width, height);
395 }
396
397 /**
398  * Returns the size of the receiver's thumb relative to the
399  * difference between its maximum and minimum values.
400  *
401  * @return the thumb value
402  *
403  * @exception DWTException <ul>
404  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
405  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
406  * </ul>
407  *
408  * @see ScrollBar
409  */
410 public int getThumb () {
411     checkWidget();
412     SCROLLINFO info;
413     info.cbSize = SCROLLINFO.sizeof;
414     info.fMask = OS.SIF_PAGE;
415     auto hwnd = hwndScrollBar ();
416     auto type = scrollBarType ();
417     OS.GetScrollInfo (hwnd, type, &info);
418     if (info.nPage !is 0) --info.nPage;
419     return info.nPage;
420 }
421
422 /**
423  * Returns <code>true</code> if the receiver is visible, and
424  * <code>false</code> otherwise.
425  * <p>
426  * If one of the receiver's ancestors is not visible or some
427  * other condition makes the receiver not visible, this method
428  * may still indicate that it is considered visible even though
429  * it may not actually be showing.
430  * </p>
431  *
432  * @return the receiver's visibility state
433  *
434  * @exception DWTException <ul>
435  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
436  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
437  * </ul>
438  */
439 public bool getVisible () {
440     checkWidget();
441     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
442         SCROLLBARINFO psbi;
443         psbi.cbSize = SCROLLBARINFO.sizeof;
444         int idObject = (style & DWT.VERTICAL) !is 0 ? OS.OBJID_VSCROLL : OS.OBJID_HSCROLL;
445         OS.GetScrollBarInfo (hwndScrollBar (), idObject, &psbi);
446         return (psbi.rgstate [0] & OS.STATE_SYSTEM_INVISIBLE) is 0;
447     }
448     return (state & HIDDEN) is 0;
449 }
450
451 HWND hwndScrollBar () {
452     return parent.scrolledHandle ();
453 }
454
455 /**
456  * Returns <code>true</code> if the receiver is enabled and all
457  * of the receiver's ancestors are enabled, and <code>false</code>
458  * otherwise. A disabled control is typically not selectable from the
459  * user interface and draws with an inactive or "grayed" look.
460  *
461  * @return the receiver's enabled state
462  *
463  * @exception DWTException <ul>
464  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
465  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
466  * </ul>
467  *
468  * @see #getEnabled
469  */
470 public bool isEnabled () {
471     checkWidget();
472     return getEnabled () && parent.isEnabled ();
473 }
474
475 /**
476  * Returns <code>true</code> if the receiver is visible and all
477  * of the receiver's ancestors are visible and <code>false</code>
478  * otherwise.
479  *
480  * @return the receiver's visibility state
481  *
482  * @exception DWTException <ul>
483  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
484  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
485  * </ul>
486  *
487  * @see #getVisible
488  */
489 public bool isVisible () {
490     checkWidget();
491     return getVisible () && parent.isVisible ();
492 }
493
494 override void releaseHandle () {
495     super.releaseHandle ();
496     parent = null;
497 }
498
499 override void releaseParent () {
500     super.releaseParent ();
501     if (parent.horizontalBar is this) parent.horizontalBar = null;
502     if (parent.verticalBar is this) parent.verticalBar = null;
503 }
504
505 /**
506  * Removes the listener from the collection of listeners who will
507  * be notified when the user changes the receiver's value.
508  *
509  * @param listener the listener which should no longer be notified
510  *
511  * @exception IllegalArgumentException <ul>
512  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
513  * </ul>
514  * @exception DWTException <ul>
515  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
516  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
517  * </ul>
518  *
519  * @see SelectionListener
520  * @see #addSelectionListener
521  */
522 public void removeSelectionListener (SelectionListener listener) {
523     checkWidget();
524     if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
525     if (eventTable is null) return;
526     eventTable.unhook (DWT.Selection, listener);
527     eventTable.unhook (DWT.DefaultSelection,listener);
528 }
529
530 int scrollBarType () {
531     return (style & DWT.VERTICAL) !is 0 ? OS.SB_VERT : OS.SB_HORZ;
532 }
533
534 /**
535  * Enables the receiver if the argument is <code>true</code>,
536  * and disables it otherwise. A disabled control is typically
537  * not selectable from the user interface and draws with an
538  * inactive or "grayed" look.
539  *
540  * @param enabled the new enabled state
541  *
542  * @exception DWTException <ul>
543  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
544  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
545  * </ul>
546  */
547 public void setEnabled (bool enabled) {
548     checkWidget();
549     /*
550     * This line is intentionally commented.  Currently
551     * always show scrollbar as being enabled and visible.
552     */
553 //  if (OS.IsWinCE) error (DWT.ERROR_NOT_IMPLEMENTED);
554     static if (!OS.IsWinCE) {
555         auto hwnd = hwndScrollBar ();
556         auto type = scrollBarType ();
557         int flags = enabled ? OS.ESB_ENABLE_BOTH : OS.ESB_DISABLE_BOTH;
558         OS.EnableScrollBar (hwnd, type, flags);
559         if (enabled) {
560             state &= ~DISABLED;
561         } else {
562             state |= DISABLED;
563         }
564     }
565 }
566
567 /**
568  * Sets the amount that the receiver's value will be
569  * modified by when the up/down (or right/left) arrows
570  * are pressed to the argument, which must be at least
571  * one.
572  *
573  * @param value the new increment (must be greater than zero)
574  *
575  * @exception DWTException <ul>
576  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
577  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
578  * </ul>
579  */
580 public void setIncrement (int value) {
581     checkWidget();
582     if (value < 1) return;
583     increment = value;
584 }
585
586 /**
587  * Sets the maximum. If this value is negative or less than or
588  * equal to the minimum, the value is ignored. If necessary, first
589  * the thumb and then the selection are adjusted to fit within the
590  * new range.
591  *
592  * @param value the new maximum
593  *
594  * @exception DWTException <ul>
595  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
596  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
597  * </ul>
598  */
599 public void setMaximum (int value) {
600     checkWidget();
601     if (value < 0) return;
602     SCROLLINFO info;
603     info.cbSize = SCROLLINFO.sizeof;
604     auto hwnd = hwndScrollBar ();
605     auto type = scrollBarType ();
606     info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
607     OS.GetScrollInfo (hwnd, type, &info);
608     if (value - info.nMin - info.nPage < 1) return;
609     info.nMax = value;
610     SetScrollInfo (hwnd, type, &info, true);
611 }
612
613 /**
614  * Sets the minimum value. If this value is negative or greater
615  * than or equal to the maximum, the value is ignored. If necessary,
616  * first the thumb and then the selection are adjusted to fit within
617  * the new range.
618  *
619  * @param value the new minimum
620  *
621  * @exception DWTException <ul>
622  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
623  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
624  * </ul>
625  */
626 public void setMinimum (int value) {
627     checkWidget();
628     if (value < 0) return;
629     SCROLLINFO info;
630     info.cbSize = SCROLLINFO.sizeof;
631     auto hwnd = hwndScrollBar ();
632     auto type = scrollBarType ();
633     info.fMask = OS.SIF_RANGE | OS.SIF_DISABLENOSCROLL;
634     OS.GetScrollInfo (hwnd, type, &info);
635     if (info.nMax - value - info.nPage < 1) return;
636     info.nMin = value;
637     SetScrollInfo (hwnd, type, &info, true);
638 }
639
640 /**
641  * Sets the amount that the receiver's value will be
642  * modified by when the page increment/decrement areas
643  * are selected to the argument, which must be at least
644  * one.
645  *
646  * @param value the page increment (must be greater than zero)
647  *
648  * @exception DWTException <ul>
649  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
650  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
651  * </ul>
652  */
653 public void setPageIncrement (int value) {
654     checkWidget();
655     if (value < 1) return;
656     pageIncrement = value;
657 }
658
659 bool SetScrollInfo (HWND hwnd, int flags, SCROLLINFO* info, bool fRedraw) {
660     /*
661     * Bug in Windows.  For some reason, when SetScrollInfo()
662     * is used with SIF_POS and the scroll bar is hidden,
663     * the opposite scroll bar is incorrectly made visible
664     * so that the next time the parent is resized (or another
665     * scroll bar operation is performed), the opposite scroll
666     * bar draws.  The fix is to hide both scroll bars.
667     */
668     bool barVisible = false;
669     bool visible = getVisible ();
670
671     /*
672     * This line is intentionally commented.  Currently
673     * always show scrollbar as being enabled and visible.
674     */
675 //  if (OS.IsWinCE) error (DWT.ERROR_NOT_IMPLEMENTED);
676     ScrollBar bar = null;
677     if (!OS.IsWinCE) {
678         switch (flags) {
679             case OS.SB_HORZ:
680                 bar = parent.getVerticalBar ();
681                 break;
682             case OS.SB_VERT:
683                 bar = parent.getHorizontalBar ();
684                 break;
685             default:
686         }
687         barVisible = bar !is null && bar.getVisible ();
688     }
689     if (!visible || (state & DISABLED) !is 0) fRedraw = false;
690     bool result = cast(bool) OS.SetScrollInfo (hwnd, flags, info, fRedraw);
691
692     /*
693     * Bug in Windows.  For some reason, when the widget
694     * is a standard scroll bar, and SetScrollInfo() is
695     * called with SIF_RANGE or SIF_PAGE, the widget is
696     * incorrectly made visible so that the next time the
697     * parent is resized (or another scroll bar operation
698     * is performed), the scroll bar draws.  The fix is
699     * to hide the scroll bar (again) when already hidden.
700     */
701     if (!visible) {
702         /*
703         * This line is intentionally commented.  Currently
704         * always show scrollbar as being enabled and visible.
705         */
706 //      if (OS.IsWinCE) error (DWT.ERROR_NOT_IMPLEMENTED);
707         if (!OS.IsWinCE) {
708             OS.ShowScrollBar (hwnd, !barVisible ? OS.SB_BOTH : flags, false);
709         }
710     }
711
712     /*
713     * Bug in Windows.  When only one scroll bar is visible,
714     * and the thumb changes using SIF_RANGE or SIF_PAGE
715     * from being visible to hidden, the opposite scroll
716     * bar is incorrectly made visible.  The next time the
717     * parent is resized (or another scroll bar operation
718     * is performed), the opposite scroll bar draws.  The
719     * fix is to hide the opposite scroll bar again.
720     *
721     * NOTE: This problem only happens on Vista
722     */
723     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
724         if (visible && bar !is null && !barVisible) {
725             OS.ShowScrollBar (hwnd, flags is OS.SB_HORZ ? OS.SB_VERT : OS.SB_HORZ, false);
726         }
727     }
728
729     /*
730     * Feature in Windows.  Using SIF_DISABLENOSCROLL,
731     * SetScrollInfo () can change enabled and disabled
732     * state of the scroll bar causing a scroll bar that
733     * was disabled by the application to become enabled.
734     * The fix is to disable the scroll bar (again) when
735     * the application has disabled the scroll bar.
736     */
737     if ((state & DISABLED) !is 0) {
738         /*
739         * This line is intentionally commented.  Currently
740         * always show scrollbar as being enabled and visible.
741         */
742 //