comparison dwt/widgets/ScrollBar.d @ 0:380af2bdd8e5

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