Add RingProgressIndicator control
This commit is contained in:
parent
2716cca2a0
commit
1c4c6a5232
85
base/src/main/java/atlantafx/base/controls/RingProgressIndicator.java
Executable file
85
base/src/main/java/atlantafx/base/controls/RingProgressIndicator.java
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
package atlantafx.base.controls;
|
||||||
|
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
|
import javafx.beans.property.ReadOnlyBooleanWrapper;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ProgressIndicator;
|
||||||
|
import javafx.scene.control.Skin;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
|
|
||||||
|
public class RingProgressIndicator extends ProgressIndicator {
|
||||||
|
|
||||||
|
public RingProgressIndicator() { }
|
||||||
|
|
||||||
|
public RingProgressIndicator(double progress) {
|
||||||
|
this(progress, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RingProgressIndicator(double progress, boolean reverse) {
|
||||||
|
super(progress);
|
||||||
|
this.reverse.set(reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Skin<?> createDefaultSkin() {
|
||||||
|
return new RingProgressIndicatorSkin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Properties //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
protected final ObjectProperty<Node> graphic = new SimpleObjectProperty<>(this, "graphic", null);
|
||||||
|
|
||||||
|
public Node getGraphic() {
|
||||||
|
return graphicProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGraphic(Node graphic) {
|
||||||
|
graphicProperty().set(graphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any node to be displayed within the progress indicator. If null,
|
||||||
|
* it will fall back to the Label with integer progress value from 1 to 100.
|
||||||
|
*/
|
||||||
|
public ObjectProperty<Node> graphicProperty() {
|
||||||
|
return graphic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~
|
||||||
|
|
||||||
|
protected final ObjectProperty<StringConverter<Double>> stringConverter = new SimpleObjectProperty<>(this, "converter", null);
|
||||||
|
|
||||||
|
public StringConverter<Double> getStringConverter() {
|
||||||
|
return stringConverterProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStringConverter(StringConverter<Double> stringConverter) {
|
||||||
|
this.stringConverterProperty().set(stringConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Optional converter to transform progress value to string. */
|
||||||
|
public ObjectProperty<StringConverter<Double>> stringConverterProperty() {
|
||||||
|
return stringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~
|
||||||
|
|
||||||
|
private final ReadOnlyBooleanWrapper reverse = new ReadOnlyBooleanWrapper(this, "reverse", false);
|
||||||
|
|
||||||
|
public boolean isReverse() {
|
||||||
|
return reverse.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse progress indicator scale. For indeterminate variant
|
||||||
|
* this means it will be rotated counterclockwise.
|
||||||
|
*/
|
||||||
|
public ReadOnlyBooleanProperty reverseProperty() {
|
||||||
|
return reverse.getReadOnlyProperty();
|
||||||
|
}
|
||||||
|
}
|
261
base/src/main/java/atlantafx/base/controls/RingProgressIndicatorSkin.java
Executable file
261
base/src/main/java/atlantafx/base/controls/RingProgressIndicatorSkin.java
Executable file
@ -0,0 +1,261 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
package atlantafx.base.controls;
|
||||||
|
|
||||||
|
import javafx.animation.Animation;
|
||||||
|
import javafx.animation.Interpolator;
|
||||||
|
import javafx.animation.RotateTransition;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.value.WritableValue;
|
||||||
|
import javafx.css.CssMetaData;
|
||||||
|
import javafx.css.Styleable;
|
||||||
|
import javafx.css.StyleableDoubleProperty;
|
||||||
|
import javafx.css.StyleableProperty;
|
||||||
|
import javafx.css.converter.SizeConverter;
|
||||||
|
import javafx.scene.CacheHint;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.SkinBase;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Arc;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RingProgressIndicatorSkin extends SkinBase<RingProgressIndicator> {
|
||||||
|
|
||||||
|
protected static final double DEFAULT_ANIMATION_TIME = 3;
|
||||||
|
|
||||||
|
protected final StackPane container = new StackPane();
|
||||||
|
protected final Circle trackCircle = new Circle();
|
||||||
|
protected final Arc progressArc = new Arc();
|
||||||
|
protected final Label progressLabel = new Label();
|
||||||
|
protected final RotateTransition transition = new RotateTransition(
|
||||||
|
Duration.seconds(DEFAULT_ANIMATION_TIME), progressArc
|
||||||
|
);
|
||||||
|
|
||||||
|
public RingProgressIndicatorSkin(RingProgressIndicator indicator) {
|
||||||
|
super(indicator);
|
||||||
|
|
||||||
|
trackCircle.getStyleClass().add("track");
|
||||||
|
trackCircle.setManaged(false);
|
||||||
|
trackCircle.setFill(Color.TRANSPARENT);
|
||||||
|
|
||||||
|
progressArc.getStyleClass().add("ring");
|
||||||
|
progressArc.setManaged(false);
|
||||||
|
progressArc.setStartAngle(90);
|
||||||
|
progressArc.setLength(calcProgressArcLength());
|
||||||
|
progressArc.setCache(true);
|
||||||
|
progressArc.setCacheHint(CacheHint.ROTATE);
|
||||||
|
progressArc.setFill(Color.TRANSPARENT);
|
||||||
|
|
||||||
|
transition.setAutoReverse(false);
|
||||||
|
transition.setByAngle(-getMaxAngle());
|
||||||
|
transition.setCycleCount(Animation.INDEFINITE);
|
||||||
|
transition.setDelay(Duration.ZERO);
|
||||||
|
transition.setInterpolator(Interpolator.LINEAR);
|
||||||
|
|
||||||
|
progressLabel.getStyleClass().add("progress");
|
||||||
|
|
||||||
|
container.getStyleClass().addAll("container");
|
||||||
|
container.setMaxHeight(Region.USE_PREF_SIZE);
|
||||||
|
container.setMaxWidth(Region.USE_PREF_SIZE);
|
||||||
|
container.getChildren().addAll(trackCircle, progressArc);
|
||||||
|
container.getChildren().add(indicator.getGraphic() != null ? indicator.getGraphic() : progressLabel);
|
||||||
|
|
||||||
|
indicator.getStyleClass().add("ring-progress-indicator");
|
||||||
|
indicator.setMaxHeight(Region.USE_PREF_SIZE);
|
||||||
|
indicator.setMaxWidth(Region.USE_PREF_SIZE);
|
||||||
|
getChildren().add(container);
|
||||||
|
|
||||||
|
// == INIT LISTENERS ==
|
||||||
|
|
||||||
|
updateProgressLabel();
|
||||||
|
toggleIndeterminate();
|
||||||
|
|
||||||
|
registerChangeListener(indicator.progressProperty(), e -> {
|
||||||
|
updateProgressLabel();
|
||||||
|
progressArc.setLength(calcProgressArcLength());
|
||||||
|
});
|
||||||
|
|
||||||
|
registerChangeListener(indicator.indeterminateProperty(), e -> toggleIndeterminate());
|
||||||
|
|
||||||
|
registerChangeListener(indicator.visibleProperty(), e -> {
|
||||||
|
if (indicator.isVisible() && indicator.isIndeterminate()) {
|
||||||
|
transition.play();
|
||||||
|
} else {
|
||||||
|
transition.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerChangeListener(indeterminateAnimationTimeProperty(), e -> {
|
||||||
|
transition.setDuration(Duration.seconds(getIndeterminateAnimationTime()));
|
||||||
|
if (indicator.isIndeterminate()) {
|
||||||
|
transition.playFromStart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerChangeListener(indicator.graphicProperty(), e -> {
|
||||||
|
if (indicator.getGraphic() != null) {
|
||||||
|
container.getChildren().remove(progressLabel);
|
||||||
|
container.getChildren().add(indicator.getGraphic());
|
||||||
|
} else {
|
||||||
|
if (container.getChildren().size() > 1) {
|
||||||
|
container.getChildren().remove(1);
|
||||||
|
container.getChildren().add(progressLabel);
|
||||||
|
updateProgressLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMaxAngle() {
|
||||||
|
return getSkinnable().isReverse() ? 360 : -360;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calcProgressArcLength() {
|
||||||
|
var progress = getSkinnable().getProgress();
|
||||||
|
return getSkinnable().isReverse() ? (1 - progress) * getMaxAngle() : progress * getMaxAngle();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateProgressLabel() {
|
||||||
|
var progress = getSkinnable().getProgress();
|
||||||
|
|
||||||
|
if (getSkinnable().getStringConverter() != null) {
|
||||||
|
progressLabel.setText(getSkinnable().getStringConverter().toString(progress));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress >= 0) {
|
||||||
|
progressLabel.setText((int) Math.ceil(progress * 100) + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void toggleIndeterminate() {
|
||||||
|
var indeterminate = getSkinnable().isIndeterminate();
|
||||||
|
progressLabel.setManaged(!indeterminate);
|
||||||
|
|
||||||
|
if (indeterminate) {
|
||||||
|
if (getSkinnable().isVisible()) {
|
||||||
|
transition.play();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
progressArc.setRotate(0);
|
||||||
|
transition.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void layoutChildren(double x, double y, double w, double h) {
|
||||||
|
var size = Math.max(w, h);
|
||||||
|
var radius = (size / 2) - (progressArc.getStrokeWidth() / 2);
|
||||||
|
|
||||||
|
trackCircle.setCenterX(size / 2);
|
||||||
|
trackCircle.setCenterY(size / 2);
|
||||||
|
trackCircle.setRadius(radius);
|
||||||
|
|
||||||
|
progressArc.setCenterX(size / 2);
|
||||||
|
progressArc.setCenterY(size / 2);
|
||||||
|
progressArc.setRadiusX(radius);
|
||||||
|
progressArc.setRadiusY(radius);
|
||||||
|
|
||||||
|
container.resizeRelocate(x, y, size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control height is always equal to its width.
|
||||||
|
@Override
|
||||||
|
protected double computeMinHeight(double width, double topInset, double rightInset,
|
||||||
|
double bottomInset, double leftInset) {
|
||||||
|
return super.computeMinWidth(0, topInset, rightInset, bottomInset, leftInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double computePrefHeight(double width, double topInset, double rightInset,
|
||||||
|
double bottomInset, double leftInset) {
|
||||||
|
return super.computePrefWidth(0, topInset, rightInset, bottomInset, leftInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double computeMaxHeight(double width, double topInset, double rightInset,
|
||||||
|
double bottomInset, double leftInset) {
|
||||||
|
return super.computeMaxWidth(0, topInset, rightInset, bottomInset, leftInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
transition.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
|
||||||
|
return getClassCssMetaData();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Styleable Properties //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
protected DoubleProperty indeterminateAnimationTime = null;
|
||||||
|
|
||||||
|
private DoubleProperty indeterminateAnimationTimeProperty() {
|
||||||
|
if (indeterminateAnimationTime == null) {
|
||||||
|
indeterminateAnimationTime = new StyleableDoubleProperty(DEFAULT_ANIMATION_TIME) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBean() {
|
||||||
|
return RingProgressIndicatorSkin.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "indeterminateAnimationTime";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CssMetaData<RingProgressIndicator, Number> getCssMetaData() {
|
||||||
|
return StyleableProperties.INDETERMINATE_ANIMATION_TIME;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return indeterminateAnimationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getIndeterminateAnimationTime() {
|
||||||
|
return indeterminateAnimationTime == null ? DEFAULT_ANIMATION_TIME : indeterminateAnimationTime.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StyleableProperties {
|
||||||
|
|
||||||
|
private static final CssMetaData<RingProgressIndicator, Number> INDETERMINATE_ANIMATION_TIME =
|
||||||
|
new CssMetaData<>("-fx-indeterminate-animation-time", SizeConverter.getInstance(), DEFAULT_ANIMATION_TIME) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSettable(RingProgressIndicator n) {
|
||||||
|
return n.getSkin() instanceof RingProgressIndicatorSkin s &&
|
||||||
|
(s.indeterminateAnimationTime == null || !s.indeterminateAnimationTime.isBound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("RedundantCast")
|
||||||
|
public StyleableProperty<Number> getStyleableProperty(RingProgressIndicator n) {
|
||||||
|
final RingProgressIndicatorSkin skin = (RingProgressIndicatorSkin) n.getSkin();
|
||||||
|
return (StyleableProperty<Number>) (WritableValue<Number>) skin.indeterminateAnimationTimeProperty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(SkinBase.getClassCssMetaData());
|
||||||
|
styleables.add(INDETERMINATE_ANIMATION_TIME);
|
||||||
|
STYLEABLES = Collections.unmodifiableList(styleables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
|
||||||
|
return RingProgressIndicatorSkin.StyleableProperties.STYLEABLES;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: MIT */
|
/* SPDX-License-Identifier: MIT */
|
||||||
package atlantafx.sampler.page.components;
|
package atlantafx.sampler.page.components;
|
||||||
|
|
||||||
|
import atlantafx.base.controls.RingProgressIndicator;
|
||||||
import atlantafx.sampler.page.AbstractPage;
|
import atlantafx.sampler.page.AbstractPage;
|
||||||
import atlantafx.sampler.page.Page;
|
import atlantafx.sampler.page.Page;
|
||||||
import atlantafx.sampler.page.SampleBlock;
|
import atlantafx.sampler.page.SampleBlock;
|
||||||
@ -12,11 +13,11 @@ import javafx.scene.control.Button;
|
|||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ProgressBar;
|
import javafx.scene.control.ProgressBar;
|
||||||
import javafx.scene.control.ProgressIndicator;
|
import javafx.scene.control.ProgressIndicator;
|
||||||
import javafx.scene.layout.FlowPane;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.layout.HBox;
|
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
|
import org.kordamp.ikonli.feather.Feather;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import static atlantafx.base.theme.Styles.*;
|
import static atlantafx.base.theme.Styles.*;
|
||||||
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
|
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
|
||||||
@ -33,50 +34,111 @@ public class ProgressPage extends AbstractPage {
|
|||||||
|
|
||||||
public ProgressPage() {
|
public ProgressPage() {
|
||||||
super();
|
super();
|
||||||
setUserContent(new VBox(Page.PAGE_VGAP,
|
|
||||||
expandingHBox(basicBarSample(), basicIndicatorSample()),
|
var grid = new GridPane();
|
||||||
expandingHBox(barSizeSample(), colorChangeSample())
|
grid.setHgap(Page.PAGE_HGAP);
|
||||||
));
|
grid.setVgap(Page.PAGE_VGAP);
|
||||||
|
|
||||||
|
grid.add(basicBarSample(), 0, 0);
|
||||||
|
grid.add(basicIndicatorSample(), 1, 0);
|
||||||
|
|
||||||
|
grid.add(ringIndicatorSample(), 0, 1);
|
||||||
|
grid.add(barSizeSample(), 1, 1);
|
||||||
|
|
||||||
|
grid.add(colorChangeSample(), 0, 2);
|
||||||
|
|
||||||
|
setUserContent(grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SampleBlock basicBarSample() {
|
private SampleBlock basicBarSample() {
|
||||||
var flowPane = new FlowPane(
|
var flowPane = new FlowPane(BLOCK_HGAP, BLOCK_VGAP, createBar(0, false), createBar(0.5, false), createBar(1, false), createBar(0.5, true));
|
||||||
BLOCK_HGAP, BLOCK_VGAP,
|
|
||||||
createBar(0, false),
|
|
||||||
createBar(0.5, false),
|
|
||||||
createBar(1, false),
|
|
||||||
createBar(0.5, true)
|
|
||||||
);
|
|
||||||
flowPane.setAlignment(Pos.CENTER_LEFT);
|
flowPane.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
|
||||||
return new SampleBlock("Progress Bar", flowPane);
|
return new SampleBlock("Progress Bar", flowPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SampleBlock basicIndicatorSample() {
|
private SampleBlock basicIndicatorSample() {
|
||||||
var flowPane = new FlowPane(
|
var flowPane = new FlowPane(BLOCK_HGAP, BLOCK_VGAP, createIndicator(0, false), createIndicator(0.5, false), createIndicator(1, false), createIndicator(0.5, true));
|
||||||
BLOCK_HGAP, BLOCK_VGAP,
|
|
||||||
createIndicator(0, false),
|
|
||||||
createIndicator(0.5, false),
|
|
||||||
createIndicator(1, false),
|
|
||||||
createIndicator(0.5, true)
|
|
||||||
);
|
|
||||||
flowPane.setAlignment(Pos.TOP_LEFT);
|
flowPane.setAlignment(Pos.TOP_LEFT);
|
||||||
|
|
||||||
return new SampleBlock("Progress Indicator", flowPane);
|
return new SampleBlock("Progress Indicator", flowPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SampleBlock barSizeSample() {
|
private SampleBlock barSizeSample() {
|
||||||
var container = new VBox(
|
var container = new VBox(BLOCK_VGAP, new HBox(20, createBar(0.5, false, SMALL), new Text("small")), new HBox(20, createBar(0.5, false, MEDIUM), new Text("medium")), new HBox(20, createBar(0.5, false, LARGE), new Text("large")));
|
||||||
BLOCK_VGAP,
|
|
||||||
new HBox(20, createBar(0.5, false, SMALL), new Text("small")),
|
|
||||||
new HBox(20, createBar(0.5, false, MEDIUM), new Text("medium")),
|
|
||||||
new HBox(20, createBar(0.5, false, LARGE), new Text("large"))
|
|
||||||
);
|
|
||||||
container.getChildren().forEach(c -> ((HBox) c).setAlignment(Pos.CENTER_LEFT));
|
container.getChildren().forEach(c -> ((HBox) c).setAlignment(Pos.CENTER_LEFT));
|
||||||
|
|
||||||
return new SampleBlock("Size", container);
|
return new SampleBlock("Size", container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SampleBlock ringIndicatorSample() {
|
||||||
|
var basicIndicator = new RingProgressIndicator(0, false);
|
||||||
|
|
||||||
|
var customTextIndicator = new RingProgressIndicator(0.5, false);
|
||||||
|
customTextIndicator.setPrefSize(75, 75);
|
||||||
|
customTextIndicator.setStringConverter(new StringConverter<>() {
|
||||||
|
@Override
|
||||||
|
public String toString(Double progress) {
|
||||||
|
return (int) Math.ceil(progress * 100) + "°";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double fromString(String progress) {
|
||||||
|
return 0d;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var reverseIndicator = new RingProgressIndicator(0.25, true);
|
||||||
|
reverseIndicator.setPrefSize(150, 150);
|
||||||
|
|
||||||
|
var reverseIndicatorLabel = new Label("25%");
|
||||||
|
reverseIndicatorLabel.getStyleClass().add(TITLE_4);
|
||||||
|
|
||||||
|
var reversePlayButton = new Button("", new FontIcon(Feather.PLAY));
|
||||||
|
reversePlayButton.getStyleClass().addAll(BUTTON_CIRCLE, FLAT);
|
||||||
|
reversePlayButton.disableProperty().bind(reverseIndicator.progressProperty().greaterThan(0.25));
|
||||||
|
reversePlayButton.setOnAction(e1 -> {
|
||||||
|
var task = new Task<Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void call() throws Exception {
|
||||||
|
int steps = 100;
|
||||||
|
|
||||||
|
for (int i = 25; i <= steps; i++) {
|
||||||
|
Thread.sleep(100);
|
||||||
|
updateProgress(i, steps);
|
||||||
|
updateMessage(i + "%");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// reset properties, so we can start a new task
|
||||||
|
task.setOnSucceeded(e2 -> {
|
||||||
|
reverseIndicator.progressProperty().unbind();
|
||||||
|
reverseIndicatorLabel.textProperty().unbind();
|
||||||
|
|
||||||
|
reverseIndicator.setProgress(0.25);
|
||||||
|
reverseIndicatorLabel.setText("25%");
|
||||||
|
});
|
||||||
|
|
||||||
|
reverseIndicator.progressProperty().bind(task.progressProperty());
|
||||||
|
reverseIndicatorLabel.textProperty().bind(task.messageProperty());
|
||||||
|
|
||||||
|
new Thread(task).start();
|
||||||
|
});
|
||||||
|
|
||||||
|
var reverseBox = new VBox(10, reverseIndicatorLabel, reversePlayButton);
|
||||||
|
reverseBox.setAlignment(Pos.CENTER);
|
||||||
|
reverseIndicator.setGraphic(reverseBox);
|
||||||
|
|
||||||
|
// ~
|
||||||
|
|
||||||
|
var box = new HBox(BLOCK_HGAP, basicIndicator, customTextIndicator, reverseIndicator);
|
||||||
|
box.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
|
||||||
|
return new SampleBlock("Ring Indicator", box);
|
||||||
|
}
|
||||||
|
|
||||||
private SampleBlock colorChangeSample() {
|
private SampleBlock colorChangeSample() {
|
||||||
var stateSuccess = PseudoClass.getPseudoClass("state-success");
|
var stateSuccess = PseudoClass.getPseudoClass("state-success");
|
||||||
var stateDanger = PseudoClass.getPseudoClass("state-danger");
|
var stateDanger = PseudoClass.getPseudoClass("state-danger");
|
||||||
@ -124,8 +186,7 @@ public class ProgressPage extends AbstractPage {
|
|||||||
.example:state-danger .label {
|
.example:state-danger .label {
|
||||||
-fx-text-fill: -color-fg-emphasis;
|
-fx-text-fill: -color-fg-emphasis;
|
||||||
}
|
}
|
||||||
"""
|
""").addTo(content);
|
||||||
).addTo(content);
|
|
||||||
|
|
||||||
runBtn.setOnAction(e1 -> {
|
runBtn.setOnAction(e1 -> {
|
||||||
var task = new Task<Void>() {
|
var task = new Task<Void>() {
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
$color-bar-track: -color-bg-subtle !default;
|
$color-bar-track: -color-bg-subtle !default;
|
||||||
$color-bar-fill: -color-accent-emphasis !default;
|
$color-bar-fill: -color-accent-emphasis !default;
|
||||||
|
|
||||||
|
$color-ring-indicator-track: -color-bg-subtle !default;
|
||||||
|
$color-ring-indicator-fill: -color-accent-emphasis !default;
|
||||||
|
|
||||||
$size: (
|
$size: (
|
||||||
"small": 2px,
|
"small": 2px,
|
||||||
"medium": 0.4em,
|
"medium": 0.4em,
|
||||||
@ -163,3 +166,40 @@ $size: (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ring-progress-indicator {
|
||||||
|
-fx-indeterminate-animation-time: 3;
|
||||||
|
-color-progress-indicator-track: $color-ring-indicator-track;
|
||||||
|
-color-progress-indicator-fill: $color-ring-indicator-fill;
|
||||||
|
|
||||||
|
>.container {
|
||||||
|
// for extra small/large indicators you should also change the stroke width
|
||||||
|
-fx-min-width: 4em;
|
||||||
|
|
||||||
|
>.track {
|
||||||
|
-fx-stroke: -color-progress-indicator-track;
|
||||||
|
-fx-stroke-width: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>.ring {
|
||||||
|
-fx-stroke: -color-progress-indicator-fill;
|
||||||
|
-fx-stroke-width: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:indeterminate {
|
||||||
|
>.container {
|
||||||
|
// for extra small/large indicators you should also change the stroke width
|
||||||
|
-fx-min-width: 1.5em;
|
||||||
|
|
||||||
|
>.track {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
>.ring {
|
||||||
|
-fx-stroke: linear-gradient(-color-bg-default, -color-progress-indicator-fill);
|
||||||
|
-fx-stroke-width: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user