You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2026 lines
69 KiB
2026 lines
69 KiB
/*
|
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.swing.plaf.basic;
|
|
|
|
import java.awt.event.*;
|
|
import java.awt.*;
|
|
import java.beans.*;
|
|
import java.util.Dictionary;
|
|
import java.util.Enumeration;
|
|
|
|
import javax.swing.*;
|
|
import javax.swing.event.*;
|
|
import javax.swing.plaf.*;
|
|
import sun.swing.DefaultLookup;
|
|
import sun.swing.UIAction;
|
|
|
|
|
|
/**
|
|
* A Basic L&F implementation of SliderUI.
|
|
*
|
|
* @author Tom Santos
|
|
*/
|
|
public class BasicSliderUI extends SliderUI{
|
|
// Old actions forward to an instance of this.
|
|
private static final Actions SHARED_ACTION = new Actions();
|
|
|
|
public static final int POSITIVE_SCROLL = +1;
|
|
public static final int NEGATIVE_SCROLL = -1;
|
|
public static final int MIN_SCROLL = -2;
|
|
public static final int MAX_SCROLL = +2;
|
|
|
|
protected Timer scrollTimer;
|
|
protected JSlider slider;
|
|
|
|
protected Insets focusInsets = null;
|
|
protected Insets insetCache = null;
|
|
protected boolean leftToRightCache = true;
|
|
protected Rectangle focusRect = null;
|
|
protected Rectangle contentRect = null;
|
|
protected Rectangle labelRect = null;
|
|
protected Rectangle tickRect = null;
|
|
protected Rectangle trackRect = null;
|
|
protected Rectangle thumbRect = null;
|
|
|
|
protected int trackBuffer = 0; // The distance that the track is from the side of the control
|
|
|
|
private transient boolean isDragging;
|
|
|
|
protected TrackListener trackListener;
|
|
protected ChangeListener changeListener;
|
|
protected ComponentListener componentListener;
|
|
protected FocusListener focusListener;
|
|
protected ScrollListener scrollListener;
|
|
protected PropertyChangeListener propertyChangeListener;
|
|
private Handler handler;
|
|
private int lastValue;
|
|
|
|
// Colors
|
|
private Color shadowColor;
|
|
private Color highlightColor;
|
|
private Color focusColor;
|
|
|
|
/**
|
|
* Whther or not sameLabelBaselines is up to date.
|
|
*/
|
|
private boolean checkedLabelBaselines;
|
|
/**
|
|
* Whether or not all the entries in the labeltable have the same
|
|
* baseline.
|
|
*/
|
|
private boolean sameLabelBaselines;
|
|
|
|
|
|
protected Color getShadowColor() {
|
|
return shadowColor;
|
|
}
|
|
|
|
protected Color getHighlightColor() {
|
|
return highlightColor;
|
|
}
|
|
|
|
protected Color getFocusColor() {
|
|
return focusColor;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the user is dragging the slider.
|
|
*
|
|
* @return true if the user is dragging the slider
|
|
* @since 1.5
|
|
*/
|
|
protected boolean isDragging() {
|
|
return isDragging;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ComponentUI Interface Implementation methods
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
public static ComponentUI createUI(JComponent b) {
|
|
return new BasicSliderUI((JSlider)b);
|
|
}
|
|
|
|
public BasicSliderUI(JSlider b) {
|
|
}
|
|
|
|
public void installUI(JComponent c) {
|
|
slider = (JSlider) c;
|
|
|
|
checkedLabelBaselines = false;
|
|
|
|
slider.setEnabled(slider.isEnabled());
|
|
LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE);
|
|
|
|
isDragging = false;
|
|
trackListener = createTrackListener( slider );
|
|
changeListener = createChangeListener( slider );
|
|
componentListener = createComponentListener( slider );
|
|
focusListener = createFocusListener( slider );
|
|
scrollListener = createScrollListener( slider );
|
|
propertyChangeListener = createPropertyChangeListener( slider );
|
|
|
|
installDefaults( slider );
|
|
installListeners( slider );
|
|
installKeyboardActions( slider );
|
|
|
|
scrollTimer = new Timer( 100, scrollListener );
|
|
scrollTimer.setInitialDelay( 300 );
|
|
|
|
insetCache = slider.getInsets();
|
|
leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider);
|
|
focusRect = new Rectangle();
|
|
contentRect = new Rectangle();
|
|
labelRect = new Rectangle();
|
|
tickRect = new Rectangle();
|
|
trackRect = new Rectangle();
|
|
thumbRect = new Rectangle();
|
|
lastValue = slider.getValue();
|
|
|
|
calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are.
|
|
}
|
|
|
|
public void uninstallUI(JComponent c) {
|
|
if ( c != slider )
|
|
throw new IllegalComponentStateException(
|
|
this + " was asked to deinstall() "
|
|
+ c + " when it only knows about "
|
|
+ slider + ".");
|
|
|
|
scrollTimer.stop();
|
|
scrollTimer = null;
|
|
|
|
uninstallDefaults(slider);
|
|
uninstallListeners( slider );
|
|
uninstallKeyboardActions(slider);
|
|
|
|
insetCache = null;
|
|
leftToRightCache = true;
|
|
focusRect = null;
|
|
contentRect = null;
|
|
labelRect = null;
|
|
tickRect = null;
|
|
trackRect = null;
|
|
thumbRect = null;
|
|
trackListener = null;
|
|
changeListener = null;
|
|
componentListener = null;
|
|
focusListener = null;
|
|
scrollListener = null;
|
|
propertyChangeListener = null;
|
|
slider = null;
|
|
}
|
|
|
|
protected void installDefaults( JSlider slider ) {
|
|
LookAndFeel.installBorder(slider, "Slider.border");
|
|
LookAndFeel.installColorsAndFont(slider, "Slider.background",
|
|
"Slider.foreground", "Slider.font");
|
|
highlightColor = UIManager.getColor("Slider.highlight");
|
|
|
|
shadowColor = UIManager.getColor("Slider.shadow");
|
|
focusColor = UIManager.getColor("Slider.focus");
|
|
|
|
focusInsets = (Insets)UIManager.get( "Slider.focusInsets" );
|
|
// use default if missing so that BasicSliderUI can be used in other
|
|
// LAFs like Nimbus
|
|
if (focusInsets == null) focusInsets = new InsetsUIResource(2,2,2,2);
|
|
}
|
|
|
|
protected void uninstallDefaults(JSlider slider) {
|
|
LookAndFeel.uninstallBorder(slider);
|
|
|
|
focusInsets = null;
|
|
}
|
|
|
|
protected TrackListener createTrackListener(JSlider slider) {
|
|
return new TrackListener();
|
|
}
|
|
|
|
protected ChangeListener createChangeListener(JSlider slider) {
|
|
return getHandler();
|
|
}
|
|
|
|
protected ComponentListener createComponentListener(JSlider slider) {
|
|
return getHandler();
|
|
}
|
|
|
|
protected FocusListener createFocusListener(JSlider slider) {
|
|
return getHandler();
|
|
}
|
|
|
|
protected ScrollListener createScrollListener( JSlider slider ) {
|
|
return new ScrollListener();
|
|
}
|
|
|
|
protected PropertyChangeListener createPropertyChangeListener(
|
|
JSlider slider) {
|
|
return getHandler();
|
|
}
|
|
|
|
private Handler getHandler() {
|
|
if (handler == null) {
|
|
handler = new Handler();
|
|
}
|
|
return handler;
|
|
}
|
|
|
|
protected void installListeners( JSlider slider ) {
|
|
slider.addMouseListener(trackListener);
|
|
slider.addMouseMotionListener(trackListener);
|
|
slider.addFocusListener(focusListener);
|
|
slider.addComponentListener(componentListener);
|
|
slider.addPropertyChangeListener( propertyChangeListener );
|
|
slider.getModel().addChangeListener(changeListener);
|
|
}
|
|
|
|
protected void uninstallListeners( JSlider slider ) {
|
|
slider.removeMouseListener(trackListener);
|
|
slider.removeMouseMotionListener(trackListener);
|
|
slider.removeFocusListener(focusListener);
|
|
slider.removeComponentListener(componentListener);
|
|
slider.removePropertyChangeListener( propertyChangeListener );
|
|
slider.getModel().removeChangeListener(changeListener);
|
|
handler = null;
|
|
}
|
|
|
|
protected void installKeyboardActions( JSlider slider ) {
|
|
InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
|
|
SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km);
|
|
LazyActionMap.installLazyActionMap(slider, BasicSliderUI.class,
|
|
"Slider.actionMap");
|
|
}
|
|
|
|
InputMap getInputMap(int condition, JSlider slider) {
|
|
if (condition == JComponent.WHEN_FOCUSED) {
|
|
InputMap keyMap = (InputMap)DefaultLookup.get(slider, this,
|
|
"Slider.focusInputMap");
|
|
InputMap rtlKeyMap;
|
|
|
|
if (slider.getComponentOrientation().isLeftToRight() ||
|
|
((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this,
|
|
"Slider.focusInputMap.RightToLeft")) == null)) {
|
|
return keyMap;
|
|
} else {
|
|
rtlKeyMap.setParent(keyMap);
|
|
return rtlKeyMap;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Populates ComboBox's actions.
|
|
*/
|
|
static void loadActionMap(LazyActionMap map) {
|
|
map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
|
|
map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
|
|
map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
|
|
map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
|
|
map.put(new Actions(Actions.MIN_SCROLL_INCREMENT));
|
|
map.put(new Actions(Actions.MAX_SCROLL_INCREMENT));
|
|
}
|
|
|
|
protected void uninstallKeyboardActions( JSlider slider ) {
|
|
SwingUtilities.replaceUIActionMap(slider, null);
|
|
SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED,
|
|
null);
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the baseline.
|
|
*
|
|
* @throws NullPointerException {@inheritDoc}
|
|
* @throws IllegalArgumentException {@inheritDoc}
|
|
* @see javax.swing.JComponent#getBaseline(int, int)
|
|
* @since 1.6
|
|
*/
|
|
public int getBaseline(JComponent c, int width, int height) {
|
|
super.getBaseline(c, width, height);
|
|
if (slider.getPaintLabels() && labelsHaveSameBaselines()) {
|
|
FontMetrics metrics = slider.getFontMetrics(slider.getFont());
|
|
Insets insets = slider.getInsets();
|
|
Dimension thumbSize = getThumbSize();
|
|
if (slider.getOrientation() == JSlider.HORIZONTAL) {
|
|
int tickLength = getTickLength();
|
|
int contentHeight = height - insets.top - insets.bottom -
|
|
focusInsets.top - focusInsets.bottom;
|
|
int thumbHeight = thumbSize.height;
|
|
int centerSpacing = thumbHeight;
|
|
if (slider.getPaintTicks()) {
|
|
centerSpacing += tickLength;
|
|
}
|
|
// Assume uniform labels.
|
|
centerSpacing += getHeightOfTallestLabel();
|
|
int trackY = insets.top + focusInsets.top +
|
|
(contentHeight - centerSpacing - 1) / 2;
|
|
int trackHeight = thumbHeight;
|
|
int tickY = trackY + trackHeight;
|
|
int tickHeight = tickLength;
|
|
if (!slider.getPaintTicks()) {
|
|
tickHeight = 0;
|
|
}
|
|
int labelY = tickY + tickHeight;
|
|
return labelY + metrics.getAscent();
|
|
}
|
|
else { // vertical
|
|
boolean inverted = slider.getInverted();
|
|
Integer value = inverted ? getLowestValue() :
|
|
getHighestValue();
|
|
if (value != null) {
|
|
int thumbHeight = thumbSize.height;
|
|
int trackBuffer = Math.max(metrics.getHeight() / 2,
|
|
thumbHeight / 2);
|
|
int contentY = focusInsets.top + insets.top;
|
|
int trackY = contentY + trackBuffer;
|
|
int trackHeight = height - focusInsets.top -
|
|
focusInsets.bottom - insets.top - insets.bottom -
|
|
trackBuffer - trackBuffer;
|
|
int yPosition = yPositionForValue(value, trackY,
|
|
trackHeight);
|
|
return yPosition - metrics.getHeight() / 2 +
|
|
metrics.getAscent();
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns an enum indicating how the baseline of the component
|
|
* changes as the size changes.
|
|
*
|
|
* @throws NullPointerException {@inheritDoc}
|
|
* @see javax.swing.JComponent#getBaseline(int, int)
|
|
* @since 1.6
|
|
*/
|
|
public Component.BaselineResizeBehavior getBaselineResizeBehavior(
|
|
JComponent c) {
|
|
super.getBaselineResizeBehavior(c);
|
|
// NOTE: BasicSpinner really provides for CENTER_OFFSET, but
|
|
// the default min/pref size is smaller than it should be
|
|
// so that getBaseline() doesn't implement the contract
|
|
// for CENTER_OFFSET as defined in Component.
|
|
return Component.BaselineResizeBehavior.OTHER;
|
|
}
|
|
|
|
/**
|
|
* Returns true if all the labels from the label table have the same
|
|
* baseline.
|
|
*
|
|
* @return true if all the labels from the label table have the
|
|
* same baseline
|
|
* @since 1.6
|
|
*/
|
|
protected boolean labelsHaveSameBaselines() {
|
|
if (!checkedLabelBaselines) {
|
|
checkedLabelBaselines = true;
|
|
Dictionary dictionary = slider.getLabelTable();
|
|
if (dictionary != null) {
|
|
sameLabelBaselines = true;
|
|
Enumeration elements = dictionary.elements();
|
|
int baseline = -1;
|
|
while (elements.hasMoreElements()) {
|
|
JComponent label = (JComponent) elements.nextElement();
|
|
Dimension pref = label.getPreferredSize();
|
|
int labelBaseline = label.getBaseline(pref.width,
|
|
pref.height);
|
|
if (labelBaseline >= 0) {
|
|
if (baseline == -1) {
|
|
baseline = labelBaseline;
|
|
}
|
|
else if (baseline != labelBaseline) {
|
|
sameLabelBaselines = false;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
sameLabelBaselines = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
sameLabelBaselines = false;
|
|
}
|
|
}
|
|
return sameLabelBaselines;
|
|
}
|
|
|
|
public Dimension getPreferredHorizontalSize() {
|
|
Dimension horizDim = (Dimension)DefaultLookup.get(slider,
|
|
this, "Slider.horizontalSize");
|
|
if (horizDim == null) {
|
|
horizDim = new Dimension(200, 21);
|
|
}
|
|
return horizDim;
|
|
}
|
|
|
|
public Dimension getPreferredVerticalSize() {
|
|
Dimension vertDim = (Dimension)DefaultLookup.get(slider,
|
|
this, "Slider.verticalSize");
|
|
if (vertDim == null) {
|
|
vertDim = new Dimension(21, 200);
|
|
}
|
|
return vertDim;
|
|
}
|
|
|
|
public Dimension getMinimumHorizontalSize() {
|
|
Dimension minHorizDim = (Dimension)DefaultLookup.get(slider,
|
|
this, "Slider.minimumHorizontalSize");
|
|
if (minHorizDim == null) {
|
|
minHorizDim = new Dimension(36, 21);
|
|
}
|
|
return minHorizDim;
|
|
}
|
|
|
|
public Dimension getMinimumVerticalSize() {
|
|
Dimension minVertDim = (Dimension)DefaultLookup.get(slider,
|
|
this, "Slider.minimumVerticalSize");
|
|
if (minVertDim == null) {
|
|
minVertDim = new Dimension(21, 36);
|
|
}
|
|
return minVertDim;
|
|
}
|
|
|
|
public Dimension getPreferredSize(JComponent c) {
|
|
recalculateIfInsetsChanged();
|
|
Dimension d;
|
|
if ( slider.getOrientation() == JSlider.VERTICAL ) {
|
|
d = new Dimension(getPreferredVerticalSize());
|
|
d.width = insetCache.left + insetCache.right;
|
|
d.width += focusInsets.left + focusInsets.right;
|
|
d.width += trackRect.width + tickRect.width + labelRect.width;
|
|
}
|
|
else {
|
|
d = new Dimension(getPreferredHorizontalSize());
|
|
d.height = insetCache.top + insetCache.bottom;
|
|
d.height += focusInsets.top + focusInsets.bottom;
|
|
d.height += trackRect.height + tickRect.height + labelRect.height;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
public Dimension getMinimumSize(JComponent c) {
|
|
recalculateIfInsetsChanged();
|
|
Dimension d;
|
|
|
|
if ( slider.getOrientation() == JSlider.VERTICAL ) {
|
|
d = new Dimension(getMinimumVerticalSize());
|
|
d.width = insetCache.left + insetCache.right;
|
|
d.width += focusInsets.left + focusInsets.right;
|
|
d.width += trackRect.width + tickRect.width + labelRect.width;
|
|
}
|
|
else {
|
|
d = new Dimension(getMinimumHorizontalSize());
|
|
d.height = insetCache.top + insetCache.bottom;
|
|
d.height += focusInsets.top + focusInsets.bottom;
|
|
d.height += trackRect.height + tickRect.height + labelRect.height;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
public Dimension getMaximumSize(JComponent c) {
|
|
Dimension d = getPreferredSize(c);
|
|
if ( slider.getOrientation() == JSlider.VERTICAL ) {
|
|
d.height = Short.MAX_VALUE;
|
|
}
|
|
else {
|
|
d.width = Short.MAX_VALUE;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
protected void calculateGeometry() {
|
|
calculateFocusRect();
|
|
calculateContentRect();
|
|
calculateThumbSize();
|
|
calculateTrackBuffer();
|
|
calculateTrackRect();
|
|
calculateTickRect();
|
|
calculateLabelRect();
|
|
calculateThumbLocation();
|
|
}
|
|
|
|
protected void calculateFocusRect() {
|
|
focusRect.x = insetCache.left;
|
|
focusRect.y = insetCache.top;
|
|
focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right);
|
|
focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom);
|
|
}
|
|
|
|
protected void calculateThumbSize() {
|
|
Dimension size = getThumbSize();
|
|
thumbRect.setSize( size.width, size.height );
|
|
}
|
|
|
|
protected void calculateContentRect() {
|
|
contentRect.x = focusRect.x + focusInsets.left;
|
|
contentRect.y = focusRect.y + focusInsets.top;
|
|
contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right);
|
|
contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom);
|
|
}
|
|
|
|
private int getTickSpacing() {
|
|
int majorTickSpacing = slider.getMajorTickSpacing();
|
|
int minorTickSpacing = slider.getMinorTickSpacing();
|
|
|
|
int result;
|
|
|
|
if (minorTickSpacing > 0) {
|
|
result = minorTickSpacing;
|
|
} else if (majorTickSpacing > 0) {
|
|
result = majorTickSpacing;
|
|
} else {
|
|
result = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
protected void calculateThumbLocation() {
|
|
if ( slider.getSnapToTicks() ) {
|
|
int sliderValue = slider.getValue();
|
|
int snappedValue = sliderValue;
|
|
int tickSpacing = getTickSpacing();
|
|
|
|
if ( tickSpacing != 0 ) {
|
|
// If it's not on a tick, change the value
|
|
if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) {
|
|
float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing;
|
|
int whichTick = Math.round( temp );
|
|
|
|
// This is the fix for the bug #6401380
|
|
if (temp - (int)temp == .5 && sliderValue < lastValue) {
|
|
whichTick --;
|
|
}
|
|
snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
|
|
}
|
|
|
|
if( snappedValue != sliderValue ) {
|
|
slider.setValue( snappedValue );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
int valuePosition = xPositionForValue(slider.getValue());
|
|
|
|
thumbRect.x = valuePosition - (thumbRect.width / 2);
|
|
thumbRect.y = trackRect.y;
|
|
}
|
|
else {
|
|
int valuePosition = yPositionForValue(slider.getValue());
|
|
|
|
thumbRect.x = trackRect.x;
|
|
thumbRect.y = valuePosition - (thumbRect.height / 2);
|
|
}
|
|
}
|
|
|
|
protected void calculateTrackBuffer() {
|
|
if ( slider.getPaintLabels() && slider.getLabelTable() != null ) {
|
|
Component highLabel = getHighestValueLabel();
|
|
Component lowLabel = getLowestValueLabel();
|
|
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2;
|
|
trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 );
|
|
}
|
|
else {
|
|
trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2;
|
|
trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 );
|
|
}
|
|
}
|
|
else {
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
trackBuffer = thumbRect.width / 2;
|
|
}
|
|
else {
|
|
trackBuffer = thumbRect.height / 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
protected void calculateTrackRect() {
|
|
int centerSpacing; // used to center sliders added using BorderLayout.CENTER (bug 4275631)
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
centerSpacing = thumbRect.height;
|
|
if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
|
|
if ( slider.getPaintLabels() ) centerSpacing += getHeightOfTallestLabel();
|
|
trackRect.x = contentRect.x + trackBuffer;
|
|
trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1)/2;
|
|
trackRect.width = contentRect.width - (trackBuffer * 2);
|
|
trackRect.height = thumbRect.height;
|
|
}
|
|
else {
|
|
centerSpacing = thumbRect.width;
|
|
if (BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
|
|
if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel();
|
|
} else {
|
|
if ( slider.getPaintTicks() ) centerSpacing -= getTickLength();
|
|
if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel();
|
|
}
|
|
trackRect.x = contentRect.x + (contentRect.width - centerSpacing - 1)/2;
|
|
trackRect.y = contentRect.y + trackBuffer;
|
|
trackRect.width = thumbRect.width;
|
|
trackRect.height = contentRect.height - (trackBuffer * 2);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Gets the height of the tick area for horizontal sliders and the width of the
|
|
* tick area for vertical sliders. BasicSliderUI uses the returned value to
|
|
* determine the tick area rectangle. If you want to give your ticks some room,
|
|
* make this larger than you need and paint your ticks away from the sides in paintTicks().
|
|
*/
|
|
protected int getTickLength() {
|
|
return 8;
|
|
}
|
|
|
|
protected void calculateTickRect() {
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
tickRect.x = trackRect.x;
|
|
tickRect.y = trackRect.y + trackRect.height;
|
|
tickRect.width = trackRect.width;
|
|
tickRect.height = (slider.getPaintTicks()) ? getTickLength() : 0;
|
|
}
|
|
else {
|
|
tickRect.width = (slider.getPaintTicks()) ? getTickLength() : 0;
|
|
if(BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
tickRect.x = trackRect.x + trackRect.width;
|
|
}
|
|
else {
|
|
tickRect.x = trackRect.x - tickRect.width;
|
|
}
|
|
tickRect.y = trackRect.y;
|
|
tickRect.height = trackRect.height;
|
|
}
|
|
}
|
|
|
|
protected void calculateLabelRect() {
|
|
if ( slider.getPaintLabels() ) {
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
labelRect.x = tickRect.x - trackBuffer;
|
|
labelRect.y = tickRect.y + tickRect.height;
|
|
labelRect.width = tickRect.width + (trackBuffer * 2);
|
|
labelRect.height = getHeightOfTallestLabel();
|
|
}
|
|
else {
|
|
if(BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
labelRect.x = tickRect.x + tickRect.width;
|
|
labelRect.width = getWidthOfWidestLabel();
|
|
}
|
|
else {
|
|
labelRect.width = getWidthOfWidestLabel();
|
|
labelRect.x = tickRect.x - labelRect.width;
|
|
}
|
|
labelRect.y = tickRect.y - trackBuffer;
|
|
labelRect.height = tickRect.height + (trackBuffer * 2);
|
|
}
|
|
}
|
|
else {
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
labelRect.x = tickRect.x;
|
|
labelRect.y = tickRect.y + tickRect.height;
|
|
labelRect.width = tickRect.width;
|
|
labelRect.height = 0;
|
|
}
|
|
else {
|
|
if(BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
labelRect.x = tickRect.x + tickRect.width;
|
|
}
|
|
else {
|
|
labelRect.x = tickRect.x;
|
|
}
|
|
labelRect.y = tickRect.y;
|
|
labelRect.width = 0;
|
|
labelRect.height = tickRect.height;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected Dimension getThumbSize() {
|
|
Dimension size = new Dimension();
|
|
|
|
if ( slider.getOrientation() == JSlider.VERTICAL ) {
|
|
size.width = 20;
|
|
size.height = 11;
|
|
}
|
|
else {
|
|
size.width = 11;
|
|
size.height = 20;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
public class PropertyChangeHandler implements PropertyChangeListener {
|
|
// NOTE: This class exists only for backward compatibility. All
|
|
// its functionality has been moved into Handler. If you need to add
|
|
// new functionality add it to the Handler, but make sure this
|
|
// class calls into the Handler.
|
|
public void propertyChange( PropertyChangeEvent e ) {
|
|
getHandler().propertyChange(e);
|
|
}
|
|
}
|
|
|
|
protected int getWidthOfWidestLabel() {
|
|
Dictionary dictionary = slider.getLabelTable();
|
|
int widest = 0;
|
|
if ( dictionary != null ) {
|
|
Enumeration keys = dictionary.keys();
|
|
while ( keys.hasMoreElements() ) {
|
|
JComponent label = (JComponent) dictionary.get(keys.nextElement());
|
|
widest = Math.max( label.getPreferredSize().width, widest );
|
|
}
|
|
}
|
|
return widest;
|
|
}
|
|
|
|
protected int getHeightOfTallestLabel() {
|
|
Dictionary dictionary = slider.getLabelTable();
|
|
int tallest = 0;
|
|
if ( dictionary != null ) {
|
|
Enumeration keys = dictionary.keys();
|
|
while ( keys.hasMoreElements() ) {
|
|
JComponent label = (JComponent) dictionary.get(keys.nextElement());
|
|
tallest = Math.max( label.getPreferredSize().height, tallest );
|
|
}
|
|
}
|
|
return tallest;
|
|
}
|
|
|
|
protected int getWidthOfHighValueLabel() {
|
|
Component label = getHighestValueLabel();
|
|
int width = 0;
|
|
|
|
if ( label != null ) {
|
|
width = label.getPreferredSize().width;
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
protected int getWidthOfLowValueLabel() {
|
|
Component label = getLowestValueLabel();
|
|
int width = 0;
|
|
|
|
if ( label != null ) {
|
|
width = label.getPreferredSize().width;
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
protected int getHeightOfHighValueLabel() {
|
|
Component label = getHighestValueLabel();
|
|
int height = 0;
|
|
|
|
if ( label != null ) {
|
|
height = label.getPreferredSize().height;
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
protected int getHeightOfLowValueLabel() {
|
|
Component label = getLowestValueLabel();
|
|
int height = 0;
|
|
|
|
if ( label != null ) {
|
|
height = label.getPreferredSize().height;
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
protected boolean drawInverted() {
|
|
if (slider.getOrientation()==JSlider.HORIZONTAL) {
|
|
if(BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
return slider.getInverted();
|
|
} else {
|
|
return !slider.getInverted();
|
|
}
|
|
} else {
|
|
return slider.getInverted();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the biggest value that has an entry in the label table.
|
|
*
|
|
* @return biggest value that has an entry in the label table, or
|
|
* null.
|
|
* @since 1.6
|
|
*/
|
|
protected Integer getHighestValue() {
|
|
Dictionary dictionary = slider.getLabelTable();
|
|
|
|
if (dictionary == null) {
|
|
return null;
|
|
}
|
|
|
|
Enumeration keys = dictionary.keys();
|
|
|
|
Integer max = null;
|
|
|
|
while (keys.hasMoreElements()) {
|
|
Integer i = (Integer) keys.nextElement();
|
|
|
|
if (max == null || i > max) {
|
|
max = i;
|
|
}
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
/**
|
|
* Returns the smallest value that has an entry in the label table.
|
|
*
|
|
* @return smallest value that has an entry in the label table, or
|
|
* null.
|
|
* @since 1.6
|
|
*/
|
|
protected Integer getLowestValue() {
|
|
Dictionary dictionary = slider.getLabelTable();
|
|
|
|
if (dictionary == null) {
|
|
return null;
|
|
}
|
|
|
|
Enumeration keys = dictionary.keys();
|
|
|
|
Integer min = null;
|
|
|
|
while (keys.hasMoreElements()) {
|
|
Integer i = (Integer) keys.nextElement();
|
|
|
|
if (min == null || i < min) {
|
|
min = i;
|
|
}
|
|
}
|
|
|
|
return min;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the label that corresponds to the highest slider value in the label table.
|
|
* @see JSlider#setLabelTable
|
|
*/
|
|
protected Component getLowestValueLabel() {
|
|
Integer min = getLowestValue();
|
|
if (min != null) {
|
|
return (Component)slider.getLabelTable().get(min);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Returns the label that corresponds to the lowest slider value in the label table.
|
|
* @see JSlider#setLabelTable
|
|
*/
|
|
protected Component getHighestValueLabel() {
|
|
Integer max = getHighestValue();
|
|
if (max != null) {
|
|
return (Component)slider.getLabelTable().get(max);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void paint( Graphics g, JComponent c ) {
|
|
recalculateIfInsetsChanged();
|
|
recalculateIfOrientationChanged();
|
|
Rectangle clip = g.getClipBounds();
|
|
|
|
if ( !clip.intersects(trackRect) && slider.getPaintTrack())
|
|
calculateGeometry();
|
|
|
|
if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) {
|
|
paintTrack( g );
|
|
}
|
|
if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) {
|
|
paintTicks( g );
|
|
}
|
|
if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) {
|
|
paintLabels( g );
|
|
}
|
|
if ( slider.hasFocus() && clip.intersects( focusRect ) ) {
|
|
paintFocus( g );
|
|
}
|
|
if ( clip.intersects( thumbRect ) ) {
|
|
paintThumb( g );
|
|
}
|
|
}
|
|
|
|
protected void recalculateIfInsetsChanged() {
|
|
Insets newInsets = slider.getInsets();
|
|
if ( !newInsets.equals( insetCache ) ) {
|
|
insetCache = newInsets;
|
|
calculateGeometry();
|
|
}
|
|
}
|
|
|
|
protected void recalculateIfOrientationChanged() {
|
|
boolean ltr = BasicGraphicsUtils.isLeftToRight(slider);
|
|
if ( ltr!=leftToRightCache ) {
|
|
leftToRightCache = ltr;
|
|
calculateGeometry();
|
|
}
|
|
}
|
|
|
|
public void paintFocus(Graphics g) {
|
|
g.setColor( getFocusColor() );
|
|
|
|
BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y,
|
|
focusRect.width, focusRect.height );
|
|
}
|
|
|
|
public void paintTrack(Graphics g) {
|
|
|
|
Rectangle trackBounds = trackRect;
|
|
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
int cy = (trackBounds.height / 2) - 2;
|
|
int cw = trackBounds.width;
|
|
|
|
g.translate(trackBounds.x, trackBounds.y + cy);
|
|
|
|
g.setColor(getShadowColor());
|
|
g.drawLine(0, 0, cw - 1, 0);
|
|
g.drawLine(0, 1, 0, 2);
|
|
g.setColor(getHighlightColor());
|
|
g.drawLine(0, 3, cw, 3);
|
|
g.drawLine(cw, 0, cw, 3);
|
|
g.setColor(Color.black);
|
|
g.drawLine(1, 1, cw-2, 1);
|
|
|
|
g.translate(-trackBounds.x, -(trackBounds.y + cy));
|
|
}
|
|
else {
|
|
int cx = (trackBounds.width / 2) - 2;
|
|
int ch = trackBounds.height;
|
|
|
|
g.translate(trackBounds.x + cx, trackBounds.y);
|
|
|
|
g.setColor(getShadowColor());
|
|
g.drawLine(0, 0, 0, ch - 1);
|
|
g.drawLine(1, 0, 2, 0);
|
|
g.setColor(getHighlightColor());
|
|
g.drawLine(3, 0, 3, ch);
|
|
g.drawLine(0, ch, 3, ch);
|
|
g.setColor(Color.black);
|
|
g.drawLine(1, 1, 1, ch-2);
|
|
|
|
g.translate(-(trackBounds.x + cx), -trackBounds.y);
|
|
}
|
|
}
|
|
|
|
public void paintTicks(Graphics g) {
|
|
Rectangle tickBounds = tickRect;
|
|
|
|
g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black));
|
|
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
g.translate(0, tickBounds.y);
|
|
|
|
if (slider.getMinorTickSpacing() > 0) {
|
|
int value = slider.getMinimum();
|
|
|
|
while ( value <= slider.getMaximum() ) {
|
|
int xPos = xPositionForValue(value);
|
|
paintMinorTickForHorizSlider( g, tickBounds, xPos );
|
|
|
|
// Overflow checking
|
|
if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) {
|
|
break;
|
|
}
|
|
|
|
value += slider.getMinorTickSpacing();
|
|
}
|
|
}
|
|
|
|
if (slider.getMajorTickSpacing() > 0) {
|
|
int value = slider.getMinimum();
|
|
|
|
while ( value <= slider.getMaximum() ) {
|
|
int xPos = xPositionForValue(value);
|
|
paintMajorTickForHorizSlider( g, tickBounds, xPos );
|
|
|
|
// Overflow checking
|
|
if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) {
|
|
break;
|
|
}
|
|
|
|
value += slider.getMajorTickSpacing();
|
|
}
|
|
}
|
|
|
|
g.translate( 0, -tickBounds.y);
|
|
} else {
|
|
g.translate(tickBounds.x, 0);
|
|
|
|
if (slider.getMinorTickSpacing() > 0) {
|
|
int offset = 0;
|
|
if(!BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
offset = tickBounds.width - tickBounds.width / 2;
|
|
g.translate(offset, 0);
|
|
}
|
|
|
|
int value = slider.getMinimum();
|
|
|
|
while (value <= slider.getMaximum()) {
|
|
int yPos = yPositionForValue(value);
|
|
paintMinorTickForVertSlider( g, tickBounds, yPos );
|
|
|
|
// Overflow checking
|
|
if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) {
|
|
break;
|
|
}
|
|
|
|
value += slider.getMinorTickSpacing();
|
|
}
|
|
|
|
if(!BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
g.translate(-offset, 0);
|
|
}
|
|
}
|
|
|
|
if (slider.getMajorTickSpacing() > 0) {
|
|
if(!BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
g.translate(2, 0);
|
|
}
|
|
|
|
int value = slider.getMinimum();
|
|
|
|
while (value <= slider.getMaximum()) {
|
|
int yPos = yPositionForValue(value);
|
|
paintMajorTickForVertSlider( g, tickBounds, yPos );
|
|
|
|
// Overflow checking
|
|
if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) {
|
|
break;
|
|
}
|
|
|
|
value += slider.getMajorTickSpacing();
|
|
}
|
|
|
|
if(!BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
g.translate(-2, 0);
|
|
}
|
|
}
|
|
g.translate(-tickBounds.x, 0);
|
|
}
|
|
}
|
|
|
|
protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
|
|
g.drawLine( x, 0, x, tickBounds.height / 2 - 1 );
|
|
}
|
|
|
|
protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
|
|
g.drawLine( x, 0, x, tickBounds.height - 2 );
|
|
}
|
|
|
|
protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
|
|
g.drawLine( 0, y, tickBounds.width / 2 - 1, y );
|
|
}
|
|
|
|
protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
|
|
g.drawLine( 0, y, tickBounds.width - 2, y );
|
|
}
|
|
|
|
public void paintLabels( Graphics g ) {
|
|
Rectangle labelBounds = labelRect;
|
|
|
|
Dictionary dictionary = slider.getLabelTable();
|
|
if ( dictionary != null ) {
|
|
Enumeration keys = dictionary.keys();
|
|
int minValue = slider.getMinimum();
|
|
int maxValue = slider.getMaximum();
|
|
boolean enabled = slider.isEnabled();
|
|
while ( keys.hasMoreElements() ) {
|
|
Integer key = (Integer)keys.nextElement();
|
|
int value = key.intValue();
|
|
if (value >= minValue && value <= maxValue) {
|
|
JComponent label = (JComponent) dictionary.get(key);
|
|
label.setEnabled(enabled);
|
|
|
|
if (label instanceof JLabel) {
|
|
Icon icon = label.isEnabled() ? ((JLabel) label).getIcon() : ((JLabel) label).getDisabledIcon();
|
|
|
|
if (icon instanceof ImageIcon) {
|
|
// Register Slider as an image observer. It allows to catch notifications about
|
|
// image changes (e.g. gif animation)
|
|
Toolkit.getDefaultToolkit().checkImage(((ImageIcon) icon).getImage(), -1, -1, slider);
|
|
}
|
|
}
|
|
|
|
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
g.translate( 0, labelBounds.y );
|
|
paintHorizontalLabel( g, value, label );
|
|
g.translate( 0, -labelBounds.y );
|
|
}
|
|
else {
|
|
int offset = 0;
|
|
if (!BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
offset = labelBounds.width -
|
|
label.getPreferredSize().width;
|
|
}
|
|
g.translate( labelBounds.x + offset, 0 );
|
|
paintVerticalLabel( g, value, label );
|
|
g.translate( -labelBounds.x - offset, 0 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Called for every label in the label table. Used to draw the labels for horizontal sliders.
|
|
* The graphics have been translated to labelRect.y already.
|
|
* @see JSlider#setLabelTable
|
|
*/
|
|
protected void paintHorizontalLabel( Graphics g, int value, Component label ) {
|
|
int labelCenter = xPositionForValue( value );
|
|
int labelLeft = labelCenter - (label.getPreferredSize().width / 2);
|
|
g.translate( labelLeft, 0 );
|
|
label.paint( g );
|
|
g.translate( -labelLeft, 0 );
|
|
}
|
|
|
|
/**
|
|
* Called for every label in the label table. Used to draw the labels for vertical sliders.
|
|
* The graphics have been translated to labelRect.x already.
|
|
* @see JSlider#setLabelTable
|
|
*/
|
|
protected void paintVerticalLabel( Graphics g, int value, Component label ) {
|
|
int labelCenter = yPositionForValue( value );
|
|
int labelTop = labelCenter - (label.getPreferredSize().height / 2);
|
|
g.translate( 0, labelTop );
|
|
label.paint( g );
|
|
g.translate( 0, -labelTop );
|
|
}
|
|
|
|
public void paintThumb(Graphics g) {
|
|
Rectangle knobBounds = thumbRect;
|
|
int w = knobBounds.width;
|
|
int h = knobBounds.height;
|
|
|
|
g.translate(knobBounds.x, knobBounds.y);
|
|
|
|
if ( slider.isEnabled() ) {
|
|
g.setColor(slider.getBackground());
|
|
}
|
|
else {
|
|
g.setColor(slider.getBackground().darker());
|
|
}
|
|
|
|
Boolean paintThumbArrowShape =
|
|
(Boolean)slider.getClientProperty("Slider.paintThumbArrowShape");
|
|
|
|
if ((!slider.getPaintTicks() && paintThumbArrowShape == null) ||
|
|
paintThumbArrowShape == Boolean.FALSE) {
|
|
|
|
// "plain" version
|
|
g.fillRect(0, 0, w, h);
|
|
|
|
g.setColor(Color.black);
|
|
g.drawLine(0, h-1, w-1, h-1);
|
|
g.drawLine(w-1, 0, w-1, h-1);
|
|
|
|
g.setColor(highlightColor);
|
|
g.drawLine(0, 0, 0, h-2);
|
|
g.drawLine(1, 0, w-2, 0);
|
|
|
|
g.setColor(shadowColor);
|
|
g.drawLine(1, h-2, w-2, h-2);
|
|
g.drawLine(w-2, 1, w-2, h-3);
|
|
}
|
|
else if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
|
|
int cw = w / 2;
|
|
g.fillRect(1, 1, w-3, h-1-cw);
|
|
Polygon p = new Polygon();
|
|
p.addPoint(1, h-cw);
|
|
p.addPoint(cw-1, h-1);
|
|
p.addPoint(w-2, h-1-cw);
|
|
g.fillPolygon(p);
|
|
|
|
g.setColor(highlightColor);
|
|
g.drawLine(0, 0, w-2, 0);
|
|
g.drawLine(0, 1, 0, h-1-cw);
|
|
g.drawLine(0, h-cw, cw-1, h-1);
|
|
|
|
g.setColor(Color.black);
|
|
g.drawLine(w-1, 0, w-1, h-2-cw);
|
|
g.drawLine(w-1, h-1-cw, w-1-cw, h-1);
|
|
|
|
g.setColor(shadowColor);
|
|
g.drawLine(w-2, 1, w-2, h-2-cw);
|
|
g.drawLine(w-2, h-1-cw, w-1-cw, h-2);
|
|
}
|
|
else { // vertical
|
|
int cw = h / 2;
|
|
if(BasicGraphicsUtils.isLeftToRight(slider)) {
|
|
g.fillRect(1, 1, w-1-cw, h-3);
|
|
Polygon p = new Polygon();
|
|
p.addPoint(w-cw-1, 0);
|
|
p.addPoint(w-1, cw);
|
|
p.addPoint(w-1-cw, h-2);
|
|
g.fillPolygon(p);
|
|
|
|
g.setColor(highlightColor);
|
|
g.drawLine(0, 0, 0, h - 2); // left
|
|
g.drawLine(1, 0, w-1-cw, 0); // top
|
|
g.drawLine(w-cw-1, 0, w-1, cw); // top slant
|
|
|
|
g.setColor(Color.black);
|
|
g.drawLine(0, h-1, w-2-cw, h-1); // bottom
|
|
g.drawLine(w-1-cw, h-1, w-1, h-1-cw); // bottom slant
|
|
|
|
g.setColor(shadowColor);
|
|
g.drawLine(1, h-2, w-2-cw, h-2 ); // bottom
|
|
g.drawLine(w-1-cw, h-2, w-2, h-cw-1 ); // bottom slant
|
|
}
|
|
else {
|
|
g.fillRect(5, 1, w-1-cw, h-3);
|
|
Polygon p = new Polygon();
|
|
p.addPoint(cw, 0);
|
|
p.addPoint(0, cw);
|
|
p.addPoint(cw, h-2);
|
|
g.fillPolygon(p);
|
|
|
|
g.setColor(highlightColor);
|
|
g.drawLine(cw-1, 0, w-2, 0); // top
|
|
g.drawLine(0, cw, cw, 0); // top slant
|
|
|
|
g.setColor(Color.black);
|
|
g.drawLine(0, h-1-cw, cw, h-1 ); // bottom slant
|
|
g.drawLine(cw, h-1, w-1, h-1); // bottom
|
|
|
|
g.setColor(shadowColor);
|
|
g.drawLine(cw, h-2, w-2, h-2 ); // bottom
|
|
g.drawLine(w-1, 1, w-1, h-2 ); // right
|
|
}
|
|
}
|
|
|
|
g.translate(-knobBounds.x, -knobBounds.y);
|
|
}
|
|
|
|
// Used exclusively by setThumbLocation()
|
|
private static Rectangle unionRect = new Rectangle();
|
|
|
|
public void setThumbLocation(int x, int y) {
|
|
unionRect.setBounds( thumbRect );
|
|
|
|
thumbRect.setLocation( x, y );
|
|
|
|
SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect );
|
|
slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height );
|
|
}
|
|
|
|
public void scrollByBlock(int direction) {
|
|
synchronized(slider) {
|
|
int blockIncrement =
|
|
(slider.getMaximum() - slider.getMinimum()) / 10;
|
|
if (blockIncrement == 0) {
|
|
blockIncrement = 1;
|
|
}
|
|
|
|
if (slider.getSnapToTicks()) {
|
|
int tickSpacing = getTickSpacing();
|
|
|
|
if (blockIncrement < tickSpacing) {
|
|
blockIncrement = tickSpacing;
|
|
}
|
|
}
|
|
|
|
int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
|
|
slider.setValue(slider.getValue() + delta);
|
|
}
|
|
}
|
|
|
|
public void scrollByUnit(int direction) {
|
|
synchronized(slider) {
|
|
int delta = ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
|
|
|
|
if (slider.getSnapToTicks()) {
|
|
delta *= getTickSpacing();
|
|
}
|
|
|
|
slider.setValue(slider.getValue() + delta);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function is called when a mousePressed was detected in the track, not
|
|
* in the thumb. The default behavior is to scroll by block. You can
|
|
* override this method to stop it from scrolling or to add additional behavior.
|
|
*/
|
|
protected void scrollDueToClickInTrack( int dir ) {
|
|
scrollByBlock( dir );
|
|
}
|
|
|
|
protected int xPositionForValue( int value ) {
|
|
int min = slider.getMinimum();
|
|
int max = slider.getMaximum();
|
|
int trackLength = trackRect.width;
|
|
double valueRange = (double)max - (double)min;
|
|
double pixelsPerValue = (double)trackLength / valueRange;
|
|
int trackLeft = trackRect.x;
|
|
int trackRight = trackRect.x + (trackRect.width - 1);
|
|
int xPosition;
|
|
|
|
if ( !drawInverted() ) {
|
|
xPosition = trackLeft;
|
|
xPosition += Math.round( pixelsPerValue * ((double)value - min) );
|
|
}
|
|
else {
|
|
xPosition = trackRight;
|
|
xPosition -= Math.round( pixelsPerValue * ((double)value - min) );
|
|
}
|
|
|
|
xPosition = Math.max( trackLeft, xPosition );
|
|
xPosition = Math.min( trackRight, xPosition );
|
|
|
|
return xPosition;
|
|
}
|
|
|
|
protected int yPositionForValue( int value ) {
|
|
return yPositionForValue(value, trackRect.y, trackRect.height);
|
|
}
|
|
|
|
/**
|
|
* Returns the y location for the specified value. No checking is
|
|
* done on the arguments. In particular if <code>trackHeight</code> is
|
|
* negative undefined results may occur.
|
|
*
|
|
* @param value the slider value to get the location for
|
|
* @param trackY y-origin of the track
|
|
* @param trackHeight the height of the track
|
|
* @since 1.6
|
|
*/
|
|
protected int yPositionForValue(int value, int trackY, int trackHeight) {
|
|
int min = slider.getMinimum();
|
|
int max = slider.getMaximum();
|
|
double valueRange = (double)max - (double)min;
|
|
double pixelsPerValue = (double)trackHeight / valueRange;
|
|
int trackBottom = trackY + (trackHeight - 1);
|
|
int yPosition;
|
|
|
|
if ( !drawInverted() ) {
|
|
yPosition = trackY;
|
|
yPosition += Math.round( pixelsPerValue * ((double)max - value ) );
|
|
}
|
|
else {
|
|
yPosition = trackY;
|
|
yPosition += Math.round( pixelsPerValue * ((double)value - min) );
|
|
}
|
|
|
|
yPosition = Math.max( trackY, yPosition );
|
|
yPosition = Math.min( trackBottom, yPosition );
|
|
|
|
return yPosition;
|
|
}
|
|
|
|
/**
|
|
* Returns the value at the y position. If {@code yPos} is beyond the
|
|
* track at the the bottom or the top, this method sets the value to either
|
|
* the minimum or maximum value of the slider, depending on if the slider
|
|
* is inverted or not.
|
|
*/
|
|
public int valueForYPosition( int yPos ) {
|
|
int value;
|
|
final int minValue = slider.getMinimum();
|
|
final int maxValue = slider.getMaximum();
|
|
final int trackLength = trackRect.height;
|
|
final int trackTop = trackRect.y;
|
|
final int trackBottom = trackRect.y + (trackRect.height - 1);
|
|
|
|
if ( yPos <= trackTop ) {
|
|
value = drawInverted() ? minValue : maxValue;
|
|
}
|
|
else if ( yPos >= trackBottom ) {
|
|
value = drawInverted() ? maxValue : minValue;
|
|
}
|
|
else {
|
|
int distanceFromTrackTop = yPos - trackTop;
|
|
double valueRange = (double)maxValue - (double)minValue;
|
|
double valuePerPixel = valueRange / (double)trackLength;
|
|
int valueFromTrackTop = (int)Math.round( distanceFromTrackTop * valuePerPixel );
|
|
|
|
value = drawInverted() ? minValue + valueFromTrackTop : maxValue - valueFromTrackTop;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Returns the value at the x position. If {@code xPos} is beyond the
|
|
* track at the left or the right, this method sets the value to either the
|
|
* minimum or maximum value of the slider, depending on if the slider is
|
|
* inverted or not.
|
|
*/
|
|
public int valueForXPosition( int xPos ) {
|
|
int value;
|
|
final int minValue = slider.getMinimum();
|
|
final int maxValue = slider.getMaximum();
|
|
final int trackLength = trackRect.width;
|
|
final int trackLeft = trackRect.x;
|
|
final int trackRight = trackRect.x + (trackRect.width - 1);
|
|
|
|
if ( xPos <= trackLeft ) {
|
|
value = drawInverted() ? maxValue : minValue;
|
|
}
|
|
else if ( xPos >= trackRight ) {
|
|
value = drawInverted() ? minValue : maxValue;
|
|
}
|
|
else {
|
|
int distanceFromTrackLeft = xPos - trackLeft;
|
|
double valueRange = (double)maxValue - (double)minValue;
|
|
double valuePerPixel = valueRange / (double)trackLength;
|
|
int valueFromTrackLeft = (int)Math.round( distanceFromTrackLeft * valuePerPixel );
|
|
|
|
value = drawInverted() ? maxValue - valueFromTrackLeft :
|
|
minValue + valueFromTrackLeft;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
private class Handler implements ChangeListener,
|
|
ComponentListener, FocusListener, PropertyChangeListener {
|
|
// Change Handler
|
|
public void stateChanged(ChangeEvent e) {
|
|
if (!isDragging) {
|
|
calculateThumbLocation();
|
|
slider.repaint();
|
|
}
|
|
lastValue = slider.getValue();
|
|
}
|
|
|
|
// Component Handler
|
|
public void componentHidden(ComponentEvent e) { }
|
|
public void componentMoved(ComponentEvent e) { }
|
|
public void componentResized(ComponentEvent e) {
|
|
calculateGeometry();
|
|
slider.repaint();
|
|
}
|
|
public void componentShown(ComponentEvent e) { }
|
|
|
|
// Focus Handler
|
|
public void focusGained(FocusEvent e) { slider.repaint(); }
|
|
public void focusLost(FocusEvent e) { slider.repaint(); }
|
|
|
|
// Property Change Handler
|
|
public void propertyChange(PropertyChangeEvent e) {
|
|
String propertyName = e.getPropertyName();
|
|
if (propertyName == "orientation" ||
|
|
propertyName == "inverted" ||
|
|
propertyName == "labelTable" ||
|
|
propertyName == "majorTickSpacing" ||
|
|
propertyName == "minorTickSpacing" ||
|
|
propertyName == "paintTicks" ||
|
|
propertyName == "paintTrack" ||
|
|
propertyName == "font" ||
|
|
propertyName == "paintLabels" ||
|
|
propertyName == "Slider.paintThumbArrowShape") {
|
|
checkedLabelBaselines = false;
|
|
calculateGeometry();
|
|
slider.repaint();
|
|
} else if (propertyName == "componentOrientation") {
|
|
calculateGeometry();
|
|
slider.repaint();
|
|
InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
|
|
SwingUtilities.replaceUIInputMap(slider,
|
|
JComponent.WHEN_FOCUSED, km);
|
|
} else if (propertyName == "model") {
|
|
((BoundedRangeModel)e.getOldValue()).removeChangeListener(
|
|
changeListener);
|
|
((BoundedRangeModel)e.getNewValue()).addChangeListener(
|
|
changeListener);
|
|
calculateThumbLocation();
|
|
slider.repaint();
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
/// Model Listener Class
|
|
/////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* Data model listener.
|
|
*
|
|
* This class should be treated as a "protected" inner class.
|
|
* Instantiate it only within subclasses of <code>Foo</code>.
|
|
*/
|
|
public class ChangeHandler implements ChangeListener {
|
|
// NOTE: This class exists only for backward compatibility. All
|
|
// its functionality has been moved into Handler. If you need to add
|
|
// new functionality add it to the Handler, but make sure this
|
|
// class calls into the Handler.
|
|
public void stateChanged(ChangeEvent e) {
|
|
getHandler().stateChanged(e);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
/// Track Listener Class
|
|
/////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* Track mouse movements.
|
|
*
|
|
* This class should be treated as a "protected" inner class.
|
|
* Instantiate it only within subclasses of <code>Foo</code>.
|
|
*/
|
|
public class TrackListener extends MouseInputAdapter {
|
|
protected transient int offset;
|
|
protected transient int currentMouseX, currentMouseY;
|
|
|
|
public void mouseReleased(MouseEvent e) {
|
|
if (!slider.isEnabled()) {
|
|
return;
|
|
}
|
|
|
|
offset = 0;
|
|
scrollTimer.stop();
|
|
|
|
isDragging = false;
|
|
slider.setValueIsAdjusting(false);
|
|
slider.repaint();
|
|
}
|
|
|
|
/**
|
|
* If the mouse is pressed above the "thumb" component
|
|
* then reduce the scrollbars value by one page ("page up"),
|
|
* otherwise increase it by one page. If there is no
|
|
* thumb then page up if the mouse is in the upper half
|
|
* of the track.
|
|
*/
|
|
public void mousePressed(MouseEvent e) {
|
|
if (!slider.isEnabled()) {
|
|
return;
|
|
}
|
|
|
|
// We should recalculate geometry just before
|
|
// calculation of the thumb movement direction.
|
|
// It is important for the case, when JSlider
|
|
// is a cell editor in JTable. See 6348946.
|
|
calculateGeometry();
|
|
|
|
currentMouseX = e.getX();
|
|
currentMouseY = e.getY();
|
|
|
|
if (slider.isRequestFocusEnabled()) {
|
|
slider.requestFocus();
|
|
}
|
|
|
|
// Clicked in the Thumb area?
|
|
if (thumbRect.contains(currentMouseX, currentMouseY)) {
|
|
if (UIManager.getBoolean("Slider.onlyLeftMouseButtonDrag")
|
|
&& !SwingUtilities.isLeftMouseButton(e)) {
|
|
return;
|
|
}
|
|
|
|
switch (slider.getOrientation()) {
|
|
case JSlider.VERTICAL:
|
|
offset = currentMouseY - thumbRect.y;
|
|
break;
|
|
case JSlider.HORIZONTAL:
|
|
offset = currentMouseX - thumbRect.x;
|
|
break;
|
|
}
|
|
isDragging = true;
|
|
return;
|
|
}
|
|
|
|
if (!SwingUtilities.isLeftMouseButton(e)) {
|
|
return;
|
|
}
|
|
|
|
isDragging = false;
|
|
slider.setValueIsAdjusting(true);
|
|
|
|
Dimension sbSize = slider.getSize();
|
|
int direction = POSITIVE_SCROLL;
|
|
|
|
switch (slider.getOrientation()) {
|
|
case JSlider.VERTICAL:
|
|
if ( thumbRect.isEmpty() ) {
|
|
int scrollbarCenter = sbSize.height / 2;
|
|
if ( !drawInverted() ) {
|
|
direction = (currentMouseY < scrollbarCenter) ?
|
|
POSITIVE_SCROLL : NEGATIVE_SCROLL;
|
|
}
|
|
else {
|
|
direction = (currentMouseY < scrollbarCenter) ?
|
|
NEGATIVE_SCROLL : POSITIVE_SCROLL;
|
|
}
|
|
}
|
|
else {
|
|
int thumbY = thumbRect.y;
|
|
if ( !drawInverted() ) {
|
|
direction = (currentMouseY < thumbY) ?
|
|
POSITIVE_SCROLL : NEGATIVE_SCROLL;
|
|
}
|
|
else {
|
|
direction = (currentMouseY < thumbY) ?
|
|
NEGATIVE_SCROLL : POSITIVE_SCROLL;
|
|
}
|
|
}
|
|
break;
|
|
case JSlider.HORIZONTAL:
|
|
if ( thumbRect.isEmpty() ) {
|
|
int scrollbarCenter = sbSize.width / 2;
|
|
if ( !drawInverted() ) {
|
|
direction = (currentMouseX < scrollbarCenter) ?
|
|
NEGATIVE_SCROLL : POSITIVE_SCROLL;
|
|
}
|
|
else {
|
|
direction = (currentMouseX < scrollbarCenter) ?
|
|
POSITIVE_SCROLL : NEGATIVE_SCROLL;
|
|
}
|
|
}
|
|
else {
|
|
int thumbX = thumbRect.x;
|
|
if ( !drawInverted() ) {
|
|
direction = (currentMouseX < thumbX) ?
|
|
NEGATIVE_SCROLL : POSITIVE_SCROLL;
|
|
}
|
|
else {
|
|
direction = (currentMouseX < thumbX) ?
|
|
POSITIVE_SCROLL : NEGATIVE_SCROLL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (shouldScroll(direction)) {
|
|
scrollDueToClickInTrack(direction);
|
|
}
|
|
if (shouldScroll(direction)) {
|
|
scrollTimer.stop();
|
|
scrollListener.setDirection(direction);
|
|
scrollTimer.start();
|
|
}
|
|
}
|
|
|
|
public boolean shouldScroll(int direction) {
|
|
Rectangle r = thumbRect;
|
|
if (slider.getOrientation() == JSlider.VERTICAL) {
|
|
if (drawInverted() ? direction < 0 : direction > 0) {
|
|
if (r.y <= currentMouseY) {
|
|
return false;
|
|
}
|
|
}
|
|
else if (r.y + r.height >= currentMouseY) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if (drawInverted() ? direction < 0 : direction > 0) {
|
|
if (r.x + r.width >= currentMouseX) {
|
|
return false;
|
|
}
|
|
}
|
|
else if (r.x <= currentMouseX) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (direction > 0 && slider.getValue() + slider.getExtent() >=
|
|
slider.getMaximum()) {
|
|
return false;
|
|
}
|
|
else if (direction < 0 && slider.getValue() <=
|
|
slider.getMinimum()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the models value to the position of the top/left
|
|
* of the thumb relative to the origin of the track.
|
|
*/
|
|
public void mouseDragged(MouseEvent e) {
|
|
int thumbMiddle;
|
|
|
|
if (!slider.isEnabled()) {
|
|
return;
|
|
}
|
|
|
|
currentMouseX = e.getX();
|
|
currentMouseY = e.getY();
|
|
|
|
if (!isDragging) {
|
|
return;
|
|
}
|
|
|
|
slider.setValueIsAdjusting(true);
|
|
|
|
switch (slider.getOrientation()) {
|
|
case JSlider.VERTICAL:
|
|
int halfThumbHeight = thumbRect.height / 2;
|
|
int thumbTop = e.getY() - offset;
|
|
int trackTop = trackRect.y;
|
|
int trackBottom = trackRect.y + (trackRect.height - 1);
|
|
int vMax = yPositionForValue(slider.getMaximum() -
|
|
slider.getExtent());
|
|
|
|
if (drawInverted()) {
|
|
trackBottom = vMax;
|
|
}
|
|
else {
|
|
trackTop = vMax;
|
|
}
|
|
thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight);
|
|
thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight);
|
|
|
|
setThumbLocation(thumbRect.x, thumbTop);
|
|
|
|
thumbMiddle = thumbTop + halfThumbHeight;
|
|
slider.setValue( valueForYPosition( thumbMiddle ) );
|
|
break;
|
|
case JSlider.HORIZONTAL:
|
|
int halfThumbWidth = thumbRect.width / 2;
|
|
int thumbLeft = e.getX() - offset;
|
|
int trackLeft = trackRect.x;
|
|
int trackRight = trackRect.x + (trackRect.width - 1);
|
|
int hMax = xPositionForValue(slider.getMaximum() -
|
|
slider.getExtent());
|
|
|
|
if (drawInverted()) {
|
|
trackLeft = hMax;
|
|
}
|
|
else {
|
|
trackRight = hMax;
|
|
}
|
|
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
|
|
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
|
|
|
|
setThumbLocation(thumbLeft, thumbRect.y);
|
|
|
|
thumbMiddle = thumbLeft + halfThumbWidth;
|
|
slider.setValue(valueForXPosition(thumbMiddle));
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void mouseMoved(MouseEvent e) { }
|
|
}
|
|
|
|
/**
|
|
* Scroll-event listener.
|
|
*
|
|
* This class should be treated as a "protected" inner class.
|
|
* Instantiate it only within subclasses of <code>Foo</code>.
|
|
*/
|
|
public class ScrollListener implements ActionListener {
|
|
// changed this class to public to avoid bogus IllegalAccessException
|
|
// bug in InternetExplorer browser. It was protected. Work around
|
|
// for 4109432
|
|
int direction = POSITIVE_SCROLL;
|
|
boolean useBlockIncrement;
|
|
|
|
public ScrollListener() {
|
|
direction = POSITIVE_SCROLL;
|
|
useBlockIncrement = true;
|
|
}
|
|
|
|
public ScrollListener(int dir, boolean block) {
|
|
direction = dir;
|
|
useBlockIncrement = block;
|
|
}
|
|
|
|
public void setDirection(int direction) {
|
|
this.direction = direction;
|
|
}
|
|
|
|
public void setScrollByBlock(boolean block) {
|
|
this.useBlockIncrement = block;
|
|
}
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
if (useBlockIncrement) {
|
|
scrollByBlock(direction);
|
|
}
|
|
else {
|
|
scrollByUnit(direction);
|
|
}
|
|
if (!trackListener.shouldScroll(direction)) {
|
|
((Timer)e.getSource()).stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Listener for resizing events.
|
|
* <p>
|
|
* This class should be treated as a "protected" inner class.
|
|
* Instantiate it only within subclasses of <code>Foo</code>.
|
|
*/
|
|
public class ComponentHandler extends ComponentAdapter {
|
|
// NOTE: This class exists only for backward compatibility. All
|
|
// its functionality has been moved into Handler. If you need to add
|
|
// new functionality add it to the Handler, but make sure this
|
|
// class calls into the Handler.
|
|
public void componentResized(ComponentEvent e) {
|
|
getHandler().componentResized(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Focus-change listener.
|
|
* <p>
|
|
* This class should be treated as a "protected" inner class.
|
|
* Instantiate it only within subclasses of <code>Foo</code>.
|
|
*/
|
|
public class FocusHandler implements FocusListener {
|
|
// NOTE: This class exists only for backward compatibility. All
|
|
// its functionality has been moved into Handler. If you need to add
|
|
// new functionality add it to the Handler, but make sure this
|
|
// class calls into the Handler.
|
|
public void focusGained(FocusEvent e) {
|
|
getHandler().focusGained(e);
|
|
}
|
|
|
|
public void focusLost(FocusEvent e) {
|
|
getHandler().focusLost(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* As of Java 2 platform v1.3 this undocumented class is no longer used.
|
|
* The recommended approach to creating bindings is to use a
|
|
* combination of an <code>ActionMap</code>, to contain the action,
|
|
* and an <code>InputMap</code> to contain the mapping from KeyStroke
|
|
* to action description. The InputMap is is usually described in the
|
|
* LookAndFeel tables.
|
|
* <p>
|
|
* Please refer to the key bindings specification for further details.
|
|
* <p>
|
|
* This class should be treated as a "protected" inner class.
|
|
* Instantiate it only within subclasses of <code>Foo</code>.
|
|
*/
|
|
public class ActionScroller extends AbstractAction {
|
|
// NOTE: This class exists only for backward compatibility. All
|
|
// its functionality has been moved into Actions. If you need to add
|
|
// new functionality add it to the Actions, but make sure this
|
|
// class calls into the Actions.
|
|
int dir;
|
|
boolean block;
|
|
JSlider slider;
|
|
|
|
public ActionScroller( JSlider slider, int dir, boolean block) {
|
|
this.dir = dir;
|
|
this.block = block;
|
|
this.slider = slider;
|
|
}
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block);
|
|
}
|
|
|
|
public boolean isEnabled() {
|
|
boolean b = true;
|
|
if (slider != null) {
|
|
b = slider.isEnabled();
|
|
}
|
|
return b;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* A static version of the above.
|
|
*/
|
|
static class SharedActionScroller extends AbstractAction {
|
|
// NOTE: This class exists only for backward compatibility. All
|
|
// its functionality has been moved into Actions. If you need to add
|
|
// new functionality add it to the Actions, but make sure this
|
|
// class calls into the Actions.
|
|
int dir;
|
|
boolean block;
|
|
|
|
public SharedActionScroller(int dir, boolean block) {
|
|
this.dir = dir;
|
|
this.block = block;
|
|
}
|
|
|
|
public void actionPerformed(ActionEvent evt) {
|
|
JSlider slider = (JSlider)evt.getSource();
|
|
BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType(
|
|
slider.getUI(), BasicSliderUI.class);
|
|
if (ui == null) {
|
|
return;
|
|
}
|
|
SHARED_ACTION.scroll(slider, ui, dir, block);
|
|
}
|
|
}
|
|
|
|
private static class Actions extends UIAction {
|
|
public static final String POSITIVE_UNIT_INCREMENT =
|
|
"positiveUnitIncrement";
|
|
public static final String POSITIVE_BLOCK_INCREMENT =
|
|
"positiveBlockIncrement";
|
|
public static final String NEGATIVE_UNIT_INCREMENT =
|
|
"negativeUnitIncrement";
|
|
public static final String NEGATIVE_BLOCK_INCREMENT =
|
|
"negativeBlockIncrement";
|
|
public static final String MIN_SCROLL_INCREMENT = "minScroll";
|
|
public static final String MAX_SCROLL_INCREMENT = "maxScroll";
|
|
|
|
|
|
Actions() {
|
|
super(null);
|
|
}
|
|
|
|
public Actions(String name) {
|
|
super(name);
|
|
}
|
|
|
|
public void actionPerformed(ActionEvent evt) {
|
|
JSlider slider = (JSlider)evt.getSource();
|
|
BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType(
|
|
slider.getUI(), BasicSliderUI.class);
|
|
String name = getName();
|
|
|
|
if (ui == null) {
|
|
return;
|
|
}
|
|
if (POSITIVE_UNIT_INCREMENT == name) {
|
|
scroll(slider, ui, POSITIVE_SCROLL, false);
|
|
} else if (NEGATIVE_UNIT_INCREMENT == name) {
|
|
scroll(slider, ui, NEGATIVE_SCROLL, false);
|
|
} else if (POSITIVE_BLOCK_INCREMENT == name) {
|
|
scroll(slider, ui, POSITIVE_SCROLL, true);
|
|
} else if (NEGATIVE_BLOCK_INCREMENT == name) {
|
|
scroll(slider, ui, NEGATIVE_SCROLL, true);
|
|
} else if (MIN_SCROLL_INCREMENT == name) {
|
|
scroll(slider, ui, MIN_SCROLL, false);
|
|
} else if (MAX_SCROLL_INCREMENT == name) {
|
|
scroll(slider, ui, MAX_SCROLL, false);
|
|
}
|
|
}
|
|
|
|
private void scroll(JSlider slider, BasicSliderUI ui, int direction,
|
|
boolean isBlock) {
|
|
boolean invert = slider.getInverted();
|
|
|
|
if (direction == NEGATIVE_SCROLL || direction == POSITIVE_SCROLL) {
|
|
if (invert) {
|
|
direction = (direction == POSITIVE_SCROLL) ?
|
|
NEGATIVE_SCROLL : POSITIVE_SCROLL;
|
|
}
|
|
|
|
if (isBlock) {
|
|
ui.scrollByBlock(direction);
|
|
} else {
|
|
ui.scrollByUnit(direction);
|
|
}
|
|
} else { // MIN or MAX
|
|
if (invert) {
|
|
direction = (direction == MIN_SCROLL) ?
|
|
MAX_SCROLL : MIN_SCROLL;
|
|
}
|
|
|
|
slider.setValue((direction == MIN_SCROLL) ?
|
|
slider.getMinimum() : slider.getMaximum());
|
|
}
|
|
}
|
|
}
|
|
}
|