使用 LineComponent 简化代码 (#5408)
This commit is contained in:
@@ -1,162 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher
|
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.jackhuang.hmcl.ui.construct;
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
|
||||||
import javafx.beans.property.StringProperty;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.layout.BorderPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.stage.DirectoryChooser;
|
|
||||||
import org.jackhuang.hmcl.Metadata;
|
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.InvalidPathException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
|
||||||
|
|
||||||
public class FileItem extends BorderPane {
|
|
||||||
private final Label lblPath = new Label();
|
|
||||||
|
|
||||||
private final SimpleStringProperty name = new SimpleStringProperty(this, "name");
|
|
||||||
private final SimpleStringProperty title = new SimpleStringProperty(this, "title");
|
|
||||||
private final SimpleStringProperty path = new SimpleStringProperty(this, "path");
|
|
||||||
private final SimpleBooleanProperty convertToRelativePath = new SimpleBooleanProperty(this, "convertToRelativePath");
|
|
||||||
|
|
||||||
public FileItem() {
|
|
||||||
VBox left = new VBox();
|
|
||||||
Label name = new Label();
|
|
||||||
name.textProperty().bind(nameProperty());
|
|
||||||
lblPath.getStyleClass().addAll("subtitle-label");
|
|
||||||
lblPath.textProperty().bind(path);
|
|
||||||
left.getChildren().addAll(name, lblPath);
|
|
||||||
setLeft(left);
|
|
||||||
|
|
||||||
JFXButton right = new JFXButton();
|
|
||||||
right.setGraphic(SVG.EDIT.createIcon(16));
|
|
||||||
right.getStyleClass().add("toggle-icon4");
|
|
||||||
right.setOnAction(e -> onExplore());
|
|
||||||
FXUtils.installFastTooltip(right, i18n("button.edit"));
|
|
||||||
setRight(right);
|
|
||||||
|
|
||||||
convertToRelativePath.addListener(onInvalidating(() -> path.set(processPath(path.get()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the given path to absolute/relative(if possible) path according to {@link #convertToRelativePathProperty()}.
|
|
||||||
*/
|
|
||||||
private String processPath(String path) {
|
|
||||||
Path given;
|
|
||||||
try {
|
|
||||||
given = Path.of(path).toAbsolutePath().normalize();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isConvertToRelativePath()) {
|
|
||||||
try {
|
|
||||||
return Metadata.CURRENT_DIRECTORY.relativize(given).normalize().toString();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// the given path can't be relativized against current path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return given.normalize().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onExplore() {
|
|
||||||
DirectoryChooser chooser = new DirectoryChooser();
|
|
||||||
if (path.get() != null) {
|
|
||||||
Path file;
|
|
||||||
try {
|
|
||||||
file = Path.of(path.get());
|
|
||||||
if (Files.exists(file)) {
|
|
||||||
if (Files.isRegularFile(file))
|
|
||||||
file = file.toAbsolutePath().normalize().getParent();
|
|
||||||
else if (Files.isDirectory(file))
|
|
||||||
file = file.toAbsolutePath().normalize();
|
|
||||||
chooser.setInitialDirectory(file.toFile());
|
|
||||||
}
|
|
||||||
} catch (InvalidPathException e) {
|
|
||||||
LOG.warning("Failed to resolve path: " + path.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chooser.titleProperty().bind(titleProperty());
|
|
||||||
var selectedDir = chooser.showDialog(Controllers.getStage());
|
|
||||||
if (selectedDir != null) {
|
|
||||||
path.set(processPath(selectedDir.toString()));
|
|
||||||
}
|
|
||||||
chooser.titleProperty().unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringProperty nameProperty() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name.set(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return title.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringProperty titleProperty() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(String title) {
|
|
||||||
this.title.set(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPath() {
|
|
||||||
return path.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringProperty pathProperty() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPath(String path) {
|
|
||||||
this.path.set(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConvertToRelativePath() {
|
|
||||||
return convertToRelativePath.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanProperty convertToRelativePathProperty() {
|
|
||||||
return convertToRelativePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConvertToRelativePath(boolean convertToRelativePath) {
|
|
||||||
this.convertToRelativePath.set(convertToRelativePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2026 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.ui.construct;
|
||||||
|
|
||||||
|
import javafx.beans.property.*;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.stage.DirectoryChooser;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
|
public class LineFileChooserButton extends LineButton {
|
||||||
|
private static final String DEFAULT_STYLE_CLASS = "line-file-select-button";
|
||||||
|
|
||||||
|
public LineFileChooserButton() {
|
||||||
|
getStyleClass().add(DEFAULT_STYLE_CLASS);
|
||||||
|
setTrailingIcon(SVG.EDIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the given path to absolute/relative(if possible) path according to [#convertToRelativePathProperty()].
|
||||||
|
private String processPath(Path path) {
|
||||||
|
if (isConvertToRelativePath() && path.isAbsolute()) {
|
||||||
|
try {
|
||||||
|
return Metadata.CURRENT_DIRECTORY.relativize(path).normalize().toString();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// the given path can't be relativized against current path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path.normalize().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fire() {
|
||||||
|
super.fire();
|
||||||
|
|
||||||
|
Stage owner = Controllers.getStage(); // TODO: Allow user to set owner stage
|
||||||
|
String windowTitle = getFileChooserTitle();
|
||||||
|
|
||||||
|
Path initialDirectory = null;
|
||||||
|
if (getLocation() != null) {
|
||||||
|
Path file;
|
||||||
|
try {
|
||||||
|
file = FileUtils.toAbsolute(Path.of(getLocation()));
|
||||||
|
if (Files.exists(file)) {
|
||||||
|
if (Files.isRegularFile(file))
|
||||||
|
initialDirectory = file.getParent();
|
||||||
|
else if (Files.isDirectory(file))
|
||||||
|
initialDirectory = file;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOG.warning("Failed to resolve path: " + getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Path path;
|
||||||
|
Type type = getType();
|
||||||
|
if (type == Type.OPEN_DIRECTORY) {
|
||||||
|
var directoryChooser = new DirectoryChooser();
|
||||||
|
if (windowTitle != null)
|
||||||
|
directoryChooser.setTitle(windowTitle);
|
||||||
|
if (initialDirectory != null)
|
||||||
|
directoryChooser.setInitialDirectory(initialDirectory.toFile());
|
||||||
|
|
||||||
|
path = FileUtils.toPath(directoryChooser.showDialog(owner));
|
||||||
|
} else {
|
||||||
|
var fileChooser = new FileChooser();
|
||||||
|
if (windowTitle != null)
|
||||||
|
fileChooser.setTitle(windowTitle);
|
||||||
|
if (initialDirectory != null)
|
||||||
|
fileChooser.setInitialDirectory(initialDirectory.toFile());
|
||||||
|
|
||||||
|
if (extensionFilters != null)
|
||||||
|
fileChooser.getExtensionFilters().setAll(extensionFilters);
|
||||||
|
|
||||||
|
fileChooser.setInitialFileName(getInitialFileName());
|
||||||
|
|
||||||
|
path = FileUtils.toPath(switch (type) {
|
||||||
|
case OPEN_FILE -> fileChooser.showOpenDialog(owner);
|
||||||
|
case SAVE_FILE -> fileChooser.showSaveDialog(owner);
|
||||||
|
default -> throw new AssertionError("Unknown Type: " + type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path != null) {
|
||||||
|
setLocation(processPath(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final StringProperty location = new StringPropertyBase() {
|
||||||
|
@Override
|
||||||
|
public Object getBean() {
|
||||||
|
return LineFileChooserButton.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "location";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invalidated() {
|
||||||
|
setTrailingText(get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public StringProperty locationProperty() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return locationProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(String location) {
|
||||||
|
locationProperty().set(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final StringProperty fileChooserTitle = new SimpleStringProperty(this, "fileChooserTitle");
|
||||||
|
|
||||||
|
public StringProperty fileChooserTitleProperty() {
|
||||||
|
return fileChooserTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileChooserTitle() {
|
||||||
|
return fileChooserTitleProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileChooserTitle(String fileChooserTitle) {
|
||||||
|
fileChooserTitleProperty().set(fileChooserTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObjectProperty<Type> type;
|
||||||
|
|
||||||
|
public ObjectProperty<Type> typeProperty() {
|
||||||
|
if (type == null) {
|
||||||
|
type = new SimpleObjectProperty<>(this, "type", Type.OPEN_FILE);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return type != null ? type.get() : Type.OPEN_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
typeProperty().set(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObjectProperty<String> initialFileName;
|
||||||
|
|
||||||
|
public final ObjectProperty<String> initialFileNameProperty() {
|
||||||
|
if (initialFileName == null)
|
||||||
|
initialFileName = new SimpleObjectProperty<>(this, "initialFileName");
|
||||||
|
|
||||||
|
return initialFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getInitialFileName() {
|
||||||
|
return initialFileName != null ? initialFileName.get() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setInitialFileName(String value) {
|
||||||
|
initialFileNameProperty().set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableList<FileChooser.ExtensionFilter> extensionFilters;
|
||||||
|
|
||||||
|
public ObservableList<FileChooser.ExtensionFilter> getExtensionFilters() {
|
||||||
|
if (extensionFilters == null)
|
||||||
|
extensionFilters = FXCollections.observableArrayList();
|
||||||
|
return extensionFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BooleanProperty convertToRelativePath;
|
||||||
|
|
||||||
|
public BooleanProperty convertToRelativePathProperty() {
|
||||||
|
if (convertToRelativePath == null)
|
||||||
|
convertToRelativePath = new BooleanPropertyBase(false) {
|
||||||
|
@Override
|
||||||
|
public Object getBean() {
|
||||||
|
return LineFileChooserButton.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "convertToRelativePath";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invalidated() {
|
||||||
|
String location = getLocation();
|
||||||
|
if (location == null)
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
setLocation(processPath(FileUtils.toAbsolute(Path.of(getLocation()))));
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return convertToRelativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConvertToRelativePath() {
|
||||||
|
return convertToRelativePath != null && convertToRelativePath.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertToRelativePath(boolean convertToRelativePath) {
|
||||||
|
convertToRelativePathProperty().set(convertToRelativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
OPEN_FILE,
|
||||||
|
OPEN_DIRECTORY,
|
||||||
|
SAVE_FILE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,7 +107,7 @@ public final class LocalModpackPage extends ModpackPage {
|
|||||||
.whenComplete(Schedulers.javafx(), (manifest, exception) -> {
|
.whenComplete(Schedulers.javafx(), (manifest, exception) -> {
|
||||||
if (exception instanceof ManuallyCreatedModpackException) {
|
if (exception instanceof ManuallyCreatedModpackException) {
|
||||||
hideSpinner();
|
hideSpinner();
|
||||||
lblName.setText(FileUtils.getName(selectedFile));
|
nameProperty.set(FileUtils.getName(selectedFile));
|
||||||
installAsVersion.set(false);
|
installAsVersion.set(false);
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
@@ -127,9 +127,9 @@ public final class LocalModpackPage extends ModpackPage {
|
|||||||
} else {
|
} else {
|
||||||
hideSpinner();
|
hideSpinner();
|
||||||
controller.getSettings().put(MODPACK_MANIFEST, manifest);
|
controller.getSettings().put(MODPACK_MANIFEST, manifest);
|
||||||
lblName.setText(manifest.getName());
|
nameProperty.set(manifest.getName());
|
||||||
lblVersion.setText(manifest.getVersion());
|
versionProperty.set(manifest.getVersion());
|
||||||
lblAuthor.setText(manifest.getAuthor());
|
authorProperty.set(manifest.getAuthor());
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
// trim: https://github.com/HMCL-dev/HMCL/issues/962
|
// trim: https://github.com/HMCL-dev/HMCL/issues/962
|
||||||
|
|||||||
@@ -2,14 +2,15 @@ package org.jackhuang.hmcl.ui.download;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
import javafx.geometry.Insets;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.LinePane;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.LineTextPane;
|
||||||
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
||||||
@@ -23,9 +24,9 @@ public abstract class ModpackPage extends SpinnerPane implements WizardPage {
|
|||||||
|
|
||||||
protected final WizardController controller;
|
protected final WizardController controller;
|
||||||
|
|
||||||
protected final Label lblName;
|
protected final StringProperty nameProperty;
|
||||||
protected final Label lblVersion;
|
protected final StringProperty versionProperty;
|
||||||
protected final Label lblAuthor;
|
protected final StringProperty authorProperty;
|
||||||
protected final JFXTextField txtModpackName;
|
protected final JFXTextField txtModpackName;
|
||||||
protected final JFXButton btnInstall;
|
protected final JFXButton btnInstall;
|
||||||
protected final JFXButton btnDescription;
|
protected final JFXButton btnDescription;
|
||||||
@@ -39,46 +40,37 @@ public abstract class ModpackPage extends SpinnerPane implements WizardPage {
|
|||||||
|
|
||||||
ComponentList componentList = new ComponentList();
|
ComponentList componentList = new ComponentList();
|
||||||
{
|
{
|
||||||
BorderPane archiveNamePane = new BorderPane();
|
var archiveNamePane = new LinePane();
|
||||||
{
|
{
|
||||||
Label label = new Label(i18n("archive.file.name"));
|
archiveNamePane.setTitle(i18n("archive.file.name"));
|
||||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
|
||||||
archiveNamePane.setLeft(label);
|
|
||||||
|
|
||||||
txtModpackName = new JFXTextField();
|
txtModpackName = new JFXTextField();
|
||||||
BorderPane.setMargin(txtModpackName, new Insets(0, 0, 8, 32));
|
txtModpackName.setPrefWidth(300);
|
||||||
|
// FIXME: Validator are not shown properly
|
||||||
|
// BorderPane.setMargin(txtModpackName, new Insets(0, 0, 8, 32));
|
||||||
BorderPane.setAlignment(txtModpackName, Pos.CENTER_RIGHT);
|
BorderPane.setAlignment(txtModpackName, Pos.CENTER_RIGHT);
|
||||||
archiveNamePane.setCenter(txtModpackName);
|
archiveNamePane.setRight(txtModpackName);
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderPane modpackNamePane = new BorderPane();
|
var modpackNamePane = new LineTextPane();
|
||||||
{
|
{
|
||||||
modpackNamePane.setLeft(new Label(i18n("modpack.name")));
|
modpackNamePane.setTitle(i18n("modpack.name"));
|
||||||
|
nameProperty = modpackNamePane.textProperty();
|
||||||
lblName = new Label();
|
|
||||||
BorderPane.setAlignment(lblName, Pos.CENTER_RIGHT);
|
|
||||||
modpackNamePane.setCenter(lblName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderPane versionPane = new BorderPane();
|
var versionPane = new LineTextPane();
|
||||||
{
|
{
|
||||||
versionPane.setLeft(new Label(i18n("archive.version")));
|
versionPane.setTitle(i18n("archive.version"));
|
||||||
|
versionProperty = versionPane.textProperty();
|
||||||
lblVersion = new Label();
|
|
||||||
BorderPane.setAlignment(lblVersion, Pos.CENTER_RIGHT);
|
|
||||||
versionPane.setCenter(lblVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderPane authorPane = new BorderPane();
|
var authorPane = new LineTextPane();
|
||||||
{
|
{
|
||||||
authorPane.setLeft(new Label(i18n("archive.author")));
|
authorPane.setTitle(i18n("archive.author"));
|
||||||
|
authorProperty = authorPane.textProperty();
|
||||||
lblAuthor = new Label();
|
|
||||||
BorderPane.setAlignment(lblAuthor, Pos.CENTER_RIGHT);
|
|
||||||
authorPane.setCenter(lblAuthor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderPane descriptionPane = new BorderPane();
|
var descriptionPane = new BorderPane();
|
||||||
{
|
{
|
||||||
btnDescription = FXUtils.newBorderButton(i18n("modpack.description"));
|
btnDescription = FXUtils.newBorderButton(i18n("modpack.description"));
|
||||||
btnDescription.setOnAction(e -> onDescribe());
|
btnDescription.setOnAction(e -> onDescribe());
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ public final class RemoteModpackPage extends ModpackPage {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lblName.setText(manifest.getName());
|
nameProperty.set(manifest.getName());
|
||||||
lblVersion.setText(manifest.getVersion());
|
versionProperty.set(manifest.getVersion());
|
||||||
lblAuthor.setText(manifest.getAuthor());
|
authorProperty.set(manifest.getAuthor());
|
||||||
|
|
||||||
Profile profile = controller.getSettings().get(ModpackPage.PROFILE);
|
Profile profile = controller.getSettings().get(ModpackPage.PROFILE);
|
||||||
String name = controller.getSettings().get(MODPACK_NAME);
|
String name = controller.getSettings().get(MODPACK_NAME);
|
||||||
|
|||||||
@@ -17,7 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui.export;
|
package org.jackhuang.hmcl.ui.export;
|
||||||
|
|
||||||
import com.jfoenix.controls.*;
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXSlider;
|
||||||
|
import com.jfoenix.controls.JFXTextArea;
|
||||||
|
import com.jfoenix.controls.JFXTextField;
|
||||||
|
import com.jfoenix.validation.base.ValidatorBase;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@@ -53,8 +57,6 @@ import java.util.*;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.jfxListCellFactory;
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
|
|
||||||
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE;
|
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE;
|
||||||
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_MODRINTH;
|
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_MODRINTH;
|
||||||
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_SERVER;
|
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_SERVER;
|
||||||
@@ -127,7 +129,6 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
exportInfo.setVersion(version.get());
|
exportInfo.setVersion(version.get());
|
||||||
exportInfo.setAuthor(author.get());
|
exportInfo.setAuthor(author.get());
|
||||||
exportInfo.setDescription(description.get());
|
exportInfo.setDescription(description.get());
|
||||||
exportInfo.setPackWithLauncher(packWithLauncher.get());
|
|
||||||
exportInfo.setUrl(url.get());
|
exportInfo.setUrl(url.get());
|
||||||
exportInfo.setForceUpdate(forceUpdate.get());
|
exportInfo.setForceUpdate(forceUpdate.get());
|
||||||
exportInfo.setPackWithLauncher(packWithLauncher.get());
|
exportInfo.setPackWithLauncher(packWithLauncher.get());
|
||||||
@@ -171,10 +172,11 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
public static class ModpackInfoPageSkin extends SkinBase<ModpackInfoPage> {
|
public static class ModpackInfoPageSkin extends SkinBase<ModpackInfoPage> {
|
||||||
private ObservableList<Node> originList;
|
private ObservableList<Node> originList;
|
||||||
|
|
||||||
|
private final List<JFXTextField> validatingFields = new ArrayList<>();
|
||||||
|
|
||||||
public ModpackInfoPageSkin(ModpackInfoPage skinnable) {
|
public ModpackInfoPageSkin(ModpackInfoPage skinnable) {
|
||||||
super(skinnable);
|
super(skinnable);
|
||||||
|
|
||||||
Insets insets = new Insets(5, 0, 12, 0);
|
|
||||||
Insets componentListMargin = new Insets(16, 0, 16, 0);
|
Insets componentListMargin = new Insets(16, 0, 16, 0);
|
||||||
|
|
||||||
ScrollPane scroll = new ScrollPane();
|
ScrollPane scroll = new ScrollPane();
|
||||||
@@ -182,7 +184,6 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
scroll.setFitToHeight(true);
|
scroll.setFitToHeight(true);
|
||||||
getChildren().setAll(scroll);
|
getChildren().setAll(scroll);
|
||||||
|
|
||||||
List<JFXTextField> validatingFields = new ArrayList<>();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
BorderPane borderPane = new BorderPane();
|
BorderPane borderPane = new BorderPane();
|
||||||
@@ -209,83 +210,52 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
BorderPane.setMargin(list, componentListMargin);
|
BorderPane.setMargin(list, componentListMargin);
|
||||||
borderPane.setCenter(list);
|
borderPane.setCenter(list);
|
||||||
|
|
||||||
|
var instanceNamePane = new LineTextPane();
|
||||||
{
|
{
|
||||||
BorderPane borderPane1 = new BorderPane();
|
instanceNamePane.setTitle(i18n("modpack.wizard.step.initialization.exported_version"));
|
||||||
borderPane1.setLeft(new Label(i18n("modpack.wizard.step.initialization.exported_version")));
|
instanceNamePane.setText(skinnable.versionName);
|
||||||
|
|
||||||
Label versionNameLabel = new Label();
|
list.getContent().add(instanceNamePane);
|
||||||
versionNameLabel.setText(skinnable.versionName);
|
|
||||||
borderPane1.setRight(versionNameLabel);
|
|
||||||
list.getContent().add(borderPane1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
GridPane pane = new GridPane();
|
|
||||||
list.getContent().add(pane);
|
|
||||||
pane.setHgap(16);
|
|
||||||
pane.setVgap(8);
|
|
||||||
pane.getColumnConstraints().setAll(new ColumnConstraints(), FXUtils.getColumnHgrowing());
|
|
||||||
|
|
||||||
int rowIndex = 0;
|
list.getContent().addAll(
|
||||||
|
createTextFieldLinePane(i18n("modpack.name"), skinnable.name, new RequiredValidator()),
|
||||||
|
createTextFieldLinePane(i18n("archive.author"), skinnable.author, new RequiredValidator()),
|
||||||
|
createTextFieldLinePane(i18n("archive.version"), skinnable.version, new RequiredValidator())
|
||||||
|
);
|
||||||
|
|
||||||
JFXTextField txtModpackName = new JFXTextField();
|
if (skinnable.options.isRequireFileApi()) {
|
||||||
txtModpackName.textProperty().bindBidirectional(skinnable.name);
|
list.getContent().add(createTextFieldLinePane(
|
||||||
txtModpackName.getValidators().add(new RequiredValidator());
|
i18n("modpack.file_api"), skinnable.fileApi,
|
||||||
validatingFields.add(txtModpackName);
|
skinnable.options.isValidateFileApi() ? new RequiredValidator() : null,
|
||||||
pane.addRow(rowIndex++, new Label(i18n("modpack.name")), txtModpackName);
|
new URLValidator(true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
JFXTextField txtModpackAuthor = new JFXTextField();
|
if (skinnable.options.isRequireLaunchArguments()) {
|
||||||
txtModpackAuthor.textProperty().bindBidirectional(skinnable.author);
|
list.getContent().add(createTextFieldLinePane(
|
||||||
txtModpackAuthor.getValidators().add(new RequiredValidator());
|
i18n("settings.advanced.minecraft_arguments"), skinnable.launchArguments
|
||||||
validatingFields.add(txtModpackAuthor);
|
));
|
||||||
pane.addRow(rowIndex++, new Label(i18n("archive.author")), txtModpackAuthor);
|
}
|
||||||
|
|
||||||
JFXTextField txtModpackVersion = new JFXTextField();
|
if (skinnable.options.isRequireJavaArguments()) {
|
||||||
txtModpackVersion.textProperty().bindBidirectional(skinnable.version);
|
list.getContent().add(createTextFieldLinePane(
|
||||||
txtModpackVersion.getValidators().add(new RequiredValidator());
|
i18n("settings.advanced.jvm_args"), skinnable.javaArguments
|
||||||
validatingFields.add(txtModpackVersion);
|
));
|
||||||
pane.addRow(rowIndex++, new Label(i18n("archive.version")), txtModpackVersion);
|
}
|
||||||
|
|
||||||
if (skinnable.options.isRequireFileApi()) {
|
if (skinnable.options.isRequireUrl()) {
|
||||||
JFXTextField txtModpackFileApi = new JFXTextField();
|
list.getContent().add(createTextFieldLinePane(
|
||||||
txtModpackFileApi.textProperty().bindBidirectional(skinnable.fileApi);
|
i18n("modpack.origin.url"), skinnable.url
|
||||||
validatingFields.add(txtModpackFileApi);
|
));
|
||||||
|
}
|
||||||
if (skinnable.options.isValidateFileApi()) {
|
|
||||||
txtModpackFileApi.getValidators().add(new RequiredValidator());
|
|
||||||
}
|
|
||||||
|
|
||||||
txtModpackFileApi.getValidators().add(new URLValidator(true));
|
|
||||||
pane.addRow(rowIndex++, new Label(i18n("modpack.file_api")), txtModpackFileApi);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skinnable.options.isRequireLaunchArguments()) {
|
|
||||||
JFXTextField txtLaunchArguments = new JFXTextField();
|
|
||||||
txtLaunchArguments.textProperty().bindBidirectional(skinnable.launchArguments);
|
|
||||||
pane.addRow(rowIndex++, new Label(i18n("settings.advanced.minecraft_arguments")), txtLaunchArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skinnable.options.isRequireJavaArguments()) {
|
|
||||||
JFXTextField txtJavaArguments = new JFXTextField();
|
|
||||||
txtJavaArguments.textProperty().bindBidirectional(skinnable.javaArguments);
|
|
||||||
pane.addRow(rowIndex++, new Label(i18n("settings.advanced.jvm_args")), txtJavaArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skinnable.options.isRequireUrl()) {
|
|
||||||
JFXTextField txtModpackUrl = new JFXTextField();
|
|
||||||
txtModpackUrl.textProperty().bindBidirectional(skinnable.url);
|
|
||||||
pane.addRow(rowIndex++, new Label(i18n("modpack.origin.url")), txtModpackUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skinnable.options.isRequireOrigins()) {
|
|
||||||
JFXTextField txtMcbbs = new JFXTextField();
|
|
||||||
FXUtils.setValidateWhileTextChanged(txtMcbbs, true);
|
|
||||||
txtMcbbs.getValidators().add(new NumberValidator(i18n("input.number"), true));
|
|
||||||
txtMcbbs.textProperty().bindBidirectional(skinnable.mcbbsThreadId);
|
|
||||||
validatingFields.add(txtMcbbs);
|
|
||||||
pane.addRow(rowIndex++, new Label(i18n("modpack.origin.mcbbs")), txtMcbbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (skinnable.options.isRequireOrigins()) {
|
||||||
|
list.getContent().add(createTextFieldLinePane(
|
||||||
|
i18n("modpack.origin.mcbbs"), skinnable.mcbbsThreadId,
|
||||||
|
new NumberValidator(i18n("input.number"), true)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skinnable.options.isRequireMinMemory()) {
|
if (skinnable.options.isRequireMinMemory()) {
|
||||||
@@ -339,78 +309,51 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (skinnable.options.isRequireAuthlibInjectorServer()) {
|
if (skinnable.options.isRequireAuthlibInjectorServer()) {
|
||||||
JFXComboBox<AuthlibInjectorServer> cboServers = new JFXComboBox<>();
|
var serversSelectButton = new LineSelectButton<AuthlibInjectorServer>();
|
||||||
cboServers.setMaxWidth(Double.MAX_VALUE);
|
serversSelectButton.setTitle(i18n("account.injector.server"));
|
||||||
cboServers.setCellFactory(jfxListCellFactory(server -> new TwoLineListItem(server.getName(), server.getUrl())));
|
serversSelectButton.setConverter(AuthlibInjectorServer::getName);
|
||||||
cboServers.setConverter(stringConverter(AuthlibInjectorServer::getName));
|
serversSelectButton.setDescriptionConverter(AuthlibInjectorServer::getUrl);
|
||||||
Bindings.bindContent(cboServers.getItems(), config().getAuthlibInjectorServers());
|
serversSelectButton.itemsProperty().set(config().getAuthlibInjectorServers());
|
||||||
|
|
||||||
skinnable.authlibInjectorServer.bind(Bindings.createStringBinding(() ->
|
skinnable.authlibInjectorServer.bind(Bindings.createStringBinding(() -> {
|
||||||
Optional.ofNullable(cboServers.getSelectionModel().getSelectedItem())
|
AuthlibInjectorServer selected = serversSelectButton.getValue();
|
||||||
.map(AuthlibInjectorServer::getUrl)
|
return selected != null ? selected.getUrl() : null;
|
||||||
.orElse(null)));
|
}, serversSelectButton.valueProperty()));
|
||||||
|
|
||||||
BorderPane pane = new BorderPane();
|
list.getContent().add(serversSelectButton);
|
||||||
|
|
||||||
Label left = new Label(i18n("account.injector.server"));
|
|
||||||
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
|
|
||||||
pane.setLeft(left);
|
|
||||||
pane.setRight(cboServers);
|
|
||||||
|
|
||||||
list.getContent().add(pane);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skinnable.options.isRequireForceUpdate()) {
|
if (skinnable.options.isRequireForceUpdate()) {
|
||||||
BorderPane pane = new BorderPane();
|
var requireForceUpdateButton = new LineToggleButton();
|
||||||
pane.setLeft(new Label(i18n("modpack.wizard.step.initialization.force_update")));
|
requireForceUpdateButton.setTitle(i18n("modpack.wizard.step.initialization.force_update"));
|
||||||
list.getContent().add(pane);
|
requireForceUpdateButton.selectedProperty().bindBidirectional(skinnable.forceUpdate);
|
||||||
|
|
||||||
JFXToggleButton button = new JFXToggleButton();
|
list.getContent().add(requireForceUpdateButton);
|
||||||
button.selectedProperty().bindBidirectional(skinnable.forceUpdate);
|
|
||||||
button.setSize(8);
|
|
||||||
button.setMinHeight(16);
|
|
||||||
button.setMaxHeight(16);
|
|
||||||
pane.setRight(button);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
BorderPane pane = new BorderPane();
|
var canIncludeLauncherButton = new LineToggleButton();
|
||||||
pane.setLeft(new Label(i18n("modpack.wizard.step.initialization.include_launcher")));
|
canIncludeLauncherButton.setTitle(i18n("modpack.wizard.step.initialization.include_launcher"));
|
||||||
list.getContent().add(pane);
|
canIncludeLauncherButton.setDisable(!skinnable.canIncludeLauncher);
|
||||||
|
canIncludeLauncherButton.selectedProperty().bindBidirectional(skinnable.packWithLauncher);
|
||||||
|
|
||||||
JFXToggleButton button = new JFXToggleButton();
|
list.getContent().add(canIncludeLauncherButton);
|
||||||
button.setDisable(!skinnable.canIncludeLauncher);
|
|
||||||
button.selectedProperty().bindBidirectional(skinnable.packWithLauncher);
|
|
||||||
button.setSize(8);
|
|
||||||
button.setMinHeight(16);
|
|
||||||
button.setMaxHeight(16);
|
|
||||||
pane.setRight(button);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skinnable.options.isRequireNoCreateRemoteFiles()) {
|
if (skinnable.options.isRequireNoCreateRemoteFiles()) {
|
||||||
BorderPane noCreateRemoteFiles = new BorderPane();
|
var requireNoCreateRemoteFilesButton = new LineToggleButton();
|
||||||
noCreateRemoteFiles.setLeft(new Label(i18n("modpack.wizard.step.initialization.no_create_remote_files")));
|
requireNoCreateRemoteFilesButton.setTitle(i18n("modpack.wizard.step.initialization.no_create_remote_files"));
|
||||||
list.getContent().add(noCreateRemoteFiles);
|
requireNoCreateRemoteFilesButton.selectedProperty().bindBidirectional(skinnable.noCreateRemoteFiles);
|
||||||
|
|
||||||
JFXToggleButton noCreateRemoteFilesButton = new JFXToggleButton();
|
list.getContent().add(requireNoCreateRemoteFilesButton);
|
||||||
noCreateRemoteFilesButton.selectedProperty().bindBidirectional(skinnable.noCreateRemoteFiles);
|
|
||||||
noCreateRemoteFilesButton.setSize(8);
|
|
||||||
noCreateRemoteFilesButton.setMinHeight(16);
|
|
||||||
noCreateRemoteFilesButton.setMaxHeight(16);
|
|
||||||
noCreateRemoteFiles.setRight(noCreateRemoteFilesButton);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skinnable.options.isRequireSkipCurseForgeRemoteFiles()) {
|
if (skinnable.options.isRequireSkipCurseForgeRemoteFiles()) {
|
||||||
BorderPane skipCurseForgeRemoteFiles = new BorderPane();
|
var skipCurseForgeRemoteFilesButton = new LineToggleButton();
|
||||||
skipCurseForgeRemoteFiles.setLeft(new Label(i18n("modpack.wizard.step.initialization.skip_curseforge_remote_files")));
|
skipCurseForgeRemoteFilesButton.setTitle(i18n("modpack.wizard.step.initialization.skip_curseforge_remote_files"));
|
||||||
list.getContent().add(skipCurseForgeRemoteFiles);
|
|
||||||
|
|
||||||
JFXToggleButton skipCurseForgeRemoteFilesButton = new JFXToggleButton();
|
|
||||||
skipCurseForgeRemoteFilesButton.selectedProperty().bindBidirectional(skinnable.skipCurseForgeRemoteFiles);
|
skipCurseForgeRemoteFilesButton.selectedProperty().bindBidirectional(skinnable.skipCurseForgeRemoteFiles);
|
||||||
skipCurseForgeRemoteFilesButton.setSize(8);
|
|
||||||
skipCurseForgeRemoteFilesButton.setMinHeight(16);
|
list.getContent().add(skipCurseForgeRemoteFilesButton);
|
||||||
skipCurseForgeRemoteFilesButton.setMaxHeight(16);
|
|
||||||
skipCurseForgeRemoteFiles.setRight(skipCurseForgeRemoteFilesButton);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,5 +379,31 @@ public final class ModpackInfoPage extends Control implements WizardPage {
|
|||||||
|
|
||||||
FXUtils.smoothScrolling(scroll);
|
FXUtils.smoothScrolling(scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LinePane createTextFieldLinePane(String title, StringProperty property, ValidatorBase... validators) {
|
||||||
|
LinePane linePane = new LinePane();
|
||||||
|
JFXTextField textField = new JFXTextField();
|
||||||
|
textField.setMinWidth(500);
|
||||||
|
|
||||||
|
linePane.setTitle(title);
|
||||||
|
linePane.setRight(textField);
|
||||||
|
textField.textProperty().bindBidirectional(property);
|
||||||
|
|
||||||
|
boolean needValidation = false;
|
||||||
|
if (validators != null) {
|
||||||
|
for (ValidatorBase validator : validators) {
|
||||||
|
if (validator != null) {
|
||||||
|
needValidation = true;
|
||||||
|
textField.getValidators().add(validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needValidation) {
|
||||||
|
FXUtils.setValidateWhileTextChanged(textField, true);
|
||||||
|
validatingFields.add(textField);
|
||||||
|
}
|
||||||
|
|
||||||
|
return linePane;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,7 @@ import javafx.scene.layout.VBox;
|
|||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
import org.jackhuang.hmcl.ui.construct.FileItem;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.LineToggleButton;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.PageCloseEvent;
|
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
@@ -54,7 +51,7 @@ public final class ProfilePage extends BorderPane implements DecoratorPage {
|
|||||||
private final StringProperty location;
|
private final StringProperty location;
|
||||||
private final Profile profile;
|
private final Profile profile;
|
||||||
private final JFXTextField txtProfileName;
|
private final JFXTextField txtProfileName;
|
||||||
private final FileItem gameDir;
|
private final LineFileChooserButton gameDir;
|
||||||
private final LineToggleButton toggleUseRelativePath;
|
private final LineToggleButton toggleUseRelativePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,10 +104,11 @@ public final class ProfilePage extends BorderPane implements DecoratorPage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
gameDir = new FileItem();
|
gameDir = new LineFileChooserButton();
|
||||||
gameDir.setName(i18n("profile.instance_directory"));
|
gameDir.setTitle(i18n("profile.instance_directory"));
|
||||||
gameDir.setTitle(i18n("profile.instance_directory.choose"));
|
gameDir.setFileChooserTitle(i18n("profile.instance_directory.choose"));
|
||||||
gameDir.pathProperty().bindBidirectional(location);
|
gameDir.setType(LineFileChooserButton.Type.OPEN_DIRECTORY);
|
||||||
|
gameDir.locationProperty().bindBidirectional(location);
|
||||||
|
|
||||||
toggleUseRelativePath = new LineToggleButton();
|
toggleUseRelativePath = new LineToggleButton();
|
||||||
toggleUseRelativePath.setTitle(i18n("profile.use_relative_path"));
|
toggleUseRelativePath.setTitle(i18n("profile.use_relative_path"));
|
||||||
@@ -188,7 +186,7 @@ public final class ProfilePage extends BorderPane implements DecoratorPage {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (StringUtils.isBlank(getLocation())) {
|
if (StringUtils.isBlank(getLocation())) {
|
||||||
gameDir.onExplore();
|
gameDir.fire();
|
||||||
}
|
}
|
||||||
Profile newProfile = new Profile(txtProfileName.getText(), Path.of(getLocation()));
|
Profile newProfile = new Profile(txtProfileName.getText(), Path.of(getLocation()));
|
||||||
newProfile.setUseRelativePath(toggleUseRelativePath.isSelected());
|
newProfile.setUseRelativePath(toggleUseRelativePath.isSelected());
|
||||||
|
|||||||
@@ -175,27 +175,19 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
|
|||||||
componentList = new ComponentList();
|
componentList = new ComponentList();
|
||||||
|
|
||||||
if (!globalSetting) {
|
if (!globalSetting) {
|
||||||
BorderPane copyGlobalPane = new BorderPane();
|
var copyGlobalButton = LineButton.createNavigationButton();
|
||||||
{
|
copyGlobalButton.setTitle(i18n("settings.game.copy_global"));
|
||||||
Label label = new Label(i18n("settings.game.copy_global"));
|
copyGlobalButton.setOnAction(event ->
|
||||||
copyGlobalPane.setLeft(label);
|
Controllers.confirm(i18n("settings.game.copy_global.copy_all.confirm"), null, () -> {
|
||||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
Set<String> ignored = new HashSet<>(Arrays.asList(
|
||||||
|
"usesGlobal",
|
||||||
|
"versionIcon"
|
||||||
|
));
|
||||||
|
|
||||||
JFXButton copyAll = FXUtils.newBorderButton(i18n("settings.game.copy_global.copy_all"));
|
PropertyUtils.copyProperties(profile.getGlobal(), lastVersionSetting, name -> !ignored.contains(name));
|
||||||
copyAll.disableProperty().bind(modpack);
|
}, null));
|
||||||
copyGlobalPane.setRight(copyAll);
|
|
||||||
copyAll.setOnAction(e -> Controllers.confirm(i18n("settings.game.copy_global.copy_all.confirm"), null, () -> {
|
|
||||||
Set<String> ignored = new HashSet<>(Arrays.asList(
|
|
||||||
"usesGlobal",
|
|
||||||
"versionIcon"
|
|
||||||
));
|
|
||||||
|
|
||||||
PropertyUtils.copyProperties(profile.getGlobal(), lastVersionSetting, name -> !ignored.contains(name));
|
componentList.getContent().add(copyGlobalButton);
|
||||||
}, null));
|
|
||||||
BorderPane.setAlignment(copyAll, Pos.CENTER_RIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentList.getContent().add(copyGlobalPane);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
javaItem = new MultiFileItem<>();
|
javaItem = new MultiFileItem<>();
|
||||||
|
|||||||
@@ -20,17 +20,16 @@ package org.jackhuang.hmcl.ui.versions;
|
|||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.SkinBase;
|
import javafx.scene.control.SkinBase;
|
||||||
import javafx.scene.layout.BorderPane;
|
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
import org.jackhuang.hmcl.ui.construct.FileItem;
|
import org.jackhuang.hmcl.ui.construct.LineFileChooserButton;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.LinePane;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.LineTextPane;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -42,47 +41,40 @@ public class WorldExportPageSkin extends SkinBase<WorldExportPage> {
|
|||||||
public WorldExportPageSkin(WorldExportPage skinnable) {
|
public WorldExportPageSkin(WorldExportPage skinnable) {
|
||||||
super(skinnable);
|
super(skinnable);
|
||||||
|
|
||||||
Insets insets = new Insets(0, 0, 12, 0);
|
|
||||||
VBox container = new VBox();
|
VBox container = new VBox();
|
||||||
container.setSpacing(16);
|
container.setSpacing(16);
|
||||||
container.setAlignment(Pos.CENTER);
|
container.setAlignment(Pos.CENTER);
|
||||||
FXUtils.setLimitWidth(container, 500);
|
FXUtils.setLimitWidth(container, 500);
|
||||||
{
|
|
||||||
HBox labelContainer = new HBox();
|
|
||||||
labelContainer.setPadding(new Insets(0, 0, 0, 5));
|
|
||||||
Label label = new Label(i18n("world.export"));
|
|
||||||
labelContainer.getChildren().setAll(label);
|
|
||||||
container.getChildren().add(labelContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentList list = new ComponentList();
|
ComponentList list = new ComponentList();
|
||||||
|
|
||||||
FileItem fileItem = new FileItem();
|
var chooseFileButton = new LineFileChooserButton();
|
||||||
fileItem.setName(i18n("world.export.location"));
|
chooseFileButton.setTitle(i18n("world.export.location"));
|
||||||
fileItem.pathProperty().bindBidirectional(skinnable.pathProperty());
|
chooseFileButton.setType(LineFileChooserButton.Type.SAVE_FILE);
|
||||||
list.getContent().add(fileItem);
|
chooseFileButton.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("world"), "*.zip"));
|
||||||
|
chooseFileButton.locationProperty().bindBidirectional(skinnable.pathProperty());
|
||||||
|
|
||||||
|
var worldNamePane = new LinePane();
|
||||||
|
worldNamePane.setTitle(i18n("world.name"));
|
||||||
JFXTextField txtWorldName = new JFXTextField();
|
JFXTextField txtWorldName = new JFXTextField();
|
||||||
txtWorldName.textProperty().bindBidirectional(skinnable.worldNameProperty());
|
txtWorldName.textProperty().bindBidirectional(skinnable.worldNameProperty());
|
||||||
txtWorldName.setLabelFloat(true);
|
txtWorldName.setPrefWidth(300);
|
||||||
txtWorldName.setPromptText(i18n("world.name"));
|
worldNamePane.setRight(txtWorldName);
|
||||||
StackPane.setMargin(txtWorldName, insets);
|
|
||||||
list.getContent().add(txtWorldName);
|
|
||||||
|
|
||||||
Label lblGameVersionTitle = new Label(i18n("world.game_version"));
|
LineTextPane gameVersionPane = new LineTextPane();
|
||||||
Label lblGameVersion = new Label();
|
gameVersionPane.setTitle(i18n("world.game_version"));
|
||||||
lblGameVersion.textProperty().bind(skinnable.gameVersionProperty());
|
gameVersionPane.textProperty().bind(skinnable.gameVersionProperty());
|
||||||
BorderPane gameVersionPane = new BorderPane();
|
|
||||||
gameVersionPane.setPadding(new Insets(4, 0, 4, 0));
|
|
||||||
gameVersionPane.setLeft(lblGameVersionTitle);
|
|
||||||
gameVersionPane.setRight(lblGameVersion);
|
|
||||||
list.getContent().add(gameVersionPane);
|
|
||||||
|
|
||||||
container.getChildren().add(list);
|
list.getContent().setAll(chooseFileButton, worldNamePane, gameVersionPane);
|
||||||
|
|
||||||
|
container.getChildren().setAll(
|
||||||
|
ComponentList.createComponentListTitle(i18n("world.export")),
|
||||||
|
list
|
||||||
|
);
|
||||||
|
|
||||||
JFXButton btnExport = FXUtils.newRaisedButton(i18n("button.export"));
|
JFXButton btnExport = FXUtils.newRaisedButton(i18n("button.export"));
|
||||||
btnExport.disableProperty().bind(Bindings.createBooleanBinding(() -> txtWorldName.getText().isEmpty() || Files.exists(Paths.get(fileItem.getPath())),
|
btnExport.disableProperty().bind(Bindings.createBooleanBinding(() -> txtWorldName.getText().isEmpty() || Files.exists(Paths.get(chooseFileButton.getLocation())),
|
||||||
txtWorldName.textProperty().isEmpty(), fileItem.pathProperty()));
|
txtWorldName.textProperty().isEmpty(), chooseFileButton.locationProperty()));
|
||||||
btnExport.setOnAction(e -> skinnable.export());
|
btnExport.setOnAction(e -> skinnable.export());
|
||||||
HBox bottom = new HBox();
|
HBox bottom = new HBox();
|
||||||
bottom.setAlignment(Pos.CENTER_RIGHT);
|
bottom.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public final class WorldManageUIUtils {
|
|||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
fileChooser.setTitle(i18n("world.export.title"));
|
fileChooser.setTitle(i18n("world.export.title"));
|
||||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("world"), "*.zip"));
|
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("world"), "*.zip"));
|
||||||
fileChooser.setInitialFileName(world.getWorldName());
|
fileChooser.setInitialFileName(world.getWorldName() + ".zip");
|
||||||
Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
|
Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user