Implement changing font family at runtime
This commit is contained in:
parent
cd16046340
commit
c2e03d2193
@ -55,10 +55,7 @@ public class Launcher extends Application {
|
|||||||
tm.setTheme(tm.getAvailableThemes().get(0));
|
tm.setTheme(tm.getAvailableThemes().get(0));
|
||||||
if (IS_DEV_MODE) { startCssFX(scene); }
|
if (IS_DEV_MODE) { startCssFX(scene); }
|
||||||
|
|
||||||
scene.getStylesheets().addAll(
|
scene.getStylesheets().addAll(Resources.resolve("assets/styles/index.css"));
|
||||||
Resources.resolve("assets/fonts/index.css"),
|
|
||||||
Resources.resolve("assets/styles/index.css")
|
|
||||||
);
|
|
||||||
|
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.setTitle(System.getProperty("app.name"));
|
stage.setTitle(System.getProperty("app.name"));
|
||||||
|
@ -5,13 +5,16 @@ import atlantafx.sampler.page.AbstractPage;
|
|||||||
import atlantafx.sampler.page.SampleBlock;
|
import atlantafx.sampler.page.SampleBlock;
|
||||||
import atlantafx.sampler.theme.ThemeManager;
|
import atlantafx.sampler.theme.ThemeManager;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Hyperlink;
|
import javafx.scene.control.Hyperlink;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Spinner;
|
import javafx.scene.control.Spinner;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.text.Font;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.scene.text.TextFlow;
|
import javafx.scene.text.TextFlow;
|
||||||
|
|
||||||
@ -23,6 +26,8 @@ import static atlantafx.base.theme.Styles.*;
|
|||||||
|
|
||||||
public class TypographyPage extends AbstractPage {
|
public class TypographyPage extends AbstractPage {
|
||||||
|
|
||||||
|
private static final double CONTROL_WIDTH = 200;
|
||||||
|
|
||||||
public static final String NAME = "Typography";
|
public static final String NAME = "Typography";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -36,18 +41,20 @@ public class TypographyPage extends AbstractPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createView() {
|
private void createView() {
|
||||||
Spinner<Integer> fontSizeSpinner = fontSizeSpinner();
|
var controlsGrid = new GridPane();
|
||||||
fontSizeSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
|
controlsGrid.setVgap(10);
|
||||||
fontSizeSpinner.setPrefWidth(200);
|
controlsGrid.setHgap(20);
|
||||||
|
|
||||||
var fontSizeBox = new HBox(20, new Label("Font size"), fontSizeSpinner);
|
controlsGrid.add(new Label("Font family"), 0, 0);
|
||||||
fontSizeBox.setAlignment(Pos.CENTER_LEFT);
|
controlsGrid.add(fontFamilyChooser(), 1, 0);
|
||||||
|
controlsGrid.add(new Label("Font size"), 0, 1);
|
||||||
|
controlsGrid.add(fontSizeSpinner(), 1, 1);
|
||||||
|
|
||||||
var fontSizeSample = fontSizeSample();
|
var fontSizeSample = fontSizeSample();
|
||||||
fontSizeSampleContent = (GridPane) fontSizeSample.getContent();
|
fontSizeSampleContent = (GridPane) fontSizeSample.getContent();
|
||||||
|
|
||||||
userContent.getChildren().setAll(
|
userContent.getChildren().setAll(
|
||||||
fontSizeBox,
|
controlsGrid,
|
||||||
fontSizeSample.getRoot(),
|
fontSizeSample.getRoot(),
|
||||||
fontWeightSample().getRoot(),
|
fontWeightSample().getRoot(),
|
||||||
fontStyleSample().getRoot(),
|
fontStyleSample().getRoot(),
|
||||||
@ -57,19 +64,42 @@ public class TypographyPage extends AbstractPage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ComboBox<String> fontFamilyChooser() {
|
||||||
|
final var tm = ThemeManager.getInstance();
|
||||||
|
|
||||||
|
ComboBox<String> 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<Integer> fontSizeSpinner() {
|
private Spinner<Integer> fontSizeSpinner() {
|
||||||
var spinner = new Spinner<Integer>(10, 24, 14);
|
final var tm = ThemeManager.getInstance();
|
||||||
|
|
||||||
|
var spinner = new Spinner<Integer>(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.
|
// 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)
|
// But since it's not trivial (thanks to JavaFX doesn't expose relevant API)
|
||||||
// we just keep current font size inside ThemeManager singleton.
|
// we just keep current font size inside ThemeManager singleton.
|
||||||
// It works fine if ThemeManager default font size value matches
|
// It works fine if ThemeManager default font size value matches
|
||||||
// default theme font size value.
|
// default theme font size value.
|
||||||
spinner.getValueFactory().setValue(ThemeManager.getInstance().getFontSize());
|
spinner.getValueFactory().setValue(tm.getFontSize());
|
||||||
|
|
||||||
spinner.valueProperty().addListener((obs, old, val) -> {
|
spinner.valueProperty().addListener((obs, old, val) -> {
|
||||||
if (val != null && getScene() != null) {
|
if (val != null) {
|
||||||
var tm = ThemeManager.getInstance();
|
|
||||||
tm.setFontSize(val);
|
tm.setFontSize(val);
|
||||||
tm.reloadCustomCSS();
|
tm.reloadCustomCSS();
|
||||||
updateFontInfo(Duration.ofMillis(1000));
|
updateFontInfo(Duration.ofMillis(1000));
|
||||||
|
@ -19,6 +19,7 @@ public final class ThemeManager {
|
|||||||
|
|
||||||
private static final String DUMMY_STYLESHEET = Resources.getResource("assets/styles/empty.css").toString();
|
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 PseudoClass USER_CUSTOM = PseudoClass.getPseudoClass("user-custom");
|
||||||
|
private static final String DEFAULT_FONT_FAMILY_NAME = "Application Default";
|
||||||
|
|
||||||
// KEY | VALUE
|
// KEY | VALUE
|
||||||
// -fx-property | value;
|
// -fx-property | value;
|
||||||
@ -26,9 +27,10 @@ public final class ThemeManager {
|
|||||||
// .foo | -fx-property: value;
|
// .foo | -fx-property: value;
|
||||||
private final Map<String, String> customCSSRules = new LinkedHashMap<>();
|
private final Map<String, String> customCSSRules = new LinkedHashMap<>();
|
||||||
|
|
||||||
private Theme currentTheme = null;
|
|
||||||
private int currentFontSize = 14;
|
|
||||||
private Scene scene;
|
private Scene scene;
|
||||||
|
private Theme currentTheme = null;
|
||||||
|
private String fontFamily = DEFAULT_FONT_FAMILY_NAME;
|
||||||
|
private int fontSize = 14;
|
||||||
|
|
||||||
public Scene getScene() {
|
public Scene getScene() {
|
||||||
return scene;
|
return scene;
|
||||||
@ -66,10 +68,7 @@ public final class ThemeManager {
|
|||||||
|
|
||||||
public List<Theme> getAvailableThemes() {
|
public List<Theme> getAvailableThemes() {
|
||||||
var themes = new ArrayList<Theme>();
|
var themes = new ArrayList<Theme>();
|
||||||
var appStylesheets = new URI[] {
|
var appStylesheets = new URI[] { URI.create(Resources.resolve("assets/styles/index.css")) };
|
||||||
URI.create(Resources.resolve("assets/fonts/index.css")),
|
|
||||||
URI.create(Resources.resolve("assets/styles/index.css"))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Launcher.IS_DEV_MODE) {
|
if (Launcher.IS_DEV_MODE) {
|
||||||
themes.add(new ExternalTheme("Primer Light", DUMMY_STYLESHEET, merge(
|
themes.add(new ExternalTheme("Primer Light", DUMMY_STYLESHEET, merge(
|
||||||
@ -95,14 +94,23 @@ public final class ThemeManager {
|
|||||||
return themes;
|
return themes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFontFamily() {
|
||||||
|
return fontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFontFamily(String fontFamily) {
|
||||||
|
setCustomDeclaration("-fx-font-family", "\"" + fontFamily + "\"");
|
||||||
|
this.fontFamily = fontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
public int getFontSize() {
|
public int getFontSize() {
|
||||||
return currentFontSize;
|
return fontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFontSize(int fontSize) {
|
public void setFontSize(int fontSize) {
|
||||||
setCustomDeclaration("-fx-font-size", fontSize + "px");
|
setCustomDeclaration("-fx-font-size", fontSize + "px");
|
||||||
setCustomRule(".ikonli-font-icon", String.format("-fx-icon-size: %dpx;", fontSize + 2));
|
setCustomRule(".ikonli-font-icon", String.format("-fx-icon-size: %dpx;", fontSize + 2));
|
||||||
currentFontSize = fontSize;
|
this.fontSize = fontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCustomDeclaration(String property, String value) {
|
private void setCustomDeclaration(String property, String value) {
|
||||||
@ -139,8 +147,6 @@ public final class ThemeManager {
|
|||||||
css.append("}\n");
|
css.append("}\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
System.out.println(css);
|
|
||||||
|
|
||||||
scene.getStylesheets().removeIf(uri -> uri.startsWith("data:text/css"));
|
scene.getStylesheets().removeIf(uri -> uri.startsWith("data:text/css"));
|
||||||
scene.getStylesheets().add(
|
scene.getStylesheets().add(
|
||||||
"data:text/css;base64," + Base64.getEncoder().encodeToString(css.toString().getBytes(UTF_8))
|
"data:text/css;base64," + Base64.getEncoder().encodeToString(css.toString().getBytes(UTF_8))
|
||||||
|
@ -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 <url>. 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');
|
|
||||||
}
|
|
@ -1,7 +1,12 @@
|
|||||||
/** SPDX-License-Identifier: MIT */
|
/** SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Application Default";
|
||||||
|
src: url('../fonts/Inter-Regular.otf');
|
||||||
|
}
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
-fx-font-family: "Inter";
|
-fx-font-family: "Application Default";
|
||||||
}
|
}
|
||||||
.root:showcase-mode #sidebar,
|
.root:showcase-mode #sidebar,
|
||||||
.root:showcase-mode .page > .header {
|
.root:showcase-mode .page > .header {
|
||||||
|
@ -72,7 +72,6 @@
|
|||||||
|
|
||||||
// default props inherited by all nodes
|
// default props inherited by all nodes
|
||||||
-fx-background-color: -color-bg-default;
|
-fx-background-color: -color-bg-default;
|
||||||
-fx-font-family: "Inter";
|
|
||||||
-fx-font-size: cfg.$font-default;
|
-fx-font-size: cfg.$font-default;
|
||||||
|
|
||||||
// these are needed for Popup
|
// these are needed for Popup
|
||||||
|
Loading…
Reference in New Issue
Block a user