From 0a0949af663c57bdc5b9763a701fda3dcf26ff1d Mon Sep 17 00:00:00 2001 From: mkpaz Date: Mon, 12 Sep 2022 16:31:48 +0400 Subject: [PATCH] Expose ProgressBar looked-up color variables --- .../sampler/page/components/ProgressPage.java | 94 ++++++++++++++++++- .../atlantafx/sampler/theme/CSSFragment.java | 56 +++++++++++ styles/src/components/_progress.scss | 10 +- 3 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 sampler/src/main/java/atlantafx/sampler/theme/CSSFragment.java diff --git a/sampler/src/main/java/atlantafx/sampler/page/components/ProgressPage.java b/sampler/src/main/java/atlantafx/sampler/page/components/ProgressPage.java index 28fa6a6..481e9ac 100644 --- a/sampler/src/main/java/atlantafx/sampler/page/components/ProgressPage.java +++ b/sampler/src/main/java/atlantafx/sampler/page/components/ProgressPage.java @@ -4,11 +4,17 @@ package atlantafx.sampler.page.components; import atlantafx.base.theme.Styles; import atlantafx.sampler.page.AbstractPage; import atlantafx.sampler.page.SampleBlock; +import atlantafx.sampler.theme.CSSFragment; +import javafx.concurrent.Task; +import javafx.css.PseudoClass; import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; import javafx.scene.control.ProgressBar; import javafx.scene.control.ProgressIndicator; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; @@ -31,7 +37,8 @@ public class ProgressPage extends AbstractPage { userContent.getChildren().addAll( basicBarSamples().getRoot(), basicIndicatorSamples().getRoot(), - barSizeSamples().getRoot() + barSizeSamples().getRoot(), + colorChangeSample().getRoot() ); } @@ -73,6 +80,91 @@ public class ProgressPage extends AbstractPage { return new SampleBlock("Size", container); } + private SampleBlock colorChangeSample() { + var stateSuccess = PseudoClass.getPseudoClass("state-success"); + var stateDanger = PseudoClass.getPseudoClass("state-danger"); + var width = 400; + + var bar = new ProgressBar(0); + bar.getStyleClass().add(Styles.LARGE); + bar.setPrefWidth(width); + bar.setMaxWidth(width); + + var barText = new Label(); + + var barStack = new StackPane(bar, barText); + barStack.getStyleClass().add("example"); + barStack.setPrefWidth(width); + barStack.setMaxWidth(width); + + var runBtn = new Button("Start"); + runBtn.disableProperty().bind(bar.progressProperty().greaterThan(0)); + + // ~ + + var content = new VBox(10); + content.getChildren().setAll(barStack, runBtn); + content.setAlignment(Pos.CENTER_LEFT); + + bar.progressProperty().addListener((obs, old, val) -> { + if (val == null) { return; } + + if (val.floatValue() > 0.80) { + barStack.pseudoClassStateChanged(stateDanger, true); + } else if (val.floatValue() > 0.47) { + barStack.pseudoClassStateChanged(stateSuccess, true); + } + }); + + new CSSFragment(""" + .example:state-success .progress-bar { + -color-progress-bar-fill: -color-success-emphasis; + } + .example:state-danger .progress-bar { + -color-progress-bar-fill: -color-danger-emphasis; + } + .example:state-success .label, + .example:state-danger .label { + -fx-text-fill: -color-fg-emphasis; + } + """).addTo(content); + + runBtn.setOnAction(e1 -> { + var task = new Task() { + @Override + protected Void call() throws Exception { + int steps = 1_000; + + for (int i = 0; i < steps; i++) { + Thread.sleep(10); + updateProgress(i, steps); + updateMessage(String.valueOf(i)); + } + return null; + } + }; + + // reset properties, so we can start a new task + task.setOnSucceeded(e2 -> { + bar.progressProperty().unbind(); + barText.textProperty().unbind(); + + bar.setProgress(0); + barText.setText(null); + + barStack.pseudoClassStateChanged(stateSuccess, false); + barStack.pseudoClassStateChanged(stateDanger, false); + }); + + bar.progressProperty().bind(task.progressProperty()); + barText.textProperty().bind(task.messageProperty()); + + new Thread(task).start(); + }); + + return new SampleBlock("Live color change", content); + } + private ProgressIndicator progressBar(double progress, boolean disabled, String... styleClasses) { var bar = new ProgressBar(progress); bar.getStyleClass().addAll(styleClasses); diff --git a/sampler/src/main/java/atlantafx/sampler/theme/CSSFragment.java b/sampler/src/main/java/atlantafx/sampler/theme/CSSFragment.java new file mode 100644 index 0000000..a5088e2 --- /dev/null +++ b/sampler/src/main/java/atlantafx/sampler/theme/CSSFragment.java @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: MIT */ +package atlantafx.sampler.theme; + +import javafx.scene.layout.Region; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Objects; + +public final class CSSFragment { + + private static final String DATA_URI_PREFIX = "data:base64,"; + + private final String css; + + public CSSFragment(String css) { + this.css = Objects.requireNonNull(css); + } + + public void addTo(Region region) { + Objects.requireNonNull(region); + region.getStylesheets().add(toDataURI()); + } + + public void removeFrom(Region region) { + Objects.requireNonNull(region); + region.getStyleClass().remove(toDataURI()); + } + + public boolean existsIn(Region region) { + Objects.requireNonNull(region); + return region.getStyleClass().contains(toDataURI()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CSSFragment cssFragment = (CSSFragment) o; + return css.equals(cssFragment.css); + } + + @Override + public int hashCode() { + return Objects.hash(css); + } + + @Override + public String toString() { + return css; + } + + public String toDataURI() { + return DATA_URI_PREFIX + new String(Base64.getEncoder().encode(css.getBytes()), StandardCharsets.UTF_8); + } +} diff --git a/styles/src/components/_progress.scss b/styles/src/components/_progress.scss index b729a40..a8f73cc 100755 --- a/styles/src/components/_progress.scss +++ b/styles/src/components/_progress.scss @@ -7,6 +7,9 @@ // ProgressBar // /////////////////////////////////////////////////////////////////////////////// +$progress-bar-track-color: -color-bg-subtle !default; +$progress-bar-fill-color: -color-accent-emphasis !default; + $size: ( "small": 2px, "medium": 0.4em, @@ -15,19 +18,22 @@ $size: ( .progress-bar { + -color-progress-bar-track: $progress-bar-track-color; + -color-progress-bar-fill: $progress-bar-fill-color; + -fx-indeterminate-bar-length: 60; -fx-indeterminate-bar-escape: true; -fx-indeterminate-bar-flip: true; -fx-indeterminate-bar-animation-time: 2; >.track { - -fx-background-color: -color-bg-subtle; + -fx-background-color: -color-progress-bar-track; -fx-background-insets: 0; -fx-background-radius: cfg.$border-radius; } >.bar { - -fx-background-color: -color-accent-emphasis; + -fx-background-color: -color-progress-bar-fill; -fx-background-insets: 0; -fx-background-radius: cfg.$border-radius; -fx-padding: map-get($size, "medium");