BasicScrollBarUI.java [plain text]
package javax.swing.plaf.basic;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BoundedRangeModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ScrollBarUI;
public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
SwingConstants
{
protected class ArrowButtonListener extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
scrollTimer.stop();
scrollListener.setScrollByBlock(false);
if (e.getSource() == incrButton)
scrollListener.setDirection(POSITIVE_SCROLL);
else
scrollListener.setDirection(NEGATIVE_SCROLL);
scrollTimer.start();
}
public void mouseReleased(MouseEvent e)
{
scrollTimer.stop();
}
}
protected class ModelListener implements ChangeListener
{
public void stateChanged(ChangeEvent e)
{
getThumbBounds();
scrollbar.repaint();
}
}
public class PropertyChangeHandler implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent e)
{
if (e.getPropertyName().equals(JScrollBar.MODEL_CHANGED_PROPERTY))
{
((BoundedRangeModel) e.getOldValue()).removeChangeListener(modelListener);
scrollbar.getModel().addChangeListener(modelListener);
getThumbBounds();
}
else if (e.getPropertyName().equals(JScrollBar.ORIENTATION_CHANGED_PROPERTY))
{
incrButton.removeMouseListener(buttonListener);
decrButton.removeMouseListener(buttonListener);
incrButton = createIncreaseButton(scrollbar.getOrientation());
decrButton = createDecreaseButton(scrollbar.getOrientation());
incrButton.addMouseListener(buttonListener);
decrButton.addMouseListener(buttonListener);
calculatePreferredSize();
layoutContainer(scrollbar);
}
layoutContainer(scrollbar);
scrollbar.repaint();
}
}
protected class ScrollListener implements ActionListener
{
private transient int direction;
private transient boolean block;
public ScrollListener()
{
direction = POSITIVE_SCROLL;
block = true;
}
public ScrollListener(int dir, boolean block)
{
direction = dir;
this.block = block;
}
public void setDirection(int direction)
{
this.direction = direction;
}
public void setScrollByBlock(boolean block)
{
this.block = block;
}
public void actionPerformed(ActionEvent e)
{
if (block)
{
if (!trackListener.shouldScroll(direction))
{
trackHighlight = NO_HIGHLIGHT;
scrollbar.repaint();
return;
}
scrollByBlock(direction);
}
else
scrollByUnit(direction);
}
}
protected class TrackListener extends MouseAdapter
implements MouseMotionListener
{
protected int currentMouseX;
protected int currentMouseY;
protected int offset;
public void mouseDragged(MouseEvent e)
{
currentMouseX = e.getX();
currentMouseY = e.getY();
if (scrollbar.getValueIsAdjusting())
{
int value;
if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
value = valueForXPosition(currentMouseX) - offset;
else
value = valueForYPosition(currentMouseY) - offset;
scrollbar.setValue(value);
}
}
public void mouseMoved(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
currentMouseX = e.getX();
currentMouseY = e.getY();
int value;
if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
value = valueForXPosition(currentMouseX);
else
value = valueForYPosition(currentMouseY);
if (value == scrollbar.getValue())
return;
if (!thumbRect.contains(e.getPoint()))
{
scrollTimer.stop();
scrollListener.setScrollByBlock(true);
if (value > scrollbar.getValue())
{
trackHighlight = INCREASE_HIGHLIGHT;
scrollListener.setDirection(POSITIVE_SCROLL);
}
else
{
trackHighlight = DECREASE_HIGHLIGHT;
scrollListener.setDirection(NEGATIVE_SCROLL);
}
scrollTimer.start();
}
else
{
scrollbar.setValueIsAdjusting(true);
offset = value - scrollbar.getValue();
}
scrollbar.repaint();
}
public void mouseReleased(MouseEvent e)
{
trackHighlight = NO_HIGHLIGHT;
scrollTimer.stop();
if (scrollbar.getValueIsAdjusting())
scrollbar.setValueIsAdjusting(false);
scrollbar.repaint();
}
public boolean shouldScroll (int direction)
{
int value;
if (scrollbar.getOrientation() == HORIZONTAL)
value = valueForXPosition(currentMouseX);
else
value = valueForYPosition(currentMouseY);
if (direction == POSITIVE_SCROLL)
return (value > scrollbar.getValue());
else
return (value < scrollbar.getValue());
}
}
protected ArrowButtonListener buttonListener;
protected ModelListener modelListener;
protected PropertyChangeListener propertyChangeListener;
protected ScrollListener scrollListener;
protected TrackListener trackListener;
protected JButton decrButton;
protected JButton incrButton;
protected static Dimension maximumThumbSize;
protected static Dimension minimumThumbSize;
protected Color thumbColor;
protected Color thumbDarkShadowColor;
protected Color thumbHighlightColor;
protected Color thumbLightShadowColor;
protected Color trackHighlightColor;
protected Color trackColor;
protected Rectangle trackRect;
protected Rectangle thumbRect;
protected static int DECREASE_HIGHLIGHT = 1;
protected static int INCREASE_HIGHLIGHT = 2;
protected static int NO_HIGHLIGHT = 0;
private static int POSITIVE_SCROLL = 1;
private static int NEGATIVE_SCROLL = -1;
private transient Dimension preferredSize;
protected int trackHighlight;
protected boolean isDragging;
protected Timer scrollTimer;
protected JScrollBar scrollbar;
private static class arrowIcon implements Icon
{
private Polygon arrow;
public arrowIcon(Polygon arrow)
{
this.arrow = arrow;
}
public int getIconHeight()
{
return 10;
}
public int getIconWidth()
{
return 10;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.translate(x, y);
Color saved = g.getColor();
g.setColor(Color.BLACK);
g.fillPolygon(arrow);
g.setColor(saved);
g.translate(-x, -y);
}
}
private static Icon upIcon = new arrowIcon(new Polygon(new int[] { 2, 5, 8 },
new int[] { 7, 3, 7 },
3));
private static Icon downIcon = new arrowIcon(new Polygon(new int[] { 2, 5, 8 },
new int[] { 3, 7, 3 },
3));
private static Icon leftIcon = new arrowIcon(new Polygon(new int[] { 7, 3, 7 },
new int[] { 2, 5, 8 },
3));
private static Icon rightIcon = new arrowIcon(new Polygon(new int[]
{
3, 7, 3
},
new int[]
{
2, 5, 8
}, 3));
public void addLayoutComponent(String name, Component child)
{
}
protected void configureScrollBarColors()
{
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
trackColor = defaults.getColor("ScrollBar.track");
trackHighlightColor = defaults.getColor("ScrollBar.trackHighlight");
thumbColor = defaults.getColor("ScrollBar.thumb");
thumbHighlightColor = defaults.getColor("ScrollBar.thumbHighlight");
thumbDarkShadowColor = defaults.getColor("ScrollBar.thumbDarkShadow");
thumbLightShadowColor = defaults.getColor("ScrollBar.thumbLightShadow");
}
protected ArrowButtonListener createArrowButtonListener()
{
return new ArrowButtonListener();
}
protected JButton createIncreaseButton(int orientation)
{
if (incrButton == null)
incrButton = new JButton();
if (orientation == SwingConstants.HORIZONTAL)
incrButton.setIcon(rightIcon);
else
incrButton.setIcon(downIcon);
return incrButton;
}
protected JButton createDecreaseButton(int orientation)
{
if (decrButton == null)
decrButton = new JButton();
if (orientation == SwingConstants.HORIZONTAL)
decrButton.setIcon(leftIcon);
else
decrButton.setIcon(upIcon);
return decrButton;
}
protected ModelListener createModelListener()
{
return new ModelListener();
}
protected PropertyChangeListener createPropertyChangeListener()
{
return new PropertyChangeHandler();
}
protected ScrollListener createScrollListener()
{
return new ScrollListener();
}
protected TrackListener createTrackListener()
{
return new TrackListener();
}
public static ComponentUI createUI(JComponent c)
{
return new BasicScrollBarUI();
}
public Dimension getMaximumSize(JComponent c)
{
return getPreferredSize(c);
}
protected Dimension getMaximumThumbSize()
{
return maximumThumbSize;
}
public Dimension getMinimumSize(JComponent c)
{
return getPreferredSize(c);
}
protected Dimension getMinimumThumbSize()
{
return minimumThumbSize;
}
private void calculatePreferredSize()
{
int height;
int width;
height = width = 0;
if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
{
width += incrButton.getPreferredSize().getWidth();
width += decrButton.getPreferredSize().getWidth();
width += Math.max(200, scrollbar.getVisibleAmount());
height = Math.max(incrButton.getPreferredSize().height,
decrButton.getPreferredSize().height);
height = Math.max(getMinimumThumbSize().height, height);
height = Math.max(20, height);
height = Math.min(getMaximumThumbSize().height, height);
}
else
{
height += incrButton.getPreferredSize().getHeight();
height += decrButton.getPreferredSize().getHeight();
height += Math.max(200, scrollbar.getVisibleAmount());
width = Math.max(incrButton.getPreferredSize().width,
decrButton.getPreferredSize().width);
width = Math.max(getMinimumThumbSize().width, width);
width = Math.max(20, width);
width = Math.min(getMaximumThumbSize().width, width);
}
Insets insets = scrollbar.getInsets();
height += insets.top + insets.bottom;
width += insets.left + insets.right;
preferredSize = new Dimension(width, height);
}
public Dimension getPreferredSize(JComponent c)
{
layoutContainer(scrollbar);
return preferredSize;
}
protected Rectangle getThumbBounds()
{
int max = scrollbar.getMaximum();
int min = scrollbar.getMinimum();
int value = scrollbar.getValue();
int extent = scrollbar.getVisibleAmount();
if (max == min)
{
thumbRect.x = trackRect.x;
thumbRect.y = trackRect.y;
if (scrollbar.getOrientation() == HORIZONTAL)
{
thumbRect.width = getMinimumThumbSize().width;
thumbRect.height = trackRect.height;
}
else
{
thumbRect.width = trackRect.width;
thumbRect.height = getMinimumThumbSize().height;
}
return thumbRect;
}
if (scrollbar.getOrientation() == HORIZONTAL)
{
thumbRect.x = trackRect.x;
thumbRect.x += (value - min) * trackRect.width / (max - min);
thumbRect.y = trackRect.y;
thumbRect.width = extent * trackRect.width / (max - min);
thumbRect.height = trackRect.height;
}
else
{
thumbRect.x = trackRect.x;
thumbRect.y = trackRect.y
+ value * trackRect.height / (max - min);
thumbRect.width = trackRect.width;
thumbRect.height = extent * trackRect.height / (max - min);
}
return thumbRect;
}
protected Rectangle getTrackBounds()
{
SwingUtilities.calculateInnerArea(scrollbar, trackRect);
if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
{
trackRect.width -= incrButton.getPreferredSize().getWidth();
trackRect.width -= decrButton.getPreferredSize().getWidth();
trackRect.x += decrButton.getPreferredSize().getWidth();
}
else
{
trackRect.height -= incrButton.getPreferredSize().getHeight();
trackRect.height -= decrButton.getPreferredSize().getHeight();
trackRect.y += incrButton.getPreferredSize().getHeight();
}
return trackRect;
}
protected void installComponents()
{
incrButton = createIncreaseButton(scrollbar.getOrientation());
scrollbar.add(incrButton);
decrButton = createDecreaseButton(scrollbar.getOrientation());
scrollbar.add(decrButton);
}
protected void installDefaults()
{
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
scrollbar.setForeground(defaults.getColor("ScrollBar.foreground"));
scrollbar.setBackground(defaults.getColor("ScrollBar.background"));
scrollbar.setBorder(defaults.getBorder("ScrollBar.border"));
maximumThumbSize = defaults.getDimension("ScrollBar.maximumThumbSize");
minimumThumbSize = defaults.getDimension("ScrollBar.minimumThumbSize");
}
protected void installKeyboardActions()
{
}
protected void installListeners()
{
scrollListener = createScrollListener();
trackListener = createTrackListener();
buttonListener = createArrowButtonListener();
modelListener = createModelListener();
propertyChangeListener = createPropertyChangeListener();
scrollbar.addMouseMotionListener(trackListener);
scrollbar.addMouseListener(trackListener);
incrButton.addMouseListener(buttonListener);
decrButton.addMouseListener(buttonListener);
scrollbar.addPropertyChangeListener(propertyChangeListener);
scrollbar.getModel().addChangeListener(modelListener);
scrollTimer.addActionListener(scrollListener);
}
public void installUI(JComponent c)
{
super.installUI(c);
if (c instanceof JScrollBar)
{
scrollbar = (JScrollBar) c;
trackRect = new Rectangle();
thumbRect = new Rectangle();
scrollTimer = new Timer();
scrollTimer.setDelay(200);
scrollTimer.setRepeats(true);
installComponents();
installListeners();
installDefaults();
configureScrollBarColors();
calculatePreferredSize();
layoutContainer(scrollbar);
}
}
public void layoutContainer(Container scrollbarContainer)
{
if (scrollbarContainer instanceof JScrollBar)
{
if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
layoutHScrollbar((JScrollBar) scrollbarContainer);
else
layoutVScrollbar((JScrollBar) scrollbarContainer);
}
}
protected void layoutHScrollbar(JScrollBar sb)
{
Rectangle vr = new Rectangle();
SwingUtilities.calculateInnerArea(scrollbar, vr);
getTrackBounds();
getThumbBounds();
Dimension incrDims = incrButton.getPreferredSize();
Dimension decrDims = decrButton.getPreferredSize();
decrButton.setBounds(vr.x, vr.y, decrDims.width, trackRect.height);
incrButton.setBounds(trackRect.x + trackRect.width, vr.y, incrDims.width,
trackRect.height);
}
protected void layoutVScrollbar(JScrollBar sb)
{
Rectangle vr = new Rectangle();
SwingUtilities.calculateInnerArea(scrollbar, vr);
getTrackBounds();
getThumbBounds();
Dimension incrDims = incrButton.getPreferredSize();
Dimension decrDims = decrButton.getPreferredSize();
decrButton.setBounds(vr.x, vr.y, trackRect.width, decrDims.height);
incrButton.setBounds(vr.x, trackRect.y + trackRect.height,
trackRect.width, incrDims.height);
}
public Dimension minimumLayoutSize(Container scrollbarContainer)
{
return preferredLayoutSize(scrollbarContainer);
}
public void paint(Graphics g, JComponent c)
{
layoutContainer(scrollbar);
paintTrack(g, c, getTrackBounds());
paintThumb(g, c, getThumbBounds());
if (trackHighlight == INCREASE_HIGHLIGHT)
paintIncreaseHighlight(g);
else if (trackHighlight == DECREASE_HIGHLIGHT)
paintDecreaseHighlight(g);
}
protected void paintDecreaseHighlight(Graphics g)
{
Color saved = g.getColor();
g.setColor(trackHighlightColor);
if (scrollbar.getOrientation() == HORIZONTAL)
g.fillRect(trackRect.x, trackRect.y, thumbRect.x - trackRect.x,
trackRect.height);
else
g.fillRect(trackRect.x, trackRect.y, trackRect.width,
thumbRect.y - trackRect.y);
g.setColor(saved);
}
protected void paintIncreaseHighlight(Graphics g)
{
Color saved = g.getColor();
g.setColor(trackHighlightColor);
if (scrollbar.getOrientation() == HORIZONTAL)
g.fillRect(thumbRect.x + thumbRect.width, trackRect.y,
trackRect.x + trackRect.width - thumbRect.x - thumbRect.width,
trackRect.height);
else
g.fillRect(trackRect.x, thumbRect.y + thumbRect.height,
trackRect.width,
trackRect.y + trackRect.height - thumbRect.y -
thumbRect.height);
g.setColor(saved);
}
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
{
Color saved = g.getColor();
Point x;
Point y;
Point z;
Polygon lines;
g.setColor(thumbHighlightColor);
x = new Point(thumbBounds.x + 1, thumbBounds.y + 1);
y = new Point(x);
y.translate(thumbBounds.width - 2, 0);
z = new Point(x);
z.translate(0, thumbBounds.height - 2);
lines = new Polygon(new int[] { x.x, y.x, z.x },
new int[] { x.y, y.y, z.y }, 3);
g.drawPolygon(lines);
g.setColor(thumbLightShadowColor);
x = new Point(thumbBounds.x + thumbBounds.width - 1,
thumbBounds.y + thumbBounds.height - 1);
y = new Point(x);
y.translate(-(thumbBounds.width - 2), 0);
z = new Point(x);
z.translate(0, -(thumbBounds.height - 2));
lines = new Polygon(new int[] { x.x, y.x, z.x },
new int[] { x.y, y.y, z.y }, 3);
g.drawPolygon(lines);
g.setColor(thumbDarkShadowColor);
x = new Point(thumbBounds.x + thumbBounds.width,
thumbBounds.y + thumbBounds.height);
y = new Point(x);
y.translate(-thumbBounds.width, 0);
z = new Point(x);
z.translate(0, -thumbBounds.height);
lines = new Polygon(new int[] { x.x, y.x, z.x },
new int[] { x.y, y.y, z.y }, 3);
g.drawPolygon(lines);
g.setColor(thumbColor);
g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width,
thumbBounds.height);
g.setColor(saved);
}
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
{
Color saved = g.getColor();
g.setColor(trackColor);
g.fill3DRect(trackBounds.x, trackBounds.y, trackBounds.width,
trackBounds.height, false);
g.setColor(saved);
}
public Dimension preferredLayoutSize(Container scrollbarContainer)
{
if (scrollbarContainer instanceof JComponent)
return getPreferredSize((JComponent) scrollbarContainer);
else
return null;
}
public void removeLayoutComponent(Component child)
{
}
protected void scrollByBlock(int direction)
{
scrollbar.setValue(scrollbar.getValue() + scrollbar.getBlockIncrement(direction));
}
protected void scrollByUnit(int direction)
{
scrollbar.setValue(scrollbar.getValue() + scrollbar.getUnitIncrement(direction));
}
protected void setThumbBounds(int x, int y, int width, int height)
{
thumbRect.x = x;
thumbRect.y = y;
thumbRect.width = width;
thumbRect.height = height;
}
protected void uninstallComponents()
{
scrollbar.remove(incrButton);
scrollbar.remove(decrButton);
incrButton = null;
decrButton = null;
}
protected void uninstallDefaults()
{
scrollbar.setForeground(null);
scrollbar.setBackground(null);
scrollbar.setBorder(null);
}
protected void uninstallKeyboardActions()
{
}
protected void uninstallListeners()
{
scrollTimer.removeActionListener(scrollListener);
scrollbar.getModel().removeChangeListener(modelListener);
scrollbar.removePropertyChangeListener(propertyChangeListener);
decrButton.removeMouseListener(buttonListener);
incrButton.removeMouseListener(buttonListener);
scrollbar.removeMouseListener(trackListener);
scrollbar.removeMouseMotionListener(trackListener);
propertyChangeListener = null;
modelListener = null;
buttonListener = null;
trackListener = null;
scrollListener = null;
}
public void uninstallUI(JComponent c)
{
uninstallDefaults();
uninstallListeners();
uninstallComponents();
scrollTimer = null;
thumbRect = null;
trackRect = null;
trackColor = null;
trackHighlightColor = null;
thumbColor = null;
thumbHighlightColor = null;
thumbDarkShadowColor = null;
thumbLightShadowColor = null;
scrollbar = null;
}
private int valueForYPosition(int yPos)
{
int min = scrollbar.getMinimum();
int max = scrollbar.getMaximum();
int len = trackRect.height;
int value;
if (len == 0)
return ((max - min) / 2);
value = ((yPos - trackRect.y) * (max - min) / len + min);
if (value > max)
value = max;
else if (value < min)
value = min;
return value;
}
private int valueForXPosition(int xPos)
{
int min = scrollbar.getMinimum();
int max = scrollbar.getMaximum();
int len = trackRect.width;
int value;
if (len == 0)
return ((max - min) / 2);
value = ((xPos - trackRect.x) * (max - min) / len + min);
if (value > max)
value = max;
else if (value < min)
value = min;
return value;
}
}