Add color scale preview
This commit is contained in:
parent
9b0b0bf44c
commit
fc19ca5a36
@ -139,6 +139,7 @@ public class QuickConfigMenu extends StackPane {
|
||||
() -> FONT_SCALE.indexOf(fontScale.get()) <= 0, fontScale)
|
||||
);
|
||||
|
||||
// FIXME: Default zoom value is always 100% which isn't correct because it may have been changed earlier
|
||||
var zoomLabel = new Label();
|
||||
zoomLabel.textProperty().bind(Bindings.createStringBinding(() -> fontScale.get() + "%", fontScale));
|
||||
|
||||
@ -149,7 +150,9 @@ public class QuickConfigMenu extends StackPane {
|
||||
final var tm = ThemeManager.getInstance();
|
||||
fontScale.addListener((obs, old, val) -> {
|
||||
if (val != null) {
|
||||
double fontSize = ThemeManager.DEFAULT_FONT_SIZE / 100.0 * val.intValue();
|
||||
double fontSize = val.intValue() != 100 ?
|
||||
ThemeManager.DEFAULT_FONT_SIZE / 100.0 * val.intValue() :
|
||||
ThemeManager.DEFAULT_FONT_SIZE;
|
||||
tm.setFontSize((int) Math.ceil(fontSize));
|
||||
tm.reloadCustomCSS();
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
package atlantafx.sampler.page.general;
|
||||
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import javafx.application.Platform;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.geometry.Pos;
|
||||
@ -12,18 +12,20 @@ import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class ColorPalette extends VBox {
|
||||
|
||||
private final List<ColorBlock> blocks = new ArrayList<>();
|
||||
private final List<ColorPaletteBlock> blocks = new ArrayList<>();
|
||||
private final ReadOnlyObjectWrapper<Color> bgBaseColor = new ReadOnlyObjectWrapper<>(Color.WHITE);
|
||||
private final Consumer<ColorBlock> colorBlockActionHandler;
|
||||
private final Consumer<ColorPaletteBlock> colorBlockActionHandler;
|
||||
|
||||
public ColorPalette(Consumer<ColorBlock> blockClickedHandler) {
|
||||
public ColorPalette(Consumer<ColorPaletteBlock> blockClickedHandler) {
|
||||
super();
|
||||
|
||||
this.colorBlockActionHandler = Objects.requireNonNull(blockClickedHandler);
|
||||
@ -35,7 +37,7 @@ class ColorPalette extends VBox {
|
||||
headerLabel.getStyleClass().add(Styles.TITLE_4);
|
||||
|
||||
var headerBox = new HBox();
|
||||
headerBox.getChildren().setAll(headerLabel, new Spacer());
|
||||
headerBox.getChildren().setAll(headerLabel);
|
||||
headerBox.setAlignment(Pos.CENTER_LEFT);
|
||||
headerBox.getStyleClass().add("header");
|
||||
|
||||
@ -85,8 +87,8 @@ class ColorPalette extends VBox {
|
||||
return grid;
|
||||
}
|
||||
|
||||
private ColorBlock colorBlock(String fgColor, String bgColor, String borderColor) {
|
||||
var block = new ColorBlock(fgColor, bgColor, borderColor, bgBaseColor.getReadOnlyProperty());
|
||||
private ColorPaletteBlock colorBlock(String fgColor, String bgColor, String borderColor) {
|
||||
var block = new ColorPaletteBlock(fgColor, bgColor, borderColor, bgBaseColor.getReadOnlyProperty());
|
||||
block.setOnAction(colorBlockActionHandler);
|
||||
blocks.add(block);
|
||||
return block;
|
||||
@ -96,12 +98,9 @@ class ColorPalette extends VBox {
|
||||
// Unfortunately, JavaFX doesn't provide an API to observe when stylesheet changes has been applied.
|
||||
// The timer is introduced to defer widget update to a time when scene changes supposedly will be finished.
|
||||
public void updateColorInfo(Duration delay) {
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Platform.runLater(() -> blocks.forEach(ColorBlock::update));
|
||||
}
|
||||
}, delay.toMillis());
|
||||
var t = new Timeline(new KeyFrame(delay));
|
||||
t.setOnFinished(e -> blocks.forEach(ColorPaletteBlock::update));
|
||||
t.play();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Color> bgBaseColorProperty() {
|
||||
|
@ -20,7 +20,7 @@ import static atlantafx.sampler.page.general.ContrastChecker.*;
|
||||
import static atlantafx.sampler.util.JColorUtils.flattenColor;
|
||||
import static atlantafx.sampler.util.JColorUtils.getColorLuminance;
|
||||
|
||||
class ColorBlock extends VBox {
|
||||
class ColorPaletteBlock extends VBox {
|
||||
|
||||
private final String fgColorName;
|
||||
private final String bgColorName;
|
||||
@ -33,9 +33,9 @@ class ColorBlock extends VBox {
|
||||
private final Label wsagLabel = new Label();
|
||||
private final FontIcon expandIcon = new FontIcon(Feather.MAXIMIZE_2);
|
||||
|
||||
private Consumer<ColorBlock> actionHandler;
|
||||
private Consumer<ColorPaletteBlock> actionHandler;
|
||||
|
||||
public ColorBlock(String fgColorName,
|
||||
public ColorPaletteBlock(String fgColorName,
|
||||
String bgColorName,
|
||||
String borderColorName,
|
||||
ReadOnlyObjectProperty<Color> bgBaseColor) {
|
||||
@ -150,7 +150,7 @@ class ColorBlock extends VBox {
|
||||
return borderColorName;
|
||||
}
|
||||
|
||||
public void setOnAction(Consumer<ColorBlock> actionHandler) {
|
||||
public void setOnAction(Consumer<ColorPaletteBlock> actionHandler) {
|
||||
this.actionHandler = actionHandler;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
package atlantafx.sampler.page.general;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ColorScale extends VBox {
|
||||
|
||||
private final ReadOnlyObjectWrapper<Color> bgBaseColor = new ReadOnlyObjectWrapper<>(Color.WHITE);
|
||||
private final List<ColorScaleBlock> blocks = Arrays.asList(
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-gray-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-blue-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-green-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-yellow-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-red-", 10),
|
||||
ColorScaleBlock.forColorName(bgBaseColor, "-color-black", "-color-white")
|
||||
);
|
||||
|
||||
public ColorScale() {
|
||||
super();
|
||||
createView();
|
||||
}
|
||||
|
||||
private void createView() {
|
||||
var headerLabel = new Label("Color Scale");
|
||||
headerLabel.getStyleClass().add(Styles.TITLE_4);
|
||||
|
||||
var headerBox = new HBox();
|
||||
headerBox.getChildren().setAll(headerLabel);
|
||||
headerBox.setAlignment(Pos.CENTER_LEFT);
|
||||
headerBox.getStyleClass().add("header");
|
||||
|
||||
backgroundProperty().addListener((obs, old, val) -> bgBaseColor.set(
|
||||
val != null && !val.getFills().isEmpty() ? (Color) val.getFills().get(0).getFill() : Color.WHITE
|
||||
));
|
||||
|
||||
setId("color-scale");
|
||||
getChildren().setAll(
|
||||
headerBox,
|
||||
colorTable()
|
||||
);
|
||||
}
|
||||
|
||||
public void updateColorInfo(Duration delay) {
|
||||
var t = new Timeline(new KeyFrame(delay));
|
||||
t.setOnFinished(e -> blocks.forEach(ColorScaleBlock::update));
|
||||
t.play();
|
||||
}
|
||||
|
||||
private FlowPane colorTable() {
|
||||
var root = new FlowPane(20, 20);
|
||||
root.getStyleClass().add("table");
|
||||
root.getChildren().setAll(blocks);
|
||||
return root;
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
package atlantafx.sampler.page.general;
|
||||
|
||||
import atlantafx.sampler.util.JColorUtils;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import static atlantafx.sampler.util.JColorUtils.flattenColor;
|
||||
import static atlantafx.sampler.util.JColorUtils.getColorLuminance;
|
||||
|
||||
public class ColorScaleBlock extends VBox {
|
||||
|
||||
private static final double BLOCK_WIDTH = 250;
|
||||
private static final double BLOCK_HEIGHT = 50;
|
||||
|
||||
private final ReadOnlyObjectProperty<Color> bgBaseColor;
|
||||
|
||||
private ColorScaleBlock(ReadOnlyObjectProperty<Color> bgBaseColor) {
|
||||
super();
|
||||
|
||||
this.bgBaseColor = bgBaseColor;
|
||||
createView();
|
||||
}
|
||||
|
||||
private void addCell(String colorName) {
|
||||
getChildren().add(label(colorName));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
getChildren().forEach(c -> {
|
||||
if (c instanceof Label label) {
|
||||
String colorName = (String) label.getUserData();
|
||||
label.setStyle(String.format("-fx-background-color:%s;-fx-text-fill:%s;",
|
||||
colorName,
|
||||
JColorUtils.toHexWithAlpha(getSafeFgColor(label))
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createView() {
|
||||
getStyleClass().add("column");
|
||||
}
|
||||
|
||||
private static Label label(String colorName) {
|
||||
var label = new Label(colorName);
|
||||
label.setMinHeight(BLOCK_HEIGHT);
|
||||
label.setMinWidth(BLOCK_WIDTH);
|
||||
label.setPrefWidth(BLOCK_WIDTH);
|
||||
label.setMaxWidth(BLOCK_WIDTH);
|
||||
label.setAlignment(Pos.CENTER_LEFT);
|
||||
label.getStyleClass().add("cell");
|
||||
label.setUserData(colorName);
|
||||
label.setStyle(String.format("-fx-background-color:%s;", colorName));
|
||||
return label;
|
||||
}
|
||||
|
||||
private Color getSafeFgColor(Label label) {
|
||||
var bg = getBgColor(label);
|
||||
// deliberately reduce luminance threshold from 0.55 to 0.4
|
||||
// to improve readability which is an experimental value anyway
|
||||
return getColorLuminance(flattenColor(bgBaseColor.get(), bg)) < 0.4 ? Color.WHITE : Color.BLACK;
|
||||
}
|
||||
|
||||
private Color getBgColor(Label label) {
|
||||
return label.getBackground() != null && !label.getBackground().isEmpty() ?
|
||||
(Color) label.getBackground().getFills().get(0).getFill() : Color.WHITE;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static ColorScaleBlock forColorPrefix(ReadOnlyObjectProperty<Color> bgBaseColor,
|
||||
String colorPrefix,
|
||||
int count) {
|
||||
var block = new ColorScaleBlock(bgBaseColor);
|
||||
for (int idx = 0; idx < count; idx++) {
|
||||
block.addCell(colorPrefix + idx);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
public static ColorScaleBlock forColorName(ReadOnlyObjectProperty<Color> bgBaseColor,
|
||||
String... colors) {
|
||||
var block = new ColorScaleBlock(bgBaseColor);
|
||||
for (String colorName : colors) {
|
||||
block.addCell(colorName);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ import org.kordamp.ikonli.material2.Material2AL;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static atlantafx.sampler.page.general.ColorBlock.validateColorName;
|
||||
import static atlantafx.sampler.page.general.ColorPaletteBlock.validateColorName;
|
||||
import static atlantafx.sampler.util.JColorUtils.flattenColor;
|
||||
import static atlantafx.sampler.util.JColorUtils.getColorLuminance;
|
||||
|
||||
|
@ -10,9 +10,9 @@ import javafx.geometry.HPos;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.util.Duration;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -20,7 +20,7 @@ public class ThemePage extends AbstractPage {
|
||||
|
||||
public static final String NAME = "Theme";
|
||||
|
||||
private final Consumer<ColorBlock> colorBlockActionHandler = colorBlock -> {
|
||||
private final Consumer<ColorPaletteBlock> colorBlockActionHandler = colorBlock -> {
|
||||
ContrastCheckerDialog dialog = getOrCreateContrastCheckerDialog();
|
||||
dialog.getContent().setValues(colorBlock.getFgColorName(),
|
||||
colorBlock.getFgColor(),
|
||||
@ -32,6 +32,7 @@ public class ThemePage extends AbstractPage {
|
||||
};
|
||||
|
||||
private final ColorPalette colorPalette = new ColorPalette(colorBlockActionHandler);
|
||||
private final ColorScale colorScale = new ColorScale();
|
||||
|
||||
private ContrastCheckerDialog contrastCheckerDialog;
|
||||
|
||||
@ -44,7 +45,8 @@ public class ThemePage extends AbstractPage {
|
||||
ThemeManager.getInstance().addEventListener(e -> {
|
||||
if (e.eventType() == EventType.THEME_CHANGE || e.eventType() == EventType.CUSTOM_CSS_CHANGE) {
|
||||
// only works for managed nodes
|
||||
colorPalette.updateColorInfo(Duration.ofSeconds(1));
|
||||
colorPalette.updateColorInfo(Duration.seconds(1));
|
||||
colorScale.updateColorInfo(Duration.seconds(1));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -53,12 +55,14 @@ public class ThemePage extends AbstractPage {
|
||||
protected void onRendered() {
|
||||
super.onRendered();
|
||||
colorPalette.updateColorInfo(Duration.ZERO);
|
||||
colorScale.updateColorInfo(Duration.ZERO);
|
||||
}
|
||||
|
||||
private void createView() {
|
||||
userContent.getChildren().addAll(
|
||||
optionsGrid(),
|
||||
colorPalette
|
||||
colorPalette,
|
||||
colorScale
|
||||
);
|
||||
// if you want to enable quick menu don't forget that
|
||||
// theme selection choice box have to be updated accordingly
|
||||
|
@ -6,7 +6,8 @@ import atlantafx.sampler.page.SampleBlock;
|
||||
import atlantafx.sampler.theme.ThemeEvent.EventType;
|
||||
import atlantafx.sampler.theme.ThemeManager;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import javafx.application.Platform;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
@ -21,10 +22,7 @@ import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextFlow;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import static atlantafx.base.theme.Styles.*;
|
||||
|
||||
@ -46,7 +44,7 @@ public class TypographyPage extends AbstractPage {
|
||||
ThemeManager.getInstance().addEventListener(e -> {
|
||||
if (e.eventType() == EventType.FONT_FAMILY_CHANGE || e.eventType() == EventType.FONT_SIZE_CHANGE) {
|
||||
// only works for managed nodes
|
||||
updateFontInfo(Duration.ofMillis(1000));
|
||||
updateFontInfo(Duration.seconds(1));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -116,7 +114,7 @@ public class TypographyPage extends AbstractPage {
|
||||
if (val != null) {
|
||||
tm.setFontSize(val);
|
||||
tm.reloadCustomCSS();
|
||||
updateFontInfo(Duration.ofMillis(1000));
|
||||
updateFontInfo(Duration.seconds(1));
|
||||
}
|
||||
});
|
||||
|
||||
@ -130,10 +128,8 @@ public class TypographyPage extends AbstractPage {
|
||||
}
|
||||
|
||||
private void updateFontInfo(Duration delay) {
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Platform.runLater(() -> {
|
||||
var t = new Timeline(new KeyFrame(delay));
|
||||
t.setOnFinished(e -> {
|
||||
for (Node node : fontSizeSampleContent.getChildren()) {
|
||||
if (node instanceof Text textNode) {
|
||||
var font = textNode.getFont();
|
||||
@ -143,8 +139,7 @@ public class TypographyPage extends AbstractPage {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, delay.toMillis());
|
||||
t.play();
|
||||
}
|
||||
|
||||
private SampleBlock fontSizeSample() {
|
||||
|
@ -1,3 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
.overlay {
|
||||
-fx-background-color: transparent;
|
||||
|
||||
|
@ -9,10 +9,6 @@ $color-wsag-fg: white;
|
||||
-fx-spacing: 20px;
|
||||
-fx-background-color: -color-bg-default; // mandatory base bg for flatten color calc
|
||||
|
||||
>.header {
|
||||
-fx-pref-height: 40px;
|
||||
}
|
||||
|
||||
>.grid {
|
||||
-fx-vgap: 20px;
|
||||
-fx-hgap: 40px;
|
||||
|
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#color-scale {
|
||||
-fx-spacing: 20px;
|
||||
-fx-background-color: -color-bg-default; // mandatory base bg for flatten color calc
|
||||
|
||||
|
||||
>.table {
|
||||
>.column {
|
||||
>.cell {
|
||||
-fx-text-fill: -color-fg-default;
|
||||
-fx-font-size: 1.1em;
|
||||
-fx-padding: 0 0 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
@use "color-palette" as palette;
|
||||
|
||||
.contrast-checker {
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@use "color-palette";
|
||||
@use "color-scale";
|
||||
@use "contrast-checker";
|
||||
@use "quick-config-menu";
|
Loading…
Reference in New Issue
Block a user