comparison dwtx/draw2d/ScrollBar.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children 2d6540440fe6
comparison
equal deleted inserted replaced
96:b492ba44e44d 98:95307ad235d9
1 /*******************************************************************************
2 * Copyright (c) 2000, 2005 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 dwtx.draw2d.ScrollBar;
14
15 import dwt.dwthelper.utils;
16
17 import dwtx.dwtxhelper.Bean;
18
19 import dwt.graphics.Color;
20 import dwtx.draw2d.geometry.Dimension;
21 import dwtx.draw2d.geometry.Point;
22 import dwtx.draw2d.geometry.Rectangle;
23 import dwtx.draw2d.geometry.Transposer;
24
25 import dwtx.draw2d.Orientable;
26 import dwtx.draw2d.Figure;
27 import dwtx.draw2d.IFigure;
28 import dwtx.draw2d.RangeModel;
29 import dwtx.draw2d.Clickable;
30 import dwtx.draw2d.MouseMotionListener;
31 import dwtx.draw2d.MouseListener;
32 import dwtx.draw2d.MouseEvent;
33 import dwtx.draw2d.FigureUtilities;
34 import dwtx.draw2d.ColorConstants;
35 import dwtx.draw2d.Button;
36 import dwtx.draw2d.RangeModel;
37 import dwtx.draw2d.DefaultRangeModel;
38 import dwtx.draw2d.ArrowButton;
39 import dwtx.draw2d.ButtonBorder;
40 import dwtx.draw2d.ChangeListener;
41 import dwtx.draw2d.ChangeEvent;
42 import dwtx.draw2d.Panel;
43 import dwtx.draw2d.ScrollBarLayout;
44 import dwtx.draw2d.SchemeBorder;
45 import dwtx.draw2d.ActionListener;
46 import dwtx.draw2d.ActionEvent;
47
48 /**
49 * Provides for the scrollbars used by the {@link ScrollPane}. A ScrollBar is made up of
50 * five essential Figures: An 'Up' arrow button, a 'Down' arrow button, a draggable
51 * 'Thumb', a 'Pageup' button, and a 'Pagedown' button.
52 */
53 public class ScrollBar
54 : Figure
55 , Orientable, PropertyChangeListener
56 {
57
58 private static const int ORIENTATION_FLAG = Figure.MAX_FLAG << 1;
59 /** @see Figure#MAX_FLAG */
60 protected static const int MAX_FLAG = ORIENTATION_FLAG;
61
62 private static const Color COLOR_TRACK;
63 static this(){
64 COLOR_TRACK = FigureUtilities.mixColors(
65 ColorConstants.white,
66 ColorConstants.button);
67 }
68
69 private RangeModel rangeModel = null;
70 private IFigure thumb;
71 private Clickable pageUp_, pageDown_;
72 private Clickable buttonUp, buttonDown;
73 /**
74 * Listens to mouse events on the scrollbar to take care of scrolling.
75 */
76 protected ThumbDragger thumbDragger;
77
78 private bool isHorizontal_ = false;
79
80 private int pageIncrement = 50;
81 private int stepIncrement = 10;
82
83 /**
84 * Transposes from vertical to horizontal if needed.
85 */
86 protected /+final+/ Transposer transposer;
87
88 private void instanceInit(){
89 thumbDragger = new ThumbDragger();
90 transposer = new Transposer();
91 setRangeModel(new DefaultRangeModel());
92 }
93
94 /**
95 * Constructs a ScrollBar. ScrollBar orientation is vertical by default. Call
96 * {@link #setHorizontal(bool)} with <code>true</code> to set horizontal orientation.
97 *
98 * @since 2.0
99 */
100 public this() {
101 instanceInit();
102 initialize();
103 }
104
105 /**
106 * Creates the default 'Up' ArrowButton for the ScrollBar.
107 *
108 * @return the up button
109 * @since 2.0
110 */
111 protected Clickable createDefaultUpButton() {
112 Button buttonUp = new ArrowButton();
113 buttonUp.setBorder(new ButtonBorder(ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
114 return buttonUp;
115 }
116
117 /**
118 * Creates the default 'Down' ArrowButton for the ScrollBar.
119 *
120 * @return the down button
121 * @since 2.0
122 */
123 protected Clickable createDefaultDownButton() {
124 Button buttonDown = new ArrowButton();
125 buttonDown.setBorder(new ButtonBorder(ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
126 return buttonDown;
127 }
128
129 /**
130 * Creates the pagedown Figure for the Scrollbar.
131 *
132 * @return the page down figure
133 * @since 2.0
134 */
135 protected Clickable createPageDown() {
136 return createPageUp();
137 }
138
139 /**
140 * Creates the pageup Figure for the Scrollbar.
141 *
142 * @return the page up figure
143 * @since 2.0
144 */
145 protected Clickable createPageUp() {
146 Clickable clickable = new Clickable();
147 clickable.setOpaque(true);
148 clickable.setBackgroundColor(COLOR_TRACK);
149 clickable.setRequestFocusEnabled(false);
150 clickable.setFocusTraversable(false);
151 clickable.addChangeListener( dgChangeListener( (ChangeEvent evt, Clickable clickable_){
152 if (clickable_.getModel().isArmed())
153 clickable_.setBackgroundColor(ColorConstants.black);
154 else
155 clickable_.setBackgroundColor(COLOR_TRACK);
156 }, clickable));
157 return clickable;
158 }
159
160 /**
161 * Creates the Scrollbar's "thumb", the draggable Figure that indicates the Scrollbar's
162 * position.
163 *
164 * @return the thumb figure
165 * @since 2.0
166 */
167 protected IFigure createDefaultThumb() {
168 Panel thumb = new Panel();
169 thumb.setMinimumSize(new Dimension(6, 6));
170 thumb.setBackgroundColor(ColorConstants.button);
171
172 thumb.setBorder(new SchemeBorder(SchemeBorder.SCHEMES.BUTTON_CONTRAST));
173 return thumb;
174 }
175
176 /**
177 * Returns the figure used as the up button.
178 * @return the up button
179 */
180 protected IFigure getButtonUp() {
181 // TODO: The set method takes a Clickable while the get method returns an IFigure.
182 // Change the get method to return Clickable (since that's what it's typed as).
183 return buttonUp;
184 }
185
186 /**
187 * Returns the figure used as the down button.
188 * @return the down button
189 */
190 protected IFigure getButtonDown() {
191 // TODO: The set method takes a Clickable while the get method returns an IFigure.
192 // Change the get method to return Clickable (since that's what it's typed as).
193 return buttonDown;
194 }
195
196 /**
197 * Returns the extent.
198 * @return the extent
199 * @see RangeModel#getExtent()
200 */
201 public int getExtent() {
202 return getRangeModel().getExtent();
203 }
204
205 /**
206 * Returns the minumum value.
207 * @return the minimum
208 * @see RangeModel#getMinimum()
209 */
210 public int getMinimum() {
211 return getRangeModel().getMinimum();
212 }
213
214 /**
215 * Returns the maximum value.
216 * @return the maximum
217 * @see RangeModel#getMaximum()
218 */
219 public int getMaximum() {
220 return getRangeModel().getMaximum();
221 }
222
223 /**
224 * Returns the figure used for page down.
225 * @return the page down figure
226 */
227 protected IFigure getPageDown() {
228 // TODO: The set method takes a Clickable while the get method returns an IFigure.
229 // Change the get method to return Clickable (since that's what it's typed as).
230 return pageDown_;
231 }
232
233 /**
234 * Returns the the amound the scrollbar will move when the page up or page down areas are
235 * pressed.
236 * @return the page increment
237 */
238 public int getPageIncrement() {
239 return pageIncrement;
240 }
241
242 /**
243 * Returns the figure used for page up.
244 * @return the page up figure
245 */
246 protected IFigure getPageUp() {
247 // TODO: The set method takes a Clickable while the get method returns an IFigure.
248 // Change the get method to return Clickable (since that's what it's typed as).
249 return pageUp_;
250 }
251
252 /**
253 * Returns the range model for this scrollbar.
254 * @return the range model
255 */
256 public RangeModel getRangeModel() {
257 return rangeModel;
258 }
259
260 /**
261 * Returns the amount the scrollbar will move when the up or down arrow buttons are
262 * pressed.
263 * @return the step increment
264 */
265 public int getStepIncrement() {
266 return stepIncrement;
267 }
268
269 /**
270 * Returns the figure used as the scrollbar's thumb.
271 * @return the thumb figure
272 */
273 protected IFigure getThumb() {
274 return thumb;
275 }
276
277 /**
278 * Returns the current scroll position of the scrollbar.
279 * @return the current value
280 * @see RangeModel#getValue()
281 */
282 public int getValue() {
283 return getRangeModel().getValue();
284 }
285
286 /**
287 * Returns the size of the range of allowable values.
288 * @return the value range
289 */
290 protected int getValueRange() {
291 return getMaximum() - getExtent() - getMinimum();
292 }
293
294 /**
295 * Initilization of the ScrollBar. Sets the Scrollbar to have a ScrollBarLayout with
296 * vertical orientation. Creates the Figures that make up the components of the ScrollBar.
297 *
298 * @since 2.0
299 */
300 protected void initialize() {
301 setLayoutManager(new ScrollBarLayout(transposer));
302 setUpClickable(createDefaultUpButton());
303 setDownClickable(createDefaultDownButton());
304 setPageUp(createPageUp());
305 setPageDown(createPageDown());
306 setThumb(createDefaultThumb());
307 }
308
309 /**
310 * Returns <code>true</code> if this scrollbar is orientated horizontally,
311 * <code>false</code> otherwise.
312 * @return whether this scrollbar is horizontal
313 */
314 public bool isHorizontal() {
315 return isHorizontal_;
316 }
317
318 private void pageDown() {
319 setValue(getValue() + getPageIncrement());
320 }
321
322 private void pageUp() {
323 setValue(getValue() - getPageIncrement());
324 }
325
326 /**
327 * @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
328 */
329 public void propertyChange(PropertyChangeEvent event) {
330 if (null !is cast(RangeModel)event.getSource() ) {
331 setEnabled(getRangeModel().isEnabled());
332 if (RangeModel.PROPERTY_VALUE.equals(event.getPropertyName())) {
333 firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
334 event.getNewValue());
335 revalidate();
336 }
337 if (RangeModel.PROPERTY_MINIMUM.equals(event.getPropertyName())) {
338 firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
339 event.getNewValue());
340 revalidate();
341 }
342 if (RangeModel.PROPERTY_MAXIMUM.equals(event.getPropertyName())) {
343 firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
344 event.getNewValue());
345 revalidate();
346 }
347 if (RangeModel.PROPERTY_EXTENT.equals(event.getPropertyName())) {
348 firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
349 event.getNewValue());
350 revalidate();
351 }
352 }
353 }
354
355 /**
356 * @see IFigure#revalidate()
357 */
358 public void revalidate() {
359 // Override default revalidate to prevent going up the parent chain. Reason for this
360 // is that preferred size never changes unless orientation changes.
361 invalidate();
362 getUpdateManager().addInvalidFigure(this);
363 }
364
365 /**
366 * Does nothing because this doesn't make sense for a scrollbar.
367 * @see Orientable#setDirection(int)
368 */
369 public void setDirection(int direction) {
370 //Doesn't make sense for Scrollbar.
371 }
372
373 /**
374 * Sets the Clickable that represents the down arrow of the Scrollbar to <i>down</i>.
375 *
376 * @param down the down button
377 * @since 2.0
378 */
379 public void setDownClickable(Clickable down) {
380 if (buttonDown !is null) {
381 remove(buttonDown);
382 }
383 buttonDown = down;
384 if (buttonDown !is null) {
385 if (auto b = cast(Orientable)buttonDown )
386 b.setDirection(isHorizontal()
387 ? Orientable.EAST
388 : Orientable.SOUTH);
389 buttonDown.setFiringMethod(Clickable.REPEAT_FIRING);
390 buttonDown.addActionListener(dgActionListener( (ActionEvent evt){
391 stepDown();
392 }));
393 add(buttonDown, stringcast(ScrollBarLayout.DOWN_ARROW));
394 }
395 }
396
397 /**
398 * Sets the Clickable that represents the up arrow of the Scrollbar to <i>up</i>.
399 *
400 * @param up the up button
401 * @since 2.0
402 */
403 public void setUpClickable(Clickable up) {
404 if (buttonUp !is null) {
405 remove(buttonUp);
406 }
407 buttonUp = up;
408 if (up !is null) {
409 if (auto o = cast(Orientable)up )
410 o.setDirection(isHorizontal()
411 ? Orientable.WEST
412 : Orientable.NORTH);
413 buttonUp.setFiringMethod(Clickable.REPEAT_FIRING);
414 buttonUp.addActionListener(dgActionListener( (ActionEvent evt){
415 stepUp();
416 }));
417 add(buttonUp, stringcast(ScrollBarLayout.UP_ARROW));
418 }
419 }
420
421 /**
422 * @see IFigure#setEnabled(bool)
423 */
424 public void setEnabled(bool value) {
425 if (isEnabled() is value)
426 return;
427 super.setEnabled(value);
428 setChildrenEnabled(value);
429 if (getThumb() !is null) {
430 getThumb().setVisible(value);
431 revalidate();
432 }
433 }
434
435 /**
436 * Sets the extent of the Scrollbar to <i>ext</i>
437 *
438 * @param ext the extent
439 * @since 2.0
440 */
441 public void setExtent(int ext) {
442 if (getExtent() is ext)
443 return;
444 getRangeModel().setExtent(ext);
445 }
446
447 /**
448 * Sets the orientation of the ScrollBar. If <code>true</code>, the Scrollbar will have
449 * a horizontal orientation. If <code>false</code>, the scrollBar will have a vertical
450 * orientation.
451 *
452 * @param value <code>true</code> if the scrollbar should be horizontal
453 * @since 2.0
454 */
455 public final void setHorizontal(bool value) {
456 setOrientation(value ? HORIZONTAL : VERTICAL);
457 }
458
459 /**
460 * Sets the maximum position to <i>max</i>.
461 *
462 * @param max the maximum position
463 * @since 2.0
464 */
465 public void setMaximum(int max) {
466 if (getMaximum() is max)
467 return;
468 getRangeModel().setMaximum(max);
469 }
470
471 /**
472 * Sets the minimum position to <i>min</i>.
473 *
474 * @param min the minumum position
475 * @since 2.0
476 */
477 public void setMinimum(int min) {
478 if (getMinimum() is min)
479 return;
480 getRangeModel().setMinimum(min);
481 }
482
483 /**
484 * @see Orientable#setOrientation(int)
485 */
486 public void setOrientation(int value) {
487 if ((value is HORIZONTAL) is isHorizontal())
488 return;
489 isHorizontal_ = value is HORIZONTAL;
490 transposer.setEnabled(isHorizontal_);
491
492 setChildrenOrientation(value);
493 super.revalidate();
494 }
495
496 /**
497 * Sets the ScrollBar to scroll <i>increment</i> pixels when its pageup or pagedown
498 * buttons are pressed. (Note that the pageup and pagedown buttons are <b>NOT</b> the
499 * arrow buttons, they are the figures between the arrow buttons and the ScrollBar's
500 * thumb figure).
501 *
502 * @param increment the new page increment
503 * @since 2.0
504 */
505 public void setPageIncrement(int increment) {
506 pageIncrement = increment;
507 }
508
509 /**
510 * Sets the pagedown button to the passed Clickable. The pagedown button is the figure
511 * between the down arrow button and the ScrollBar's thumb figure.
512 *
513 * @param down the page down figure
514 * @since 2.0
515 */
516 public void setPageDown(Clickable down) {
517 if (pageDown_ !is null)
518 remove(pageDown_);
519 pageDown_ = down;
520 if (pageDown_ !is null) {
521 pageDown_.setFiringMethod(Clickable.REPEAT_FIRING);
522 pageDown_.addActionListener(dgActionListener( (ActionEvent evt){
523 pageDown();
524 }));
525 add(down,stringcast( ScrollBarLayout.PAGE_DOWN));
526 }
527 }
528
529 /**
530 * Sets the pageup button to the passed Clickable. The pageup button is the rectangular
531 * figure between the down arrow button and the ScrollBar's thumb figure.
532 *
533 * @param up the page up figure
534 * @since 2.0
535 */
536 public void setPageUp(Clickable up) {
537 if (pageUp_ !is null)
538 remove(pageUp_);
539 pageUp_ = up;
540 if (pageUp_ !is null) {
541 pageUp_.setFiringMethod(Clickable.REPEAT_FIRING);
542 pageUp_.addActionListener(dgActionListener((ActionEvent evt){
543 pageUp();
544 }));
545 add(pageUp_, stringcast(ScrollBarLayout.PAGE_UP));
546 }
547 }
548
549 /**
550 * Sets the ScrollBar's RangeModel to the passed value.
551 *
552 * @param rangeModel the new range model
553 * @since 2.0
554 */
555 public void setRangeModel(RangeModel rangeModel) {
556 if (this.rangeModel !is null)
557 this.rangeModel.removePropertyChangeListener(this);
558 this.rangeModel = rangeModel;
559 rangeModel.addPropertyChangeListener(this);
560 }
561
562 /**
563 * Sets the ScrollBar's step increment to the passed value. The step increment indicates
564 * how many pixels the ScrollBar will scroll when its up or down arrow button is pressed.
565 *
566 * @param increment the new step increment
567 * @since 2.0
568 */
569 public void setStepIncrement(int increment) {
570 stepIncrement = increment;
571 }
572
573 /**
574 * Sets the ScrollBar's thumb to the passed Figure. The thumb is the draggable component
575 * of the ScrollBar that indicates the ScrollBar's position.
576 *
577 * @param figure the thumb figure
578 * @since 2.0
579 */
580 public void setThumb(IFigure figure) {
581 if (thumb !is null) {
582 thumb.removeMouseListener(thumbDragger);
583 thumb.removeMouseMotionListener(thumbDragger);
584 remove(thumb);
585 }
586 thumb = figure;
587 if (thumb !is null) {
588 thumb.addMouseListener(thumbDragger);
589 thumb.addMouseMotionListener(thumbDragger);
590 add(thumb, stringcast(ScrollBarLayout.THUMB));
591 }
592 }
593
594 /**
595 * Sets the value of the Scrollbar to <i>v</i>
596 *
597 * @param v the new value
598 * @since 2.0
599 */
600 public void setValue(int v) {
601 getRangeModel().setValue(v);
602 }
603
604 /**
605 * Causes the ScrollBar to scroll down (or right) by the value of its step increment.
606 *
607 * @since 2.0
608 */
609 protected void stepDown() {
610 setValue(getValue() + getStepIncrement());
611 }
612
613 /**
614 * Causes the ScrollBar to scroll up (or left) by the value of its step increment.
615 *
616 * @since 2.0
617 */
618 protected void stepUp() {
619 setValue(getValue() - getStepIncrement());
620 }
621
622 class ThumbDragger
623 : MouseMotionListener.Stub
624 , MouseListener
625 {
626 protected Point start;
627 protected int dragRange;
628 protected int revertValue;
629 protected bool armed;
630 public this() { }
631
632 public void mousePressed(MouseEvent me) {
633 armed = true;
634 start = me.getLocation();
635 Rectangle area = new Rectangle(transposer.t(getClientArea()));
636 Dimension thumbSize = transposer.t(getThumb().getSize());
637 if (getButtonUp() !is null)
638 area.height -= transposer.t(getButtonUp().getSize()).height;
639 if (getButtonDown() !is null)
640 area.height -= transposer.t(getButtonDown().getSize()).height;
641 Dimension sizeDifference = new Dimension(area.width,
642 area.height - thumbSize.height);
643 dragRange = sizeDifference.height;
644 revertValue = getValue();
645 me.consume();
646 }
647
648 public void mouseDragged(MouseEvent me) {
649 if (!armed)
650 return;
651 Dimension difference = transposer.t(me.getLocation().getDifference(start));
652 int change = getValueRange() * difference.height / dragRange;
653 setValue(revertValue + change);
654 me.consume();
655 }
656
657 public void mouseReleased(MouseEvent me) {
658 if (!armed)
659 return;
660 armed = false;
661 me.consume();
662 }
663
664 public void mouseDoubleClicked(MouseEvent me) { }
665 }
666
667 }