From ca3bc69a61c2e524bf2e6695cf02d7a194dbecc8 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Mon, 20 Sep 2021 01:54:08 +0800 Subject: [PATCH] feat: multifileitem supports multiple custom type. --- .../org/jackhuang/hmcl/setting/Config.java | 30 ++ .../hmcl/setting/EnumBackgroundImage.java | 4 +- .../hmcl/ui/construct/MultiFileItem.java | 339 ++++++++++-------- .../ui/decorator/DecoratorController.java | 3 + .../hmcl/ui/main/PersonalizationPage.java | 37 +- .../jackhuang/hmcl/ui/main/SettingsPage.java | 6 - .../jackhuang/hmcl/ui/main/SettingsView.java | 14 +- .../hmcl/ui/versions/VersionSettingsPage.java | 78 ++-- .../resources/assets/lang/I18N.properties | 2 + .../resources/assets/lang/I18N_zh.properties | 2 + .../assets/lang/I18N_zh_CN.properties | 2 + 11 files changed, 299 insertions(+), 218 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java index 9fafb4874..f2fa5c081 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java @@ -83,6 +83,9 @@ public final class Config implements Cloneable, Observable { @SerializedName("bgpath") private StringProperty backgroundImage = new SimpleStringProperty(); + @SerializedName("bgurl") + private StringProperty backgroundImageUrl = new SimpleStringProperty(); + @SerializedName("commonDirType") private ObjectProperty commonDirType = new SimpleObjectProperty<>(EnumCommonDirectory.DEFAULT); @@ -149,6 +152,9 @@ public final class Config implements Cloneable, Observable { @SerializedName("fontSize") private DoubleProperty fontSize = new SimpleDoubleProperty(12); + @SerializedName("launcherFontFamily") + private StringProperty launcherFontFamily = new SimpleStringProperty(); + @SerializedName("logLines") private IntegerProperty logLines = new SimpleIntegerProperty(100); @@ -239,6 +245,18 @@ public final class Config implements Cloneable, Observable { return backgroundImage; } + public String getBackgroundImageUrl() { + return backgroundImageUrl.get(); + } + + public StringProperty backgroundImageUrlProperty() { + return backgroundImageUrl; + } + + public void setBackgroundImageUrl(String backgroundImageUrl) { + this.backgroundImageUrl.set(backgroundImageUrl); + } + public EnumCommonDirectory getCommonDirType() { return commonDirType.get(); } @@ -487,6 +505,18 @@ public final class Config implements Cloneable, Observable { return fontSize; } + public String getLauncherFontFamily() { + return launcherFontFamily.get(); + } + + public StringProperty launcherFontFamilyProperty() { + return launcherFontFamily; + } + + public void setLauncherFontFamily(String launcherFontFamily) { + this.launcherFontFamily.set(launcherFontFamily); + } + public int getLogLines() { return logLines.get(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumBackgroundImage.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumBackgroundImage.java index ae9bb0e20..f5b54292c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumBackgroundImage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumBackgroundImage.java @@ -19,5 +19,7 @@ package org.jackhuang.hmcl.setting; public enum EnumBackgroundImage { DEFAULT, - CUSTOM + CUSTOM, + CLASSIC, + NETWORK } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java index 076206251..e605b131e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java @@ -20,7 +20,6 @@ package org.jackhuang.hmcl.ui.construct; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXRadioButton; import com.jfoenix.controls.JFXTextField; -import javafx.beans.NamedArg; import javafx.beans.property.*; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -39,74 +38,30 @@ 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.util.StringUtils; import java.io.File; import java.util.Collection; import java.util.Optional; import java.util.function.Consumer; +import java.util.stream.Collectors; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class MultiFileItem extends ComponentSublist { - private final StringProperty customTitle = new SimpleStringProperty(this, "customTitle", i18n("selector.custom")); - private final StringProperty chooserTitle = new SimpleStringProperty(this, "chooserTitle", i18n("selector.choose_file")); - private final BooleanProperty directory = new SimpleBooleanProperty(this, "directory", false); private final ObjectProperty selectedData = new SimpleObjectProperty<>(this, "selectedData"); private final ObjectProperty fallbackData = new SimpleObjectProperty<>(this, "fallbackData"); - private final ObservableList extensionFilters = FXCollections.observableArrayList(); private final ToggleGroup group = new ToggleGroup(); - private final JFXTextField txtCustom = new JFXTextField(); - private final JFXButton btnSelect = new JFXButton(); - private final JFXRadioButton radioCustom = new JFXRadioButton(); - private final BorderPane custom = new BorderPane(); private final VBox pane = new VBox(); - private final boolean hasCustom; private Consumer toggleSelectedListener; @SuppressWarnings("unchecked") - public MultiFileItem(@NamedArg(value = "hasCustom", defaultValue = "true") boolean hasCustom) { - this.hasCustom = hasCustom; - - BorderPane.setAlignment(txtCustom, Pos.CENTER_RIGHT); - - btnSelect.setGraphic(SVG.folderOpen(Theme.blackFillBinding(), 15, 15)); - btnSelect.setOnMouseClicked(e -> { - if (isDirectory()) { - DirectoryChooser chooser = new DirectoryChooser(); - chooser.titleProperty().bind(chooserTitle); - File dir = chooser.showDialog(Controllers.getStage()); - if (dir != null) - txtCustom.setText(dir.getAbsolutePath()); - } else { - FileChooser chooser = new FileChooser(); - chooser.getExtensionFilters().addAll(getExtensionFilters()); - chooser.titleProperty().bind(chooserTitle); - File file = chooser.showOpenDialog(Controllers.getStage()); - if (file != null) - txtCustom.setText(file.getAbsolutePath()); - } - }); - - radioCustom.textProperty().bind(customTitleProperty()); - radioCustom.setToggleGroup(group); - txtCustom.disableProperty().bind(radioCustom.selectedProperty().not()); - btnSelect.disableProperty().bind(radioCustom.selectedProperty().not()); - - custom.setLeft(radioCustom); - custom.setStyle("-fx-padding: 3;"); - HBox right = new HBox(); - right.setSpacing(3); - right.getChildren().addAll(txtCustom, btnSelect); - custom.setRight(right); - FXUtils.setLimitHeight(custom, 20); - + public MultiFileItem() { pane.setStyle("-fx-padding: 0 0 10 0;"); pane.setSpacing(8); - if (hasCustom) - pane.getChildren().add(custom); getContent().add(pane); group.selectedToggleProperty().addListener((a, b, newValue) -> { @@ -129,117 +84,20 @@ public class MultiFileItem extends ComponentSublist { }); } - public Node createChildren(String title) { - return createChildren(title, null); - } - - public Node createChildren(String title, T userData) { - return createChildren(title, "", userData); - } - - public Node createChildren(String title, String subtitle, T userData) { - BorderPane pane = new BorderPane(); - pane.setPadding(new Insets(3)); - FXUtils.setLimitHeight(pane, 20); - - JFXRadioButton left = new JFXRadioButton(title); - left.setToggleGroup(group); - left.setUserData(userData); - pane.setLeft(left); - - Label right = new Label(subtitle); - right.setWrapText(true); - right.getStyleClass().add("subtitle-label"); - right.setStyle("-fx-font-size: 10;"); - pane.setRight(right); - - return pane; - } - - public void loadChildren(Collection list) { - pane.getChildren().setAll(list); - - if (hasCustom) - pane.getChildren().add(custom); - } - - public void loadChildren(Collection list, T customUserData) { - loadChildren(list); - setCustomUserData(customUserData); + public void loadChildren(Collection> options) { + pane.getChildren().setAll(options.stream() + .map(option -> option.createItem(group)) + .collect(Collectors.toList())); } public ToggleGroup getGroup() { return group; } - public String getCustomTitle() { - return customTitle.get(); - } - - public StringProperty customTitleProperty() { - return customTitle; - } - - public void setCustomTitle(String customTitle) { - this.customTitle.set(customTitle); - } - - public String getChooserTitle() { - return chooserTitle.get(); - } - - public StringProperty chooserTitleProperty() { - return chooserTitle; - } - - public void setChooserTitle(String chooserTitle) { - this.chooserTitle.set(chooserTitle); - } - - public void setCustomUserData(T userData) { - radioCustom.setUserData(userData); - } - - public boolean isCustomToggle(Toggle toggle) { - return radioCustom == toggle; - } - public void setToggleSelectedListener(Consumer consumer) { toggleSelectedListener = consumer; } - public StringProperty customTextProperty() { - return txtCustom.textProperty(); - } - - public String getCustomText() { - return txtCustom.getText(); - } - - public void setCustomText(String customText) { - txtCustom.setText(customText); - } - - public JFXTextField getTxtCustom() { - return txtCustom; - } - - public boolean isDirectory() { - return directory.get(); - } - - public BooleanProperty directoryProperty() { - return directory; - } - - public void setDirectory(boolean directory) { - this.directory.set(directory); - } - - public ObservableList getExtensionFilters() { - return extensionFilters; - } - public T getSelectedData() { return selectedData.get(); } @@ -263,4 +121,187 @@ public class MultiFileItem extends ComponentSublist { public void setFallbackData(T fallbackData) { this.fallbackData.set(fallbackData); } + + public static class Option { + protected final String title; + protected String subtitle; + protected final T data; + + public Option(String title, T data) { + this.title = title; this.data = data; + } + + public T getData() { + return data; + } + + public String getTitle() { + return title; + } + + public String getSubtitle() { + return subtitle; + } + + public Option setSubtitle(String subtitle) { + this.subtitle = subtitle; + return this; + } + + protected Node createItem(ToggleGroup group) { + BorderPane pane = new BorderPane(); + pane.setPadding(new Insets(3)); + FXUtils.setLimitHeight(pane, 30); + + JFXRadioButton left = new JFXRadioButton(title); + BorderPane.setAlignment(left, Pos.CENTER_LEFT); + left.setToggleGroup(group); + left.setUserData(data); + pane.setLeft(left); + + if (StringUtils.isNotBlank(subtitle)) { + Label right = new Label(subtitle); + BorderPane.setAlignment(right, Pos.CENTER_RIGHT); + right.setWrapText(true); + right.getStyleClass().add("subtitle-label"); + right.setStyle("-fx-font-size: 10;"); + pane.setRight(right); + } + + return pane; + } + } + + public static class StringOption extends Option { + private StringProperty value = new SimpleStringProperty(); + + public StringOption(String title, T data) { + super(title, data); + } + + public String getValue() { + return value.get(); + } + + public StringProperty valueProperty() { + return value; + } + + public void setValue(String value) { + this.value.set(value); + } + + public StringOption bindBidirectional(Property property) { + this.value.bindBidirectional(property); + return this; + } + + @Override + protected Node createItem(ToggleGroup group) { + BorderPane pane = new BorderPane(); + pane.setPadding(new Insets(3)); + FXUtils.setLimitHeight(pane, 30); + + JFXRadioButton left = new JFXRadioButton(title); + BorderPane.setAlignment(left, Pos.CENTER_LEFT); + left.setToggleGroup(group); + left.setUserData(data); + pane.setLeft(left); + + JFXTextField customField = new JFXTextField(); + BorderPane.setAlignment(customField, Pos.CENTER_RIGHT); + customField.textProperty().bindBidirectional(valueProperty()); + customField.disableProperty().bind(left.selectedProperty().not()); + pane.setRight(customField); + + return pane; + } + } + + public static class FileOption extends Option { + private StringProperty value = new SimpleStringProperty(); + private String chooserTitle = i18n("selector.choose_file"); + private boolean directory = false; + private final ObservableList extensionFilters = FXCollections.observableArrayList(); + + public FileOption(String title, T data) { + super(title, data); + } + + public String getValue() { + return value.get(); + } + + public StringProperty valueProperty() { + return value; + } + + public void setValue(String value) { + this.value.set(value); + } + + public FileOption setDirectory(boolean directory) { + this.directory = directory; + return this; + } + + public FileOption bindBidirectional(Property property) { + this.value.bindBidirectional(property); + return this; + } + + public FileOption setChooserTitle(String chooserTitle) { + this.chooserTitle = chooserTitle; + return this; + } + + public ObservableList getExtensionFilters() { + return extensionFilters; + } + + @Override + protected Node createItem(ToggleGroup group) { + BorderPane pane = new BorderPane(); + pane.setPadding(new Insets(3)); + FXUtils.setLimitHeight(pane, 30); + + JFXRadioButton left = new JFXRadioButton(title); + BorderPane.setAlignment(left, Pos.CENTER_LEFT); + left.setToggleGroup(group); + left.setUserData(data); + pane.setLeft(left); + + JFXTextField customField = new JFXTextField(); + customField.textProperty().bindBidirectional(valueProperty()); + customField.disableProperty().bind(left.selectedProperty().not()); + + JFXButton selectButton = new JFXButton(); + selectButton.disableProperty().bind(left.selectedProperty().not()); + selectButton.setGraphic(SVG.folderOpen(Theme.blackFillBinding(), 15, 15)); + selectButton.setOnMouseClicked(e -> { + if (directory) { + DirectoryChooser chooser = new DirectoryChooser(); + chooser.setTitle(chooserTitle); + File dir = chooser.showDialog(Controllers.getStage()); + if (dir != null) + customField.setText(dir.getAbsolutePath()); + } else { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters().addAll(getExtensionFilters()); + chooser.setTitle(chooserTitle); + File file = chooser.showOpenDialog(Controllers.getStage()); + if (file != null) + customField.setText(file.getAbsolutePath()); + } + }); + + HBox right = new HBox(); + right.setAlignment(Pos.CENTER_RIGHT); + BorderPane.setAlignment(right, Pos.CENTER_RIGHT); + right.setSpacing(3); + right.getChildren().addAll(customField, selectButton); + pane.setRight(right); + return pane; + } + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java index f341ab605..f6666fbb6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java @@ -137,6 +137,9 @@ public class DecoratorController { if (config().getBackgroundImageType() == EnumBackgroundImage.CUSTOM && config().getBackgroundImage() != null) { image = tryLoadImage(Paths.get(config().getBackgroundImage())) .orElse(null); + } + if (config().getBackgroundImageType() == EnumBackgroundImage.NETWORK) { + } if (image == null) { image = loadDefaultBackgroundImage(); 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 e2595fe5b..d89d6c21d 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 @@ -41,7 +41,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.util.javafx.SafeStringConverter; -import java.util.Collections; +import java.util.Arrays; import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -86,17 +86,19 @@ public class PersonalizationPage extends StackPane { { StackPane componentList = new StackPane(); - MultiFileItem backgroundItem = new MultiFileItem<>(true); + MultiFileItem backgroundItem = new MultiFileItem<>(); backgroundItem.setTitle(i18n("launcher.background")); - backgroundItem.setChooserTitle(i18n("launcher.background.choose")); backgroundItem.setHasSubtitle(true); - backgroundItem.setCustomText(i18n("settings.custom")); - backgroundItem.setStyle("-fx-padding: 8 0 0 0"); - backgroundItem.loadChildren(Collections.singletonList( - backgroundItem.createChildren(i18n("launcher.background.default"), EnumBackgroundImage.DEFAULT) - ), EnumBackgroundImage.CUSTOM); - backgroundItem.customTextProperty().bindBidirectional(config().backgroundImageProperty()); + backgroundItem.loadChildren(Arrays.asList( + new MultiFileItem.Option<>(i18n("launcher.background.default"), EnumBackgroundImage.DEFAULT), + new MultiFileItem.Option<>(i18n("launcher.background.classic"), EnumBackgroundImage.CLASSIC), + new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumBackgroundImage.CUSTOM) + .setChooserTitle(i18n("launcher.background.choose")) + .bindBidirectional(config().backgroundImageProperty()), + new MultiFileItem.StringOption<>(i18n("launcher.background.network"), EnumBackgroundImage.NETWORK) + .bindBidirectional(config().backgroundImageUrlProperty()) + )); backgroundItem.selectedDataProperty().bindBidirectional(config().backgroundImageTypeProperty()); backgroundItem.subtitleProperty().bind( new When(backgroundItem.selectedDataProperty().isEqualTo(EnumBackgroundImage.DEFAULT)) @@ -181,18 +183,9 @@ public class PersonalizationPage extends StackPane { hBox.setSpacing(3); FontComboBox cboFont = new FontComboBox(12); - cboFont.valueProperty().bindBidirectional(config().fontFamilyProperty()); + cboFont.valueProperty().bindBidirectional(config().launcherFontFamilyProperty()); - JFXTextField txtFontSize = new JFXTextField(); - FXUtils.setLimitWidth(txtFontSize, 50); - txtFontSize.textProperty().bindBidirectional(config().fontSizeProperty(), - SafeStringConverter.fromFiniteDouble() - .restrict(it -> it > 0) - .fallbackTo(12.0) - .asPredicate(Validator.addTo(txtFontSize))); - - - hBox.getChildren().setAll(cboFont, txtFontSize); + hBox.getChildren().setAll(cboFont); borderPane.setRight(hBox); } @@ -200,8 +193,8 @@ public class PersonalizationPage extends StackPane { Label lblFontDisplay = new Label("Hello Minecraft! Launcher"); lblFontDisplay.fontProperty().bind(Bindings.createObjectBinding( - () -> Font.font(config().getFontFamily(), config().getFontSize()), - config().fontFamilyProperty(), config().fontSizeProperty())); + () -> Font.font(config().getLauncherFontFamily(), 12), + config().launcherFontFamilyProperty())); vbox.getChildren().add(lblFontDisplay); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index d925a6f2d..55fa9f9fa 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -22,7 +22,6 @@ import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; import javafx.beans.binding.Bindings; import javafx.scene.control.ToggleGroup; -import org.jackhuang.hmcl.setting.EnumCommonDirectory; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; @@ -43,7 +42,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.Collections; import java.util.Optional; import java.util.logging.Level; @@ -65,11 +63,7 @@ public final class SettingsPage extends SettingsView { selectedItemPropertyFor(cboLanguage).bindBidirectional(config().localizationProperty()); // ==== - fileCommonLocation.loadChildren(Collections.singletonList( - fileCommonLocation.createChildren(i18n("launcher.cache_directory.default"), EnumCommonDirectory.DEFAULT) - ), EnumCommonDirectory.CUSTOM); fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty()); - fileCommonLocation.customTextProperty().bindBidirectional(config().commonDirectoryProperty()); fileCommonLocation.subtitleProperty().bind( Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.instance().getCommonDirectory()) .orElse(i18n("launcher.cache_directory.disabled")), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java index 2b0645110..93cff9c0d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java @@ -38,6 +38,8 @@ import org.jackhuang.hmcl.ui.construct.ComponentSublist; import org.jackhuang.hmcl.ui.construct.MultiFileItem; import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale; +import java.util.Arrays; + import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.ui.FXUtils.stringConverter; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -143,12 +145,16 @@ public abstract class SettingsView extends StackPane { } { - fileCommonLocation = new MultiFileItem<>(true); + fileCommonLocation = new MultiFileItem<>(); fileCommonLocation.setTitle(i18n("launcher.cache_directory")); - fileCommonLocation.setDirectory(true); - fileCommonLocation.setChooserTitle(i18n("launcher.cache_directory.choose")); fileCommonLocation.setHasSubtitle(true); - fileCommonLocation.setCustomText("settings.custom"); + fileCommonLocation.loadChildren(Arrays.asList( + new MultiFileItem.Option<>(i18n("launcher.cache_directory.default"), EnumCommonDirectory.DEFAULT), + new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumCommonDirectory.CUSTOM) + .setChooserTitle(i18n("launcher.cache_directory.choose")) + .setDirectory(true) + .bindBidirectional(config().commonDirectoryProperty()) + )); { JFXButton cleanButton = new JFXButton(i18n("launcher.cache_directory.clean")); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index 4dd6b45b5..5c5ac5092 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -56,6 +56,7 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -94,8 +95,11 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag private final JFXToggleButton chkUseNativeGLFW; private final JFXToggleButton chkUseNativeOpenAL; private final MultiFileItem javaItem; + private final MultiFileItem.FileOption javaCustomOption; private final MultiFileItem gameDirItem; + private final MultiFileItem.FileOption gameDirCustomOption; private final MultiFileItem nativesDirItem; + private final MultiFileItem.FileOption nativesDirCustomOption; private final JFXComboBox cboProcessPriority; private final JFXToggleButton chkShowLogs; private final ImagePickerItem iconPickerItem; @@ -154,19 +158,24 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag componentList = new ComponentList(); componentList.setDepth(1); - javaItem = new MultiFileItem<>(true); + javaItem = new MultiFileItem<>(); javaItem.setTitle(i18n("settings.game.java_directory")); - javaItem.setChooserTitle(i18n("settings.game.java_directory.choose")); javaItem.setHasSubtitle(true); - javaItem.setCustomText(i18n("settings.custom")); - javaItem.setDirectory(false); + javaCustomOption = new MultiFileItem.FileOption(i18n("settings.custom"), null) + .setChooserTitle(i18n("settings.game.java_directory.choose")); - gameDirItem = new MultiFileItem<>(true); + gameDirItem = new MultiFileItem<>(); gameDirItem.setTitle(i18n("settings.game.working_directory")); - gameDirItem.setChooserTitle(i18n("settings.game.working_directory.choose")); gameDirItem.setHasSubtitle(true); - gameDirItem.setCustomText(i18n("settings.custom")); - gameDirItem.setDirectory(true); + gameDirCustomOption = new MultiFileItem.FileOption<>(i18n("settings.custom"), GameDirectoryType.CUSTOM) + .setChooserTitle(i18n("settings.game.working_directory.choose")) + .setDirectory(true); + + gameDirItem.loadChildren(Arrays.asList( + new MultiFileItem.Option<>(i18n("settings.advanced.game_dir.default"), GameDirectoryType.ROOT_FOLDER), + new MultiFileItem.Option<>(i18n("settings.advanced.game_dir.independent"), GameDirectoryType.VERSION_FOLDER), + gameDirCustomOption + )); VBox maxMemoryPane = new VBox(8); { @@ -439,12 +448,16 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag ComponentList workaroundPane = new ComponentList(); workaroundPane.disableProperty().bind(chkEnableSpecificSettings.selectedProperty().not()); { - nativesDirItem = new MultiFileItem<>(true); + nativesDirItem = new MultiFileItem<>(); nativesDirItem.setTitle(i18n("settings.advanced.natives_directory")); - nativesDirItem.setChooserTitle(i18n("settings.advanced.natives_directory.choose")); nativesDirItem.setHasSubtitle(true); - nativesDirItem.setCustomText(i18n("settings.custom")); - nativesDirItem.setDirectory(true); + nativesDirCustomOption = new MultiFileItem.FileOption<>(i18n("settings.custom"), NativesDirectoryType.CUSTOM) + .setChooserTitle(i18n("settings.advanced.natives_directory.choose")) + .setDirectory(true); + nativesDirItem.loadChildren(Arrays.asList( + new MultiFileItem.Option<>(i18n("settings.advanced.natives_directory.default"), NativesDirectoryType.VERSION_FOLDER), + nativesDirCustomOption + )); BorderPane noJVMArgsPane = new BorderPane(); { @@ -534,10 +547,13 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag memoryStatusProperty.set(OperatingSystem.getPhysicalMemoryStatus().orElse(OperatingSystem.PhysicalMemoryStatus.INVALID)); Task.supplyAsync(JavaVersion::getJavas).thenAcceptAsync(Schedulers.javafx(), list -> { - javaItem.loadChildren(list.stream() - .map(javaVersion -> javaItem.createChildren(javaVersion.getVersion() + i18n("settings.game.java_directory.bit", - javaVersion.getPlatform().getBit()), javaVersion.getBinary().toString(), javaVersion)) - .collect(Collectors.toList())); + List> options = list.stream() + .map(javaVersion -> new MultiFileItem.Option<>(javaVersion.getVersion() + i18n("settings.game.java_directory.bit", + javaVersion.getPlatform().getBit()), javaVersion) + .setSubtitle(javaVersion.getBinary().toString())) + .collect(Collectors.toList()); + options.add(javaCustomOption); + javaItem.loadChildren(options); javaItemsLoaded = true; initializeSelectedJava(); }).start(); @@ -545,18 +561,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag javaItem.setSelectedData(null); javaItem.setFallbackData(JavaVersion.fromCurrentEnvironment()); if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) - javaItem.getExtensionFilters().add(new FileChooser.ExtensionFilter("Java", "java.exe", "javaw.exe")); - - gameDirItem.setCustomUserData(GameDirectoryType.CUSTOM); - gameDirItem.loadChildren(Arrays.asList( - gameDirItem.createChildren(i18n("settings.advanced.game_dir.default"), GameDirectoryType.ROOT_FOLDER), - gameDirItem.createChildren(i18n("settings.advanced.game_dir.independent"), GameDirectoryType.VERSION_FOLDER) - )); - - nativesDirItem.setCustomUserData(NativesDirectoryType.CUSTOM); - nativesDirItem.loadChildren(Arrays.asList( - nativesDirItem.createChildren(i18n("settings.advanced.natives_directory.default"), NativesDirectoryType.VERSION_FOLDER) - )); + javaCustomOption.getExtensionFilters().add(new FileChooser.ExtensionFilter("Java", "java.exe", "javaw.exe")); chkEnableSpecificSettings.selectedProperty().addListener((a, b, newValue) -> { if (versionId == null) return; @@ -597,9 +602,9 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag FXUtils.unbindInt(txtWidth, lastVersionSetting.widthProperty()); FXUtils.unbindInt(txtHeight, lastVersionSetting.heightProperty()); maxMemoryProperty.unbindBidirectional(lastVersionSetting.maxMemoryProperty()); - FXUtils.unbindString(javaItem.getTxtCustom(), lastVersionSetting.javaDirProperty()); - FXUtils.unbindString(gameDirItem.getTxtCustom(), lastVersionSetting.gameDirProperty()); - FXUtils.unbindString(nativesDirItem.getTxtCustom(), lastVersionSetting.nativesDirProperty()); + javaCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.javaDirProperty()); + gameDirCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.gameDirProperty()); + nativesDirCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.nativesDirProperty()); FXUtils.unbindString(txtJVMArgs, lastVersionSetting.javaArgsProperty()); FXUtils.unbindString(txtGameArgs, lastVersionSetting.minecraftArgsProperty()); FXUtils.unbindString(txtMetaspace, lastVersionSetting.permSizeProperty()); @@ -636,9 +641,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag FXUtils.bindInt(txtWidth, versionSetting.widthProperty()); FXUtils.bindInt(txtHeight, versionSetting.heightProperty()); maxMemoryProperty.bindBidirectional(versionSetting.maxMemoryProperty()); - FXUtils.bindString(javaItem.getTxtCustom(), versionSetting.javaDirProperty()); - FXUtils.bindString(gameDirItem.getTxtCustom(), versionSetting.gameDirProperty()); - FXUtils.bindString(nativesDirItem.getTxtCustom(), versionSetting.nativesDirProperty()); + + javaCustomOption.bindBidirectional(versionSetting.javaDirProperty()); + gameDirCustomOption.bindBidirectional(versionSetting.gameDirProperty()); + nativesDirCustomOption.bindBidirectional(versionSetting.nativesDirProperty()); FXUtils.bindString(txtJVMArgs, versionSetting.javaArgsProperty()); FXUtils.bindString(txtGameArgs, versionSetting.minecraftArgsProperty()); FXUtils.bindString(txtMetaspace, versionSetting.permSizeProperty()); @@ -661,7 +667,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag chkEnableSpecificSettings.setSelected(!versionSetting.isUsesGlobal()); javaItem.setToggleSelectedListener(newValue -> { - if (javaItem.isCustomToggle(newValue)) { + if (newValue.getUserData() == null) { versionSetting.setUsesCustomJavaDir(); } else { versionSetting.setJavaVersion((JavaVersion) newValue.getUserData()); @@ -695,7 +701,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag if (lastVersionSetting.isUsesCustomJavaDir()) { javaItem.getGroup().getToggles().stream() - .filter(javaItem::isCustomToggle) + .filter(java -> java.getUserData() == null) .findFirst().get() .setSelected(true); } else { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 48e79e526..d4aa8f7eb 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -402,8 +402,10 @@ launch.wrong_javadir=Invalid Java directory, default Java path will be applied. launcher=Launcher launcher.background=Background Image +launcher.background.classic=Classic launcher.background.choose=Choose a background image file launcher.background.default=Standard +launcher.background.network=Network launcher.cache_directory=Directory for caching launcher.cache_directory.clean=Clear launcher.cache_directory.choose=Choose the directory for caching diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 8aab153d9..cf36b5aee 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -403,7 +403,9 @@ launch.wrong_javadir=Java 路徑錯誤,將自動重設為預設 Java 路徑。 launcher=啟動器 launcher.background=背景位址 launcher.background.choose=選擇背景路徑 +launcher.background.classic=經典 launcher.background.default=預設(自動尋找啟動器同目錄下的 background.png/jpg 及 bg 資料夾內的圖片) +launcher.background.network=網路 launcher.cache_directory=檔案下載快取目錄 launcher.cache_directory.clean=清理 launcher.cache_directory.choose=選擇檔案下載快取目錄 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index bf4b495c1..277b014f2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -403,7 +403,9 @@ launch.wrong_javadir=错误的 Java 路径,将自动重置为默认 Java 路 launcher=启动器 launcher.background=背景地址 launcher.background.choose=选择背景路径 +launcher.background.classic=经典 launcher.background.default=默认(自动检索启动器同目录下的 background.png/jpg 及 bg 文件夹内的图片) +launcher.background.network=网络 launcher.cache_directory=文件下载缓存目录 launcher.cache_directory.clean=清理 launcher.cache_directory.choose=选择文件下载缓存目录