Implement changing color variables at runtime via contrast checker

This commit is contained in:
mkpaz 2022-08-31 16:12:47 +04:00
parent aad6b06e12
commit 8479d9431f
6 changed files with 90 additions and 9 deletions

@ -3,6 +3,7 @@ package atlantafx.sampler.page.general;
import atlantafx.base.controls.CustomTextField;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.theme.ThemeManager;
import atlantafx.sampler.util.JColor;
import atlantafx.sampler.util.JColorUtils;
import javafx.beans.binding.Bindings;
@ -256,8 +257,8 @@ public class ColorContrastChecker extends GridPane {
// ~
var flattenButton = new Button("Flatten");
flattenButton.setOnAction(e -> {
var flattenBtn = new Button("Flatten");
flattenBtn.setOnAction(e -> {
double[] flatBg = flattenColor(bgBaseColor.get(), bgColor.getColor());
setBackground(Color.color(flatBg[0], flatBg[1], flatBg[2]));
@ -265,6 +266,17 @@ public class ColorContrastChecker extends GridPane {
setForeground(Color.color(flatFg[0], flatFg[1], flatFg[2]));
});
var applyBtn = new Button("Apply");
applyBtn.setOnAction(e -> {
var tm = ThemeManager.getInstance();
tm.setColor(getBgColorName(), bgColor.getColor());
tm.setColor(getFgColorName(), fgColor.getColor());
tm.reloadCustomCSS();
});
var controlsBox = new HBox(20, flattenBtn, applyBtn);
controlsBox.setAlignment(Pos.CENTER_LEFT);
// ~
getStyleClass().add("contrast-checker");
@ -283,7 +295,7 @@ public class ColorContrastChecker extends GridPane {
add(bgAlphaLabel, 0, 10);
add(bgAlphaSlider, 0, 11);
add(flattenButton, 0, 12);
add(controlsBox, 0, 12, REMAINING, 1);
// column 1
add(wsagBox, 1, 0);

@ -3,6 +3,7 @@ package atlantafx.sampler.page.general;
import atlantafx.base.theme.Theme;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.theme.ThemeEvent.EventType;
import atlantafx.sampler.theme.ThemeManager;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
@ -24,6 +25,12 @@ public class ThemePage extends AbstractPage {
public ThemePage() {
super();
createView();
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));
}
});
}
@Override
@ -37,6 +44,8 @@ public class ThemePage extends AbstractPage {
optionsGrid(),
colorPalette
);
// if you want to enable quick menu don't forget that
// theme selection choice box have to be updated accordingly
quickConfigBtn.setVisible(false);
quickConfigBtn.setManaged(false);
sourceCodeToggleBtn.setVisible(false);
@ -69,7 +78,6 @@ public class ThemePage extends AbstractPage {
var tm = ThemeManager.getInstance();
tm.setTheme(val);
tm.reloadCustomCSS();
colorPalette.updateColorInfo(Duration.ofSeconds(1));
}
});

@ -3,6 +3,7 @@ package atlantafx.sampler.page.general;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import atlantafx.sampler.theme.ThemeEvent.EventType;
import atlantafx.sampler.theme.ThemeManager;
import javafx.application.Platform;
import javafx.collections.FXCollections;
@ -41,6 +42,12 @@ public class TypographyPage extends AbstractPage {
public TypographyPage() {
super();
createView();
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));
}
});
}
private void createView() {
@ -65,6 +72,8 @@ public class TypographyPage extends AbstractPage {
textColorSample().getRoot(),
textFlowSample().getRoot()
);
// if you want to enable quick menu don't forget that
// font size spinner value have to be updated accordingly
quickConfigBtn.setVisible(false);
quickConfigBtn.setManaged(false);
sourceCodeToggleBtn.setVisible(false);
@ -84,7 +93,6 @@ public class TypographyPage extends AbstractPage {
if (val != null) {
tm.setFontFamily(DEFAULT_FONT_ID.equals(val) ? ThemeManager.DEFAULT_FONT_FAMILY_NAME : val);
tm.reloadCustomCSS();
updateFontInfo(Duration.ofMillis(1000));
}
});

@ -0,0 +1,11 @@
package atlantafx.sampler.theme;
public record ThemeEvent(EventType eventType) {
public enum EventType {
THEME_CHANGE,
FONT_FAMILY_CHANGE,
FONT_SIZE_CHANGE,
CUSTOM_CSS_CHANGE
}
}

@ -6,12 +6,16 @@ import atlantafx.base.theme.PrimerLight;
import atlantafx.base.theme.Theme;
import atlantafx.sampler.Launcher;
import atlantafx.sampler.Resources;
import atlantafx.sampler.theme.ThemeEvent.EventType;
import atlantafx.sampler.util.JColor;
import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import java.net.URI;
import java.util.*;
import java.util.function.Consumer;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -33,11 +37,16 @@ public final class ThemeManager {
private Theme currentTheme = null;
private String fontFamily = DEFAULT_FONT_FAMILY_NAME;
private int fontSize = DEFAULT_FONT_SIZE;
private final List<Consumer<ThemeEvent>> eventListeners = new ArrayList<>();
public Scene getScene() {
return scene;
}
public void addEventListener(Consumer<ThemeEvent> listener) {
eventListeners.add(Objects.requireNonNull(listener));
}
public void setScene(Scene scene) {
this.scene = scene;
}
@ -66,6 +75,7 @@ public final class ThemeManager {
theme.getStylesheets().forEach(uri -> scene.getStylesheets().add(uri.toString()));
currentTheme = theme;
notifyEventListeners(EventType.THEME_CHANGE);
}
public List<Theme> getAvailableThemes() {
@ -104,6 +114,7 @@ public final class ThemeManager {
Objects.requireNonNull(fontFamily);
setCustomDeclaration("-fx-font-family", "\"" + fontFamily + "\"");
this.fontFamily = fontFamily;
notifyEventListeners(EventType.FONT_FAMILY_CHANGE);
}
public boolean isDefaultFontFamily() {
@ -118,16 +129,38 @@ public final class ThemeManager {
setCustomDeclaration("-fx-font-size", fontSize + "px");
setCustomRule(".ikonli-font-icon", String.format("-fx-icon-size: %dpx;", fontSize + 2));
this.fontSize = fontSize;
notifyEventListeners(EventType.FONT_SIZE_CHANGE);
}
public void setColor(String colorName, Color color) {
Objects.requireNonNull(colorName);
Objects.requireNonNull(color);
setCustomDeclaration(colorName, JColor.color(
(float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity()).getColorHexWithAlpha()
);
}
public void resetColor(String colorName) {
Objects.requireNonNull(colorName);
removeCustomDeclaration(colorName);
}
private void setCustomDeclaration(String property, String value) {
customCSSDeclarations.put(property, value);
}
private void removeCustomDeclaration(String property) {
customCSSDeclarations.remove(property);
}
private void setCustomRule(String selector, String rule) {
customCSSRules.put(selector, rule);
}
private void removeCustomRule(String selector) {
customCSSRules.remove(selector);
}
public void reloadCustomCSS() {
Objects.requireNonNull(scene);
StringBuilder css = new StringBuilder();
@ -159,12 +192,14 @@ public final class ThemeManager {
"data:text/css;base64," + Base64.getEncoder().encodeToString(css.toString().getBytes(UTF_8))
);
scene.getRoot().pseudoClassStateChanged(USER_CUSTOM, true);
notifyEventListeners(EventType.CUSTOM_CSS_CHANGE);
}
public void resetCustomCSS() {
customCSSDeclarations.clear();
customCSSRules.clear();
scene.getRoot().pseudoClassStateChanged(USER_CUSTOM, false);
notifyEventListeners(EventType.CUSTOM_CSS_CHANGE);
}
public HighlightJSTheme getMatchingHighlightJSTheme(Theme theme) {
@ -174,6 +209,11 @@ public final class ThemeManager {
return theme.isDarkMode() ? HighlightJSTheme.githubDark() : HighlightJSTheme.githubLight();
}
public void notifyEventListeners(EventType eventType) {
var e = new ThemeEvent(eventType);
eventListeners.forEach(l -> l.accept(e));
}
@SafeVarargs
private <T> Set<T> merge(T first, T... arr) {
var set = new LinkedHashSet<T>();

@ -126,12 +126,14 @@ public class JColorUtils {
validateHexSingle(green);
validateHexSingle(blue);
StringBuilder color = new StringBuilder("#");
if (alpha != null) {
color.append(expandShorthandHexSingle(alpha));
}
color.append(expandShorthandHexSingle(red));
color.append(expandShorthandHexSingle(green));
color.append(expandShorthandHexSingle(blue));
// alpha must be at the end of the string
// not at the start, like it was originally
if (alpha != null) {
color.append(expandShorthandHexSingle(alpha));
}
return color.toString();
}