Implement changing color variables at runtime via contrast checker
This commit is contained in:
parent
aad6b06e12
commit
8479d9431f
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user