1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15 
16 
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.cocoa.*;
21 
22 /**
23  * Instances of this class are selectable user interface
24  * objects that represent a range of positive, numeric values.
25  * <p>
26  * At any given moment, a given scroll bar will have a
27  * single 'selection' that is considered to be its
28  * value, which is constrained to be within the range of
29  * values the scroll bar represents (that is, between its
30  * <em>minimum</em> and <em>maximum</em> values).
31  * </p><p>
32  * Typically, scroll bars will be made up of five areas:</p>
33  * <ol>
34  * <li>an arrow button for decrementing the value</li>
35  * <li>a page decrement area for decrementing the value by a larger amount</li>
36  * <li>a <em>thumb</em> for modifying the value by mouse dragging</li>
37  * <li>a page increment area for incrementing the value by a larger amount</li>
38  * <li>an arrow button for incrementing the value</li>
39  * </ol>
40  * <p>
41  * Based on their style, scroll bars are either <code>HORIZONTAL</code>
42  * (which have a left facing button for decrementing the value and a
43  * right facing button for incrementing it) or <code>VERTICAL</code>
44  * (which have an upward facing button for decrementing the value
45  * and a downward facing buttons for incrementing it).
46  * </p><p>
47  * On some platforms, the size of the scroll bar's thumb can be
48  * varied relative to the magnitude of the range of values it
49  * represents (that is, relative to the difference between its
50  * maximum and minimum values). Typically, this is used to
51  * indicate some proportional value such as the ratio of the
52  * visible area of a document to the total amount of space that
53  * it would take to display it. SWT supports setting the thumb
54  * size even if the underlying platform does not, but in this
55  * case the appearance of the scroll bar will not change.
56  * </p><p>
57  * Scroll bars are created by specifying either <code>H_SCROLL</code>,
58  * <code>V_SCROLL</code> or both when creating a <code>Scrollable</code>.
59  * They are accessed from the <code>Scrollable</code> using
60  * <code>getHorizontalBar</code> and <code>getVerticalBar</code>.
61  * </p><p>
62  * Note: Scroll bars are not Controls.  On some platforms, scroll bars
63  * that appear as part of some standard controls such as a text or list
64  * have no operating system resources and are not children of the control.
65  * For this reason, scroll bars are treated specially.  To create a control
66  * that looks like a scroll bar but has operating system resources, use
67  * <code>Slider</code>.
68  * </p>
69  * <dl>
70  * <dt><b>Styles:</b></dt>
71  * <dd>HORIZONTAL, VERTICAL</dd>
72  * <dt><b>Events:</b></dt>
73  * <dd>Selection</dd>
74  * </dl>
75  * <p>
76  * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
77  * </p><p>
78  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
79  * </p>
80  *
81  * @see Slider
82  * @see Scrollable
83  * @see Scrollable#getHorizontalBar
84  * @see Scrollable#getVerticalBar
85  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
86  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
87  * @noextend This class is not intended to be subclassed by clients.
88  */
89 public class ScrollBar extends Widget {
90 	NSScroller view;
91 	Scrollable parent;
92 	int minimum, maximum = 100, thumb = 10;
93 	int increment = 1;
94 	int pageIncrement = 10;
95 	id target;
96 	long actionSelector;
97 
ScrollBar()98 ScrollBar () {
99 	/* Do nothing */
100 }
101 
102 /**
103  * Adds the listener to the collection of listeners who will
104  * be notified when the user changes the receiver's value, by sending
105  * it one of the messages defined in the <code>SelectionListener</code>
106  * interface.
107  * <p>
108  * When <code>widgetSelected</code> is called, the event object detail field contains one of the following values:
109  * <code>SWT.NONE</code> - for the end of a drag.
110  * <code>SWT.DRAG</code>.
111  * <code>SWT.HOME</code>.
112  * <code>SWT.END</code>.
113  * <code>SWT.ARROW_DOWN</code>.
114  * <code>SWT.ARROW_UP</code>.
115  * <code>SWT.PAGE_DOWN</code>.
116  * <code>SWT.PAGE_UP</code>.
117  * <code>widgetDefaultSelected</code> is not called.
118  * </p>
119  *
120  * @param listener the listener which should be notified when the user changes the receiver's value
121  *
122  * @exception IllegalArgumentException <ul>
123  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
124  * </ul>
125  * @exception SWTException <ul>
126  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
127  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
128  * </ul>
129  *
130  * @see SelectionListener
131  * @see #removeSelectionListener
132  * @see SelectionEvent
133  */
addSelectionListener(SelectionListener listener)134 public void addSelectionListener(SelectionListener listener) {
135 	checkWidget();
136 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
137 	TypedListener typedListener = new TypedListener(listener);
138 	addListener(SWT.Selection,typedListener);
139 	addListener(SWT.DefaultSelection,typedListener);
140 }
141 
checkStyle(int style)142 static int checkStyle (int style) {
143 	return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
144 }
145 
146 @Override
deregister()147 void deregister () {
148 	super.deregister ();
149 	display.removeWidget (view);
150 }
151 
152 @Override
getDrawing()153 boolean getDrawing () {
154 	return parent.getDrawing ();
155 }
156 
157 /**
158  * Returns <code>true</code> if the receiver is enabled, and
159  * <code>false</code> otherwise. A disabled control is typically
160  * not selectable from the user interface and draws with an
161  * inactive or "grayed" look.
162  *
163  * @return the receiver's enabled state
164  *
165  * @exception SWTException <ul>
166  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
167  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
168  * </ul>
169  *
170  * @see #isEnabled
171  */
getEnabled()172 public boolean getEnabled () {
173 	checkWidget();
174 	return (state & DISABLED) == 0;
175 }
176 
177 /**
178  * Returns the amount that the receiver's value will be
179  * modified by when the up/down (or right/left) arrows
180  * are pressed.
181  *
182  * @return the increment
183  *
184  * @exception SWTException <ul>
185  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
186  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
187  * </ul>
188  */
getIncrement()189 public int getIncrement () {
190 	checkWidget();
191 	return increment;
192 }
193 
194 /**
195  * Returns the maximum value which the receiver will allow.
196  *
197  * @return the maximum
198  *
199  * @exception SWTException <ul>
200  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
201  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
202  * </ul>
203  */
getMaximum()204 public int getMaximum () {
205 	checkWidget();
206 	return maximum;
207 }
208 
209 /**
210  * Returns the minimum value which the receiver will allow.
211  *
212  * @return the minimum
213  *
214  * @exception SWTException <ul>
215  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
216  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
217  * </ul>
218  */
getMinimum()219 public int getMinimum () {
220 	checkWidget();
221 	return minimum;
222 }
223 
224 /**
225  * Returns the amount that the receiver's value will be
226  * modified by when the page increment/decrement areas
227  * are selected.
228  *
229  * @return the page increment
230  *
231  * @exception SWTException <ul>
232  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
233  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
234  * </ul>
235  */
getPageIncrement()236 public int getPageIncrement () {
237 	checkWidget();
238 	return pageIncrement;
239 }
240 
241 /**
242  * Returns the receiver's parent, which must be a Scrollable.
243  *
244  * @return the receiver's parent
245  *
246  * @exception SWTException <ul>
247  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
248  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
249  * </ul>
250  */
getParent()251 public Scrollable getParent () {
252 	checkWidget ();
253 	return parent;
254 }
255 
256 /**
257  * Returns the single 'selection' that is the receiver's value.
258  *
259  * @return the selection
260  *
261  * @exception SWTException <ul>
262  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
263  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
264  * </ul>
265  */
getSelection()266 public int getSelection () {
267 	checkWidget();
268 	NSScroller widget = (NSScroller)view;
269 	double value = widget.doubleValue();
270 	return (int)(0.5f + ((maximum - thumb - minimum) * value + minimum));
271 }
272 
273 /**
274  * Returns a point describing the receiver's size. The
275  * x coordinate of the result is the width of the receiver.
276  * The y coordinate of the result is the height of the
277  * receiver.
278  *
279  * @return the receiver's size
280  *
281  * @exception SWTException <ul>
282  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
283  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
284  * </ul>
285  */
getSize()286 public Point getSize () {
287 	checkWidget();
288 	NSRect rect = ((NSScroller)view).frame();
289 	return new Point((int)rect.width, (int)rect.height);
290 }
291 
292 /**
293  * Returns the receiver's thumb value.
294  *
295  * @return the thumb value
296  *
297  * @exception SWTException <ul>
298  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
299  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
300  * </ul>
301  *
302  * @see ScrollBar
303  */
getThumb()304 public int getThumb () {
305 	checkWidget();
306 	return thumb;
307 }
308 
309 /**
310  * Returns a rectangle describing the size and location of the
311  * receiver's thumb relative to its parent.
312  *
313  * @return the thumb bounds, relative to the {@link #getParent() parent}
314  *
315  * @exception SWTException <ul>
316  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
317  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
318  * </ul>
319  *
320  * @since 3.6
321  */
getThumbBounds()322 public Rectangle getThumbBounds () {
323 	checkWidget();
324 	NSRect rect = view.rectForPart(OS.NSScrollerKnob);
325 	rect = view.convertRect_toView_(rect, parent.view);
326 	return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
327 }
328 
329 /**
330  * Returns a rectangle describing the size and location of the
331  * receiver's thumb track relative to its parent. This rectangle
332  * comprises the areas 2, 3, and 4 as described in {@link ScrollBar}.
333  *
334  * @return the thumb track bounds, relative to the {@link #getParent() parent}
335  *
336  * @exception SWTException <ul>
337  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
338  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
339  * </ul>
340  *
341  * @since 3.6
342  */
getThumbTrackBounds()343 public Rectangle getThumbTrackBounds () {
344 	checkWidget();
345 	NSRect rect = view.rectForPart(OS.NSScrollerKnobSlot);
346 	rect = view.convertRect_toView_(rect, parent.view);
347 	return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
348 }
349 
350 /**
351  * Returns <code>true</code> if the receiver is visible, and
352  * <code>false</code> otherwise.
353  * <p>
354  * If one of the receiver's ancestors is not visible or some
355  * other condition makes the receiver not visible, this method
356  * may still indicate that it is considered visible even though
357  * it may not actually be showing.
358  * </p>
359  *
360  * @return the receiver's visibility state
361  *
362  * @exception SWTException <ul>
363  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
364  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
365  * </ul>
366  */
getVisible()367 public boolean getVisible () {
368 	checkWidget();
369 	return (state & HIDDEN) == 0 && !view.isHidden();
370 }
371 
372 /**
373  * Returns <code>true</code> if the receiver is enabled and all
374  * of the receiver's ancestors are enabled, and <code>false</code>
375  * otherwise. A disabled control is typically not selectable from the
376  * user interface and draws with an inactive or "grayed" look.
377  *
378  * @return the receiver's enabled state
379  *
380  * @exception SWTException <ul>
381  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
382  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
383  * </ul>
384  *
385  * @see #getEnabled
386  */
isEnabled()387 public boolean isEnabled () {
388 	checkWidget();
389 	return getEnabled () && parent.isEnabled ();
390 }
391 
392 @Override
isDrawing()393 boolean isDrawing () {
394 	return getDrawing() && parent.isDrawing ();
395 }
396 
397 /**
398  * Returns <code>true</code> if the receiver is visible and all
399  * of the receiver's ancestors are visible and <code>false</code>
400  * otherwise.
401  *
402  * @return the receiver's visibility state
403  *
404  * @exception SWTException <ul>
405  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
406  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
407  * </ul>
408  *
409  * @see #getVisible
410  */
isVisible()411 public boolean isVisible () {
412 	checkWidget();
413 	return getVisible () && parent.isVisible ();
414 }
415 
416 /**
417  * Removes the listener from the collection of listeners who will
418  * be notified when the user changes the receiver's value.
419  *
420  * @param listener the listener which should no longer be notified
421  *
422  * @exception IllegalArgumentException <ul>
423  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
424  * </ul>
425  * @exception SWTException <ul>
426  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
427  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
428  * </ul>
429  *
430  * @see SelectionListener
431  * @see #addSelectionListener
432  */
removeSelectionListener(SelectionListener listener)433 public void removeSelectionListener(SelectionListener listener) {
434 	checkWidget();
435 	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
436 	if (eventTable == null) return;
437 	eventTable.unhook(SWT.Selection, listener);
438 	eventTable.unhook(SWT.DefaultSelection,listener);
439 }
440 
441 @Override
register()442 void register () {
443 	super.register ();
444 	display.addWidget (view, this);
445 }
446 
447 @Override
releaseHandle()448 void releaseHandle () {
449 	super.releaseHandle ();
450 	if (view != null) view.release();
451 	view = null;
452 }
453 
454 @Override
releaseParent()455 void releaseParent () {
456 	super.releaseParent ();
457 	if (parent.horizontalBar == this) parent.horizontalBar = null;
458 	if (parent.verticalBar == this) parent.verticalBar = null;
459 }
460 
461 @Override
releaseWidget()462 void releaseWidget () {
463 	super.releaseWidget ();
464 	parent = null;
465 }
466 
467 @Override
sendSelection()468 void sendSelection () {
469 	NSWindow window = view.window ();
470 	if (target == null) parent.getShell().deferFlushing();
471 	int value = 0;
472 	if (target != null) {
473 		view.sendAction(actionSelector, target);
474 	} else {
475 		value = getSelection ();
476 	}
477 	NSPoint point;
478 	NSEvent nsEvent = NSApplication.sharedApplication().currentEvent();
479 	if (nsEvent != null) {
480 		point = nsEvent.locationInWindow();
481 		if (nsEvent.window() == null) point = window.convertScreenToBase(point);
482 	} else {
483 		point = window.mouseLocationOutsideOfEventStream();
484 	}
485 	int hitPart = (int)((NSScroller)view).testPart(point);
486 	Event event = new Event();
487 	switch (hitPart) {
488 	case OS.NSScrollerDecrementLine:
489 		value -= increment;
490 		event.detail = SWT.ARROW_UP;
491 		break;
492 	case OS.NSScrollerDecrementPage:
493 		value -= pageIncrement;
494 		event.detail = SWT.PAGE_UP;
495 		break;
496 	case OS.NSScrollerIncrementLine:
497 		value += increment;
498 		event.detail = SWT.ARROW_DOWN;
499 		break;
500 	case OS.NSScrollerIncrementPage:
501 		value += pageIncrement;
502 		event.detail = SWT.PAGE_DOWN;
503 		break;
504 	case OS.NSScrollerKnob:
505 		event.detail = SWT.DRAG;
506 		break;
507 	}
508 	if (target == null) {
509 		if (event.detail != SWT.DRAG) {
510 			setSelection(value);
511 		}
512 	}
513 	sendSelectionEvent(SWT.Selection, event, true);
514 }
515 
516 /**
517  * Sets the amount that the receiver's value will be
518  * modified by when the up/down (or right/left) arrows
519  * are pressed to the argument, which must be at least
520  * one.
521  *
522  * @param value the new increment (must be greater than zero)
523  *
524  * @exception SWTException <ul>
525  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
526  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
527  * </ul>
528  */
setIncrement(int value)529 public void setIncrement (int value) {
530 	checkWidget();
531 	if (value < 1) return;
532 	increment = value;
533 }
534 
535 @Override
setClipRegion(NSView view)536 void setClipRegion (NSView view) {
537 	parent.setClipRegion(view);
538 }
539 
540 /**
541  * Enables the receiver if the argument is <code>true</code>,
542  * and disables it otherwise. A disabled control is typically
543  * not selectable from the user interface and draws with an
544  * inactive or "grayed" look.
545  *
546  * @param enabled the new enabled state
547  *
548  * @exception SWTException <ul>
549  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
550  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
551  * </ul>
552  */
setEnabled(boolean enabled)553 public void setEnabled (boolean enabled) {
554 	checkWidget();
555 	if (enabled) {
556 		if ((state & DISABLED) == 0) return;
557 		state &= ~DISABLED;
558 	} else {
559 		if ((state & DISABLED) != 0) return;
560 		state |= DISABLED;
561 	}
562 	enableWidget (enabled);
563 }
564 
enableWidget(boolean enabled)565 void enableWidget (boolean enabled) {
566 	if (!enabled || (state & DISABLED) == 0) {
567 		view.setEnabled (enabled);
568 	}
569 }
570 
571 /**
572  * Sets the maximum. If this value is negative or less than or
573  * equal to the minimum, the value is ignored. If necessary, first
574  * the thumb and then the selection are adjusted to fit within the
575  * new range.
576  *
577  * @param value the new maximum
578  *
579  * @exception SWTException <ul>
580  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
581  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
582  * </ul>
583  */
setMaximum(int value)584 public void setMaximum (int value) {
585 	checkWidget();
586 	if (value < 0) return;
587 	if (value <= minimum) return;
588 	if (value - minimum < thumb) {
589 		thumb = value - minimum;
590 	}
591 	int selection = Math.max(minimum, Math.min (getSelection (), value - thumb));
592 	this.maximum = value;
593 	updateBar(selection, minimum, value, thumb);
594 }
595 
596 /**
597  * Sets the minimum value. If this value is negative or greater
598  * than or equal to the maximum, the value is ignored. If necessary,
599  * first the thumb and then the selection are adjusted to fit within
600  * the new range.
601  *
602  * @param value the new minimum
603  *
604  * @exception SWTException <ul>
605  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
606  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
607  * </ul>
608  */
setMinimum(int value)609 public void setMinimum (int value) {
610 	checkWidget();
611 	if (value < 0) return;
612 	if (value >= maximum) return;
613 	if (maximum - value < thumb) {
614 		thumb = maximum - value;
615 	}
616 	int selection = Math.min(maximum - thumb, Math.max (getSelection (), value));
617 	this.minimum = value;
618 	updateBar(selection, value, maximum, thumb);
619 }
620 
621 /**
622  * Sets the amount that the receiver's value will be
623  * modified by when the page increment/decrement areas
624  * are selected to the argument, which must be at least
625  * one.
626  *
627  * @param value the page increment (must be greater than zero)
628  *
629  * @exception SWTException <ul>
630  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
631  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
632  * </ul>
633  */
setPageIncrement(int value)634 public void setPageIncrement (int value) {
635 	checkWidget();
636 	if (value < 1) return;
637 	pageIncrement = value;
638 }
639 
640 /**
641  * Sets the single <em>selection</em> that is the receiver's
642  * value to the argument which must be greater than or equal
643  * to zero.
644  *
645  * @param selection the new selection (must be zero or greater)
646  *
647  * @exception SWTException <ul>
648  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
649  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
650  * </ul>
651  */
setSelection(int selection)652 public void setSelection (int selection) {
653 	checkWidget();
654 	updateBar(selection, minimum, maximum, thumb);
655 }
656 
657 /**
658  * Sets the thumb value. The thumb value should be used to represent
659  * the size of the visual portion of the current range. This value is
660  * usually the same as the page increment value.
661  * <p>
662  * This new value will be ignored if it is less than one, and will be
663  * clamped if it exceeds the receiver's current range.
664  * </p>
665  *
666  * @param value the new thumb value, which must be at least one and not
667  * larger than the size of the current range
668  *
669  * @exception SWTException <ul>
670  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
671  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
672  * </ul>
673  */
setThumb(int value)674 public void setThumb (int value) {
675 	checkWidget();
676 	if (value < 1) return;
677 	value = Math.min (value, maximum - minimum);
678 	updateBar(getSelection(), minimum, maximum, value);
679 	this.thumb = value;
680 }
681 
682 /**
683  * Sets the receiver's selection, minimum value, maximum
684  * value, thumb, increment and page increment all at once.
685  * <p>
686  * Note: This is similar to setting the values individually
687  * using the appropriate methods, but may be implemented in a
688  * more efficient fashion on some platforms.
689  * </p>
690  *
691  * @param selection the new selection value
692  * @param minimum the new minimum value
693  * @param maximum the new maximum value
694  * @param thumb the new thumb value
695  * @param increment the new increment value
696  * @param pageIncrement the new pageIncrement value
697  *
698  * @exception SWTException <ul>
699  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
700  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
701  * </ul>
702  */
setValues(int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement)703 public void setValues (int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) {
704 	checkWidget();
705 	if (minimum < 0) return;
706 	if (maximum < 0) return;
707 	if (thumb < 1) return;
708 	if (increment < 1) return;
709 	if (pageIncrement < 1) return;
710 	this.thumb = thumb = Math.min (thumb, maximum - minimum);
711 	this.maximum = maximum;
712 	this.minimum = minimum;
713 	this.increment = increment;
714 	this.pageIncrement = pageIncrement;
715 	updateBar (selection, minimum, maximum, thumb);
716 }
717 
718 /**
719  * Marks the receiver as visible if the argument is <code>true</code>,
720  * and marks it invisible otherwise.
721  * <p>
722  * If one of the receiver's ancestors is not visible or some
723  * other condition makes the receiver not visible, marking
724  * it visible may not actually cause it to be displayed.
725  * </p>
726  *
727  * @param visible the new visibility state
728  *
729  * @exception SWTException <ul>
730  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
731  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
732  * </ul>
733  */
setVisible(boolean visible)734 public void setVisible (boolean visible) {
735 	checkWidget();
736 	parent.setScrollBarVisible (this, visible);
737 }
738 
updateBar(int selection, int minimum, int maximum, int thumb)739 void updateBar (int selection, int minimum, int maximum, int thumb) {
740 	NSScroller widget = (NSScroller) view;
741 	selection = Math.max (minimum, Math.min (maximum - thumb, selection));
742 	int range = maximum - thumb - minimum;
743 	float fraction = range <= 0 ? 1 : (float) (selection - minimum) / range;
744 	float knob = range <= 0 ? 1 : (float) thumb / (maximum - minimum);
745 	double oldFraction = widget.doubleValue();
746 	double oldKnob = widget.knobProportion();
747 	widget.setDoubleValue(fraction);
748 	widget.setKnobProportion(knob);
749 	widget.setEnabled (range > 0);
750 	if (target == null && (knob != oldKnob || fraction != oldFraction)) {
751 		parent.scrollView.flashScrollers();
752 	}
753 }
754 
755 }
756