diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ColorContrastChecker.java b/sampler/src/main/java/atlantafx/sampler/page/general/ColorContrastChecker.java index d92cfc0..9c7cb25 100644 --- a/sampler/src/main/java/atlantafx/sampler/page/general/ColorContrastChecker.java +++ b/sampler/src/main/java/atlantafx/sampler/page/general/ColorContrastChecker.java @@ -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); diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java b/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java index efc4155..b05e0c4 100755 --- a/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java +++ b/sampler/src/main/java/atlantafx/sampler/page/general/ThemePage.java @@ -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)); } }); diff --git a/sampler/src/main/java/atlantafx/sampler/page/general/TypographyPage.java b/sampler/src/main/java/atlantafx/sampler/page/general/TypographyPage.java index 9fdced0..6576175 100755 --- a/sampler/src/main/java/atlantafx/sampler/page/general/TypographyPage.java +++ b/sampler/src/main/java/atlantafx/sampler/page/general/TypographyPage.java @@ -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)); } }); diff --git a/sampler/src/main/java/atlantafx/sampler/theme/ThemeEvent.java b/sampler/src/main/java/atlantafx/sampler/theme/ThemeEvent.java new file mode 100644 index 0000000..578313b --- /dev/null +++ b/sampler/src/main/java/atlantafx/sampler/theme/ThemeEvent.java @@ -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 + } +} diff --git a/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java b/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java index fd95e48..97de790 100644 --- a/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java +++ b/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java @@ -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> eventListeners = new ArrayList<>(); public Scene getScene() { return scene; } + public void addEventListener(Consumer 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 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 Set merge(T first, T... arr) { var set = new LinkedHashSet(); diff --git a/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java b/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java index 18c5820..88aa470 100644 --- a/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java +++ b/sampler/src/main/java/atlantafx/sampler/util/JColorUtils.java @@ -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(); } @@ -897,4 +899,4 @@ public class JColorUtils { fgColor.getBlue(), }; } -} \ No newline at end of file +}