/*
* 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.Color;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.Set;
import javax.swing.BoundedRangeModel;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JProgressBar;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicProgressBarUI;
import org.pushingpixels.lafwidget.LafWidgetUtilities;
import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
import org.pushingpixels.lafwidget.contrib.intellij.UIUtil;
import org.pushingpixels.lafwidget.utils.RenderingUtils;
import org.pushingpixels.substance.api.ColorSchemeSingleColorQuery;
import org.pushingpixels.substance.api.ComponentState;
import org.pushingpixels.substance.api.ComponentStateFacet;
import org.pushingpixels.substance.api.SubstanceColorScheme;
import org.pushingpixels.substance.api.SubstanceConstants.Side;
import org.pushingpixels.substance.api.painter.fill.FractionBasedFillPainter;
import org.pushingpixels.substance.api.painter.fill.SubstanceFillPainter;
import org.pushingpixels.substance.internal.utils.HashMapKey;
import org.pushingpixels.substance.internal.utils.LazyResettableHashMap;
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceColorUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceImageCreator;
import org.pushingpixels.substance.internal.utils.SubstanceOutlineUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils;
import org.pushingpixels.substance.internal.utils.SubstanceTextUtilities;
import org.pushingpixels.trident.Timeline;
import org.pushingpixels.trident.Timeline.RepeatBehavior;
import org.pushingpixels.trident.Timeline.TimelineState;
import org.pushingpixels.trident.TimelinePropertyBuilder.PropertySetter;
import org.pushingpixels.trident.callback.TimelineCallback;
import org.pushingpixels.trident.ease.Spline;
/**
* UI for progress bars in <b>Substance</b> look and feel.
*
* @author Kirill Grouchnikov
*/
public class SubstanceProgressBarUI extends BasicProgressBarUI {
private static final ComponentState DETERMINATE_SELECTED = new ComponentState(
"determinate enabled", new ComponentStateFacet[] {
ComponentStateFacet.ENABLE,
ComponentStateFacet.DETERMINATE,
ComponentStateFacet.SELECTION }, null);
private static final ComponentState DETERMINATE_SELECTED_DISABLED = new ComponentState(
"determinate disabled", new ComponentStateFacet[] {
ComponentStateFacet.DETERMINATE,
ComponentStateFacet.SELECTION },
new ComponentStateFacet[] { ComponentStateFacet.ENABLE });
private static final ComponentState INDETERMINATE_SELECTED = new ComponentState(
"indeterminate enabled",
new ComponentStateFacet[] { ComponentStateFacet.ENABLE,
ComponentStateFacet.SELECTION },
new ComponentStateFacet[] { ComponentStateFacet.DETERMINATE });
private static final ComponentState INDETERMINATE_SELECTED_DISABLED = new ComponentState(
"indeterminate disabled", null, new ComponentStateFacet[] {
ComponentStateFacet.DETERMINATE,
ComponentStateFacet.ENABLE, ComponentStateFacet.SELECTION });
private static final SubstanceFillPainter progressFillPainter =
new FractionBasedFillPainter("Progress fill (internal)",
new float[] { 0.0f, 0.5f, 1.0f },
new ColorSchemeSingleColorQuery[] {
ColorSchemeSingleColorQuery.EXTRALIGHT,
ColorSchemeSingleColorQuery.LIGHT,
ColorSchemeSingleColorQuery.MID
});
private final class SubstanceChangeListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
SubstanceCoreUtilities
.testComponentStateChangeThreadingViolation(progressBar);
int currValue = progressBar.getValue();
int span = progressBar.getMaximum() - progressBar.getMinimum();
int barRectWidth = progressBar.getWidth() - 2 * margin;
int barRectHeight = progressBar.getHeight() - 2 * margin;
int totalPixels = (progressBar.getOrientation() == JProgressBar.HORIZONTAL) ? barRectWidth
: barRectHeight;
// fix for defect 223 (min and max on the model are the
// same).
int pixelDelta = (span <= 0) ? 0 : (currValue - displayedValue)
* totalPixels / span;
if (displayTimeline != null) {
displayTimeline.abort();
}
displayTimeline = new Timeline(progressBar);
displayTimeline.addPropertyToInterpolate(Timeline
.<Integer> property("displayedValue").from(displayedValue)
.to(currValue).setWith(new PropertySetter<Integer>() {
@Override
public void set(Object obj, String fieldName,
Integer value) {
displayedValue = value;
if (progressBar != null) {
progressBar.repaint();
}
}
}));
displayTimeline.setEase(new Spline(0.4f));
AnimationConfigurationManager.getInstance().configureTimeline(
displayTimeline);
// do not animate progress bars used in cell renderers
// since in this case it will most probably be the
// same progress bar used to display different
// values for different cells.
boolean isInCellRenderer = (SwingUtilities.getAncestorOfClass(
CellRendererPane.class, progressBar) != null);
if (!isInCellRenderer && Math.abs(pixelDelta) > 5) {
displayTimeline.play();
} else {
displayedValue = currValue;
progressBar.repaint();
}
}
}
/**
* Hash for computed stripe images.
*/
private static LazyResettableHashMap<BufferedImage> stripeMap =
new LazyResettableHashMap<BufferedImage>("SubstanceProgressBarUI.stripeMap");
/**
* Hash for computed background images.
*/
private static LazyResettableHashMap<BufferedImage> backgroundMap =
new LazyResettableHashMap<BufferedImage>("SubstanceProgressBarUI.backgroundMap");
/**
* Hash for computed progress images.
*/
private static LazyResettableHashMap<BufferedImage> progressMap =
new LazyResettableHashMap<BufferedImage>("SubstanceProgressBarUI.progressMap");
/**
* The current position of the indeterminate animation's cycle. 0, the
* initial value, means paint the first frame. When the progress bar is
* indeterminate and showing, the {@link #indeterminateLoopTimeline} is
* updating this value.
*/
private float animationPosition;
/**
* Value change listener on the associated progress bar.
*/
protected ChangeListener substanceValueChangeListener;
/**
* Property change listener. Tracks changes to the <code>font</code>
* property.
*/
protected PropertyChangeListener substancePropertyChangeListener;
/**
* Inner margin.
*/
protected int margin;
/**
* The speed factor for the indeterminate progress bars.
*/
protected float speed;
protected int displayedValue;
protected Timeline displayTimeline;
protected Timeline indeterminateLoopTimeline;
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent comp) {
SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
return new SubstanceProgressBarUI();
}
@Override
protected void installDefaults() {
super.installDefaults();
this.displayedValue = progressBar.getValue();
LookAndFeel.installProperty(progressBar, "opaque", Boolean.FALSE);
this.speed = (20.0f * UIManager.getInt("ProgressBar.repaintInterval"))
/ UIManager.getInt("ProgressBar.cycleTime");
this.margin = 0;
}
@Override
protected void installListeners() {
super.installListeners();
substanceValueChangeListener = new SubstanceChangeListener();
this.progressBar.addChangeListener(this.substanceValueChangeListener);
this.substancePropertyChangeListener = (PropertyChangeEvent evt) -> {
if ("font".equals(evt.getPropertyName())) {
SwingUtilities.invokeLater(() -> {
if (progressBar != null)
progressBar.updateUI();
});
}
};
this.progressBar
.addPropertyChangeListener(this.substancePropertyChangeListener);
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicProgressBarUI#uninstallListeners()
*/
@Override
protected void uninstallListeners() {
this.progressBar
.removeChangeListener(this.substanceValueChangeListener);
this.substanceValueChangeListener = null;
this.progressBar
.removePropertyChangeListener(this.substancePropertyChangeListener);
this.substancePropertyChangeListener = null;
super.uninstallListeners();
}
/**
* Retrieves stripe image.
*
* @param baseSize
* Stripe base in pixels.
* @param isRotated
* if <code>true</code>, the resulting stripe image will be
* rotated.
* @param colorScheme
* Color scheme to paint the stripe image.
* @return Stripe image.
*/
private static BufferedImage getStripe(int baseSize, boolean isRotated,
SubstanceColorScheme colorScheme) {
HashMapKey key = SubstanceCoreUtilities.getHashKey(baseSize, isRotated,
colorScheme.getDisplayName());
BufferedImage result = SubstanceProgressBarUI.stripeMap.get(key);
if (result == null) {
result = SubstanceImageCreator.getStripe(baseSize, colorScheme
.getUltraLightColor());
if (isRotated) {
result = SubstanceImageCreator.getRotated(result, 1, false);
}
SubstanceProgressBarUI.stripeMap.put(key, result);
}
return result;
}
/**
* Returns the background of a determinate progress bar.
*
* @param bar
* Progress bar.
* @param width
* Progress bar width.
* @param height
* Progress bar height.
* @param scheme
* Color scheme for the background.
* @param fillPainter
* Fill painter.
* @param orientation
* Progress bar orientation (vertical / horizontal).
* @param componentOrientation
* Progress bar LTR / RTL orientation.
* @return Background image.
*/
private static BufferedImage getDeterminateBackground(JProgressBar bar,
int width, int height, SubstanceColorScheme scheme,
SubstanceFillPainter fillPainter, int orientation,
ComponentOrientation componentOrientation) {
HashMapKey key = SubstanceCoreUtilities.getHashKey(width, height,
scheme.getDisplayName(), fillPainter.getDisplayName(), orientation,
componentOrientation);
BufferedImage result = SubstanceProgressBarUI.backgroundMap.get(key);
if (result == null) {
result = SubstanceCoreUtilities.getBlankImage(width, height);
Graphics2D g2d = result.createGraphics();
float radius = 0.5f * SubstanceSizeUtils
.getClassicButtonCornerRadius(SubstanceSizeUtils
.getComponentFontSize(bar));
Shape contour = SubstanceOutlineUtilities.getBaseOutline(width,
height, radius, null);
fillPainter.paintContourBackground(g2d, bar, width, height, contour, false,
scheme, true);
g2d.dispose();
if (orientation == SwingConstants.VERTICAL) {
result = SubstanceImageCreator.getRotated(result, 3, false);
}
SubstanceProgressBarUI.backgroundMap.put(key, result);
}
return result;
}
/**
* Returns the background of a determinate progress bar.
*
* @param bar
* Progress bar.
* @param width
* Progress bar width.
* @param height
* Progress bar height.
* @param scheme
* Color scheme for the background.
* @param fillPainter
* Fill painter.
* @param orientation
* Progress bar orientation (vertical / horizontal).
* @param componentOrientation
* Progress bar LTR / RTL orientation.
* @return Background image.
*/
private static BufferedImage getDeterminateProgress(JProgressBar bar,
int width, int height, boolean isFull, SubstanceColorScheme scheme,
SubstanceFillPainter fillPainter, int orientation,
ComponentOrientation componentOrientation) {
HashMapKey key = SubstanceCoreUtilities.getHashKey(width, height,
scheme.getDisplayName(), fillPainter.getDisplayName(), orientation,
componentOrientation);
BufferedImage result = SubstanceProgressBarUI.progressMap.get(key);
if (result == null) {
result = SubstanceCoreUtilities.getBlankImage(width, height);
Graphics2D g2d = result.createGraphics();
float radius = 0.5f * SubstanceSizeUtils
.getClassicButtonCornerRadius(SubstanceSizeUtils
.getComponentFontSize(bar));
Side straightSide = (orientation == SwingConstants.VERTICAL) ? Side.RIGHT
: (componentOrientation.isLeftToRight() ? Side.RIGHT : Side.LEFT);
Set<Side> straightSides = isFull ? null : EnumSet.of(straightSide);
Shape contour = SubstanceOutlineUtilities.getBaseOutline(width,
height, radius, straightSides);
fillPainter.paintContourBackground(g2d, bar, width, height, contour, false,
scheme, true);
g2d.dispose();
if (orientation == SwingConstants.VERTICAL) {
result = SubstanceImageCreator.getRotated(result, 3, false);
}
SubstanceProgressBarUI.progressMap.put(key, result);
}
return result;
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.plaf.basic.BasicProgressBarUI#paintDeterminate(java.awt.Graphics
* , javax.swing.JComponent)
*/
@Override
public void paintDeterminate(Graphics g, JComponent c) {
if (!(g instanceof Graphics2D)) {
return;
}
ComponentState fillState = getFillState();
ComponentState progressState = getProgressState();
int barRectWidth = progressBar.getWidth() - 2 * margin;
int barRectHeight = progressBar.getHeight() - 2 * margin;
// amount of progress to draw
int amountFull = getAmountFull(new Insets(margin, margin, margin,
margin), barRectWidth, barRectHeight);
Graphics2D g2d = (Graphics2D) g.create();
// install state-aware alpha channel (support for skins
// that use translucency on disabled states).
float stateAlpha = SubstanceColorSchemeUtilities.getAlpha(progressBar, fillState);
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(progressBar, stateAlpha, g));
SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
.getColorScheme(progressBar, fillState);
SubstanceFillPainter fillPainter = SubstanceCoreUtilities
.getFillPainter(progressBar);
int scaleFactor = UIUtil.getScaleFactor();
if (progressBar.getOrientation() == SwingConstants.HORIZONTAL) {
BufferedImage back = getDeterminateBackground(progressBar,
barRectWidth, barRectHeight, fillScheme,
fillPainter, progressBar.getOrientation(),
this.progressBar.getComponentOrientation());
g2d.drawImage(back, margin, margin, back.getWidth() / scaleFactor,
back.getHeight() / scaleFactor, null);
} else {
BufferedImage back = getDeterminateBackground(progressBar,
barRectHeight, barRectWidth, fillScheme,
fillPainter, progressBar.getOrientation(),
this.progressBar.getComponentOrientation());
g2d.drawImage(back, margin, margin, back.getWidth() / scaleFactor,
back.getHeight() / scaleFactor, null);
}
if (amountFull > 0) {
boolean isFull = (this.progressBar.getModel().getValue() == this.progressBar.getMaximum());
SubstanceColorScheme progressColorScheme = SubstanceColorSchemeUtilities
.getColorScheme(progressBar, progressState);
if (progressBar.getOrientation() == SwingConstants.HORIZONTAL) {
int progressWidth = amountFull;
int progressHeight = barRectHeight;
if ((progressWidth > 0) && (progressHeight > 0)) {
BufferedImage progress = getDeterminateProgress(progressBar,
progressWidth, progressHeight, isFull, progressColorScheme,
progressFillPainter, progressBar.getOrientation(),
this.progressBar.getComponentOrientation());
if (progressBar.getComponentOrientation().isLeftToRight()) {
g2d.drawImage(progress, margin, margin,
progress.getWidth() / scaleFactor,
progress.getHeight() / scaleFactor, null);
} else {
// fix for RTL determinate horizontal progress
// bar in 2.3
g2d.drawImage(progress,
margin + barRectWidth - amountFull, margin,
progress.getWidth() / scaleFactor,
progress.getHeight() / scaleFactor, null);
}
}
} else { // VERTICAL
int progressWidth = barRectWidth;
int progressHeight = amountFull;
if ((amountFull > 0) && (progressHeight > 0)) {
// fix for issue 95. Vertical bar is growing from
// the bottom
BufferedImage progress = getDeterminateProgress(progressBar,
progressHeight, progressWidth, isFull, progressColorScheme,
progressFillPainter, progressBar.getOrientation(),
this.progressBar.getComponentOrientation());
g2d.drawImage(progress, margin,
margin + barRectHeight - progressHeight,
progress.getWidth() / scaleFactor,
progress.getHeight() / scaleFactor, null);
}
}
}
// Deal with possible text painting
if (progressBar.isStringPainted()) {
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(progressBar,
1.0f, g));
this.paintString(g2d, margin, margin, barRectWidth, barRectHeight,
amountFull, new Insets(margin, margin, margin, margin));
}
g2d.dispose();
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicProgressBarUI#getSelectionBackground()
*/
@Override
protected Color getSelectionBackground() {
ComponentState fillState = getFillState();
SubstanceColorScheme scheme = SubstanceColorSchemeUtilities
.getColorScheme(progressBar, fillState);
return SubstanceColorUtilities.getForegroundColor(scheme);
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicProgressBarUI#getSelectionForeground()
*/
@Override
protected Color getSelectionForeground() {
ComponentState progressState = getProgressState();
SubstanceColorScheme scheme = SubstanceColorSchemeUtilities
.getColorScheme(progressBar, progressState);
return SubstanceColorUtilities.getForegroundColor(scheme);
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.plaf.basic.BasicProgressBarUI#paintIndeterminate(java.awt
* .Graphics, javax.swing.JComponent)
*/
@Override
public void paintIndeterminate(Graphics g, JComponent c) {
if (!(g instanceof Graphics2D)) {
return;
}
ComponentState progressState = getProgressState();
final int barRectWidth = progressBar.getWidth() - 2 * margin;
final int barRectHeight = progressBar.getHeight() - 2 * margin;
int valComplete = 0;
if (progressBar.getOrientation() == SwingConstants.HORIZONTAL) {
valComplete = (int) (this.animationPosition * (2 * barRectHeight + 1));
} else {
valComplete = (int) (this.animationPosition * (2 * barRectWidth + 1));
}
Graphics2D g2d = (Graphics2D) g.create();
// install state-aware alpha channel (support for skins
// that use translucency on disabled states).
float stateAlpha = SubstanceColorSchemeUtilities.getAlpha(progressBar, progressState);
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(progressBar, stateAlpha, g));
float radius = 0.5f * SubstanceSizeUtils
.getClassicButtonCornerRadius(SubstanceSizeUtils
.getComponentFontSize(progressBar));
g2d.clip(new RoundRectangle2D.Float(margin, margin, barRectWidth, barRectHeight, radius, radius));
SubstanceColorScheme scheme = SubstanceColorSchemeUtilities
.getColorScheme(progressBar, progressState);
if (progressBar.getOrientation() == SwingConstants.HORIZONTAL) {
SubstanceImageCreator.paintRectangularStripedBackground(
progressBar, g2d, margin, margin, barRectWidth,
barRectHeight, scheme, SubstanceProgressBarUI.getStripe(
barRectHeight, false, scheme), valComplete, 0.6f,
false);
} else {
// fix for issue 95. Vertical progress bar grows from the
// bottom.
SubstanceImageCreator.paintRectangularStripedBackground(
progressBar, g2d, margin, margin, barRectWidth,
barRectHeight, scheme, SubstanceProgressBarUI.getStripe(
barRectWidth, true, scheme), 2 * barRectWidth
- valComplete, 0.6f, true);
}
// Deal with possible text painting
if (progressBar.isStringPainted()) {
g2d.setComposite(LafWidgetUtilities.getAlphaComposite(progressBar,
1.0f, g));
this.paintString(g2d, margin, margin, barRectWidth, barRectHeight,
barRectWidth, new Insets(margin, margin, margin, margin));
}
g2d.dispose();
}
private ComponentState getFillState() {
return progressBar.isEnabled() ? ComponentState.ENABLED
: ComponentState.DISABLED_UNSELECTED;
}
private ComponentState getProgressState() {
if (progressBar.isIndeterminate()) {
return progressBar.isEnabled() ? INDETERMINATE_SELECTED
: INDETERMINATE_SELECTED_DISABLED;
} else {
return progressBar.isEnabled() ? DETERMINATE_SELECTED
: DETERMINATE_SELECTED_DISABLED;
}
}
/*
* (non-Javadoc)
*
* @see javax.swing.plaf.basic.BasicProgressBarUI#getBox(java.awt.Rectangle)
*/
@Override
protected Rectangle getBox(Rectangle r) {
// Insets b = this.getInsets(); // area for border
int barRectWidth = progressBar.getWidth() - 2 * margin;
int barRectHeight = progressBar.getHeight() - 2 * margin;
return new Rectangle(margin, margin, barRectWidth, barRectHeight);
}
@Override
protected void startAnimationTimer() {
this.indeterminateLoopTimeline = new Timeline(this);
int cycleDuration = UIManager.getInt("ProgressBar.cycleTime");
if (cycleDuration == 0)
cycleDuration = 1000;
this.indeterminateLoopTimeline.setDuration(cycleDuration);
this.indeterminateLoopTimeline.addCallback(new TimelineCallback() {
@Override
public void onTimelineStateChanged(TimelineState oldState,
TimelineState newState, float durationFraction,
float timelinePosition) {
if ((progressBar != null) && progressBar.isVisible())
progressBar.repaint();
}
@Override
public void onTimelinePulse(float durationFraction,
float timelinePosition) {
if ((progressBar != null) && progressBar.isVisible())
progressBar.repaint();
}
});
this.indeterminateLoopTimeline.addPropertyToInterpolate(Timeline
.<Float> property("animationPosition").from(0.0f).to(1.0f)
.setWith(new PropertySetter<Float>() {
@Override
public void set(Object obj, String fieldName, Float value) {
animationPosition = value;
}
}));
this.indeterminateLoopTimeline.playLoop(RepeatBehavior.LOOP);
}
@Override
protected void stopAnimationTimer() {
this.indeterminateLoopTimeline.abort();
}
/**
* Returns the memory usage string.
*
* @return The memory usage string.
*/
public static String getMemoryUsage() {
StringBuffer sb = new StringBuffer();
sb.append("SubstanceProgressBarUI: \n");
sb.append("\t" + SubstanceProgressBarUI.stripeMap.size() + " stripes");
return sb.toString();
}
@Override
protected int getAmountFull(Insets b, int width, int height) {
int amountFull = 0;
BoundedRangeModel model = progressBar.getModel();
long span = model.getMaximum() - model.getMinimum();
double percentComplete = (double) (this.displayedValue - model.getMinimum())
/ (double) span;
if ((model.getMaximum() - model.getMinimum()) != 0) {
if (this.progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
amountFull = (int) Math.round(width * percentComplete);
} else {
amountFull = (int) Math.round(height * percentComplete);
}
}
return amountFull;
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.plaf.basic.BasicProgressBarUI#getPreferredInnerHorizontal()
*/
@Override
protected Dimension getPreferredInnerHorizontal() {
int size = SubstanceSizeUtils.getComponentFontSize(this.progressBar);
size += 2 * SubstanceSizeUtils.getAdjustedSize(size, 1, 4, 1, false);
return new Dimension(146 + SubstanceSizeUtils.getAdjustedSize(size, 0,
1, 10, false), size);
}
/*
* (non-Javadoc)
*
* @see
* javax.swing.plaf.basic.BasicProgressBarUI#getPreferredInnerVertical()
*/
@Override
protected Dimension getPreferredInnerVertical() {
int size = SubstanceSizeUtils.getComponentFontSize(this.progressBar);
size += 2 * SubstanceSizeUtils.getAdjustedSize(size, 1, 4, 1, false);
return new Dimension(size, 146 + SubstanceSizeUtils.getAdjustedSize(
size, 0, 1, 10, false));
}
@Override
protected void paintString(Graphics g, int x, int y, int width, int height,
int amountFull, Insets b) {
if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
if (progressBar.getComponentOrientation().isLeftToRight()) {
if (progressBar.isIndeterminate()) {
boxRect = getBox(boxRect);
paintString(g, x, y, width, height, boxRect.x,
boxRect.width, b);
} else {
paintString(g, x, y, width, height, x, amountFull, b);
}
} else {
paintString(g, x, y, width, height, x + width - amountFull,
amountFull, b);
}
} else {
if (progressBar.isIndeterminate()) {
boxRect = getBox(boxRect);
paintString(g, x, y, width, height, boxRect.y, boxRect.height,
b);
} else {
paintString(g, x, y, width, height, y + height - amountFull,
amountFull, b);
}
}
}
/**
* Paints the progress string.
*
* @param g
* Graphics used for drawing.
* @param x
* x location of bounding box
* @param y
* y location of bounding box
* @param width
* width of bounding box
* @param height
* height of bounding box
* @param fillStart
* start location, in x or y depending on orientation, of the
* filled portion of the progress bar.
* @param amountFull
* size of the fill region, either width or height depending upon
* orientation.
* @param b
* Insets of the progress bar.
*/
private void paintString(Graphics g, int x, int y, int width, int height,
int fillStart, int amountFull, Insets b) {
String progressString = progressBar.getString();
Rectangle renderRectangle = getStringRectangle(progressString, x, y,
width, height);
if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
SubstanceTextUtilities.paintText(g, this.progressBar,
renderRectangle, progressString, -1, progressBar.getFont(),
getSelectionBackground(), new Rectangle(amountFull, y,
progressBar.getWidth() - amountFull, height));
SubstanceTextUtilities.paintText(g, this.progressBar,
renderRectangle, progressString, -1, progressBar.getFont(),
getSelectionForeground(), new Rectangle(fillStart, y,
amountFull, height));
} else { // VERTICAL
SubstanceTextUtilities.paintVerticalText(g, this.progressBar,
renderRectangle, progressString, -1, progressBar.getFont(),
getSelectionBackground(), new Rectangle(x, y, width,
progressBar.getHeight() - amountFull), progressBar
.getComponentOrientation().isLeftToRight());
SubstanceTextUtilities.paintVerticalText(g, this.progressBar,
renderRectangle, progressString, -1, progressBar.getFont(),
getSelectionForeground(), new Rectangle(x, fillStart,
width, amountFull), progressBar
.getComponentOrientation().isLeftToRight());
}
}
/**
* Returns the rectangle for the progress bar string.
*
* @param progressString
* Progress bar string.
* @param x
* x location of bounding box
* @param y
* y location of bounding box
* @param width
* width of bounding box
* @param height
* height of bounding box
* @return The rectangle for the progress bar string.
*/
protected Rectangle getStringRectangle(String progressString, int x, int y,
int width, int height) {
FontMetrics fontSizer = progressBar.getFontMetrics(progressBar
.getFont());
int stringWidth = fontSizer.stringWidth(progressString);
if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
return new Rectangle(x + Math.round(width / 2 - stringWidth / 2), y
+ (height - fontSizer.getHeight()) / 2, stringWidth,
fontSizer.getHeight());
} else {
return new Rectangle(x + (width - fontSizer.getHeight()) / 2, y
+ Math.round(height / 2 - stringWidth / 2), fontSizer
.getHeight(), stringWidth);
}
}
@Override
public void update(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
RenderingUtils.installDesktopHints(g2d, c);
super.update(g2d, c);
g2d.dispose();
}
}