--- old/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ProgressBarSkin.java 2015-09-03 15:20:48.589409800 -0700 +++ /dev/null 2015-09-03 15:20:49.000000000 -0700 @@ -1,519 +0,0 @@ -/* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.javafx.scene.control.skin; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.animation.Transition; -import javafx.beans.InvalidationListener; -import javafx.beans.binding.When; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.value.WritableValue; -import javafx.css.CssMetaData; -import javafx.css.StyleableBooleanProperty; -import javafx.css.StyleableDoubleProperty; -import javafx.css.StyleableProperty; -import javafx.scene.Node; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.control.SkinBase; -import javafx.scene.layout.Background; -import javafx.scene.layout.BackgroundFill; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.scene.paint.Color; -import javafx.util.Duration; - -import com.sun.javafx.css.converters.BooleanConverter; -import com.sun.javafx.css.converters.SizeConverter; - -import javafx.css.Styleable; - - -public class ProgressBarSkin extends ProgressIndicatorSkin { - - /*************************************************************************** - * * - * CSS properties * - * * - **************************************************************************/ - - /** - * The length of the bouncing progress bar in indeterminate state - */ - private DoubleProperty indeterminateBarLength = null; - private DoubleProperty indeterminateBarLengthProperty() { - if (indeterminateBarLength == null) { - indeterminateBarLength = new StyleableDoubleProperty(60.0) { - - @Override - public Object getBean() { - return ProgressBarSkin.this; - } - - @Override - public String getName() { - return "indeterminateBarLength"; - } - - @Override - public CssMetaData getCssMetaData() { - return StyleableProperties.INDETERMINATE_BAR_LENGTH; - } - - }; - } - return indeterminateBarLength; - } - - private Double getIndeterminateBarLength() { - return indeterminateBarLength == null ? 60.0 : indeterminateBarLength.get(); - } - - /** - * If the progress bar should escape the ends of the progress bar region in indeterminate state - */ - private BooleanProperty indeterminateBarEscape = null; - private BooleanProperty indeterminateBarEscapeProperty() { - if (indeterminateBarEscape == null) { - indeterminateBarEscape = new StyleableBooleanProperty(true) { - - @Override - public Object getBean() { - return ProgressBarSkin.this; - } - - @Override - public String getName() { - return "indeterminateBarEscape"; - } - - @Override - public CssMetaData getCssMetaData() { - return StyleableProperties.INDETERMINATE_BAR_ESCAPE; - } - - - }; - } - return indeterminateBarEscape; - } - - private Boolean getIndeterminateBarEscape() { - return indeterminateBarEscape == null ? true : indeterminateBarEscape.get(); - } - - /** - * If the progress bar should flip when it gets to the ends in indeterminate state - */ - private BooleanProperty indeterminateBarFlip = null; - private BooleanProperty indeterminateBarFlipProperty() { - if (indeterminateBarFlip == null) { - indeterminateBarFlip = new StyleableBooleanProperty(true) { - - @Override - public Object getBean() { - return ProgressBarSkin.this; - } - - @Override - public String getName() { - return "indeterminateBarFlip"; - } - - @Override - public CssMetaData getCssMetaData() { - return StyleableProperties.INDETERMINATE_BAR_FLIP; - } - - }; - } - return indeterminateBarFlip; - } - - private Boolean getIndeterminateBarFlip() { - return indeterminateBarFlip == null ? true : indeterminateBarFlip.get(); - } - - /** - * How many seconds it should take for the indeterminate bar to go from - * one edge to the other - */ - private DoubleProperty indeterminateBarAnimationTime = null; - - private DoubleProperty indeterminateBarAnimationTimeProperty() { - if (indeterminateBarAnimationTime == null) { - indeterminateBarAnimationTime = new StyleableDoubleProperty(2.0) { - - @Override - public Object getBean() { - return ProgressBarSkin.this; - } - - @Override - public String getName() { - return "indeterminateBarAnimationTime"; - } - - @Override - public CssMetaData getCssMetaData() { - return StyleableProperties.INDETERMINATE_BAR_ANIMATION_TIME; - } - - - }; - } - return indeterminateBarAnimationTime; - } - - private double getIndeterminateBarAnimationTime() { - return indeterminateBarAnimationTime == null ? 2.0 : indeterminateBarAnimationTime.get(); - } - - - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - - private StackPane bar; - private StackPane track; - private Region clipRegion; - - // clean up progress so we never go out of bounds or update graphics more than twice per pixel - private double barWidth; - - - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - public ProgressBarSkin(ProgressBar control) { - super(control); - - barWidth = ((int) (control.getWidth() - snappedLeftInset() - snappedRightInset()) * 2 * Math.min(1, Math.max(0, control.getProgress()))) / 2.0F; - - InvalidationListener listener = valueModel -> { - updateProgress(); - }; - control.widthProperty().addListener(listener); - - initialize(); - getSkinnable().requestLayout(); - } - - - /*************************************************************************** - * * - * Implementation * - * * - **************************************************************************/ - - @Override protected void initialize() { - track = new StackPane(); - track.getStyleClass().setAll("track"); - - bar = new StackPane(); - bar.getStyleClass().setAll("bar"); - - getChildren().setAll(track, bar); - - // create a region to use as the clip for skin for animated indeterminate state - clipRegion = new Region(); - - // listen to the backgrounds on the bar and apply them to the clip but making them solid black for 100% - // solid anywhere the bar draws - bar.backgroundProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null && !newValue.getFills().isEmpty()) { - final BackgroundFill[] fills = new BackgroundFill[newValue.getFills().size()]; - for (int i = 0; i < newValue.getFills().size(); i++) { - BackgroundFill bf = newValue.getFills().get(i); - fills[i] = new BackgroundFill(Color.BLACK,bf.getRadii(),bf.getInsets()); - } - clipRegion.setBackground(new Background(fills)); - } - }); - } - - @Override - protected void createIndeterminateTimeline() { - if (indeterminateTransition != null) indeterminateTransition.stop(); - - ProgressIndicator control = getSkinnable(); - final double w = control.getWidth() - (snappedLeftInset() + snappedRightInset()); - final double startX = getIndeterminateBarEscape() ? -getIndeterminateBarLength() : 0; - final double endX = getIndeterminateBarEscape() ? w : w - getIndeterminateBarLength(); - - // Set up the timeline. We do not want to reverse if we are not flipping. - indeterminateTransition = new IndeterminateTransition(startX, endX, this); - indeterminateTransition.setCycleCount(Timeline.INDEFINITE); - - clipRegion.translateXProperty().bind(new When(bar.scaleXProperty().isEqualTo(-1.0, 1e-100)). - then(bar.translateXProperty().subtract(w).add(indeterminateBarLengthProperty())). - otherwise(bar.translateXProperty().negate())); - } - - boolean wasIndeterminate = false; - - @Override - protected void updateProgress() { - ProgressIndicator control = getSkinnable(); - // RT-33789: if the ProgressBar was indeterminate and still is indeterminate, don't update the bar width - final boolean isIndeterminate = control.isIndeterminate(); - if (!(isIndeterminate && wasIndeterminate)) { - barWidth = ((int) (control.getWidth() - snappedLeftInset() - snappedRightInset()) * 2 * Math.min(1, Math.max(0, control.getProgress()))) / 2.0F; - getSkinnable().requestLayout(); - } - wasIndeterminate = isIndeterminate; - } - - - /*************************************************************************** - * * - * Layout * - * * - **************************************************************************/ - - @Override - public double computeBaselineOffset(double topInset, double rightInset, double bottomInset, double leftInset) { - return Node.BASELINE_OFFSET_SAME_AS_HEIGHT; - } - - @Override - protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return Math.max(100, leftInset + bar.prefWidth(getSkinnable().getWidth()) + rightInset); - } - - @Override - protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return topInset + bar.prefHeight(width) + bottomInset; - } - - @Override - protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefWidth(height); - } - - @Override - protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefHeight(width); - } - - @Override - protected void layoutChildren(final double x, final double y, - final double w, final double h) { - - final ProgressIndicator control = getSkinnable(); - boolean isIndeterminate = control.isIndeterminate(); - - // resize clip - clipRegion.resizeRelocate(0, 0, w, h); - - track.resizeRelocate(x, y, w, h); - bar.resizeRelocate(x, y, isIndeterminate ? getIndeterminateBarLength() : barWidth, h); - - // things should be invisible only when well below minimum length - track.setVisible(true); - - // width might have changed so recreate our animation if needed - if (isIndeterminate) { - createIndeterminateTimeline(); - if (getSkinnable().impl_isTreeVisible()) { - indeterminateTransition.play(); - } - - // apply clip - bar.setClip(clipRegion); - } else if (indeterminateTransition != null) { - indeterminateTransition.stop(); - indeterminateTransition = null; - - // remove clip - bar.setClip(null); - bar.setScaleX(1); - bar.setTranslateX(0); - clipRegion.translateXProperty().unbind(); - } - } - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - /** - * Super-lazy instantiation pattern from Bill Pugh. - * - * @treatAsPrivate implementation detail - */ - private static class StyleableProperties { - private static final CssMetaData INDETERMINATE_BAR_LENGTH = - new CssMetaData("-fx-indeterminate-bar-length", - SizeConverter.getInstance(), 60.0) { - - @Override - public boolean isSettable(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return skin.indeterminateBarLength == null || - !skin.indeterminateBarLength.isBound(); - } - - @Override - public StyleableProperty getStyleableProperty(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return (StyleableProperty) (WritableValue) skin.indeterminateBarLengthProperty(); - } - }; - - private static final CssMetaData INDETERMINATE_BAR_ESCAPE = - new CssMetaData("-fx-indeterminate-bar-escape", - BooleanConverter.getInstance(), Boolean.TRUE) { - - @Override - public boolean isSettable(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return skin.indeterminateBarEscape == null || - !skin.indeterminateBarEscape.isBound(); - } - - @Override - public StyleableProperty getStyleableProperty(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return (StyleableProperty) (WritableValue) skin.indeterminateBarEscapeProperty(); - } - }; - - private static final CssMetaData INDETERMINATE_BAR_FLIP = - new CssMetaData("-fx-indeterminate-bar-flip", - BooleanConverter.getInstance(), Boolean.TRUE) { - - @Override - public boolean isSettable(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return skin.indeterminateBarFlip == null || - !skin.indeterminateBarFlip.isBound(); - } - - @Override - public StyleableProperty getStyleableProperty(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return (StyleableProperty) (WritableValue) skin.indeterminateBarFlipProperty(); - } - }; - - private static final CssMetaData INDETERMINATE_BAR_ANIMATION_TIME = - new CssMetaData("-fx-indeterminate-bar-animation-time", - SizeConverter.getInstance(), 2.0) { - - @Override - public boolean isSettable(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return skin.indeterminateBarAnimationTime == null || - !skin.indeterminateBarAnimationTime.isBound(); - } - - @Override - public StyleableProperty getStyleableProperty(ProgressBar n) { - final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); - return (StyleableProperty) (WritableValue) skin.indeterminateBarAnimationTimeProperty(); - } - }; - - private static final List> STYLEABLES; - - static { - final List> styleables = - new ArrayList>(SkinBase.getClassCssMetaData()); - styleables.add(INDETERMINATE_BAR_LENGTH); - styleables.add(INDETERMINATE_BAR_ESCAPE); - styleables.add(INDETERMINATE_BAR_FLIP); - styleables.add(INDETERMINATE_BAR_ANIMATION_TIME); - STYLEABLES = Collections.unmodifiableList(styleables); - } - } - - /** - * @return The CssMetaData associated with this class, which may include the - * CssMetaData of its super classes. - */ - public static List> getClassCssMetaData() { - return StyleableProperties.STYLEABLES; - } - - /** - * {@inheritDoc} - */ - @Override - public List> getCssMetaData() { - return getClassCssMetaData(); - } - - - private static class IndeterminateTransition extends Transition { - private final WeakReference skin; - private final double startX; - private final double endX; - private final boolean flip; - - public IndeterminateTransition(double startX, double endX, ProgressBarSkin progressBarSkin) { - this.startX = startX; - this.endX = endX; - this.skin = new WeakReference<>(progressBarSkin); - this.flip = progressBarSkin.getIndeterminateBarFlip(); - progressBarSkin.getIndeterminateBarEscape(); - setCycleDuration(Duration.seconds(progressBarSkin.getIndeterminateBarAnimationTime() * (flip ? 2 : 1))); - } - - @Override - protected void interpolate(double frac) { - ProgressBarSkin s = skin.get(); - if (s == null) { - stop(); - } else { - if (frac <= 0.5 || !flip) { - s.bar.setScaleX(-1); - s.bar.setTranslateX(startX + (flip ? 2 : 1) * frac * (endX - startX)); - } else { - s.bar.setScaleX(1); - s.bar.setTranslateX(startX + 2 * (1 - frac) * (endX - startX)); - } - } - } - } -} --- /dev/null 2015-09-03 15:20:49.000000000 -0700 +++ new/modules/controls/src/main/java/javafx/scene/control/skin/ProgressBarSkin.java 2015-09-03 15:20:47.895370100 -0700 @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.scene.control.skin; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javafx.animation.Timeline; +import javafx.animation.Transition; +import javafx.beans.binding.When; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.value.WritableValue; +import javafx.css.CssMetaData; +import javafx.css.StyleableBooleanProperty; +import javafx.css.StyleableDoubleProperty; +import javafx.css.StyleableProperty; +import javafx.scene.Node; +import javafx.scene.control.Control; +import javafx.scene.control.ProgressBar; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.control.SkinBase; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.util.Duration; + +import javafx.css.converter.BooleanConverter; +import javafx.css.converter.SizeConverter; + +import javafx.css.Styleable; + +/** + * Default skin implementation for the {@link ProgressBar} control. + * + * @see ProgressBar + * @since 9 + */ +public class ProgressBarSkin extends ProgressIndicatorSkin { + + /*************************************************************************** + * * + * Private fields * + * * + **************************************************************************/ + + private StackPane bar; + private StackPane track; + private Region clipRegion; + + // clean up progress so we never go out of bounds or update graphics more than twice per pixel + private double barWidth; + + + + /*************************************************************************** + * * + * Constructors * + * * + **************************************************************************/ + + /** + * Creates a new ProgressBarSkin instance, installing the necessary child + * nodes into the Control {@link Control#getChildren() children} list, as + * well as the necessary {@link Node#getInputMap() input mappings} for + * handling key, mouse, etc events. + * + * @param control The control that this skin should be installed onto. + */ + public ProgressBarSkin(ProgressBar control) { + super(control); + + barWidth = ((int) (control.getWidth() - snappedLeftInset() - snappedRightInset()) * 2 * Math.min(1, Math.max(0, control.getProgress()))) / 2.0F; + + control.widthProperty().addListener(observable -> updateProgress()); + + initialize(); + getSkinnable().requestLayout(); + } + + + + /*************************************************************************** + * * + * Properties * + * * + **************************************************************************/ + + /** + * The length of the bouncing progress bar in indeterminate state + */ + private DoubleProperty indeterminateBarLength = null; + private DoubleProperty indeterminateBarLengthProperty() { + if (indeterminateBarLength == null) { + indeterminateBarLength = new StyleableDoubleProperty(60.0) { + + @Override + public Object getBean() { + return ProgressBarSkin.this; + } + + @Override + public String getName() { + return "indeterminateBarLength"; + } + + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.INDETERMINATE_BAR_LENGTH; + } + + }; + } + return indeterminateBarLength; + } + + private Double getIndeterminateBarLength() { + return indeterminateBarLength == null ? 60.0 : indeterminateBarLength.get(); + } + + /** + * If the progress bar should escape the ends of the progress bar region in indeterminate state + */ + private BooleanProperty indeterminateBarEscape = null; + private BooleanProperty indeterminateBarEscapeProperty() { + if (indeterminateBarEscape == null) { + indeterminateBarEscape = new StyleableBooleanProperty(true) { + + @Override + public Object getBean() { + return ProgressBarSkin.this; + } + + @Override + public String getName() { + return "indeterminateBarEscape"; + } + + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.INDETERMINATE_BAR_ESCAPE; + } + + + }; + } + return indeterminateBarEscape; + } + + private Boolean getIndeterminateBarEscape() { + return indeterminateBarEscape == null ? true : indeterminateBarEscape.get(); + } + + /** + * If the progress bar should flip when it gets to the ends in indeterminate state + */ + private BooleanProperty indeterminateBarFlip = null; + private BooleanProperty indeterminateBarFlipProperty() { + if (indeterminateBarFlip == null) { + indeterminateBarFlip = new StyleableBooleanProperty(true) { + + @Override + public Object getBean() { + return ProgressBarSkin.this; + } + + @Override + public String getName() { + return "indeterminateBarFlip"; + } + + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.INDETERMINATE_BAR_FLIP; + } + + }; + } + return indeterminateBarFlip; + } + + private Boolean getIndeterminateBarFlip() { + return indeterminateBarFlip == null ? true : indeterminateBarFlip.get(); + } + + /** + * How many seconds it should take for the indeterminate bar to go from + * one edge to the other + */ + private DoubleProperty indeterminateBarAnimationTime = null; + + private DoubleProperty indeterminateBarAnimationTimeProperty() { + if (indeterminateBarAnimationTime == null) { + indeterminateBarAnimationTime = new StyleableDoubleProperty(2.0) { + + @Override + public Object getBean() { + return ProgressBarSkin.this; + } + + @Override + public String getName() { + return "indeterminateBarAnimationTime"; + } + + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.INDETERMINATE_BAR_ANIMATION_TIME; + } + + + }; + } + return indeterminateBarAnimationTime; + } + + private double getIndeterminateBarAnimationTime() { + return indeterminateBarAnimationTime == null ? 2.0 : indeterminateBarAnimationTime.get(); + } + + + + /*************************************************************************** + * * + * Public API * + * * + **************************************************************************/ + + /** {@inheritDoc} */ + @Override public double computeBaselineOffset(double topInset, double rightInset, double bottomInset, double leftInset) { + return Node.BASELINE_OFFSET_SAME_AS_HEIGHT; + } + + /** {@inheritDoc} */ + @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { + return Math.max(100, leftInset + bar.prefWidth(getSkinnable().getWidth()) + rightInset); + } + + /** {@inheritDoc} */ + @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return topInset + bar.prefHeight(width) + bottomInset; + } + + /** {@inheritDoc} */ + @Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { + return getSkinnable().prefWidth(height); + } + + /** {@inheritDoc} */ + @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return getSkinnable().prefHeight(width); + } + + /** {@inheritDoc} */ + @Override protected void layoutChildren(final double x, final double y, + final double w, final double h) { + + final ProgressIndicator control = getSkinnable(); + boolean isIndeterminate = control.isIndeterminate(); + + // resize clip + clipRegion.resizeRelocate(0, 0, w, h); + + track.resizeRelocate(x, y, w, h); + bar.resizeRelocate(x, y, isIndeterminate ? getIndeterminateBarLength() : barWidth, h); + + // things should be invisible only when well below minimum length + track.setVisible(true); + + // width might have changed so recreate our animation if needed + if (isIndeterminate) { + createIndeterminateTimeline(); + if (getSkinnable().impl_isTreeVisible()) { + indeterminateTransition.play(); + } + + // apply clip + bar.setClip(clipRegion); + } else if (indeterminateTransition != null) { + indeterminateTransition.stop(); + indeterminateTransition = null; + + // remove clip + bar.setClip(null); + bar.setScaleX(1); + bar.setTranslateX(0); + clipRegion.translateXProperty().unbind(); + } + } + + + + /*************************************************************************** + * * + * Private implementation * + * * + **************************************************************************/ + + /** {@inheritDoc} */ + @Override void initialize() { + track = new StackPane(); + track.getStyleClass().setAll("track"); + + bar = new StackPane(); + bar.getStyleClass().setAll("bar"); + + getChildren().setAll(track, bar); + + // create a region to use as the clip for skin for animated indeterminate state + clipRegion = new Region(); + + // listen to the backgrounds on the bar and apply them to the clip but making them solid black for 100% + // solid anywhere the bar draws + bar.backgroundProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null && !newValue.getFills().isEmpty()) { + final BackgroundFill[] fills = new BackgroundFill[newValue.getFills().size()]; + for (int i = 0; i < newValue.getFills().size(); i++) { + BackgroundFill bf = newValue.getFills().get(i); + fills[i] = new BackgroundFill(Color.BLACK,bf.getRadii(),bf.getInsets()); + } + clipRegion.setBackground(new Background(fills)); + } + }); + } + + /** {@inheritDoc} */ + @Override void createIndeterminateTimeline() { + if (indeterminateTransition != null) indeterminateTransition.stop(); + + ProgressIndicator control = getSkinnable(); + final double w = control.getWidth() - (snappedLeftInset() + snappedRightInset()); + final double startX = getIndeterminateBarEscape() ? -getIndeterminateBarLength() : 0; + final double endX = getIndeterminateBarEscape() ? w : w - getIndeterminateBarLength(); + + // Set up the timeline. We do not want to reverse if we are not flipping. + indeterminateTransition = new IndeterminateTransition(startX, endX, this); + indeterminateTransition.setCycleCount(Timeline.INDEFINITE); + + clipRegion.translateXProperty().bind(new When(bar.scaleXProperty().isEqualTo(-1.0, 1e-100)). + then(bar.translateXProperty().subtract(w).add(indeterminateBarLengthProperty())). + otherwise(bar.translateXProperty().negate())); + } + + boolean wasIndeterminate = false; + + /** {@inheritDoc} */ + @Override void updateProgress() { + ProgressIndicator control = getSkinnable(); + // RT-33789: if the ProgressBar was indeterminate and still is indeterminate, don't update the bar width + final boolean isIndeterminate = control.isIndeterminate(); + if (!(isIndeterminate && wasIndeterminate)) { + barWidth = ((int) (control.getWidth() - snappedLeftInset() - snappedRightInset()) * 2 * Math.min(1, Math.max(0, control.getProgress()))) / 2.0F; + getSkinnable().requestLayout(); + } + wasIndeterminate = isIndeterminate; + } + + + + /*************************************************************************** + * * + * Stylesheet Handling * + * * + **************************************************************************/ + + /** + * Super-lazy instantiation pattern from Bill Pugh. + * + * @treatAsPrivate implementation detail + */ + private static class StyleableProperties { + private static final CssMetaData INDETERMINATE_BAR_LENGTH = + new CssMetaData("-fx-indeterminate-bar-length", + SizeConverter.getInstance(), 60.0) { + + @Override + public boolean isSettable(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return skin.indeterminateBarLength == null || + !skin.indeterminateBarLength.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return (StyleableProperty) (WritableValue) skin.indeterminateBarLengthProperty(); + } + }; + + private static final CssMetaData INDETERMINATE_BAR_ESCAPE = + new CssMetaData("-fx-indeterminate-bar-escape", + BooleanConverter.getInstance(), Boolean.TRUE) { + + @Override + public boolean isSettable(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return skin.indeterminateBarEscape == null || + !skin.indeterminateBarEscape.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return (StyleableProperty) (WritableValue) skin.indeterminateBarEscapeProperty(); + } + }; + + private static final CssMetaData INDETERMINATE_BAR_FLIP = + new CssMetaData("-fx-indeterminate-bar-flip", + BooleanConverter.getInstance(), Boolean.TRUE) { + + @Override + public boolean isSettable(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return skin.indeterminateBarFlip == null || + !skin.indeterminateBarFlip.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return (StyleableProperty) (WritableValue) skin.indeterminateBarFlipProperty(); + } + }; + + private static final CssMetaData INDETERMINATE_BAR_ANIMATION_TIME = + new CssMetaData("-fx-indeterminate-bar-animation-time", + SizeConverter.getInstance(), 2.0) { + + @Override + public boolean isSettable(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return skin.indeterminateBarAnimationTime == null || + !skin.indeterminateBarAnimationTime.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ProgressBar n) { + final ProgressBarSkin skin = (ProgressBarSkin) n.getSkin(); + return (StyleableProperty) (WritableValue) skin.indeterminateBarAnimationTimeProperty(); + } + }; + + private static final List> STYLEABLES; + + static { + final List> styleables = + new ArrayList>(SkinBase.getClassCssMetaData()); + styleables.add(INDETERMINATE_BAR_LENGTH); + styleables.add(INDETERMINATE_BAR_ESCAPE); + styleables.add(INDETERMINATE_BAR_FLIP); + styleables.add(INDETERMINATE_BAR_ANIMATION_TIME); + STYLEABLES = Collections.unmodifiableList(styleables); + } + } + + /** + * Returns the CssMetaData associated with this class, which may include the + * CssMetaData of its super classes. + */ + public static List> getClassCssMetaData() { + return StyleableProperties.STYLEABLES; + } + + /** + * {@inheritDoc} + */ + @Override public List> getCssMetaData() { + return getClassCssMetaData(); + } + + + + /*************************************************************************** + * * + * Support classes * + * * + **************************************************************************/ + + private static class IndeterminateTransition extends Transition { + private final WeakReference skin; + private final double startX; + private final double endX; + private final boolean flip; + + public IndeterminateTransition(double startX, double endX, ProgressBarSkin progressBarSkin) { + this.startX = startX; + this.endX = endX; + this.skin = new WeakReference<>(progressBarSkin); + this.flip = progressBarSkin.getIndeterminateBarFlip(); + progressBarSkin.getIndeterminateBarEscape(); + setCycleDuration(Duration.seconds(progressBarSkin.getIndeterminateBarAnimationTime() * (flip ? 2 : 1))); + } + + @Override + protected void interpolate(double frac) { + ProgressBarSkin s = skin.get(); + if (s == null) { + stop(); + } else { + if (frac <= 0.5 || !flip) { + s.bar.setScaleX(-1); + s.bar.setTranslateX(startX + (flip ? 2 : 1) * frac * (endX - startX)); + } else { + s.bar.setScaleX(1); + s.bar.setTranslateX(startX + 2 * (1 - frac) * (endX - startX)); + } + } + } + } +}