/*
* Copyright (c) 2005-2016 Substance Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Substance Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.substance.internal.ui;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Map;
import javax.swing.ButtonModel;
import javax.swing.DefaultButtonModel;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicSliderUI;
import org.pushingpixels.lafwidget.LafWidgetUtilities;
import org.pushingpixels.lafwidget.contrib.intellij.UIUtil;
import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
import org.pushingpixels.substance.api.ComponentState;
import org.pushingpixels.substance.api.SubstanceColorScheme;
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.api.painter.border.SubstanceBorderPainter;
import org.pushingpixels.substance.api.painter.fill.ClassicFillPainter;
import org.pushingpixels.substance.api.painter.fill.SubstanceFillPainter;
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
import org.pushingpixels.substance.internal.painter.BackgroundPaintingUtils;
import org.pushingpixels.substance.internal.painter.SeparatorPainterUtils;
import org.pushingpixels.substance.internal.utils.HashMapKey;
import org.pushingpixels.substance.internal.utils.LazyResettableHashMap;
import org.pushingpixels.substance.internal.utils.RolloverControlListener;
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceOutlineUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils;
import org.pushingpixels.substance.internal.utils.icon.SubstanceIconFactory;
/**
* UI for sliders in <b>Substance</b> look and feel.
*
* @author Kirill Grouchnikov
*/
public class SubstanceSliderUI extends BasicSliderUI implements TransitionAwareUI {
/**
* Surrogate button model for tracking the thumb transitions.
*/
private ButtonModel thumbModel;
/**
* Listener for transition animations.
*/
private RolloverControlListener substanceRolloverListener;
/**
* Listener on property change events.
*/
private PropertyChangeListener substancePropertyChangeListener;
protected StateTransitionTracker stateTransitionTracker;
/**
* Icon for horizontal sliders.
*/
protected Icon horizontalIcon;
/**
* Icon for sliders without labels and ticks.
*/
protected Icon roundIcon;
/**
* Icon for vertical sliders.
*/
protected Icon verticalIcon;
/**
* Cache of track images.
*/
protected static final LazyResettableHashMap<BufferedImage> trackCache = new LazyResettableHashMap<BufferedImage>(
"SubstanceSliderUI.track");
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent comp) {
SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
return new SubstanceSliderUI((JSlider) comp);
}
/**
* Simple constructor.
*
* @param slider
* Slider.
*/
public SubstanceSliderUI(JSlider slider) {
super(null);
this.thumbModel = new DefaultButtonModel();
this.thumbModel.setArmed(false);
this.thumbModel.setSelected(false);
this.thumbModel.setPressed(false);
this.thumbModel.setRollover(false);
this.thumbModel.setEnabled(slider.isEnabled());
this.stateTransitionTracker = new StateTransitionTracker(slider, this.thumbModel);
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#calculateTrackRect()
*/
@Override
protected void calculateTrackRect() {
super.calculateTrackRect();
if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) {
// this.trackRect.y = 3
// + (int) Math.ceil(SubstanceSizeUtils
// .getFocusStrokeWidth(SubstanceSizeUtils
// .getComponentFontSize(this.slider)))
// + this.insetCache.top;
} else {
if (this.slider.getComponentOrientation().isLeftToRight()) {
this.trackRect.x += 2;
} else {
this.trackRect.x -= 2;
}
}
}
/**
* Returns the rectangle of track for painting.
*
* @return The rectangle of track for painting.
*/
private Rectangle getPaintTrackRect() {
int trackLeft = 0, trackRight = 0, trackTop = 0, trackBottom = 0;
int trackWidth = this.getTrackWidth();
if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) {
trackRight = this.trackRect.width;
if (this.slider.getPaintLabels() || this.slider.getPaintTicks()) {
trackTop = 3 + this.insetCache.top + 2 * this.focusInsets.top;
} else {
// vertically center the track
int topInset = this.insetCache.top + this.focusInsets.top;
int bottomInset = this.insetCache.bottom + this.focusInsets.bottom;
trackTop = topInset + (this.slider.getHeight() - topInset - bottomInset) / 2
- trackWidth / 2;
}
trackBottom = trackTop + trackWidth - 1;
return new Rectangle(this.trackRect.x + trackLeft, trackTop, trackRight - trackLeft,
trackBottom - trackTop);
} else {
if (this.slider.getPaintLabels() || this.slider.getPaintTicks()) {
if (this.slider.getComponentOrientation().isLeftToRight()) {
trackLeft = trackRect.x + this.insetCache.left + this.focusInsets.left;
trackRight = trackLeft + trackWidth - 1;
} else {
trackRight = trackRect.x + trackRect.width - this.insetCache.right
- this.focusInsets.right;
trackLeft = trackRight - trackWidth - 1;
}
} else {
// horizontally center the track
int leftInset = this.insetCache.left + this.focusInsets.left;
int rightInset = this.insetCache.right + this.focusInsets.right;
trackLeft = leftInset + (this.slider.getWidth() - leftInset - rightInset) / 2
- trackWidth / 2;
trackRight = trackLeft + trackWidth - 1;
}
trackBottom = this.trackRect.height - 1;
return new Rectangle(trackLeft, this.trackRect.y + trackTop, trackRight - trackLeft,
trackBottom - trackTop);
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#paintTrack(java.awt.Graphics)
*/
@Override
public void paintTrack(Graphics g) {
Graphics2D graphics = (Graphics2D) g.create();
boolean drawInverted = this.drawInverted();
Rectangle paintRect = this.getPaintTrackRect();
// Width and height of the painting rectangle.
int width = paintRect.width;
int height = paintRect.height;
if (this.slider.getOrientation() == JSlider.VERTICAL) {
// apply rotation / translate transformation on vertical
// slider tracks
int temp = width;
width = height;
height = temp;
AffineTransform at = graphics.getTransform();
at.translate(paintRect.x, width + paintRect.y);
at.rotate(-Math.PI / 2);
graphics.setTransform(at);
} else {
graphics.translate(paintRect.x, paintRect.y);
}
StateTransitionTracker.ModelStateInfo modelStateInfo = this.stateTransitionTracker
.getModelStateInfo();
SubstanceColorScheme trackSchemeUnselected = SubstanceColorSchemeUtilities
.getColorScheme(this.slider, this.slider.isEnabled() ? ComponentState.ENABLED
: ComponentState.DISABLED_UNSELECTED);
SubstanceColorScheme trackBorderSchemeUnselected = SubstanceColorSchemeUtilities
.getColorScheme(this.slider, ColorSchemeAssociationKind.BORDER,
this.slider.isEnabled() ? ComponentState.ENABLED
: ComponentState.DISABLED_UNSELECTED);
this.paintSliderTrack(graphics, drawInverted, trackSchemeUnselected,
trackBorderSchemeUnselected, width, height);
Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo
.getStateContributionMap();
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
.entrySet()) {
ComponentState activeState = activeEntry.getKey();
if (!activeState.isActive())
continue;
float contribution = activeEntry.getValue().getContribution();
if (contribution == 0.0f)
continue;
graphics.setComposite(
LafWidgetUtilities.getAlphaComposite(this.slider, contribution, g));
SubstanceColorScheme activeFillScheme = SubstanceColorSchemeUtilities
.getColorScheme(this.slider, activeState);
SubstanceColorScheme activeBorderScheme = SubstanceColorSchemeUtilities
.getColorScheme(this.slider, ColorSchemeAssociationKind.BORDER, activeState);
this.paintSliderTrackSelected(graphics, drawInverted, paintRect, activeFillScheme,
activeBorderScheme, width, height);
}
graphics.dispose();
}
/**
* Paints the slider track.
*
* @param graphics
* Graphics.
* @param drawInverted
* Indicates whether the value-range shown for the slider is
* reversed.
* @param fillColorScheme
* Fill color scheme.
* @param borderScheme
* Border color scheme.
* @param width
* Track width.
* @param height
* Track height.
*/
private void paintSliderTrack(Graphics2D graphics, boolean drawInverted,
SubstanceColorScheme fillColorScheme, SubstanceColorScheme borderScheme, int width,
int height) {
Graphics2D g2d = (Graphics2D) graphics.create();
SubstanceFillPainter fillPainter = ClassicFillPainter.INSTANCE;
SubstanceBorderPainter borderPainter = SubstanceCoreUtilities.getBorderPainter(this.slider);
int componentFontSize = SubstanceSizeUtils.getComponentFontSize(this.slider);
float borderDelta = SubstanceSizeUtils.getBorderStrokeWidth() / 2.0f;
float radius = SubstanceSizeUtils.getClassicButtonCornerRadius(componentFontSize) / 2.0f;
float borderThickness = (int) SubstanceSizeUtils.getBorderStrokeWidth();
HashMapKey key = SubstanceCoreUtilities.getHashKey(width, height, radius, borderDelta,
borderThickness, fillColorScheme.getDisplayName(), borderScheme.getDisplayName());
int scaleFactor = UIUtil.getScaleFactor();
BufferedImage trackImage = trackCache.get(key);
if (trackImage == null) {
trackImage = SubstanceCoreUtilities.getBlankImage(width + 1, height + 1);
Graphics2D cacheGraphics = trackImage.createGraphics();
Shape contour = SubstanceOutlineUtilities.getBaseOutline(width + 1, height + 1, radius,
null, borderDelta);
fillPainter.paintContourBackground(cacheGraphics, slider, width, height, contour, false,
fillColorScheme, false);
GeneralPath contourInner = SubstanceOutlineUtilities.getBaseOutline(width + 1,
height + 1, radius - borderThickness, null, borderThickness + borderDelta);
borderPainter.paintBorder(cacheGraphics, slider, width + 1, height + 1, contour,
contourInner, borderScheme);
trackCache.put(key, trackImage);
cacheGraphics.dispose();
}
g2d.drawImage(trackImage, 0, 0, trackImage.getWidth() / scaleFactor,
trackImage.getHeight() / scaleFactor, null);
g2d.dispose();
}
/**
* Paints the selected part of the slider track.
*
* @param graphics
* Graphics.
* @param drawInverted
* Indicates whether the value-range shown for the slider is
* reversed.
* @param paintRect
* Selected portion.
* @param fillScheme
* Fill color scheme.
* @param borderScheme
* Border color scheme.
* @param width
* Track width.
* @param height
* Track height.
*/
private void paintSliderTrackSelected(Graphics2D graphics, boolean drawInverted,
Rectangle paintRect, SubstanceColorScheme fillScheme, SubstanceColorScheme borderScheme,
int width, int height) {
Graphics2D g2d = (Graphics2D) graphics.create();
Insets insets = this.slider.getInsets();
insets.top /= 2;
insets.left /= 2;
insets.bottom /= 2;
insets.right /= 2;
SubstanceFillPainter fillPainter = SubstanceCoreUtilities.getFillPainter(this.slider);
SubstanceBorderPainter borderPainter = SubstanceCoreUtilities.getBorderPainter(this.slider);
float radius = SubstanceSizeUtils.getClassicButtonCornerRadius(
SubstanceSizeUtils.getComponentFontSize(slider)) / 2.0f;
float borderDelta = SubstanceSizeUtils.getBorderStrokeWidth() / 2.0f;
// fill selected portion
if (this.slider.isEnabled()) {
if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) {
int middleOfThumb = this.thumbRect.x + (this.thumbRect.width / 2) - paintRect.x;
int fillMinX;
int fillMaxX;
if (drawInverted) {
fillMinX = middleOfThumb;
fillMaxX = width;
} else {
fillMinX = 0;
fillMaxX = middleOfThumb;
}
int fillWidth = fillMaxX - fillMinX;
int fillHeight = height + 1;
if ((fillWidth > 0) && (fillHeight > 0)) {
Shape contour = SubstanceOutlineUtilities.getBaseOutline(fillWidth, fillHeight,
radius, null, borderDelta);
g2d.translate(fillMinX, 0);
fillPainter.paintContourBackground(g2d, this.slider, fillWidth, fillHeight,
contour, false, fillScheme, false);
borderPainter.paintBorder(g2d, this.slider, fillWidth, fillHeight, contour,
null, borderScheme);
}
} else {
int middleOfThumb = this.thumbRect.y + (this.thumbRect.height / 2) - paintRect.y;
int fillMin;
int fillMax;
if (this.drawInverted()) {
fillMin = 0;
fillMax = middleOfThumb;
// fix for issue 368 - inverted vertical sliders
g2d.translate(width + 2 - middleOfThumb, 0);
} else {
fillMin = middleOfThumb;
fillMax = width + 1;
}
int fillWidth = fillMax - fillMin;
int fillHeight = height + 1;
if ((fillWidth > 0) && (fillHeight > 0)) {
Shape contour = SubstanceOutlineUtilities.getBaseOutline(fillWidth, fillHeight,
radius, null, borderDelta);
fillPainter.paintContourBackground(g2d, this.slider, fillWidth, fillHeight,
contour, false, fillScheme, false);
borderPainter.paintBorder(g2d, this.slider, fillWidth, fillHeight, contour,
null, borderScheme);
}
}
}
g2d.dispose();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#getThumbSize()
*/
@Override
protected Dimension getThumbSize() {
Icon thumbIcon = this.getIcon();
return new Dimension(thumbIcon.getIconWidth(), thumbIcon.getIconHeight());
}
/**
* Returns the thumb icon for the associated slider.
*
* @return The thumb icon for the associated slider.
*/
protected Icon getIcon() {
if (this.slider.getOrientation() == JSlider.HORIZONTAL) {
if (this.slider.getPaintTicks() || this.slider.getPaintLabels())
return this.horizontalIcon;
else
return this.roundIcon;
} else {
if (this.slider.getPaintTicks() || this.slider.getPaintLabels())
return this.verticalIcon;
else
return this.roundIcon;
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#paintThumb(java.awt.Graphics)
*/
@Override
public void paintThumb(Graphics g) {
Graphics2D graphics = (Graphics2D) g.create();
Rectangle knobBounds = this.thumbRect;
graphics.translate(knobBounds.x, knobBounds.y);
Icon icon = this.getIcon();
if (this.slider.getOrientation() == JSlider.HORIZONTAL) {
if (icon != null) {
graphics.translate(-2, 0);
icon.paintIcon(this.slider, graphics, 0, 0);
}
} else {
if (this.slider.getComponentOrientation().isLeftToRight()) {
if (icon != null) {
graphics.translate(1, -1);
icon.paintIcon(this.slider, graphics, 0, 0);
}
} else {
if (icon != null) {
graphics.translate(1, 1);
icon.paintIcon(this.slider, graphics, 0, 0);
}
}
}
graphics.dispose();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#paint(java.awt.Graphics,
* javax.swing.JComponent)
*/
@Override
public void paint(Graphics g, final JComponent c) {
Graphics2D graphics = (Graphics2D) g.create();
ComponentState currState = ComponentState.getState(this.thumbModel, this.slider);
float alpha = SubstanceColorSchemeUtilities.getAlpha(this.slider, currState);
BackgroundPaintingUtils.updateIfOpaque(graphics, c);
recalculateIfInsetsChanged();
recalculateIfOrientationChanged();
final Rectangle clip = graphics.getClipBounds();
if (!clip.intersects(trackRect) && slider.getPaintTrack())
calculateGeometry();
graphics.setComposite(LafWidgetUtilities.getAlphaComposite(this.slider, alpha, g));
if (slider.getPaintTrack() && clip.intersects(trackRect)) {
paintTrack(graphics);
}
if (slider.getPaintTicks() && clip.intersects(tickRect)) {
paintTicks(graphics);
}
paintFocus(graphics);
if (clip.intersects(thumbRect)) {
paintThumb(graphics);
}
graphics.setComposite(LafWidgetUtilities.getAlphaComposite(this.slider, 1.0f, g));
if (slider.getPaintLabels() && clip.intersects(labelRect)) {
paintLabels(graphics);
}
graphics.dispose();
}
@Override
public StateTransitionTracker getTransitionTracker() {
return this.stateTransitionTracker;
}
/*
* (non-Javadoc)
*
* @see
* org.pushingpixels.substance.Trackable#isInside(java.awt.event.MouseEvent)
*/
public boolean isInside(MouseEvent me) {
Rectangle thumbB = this.thumbRect;
if (thumbB == null)
return false;
return thumbB.contains(me.getX(), me.getY());
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.plaf.basic.BasicSliderUI#installDefaults(javax.swing.JSlider)
*/
@Override
protected void installDefaults(JSlider slider) {
super.installDefaults(slider);
Font f = slider.getFont();
if (f == null || f instanceof UIResource) {
slider.setFont(new FontUIResource(SubstanceLookAndFeel.getFontPolicy()
.getFontSet("Substance", null).getControlFont()));
}
int size = SubstanceSizeUtils
.getSliderIconSize(SubstanceSizeUtils.getComponentFontSize(slider));
// System.out.println("Slider size : " + size);
this.horizontalIcon = SubstanceIconFactory.getSliderHorizontalIcon(size, false);
this.roundIcon = SubstanceIconFactory.getSliderRoundIcon(size);
this.verticalIcon = SubstanceIconFactory.getSliderVerticalIcon(size, false);
int focusIns = (int) Math.ceil(2.0 * SubstanceSizeUtils.getFocusStrokeWidth());
this.focusInsets = new Insets(focusIns, focusIns, focusIns, focusIns);
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.plaf.basic.BasicSliderUI#installListeners(javax.swing.JSlider
* )
*/
@Override
protected void installListeners(final JSlider slider) {
super.installListeners(slider);
// fix for defect 109 - memory leak on changing skin
this.substanceRolloverListener = new RolloverControlListener(this, this.thumbModel);
slider.addMouseListener(this.substanceRolloverListener);
slider.addMouseMotionListener(this.substanceRolloverListener);
this.substancePropertyChangeListener = (PropertyChangeEvent evt) -> {
if ("enabled".equals(evt.getPropertyName())) {
SubstanceSliderUI.this.thumbModel.setEnabled(slider.isEnabled());
}
if ("font".equals(evt.getPropertyName())) {
SwingUtilities.invokeLater(() -> slider.updateUI());
}
};
this.slider.addPropertyChangeListener(this.substancePropertyChangeListener);
this.stateTransitionTracker.registerModelListeners();
this.stateTransitionTracker.registerFocusListeners();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#uninstallListeners(javax.swing.
* JSlider )
*/
@Override
protected void uninstallListeners(JSlider slider) {
super.uninstallListeners(slider);
// fix for defect 109 - memory leak on changing skin
slider.removeMouseListener(this.substanceRolloverListener);
slider.removeMouseMotionListener(this.substanceRolloverListener);
this.substanceRolloverListener = null;
slider.removePropertyChangeListener(this.substancePropertyChangeListener);
this.substancePropertyChangeListener = null;
this.stateTransitionTracker.unregisterModelListeners();
this.stateTransitionTracker.unregisterFocusListeners();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#paintFocus(java.awt.Graphics)
*/
@Override
public void paintFocus(Graphics g) {
SubstanceCoreUtilities.paintFocus(g, this.slider, this.slider, this, null, null, 1.0f,
SubstanceSizeUtils.getFocusStrokeWidth());
}
/**
* Returns the shorter dimension of the track.
*
* @return Shorter dimension of the track.
*/
protected int getTrackWidth() {
return SubstanceSizeUtils
.getSliderTrackSize(SubstanceSizeUtils.getComponentFontSize(this.slider));
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#getTickLength()
*/
@Override
protected int getTickLength() {
return SubstanceSizeUtils
.getSliderTickSize(SubstanceSizeUtils.getComponentFontSize(this.slider));
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#paintTicks(java.awt.Graphics)
*/
@Override
public void paintTicks(Graphics g) {
Rectangle tickBounds = this.tickRect;
SubstanceColorScheme tickScheme = SubstanceColorSchemeUtilities.getColorScheme(this.slider,
ColorSchemeAssociationKind.SEPARATOR,
this.slider.isEnabled() ? ComponentState.ENABLED
: ComponentState.DISABLED_UNSELECTED);
if (this.slider.getOrientation() == JSlider.HORIZONTAL) {
int value = this.slider.getMinimum() + this.slider.getMinorTickSpacing();
int xPos = 0;
if ((this.slider.getMinorTickSpacing() > 0)
&& (this.slider.getMajorTickSpacing() > 0)) {
// collect x's of the minor ticks
java.util.List<Integer> minorXs = new ArrayList<Integer>();
while (value < this.slider.getMaximum()) {
int delta = value - this.slider.getMinimum();
if (delta % this.slider.getMajorTickSpacing() != 0) {
xPos = this.xPositionForValue(value);
minorXs.add(xPos - 1);
}
value += this.slider.getMinorTickSpacing();
}
// and paint them in one call
SeparatorPainterUtils.paintVerticalLines(g, this.slider, tickScheme, tickBounds.y,
minorXs, tickBounds.height / 2, 0.75f);
}
if (this.slider.getMajorTickSpacing() > 0) {
// collect x's of the major ticks
java.util.List<Integer> majorXs = new ArrayList<Integer>();
value = this.slider.getMinimum() + this.slider.getMajorTickSpacing();
while (value < this.slider.getMaximum()) {
xPos = this.xPositionForValue(value);
majorXs.add(xPos - 1);
value += this.slider.getMajorTickSpacing();
}
// and paint them in one call
SeparatorPainterUtils.paintVerticalLines(g, this.slider, tickScheme, tickBounds.y,
majorXs, tickBounds.height, 0.75f);
}
} else {
g.translate(tickBounds.x, 0);
int value = this.slider.getMinimum() + this.slider.getMinorTickSpacing();
int yPos = 0;
boolean ltr = this.slider.getComponentOrientation().isLeftToRight();
if (this.slider.getMinorTickSpacing() > 0) {
// collect y's of the minor ticks
java.util.List<Integer> minorYs = new ArrayList<Integer>();
int offset = 0;
if (!ltr) {
offset = tickBounds.width - tickBounds.width / 2;
}
while (value < this.slider.getMaximum()) {
yPos = this.yPositionForValue(value);
minorYs.add(yPos);
value += this.slider.getMinorTickSpacing();
}
// and paint them in one call
SeparatorPainterUtils.paintHorizontalLines(g, this.slider, tickScheme, offset,
minorYs, tickBounds.width / 2, ltr ? 0.75f : 0.25f, ltr);
}
if (this.slider.getMajorTickSpacing() > 0) {
// collect y's of the major ticks
java.util.List<Integer> majorYs = new ArrayList<Integer>();
value = this.slider.getMinimum() + this.slider.getMajorTickSpacing();
while (value < this.slider.getMaximum()) {
yPos = this.yPositionForValue(value);
majorYs.add(yPos);
value += this.slider.getMajorTickSpacing();
}
// and paint them in one call
SeparatorPainterUtils.paintHorizontalLines(g, this.slider, tickScheme, 0, majorYs,
tickBounds.width, ltr ? 0.75f : 0.25f, ltr);
}
g.translate(-tickBounds.x, 0);
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#calculateTickRect()
*/
@Override
protected void calculateTickRect() {
if (this.slider.getOrientation() == JSlider.HORIZONTAL) {
this.tickRect.x = this.trackRect.x;
this.tickRect.y = this.trackRect.y + this.trackRect.height;
this.tickRect.width = this.trackRect.width;
this.tickRect.height = (this.slider.getPaintTicks()) ? this.getTickLength() : 0;
} else {
this.tickRect.width = (this.slider.getPaintTicks()) ? this.getTickLength() : 0;
if (this.slider.getComponentOrientation().isLeftToRight()) {
this.tickRect.x = this.trackRect.x + this.trackRect.width;
} else {
this.tickRect.x = this.trackRect.x - this.tickRect.width;
}
this.tickRect.y = this.trackRect.y;
this.tickRect.height = this.trackRect.height;
}
if (this.slider.getPaintTicks()) {
if (this.slider.getOrientation() == JSlider.HORIZONTAL) {
this.tickRect.y -= 3;
} else {
if (this.slider.getComponentOrientation().isLeftToRight()) {
this.tickRect.x -= 2;
} else {
this.tickRect.x += 2;
}
}
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#calculateLabelRect()
*/
@Override
protected void calculateLabelRect() {
super.calculateLabelRect();
if ((this.slider.getOrientation() == JSlider.VERTICAL) && !this.slider.getPaintTicks()
&& this.slider.getComponentOrientation().isLeftToRight()) {
this.labelRect.x += 3;
}
if (this.slider.getOrientation() == JSlider.VERTICAL) {
this.labelRect.width = getHeightOfTallestLabel();
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#calculateThumbLocation()
*/
@Override
protected void calculateThumbLocation() {
super.calculateThumbLocation();
Rectangle trackRect = this.getPaintTrackRect();
if (slider.getOrientation() == JSlider.HORIZONTAL) {
int valuePosition = xPositionForValue(slider.getValue());
double centerY = trackRect.y + trackRect.height / 2.0;
thumbRect.y = (int) (centerY - thumbRect.height / 2.0) + 1;
thumbRect.x = valuePosition - thumbRect.width / 2 + 1;
} else {
int valuePosition = yPositionForValue(slider.getValue());
double centerX = trackRect.x + trackRect.width / 2.0;
thumbRect.x = (int) (centerX - thumbRect.width / 2.0);
thumbRect.y = valuePosition - (thumbRect.height / 2);
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#getPreferredSize(javax.swing.
* JComponent )
*/
@Override
public Dimension getPreferredSize(JComponent c) {
this.recalculateIfInsetsChanged();
Dimension d;
if (this.slider.getOrientation() == JSlider.VERTICAL) {
d = new Dimension(this.getPreferredVerticalSize());
d.width = this.insetCache.left + this.insetCache.right;
d.width += this.focusInsets.left + this.focusInsets.right;
d.width += this.trackRect.width;
if (this.slider.getPaintTicks())
d.width += getTickLength();
if (this.slider.getPaintLabels())
d.width += getWidthOfWidestLabel();
d.width += 3;
} else {
d = new Dimension(this.getPreferredHorizontalSize());
d.height = this.insetCache.top + this.insetCache.bottom;
d.height += this.focusInsets.top + this.focusInsets.bottom;
d.height += this.trackRect.height;
if (this.slider.getPaintTicks())
d.height += getTickLength();
if (this.slider.getPaintLabels())
d.height += getHeightOfTallestLabel();
d.height += 6;
}
return d;
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#setThumbLocation(int, int)
*/
@Override
public void setThumbLocation(int x, int y) {
super.setThumbLocation(x, y);
this.slider.repaint();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#getPreferredHorizontalSize()
*/
@Override
public Dimension getPreferredHorizontalSize() {
return new Dimension(
SubstanceSizeUtils.getAdjustedSize(
SubstanceSizeUtils.getComponentFontSize(this.slider), 200, 1, 20, false),
21);
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicSliderUI#getPreferredVerticalSize()
*/
@Override
public Dimension getPreferredVerticalSize() {
return new Dimension(21, SubstanceSizeUtils.getAdjustedSize(
SubstanceSizeUtils.getComponentFontSize(this.slider), 200, 1, 20, false));
}
}