mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-18 16:26:05 -04:00
feat: multifileitem supports multiple custom type.
This commit is contained in:
parent
43236049ac
commit
ca3bc69a61
@ -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<EnumCommonDirectory> 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();
|
||||
}
|
||||
|
@ -19,5 +19,7 @@ package org.jackhuang.hmcl.setting;
|
||||
|
||||
public enum EnumBackgroundImage {
|
||||
DEFAULT,
|
||||
CUSTOM
|
||||
CUSTOM,
|
||||
CLASSIC,
|
||||
NETWORK
|
||||
}
|
||||
|
@ -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<T> 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<T> selectedData = new SimpleObjectProperty<>(this, "selectedData");
|
||||
private final ObjectProperty<T> fallbackData = new SimpleObjectProperty<>(this, "fallbackData");
|
||||
private final ObservableList<FileChooser.ExtensionFilter> 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<Toggle> 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<T> 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<Node> list) {
|
||||
pane.getChildren().setAll(list);
|
||||
|
||||
if (hasCustom)
|
||||
pane.getChildren().add(custom);
|
||||
}
|
||||
|
||||
public void loadChildren(Collection<Node> list, T customUserData) {
|
||||
loadChildren(list);
|
||||
setCustomUserData(customUserData);
|
||||
public void loadChildren(Collection<Option<T>> 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<Toggle> 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<FileChooser.ExtensionFilter> getExtensionFilters() {
|
||||
return extensionFilters;
|
||||
}
|
||||
|
||||
public T getSelectedData() {
|
||||
return selectedData.get();
|
||||
}
|
||||
@ -263,4 +121,187 @@ public class MultiFileItem<T> extends ComponentSublist {
|
||||
public void setFallbackData(T fallbackData) {
|
||||
this.fallbackData.set(fallbackData);
|
||||
}
|
||||
|
||||
public static class Option<T> {
|
||||
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<T> 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<T> extends Option<T> {
|
||||
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<T> bindBidirectional(Property<String> 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<T> extends Option<T> {
|
||||
private StringProperty value = new SimpleStringProperty();
|
||||
private String chooserTitle = i18n("selector.choose_file");
|
||||
private boolean directory = false;
|
||||
private final ObservableList<FileChooser.ExtensionFilter> 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<T> setDirectory(boolean directory) {
|
||||
this.directory = directory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileOption<T> bindBidirectional(Property<String> property) {
|
||||
this.value.bindBidirectional(property);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileOption<T> setChooserTitle(String chooserTitle) {
|
||||
this.chooserTitle = chooserTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObservableList<FileChooser.ExtensionFilter> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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<EnumBackgroundImage> backgroundItem = new MultiFileItem<>(true);
|
||||
MultiFileItem<EnumBackgroundImage> 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);
|
||||
|
||||
|
@ -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")),
|
||||
|
@ -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"));
|
||||
|
@ -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<JavaVersion> javaItem;
|
||||
private final MultiFileItem.FileOption<JavaVersion> javaCustomOption;
|
||||
private final MultiFileItem<GameDirectoryType> gameDirItem;
|
||||
private final MultiFileItem.FileOption<GameDirectoryType> gameDirCustomOption;
|
||||
private final MultiFileItem<NativesDirectoryType> nativesDirItem;
|
||||
private final MultiFileItem.FileOption<NativesDirectoryType> nativesDirCustomOption;
|
||||
private final JFXComboBox<ProcessPriority> 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<JavaVersion>(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<MultiFileItem.Option<JavaVersion>> 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 {
|
||||
|
@ -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
|
||||
|
@ -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=選擇檔案下載快取目錄
|
||||
|
@ -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=选择文件下载缓存目录
|
||||
|
Loading…
x
Reference in New Issue
Block a user