From c2e03d2193ba0a597147199b2c1edf6d6906661a Mon Sep 17 00:00:00 2001 From: mkpaz Date: Thu, 25 Aug 2022 16:03:55 +0400 Subject: [PATCH] Implement changing font family at runtime --- .../main/java/atlantafx/sampler/Launcher.java | 5 +- .../sampler/page/general/TypographyPage.java | 50 ++++++++++++++---- .../atlantafx/sampler/theme/ThemeManager.java | 26 +++++---- .../InterUI-Bold.otf => Inter-Bold.otf} | Bin .../InterUI-Italic.otf => Inter-Italic.otf} | Bin .../InterUI-Medium.otf => Inter-Medium.otf} | Bin .../InterUI-Regular.otf => Inter-Regular.otf} | Bin .../src/main/resources/assets/fonts/index.css | 30 ----------- .../main/resources/assets/styles/index.css | 7 ++- styles/src/general/_root.scss | 1 - 10 files changed, 63 insertions(+), 56 deletions(-) rename sampler/src/main/resources/assets/fonts/{Inter/InterUI-Bold.otf => Inter-Bold.otf} (100%) rename sampler/src/main/resources/assets/fonts/{Inter/InterUI-Italic.otf => Inter-Italic.otf} (100%) rename sampler/src/main/resources/assets/fonts/{Inter/InterUI-Medium.otf => Inter-Medium.otf} (100%) rename sampler/src/main/resources/assets/fonts/{Inter/InterUI-Regular.otf => Inter-Regular.otf} (100%) delete mode 100755 sampler/src/main/resources/assets/fonts/index.css diff --git a/sampler/src/main/java/atlantafx/sampler/Launcher.java b/sampler/src/main/java/atlantafx/sampler/Launcher.java index 07387a3..25dcddc 100755 --- a/sampler/src/main/java/atlantafx/sampler/Launcher.java +++ b/sampler/src/main/java/atlantafx/sampler/Launcher.java @@ -55,10 +55,7 @@ public class Launcher extends Application { tm.setTheme(tm.getAvailableThemes().get(0)); if (IS_DEV_MODE) { startCssFX(scene); } - scene.getStylesheets().addAll( - Resources.resolve("assets/fonts/index.css"), - Resources.resolve("assets/styles/index.css") - ); + scene.getStylesheets().addAll(Resources.resolve("assets/styles/index.css")); stage.setScene(scene); stage.setTitle(System.getProperty("app.name")); 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 44c1275..3eefd96 100755 --- a/sampler/src/main/java/atlantafx/sampler/page/general/TypographyPage.java +++ b/sampler/src/main/java/atlantafx/sampler/page/general/TypographyPage.java @@ -5,13 +5,16 @@ import atlantafx.sampler.page.AbstractPage; import atlantafx.sampler.page.SampleBlock; import atlantafx.sampler.theme.ThemeManager; import javafx.application.Platform; +import javafx.collections.FXCollections; import javafx.geometry.Pos; import javafx.scene.Node; +import javafx.scene.control.ComboBox; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.control.Spinner; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; +import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextFlow; @@ -23,6 +26,8 @@ import static atlantafx.base.theme.Styles.*; public class TypographyPage extends AbstractPage { + private static final double CONTROL_WIDTH = 200; + public static final String NAME = "Typography"; @Override @@ -36,18 +41,20 @@ public class TypographyPage extends AbstractPage { } private void createView() { - Spinner fontSizeSpinner = fontSizeSpinner(); - fontSizeSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL); - fontSizeSpinner.setPrefWidth(200); + var controlsGrid = new GridPane(); + controlsGrid.setVgap(10); + controlsGrid.setHgap(20); - var fontSizeBox = new HBox(20, new Label("Font size"), fontSizeSpinner); - fontSizeBox.setAlignment(Pos.CENTER_LEFT); + controlsGrid.add(new Label("Font family"), 0, 0); + controlsGrid.add(fontFamilyChooser(), 1, 0); + controlsGrid.add(new Label("Font size"), 0, 1); + controlsGrid.add(fontSizeSpinner(), 1, 1); var fontSizeSample = fontSizeSample(); fontSizeSampleContent = (GridPane) fontSizeSample.getContent(); userContent.getChildren().setAll( - fontSizeBox, + controlsGrid, fontSizeSample.getRoot(), fontWeightSample().getRoot(), fontStyleSample().getRoot(), @@ -57,19 +64,42 @@ public class TypographyPage extends AbstractPage { ); } + private ComboBox fontFamilyChooser() { + final var tm = ThemeManager.getInstance(); + + ComboBox comboBox = new ComboBox<>(); + comboBox.getItems().add(tm.getFontFamily()); + comboBox.getItems().addAll(FXCollections.observableArrayList(Font.getFamilies())); + comboBox.setPrefWidth(CONTROL_WIDTH); + comboBox.getSelectionModel().select(tm.getFontFamily()); + + comboBox.valueProperty().addListener((obs, old, val) -> { + if (val != null) { + tm.setFontFamily(val); + tm.reloadCustomCSS(); + updateFontInfo(Duration.ofMillis(1000)); + } + }); + + return comboBox; + } + private Spinner fontSizeSpinner() { - var spinner = new Spinner(10, 24, 14); + final var tm = ThemeManager.getInstance(); + + var spinner = new Spinner(10, 24, tm.getFontSize()); + spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL); + spinner.setPrefWidth(CONTROL_WIDTH); // Instead of this we should obtain font size from a rendered node. // But since it's not trivial (thanks to JavaFX doesn't expose relevant API) // we just keep current font size inside ThemeManager singleton. // It works fine if ThemeManager default font size value matches // default theme font size value. - spinner.getValueFactory().setValue(ThemeManager.getInstance().getFontSize()); + spinner.getValueFactory().setValue(tm.getFontSize()); spinner.valueProperty().addListener((obs, old, val) -> { - if (val != null && getScene() != null) { - var tm = ThemeManager.getInstance(); + if (val != null) { tm.setFontSize(val); tm.reloadCustomCSS(); updateFontInfo(Duration.ofMillis(1000)); diff --git a/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java b/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java index 81e61c9..947add1 100644 --- a/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java +++ b/sampler/src/main/java/atlantafx/sampler/theme/ThemeManager.java @@ -19,6 +19,7 @@ public final class ThemeManager { private static final String DUMMY_STYLESHEET = Resources.getResource("assets/styles/empty.css").toString(); private static final PseudoClass USER_CUSTOM = PseudoClass.getPseudoClass("user-custom"); + private static final String DEFAULT_FONT_FAMILY_NAME = "Application Default"; // KEY | VALUE // -fx-property | value; @@ -26,9 +27,10 @@ public final class ThemeManager { // .foo | -fx-property: value; private final Map customCSSRules = new LinkedHashMap<>(); - private Theme currentTheme = null; - private int currentFontSize = 14; private Scene scene; + private Theme currentTheme = null; + private String fontFamily = DEFAULT_FONT_FAMILY_NAME; + private int fontSize = 14; public Scene getScene() { return scene; @@ -66,10 +68,7 @@ public final class ThemeManager { public List getAvailableThemes() { var themes = new ArrayList(); - var appStylesheets = new URI[] { - URI.create(Resources.resolve("assets/fonts/index.css")), - URI.create(Resources.resolve("assets/styles/index.css")) - }; + var appStylesheets = new URI[] { URI.create(Resources.resolve("assets/styles/index.css")) }; if (Launcher.IS_DEV_MODE) { themes.add(new ExternalTheme("Primer Light", DUMMY_STYLESHEET, merge( @@ -95,14 +94,23 @@ public final class ThemeManager { return themes; } + public String getFontFamily() { + return fontFamily; + } + + public void setFontFamily(String fontFamily) { + setCustomDeclaration("-fx-font-family", "\"" + fontFamily + "\""); + this.fontFamily = fontFamily; + } + public int getFontSize() { - return currentFontSize; + return fontSize; } public void setFontSize(int fontSize) { setCustomDeclaration("-fx-font-size", fontSize + "px"); setCustomRule(".ikonli-font-icon", String.format("-fx-icon-size: %dpx;", fontSize + 2)); - currentFontSize = fontSize; + this.fontSize = fontSize; } private void setCustomDeclaration(String property, String value) { @@ -139,8 +147,6 @@ public final class ThemeManager { css.append("}\n"); }); - System.out.println(css); - scene.getStylesheets().removeIf(uri -> uri.startsWith("data:text/css")); scene.getStylesheets().add( "data:text/css;base64," + Base64.getEncoder().encodeToString(css.toString().getBytes(UTF_8)) diff --git a/sampler/src/main/resources/assets/fonts/Inter/InterUI-Bold.otf b/sampler/src/main/resources/assets/fonts/Inter-Bold.otf similarity index 100% rename from sampler/src/main/resources/assets/fonts/Inter/InterUI-Bold.otf rename to sampler/src/main/resources/assets/fonts/Inter-Bold.otf diff --git a/sampler/src/main/resources/assets/fonts/Inter/InterUI-Italic.otf b/sampler/src/main/resources/assets/fonts/Inter-Italic.otf similarity index 100% rename from sampler/src/main/resources/assets/fonts/Inter/InterUI-Italic.otf rename to sampler/src/main/resources/assets/fonts/Inter-Italic.otf diff --git a/sampler/src/main/resources/assets/fonts/Inter/InterUI-Medium.otf b/sampler/src/main/resources/assets/fonts/Inter-Medium.otf similarity index 100% rename from sampler/src/main/resources/assets/fonts/Inter/InterUI-Medium.otf rename to sampler/src/main/resources/assets/fonts/Inter-Medium.otf diff --git a/sampler/src/main/resources/assets/fonts/Inter/InterUI-Regular.otf b/sampler/src/main/resources/assets/fonts/Inter-Regular.otf similarity index 100% rename from sampler/src/main/resources/assets/fonts/Inter/InterUI-Regular.otf rename to sampler/src/main/resources/assets/fonts/Inter-Regular.otf diff --git a/sampler/src/main/resources/assets/fonts/index.css b/sampler/src/main/resources/assets/fonts/index.css deleted file mode 100755 index 5139784..0000000 --- a/sampler/src/main/resources/assets/fonts/index.css +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Note that each font-family have to be unique. That's because unlike web browsers - * OpenJFX CSS parser doesn't support `font-weight` and `font-style` attributes - * in the `@font-face` at-rule. It just silently ignores them. So, the font variant - * can only be expressed via font name. OpenJFX always uses font transformation, - * even when corresponding font variant provided explicitly. - * - * See, CSS Reference guide: - * https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/doc-files/cssref.html - * > Although the parser will parse the syntax, all @font‑face descriptors - * > are ignored except for the src descriptor. The src descriptor is expected - * > to be a . The format hint is ignored. - */ - -@font-face { - font-family: "Inter UI Regular"; - src: url('Inter/InterUI-Regular.otf'); -} -@font-face { - font-family: "Inter UI Medium"; - src: url('Inter/InterUI-Medium.otf'); -} -@font-face { - font-family: "Inter UI Bold"; - src: url('Inter/InterUI-Bold.otf'); -} -@font-face { - font-family: "Inter UI Italic"; - src: url('Inter/InterUI-Italic.otf'); -} diff --git a/sampler/src/main/resources/assets/styles/index.css b/sampler/src/main/resources/assets/styles/index.css index f12d970..6bcc56f 100755 --- a/sampler/src/main/resources/assets/styles/index.css +++ b/sampler/src/main/resources/assets/styles/index.css @@ -1,7 +1,12 @@ /** SPDX-License-Identifier: MIT */ +@font-face { + font-family: "Application Default"; + src: url('../fonts/Inter-Regular.otf'); +} + .root { - -fx-font-family: "Inter"; + -fx-font-family: "Application Default"; } .root:showcase-mode #sidebar, .root:showcase-mode .page > .header { diff --git a/styles/src/general/_root.scss b/styles/src/general/_root.scss index 6d76215..9561d82 100755 --- a/styles/src/general/_root.scss +++ b/styles/src/general/_root.scss @@ -72,7 +72,6 @@ // default props inherited by all nodes -fx-background-color: -color-bg-default; - -fx-font-family: "Inter"; -fx-font-size: cfg.$font-default; // these are needed for Popup