1 /* BasicScrollBarUI.java --
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax
.swing
.plaf
.basic
;
41 import java
.awt
.Color
;
42 import java
.awt
.Component
;
43 import java
.awt
.Container
;
44 import java
.awt
.Dimension
;
45 import java
.awt
.Graphics
;
46 import java
.awt
.Insets
;
47 import java
.awt
.LayoutManager
;
48 import java
.awt
.Point
;
49 import java
.awt
.Polygon
;
50 import java
.awt
.Rectangle
;
51 import java
.awt
.event
.ActionEvent
;
52 import java
.awt
.event
.ActionListener
;
53 import java
.awt
.event
.MouseAdapter
;
54 import java
.awt
.event
.MouseEvent
;
55 import java
.awt
.event
.MouseMotionListener
;
56 import java
.beans
.PropertyChangeEvent
;
57 import java
.beans
.PropertyChangeListener
;
59 import javax
.swing
.BoundedRangeModel
;
60 import javax
.swing
.JButton
;
61 import javax
.swing
.JComponent
;
62 import javax
.swing
.JScrollBar
;
63 import javax
.swing
.SwingConstants
;
64 import javax
.swing
.SwingUtilities
;
65 import javax
.swing
.Timer
;
66 import javax
.swing
.UIDefaults
;
67 import javax
.swing
.UIManager
;
68 import javax
.swing
.event
.ChangeEvent
;
69 import javax
.swing
.event
.ChangeListener
;
70 import javax
.swing
.plaf
.ComponentUI
;
71 import javax
.swing
.plaf
.ScrollBarUI
;
74 * The Basic Look and Feel UI delegate for JScrollBar.
76 public class BasicScrollBarUI
extends ScrollBarUI
implements LayoutManager
,
80 * A helper class that listens to the two JButtons on each end of the
83 protected class ArrowButtonListener
extends MouseAdapter
86 * Move the thumb in the direction specified by the button's arrow. If
87 * this button is held down, then it should keep moving the thumb.
89 * @param e The MouseEvent fired by the JButton.
91 public void mousePressed(MouseEvent e
)
94 scrollListener
.setScrollByBlock(false);
95 if (e
.getSource() == incrButton
)
96 scrollListener
.setDirection(POSITIVE_SCROLL
);
98 scrollListener
.setDirection(NEGATIVE_SCROLL
);
103 * Stops the thumb when the JButton is released.
105 * @param e The MouseEvent fired by the JButton.
107 public void mouseReleased(MouseEvent e
)
114 * A helper class that listens to the ScrollBar's model for ChangeEvents.
116 protected class ModelListener
implements ChangeListener
119 * Called when the model changes.
121 * @param e The ChangeEvent fired by the model.
123 public void stateChanged(ChangeEvent e
)
125 // System.err.println(this + ".stateChanged()");
126 calculatePreferredSize();
127 layoutContainer(scrollbar
);
134 * A helper class that listens to the ScrollBar's properties.
136 public class PropertyChangeHandler
implements PropertyChangeListener
139 * Called when one of the ScrollBar's properties change.
141 * @param e The PropertyChangeEvent fired by the ScrollBar.
143 public void propertyChange(PropertyChangeEvent e
)
145 if (e
.getPropertyName().equals("model"))
147 ((BoundedRangeModel
) e
.getOldValue()).removeChangeListener(modelListener
);
148 scrollbar
.getModel().addChangeListener(modelListener
);
151 else if (e
.getPropertyName().equals("orientation"))
153 incrButton
.removeMouseListener(buttonListener
);
154 decrButton
.removeMouseListener(buttonListener
);
155 incrButton
= createIncreaseButton(scrollbar
.getOrientation());
156 decrButton
= createDecreaseButton(scrollbar
.getOrientation());
157 incrButton
.addMouseListener(buttonListener
);
158 decrButton
.addMouseListener(buttonListener
);
159 calculatePreferredSize();
160 layoutContainer(scrollbar
);
162 layoutContainer(scrollbar
);
168 * A helper class that listens for events from the timer that is used to
171 protected class ScrollListener
implements ActionListener
173 /** The direction the thumb moves in. */
174 private transient int direction
;
176 /** Whether movement will be in blocks. */
177 private transient boolean block
;
180 * Creates a new ScrollListener object. The default is scrolling
181 * positively with block movement.
183 public ScrollListener()
185 direction
= POSITIVE_SCROLL
;
190 * Creates a new ScrollListener object using the given direction and
193 * @param dir The direction to move in.
194 * @param block Whether movement will be in blocks.
196 public ScrollListener(int dir
, boolean block
)
203 * Sets the direction to scroll in.
205 * @param direction The direction to scroll in.
207 public void setDirection(int direction
)
209 this.direction
= direction
;
213 * Sets whether scrolling will be done in blocks.
215 * @param block Whether scrolling will be in blocks.
217 public void setScrollByBlock(boolean block
)
223 * Called every time the timer reaches its interval.
225 * @param e The ActionEvent fired by the timer.
227 public void actionPerformed(ActionEvent e
)
231 // Only need to check it if it's block scrolling
232 // We only block scroll if the click occurs
234 if (! trackListener
.shouldScroll(direction
))
236 trackHighlight
= NO_HIGHLIGHT
;
240 scrollByBlock(direction
);
243 scrollByUnit(direction
);
248 * Helper class that listens for movement on the track.
250 protected class TrackListener
extends MouseAdapter
251 implements MouseMotionListener
253 /** The current X coordinate of the mouse. */
254 protected int currentMouseX
;
256 /** The current Y coordinate of the mouse. */
257 protected int currentMouseY
;
260 * The offset between the current mouse cursor and the current value of
263 protected int offset
;
266 * This method is called when the mouse is being dragged.
268 * @param e The MouseEvent given.
270 public void mouseDragged(MouseEvent e
)
272 currentMouseX
= e
.getX();
273 currentMouseY
= e
.getY();
274 if (scrollbar
.getValueIsAdjusting())
277 if (scrollbar
.getOrientation() == SwingConstants
.HORIZONTAL
)
278 value
= valueForXPosition(currentMouseX
) - offset
;
280 value
= valueForYPosition(currentMouseY
) - offset
;
282 scrollbar
.setValue(value
);
287 * This method is called when the mouse is moved.
289 * @param e The MouseEvent given.
291 public void mouseMoved(MouseEvent e
)
293 // Not interested in where the mouse
294 // is unless it is being dragged.
298 * This method is called when the mouse is pressed. When it is pressed,
299 * the thumb should move in blocks towards the cursor.
301 * @param e The MouseEvent given.
303 public void mousePressed(MouseEvent e
)
305 currentMouseX
= e
.getX();
306 currentMouseY
= e
.getY();
309 if (scrollbar
.getOrientation() == SwingConstants
.HORIZONTAL
)
310 value
= valueForXPosition(currentMouseX
);
312 value
= valueForYPosition(currentMouseY
);
314 if (value
== scrollbar
.getValue())
317 if (! thumbRect
.contains(e
.getPoint()))
320 scrollListener
.setScrollByBlock(true);
321 if (value
> scrollbar
.getValue())
323 trackHighlight
= INCREASE_HIGHLIGHT
;
324 scrollListener
.setDirection(POSITIVE_SCROLL
);
328 trackHighlight
= DECREASE_HIGHLIGHT
;
329 scrollListener
.setDirection(NEGATIVE_SCROLL
);
335 // We'd like to keep track of where the cursor
336 // is inside the thumb.
337 // This works because the scrollbar's value represents
338 // "lower" edge of the thumb. The value at which
339 // the cursor is at must be greater or equal
341 scrollbar
.setValueIsAdjusting(true);
342 offset
= value
- scrollbar
.getValue();
348 * This method is called when the mouse is released. It should stop
349 * movement on the thumb
351 * @param e The MouseEvent given.
353 public void mouseReleased(MouseEvent e
)
355 trackHighlight
= NO_HIGHLIGHT
;
358 if (scrollbar
.getValueIsAdjusting())
359 scrollbar
.setValueIsAdjusting(false);
364 * A helper method that decides whether we should keep scrolling in the
367 * @param direction The direction to check for.
369 * @return Whether the thumb should keep scrolling.
371 public boolean shouldScroll(int direction
)
374 if (scrollbar
.getOrientation() == HORIZONTAL
)
375 value
= valueForXPosition(currentMouseX
);
377 value
= valueForYPosition(currentMouseY
);
379 if (direction
== POSITIVE_SCROLL
)
380 return (value
> scrollbar
.getValue());
382 return (value
< scrollbar
.getValue());
386 /** The listener that listens to the JButtons. */
387 protected ArrowButtonListener buttonListener
;
389 /** The listener that listens to the model. */
390 protected ModelListener modelListener
;
392 /** The listener that listens to the scrollbar for property changes. */
393 protected PropertyChangeListener propertyChangeListener
;
395 /** The listener that listens to the timer. */
396 protected ScrollListener scrollListener
;
398 /** The listener that listens for MouseEvents on the track. */
399 protected TrackListener trackListener
;
401 /** The JButton that decrements the scrollbar's value. */
402 protected JButton decrButton
;
404 /** The JButton that increments the scrollbar's value. */
405 protected JButton incrButton
;
407 /** The dimensions of the maximum thumb size. */
408 protected Dimension maximumThumbSize
;
410 /** The dimensions of the minimum thumb size. */
411 protected Dimension minimumThumbSize
;
413 /** The color of the thumb. */
414 protected Color thumbColor
;
416 /** The outer shadow of the thumb. */
417 protected Color thumbDarkShadowColor
;
419 /** The top and left edge color for the thumb. */
420 protected Color thumbHighlightColor
;
422 /** The outer light shadow for the thumb. */
423 protected Color thumbLightShadowColor
;
425 /** The color that is used when the mouse press occurs in the track. */
426 protected Color trackHighlightColor
;
428 /** The color of the track. */
429 protected Color trackColor
;
431 /** The size and position of the track. */
432 protected Rectangle trackRect
;
434 /** The size and position of the thumb. */
435 protected Rectangle thumbRect
;
437 /** Indicates that the decrease highlight should be painted. */
438 protected static final int DECREASE_HIGHLIGHT
= 1;
440 /** Indicates that the increase highlight should be painted. */
441 protected static final int INCREASE_HIGHLIGHT
= 2;
443 /** Indicates that no highlight should be painted. */
444 protected static final int NO_HIGHLIGHT
= 0;
446 /** Indicates that the scrolling direction is positive. */
447 private static final int POSITIVE_SCROLL
= 1;
449 /** Indicates that the scrolling direction is negative. */
450 private static final int NEGATIVE_SCROLL
= -1;
452 /** The cached preferred size for the scrollbar. */
453 private transient Dimension preferredSize
;
455 /** The current highlight status. */
456 protected int trackHighlight
;
458 /** FIXME: Use this for something (presumably mouseDragged) */
459 protected boolean isDragging
;
461 /** The timer used to move the thumb when the mouse is held. */
462 protected Timer scrollTimer
;
464 /** The scrollbar this UI is acting for. */
465 protected JScrollBar scrollbar
;
468 * This method adds a component to the layout.
470 * @param name The name to associate with the component that is added.
471 * @param child The Component to add.
473 public void addLayoutComponent(String name
, Component child
)
475 // You should not be adding stuff to this component.
476 // The contents are fixed.
480 * This method configures the scrollbar's colors. This can be done by
481 * looking up the standard colors from the Look and Feel defaults.
483 protected void configureScrollBarColors()
485 UIDefaults defaults
= UIManager
.getLookAndFeelDefaults();
487 trackColor
= defaults
.getColor("ScrollBar.track");
488 trackHighlightColor
= defaults
.getColor("ScrollBar.trackHighlight");
489 thumbColor
= defaults
.getColor("ScrollBar.thumb");
490 thumbHighlightColor
= defaults
.getColor("ScrollBar.thumbHighlight");
491 thumbDarkShadowColor
= defaults
.getColor("ScrollBar.thumbDarkShadow");
492 thumbLightShadowColor
= defaults
.getColor("ScrollBar.thumbLightShadow");
496 * This method creates an ArrowButtonListener.
498 * @return A new ArrowButtonListener.
500 protected ArrowButtonListener
createArrowButtonListener()
502 return new ArrowButtonListener();
506 * This method creates a new JButton with the appropriate icon for the
509 * @param orientation The orientation this JButton uses.
511 * @return The increase JButton.
513 protected JButton
createIncreaseButton(int orientation
)
515 if (incrButton
== null)
516 incrButton
= new BasicArrowButton((orientation
== SwingConstants
.HORIZONTAL
)
517 ? SwingConstants
.EAST
518 : SwingConstants
.SOUTH
);
521 if (orientation
== SwingConstants
.HORIZONTAL
)
522 ((BasicArrowButton
) incrButton
).setDirection(SwingConstants
.EAST
);
524 ((BasicArrowButton
) incrButton
).setDirection(SwingConstants
.SOUTH
);
530 * This method creates a new JButton with the appropriate icon for the
533 * @param orientation The orientation this JButton uses.
535 * @return The decrease JButton.
537 protected JButton
createDecreaseButton(int orientation
)
539 if (decrButton
== null)
540 decrButton
= new BasicArrowButton((orientation
== SwingConstants
.HORIZONTAL
)
541 ? SwingConstants
.WEST
542 : SwingConstants
.NORTH
);
545 if (orientation
== SwingConstants
.HORIZONTAL
)
546 ((BasicArrowButton
) decrButton
).setDirection(SwingConstants
.WEST
);
548 ((BasicArrowButton
) decrButton
).setDirection(SwingConstants
.NORTH
);
554 * This method creates a new ModelListener.
556 * @return A new ModelListener.
558 protected ModelListener
createModelListener()
560 return new ModelListener();
564 * This method creates a new PropertyChangeListener.
566 * @return A new PropertyChangeListener.
568 protected PropertyChangeListener
createPropertyChangeListener()
570 return new PropertyChangeHandler();
574 * This method creates a new ScrollListener.
576 * @return A new ScrollListener.
578 protected ScrollListener
createScrollListener()
580 return new ScrollListener();
584 * This method creates a new TrackListener.
586 * @return A new TrackListener.
588 protected TrackListener
createTrackListener()
590 return new TrackListener();
594 * This method returns a new BasicScrollBarUI.
596 * @param c The JComponent to create a UI for.
598 * @return A new BasicScrollBarUI.
600 public static ComponentUI
createUI(JComponent c
)
602 return new BasicScrollBarUI();
606 * This method returns the maximum size for this JComponent.
608 * @param c The JComponent to measure the maximum size for.
610 * @return The maximum size for the component.
612 public Dimension
getMaximumSize(JComponent c
)
614 return getPreferredSize(c
);
618 * This method returns the maximum thumb size.
620 * @return The maximum thumb size.
622 protected Dimension
getMaximumThumbSize()
624 return maximumThumbSize
;
628 * This method returns the minimum size for this JComponent.
630 * @param c The JComponent to measure the minimum size for.
632 * @return The minimum size for the component.
634 public Dimension
getMinimumSize(JComponent c
)
636 return getPreferredSize(c
);
640 * This method returns the minimum thumb size.
642 * @return The minimum thumb size.
644 protected Dimension
getMinimumThumbSize()
646 return minimumThumbSize
;
650 * This method calculates the preferred size since calling
651 * getPreferredSize() returns a cached value.
653 private void calculatePreferredSize()
655 // System.err.println(this + ".calculatePreferredSize()");
660 if (scrollbar
.getOrientation() == SwingConstants
.HORIZONTAL
)
662 width
+= incrButton
.getPreferredSize().getWidth();
663 width
+= decrButton
.getPreferredSize().getWidth();
665 width
+= (scrollbar
.getMaximum() - scrollbar
.getMinimum());
667 height
= Math
.max(incrButton
.getPreferredSize().height
,
668 decrButton
.getPreferredSize().height
);
669 height
= Math
.max(getMinimumThumbSize().height
, height
);
670 height
= Math
.max(20, height
);
671 height
= Math
.min(getMaximumThumbSize().height
, height
);
675 height
+= incrButton
.getPreferredSize().getHeight();
676 height
+= decrButton
.getPreferredSize().getHeight();
678 height
+= (scrollbar
.getMaximum() - scrollbar
.getMinimum());
680 width
= Math
.max(incrButton
.getPreferredSize().width
,
681 decrButton
.getPreferredSize().width
);
682 width
= Math
.max(getMinimumThumbSize().width
, width
);
683 width
= Math
.max(20, width
);
684 width
= Math
.min(getMaximumThumbSize().width
, width
);
687 Insets insets
= scrollbar
.getInsets();
689 height
+= insets
.top
+ insets
.bottom
;
690 width
+= insets
.left
+ insets
.right
;
692 preferredSize
= new Dimension(width
, height
);
696 * This method returns a cached value of the preferredSize. The only
697 * restrictions are: If the scrollbar is horizontal, the height should be
698 * the maximum of the height of the JButtons and the minimum width of the
699 * thumb. For vertical scrollbars, the calculation is similar (swap width
700 * for height and vice versa).
702 * @param c The JComponent to measure.
704 * @return The preferredSize.
706 public Dimension
getPreferredSize(JComponent c
)
708 calculatePreferredSize();
709 return preferredSize
;
713 * This method returns the thumb's bounds based on the current value of the
714 * scrollbar. This method updates the cached value and returns that.
716 * @return The thumb bounds.
718 protected Rectangle
getThumbBounds()
720 int max
= scrollbar
.getMaximum();
721 int min
= scrollbar
.getMinimum();
722 int value
= scrollbar
.getValue();
723 int extent
= scrollbar
.getVisibleAmount();
725 // System.err.println(this + ".getThumbBounds()");
728 thumbRect
.x
= trackRect
.x
;
729 thumbRect
.y
= trackRect
.y
;
730 if (scrollbar
.getOrientation() == HORIZONTAL
)
732 thumbRect
.width
= getMinimumThumbSize().width
;
733 thumbRect
.height
= trackRect
.height
;
737 thumbRect
.width
= trackRect
.width
;
738 thumbRect
.height
= getMinimumThumbSize().height
;
743 if (scrollbar
.getOrientation() == HORIZONTAL
)
745 thumbRect
.x
= trackRect
.x
;
746 thumbRect
.x
+= (value
- min
) * trackRect
.width
/ (max
- min
);
747 thumbRect
.y
= trackRect
.y
;
749 thumbRect
.width
= extent
* trackRect
.width
/ (max
- min
);
750 thumbRect
.height
= trackRect
.height
;
754 thumbRect
.x
= trackRect
.x
;
755 thumbRect
.y
= trackRect
.y
+ value
* trackRect
.height
/ (max
- min
);
757 thumbRect
.width
= trackRect
.width
;
758 thumbRect
.height
= extent
* trackRect
.height
/ (max
- min
);
764 * This method calculates the bounds of the track. This method updates the
765 * cached value and returns it.
767 * @return The track's bounds.
769 protected Rectangle
getTrackBounds()
771 SwingUtilities
.calculateInnerArea(scrollbar
, trackRect
);
773 if (scrollbar
.getOrientation() == SwingConstants
.HORIZONTAL
)
775 trackRect
.width
-= incrButton
.getPreferredSize().getWidth();
776 trackRect
.width
-= decrButton
.getPreferredSize().getWidth();
778 trackRect
.x
+= decrButton
.getPreferredSize().getWidth();
782 trackRect
.height
-= incrButton
.getPreferredSize().getHeight();
783 trackRect
.height
-= decrButton
.getPreferredSize().getHeight();
785 trackRect
.y
+= incrButton
.getPreferredSize().getHeight();
791 * This method installs any addition Components that are a part of or
792 * related to this scrollbar.
794 protected void installComponents()
796 incrButton
= createIncreaseButton(scrollbar
.getOrientation());
797 scrollbar
.add(incrButton
);
798 decrButton
= createDecreaseButton(scrollbar
.getOrientation());
799 scrollbar
.add(decrButton
);
803 * This method installs the defaults for the scrollbar specified by the
804 * Basic Look and Feel.
806 protected void installDefaults()
808 UIDefaults defaults
= UIManager
.getLookAndFeelDefaults();
810 scrollbar
.setForeground(defaults
.getColor("ScrollBar.foreground"));
811 scrollbar
.setBackground(defaults
.getColor("ScrollBar.background"));
812 scrollbar
.setBorder(defaults
.getBorder("ScrollBar.border"));
813 scrollbar
.setOpaque(true);
815 maximumThumbSize
= defaults
.getDimension("ScrollBar.maximumThumbSize");
816 minimumThumbSize
= defaults
.getDimension("ScrollBar.minimumThumbSize");
820 * This method installs the keyboard actions for the scrollbar.
822 protected void installKeyboardActions()
828 * This method installs any listeners for the scrollbar. This method also
829 * installs listeners for things such as the JButtons and the timer.
831 protected void installListeners()
833 scrollListener
= createScrollListener();
834 trackListener
= createTrackListener();
835 buttonListener
= createArrowButtonListener();
836 modelListener
= createModelListener();
837 propertyChangeListener
= createPropertyChangeListener();
839 scrollbar
.addMouseMotionListener(trackListener
);
840 scrollbar
.addMouseListener(trackListener
);
842 incrButton
.addMouseListener(buttonListener
);
843 decrButton
.addMouseListener(buttonListener
);
845 scrollbar
.addPropertyChangeListener(propertyChangeListener
);
846 scrollbar
.getModel().addChangeListener(modelListener
);
848 scrollTimer
.addActionListener(scrollListener
);
852 * This method installs the UI for the component. This can include setting
853 * up listeners, defaults, and components. This also includes initializing
856 * @param c The JComponent to install.
858 public void installUI(JComponent c
)
861 if (c
instanceof JScrollBar
)
863 scrollbar
= (JScrollBar
) c
;
865 trackRect
= new Rectangle();
866 thumbRect
= new Rectangle();
868 scrollTimer
= new Timer(200, null);
869 scrollTimer
.setRepeats(true);
874 configureScrollBarColors();
876 calculatePreferredSize();
877 layoutContainer(scrollbar
);
882 * This method lays out the scrollbar.
884 * @param scrollbarContainer The Container to layout.
886 public void layoutContainer(Container scrollbarContainer
)
888 if (scrollbarContainer
instanceof JScrollBar
)
890 if (scrollbar
.getOrientation() == SwingConstants
.HORIZONTAL
)
891 layoutHScrollbar((JScrollBar
) scrollbarContainer
);
893 layoutVScrollbar((JScrollBar
) scrollbarContainer
);
898 * This method lays out the scrollbar horizontally.
900 * @param sb The JScrollBar to layout.
902 protected void layoutHScrollbar(JScrollBar sb
)
904 // All we have to do is layout the 2 buttons?
905 Rectangle vr
= new Rectangle();
906 SwingUtilities
.calculateInnerArea(scrollbar
, vr
);
908 // Update the rectangles.
912 Dimension incrDims
= incrButton
.getPreferredSize();
913 Dimension decrDims
= decrButton
.getPreferredSize();
915 decrButton
.setBounds(vr
.x
, vr
.y
, decrDims
.width
, trackRect
.height
);
916 incrButton
.setBounds(trackRect
.x
+ trackRect
.width
, vr
.y
, incrDims
.width
,
921 * This method lays out the scrollbar vertically.
923 * @param sb The JScrollBar to layout.
925 protected void layoutVScrollbar(JScrollBar sb
)
927 Rectangle vr
= new Rectangle();
928 SwingUtilities
.calculateInnerArea(scrollbar
, vr
);
934 Dimension incrDims
= incrButton
.getPreferredSize();
935 Dimension decrDims
= decrButton
.getPreferredSize();
937 decrButton
.setBounds(vr
.x
, vr
.y
, trackRect
.width
, decrDims
.height
);
938 incrButton
.setBounds(vr
.x
, trackRect
.y
+ trackRect
.height
,
939 trackRect
.width
, incrDims
.height
);
943 * This method returns the minimum size required for the layout.
945 * @param scrollbarContainer The Container that is laid out.
947 * @return The minimum size.
949 public Dimension
minimumLayoutSize(Container scrollbarContainer
)
951 return preferredLayoutSize(scrollbarContainer
);
955 * This method is called when the component is painted.
957 * @param g The Graphics object to paint with.
958 * @param c The JComponent to paint.
960 public void paint(Graphics g
, JComponent c
)
962 layoutContainer(scrollbar
);
963 paintTrack(g
, c
, getTrackBounds());
964 paintThumb(g
, c
, getThumbBounds());
966 if (trackHighlight
== INCREASE_HIGHLIGHT
)
967 paintIncreaseHighlight(g
);
968 else if (trackHighlight
== DECREASE_HIGHLIGHT
)
969 paintDecreaseHighlight(g
);
973 * This method is called when repainting and the mouse is pressed in the
974 * track. It paints the track below the thumb with the trackHighlight
977 * @param g The Graphics object to paint with.
979 protected void paintDecreaseHighlight(Graphics g
)
981 Color saved
= g
.getColor();
983 g
.setColor(trackHighlightColor
);
984 if (scrollbar
.getOrientation() == HORIZONTAL
)
985 g
.fillRect(trackRect
.x
, trackRect
.y
, thumbRect
.x
- trackRect
.x
,
988 g
.fillRect(trackRect
.x
, trackRect
.y
, trackRect
.width
,
989 thumbRect
.y
- trackRect
.y
);
994 * This method is called when repainting and the mouse is pressed in the
995 * track. It paints the track above the thumb with the trackHighlight
998 * @param g The Graphics objet to paint with.
1000 protected void paintIncreaseHighlight(Graphics g
)
1002 Color saved
= g
.getColor();
1004 g
.setColor(trackHighlightColor
);
1005 if (scrollbar
.getOrientation() == HORIZONTAL
)
1006 g
.fillRect(thumbRect
.x
+ thumbRect
.width
, trackRect
.y
,
1007 trackRect
.x
+ trackRect
.width
- thumbRect
.x
- thumbRect
.width
,
1010 g
.fillRect(trackRect
.x
, thumbRect
.y
+ thumbRect
.height
, trackRect
.width
,
1011 trackRect
.y
+ trackRect
.height
- thumbRect
.y
1012 - thumbRect
.height
);
1017 * This method paints the thumb.
1019 * @param g The Graphics object to paint with.
1020 * @param c The Component that is being painted.
1021 * @param thumbBounds The thumb bounds.
1023 protected void paintThumb(Graphics g
, JComponent c
, Rectangle thumbBounds
)
1025 Color saved
= g
.getColor();
1031 g
.setColor(thumbHighlightColor
);
1032 x
= new Point(thumbBounds
.x
+ 1, thumbBounds
.y
+ 1);
1034 y
.translate(thumbBounds
.width
- 2, 0);
1036 z
.translate(0, thumbBounds
.height
- 2);
1038 lines
= new Polygon(new int[] { x
.x
, y
.x
, z
.x
},
1039 new int[] { x
.y
, y
.y
, z
.y
}, 3);
1041 g
.drawPolygon(lines
);
1043 g
.setColor(thumbLightShadowColor
);
1044 x
= new Point(thumbBounds
.x
+ thumbBounds
.width
- 1,
1045 thumbBounds
.y
+ thumbBounds
.height
- 1);
1047 y
.translate(-(thumbBounds
.width
- 2), 0);
1049 z
.translate(0, -(thumbBounds
.height
- 2));
1051 lines
= new Polygon(new int[] { x
.x
, y
.x
, z
.x
},
1052 new int[] { x
.y
, y
.y
, z
.y
}, 3);
1053 g
.drawPolygon(lines
);
1055 g
.setColor(thumbDarkShadowColor
);
1056 x
= new Point(thumbBounds
.x
+ thumbBounds
.width
,
1057 thumbBounds
.y
+ thumbBounds
.height
);
1059 y
.translate(-thumbBounds
.width
, 0);
1061 z
.translate(0, -thumbBounds
.height
);
1063 lines
= new Polygon(new int[] { x
.x
, y
.x
, z
.x
},
1064 new int[] { x
.y
, y
.y
, z
.y
}, 3);
1065 g
.drawPolygon(lines
);
1067 g
.setColor(thumbColor
);
1068 g
.fillRect(thumbBounds
.x
, thumbBounds
.y
, thumbBounds
.width
,
1069 thumbBounds
.height
);
1075 * This method paints the track.
1077 * @param g The Graphics object to paint with.
1078 * @param c The JComponent being painted.
1079 * @param trackBounds The track's bounds.
1081 protected void paintTrack(Graphics g
, JComponent c
, Rectangle trackBounds
)
1083 Color saved
= g
.getColor();
1084 g
.setColor(trackColor
);
1085 g
.fill3DRect(trackBounds
.x
, trackBounds
.y
, trackBounds
.width
,
1086 trackBounds
.height
, false);
1091 * This method returns the preferred size for the layout.
1093 * @param scrollbarContainer The Container to find a size for.
1095 * @return The preferred size for the layout.
1097 public Dimension
preferredLayoutSize(Container scrollbarContainer
)
1099 if (scrollbarContainer
instanceof JComponent
)
1100 return getPreferredSize((JComponent
) scrollbarContainer
);
1106 * This method removes a child component from the layout.
1108 * @param child The child to remove.
1110 public void removeLayoutComponent(Component child
)
1112 // You should not be removing stuff from this component.
1116 * The method scrolls the thumb by a block in the direction specified.
1118 * @param direction The direction to scroll.
1120 protected void scrollByBlock(int direction
)
1122 scrollbar
.setValue(scrollbar
.getValue()
1123 + scrollbar
.getBlockIncrement(direction
));
1127 * The method scrolls the thumb by a unit in the direction specified.
1129 * @param direction The direction to scroll.
1131 protected void scrollByUnit(int direction
)
1133 scrollbar
.setValue(scrollbar
.getValue()
1134 + scrollbar
.getUnitIncrement(direction
));
1138 * This method sets the thumb's bounds.
1140 * @param x The X position of the thumb.
1141 * @param y The Y position of the thumb.
1142 * @param width The width of the thumb.
1143 * @param height The height of the thumb.
1145 protected void setThumbBounds(int x
, int y
, int width
, int height
)
1149 thumbRect
.width
= width
;
1150 thumbRect
.height
= height
;
1154 * This method uninstalls any components that are a part of or related to
1157 protected void uninstallComponents()
1159 scrollbar
.remove(incrButton
);
1160 scrollbar
.remove(decrButton
);
1166 * This method uninstalls any defaults that this scrollbar acquired from the
1167 * Basic Look and Feel defaults.
1169 protected void uninstallDefaults()
1171 scrollbar
.setForeground(null);
1172 scrollbar
.setBackground(null);
1173 scrollbar
.setBorder(null);
1177 * This method uninstalls any keyboard actions this scrollbar acquired
1180 protected void uninstallKeyboardActions()
1182 // FIXME: implement.
1186 * This method uninstalls any listeners that were registered during install.
1188 protected void uninstallListeners()
1190 scrollTimer
.removeActionListener(scrollListener
);
1192 scrollbar
.getModel().removeChangeListener(modelListener
);
1193 scrollbar
.removePropertyChangeListener(propertyChangeListener
);
1195 decrButton
.removeMouseListener(buttonListener
);
1196 incrButton
.removeMouseListener(buttonListener
);
1198 scrollbar
.removeMouseListener(trackListener
);
1199 scrollbar
.removeMouseMotionListener(trackListener
);
1201 propertyChangeListener
= null;
1202 modelListener
= null;
1203 buttonListener
= null;
1204 trackListener
= null;
1205 scrollListener
= null;
1209 * This method uninstalls the UI. This includes removing any defaults,
1210 * listeners, and components that this UI may have initialized. It also
1211 * nulls any instance data.
1213 * @param c The Component to uninstall for.
1215 public void uninstallUI(JComponent c
)
1217 uninstallDefaults();
1218 uninstallListeners();
1219 uninstallComponents();
1227 trackHighlightColor
= null;
1229 thumbHighlightColor
= null;
1230 thumbDarkShadowColor
= null;
1231 thumbLightShadowColor
= null;
1237 * This method returns the value in the scrollbar's range given the y
1238 * coordinate. If the value is out of range, it will return the closest
1241 * @param yPos The y coordinate to calculate a value for.
1243 * @return The value for the y coordinate.
1245 private int valueForYPosition(int yPos
)
1247 int min
= scrollbar
.getMinimum();
1248 int max
= scrollbar
.getMaximum();
1249 int len
= trackRect
.height
;
1253 // If the length is 0, you shouldn't be able to even see where the thumb is.
1254 // This really shouldn't ever happen, but just in case, we'll return the middle.
1256 return ((max
- min
) / 2);
1258 value
= ((yPos
- trackRect
.y
) * (max
- min
) / len
+ min
);
1260 // If this isn't a legal value, then we'll have to move to one now.
1263 else if (value
< min
)
1269 * This method returns the value in the scrollbar's range given the x
1270 * coordinate. If the value is out of range, it will return the closest
1273 * @param xPos The x coordinate to calculate a value for.
1275 * @return The value for the x coordinate.
1277 private int valueForXPosition(int xPos
)
1279 int min
= scrollbar
.getMinimum();
1280 int max
= scrollbar
.getMaximum();
1281 int len
= trackRect
.width
;
1285 // If the length is 0, you shouldn't be able to even see where the slider is.
1286 // This really shouldn't ever happen, but just in case, we'll return the middle.
1288 return ((max
- min
) / 2);
1290 value
= ((xPos
- trackRect
.x
) * (max
- min
) / len
+ min
);
1292 // If this isn't a legal value, then we'll have to move to one now.
1295 else if (value
< min
)