修复主题相关问题 (#1915)

* Update blue.css

* fix

* fix

* Cleanup Code

* Use blue.bss

* fix read theme
This commit is contained in:
Glavo 2022-12-17 18:34:10 +08:00 committed by GitHub
parent 7f599638d7
commit d67dd700e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 104 additions and 59 deletions

View File

@ -40,7 +40,6 @@ import org.jackhuang.hmcl.util.i18n.Locales;
import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale; import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale;
import org.jackhuang.hmcl.util.javafx.ObservableHelper; import org.jackhuang.hmcl.util.javafx.ObservableHelper;
import org.jackhuang.hmcl.util.javafx.PropertyUtils; import org.jackhuang.hmcl.util.javafx.PropertyUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
@ -120,7 +119,7 @@ public final class Config implements Cloneable, Observable {
private DoubleProperty height = new SimpleDoubleProperty(); private DoubleProperty height = new SimpleDoubleProperty();
@SerializedName("theme") @SerializedName("theme")
private ObjectProperty<Theme> theme = new SimpleObjectProperty<>(Theme.BLUE); private ObjectProperty<Theme> theme = new SimpleObjectProperty<>();
@SerializedName("localization") @SerializedName("localization")
private ObjectProperty<SupportedLocale> localization = new SimpleObjectProperty<>(Locales.DEFAULT); private ObjectProperty<SupportedLocale> localization = new SimpleObjectProperty<>(Locales.DEFAULT);
@ -147,7 +146,7 @@ public final class Config implements Cloneable, Observable {
private ObservableList<Map<Object, Object>> accountStorages = FXCollections.observableArrayList(); private ObservableList<Map<Object, Object>> accountStorages = FXCollections.observableArrayList();
@SerializedName("fontFamily") @SerializedName("fontFamily")
private StringProperty fontFamily = new SimpleStringProperty(OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace"); private StringProperty fontFamily = new SimpleStringProperty();
@SerializedName("fontSize") @SerializedName("fontSize")
private DoubleProperty fontSize = new SimpleDoubleProperty(12); private DoubleProperty fontSize = new SimpleDoubleProperty(12);

View File

@ -24,13 +24,12 @@ import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding; import javafx.beans.binding.ObjectBinding;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.ResourceNotFoundError;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.javafx.BindingMapping;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.logging.Level; import java.util.logging.Level;
@ -50,6 +49,11 @@ public class Theme {
Color.web("#B71C1C") // red Color.web("#B71C1C") // red
}; };
public static Theme getTheme() {
Theme theme = config().getTheme();
return theme == null ? BLUE : theme;
}
private final Color paint; private final Color paint;
private final String color; private final String color;
private final String name; private final String name;
@ -73,7 +77,7 @@ public class Theme {
} }
public boolean isLight() { public boolean isLight() {
return Color.web(color).grayscale().getRed() >= 0.5; return paint.grayscale().getRed() >= 0.5;
} }
public Color getForegroundColor() { public Color getForegroundColor() {
@ -81,33 +85,31 @@ public class Theme {
} }
public String[] getStylesheets(String overrideFontFamily) { public String[] getStylesheets(String overrideFontFamily) {
Color textFill = getForegroundColor(); String css = "/assets/css/blue.css";
String fontFamily = System.getProperty("hmcl.font.override", overrideFontFamily); String fontFamily = System.getProperty("hmcl.font.override", overrideFontFamily);
String css; if (fontFamily != null || !this.color.equalsIgnoreCase(BLUE.color)) {
try { Color textFill = getForegroundColor();
File temp = File.createTempFile("hmcl", ".css"); try {
FileUtils.writeText(temp, IOUtils.readFullyAsString(ResourceNotFoundError.getResourceAsStream("/assets/css/custom.css")) File temp = File.createTempFile("hmcl", ".css");
.replace("%base-color%", color) FileUtils.writeText(temp, IOUtils.readFullyAsString(Theme.class.getResourceAsStream("/assets/css/custom.css"))
.replace("%base-red%", Integer.toString((int)Math.ceil(paint.getRed() * 256))) .replace("%base-color%", color)
.replace("%base-green%", Integer.toString((int)Math.ceil(paint.getGreen() * 256))) .replace("%base-red%", Integer.toString((int) Math.ceil(paint.getRed() * 256)))
.replace("%base-blue%", Integer.toString((int)Math.ceil(paint.getBlue() * 256))) .replace("%base-green%", Integer.toString((int) Math.ceil(paint.getGreen() * 256)))
.replace("%base-rippler-color%", String.format("rgba(%d, %d, %d, 0.3)", (int) Math.ceil(paint.getRed() * 256), (int) Math.ceil(paint.getGreen() * 256), (int) Math.ceil(paint.getBlue() * 256))) .replace("%base-blue%", Integer.toString((int) Math.ceil(paint.getBlue() * 256)))
.replace("%disabled-font-color%", String.format("rgba(%d, %d, %d, 0.7)", (int) Math.ceil(textFill.getRed() * 256), (int) Math.ceil(textFill.getGreen() * 256), (int) Math.ceil(textFill.getBlue() * 256))) .replace("%base-rippler-color%", String.format("rgba(%d, %d, %d, 0.3)", (int) Math.ceil(paint.getRed() * 256), (int) Math.ceil(paint.getGreen() * 256), (int) Math.ceil(paint.getBlue() * 256)))
.replace("%font-color%", getColorDisplayName(getForegroundColor())) .replace("%disabled-font-color%", String.format("rgba(%d, %d, %d, 0.7)", (int) Math.ceil(textFill.getRed() * 256), (int) Math.ceil(textFill.getGreen() * 256), (int) Math.ceil(textFill.getBlue() * 256)))
.replace("%font%", Optional.ofNullable(fontFamily).map(f -> "-fx-font-family: \"" + f + "\";").orElse(""))); .replace("%font-color%", getColorDisplayName(getForegroundColor()))
temp.deleteOnExit(); .replace("%font%", Optional.ofNullable(fontFamily).map(f -> "-fx-font-family: \"" + f + "\";").orElse("")));
css = temp.toURI().toString(); temp.deleteOnExit();
} catch (IOException | NullPointerException e) { css = temp.toURI().toString();
Logging.LOG.log(Level.SEVERE, "Unable to create theme stylesheet. Fallback to blue theme.", e); } catch (IOException | NullPointerException e) {
css = "/assets/css/blue.css"; Logging.LOG.log(Level.SEVERE, "Unable to create theme stylesheet. Fallback to blue theme.", e);
}
} }
return new String[]{ return new String[]{css, "/assets/css/root.css"};
css,
"/assets/css/root.css"
};
} }
public static Theme custom(String color) { public static Theme custom(String color) {
@ -119,25 +121,35 @@ public class Theme {
public static Optional<Theme> getTheme(String name) { public static Optional<Theme> getTheme(String name) {
if (name == null) if (name == null)
return Optional.empty(); return Optional.empty();
else if (name.equalsIgnoreCase("blue")) else if (name.startsWith("#"))
return Optional.of(custom("#5C6BC0"));
else if (name.equalsIgnoreCase("darker_blue"))
return Optional.of(custom("#283593"));
else if (name.equalsIgnoreCase("green"))
return Optional.of(custom("#43A047"));
else if (name.equalsIgnoreCase("orange"))
return Optional.of(custom("#E67E22"));
else if (name.equalsIgnoreCase("purple"))
return Optional.of(custom("#9C27B0"));
else if (name.equalsIgnoreCase("red"))
return Optional.of(custom("#F44336"));
if (name.startsWith("#"))
try { try {
Color.web(name); Color.web(name);
return Optional.of(custom(name)); return Optional.of(custom(name));
} catch (IllegalArgumentException ignore) { } catch (IllegalArgumentException ignore) {
} }
else {
String color = null;
switch (name.toLowerCase(Locale.ROOT)) {
case "blue":
return Optional.of(BLUE);
case "darker_blue":
color = "#283593";
break;
case "green":
color = "#43A047";
break;
case "orange":
color = "#E67E22";
break;
case "purple":
color = "#9C27B0";
break;
case "red":
color = "#F44336";
}
if (color != null)
return Optional.of(new Theme(name, color));
}
return Optional.empty(); return Optional.empty();
} }
@ -146,17 +158,26 @@ public class Theme {
return c != null ? String.format("#%02x%02x%02x", Math.round(c.getRed() * 255.0D), Math.round(c.getGreen() * 255.0D), Math.round(c.getBlue() * 255.0D)).toUpperCase() : null; return c != null ? String.format("#%02x%02x%02x", Math.round(c.getRed() * 255.0D), Math.round(c.getGreen() * 255.0D), Math.round(c.getBlue() * 255.0D)).toUpperCase() : null;
} }
private static final ObjectBinding<Color> BLACK_FILL = Bindings.createObjectBinding(() -> BLACK);
private static final ObjectBinding<Color> WHITE_FILL = Bindings.createObjectBinding(() -> Color.WHITE);
private static ObjectBinding<Color> FOREGROUND_FILL;
public static ObjectBinding<Color> foregroundFillBinding() { public static ObjectBinding<Color> foregroundFillBinding() {
return BindingMapping.of(config().themeProperty()) if (FOREGROUND_FILL == null)
.map(Theme::getForegroundColor); FOREGROUND_FILL = Bindings.createObjectBinding(
() -> Theme.getTheme().getForegroundColor(),
config().themeProperty()
);
return FOREGROUND_FILL;
} }
public static ObjectBinding<Color> blackFillBinding() { public static ObjectBinding<Color> blackFillBinding() {
return Bindings.createObjectBinding(() -> BLACK); return BLACK_FILL;
} }
public static ObjectBinding<Color> whiteFillBinding() { public static ObjectBinding<Color> whiteFillBinding() {
return Bindings.createObjectBinding(() -> Color.WHITE); return WHITE_FILL;
} }
public static class TypeAdapter extends com.google.gson.TypeAdapter<Theme> { public static class TypeAdapter extends com.google.gson.TypeAdapter<Theme> {

View File

@ -35,6 +35,7 @@ import org.jackhuang.hmcl.game.ModpackHelper;
import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.setting.Accounts;
import org.jackhuang.hmcl.setting.EnumCommonDirectory; import org.jackhuang.hmcl.setting.EnumCommonDirectory;
import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.task.TaskExecutor;
import org.jackhuang.hmcl.ui.account.AccountListPage; import org.jackhuang.hmcl.ui.account.AccountListPage;
@ -181,7 +182,7 @@ public final class Controllers {
stage.setMinWidth(800 + 2 + 16); // bg width + border width*2 + shadow width*2 stage.setMinWidth(800 + 2 + 16); // bg width + border width*2 + shadow width*2
decorator.getDecorator().prefWidthProperty().bind(scene.widthProperty()); decorator.getDecorator().prefWidthProperty().bind(scene.widthProperty());
decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty()); decorator.getDecorator().prefHeightProperty().bind(scene.heightProperty());
scene.getStylesheets().setAll(config().getTheme().getStylesheets(config().getLauncherFontFamily())); scene.getStylesheets().setAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
stage.getIcons().add(newImage("/assets/img/icon.png")); stage.getIcons().add(newImage("/assets/img/icon.png"));
stage.setTitle(Metadata.FULL_TITLE); stage.setTitle(Metadata.FULL_TITLE);

View File

@ -94,6 +94,8 @@ public final class FXUtils {
private FXUtils() { private FXUtils() {
} }
public static String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace";
public static void runInFX(Runnable runnable) { public static void runInFX(Runnable runnable) {
if (Platform.isFxApplicationThread()) { if (Platform.isFxApplicationThread()) {
runnable.run(); runnable.run();

View File

@ -38,6 +38,7 @@ import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.game.*;
import org.jackhuang.hmcl.launch.ProcessListener; import org.jackhuang.hmcl.launch.ProcessListener;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
@ -107,7 +108,7 @@ public class GameCrashWindow extends Stage {
this.feedbackTextFlow.getChildren().addAll(FXUtils.parseSegment(i18n("game.crash.feedback"), Controllers::onHyperlinkAction)); this.feedbackTextFlow.getChildren().addAll(FXUtils.parseSegment(i18n("game.crash.feedback"), Controllers::onHyperlinkAction));
setScene(new Scene(view, 800, 480)); setScene(new Scene(view, 800, 480));
getScene().getStylesheets().addAll(config().getTheme().getStylesheets(config().getLauncherFontFamily())); getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
setTitle(i18n("game.crash.title")); setTitle(i18n("game.crash.title"));
getIcons().add(newImage("/assets/img/icon.png")); getIcons().add(newImage("/assets/img/icon.png"));

View File

@ -36,6 +36,8 @@ import javafx.scene.layout.*;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
import org.jackhuang.hmcl.game.LauncherHelper; import org.jackhuang.hmcl.game.LauncherHelper;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel; import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
@ -87,7 +89,7 @@ public final class LogWindow extends Stage {
public LogWindow() { public LogWindow() {
setScene(new Scene(impl, 800, 480)); setScene(new Scene(impl, 800, 480));
getScene().getStylesheets().addAll(config().getTheme().getStylesheets(config().getLauncherFontFamily())); getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
setTitle(i18n("logwindow.title")); setTitle(i18n("logwindow.title"));
getIcons().add(newImage("/assets/img/icon.png")); getIcons().add(newImage("/assets/img/icon.png"));
@ -286,7 +288,9 @@ public final class LogWindow extends Stage {
if (!listView.getItems().isEmpty() && control.autoScroll.get()) if (!listView.getItems().isEmpty() && control.autoScroll.get())
listView.scrollTo(listView.getItems().size() - 1); listView.scrollTo(listView.getItems().size() - 1);
}); });
listView.setStyle("-fx-font-family: " + config().getFontFamily() + "; -fx-font-size: " + config().getFontSize() + "px;");
listView.setStyle("-fx-font-family: " + Lang.requireNonNullElse(config().getFontFamily(), FXUtils.DEFAULT_MONOSPACE_FONT)
+ "; -fx-font-size: " + config().getFontSize() + "px;");
MutableObject<Object> lastCell = new MutableObject<>(); MutableObject<Object> lastCell = new MutableObject<>();
listView.setCellFactory(x -> new ListCell<Log>() { listView.setCellFactory(x -> new ListCell<Log>() {
{ {

View File

@ -26,6 +26,7 @@ import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView; import javafx.scene.web.WebView;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.setting.Theme;
import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.newImage; import static org.jackhuang.hmcl.ui.FXUtils.newImage;
@ -42,7 +43,7 @@ public class WebStage extends Stage {
public WebStage(int width, int height) { public WebStage(int width, int height) {
setScene(new Scene(pane, width, height)); setScene(new Scene(pane, width, height));
getScene().getStylesheets().addAll(config().getTheme().getStylesheets(config().getLauncherFontFamily())); getScene().getStylesheets().addAll(Theme.getTheme().getStylesheets(config().getLauncherFontFamily()));
getIcons().add(newImage("/assets/img/icon.png")); getIcons().add(newImage("/assets/img/icon.png"));
webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile()); webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile());
webView.setContextMenuEnabled(false); webView.setContextMenuEnabled(false);

View File

@ -26,7 +26,6 @@ import org.jackhuang.hmcl.util.javafx.BindingMapping;
import com.jfoenix.controls.JFXComboBox; import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXListCell; import com.jfoenix.controls.JFXListCell;
import javafx.beans.NamedArg;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.scene.text.Font; import javafx.scene.text.Font;
@ -34,7 +33,7 @@ public class FontComboBox extends JFXComboBox<String> {
private boolean loaded = false; private boolean loaded = false;
public FontComboBox(@NamedArg(value = "fontSize", defaultValue = "12.0") double fontSize) { public FontComboBox() {
styleProperty().bind(Bindings.concat("-fx-font-family: \"", valueProperty(), "\"")); styleProperty().bind(Bindings.concat("-fx-font-family: \"", valueProperty(), "\""));
setCellFactory(listView -> new JFXListCell<String>() { setCellFactory(listView -> new JFXListCell<String>() {

View File

@ -41,6 +41,7 @@ import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.javafx.SafeStringConverter; import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
import java.util.Arrays; import java.util.Arrays;
@ -72,7 +73,7 @@ public class PersonalizationPage extends StackPane {
themeColorPickerContainer.setMinHeight(30); themeColorPickerContainer.setMinHeight(30);
themePane.setRight(themeColorPickerContainer); themePane.setRight(themeColorPickerContainer);
ColorPicker picker = new ColorPicker(Color.web(config().getTheme().getColor())); ColorPicker picker = new ColorPicker(Color.web(Theme.getTheme().getColor()));
picker.getCustomColors().setAll(Theme.SUGGESTED_COLORS); picker.getCustomColors().setAll(Theme.SUGGESTED_COLORS);
picker.setOnAction(e -> { picker.setOnAction(e -> {
Theme theme = Theme.custom(Theme.getColorDisplayName(picker.getValue())); Theme theme = Theme.custom(Theme.getColorDisplayName(picker.getValue()));
@ -141,7 +142,7 @@ public class PersonalizationPage extends StackPane {
HBox hBox = new HBox(); HBox hBox = new HBox();
hBox.setSpacing(3); hBox.setSpacing(3);
FontComboBox cboLogFont = new FontComboBox(12); FontComboBox cboLogFont = new FontComboBox();
cboLogFont.valueProperty().bindBidirectional(config().fontFamilyProperty()); cboLogFont.valueProperty().bindBidirectional(config().fontFamilyProperty());
JFXTextField txtLogFontSize = new JFXTextField(); JFXTextField txtLogFontSize = new JFXTextField();
@ -159,7 +160,7 @@ public class PersonalizationPage extends StackPane {
Label lblLogFontDisplay = new Label("[23:33:33] [Client Thread/INFO] [WaterPower]: Loaded mod WaterPower."); Label lblLogFontDisplay = new Label("[23:33:33] [Client Thread/INFO] [WaterPower]: Loaded mod WaterPower.");
lblLogFontDisplay.fontProperty().bind(Bindings.createObjectBinding( lblLogFontDisplay.fontProperty().bind(Bindings.createObjectBinding(
() -> Font.font(config().getFontFamily(), config().getFontSize()), () -> Font.font(Lang.requireNonNullElse(config().getFontFamily(), FXUtils.DEFAULT_MONOSPACE_FONT), config().getFontSize()),
config().fontFamilyProperty(), config().fontSizeProperty())); config().fontFamilyProperty(), config().fontSizeProperty()));
fontPane.getChildren().add(lblLogFontDisplay); fontPane.getChildren().add(lblLogFontDisplay);
@ -191,7 +192,7 @@ public class PersonalizationPage extends StackPane {
HBox hBox = new HBox(); HBox hBox = new HBox();
hBox.setSpacing(8); hBox.setSpacing(8);
FontComboBox cboFont = new FontComboBox(12); FontComboBox cboFont = new FontComboBox();
cboFont.valueProperty().bindBidirectional(config().launcherFontFamilyProperty()); cboFont.valueProperty().bindBidirectional(config().launcherFontFamilyProperty());
JFXButton clearButton = new JFXButton(); JFXButton clearButton = new JFXButton();
@ -210,7 +211,7 @@ public class PersonalizationPage extends StackPane {
() -> Font.font(config().getLauncherFontFamily(), 12), () -> Font.font(config().getLauncherFontFamily(), 12),
config().launcherFontFamilyProperty())); config().launcherFontFamilyProperty()));
config().launcherFontFamilyProperty().addListener((a, b, newValue) -> { config().launcherFontFamilyProperty().addListener((a, b, newValue) -> {
Controllers.getScene().getStylesheets().setAll(config().getTheme().getStylesheets(newValue)); Controllers.getScene().getStylesheets().setAll(Theme.getTheme().getStylesheets(newValue));
}); });
vbox.getChildren().add(lblFontDisplay); vbox.getChildren().add(lblFontDisplay);

View File

@ -16,9 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
.root { .root {
-fx-base-color: #5c6bc0; -fx-base-color: #5C6BC0;
-fx-base-darker-color: derive(-fx-base-color, -10%); -fx-base-darker-color: derive(-fx-base-color, -10%);
-fx-base-check-color: derive(-fx-base-color, 30%); -fx-base-check-color: derive(-fx-base-color, 30%);
-fx-rippler-color: rgba(92, 107, 192, 0.3);
-fx-base-rippler-color: rgba(92, 107, 192, 0.3); -fx-base-rippler-color: rgba(92, 107, 192, 0.3);
-fx-base-disabled-text-fill: rgba(256, 256, 256, 0.7);
-fx-base-text-fill: white; -fx-base-text-fill: white;
-theme-thumb: rgba(92, 107, 192, 0.3);
} }

View File

@ -34,6 +34,18 @@ public final class Lang {
private Lang() { private Lang() {
} }
public static <T> T requireNonNullElse(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
public static <T> T requireNonNullElseGet(T value, Supplier<? extends T> defaultValue) {
return value != null ? value : defaultValue.get();
}
public static <T, U> U requireNonNullElseGet(T value, Function<? super T, ? extends U> mapper, Supplier<? extends U> defaultValue) {
return value != null ? mapper.apply(value) : defaultValue.get();
}
/** /**
* Construct a mutable map by given key-value pairs. * Construct a mutable map by given key-value pairs.
* @param pairs entries in the new map * @param pairs entries in the new map