From 76ed9353bd89ffe6b8d160623279fc52e468d691 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 14 May 2025 14:18:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=20Theme=20(#3910)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * update * update * update * update * update --- .../jackhuang/hmcl/setting/FontManager.java | 121 ++++++++++++ .../jackhuang/hmcl/setting/StyleSheets.java | 168 +++++++++++++++++ .../org/jackhuang/hmcl/setting/Theme.java | 175 +----------------- .../org/jackhuang/hmcl/ui/Controllers.java | 2 +- .../jackhuang/hmcl/ui/GameCrashWindow.java | 5 +- .../java/org/jackhuang/hmcl/ui/LogWindow.java | 4 +- .../hmcl/ui/construct/FontComboBox.java | 2 +- .../hmcl/ui/main/PersonalizationPage.java | 24 +-- HMCL/src/main/resources/assets/css/blue.css | 3 - HMCL/src/main/resources/assets/css/font.css | 21 +++ 10 files changed, 328 insertions(+), 197 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java create mode 100644 HMCL/src/main/resources/assets/css/font.css diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java new file mode 100644 index 000000000..62b06c32e --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/FontManager.java @@ -0,0 +1,121 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.setting; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.text.Font; +import org.jackhuang.hmcl.Metadata; +import org.jackhuang.hmcl.util.Lazy; +import org.jackhuang.hmcl.util.io.JarUtils; + +import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.jackhuang.hmcl.setting.ConfigHolder.config; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + +/** + * @author Glavo + */ +public final class FontManager { + + public static final double DEFAULT_FONT_SIZE = 12.0f; + + private static final Lazy DEFAULT_FONT = new Lazy<>(() -> { + Font font = tryLoadDefaultFont(Metadata.HMCL_CURRENT_DIRECTORY); + if (font != null) + return font; + + font = tryLoadDefaultFont(Metadata.CURRENT_DIRECTORY); + if (font != null) + return font; + + font = tryLoadDefaultFont(Metadata.HMCL_GLOBAL_DIRECTORY); + if (font != null) + return font; + + Path thisJar = JarUtils.thisJarPath(); + if (thisJar != null && thisJar.getParent() != null) + return tryLoadDefaultFont(thisJar.getParent()); + + return null; + }); + + private static final ObjectProperty fontProperty = new SimpleObjectProperty<>(getDefaultFont()); + + static { + fontProperty.addListener((obs, oldValue, newValue) -> { + if (newValue != null) + config().setLauncherFontFamily(newValue.getFamily()); + else + config().setLauncherFontFamily(null); + }); + } + + private static Font tryLoadDefaultFont(Path dir) { + String[] fileNames = {"font.ttf", "font.otf", "font.woff"}; + + for (String fileName : fileNames) { + Path path = dir.resolve(fileName); + if (Files.isRegularFile(path)) { + try { + Font font = Font.loadFont(path.toUri().toURL().toExternalForm(), DEFAULT_FONT_SIZE); + if (font != null) { + return font; + } + } catch (MalformedURLException ignored) { + } + + LOG.warning("Failed to load font " + path); + } + } + + return null; + } + + private static Font getDefaultFont() { + String fontFamily = config().getLauncherFontFamily(); + if (fontFamily == null) + fontFamily = System.getProperty("hmcl.font.override"); + if (fontFamily == null) + fontFamily = System.getenv("HMCL_FONT"); + + return fontFamily == null ? DEFAULT_FONT.get() : Font.font(fontFamily, DEFAULT_FONT_SIZE); + } + + public static ObjectProperty fontProperty() { + return fontProperty; + } + + public static Font getFont() { + return fontProperty.get(); + } + + public static void setFont(Font font) { + fontProperty.set(font); + } + + public static void setFontFamily(String fontFamily) { + setFont(fontFamily != null ? Font.font(fontFamily, DEFAULT_FONT_SIZE) : null); + } + + private FontManager() { + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java new file mode 100644 index 000000000..5003d7b46 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java @@ -0,0 +1,168 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.setting; + +import javafx.beans.binding.Bindings; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.Scene; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.util.io.FileUtils; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Base64; +import java.util.Locale; + +import static org.jackhuang.hmcl.setting.ConfigHolder.config; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + +/** + * @author Glavo + */ +public final class StyleSheets { + private static final int FONT_STYLE_SHEET_INDEX = 0; + private static final int THEME_STYLE_SHEET_INDEX = 1; + + private static final ObservableList stylesheets; + + static { + String[] array = new String[]{ + getFontStyleSheet(), + getThemeStyleSheet(), + "/assets/css/root.css" + }; + stylesheets = FXCollections.observableList(Arrays.asList(array)); + + FontManager.fontProperty().addListener(o -> stylesheets.set(FONT_STYLE_SHEET_INDEX, getFontStyleSheet())); + config().themeProperty().addListener(o -> stylesheets.set(THEME_STYLE_SHEET_INDEX, getThemeStyleSheet())); + } + + private static String toStyleSheetUri(String styleSheet, String fallback) { + if (FXUtils.JAVAFX_MAJOR_VERSION >= 17) + // JavaFX 17+ support loading stylesheets from data URIs + // https://bugs.openjdk.org/browse/JDK-8267554 + return "data:text/css;charset=UTF-8;base64," + Base64.getEncoder().encodeToString(styleSheet.getBytes(StandardCharsets.UTF_8)); + else + try { + Path temp = Files.createTempFile("hmcl", ".css"); + // For JavaFX 17 or earlier, CssParser uses the default charset + // https://bugs.openjdk.org/browse/JDK-8279328 + FileUtils.writeText(temp, styleSheet, Charset.defaultCharset()); + temp.toFile().deleteOnExit(); + return temp.toUri().toString(); + } catch (IOException | NullPointerException e) { + LOG.error("Unable to create stylesheet, fallback to " + fallback, e); + return fallback; + } + } + + private static String getFontStyleSheet() { + final String defaultCss = "/assets/css/font.css"; + final Font font = FontManager.getFont(); + + if (font == null || font == Font.getDefault()) + return defaultCss; + + String fontFamily = font.getFamily(); + String style = font.getStyle(); + String weight = null; + String posture = null; + + if (style != null) { + style = style.toLowerCase(Locale.ROOT); + + if (style.contains("thin")) + weight = "100"; + else if (style.contains("extralight") || style.contains("extra light") || style.contains("ultralight") | style.contains("ultra light")) + weight = "200"; + else if (style.contains("medium")) + weight = "500"; + else if (style.contains("semibold") || style.contains("semi bold") || style.contains("demibold") || style.contains("demi bold")) + weight = "600"; + else if (style.contains("extrabold") || style.contains("extra bold") || style.contains("ultrabold") || style.contains("ultra bold")) + weight = "800"; + else if (style.contains("black") || style.contains("heavy")) + weight = "900"; + else if (style.contains("light")) + weight = "lighter"; + else if (style.contains("bold")) + weight = "bold"; + + posture = style.contains("italic") || style.contains("oblique") ? "italic" : null; + } + + StringBuilder builder = new StringBuilder(); + builder.append(".root {"); + if (fontFamily == null) + // https://github.com/HMCL-dev/HMCL/pull/3423 + builder.append("-fx-font-family: -fx-base-font-family;"); + else + builder.append("-fx-font-family:\"").append(fontFamily).append("\";"); + + if (weight != null) + builder.append("-fx-font-weight:").append(weight).append(";"); + + if (posture != null) + builder.append("-fx-font-style:").append(posture).append(";"); + + builder.append('}'); + + return toStyleSheetUri(builder.toString(), fontFamily); + } + + private static String rgba(Color color, double opacity) { + return String.format("rgba(%d, %d, %d, %.1f)", + (int) Math.ceil(color.getRed() * 256), + (int) Math.ceil(color.getGreen() * 256), + (int) Math.ceil(color.getBlue() * 256), + opacity); + } + + private static String getThemeStyleSheet() { + final String blueCss = "/assets/css/blue.css"; + + Theme theme = config().getTheme(); + if (theme == null || theme.getPaint().equals(Theme.BLUE.getPaint())) + return blueCss; + + return toStyleSheetUri(".root {" + + "-fx-base-color:" + theme.getColor() + ';' + + "-fx-base-darker-color: derive(-fx-base-color, -10%);" + + "-fx-base-check-color: derive(-fx-base-color, 30%);" + + "-fx-rippler-color:" + rgba(theme.getPaint(), 0.3) + ';' + + "-fx-base-rippler-color: derive(" + rgba(theme.getPaint(), 0.3) + ", 100%);" + + "-fx-base-disabled-text-fill:" + rgba(theme.getForegroundColor(), 0.7) + ";" + + "-fx-base-text-fill:" + Theme.getColorDisplayName(theme.getForegroundColor()) + ";" + + "-theme-thumb:" + rgba(theme.getPaint(), 0.7) + ";" + + '}', blueCss); + } + + public static void init(Scene scene) { + Bindings.bindContent(scene.getStylesheets(), stylesheets); + } + + private StyleSheets() { + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Theme.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Theme.java index 075d5d4ea..45f2bb267 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Theme.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Theme.java @@ -23,31 +23,16 @@ import com.google.gson.stream.JsonWriter; import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; import javafx.scene.paint.Color; -import javafx.scene.text.Font; -import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.ui.FXUtils; -import org.jackhuang.hmcl.util.Lazy; -import org.jackhuang.hmcl.util.Pair; -import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.io.JarUtils; -import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Base64; import java.util.Locale; import java.util.Objects; import java.util.Optional; import static org.jackhuang.hmcl.setting.ConfigHolder.config; -import static org.jackhuang.hmcl.util.logging.Logger.LOG; @JsonAdapter(Theme.TypeAdapter.class) -public class Theme { +public final class Theme { public static final Theme BLUE = new Theme("blue", "#5C6BC0"); public static final Color BLACK = Color.web("#292929"); public static final Color[] SUGGESTED_COLORS = new Color[]{ @@ -59,47 +44,6 @@ public class Theme { Color.web("#B71C1C") // red }; - private static Font tryLoadDefaultFont(Path dir) { - String[] fileNames = {"font.ttf", "font.otf", "font.woff"}; - - for (String fileName : fileNames) { - Path path = dir.resolve(fileName); - if (Files.isRegularFile(path)) { - try { - Font font = Font.loadFont(path.toUri().toURL().toExternalForm(), 0); - if (font != null) { - return font; - } - } catch (MalformedURLException ignored) { - } - - LOG.warning("Failed to load font " + path); - } - } - - return null; - } - - private static final Lazy FONT = new Lazy<>(() -> { - Font font = tryLoadDefaultFont(Metadata.HMCL_CURRENT_DIRECTORY); - if (font != null) - return font; - - font = tryLoadDefaultFont(Metadata.CURRENT_DIRECTORY); - if (font != null) - return font; - - font = tryLoadDefaultFont(Metadata.HMCL_GLOBAL_DIRECTORY); - if (font != null) - return font; - - Path thisJar = JarUtils.thisJarPath(); - if (thisJar != null && thisJar.getParent() != null) - return tryLoadDefaultFont(thisJar.getParent()); - - return null; - }); - public static Theme getTheme() { Theme theme = config().getTheme(); return theme == null ? BLUE : theme; @@ -123,6 +67,10 @@ public class Theme { return color; } + public Color getPaint() { + return paint; + } + public boolean isCustom() { return name.startsWith("#"); } @@ -135,119 +83,6 @@ public class Theme { return isLight() ? Color.BLACK : Color.WHITE; } - private static String rgba(Color color, double opacity) { - return String.format("rgba(%d, %d, %d, %.1f)", - (int) Math.ceil(color.getRed() * 256), - (int) Math.ceil(color.getGreen() * 256), - (int) Math.ceil(color.getBlue() * 256), - opacity); - } - - private static Pair parseFontStyle(String style) { - if (style == null) { - return null; - } - - style = style.toLowerCase(Locale.ROOT); - - String weight; - String posture; - - if (style.contains("thin")) { - weight = "100"; - } else if (style.contains("extralight") || style.contains("extra light") || style.contains("ultralight") | style.contains("ultra light")) { - weight = "200"; - } else if (style.contains("medium")) { - weight = "500"; - } else if (style.contains("semibold") || style.contains("semi bold") || style.contains("demibold") || style.contains("demi bold")) { - weight = "600"; - } else if (style.contains("extrabold") || style.contains("extra bold") || style.contains("ultrabold") || style.contains("ultra bold")) { - weight = "800"; - } else if (style.contains("black") || style.contains("heavy")) { - weight = "900"; - } else if (style.contains("light")) { - weight = "lighter"; - } else if (style.contains("bold")) { - weight = "bold"; - } else { - weight = null; - } - - if (style.contains("italic") || style.contains("oblique")) { - posture = "italic"; - } else { - posture = null; - } - - return Pair.pair(weight, posture); - } - - public String[] getStylesheets(String overrideFontFamily) { - String css = "/assets/css/blue.css"; - - String fontFamily = overrideFontFamily == null - ? System.getProperty("hmcl.font.override", System.getenv("HMCL_FONT")) - : overrideFontFamily; - - Pair fontStyle = null; - if (fontFamily == null) { - Font font = FONT.get(); - if (font != null) { - fontFamily = font.getFamily(); - fontStyle = parseFontStyle(font.getStyle()); - } - } - - if (fontFamily != null || !this.color.equalsIgnoreCase(BLUE.color)) { - Color textFill = getForegroundColor(); - - StringBuilder themeBuilder = new StringBuilder(512); - themeBuilder.append(".root {") - .append("-fx-base-color:").append(color).append(';') - .append("-fx-base-darker-color: derive(-fx-base-color, -10%);") - .append("-fx-base-check-color: derive(-fx-base-color, 30%);") - .append("-fx-rippler-color:").append(rgba(paint, 0.3)).append(';') - .append("-fx-base-rippler-color: derive(").append(rgba(paint, 0.3)).append(", 100%);") - .append("-fx-base-disabled-text-fill:").append(rgba(textFill, 0.7)).append(";") - .append("-fx-base-text-fill:").append(getColorDisplayName(getForegroundColor())).append(";") - .append("-theme-thumb:").append(rgba(paint, 0.7)).append(";"); - - if (fontFamily == null) - // https://github.com/HMCL-dev/HMCL/pull/3423 - themeBuilder.append("-fx-font-family: -fx-base-font-family;"); - else - themeBuilder.append("-fx-font-family:\"").append(fontFamily).append("\";"); - - if (fontStyle != null) { - if (fontStyle.getKey() != null) - themeBuilder.append("-fx-font-weight:").append(fontStyle.getKey()).append(";"); - - if (fontStyle.getValue() != null) - themeBuilder.append("-fx-font-style:").append(fontStyle.getValue()).append(";"); - } - - themeBuilder.append('}'); - - if (FXUtils.JAVAFX_MAJOR_VERSION >= 17) - // JavaFX 17+ support loading stylesheets from data URIs - // https://bugs.openjdk.org/browse/JDK-8267554 - css = "data:text/css;charset=UTF-8;base64," + Base64.getEncoder().encodeToString(themeBuilder.toString().getBytes(StandardCharsets.UTF_8)); - else - try { - File temp = File.createTempFile("hmcl", ".css"); - // For JavaFX 17 or earlier, CssParser uses the default charset - // https://bugs.openjdk.org/browse/JDK-8279328 - FileUtils.writeText(temp, themeBuilder.toString(), Charset.defaultCharset()); - temp.deleteOnExit(); - css = temp.toURI().toString(); - } catch (IOException | NullPointerException e) { - LOG.error("Unable to create theme stylesheet. Fallback to blue theme.", e); - } - } - - return new String[]{css, "/assets/css/root.css"}; - } - public static Theme custom(String color) { if (!color.startsWith("#")) throw new IllegalArgumentException(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java index 4372b81ce..39850dee9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -265,7 +265,7 @@ public final class Controllers { stage.setMinHeight(MIN_HEIGHT); decorator.getDecorator().prefWidthProperty().bind(scene.widthProperty()); decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty()); - scene.getStylesheets().setAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily())); + StyleSheets.init(scene); FXUtils.setIcon(stage); stage.setTitle(Metadata.FULL_TITLE); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index df036b80c..43f698ef7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -37,7 +37,7 @@ import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.launch.ProcessListener; -import org.jackhuang.hmcl.setting.Theme; +import org.jackhuang.hmcl.setting.StyleSheets; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; @@ -58,7 +58,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES; import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.Pair.pair; @@ -104,7 +103,7 @@ public class GameCrashWindow extends Stage { this.feedbackTextFlow.getChildren().addAll(FXUtils.parseSegment(i18n("game.crash.feedback"), Controllers::onHyperlinkAction)); setScene(new Scene(view, 800, 480)); - getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily())); + StyleSheets.init(getScene()); setTitle(i18n("game.crash.title")); FXUtils.setIcon(this); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java index bcefd16e0..1f22aca73 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java @@ -40,7 +40,7 @@ import javafx.stage.Stage; import org.jackhuang.hmcl.game.GameDumpGenerator; import org.jackhuang.hmcl.game.LauncherHelper; import org.jackhuang.hmcl.game.Log; -import org.jackhuang.hmcl.setting.Theme; +import org.jackhuang.hmcl.setting.StyleSheets; import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.util.Holder; import org.jackhuang.hmcl.util.CircularArrayList; @@ -92,7 +92,7 @@ public final class LogWindow extends Stage { this.logs = logs; this.impl = new LogWindowImpl(); setScene(new Scene(impl, 800, 480)); - getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily())); + StyleSheets.init(getScene()); setTitle(i18n("logwindow.title")); FXUtils.setIcon(this); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java index 7438a318f..64ffda331 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java @@ -30,7 +30,7 @@ import com.jfoenix.controls.JFXListCell; import javafx.beans.binding.Bindings; import javafx.scene.text.Font; -public class FontComboBox extends JFXComboBox { +public final class FontComboBox extends JFXComboBox { private boolean loaded = false; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/PersonalizationPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/PersonalizationPage.java index f04afec3d..2cf3f7c3f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/PersonalizationPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/PersonalizationPage.java @@ -35,8 +35,8 @@ import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Font; import org.jackhuang.hmcl.setting.EnumBackgroundImage; +import org.jackhuang.hmcl.setting.FontManager; import org.jackhuang.hmcl.setting.Theme; -import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.construct.*; @@ -74,11 +74,8 @@ public class PersonalizationPage extends StackPane { ColorPicker picker = new ColorPicker(Color.web(Theme.getTheme().getColor())); picker.getCustomColors().setAll(Theme.SUGGESTED_COLORS); - picker.setOnAction(e -> { - Theme theme = Theme.custom(Theme.getColorDisplayName(picker.getValue())); - config().setTheme(theme); - Controllers.getScene().getStylesheets().setAll(theme.getStylesheets(config().getLauncherFontFamily())); - }); + picker.setOnAction(e -> + config().setTheme(Theme.custom(Theme.getColorDisplayName(picker.getValue())))); themeColorPickerContainer.getChildren().setAll(picker); Platform.runLater(() -> JFXDepthManager.setDepth(picker, 0)); } @@ -200,12 +197,13 @@ public class PersonalizationPage extends StackPane { hBox.setSpacing(8); FontComboBox cboFont = new FontComboBox(); - cboFont.valueProperty().bindBidirectional(config().launcherFontFamilyProperty()); + cboFont.setValue(config().getLauncherFontFamily()); + FXUtils.onChange(cboFont.valueProperty(), FontManager::setFontFamily); JFXButton clearButton = new JFXButton(); clearButton.getStyleClass().add("toggle-icon4"); clearButton.setGraphic(SVG.RESTORE.createIcon(Theme.blackFill(), -1)); - clearButton.setOnAction(e -> config().setLauncherFontFamily(null)); + clearButton.setOnAction(e -> cboFont.setValue(null)); hBox.getChildren().setAll(cboFont, clearButton); @@ -213,15 +211,7 @@ public class PersonalizationPage extends StackPane { } } - Label lblFontDisplay = new Label("Hello Minecraft! Launcher"); - lblFontDisplay.fontProperty().bind(Bindings.createObjectBinding( - () -> Font.font(config().getLauncherFontFamily(), 12), - config().launcherFontFamilyProperty())); - config().launcherFontFamilyProperty().addListener((a, b, newValue) -> { - Controllers.getScene().getStylesheets().setAll(Theme.getTheme().getStylesheets(newValue)); - }); - - vbox.getChildren().add(lblFontDisplay); + vbox.getChildren().add(new Label("Hello Minecraft! Launcher")); fontPane.getContent().add(vbox); } diff --git a/HMCL/src/main/resources/assets/css/blue.css b/HMCL/src/main/resources/assets/css/blue.css index 4e427b9c4..c02cbb1b8 100644 --- a/HMCL/src/main/resources/assets/css/blue.css +++ b/HMCL/src/main/resources/assets/css/blue.css @@ -24,8 +24,5 @@ -fx-base-disabled-text-fill: rgba(256, 256, 256, 0.7); -fx-base-text-fill: white; - /* https://github.com/HMCL-dev/HMCL/pull/3423 */ - -fx-font-family: -fx-base-font-family; - -theme-thumb: rgba(92, 107, 192, 0.7); } \ No newline at end of file diff --git a/HMCL/src/main/resources/assets/css/font.css b/HMCL/src/main/resources/assets/css/font.css new file mode 100644 index 000000000..6f012b06a --- /dev/null +++ b/HMCL/src/main/resources/assets/css/font.css @@ -0,0 +1,21 @@ +/** + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +.root { + /* https://github.com/HMCL-dev/HMCL/pull/3423 */ + -fx-font-family: -fx-base-font-family; +} \ No newline at end of file