From 5f81fc2c5b1b87c175b3a24ea7d5737132c4cd9c Mon Sep 17 00:00:00 2001 From: mkpaz Date: Sat, 27 May 2023 12:28:47 +0400 Subject: [PATCH] Compile themes to BSS format Every built-in theme is now available in both CSS and BSS formats. --- base/pom.xml | 21 +++++ .../atlantafx/base/theme/CupertinoDark.java | 9 ++ .../atlantafx/base/theme/CupertinoLight.java | 8 ++ .../java/atlantafx/base/theme/Dracula.java | 8 ++ .../java/atlantafx/base/theme/NordDark.java | 8 ++ .../java/atlantafx/base/theme/NordLight.java | 8 ++ .../java/atlantafx/base/theme/PrimerDark.java | 8 ++ .../atlantafx/base/theme/PrimerLight.java | 8 ++ .../main/java/atlantafx/base/theme/Theme.java | 14 +++ .../atlantafx/base/theme/ThemeCompiler.java | 85 +++++++++++++++++++ .../atlantafx/sampler/theme/SamplerTheme.java | 6 ++ 11 files changed, 183 insertions(+) create mode 100644 base/src/main/java/atlantafx/base/theme/ThemeCompiler.java diff --git a/base/pom.xml b/base/pom.xml index a246360..ee845ad 100755 --- a/base/pom.xml +++ b/base/pom.xml @@ -58,6 +58,27 @@ + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + + compile-to-bss + compile + + java + + + atlantafx.base.theme.ThemeCompiler + + ${project.build.directory}/classes/atlantafx/base/theme + + + + + diff --git a/base/src/main/java/atlantafx/base/theme/CupertinoDark.java b/base/src/main/java/atlantafx/base/theme/CupertinoDark.java index b1ac54f..64fe63e 100644 --- a/base/src/main/java/atlantafx/base/theme/CupertinoDark.java +++ b/base/src/main/java/atlantafx/base/theme/CupertinoDark.java @@ -3,6 +3,7 @@ package atlantafx.base.theme; import atlantafx.base.Preview; +import org.jetbrains.annotations.Nullable; /** * A theme based on IOS color palette. @@ -30,6 +31,14 @@ public class CupertinoDark implements Theme { return "/atlantafx/base/theme/cupertino-dark.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/cupertino-dark.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/CupertinoLight.java b/base/src/main/java/atlantafx/base/theme/CupertinoLight.java index 65c2170..f0e9d11 100644 --- a/base/src/main/java/atlantafx/base/theme/CupertinoLight.java +++ b/base/src/main/java/atlantafx/base/theme/CupertinoLight.java @@ -30,6 +30,14 @@ public class CupertinoLight implements Theme { return "/atlantafx/base/theme/cupertino-light.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/cupertino-light.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/Dracula.java b/base/src/main/java/atlantafx/base/theme/Dracula.java index 9757e5c..4aaae42 100644 --- a/base/src/main/java/atlantafx/base/theme/Dracula.java +++ b/base/src/main/java/atlantafx/base/theme/Dracula.java @@ -30,6 +30,14 @@ public class Dracula implements Theme { return "/atlantafx/base/theme/dracula.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/dracula.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/NordDark.java b/base/src/main/java/atlantafx/base/theme/NordDark.java index 6e62be4..102805a 100755 --- a/base/src/main/java/atlantafx/base/theme/NordDark.java +++ b/base/src/main/java/atlantafx/base/theme/NordDark.java @@ -27,6 +27,14 @@ public final class NordDark implements Theme { return "/atlantafx/base/theme/nord-dark.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/nord-dark.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/NordLight.java b/base/src/main/java/atlantafx/base/theme/NordLight.java index 598a546..2175120 100755 --- a/base/src/main/java/atlantafx/base/theme/NordLight.java +++ b/base/src/main/java/atlantafx/base/theme/NordLight.java @@ -27,6 +27,14 @@ public final class NordLight implements Theme { return "/atlantafx/base/theme/nord-light.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/nord-light.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/PrimerDark.java b/base/src/main/java/atlantafx/base/theme/PrimerDark.java index 39e24fe..5051bfc 100755 --- a/base/src/main/java/atlantafx/base/theme/PrimerDark.java +++ b/base/src/main/java/atlantafx/base/theme/PrimerDark.java @@ -27,6 +27,14 @@ public final class PrimerDark implements Theme { return "/atlantafx/base/theme/primer-dark.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/primer-dark.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/PrimerLight.java b/base/src/main/java/atlantafx/base/theme/PrimerLight.java index a9319a6..9928806 100755 --- a/base/src/main/java/atlantafx/base/theme/PrimerLight.java +++ b/base/src/main/java/atlantafx/base/theme/PrimerLight.java @@ -27,6 +27,14 @@ public final class PrimerLight implements Theme { return "/atlantafx/base/theme/primer-light.css"; } + /** + * {@inheritDoc} + */ + @Override + public String getUserAgentStylesheetBSS() { + return "/atlantafx/base/theme/primer-light.bss"; + } + /** * {@inheritDoc} */ diff --git a/base/src/main/java/atlantafx/base/theme/Theme.java b/base/src/main/java/atlantafx/base/theme/Theme.java index 9794d50..99ee5df 100755 --- a/base/src/main/java/atlantafx/base/theme/Theme.java +++ b/base/src/main/java/atlantafx/base/theme/Theme.java @@ -6,6 +6,7 @@ import static javafx.application.Application.STYLESHEET_CASPIAN; import static javafx.application.Application.STYLESHEET_MODENA; import javafx.application.Application; +import org.jetbrains.annotations.Nullable; /** * Basic theme interface. @@ -23,6 +24,14 @@ public interface Theme { */ String getUserAgentStylesheet(); + /** + * Returns the path to the theme user-agent stylesheet in binary + * (BSS) format. See {@link Application#setUserAgentStylesheet(String)} for more info. + * All built-in themes are available in BSS format, but custom themes may not, + * hence the method may return null value. + */ + @Nullable String getUserAgentStylesheetBSS(); + /** * Signifies whether the theme uses a light font on a dark background * or vise versa. @@ -52,6 +61,11 @@ public interface Theme { return userAgentStylesheet; } + @Override + public @Nullable String getUserAgentStylesheetBSS() { + return null; + } + @Override public boolean isDarkMode() { return darkMode; diff --git a/base/src/main/java/atlantafx/base/theme/ThemeCompiler.java b/base/src/main/java/atlantafx/base/theme/ThemeCompiler.java new file mode 100644 index 0000000..4d30e02 --- /dev/null +++ b/base/src/main/java/atlantafx/base/theme/ThemeCompiler.java @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: MIT */ + +package atlantafx.base.theme; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.stream.Stream; +import javafx.css.Stylesheet; + +/** + * Lazy man CSS to BSS compiler wrapper. + */ +public class ThemeCompiler { + + public static void main(String[] args) { + try { + if (args.length < 1) { + throw new IllegalArgumentException("You must provide the source directory path"); + } + + if (args.length > 1) { + throw new IllegalArgumentException( + "Unexpected arguments were found: " + + Arrays.toString(Arrays.copyOfRange(args, 1, args.length)) + ); + } + + var dir = Paths.get(args[0]); + new ThemeCompiler().convertToBinary(dir); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * Converts all CSS files in the specified directory to BSS. + * + * @param dir the source directory to scan for CSS files + * @throws IOException to punish you for using Java + */ + public void convertToBinary(Path dir) throws IOException { + if (dir == null || !Files.exists(dir) || !Files.isDirectory(dir)) { + throw new IllegalArgumentException("Invalid directory: " + dir); + } + + try (Stream stream = Files.list(dir)) { + stream.filter(f -> f.toString().endsWith(".css")) + .forEach(f -> { + try { + convertToBinary(f, f.resolveSibling(getFilename(f) + ".bss")); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + } + + /** + * Converts the specified CSS file to BSS. If no output file is given, + * then the input file name is used with an extension of 'bss'. + * + * @param in input file path + * @param out output file path + * @throws IOException to punish you for using Java + */ + public void convertToBinary(Path in, Path out) throws IOException { + if (in == null || out == null) { + throw new IllegalArgumentException("Both input and output files must be specified."); + } + + if (in.equals(out)) { + throw new IllegalArgumentException("Input file and output file cannot be the same."); + } + + Stylesheet.convertToBinary(in.toFile(), out.toFile()); + } + + private String getFilename(Path f) { + String name = f.getFileName().toString(); + return name.substring(0, name.lastIndexOf('.')); + } +} diff --git a/sampler/src/main/java/atlantafx/sampler/theme/SamplerTheme.java b/sampler/src/main/java/atlantafx/sampler/theme/SamplerTheme.java index 544a0a6..62141d8 100644 --- a/sampler/src/main/java/atlantafx/sampler/theme/SamplerTheme.java +++ b/sampler/src/main/java/atlantafx/sampler/theme/SamplerTheme.java @@ -30,6 +30,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javafx.application.Application; import javafx.scene.Scene; +import org.jetbrains.annotations.Nullable; /** * The {@link Theme} decorator to work around some JavaFX CSS limitations. @@ -87,6 +88,11 @@ public final class SamplerTheme implements Theme { return IS_DEV_MODE ? DUMMY_STYLESHEET : getResource().toURI().toString(); } + @Override + public @Nullable String getUserAgentStylesheetBSS() { + return theme.getUserAgentStylesheetBSS(); + } + @Override public boolean isDarkMode() { return theme.isDarkMode();