弃用 FXML (#1911)

* Remove message-dialog.fxml

* Remove authlib-injector-server-add.fxml

* Remove profile.fxml

* Remove task-dialog.fxml

* Flatten AddAuthlibInjectorServerPane

* Flatten MessageDialogPane

* Remove unused fxml files

* Remove modpack.fxml

* Remove modpack-source.fxml

* Remove selection.fxml

* Remove type.fxml

* Remove versions.fxml

* Remove input-dialog.fxml

* Remove fxml

* Cleanup code

* Cleanup code

* Cleanup Code

* Cleanup Code
This commit is contained in:
Glavo 2022-12-10 22:36:14 +08:00 committed by GitHub
parent 2bcf9ee39e
commit bf04854e68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 638 additions and 941 deletions

View File

@ -28,7 +28,6 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;
import javafx.beans.value.WritableValue;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
@ -52,7 +51,6 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.ResourceNotFoundError;
import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.javafx.ExtendedProperties;
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
@ -279,17 +277,6 @@ public final class FXUtils {
JFXScrollPane.smoothScrolling(scrollPane);
}
public static void loadFXML(Node node, String absolutePath) {
FXMLLoader loader = new FXMLLoader(node.getClass().getResource(absolutePath), I18n.getResourceBundle());
loader.setRoot(node);
loader.setController(node);
try {
loader.load();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static void installFastTooltip(Node node, Tooltip tooltip) {
installTooltip(node, 50, 5000, 0, tooltip);
}

View File

@ -54,6 +54,8 @@ public final class SVG {
return svg;
}
public static final String ARROW_RIGHT = "M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z";
// default fill: white, width: 24, height 24
public static Node gear(ObjectBinding<? extends Paint> fill, double width, double height) {
@ -273,7 +275,7 @@ public final class SVG {
}
public static Node arrowRight(ObjectBinding<? extends Paint> fill, double width, double height) {
return createSVGPath("M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z", fill, width,
return createSVGPath(ARROW_RIGHT, fill, width,
height);
}

View File

@ -20,10 +20,8 @@ package org.jackhuang.hmcl.ui.account;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import com.jfoenix.controls.JFXTextField;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.*;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
@ -32,29 +30,28 @@ import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.construct.DialogAware;
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.io.IOException;
import java.util.logging.Level;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.loadFXML;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class AddAuthlibInjectorServerPane extends StackPane implements DialogAware {
public final class AddAuthlibInjectorServerPane extends TransitionPane implements DialogAware {
@FXML private TransitionPane root;
@FXML private Label lblServerUrl;
@FXML private Label lblServerName;
@FXML private Label lblCreationWarning;
@FXML private Label lblServerWarning;
@FXML private JFXTextField txtServerUrl;
@FXML private JFXDialogLayout addServerPane;
@FXML private JFXDialogLayout confirmServerPane;
@FXML private SpinnerPane nextPane;
@FXML private JFXButton btnAddNext;
private final Label lblServerUrl;
private final Label lblServerName;
private final Label lblCreationWarning;
private final Label lblServerWarning;
private final JFXTextField txtServerUrl;
private final JFXDialogLayout addServerPane;
private final JFXDialogLayout confirmServerPane;
private final SpinnerPane nextPane;
private final JFXButton btnAddNext;
private AuthlibInjectorServer serverBeingAdded;
@ -65,8 +62,92 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
}
public AddAuthlibInjectorServerPane() {
loadFXML(this, "/assets/fxml/authlib-injector-server-add.fxml");
root.setContent(addServerPane, ContainerAnimations.NONE.getAnimationProducer());
addServerPane = new JFXDialogLayout();
addServerPane.setHeading(new Label(i18n("account.injector.add")));
{
txtServerUrl = new JFXTextField();
txtServerUrl.setPromptText(i18n("account.injector.server_url"));
txtServerUrl.setOnAction(e -> onAddNext());
lblCreationWarning = new Label();
lblCreationWarning.setWrapText(true);
HBox actions = new HBox();
{
JFXButton cancel = new JFXButton(i18n("button.cancel"));
cancel.getStyleClass().add("dialog-accept");
cancel.setOnAction(e -> onAddCancel());
nextPane = new SpinnerPane();
nextPane.getStyleClass().add("small-spinner-pane");
btnAddNext = new JFXButton(i18n("wizard.next"));
btnAddNext.getStyleClass().add("dialog-accept");
btnAddNext.setOnAction(e -> onAddNext());
nextPane.setContent(btnAddNext);
actions.getChildren().setAll(cancel, nextPane);
}
addServerPane.setBody(txtServerUrl);
addServerPane.setActions(lblCreationWarning, actions);
}
confirmServerPane = new JFXDialogLayout();
confirmServerPane.setHeading(new Label(i18n("account.injector.add")));
{
GridPane body = new GridPane();
body.setStyle("-fx-padding: 15 0 0 0;");
body.setVgap(15);
body.setHgap(15);
{
body.getColumnConstraints().setAll(
Lang.apply(new ColumnConstraints(), c -> c.setMaxWidth(100)),
new ColumnConstraints()
);
lblServerUrl = new Label();
GridPane.setColumnIndex(lblServerUrl, 1);
GridPane.setRowIndex(lblServerUrl, 0);
lblServerName = new Label();
GridPane.setColumnIndex(lblServerName, 1);
GridPane.setRowIndex(lblServerName, 1);
lblServerWarning = new Label(i18n("account.injector.http"));
lblServerWarning.setStyle("-fx-text-fill: red;");
GridPane.setColumnIndex(lblServerWarning, 0);
GridPane.setRowIndex(lblServerWarning, 2);
GridPane.setColumnSpan(lblServerWarning, 2);
body.getChildren().setAll(
Lang.apply(new Label(i18n("account.injector.server_url")), l -> {
GridPane.setColumnIndex(l, 0);
GridPane.setRowIndex(l, 0);
}),
Lang.apply(new Label(i18n("account.injector.server_name")), l -> {
GridPane.setColumnIndex(l, 0);
GridPane.setRowIndex(l, 1);
}),
lblServerUrl, lblServerName, lblServerWarning
);
}
JFXButton prevButton = new JFXButton(i18n("wizard.prev"));
prevButton.getStyleClass().add("dialog-cancel");
prevButton.setOnAction(e -> onAddPrev());
JFXButton cancelButton = new JFXButton(i18n("button.cancel"));
cancelButton.getStyleClass().add("dialog-cancel");
cancelButton.setOnAction(e -> onAddCancel());
JFXButton finishButton = new JFXButton(i18n("wizard.finish"));
finishButton.getStyleClass().add("dialog-accept");
finishButton.setOnAction(e -> onAddFinish());
confirmServerPane.setBody(body);
confirmServerPane.setActions(prevButton, cancelButton, finishButton);
}
this.setContent(addServerPane, ContainerAnimations.NONE.getAnimationProducer());
lblCreationWarning.maxWidthProperty().bind(((FlowPane) lblCreationWarning.getParent()).widthProperty());
btnAddNext.disableProperty().bind(txtServerUrl.textProperty().isEmpty());
@ -88,12 +169,10 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
}
}
@FXML
private void onAddCancel() {
fireEvent(new DialogCloseEvent());
}
@FXML
private void onAddNext() {
if (btnAddNext.isDisabled())
return;
@ -117,7 +196,7 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
lblServerWarning.setVisible("http".equals(NetworkUtils.toURL(serverBeingAdded.getUrl()).getProtocol()));
root.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT.getAnimationProducer());
this.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT.getAnimationProducer());
} else {
LOG.log(Level.WARNING, "Failed to resolve auth server: " + url, exception);
lblCreationWarning.setText(resolveFetchExceptionMessage(exception));
@ -126,12 +205,10 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
}
@FXML
private void onAddPrev() {
root.setContent(addServerPane, ContainerAnimations.SWIPE_RIGHT.getAnimationProducer());
this.setContent(addServerPane, ContainerAnimations.SWIPE_RIGHT.getAnimationProducer());
}
@FXML
private void onAddFinish() {
if (!config().getAuthlibInjectorServers().contains(serverBeingAdded)) {
config().getAuthlibInjectorServers().add(serverBeingAdded);

View File

@ -18,40 +18,45 @@
package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialogLayout;
import com.jfoenix.controls.JFXTextField;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.FutureCallback;
import java.util.concurrent.CompletableFuture;
public class InputDialogPane extends StackPane {
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class InputDialogPane extends JFXDialogLayout {
private final CompletableFuture<String> future = new CompletableFuture<>();
@FXML
private JFXButton acceptButton;
@FXML
private JFXButton cancelButton;
@FXML
private Label title;
@FXML
private VBox vbox;
@FXML
private Label lblCreationWarning;
@FXML
private SpinnerPane acceptPane;
private final JFXTextField textField;
private final Label lblCreationWarning;
private final SpinnerPane acceptPane;
public InputDialogPane(String text, String initialValue, FutureCallback<String> onResult) {
FXUtils.loadFXML(this, "/assets/fxml/input-dialog.fxml");
title.setText(text);
JFXTextField textField = new JFXTextField();
textField.setText(initialValue);
vbox.getChildren().setAll(textField);
cancelButton.setOnMouseClicked(e -> fireEvent(new DialogCloseEvent()));
acceptButton.setOnMouseClicked(e -> {
textField = new JFXTextField(initialValue);
this.setHeading(new HBox(new Label(text)));
this.setBody(new VBox(textField));
lblCreationWarning = new Label();
acceptPane = new SpinnerPane();
acceptPane.getStyleClass().add("small-spinner-pane");
JFXButton acceptButton = new JFXButton(i18n("button.ok"));
acceptButton.getStyleClass().add("dialog-accept");
acceptPane.setContent(acceptButton);
JFXButton cancelButton = new JFXButton(i18n("button.cancel"));
cancelButton.getStyleClass().add("dialog-cancel");
this.setActions(lblCreationWarning, acceptPane, cancelButton);
cancelButton.setOnAction(e -> fireEvent(new DialogCloseEvent()));
acceptButton.setOnAction(e -> {
acceptPane.showSpinner();
onResult.call(textField.getText(), () -> {

View File

@ -19,7 +19,6 @@ package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXButton;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.Label;
@ -45,7 +44,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class MessageDialogPane extends StackPane {
public final class MessageDialogPane extends HBox {
public enum MessageType {
ERROR,
@ -59,35 +58,19 @@ public final class MessageDialogPane extends StackPane {
}
}
@FXML
private StackPane content;
@FXML
private Label graphic;
@FXML
private Label title;
@FXML
private HBox actions;
private final HBox actions;
private @Nullable ButtonBase cancelButton;
public MessageDialogPane(@NotNull String text, @Nullable String title, @NotNull MessageType type) {
FXUtils.loadFXML(this, "/assets/fxml/message-dialog.fxml");
EnhancedTextFlow textFlow = new EnhancedTextFlow();
textFlow.getChildren().setAll(FXUtils.parseSegment(text, Controllers::onHyperlinkAction));
if (textFlow.computePrefHeight(400.0) <= 350.0)
content.getChildren().setAll(textFlow);
else {
ScrollPane scrollPane = new ScrollPane(textFlow);
VBox.setVgrow(scrollPane, Priority.ALWAYS);
scrollPane.setFitToWidth(true);
content.getChildren().setAll(scrollPane);
}
if (title != null)
this.title.setText(title);
this.setSpacing(8);
this.getStyleClass().add("jfx-dialog-layout");
Label graphic = new Label();
graphic.setTranslateX(10);
graphic.setTranslateY(10);
graphic.setMinSize(40, 40);
graphic.setMaxSize(40, 40);
switch (type) {
case INFO:
graphic.setGraphic(SVG.infoCircle(Theme.blackFillBinding(), 40, 40));
@ -108,6 +91,35 @@ public final class MessageDialogPane extends StackPane {
throw new IllegalArgumentException("Unrecognized message box message type " + type);
}
VBox vbox = new VBox();
HBox.setHgrow(vbox, Priority.ALWAYS);
{
StackPane titlePane = new StackPane();
titlePane.getStyleClass().addAll("jfx-layout-heading", "title");
titlePane.getChildren().setAll(new Label(title != null ? title : i18n("message.info")));
StackPane content = new StackPane();
content.getStyleClass().add("jfx-layout-body");
EnhancedTextFlow textFlow = new EnhancedTextFlow(text);
textFlow.setStyle("-fx-font-size: 14px;");
if (textFlow.computePrefHeight(400.0) <= 350.0)
content.getChildren().setAll(textFlow);
else {
ScrollPane scrollPane = new ScrollPane(textFlow);
scrollPane.setPrefHeight(350);
VBox.setVgrow(scrollPane, Priority.ALWAYS);
scrollPane.setFitToWidth(true);
content.getChildren().setAll(scrollPane);
}
actions = new HBox();
actions.getStyleClass().add("jfx-layout-actions");
vbox.getChildren().setAll(titlePane, content, actions);
}
this.getChildren().setAll(graphic, vbox);
onEscPressed(this, () -> {
if (cancelButton != null) {
cancelButton.fire();
@ -129,6 +141,10 @@ public final class MessageDialogPane extends StackPane {
}
private static final class EnhancedTextFlow extends TextFlow {
EnhancedTextFlow(String text) {
this.getChildren().setAll(FXUtils.parseSegment(text, Controllers::onHyperlinkAction));
}
@Override
public double computePrefHeight(double width) {
return super.computePrefHeight(width);

View File

@ -20,9 +20,12 @@ package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXButton;
import javafx.application.Platform;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.task.TaskExecutor;
import org.jackhuang.hmcl.task.TaskListener;
@ -35,23 +38,51 @@ import java.util.function.Consumer;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class TaskExecutorDialogPane extends StackPane {
public class TaskExecutorDialogPane extends BorderPane {
private TaskExecutor executor;
private TaskCancellationAction onCancel;
private final Consumer<FileDownloadTask.SpeedEvent> speedEventHandler;
@FXML
private Label lblTitle;
@FXML
private Label lblProgress;
@FXML
private JFXButton btnCancel;
@FXML
private TaskListPane taskListPane;
private final Label lblTitle;
private final Label lblProgress;
private final JFXButton btnCancel;
private final TaskListPane taskListPane;
public TaskExecutorDialogPane(@NotNull TaskCancellationAction cancel) {
FXUtils.loadFXML(this, "/assets/fxml/task-dialog.fxml");
FXUtils.setLimitWidth(this, 500);
FXUtils.setLimitHeight(this, 300);
VBox center = new VBox();
this.setCenter(center);
center.setPadding(new Insets(16));
{
lblTitle = new Label();
lblTitle.setStyle("-fx-font-size: 14px; -fx-font-weight: BOLD;");
ScrollPane scrollPane = new ScrollPane();
scrollPane.setFitToHeight(true);
scrollPane.setFitToWidth(true);
VBox.setVgrow(scrollPane, Priority.ALWAYS);
{
taskListPane = new TaskListPane();
scrollPane.setContent(taskListPane);
}
center.getChildren().setAll(lblTitle, scrollPane);
}
BorderPane bottom = new BorderPane();
this.setBottom(bottom);
bottom.setPadding(new Insets(0, 8, 8, 8));
{
lblProgress = new Label();
bottom.setLeft(lblProgress);
btnCancel = new JFXButton(i18n("button.cancel"));
bottom.setRight(btnCancel);
}
setCancel(cancel);

View File

@ -21,7 +21,6 @@ import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Control;
@ -119,7 +118,6 @@ public class InstallersPage extends Control implements WizardPage {
public void cleanup(Map<String, Object> settings) {
}
@FXML
protected void onInstall() {
controller.getSettings().put("name", txtName.getText());
controller.onFinish();

View File

@ -17,15 +17,9 @@
*/
package org.jackhuang.hmcl.ui.download;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.game.ManuallyCreatedModpackException;
@ -39,10 +33,8 @@ import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.ui.construct.Validator;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
@ -52,52 +44,21 @@ import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import static javafx.beans.binding.Bindings.createBooleanBinding;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class LocalModpackPage extends StackPane implements WizardPage {
private final WizardController controller;
private Modpack manifest = null;
@FXML
private Region borderPane;
@FXML
private Label lblName;
@FXML
private Label lblVersion;
@FXML
private Label lblAuthor;
@FXML
private Label lblModpackLocation;
@FXML
private JFXTextField txtModpackName;
@FXML
private JFXButton btnInstall;
@FXML
private SpinnerPane spinnerPane;
public final class LocalModpackPage extends ModpackPage {
private final BooleanProperty installAsVersion = new SimpleBooleanProperty(true);
private Modpack manifest = null;
private Charset charset;
public LocalModpackPage(WizardController controller) {
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/download/modpack.fxml");
super(controller);
Profile profile = (Profile) controller.getSettings().get("PROFILE");
File selectedFile;
Optional<String> name = tryCast(controller.getSettings().get(MODPACK_NAME), String.class);
if (name.isPresent()) {
txtModpackName.setText(name.get());
@ -116,12 +77,9 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId));
}
});
btnInstall.disableProperty().bind(
createBooleanBinding(txtModpackName::validate, txtModpackName.textProperty())
.not());
}
File selectedFile;
Optional<File> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), File.class);
if (filePath.isPresent()) {
selectedFile = filePath.get();
@ -138,7 +96,7 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
controller.getSettings().put(MODPACK_FILE, selectedFile);
}
spinnerPane.showSpinner();
showSpinner();
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(selectedFile.toPath()))
.thenApplyAsync(encoding -> {
charset = encoding;
@ -147,7 +105,7 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
})
.whenComplete(Schedulers.javafx(), (manifest, exception) -> {
if (exception instanceof ManuallyCreatedModpackException) {
spinnerPane.hideSpinner();
hideSpinner();
lblName.setText(selectedFile.getName());
installAsVersion.set(false);
lblModpackLocation.setText(selectedFile.getAbsolutePath());
@ -167,7 +125,7 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
Controllers.dialog(i18n("modpack.task.install.error"), i18n("message.error"), MessageDialogPane.MessageType.ERROR);
Platform.runLater(controller::onEnd);
} else {
spinnerPane.hideSpinner();
hideSpinner();
controller.getSettings().put(MODPACK_MANIFEST, manifest);
lblName.setText(manifest.getName());
lblVersion.setText(manifest.getVersion());
@ -188,26 +146,19 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
settings.remove(MODPACK_FILE);
}
@FXML
private void onInstall() {
protected void onInstall() {
if (!txtModpackName.validate()) return;
controller.getSettings().put(MODPACK_NAME, txtModpackName.getText());
controller.getSettings().put(MODPACK_CHARSET, charset);
controller.onFinish();
}
@FXML
private void onDescribe() {
protected void onDescribe() {
if (manifest != null) {
FXUtils.showWebDialog(i18n("modpack.description"), manifest.getDescription());
}
}
@Override
public String getTitle() {
return i18n("modpack.task.install");
}
public static final String MODPACK_FILE = "MODPACK_FILE";
public static final String MODPACK_NAME = "MODPACK_NAME";
public static final String MODPACK_MANIFEST = "MODPACK_MANIFEST";

View File

@ -0,0 +1,119 @@
package org.jackhuang.hmcl.ui.download;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
import static javafx.beans.binding.Bindings.createBooleanBinding;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public abstract class ModpackPage extends SpinnerPane implements WizardPage {
protected final WizardController controller;
protected final Label lblName;
protected final Label lblVersion;
protected final Label lblAuthor;
protected final Label lblModpackLocation;
protected final JFXTextField txtModpackName;
protected final JFXButton btnInstall;
protected ModpackPage(WizardController controller) {
this.controller = controller;
this.getStyleClass().add("large-spinner-pane");
VBox borderPane = new VBox();
borderPane.setAlignment(Pos.CENTER);
FXUtils.setLimitWidth(borderPane, 500);
ComponentList componentList = new ComponentList();
{
BorderPane locationPane = new BorderPane();
{
locationPane.setLeft(new Label(i18n("modpack.task.install.will")));
lblModpackLocation = new Label();
BorderPane.setAlignment(lblModpackLocation, Pos.CENTER_RIGHT);
locationPane.setCenter(lblModpackLocation);
}
BorderPane archiveNamePane = new BorderPane();
{
Label label = new Label(i18n("archive.name"));
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
archiveNamePane.setLeft(label);
txtModpackName = new JFXTextField();
BorderPane.setMargin(txtModpackName, new Insets(0, 0, 8, 32));
BorderPane.setAlignment(txtModpackName, Pos.CENTER_RIGHT);
archiveNamePane.setCenter(txtModpackName);
}
BorderPane modpackNamePane = new BorderPane();
{
modpackNamePane.setLeft(new Label(i18n("modpack.name")));
lblName = new Label();
BorderPane.setAlignment(lblName, Pos.CENTER_RIGHT);
modpackNamePane.setCenter(lblName);
}
BorderPane versionPane = new BorderPane();
{
versionPane.setLeft(new Label(i18n("archive.version")));
lblVersion = new Label();
BorderPane.setAlignment(lblVersion, Pos.CENTER_RIGHT);
versionPane.setCenter(lblVersion);
}
BorderPane authorPane = new BorderPane();
{
authorPane.setLeft(new Label(i18n("archive.author")));
lblAuthor = new Label();
BorderPane.setAlignment(lblAuthor, Pos.CENTER_RIGHT);
authorPane.setCenter(lblAuthor);
}
BorderPane descriptionPane = new BorderPane();
{
JFXButton btnDescription = new JFXButton(i18n("modpack.description"));
btnDescription.getStyleClass().add("jfx-button-border");
btnDescription.setOnAction(e -> onDescribe());
descriptionPane.setLeft(btnDescription);
btnInstall = new JFXButton(i18n("button.install"));
btnInstall.getStyleClass().add("jfx-button-raised");
btnInstall.setButtonType(JFXButton.ButtonType.RAISED);
btnInstall.setOnAction(e -> onInstall());
btnInstall.disableProperty().bind(createBooleanBinding(() -> !txtModpackName.validate(), txtModpackName.textProperty()));
descriptionPane.setRight(btnInstall);
}
componentList.getContent().setAll(
locationPane, archiveNamePane, modpackNamePane, versionPane, authorPane, descriptionPane);
}
borderPane.getChildren().setAll(componentList);
this.setContent(borderPane);
}
protected abstract void onInstall();
protected abstract void onDescribe();
@Override
public String getTitle() {
return i18n("modpack.task.install");
}
}

View File

@ -20,8 +20,12 @@ package org.jackhuang.hmcl.ui.download;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.effects.JFXDepthManager;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.SVGPath;
import javafx.stage.FileChooser;
import org.jackhuang.hmcl.game.ModpackHelper;
import org.jackhuang.hmcl.mod.server.ServerModpackManifest;
@ -30,6 +34,8 @@ import org.jackhuang.hmcl.task.GetTask;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.TaskCancellationAction;
@ -48,18 +54,23 @@ import static org.jackhuang.hmcl.ui.download.RemoteModpackPage.MODPACK_SERVER_MA
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class ModpackSelectionPage extends StackPane implements WizardPage {
public final class ModpackSelectionPage extends VBox implements WizardPage {
private final WizardController controller;
@FXML private JFXButton btnLocal;
@FXML private JFXButton btnRemote;
public ModpackSelectionPage(WizardController controller) {
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/download/modpack-source.fxml");
JFXDepthManager.setDepth(btnLocal, 1);
JFXDepthManager.setDepth(btnRemote, 1);
Label title = new Label(i18n("install.modpack"));
title.setPadding(new Insets(8));
this.getStyleClass().add("jfx-list-view");
this.setMaxSize(400, 150);
this.setSpacing(8);
this.getChildren().setAll(
title,
createButton("local", this::onChooseLocalFile),
createButton("remote", this::onChooseRemoteFile)
);
Optional<File> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), File.class);
if (filePath.isPresent()) {
@ -74,7 +85,30 @@ public final class ModpackSelectionPage extends StackPane implements WizardPage
});
}
@FXML
private JFXButton createButton(String type, Runnable action) {
JFXButton button = new JFXButton();
button.getStyleClass().add("card");
button.setStyle("-fx-cursor: HAND;");
button.prefWidthProperty().bind(this.widthProperty());
button.setOnAction(e -> action.run());
BorderPane graphic = new BorderPane();
graphic.setMouseTransparent(true);
graphic.setLeft(new TwoLineListItem(i18n("modpack.choose." + type), i18n("modpack.choose." + type + ".detail")));
SVGPath arrow = new SVGPath();
arrow.setContent(SVG.ARROW_RIGHT);
BorderPane.setAlignment(arrow, Pos.CENTER);
graphic.setRight(arrow);
button.setGraphic(graphic);
JFXDepthManager.setDepth(button, 1);
return button;
}
private void onChooseLocalFile() {
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("modpack.choose"));
@ -89,7 +123,6 @@ public final class ModpackSelectionPage extends StackPane implements WizardPage
controller.onNext();
}
@FXML
private void onChooseRemoteFile() {
Controllers.prompt(i18n("modpack.choose.remote.tooltip"), (urlString, resolve, reject) -> {
try {

View File

@ -17,14 +17,7 @@
*/
package org.jackhuang.hmcl.ui.download;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.mod.server.ServerModpackManifest;
import org.jackhuang.hmcl.setting.Profile;
@ -32,59 +25,21 @@ import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.ui.construct.Validator;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import static javafx.beans.binding.Bindings.createBooleanBinding;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class RemoteModpackPage extends StackPane implements WizardPage {
private final WizardController controller;
public final class RemoteModpackPage extends ModpackPage {
private final ServerModpackManifest manifest;
@FXML
private Region borderPane;
@FXML
private Label lblName;
@FXML
private Label lblVersion;
@FXML
private Label lblAuthor;
@FXML
private Label lblModpackLocation;
@FXML
private JFXTextField txtModpackName;
@FXML
private JFXButton btnInstall;
@FXML
private SpinnerPane spinnerPane;
public RemoteModpackPage(WizardController controller) {
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/download/modpack.fxml");
Profile profile = (Profile) controller.getSettings().get("PROFILE");
Optional<String> name = tryCast(controller.getSettings().get(MODPACK_NAME), String.class);
if (name.isPresent()) {
txtModpackName.setText(name.get());
txtModpackName.setDisable(true);
}
super(controller);
manifest = tryCast(controller.getSettings().get(MODPACK_SERVER_MANIFEST), ServerModpackManifest.class)
.orElseThrow(() -> new IllegalStateException("MODPACK_SERVER_MANIFEST should exist"));
@ -102,16 +57,18 @@ public class RemoteModpackPage extends StackPane implements WizardPage {
lblVersion.setText(manifest.getVersion());
lblAuthor.setText(manifest.getAuthor());
if (!name.isPresent()) {
Profile profile = (Profile) controller.getSettings().get("PROFILE");
Optional<String> name = tryCast(controller.getSettings().get(MODPACK_NAME), String.class);
if (name.isPresent()) {
txtModpackName.setText(name.get());
txtModpackName.setDisable(true);
} else {
// trim: https://github.com/huanghongxun/HMCL/issues/962
txtModpackName.setText(manifest.getName().trim());
txtModpackName.getValidators().addAll(
new RequiredValidator(),
new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().versionIdConflicts(str)),
new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId));
btnInstall.disableProperty().bind(
createBooleanBinding(txtModpackName::validate, txtModpackName.textProperty())
.not());
}
}
@ -120,23 +77,16 @@ public class RemoteModpackPage extends StackPane implements WizardPage {
settings.remove(MODPACK_SERVER_MANIFEST);
}
@FXML
private void onInstall() {
protected void onInstall() {
if (!txtModpackName.validate()) return;
controller.getSettings().put(MODPACK_NAME, txtModpackName.getText());
controller.onFinish();
}
@FXML
private void onDescribe() {
protected void onDescribe() {
FXUtils.showWebDialog(i18n("modpack.description"), manifest.getDescription());
}
@Override
public String getTitle() {
return i18n("modpack.task.install");
}
public static final String MODPACK_SERVER_MANIFEST = "MODPACK_SERVER_MANIFEST";
public static final String MODPACK_NAME = "MODPACK_NAME";
public static final String MODPACK_MANIFEST = "MODPACK_MANIFEST";

View File

@ -23,14 +23,11 @@ import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXSpinner;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.*;
import org.apache.commons.lang3.mutable.MutableObject;
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.RemoteVersion;
@ -45,11 +42,11 @@ import org.jackhuang.hmcl.download.quilt.QuiltAPIRemoteVersion;
import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.setting.VersionIconType;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.HintPane;
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
import org.jackhuang.hmcl.ui.wizard.Navigation;
@ -75,30 +72,18 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
private final String title;
private final Navigation navigation;
@FXML
private JFXListView<RemoteVersion> list;
@FXML
private JFXSpinner spinner;
@FXML
private StackPane failedPane;
@FXML
private StackPane emptyPane;
@FXML
private TransitionPane root;
@FXML
private JFXCheckBox chkRelease;
@FXML
private JFXCheckBox chkSnapshot;
@FXML
private JFXCheckBox chkOld;
@FXML
private JFXButton btnRefresh;
@FXML
private HBox checkPane;
@FXML
private ComponentList centrePane;
@FXML
private StackPane center;
private final JFXListView<RemoteVersion> list;
private final JFXSpinner spinner;
private final StackPane failedPane;
private final StackPane emptyPane;
private final TransitionPane root;
private final JFXCheckBox chkRelease;
private final JFXCheckBox chkSnapshot;
private final JFXCheckBox chkOld;
private final JFXButton btnRefresh;
private final HBox checkPane;
private final ComponentList centrePane;
private final StackPane center;
private final VersionList<?> versionList;
private CompletableFuture<?> executor;
@ -109,7 +94,75 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
this.libraryId = libraryId;
this.navigation = navigation;
FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml");
HintPane hintPane = new HintPane();
hintPane.setText(i18n("sponsor.bmclapi"));
hintPane.getStyleClass().add("sponsor-pane");
hintPane.setOnMouseClicked(e -> onSponsor());
BorderPane.setMargin(hintPane, new Insets(10, 10, 0, 10));
this.setTop(hintPane);
root = new TransitionPane();
{
spinner = new JFXSpinner();
center = new StackPane();
center.setStyle("-fx-padding: 10;");
{
centrePane = new ComponentList();
centrePane.getStyleClass().add("no-padding");
{
checkPane = new HBox();
checkPane.setSpacing(10);
{
chkRelease = new JFXCheckBox(i18n("version.game.releases"));
chkRelease.setSelected(true);
HBox.setMargin(chkRelease, new Insets(10, 0, 10, 0));
chkSnapshot = new JFXCheckBox(i18n("version.game.snapshots"));
HBox.setMargin(chkSnapshot, new Insets(10, 0, 10, 0));
chkOld = new JFXCheckBox(i18n("version.game.old"));
HBox.setMargin(chkOld, new Insets(10, 0, 10, 0));
HBox pane = new HBox();
HBox.setHgrow(pane, Priority.ALWAYS);
btnRefresh = new JFXButton(i18n("button.refresh"));
btnRefresh.getStyleClass().add("jfx-tool-bar-button");
btnRefresh.setOnAction(e -> onRefresh());
checkPane.getChildren().setAll(chkRelease, chkSnapshot, chkOld, pane, btnRefresh);
}
list = new JFXListView<>();
list.getStyleClass().add("jfx-list-view-float");
VBox.setVgrow(list, Priority.ALWAYS);
centrePane.getContent().setAll(checkPane, list);
}
center.getChildren().setAll(centrePane);
}
failedPane = new StackPane();
failedPane.getStyleClass().add("notice-pane");
{
Label label = new Label(i18n("download.failed.refresh"));
label.setOnMouseClicked(e -> onRefresh());
failedPane.getChildren().setAll(label);
}
emptyPane = new StackPane();
emptyPane.getStyleClass().add("notice-pane");
{
Label label = new Label(i18n("download.failed.empty"));
label.setOnMouseClicked(e -> onBack());
emptyPane.getChildren().setAll(label);
}
}
this.setCenter(root);
versionList = downloadProvider.getVersionListById(libraryId);
if (versionList.hasType()) {
@ -205,15 +258,12 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
executor.cancel(true);
}
@FXML
private void onRefresh() {
refresh();
}
@FXML
private void onBack() { navigation.onPrev(true); }
@FXML
private void onSponsor() {
HMCLService.openRedirectLink("bmclapi_sponsor");
}

View File

@ -17,17 +17,18 @@
*/
package org.jackhuang.hmcl.ui.export;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTreeView;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.mod.ModAdviser;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
@ -47,12 +48,10 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
/**
* @author huangyuhui
*/
public final class ModpackFileSelectionPage extends StackPane implements WizardPage {
public final class ModpackFileSelectionPage extends BorderPane implements WizardPage {
private final WizardController controller;
private final String version;
private final ModAdviser adviser;
@FXML
private JFXTreeView<String> treeView;
private final CheckBoxTreeItem<String> rootNode;
public ModpackFileSelectionPage(WizardController controller, Profile profile, String version, ModAdviser adviser) {
@ -60,10 +59,26 @@ public final class ModpackFileSelectionPage extends StackPane implements WizardP
this.version = version;
this.adviser = adviser;
FXUtils.loadFXML(this, "/assets/fxml/modpack/selection.fxml");
JFXTreeView<String> treeView = new JFXTreeView<>();
rootNode = getTreeItem(profile.getRepository().getRunDirectory(version), "minecraft");
treeView.setRoot(rootNode);
treeView.setSelectionModel(new NoneMultipleSelectionModel<>());
this.setCenter(treeView);
HBox nextPane = new HBox();
nextPane.setPadding(new Insets(16, 16, 16, 0));
nextPane.setAlignment(Pos.CENTER_RIGHT);
{
JFXButton btnNext = new JFXButton(i18n("wizard.next"));
btnNext.getStyleClass().add("jfx-button-raised");
btnNext.setPrefSize(100, 40);
btnNext.setButtonType(JFXButton.ButtonType.RAISED);
btnNext.setOnAction(e -> onNext());
nextPane.getChildren().setAll(btnNext);
}
this.setBottom(nextPane);
}
private CheckBoxTreeItem<String> getTreeItem(File file, String basePath) {
@ -145,7 +160,6 @@ public final class ModpackFileSelectionPage extends StackPane implements WizardP
controller.getSettings().remove(MODPACK_FILE_SELECTION);
}
@FXML
private void onNext() {
ArrayList<String> list = new ArrayList<>();
getFilesNeeded(rootNode, "minecraft", list);

View File

@ -18,13 +18,18 @@
package org.jackhuang.hmcl.ui.export;
import com.jfoenix.controls.JFXButton;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.SVGPath;
import org.jackhuang.hmcl.mod.ModpackExportInfo;
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackExportTask;
import org.jackhuang.hmcl.mod.multimc.MultiMCModpackExportTask;
import org.jackhuang.hmcl.mod.server.ServerModpackExportTask;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage;
@ -33,31 +38,47 @@ import java.util.Map;
import static org.jackhuang.hmcl.ui.export.ModpackInfoPage.MODPACK_INFO_OPTION;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class ModpackTypeSelectionPage extends StackPane implements WizardPage {
public final class ModpackTypeSelectionPage extends VBox implements WizardPage {
private final WizardController controller;
@FXML
private JFXButton btnMCBBS;
@FXML
private JFXButton btnMultiMC;
@FXML
private JFXButton btnServer;
public ModpackTypeSelectionPage(WizardController controller) {
this.controller = controller;
FXUtils.loadFXML(this, "/assets/fxml/modpack/type.fxml");
JFXButton[] buttons = new JFXButton[]{btnMCBBS, btnMultiMC, btnServer};
String[] types = new String[]{MODPACK_TYPE_MCBBS, MODPACK_TYPE_MULTIMC, MODPACK_TYPE_SERVER};
ModpackExportInfo.Options[] options = new ModpackExportInfo.Options[]{McbbsModpackExportTask.OPTION, MultiMCModpackExportTask.OPTION, ServerModpackExportTask.OPTION};
for (int i = 0; i < types.length; ++i) {
String type = types[i];
ModpackExportInfo.Options option = options[i];
buttons[i].setOnMouseClicked(e -> {
controller.getSettings().put(MODPACK_TYPE, type);
controller.getSettings().put(MODPACK_INFO_OPTION, option);
controller.onNext();
});
}
Label title = new Label(i18n("modpack.export.as"));
title.setPadding(new Insets(8));
this.getStyleClass().add("jfx-list-view");
this.setMaxSize(300, 150);
this.getChildren().setAll(
title,
createButton(MODPACK_TYPE_MCBBS, McbbsModpackExportTask.OPTION),
createButton(MODPACK_TYPE_MULTIMC, MultiMCModpackExportTask.OPTION),
createButton(MODPACK_TYPE_SERVER, ServerModpackExportTask.OPTION)
);
}
private JFXButton createButton(String type, ModpackExportInfo.Options option) {
JFXButton button = new JFXButton();
button.setOnAction(e -> {
controller.getSettings().put(MODPACK_TYPE, type);
controller.getSettings().put(MODPACK_INFO_OPTION, option);
controller.onNext();
});
button.prefWidthProperty().bind(this.widthProperty());
BorderPane graphic = new BorderPane();
graphic.setMouseTransparent(true);
graphic.setLeft(new TwoLineListItem(i18n("modpack.type." + type), i18n("modpack.type." + type + ".export")));
SVGPath arrow = new SVGPath();
arrow.setContent(SVG.ARROW_RIGHT);
BorderPane.setAlignment(arrow, Pos.CENTER);
graphic.setRight(arrow);
button.setGraphic(graphic);
return button;
}
@Override

View File

@ -18,19 +18,26 @@
package org.jackhuang.hmcl.ui.profile;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator;
import com.jfoenix.validation.base.ValidatorBase;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.FileItem;
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
import org.jackhuang.hmcl.ui.construct.PageCloseEvent;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.StringUtils;
@ -40,15 +47,14 @@ import java.util.Optional;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class ProfilePage extends StackPane implements DecoratorPage {
public final class ProfilePage extends BorderPane implements DecoratorPage {
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
private final StringProperty location;
private final Profile profile;
@FXML private JFXTextField txtProfileName;
@FXML private FileItem gameDir;
@FXML private JFXButton btnSave;
@FXML private JFXCheckBox toggleUseRelativePath;
private final JFXTextField txtProfileName;
private final FileItem gameDir;
private final OptionToggleButton toggleUseRelativePath;
/**
* @param profile null if creating a new profile.
@ -61,37 +67,86 @@ public final class ProfilePage extends StackPane implements DecoratorPage {
location = new SimpleStringProperty(this, "location",
Optional.ofNullable(profile).map(Profile::getGameDir).map(File::getAbsolutePath).orElse(".minecraft"));
FXUtils.loadFXML(this, "/assets/fxml/profile.fxml");
txtProfileName.setText(profileDisplayName);
txtProfileName.getValidators().add(new ValidatorBase() {
ScrollPane scroll = new ScrollPane();
this.setCenter(scroll);
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
{
VBox rootPane = new VBox();
rootPane.setStyle("-fx-padding: 20;");
{
setMessage(i18n("profile.already_exists"));
ComponentList componentList = new ComponentList();
componentList.setDepth(1);
{
BorderPane profileNamePane = new BorderPane();
{
Label label = new Label(i18n("profile.name"));
profileNamePane.setLeft(label);
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
txtProfileName = new JFXTextField();
profileNamePane.setRight(txtProfileName);
RequiredFieldValidator validator = new RequiredFieldValidator();
validator.setMessage(i18n("input.not_empty"));
txtProfileName.getValidators().add(validator);
BorderPane.setMargin(txtProfileName, new Insets(8, 0, 8, 0));
txtProfileName.setText(profileDisplayName);
txtProfileName.getValidators().add(new ValidatorBase() {
{
setMessage(i18n("profile.already_exists"));
}
@Override
protected void eval() {
JFXTextField control = (JFXTextField) this.getSrcControl();
hasErrors.set(Profiles.getProfiles().stream().anyMatch(profile -> profile.getName().equals(control.getText())));
}
});
}
gameDir = new FileItem();
gameDir.setName(i18n("profile.instance_directory"));
gameDir.setTitle(i18n("profile.instance_directory.choose"));
gameDir.pathProperty().bindBidirectional(location);
toggleUseRelativePath = new OptionToggleButton();
toggleUseRelativePath.setTitle(i18n("profile.use_relative_path"));
gameDir.convertToRelativePathProperty().bind(toggleUseRelativePath.selectedProperty());
if (profile != null) {
toggleUseRelativePath.setSelected(profile.isUseRelativePath());
}
componentList.getContent().setAll(profileNamePane, gameDir, toggleUseRelativePath);
}
rootPane.getChildren().setAll(componentList);
}
@Override
protected void eval() {
JFXTextField control = (JFXTextField) this.getSrcControl();
if (Profiles.getProfiles().stream().anyMatch(profile -> profile.getName().equals(control.getText())))
hasErrors.set(true);
else
hasErrors.set(false);
}
});
FXUtils.onChangeAndOperate(txtProfileName.textProperty(), it -> {
btnSave.setDisable(!txtProfileName.validate() || StringUtils.isBlank(getLocation()));
});
gameDir.pathProperty().bindBidirectional(location);
FXUtils.onChangeAndOperate(location, it -> {
btnSave.setDisable(!txtProfileName.validate() || StringUtils.isBlank(getLocation()));
});
gameDir.convertToRelativePathProperty().bind(toggleUseRelativePath.selectedProperty());
if (profile != null) {
toggleUseRelativePath.setSelected(profile.isUseRelativePath());
scroll.setContent(rootPane);
}
BorderPane savePane = new BorderPane();
this.setBottom(savePane);
savePane.setPickOnBounds(false);
savePane.setStyle("-fx-padding: 20;");
StackPane.setAlignment(savePane, Pos.BOTTOM_RIGHT);
{
JFXButton saveButton = new JFXButton(i18n("button.save"));
savePane.setRight(saveButton);
BorderPane.setAlignment(savePane, Pos.BOTTOM_RIGHT);
StackPane.setAlignment(saveButton, Pos.BOTTOM_RIGHT);
saveButton.getStyleClass().add("jfx-button-raised");
saveButton.setButtonType(JFXButton.ButtonType.RAISED);
saveButton.setPrefSize(100, 40);
saveButton.setOnAction(e -> onSave());
saveButton.disableProperty().bind(Bindings.createBooleanBinding(
() -> !txtProfileName.validate() || StringUtils.isBlank(getLocation()),
txtProfileName.textProperty(), location));
}
}
@FXML
private void onSave() {
if (profile != null) {
profile.setName(txtProfileName.getText());

View File

@ -44,7 +44,6 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
private static final class Hole {
@SuppressWarnings("unchecked")
static final Pair<String, String>[] SOURCE = (Pair<String, String>[]) new Pair<?, ?>[]{
pair("javafx.fxml.LoadException", i18n("crash.NoClassDefFound")),
pair("Location is not set", i18n("crash.NoClassDefFound")),
pair("UnsatisfiedLinkError", i18n("crash.user_fault")),
pair("java.time.zone.ZoneRulesException: Unable to load TZDB time-zone rules", i18n("crash.user_fault")),

View File

@ -431,12 +431,6 @@
-fx-wrap-text: true;
}
.jfx-layout-body > .label {
-fx-font-size: 14.0px;
-fx-pref-width: 400.0px;
-fx-wrap-text: true;
}
.jfx-layout-actions {
-fx-pref-width: 400;
-fx-padding: 10.0px 0.0 0.0 0.0;

View File

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
<?import com.jfoenix.controls.JFXProgressBar?>
<fx:root xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
type="StackPane">
<VBox fx:id="rootPane">
<ComponentList fx:id="componentList" depth="1">
<BorderPane> <!-- Name -->
<left>
<VBox>
<Label text="%account.methods" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</left>
<right>
<VBox>
<BorderPane.margin>
<Insets left="15.0" />
</BorderPane.margin>
<Label fx:id="lblType" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</right>
</BorderPane>
<BorderPane> <!-- Name -->
<left>
<VBox>
<Label text="%account.character" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</left>
<right>
<VBox>
<BorderPane.margin>
<Insets left="15.0" />
</BorderPane.margin>
<Label fx:id="lblCharacter" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</right>
</BorderPane>
<BorderPane fx:id="paneEmail"> <!-- Name -->
<left>
<VBox>
<Label text="%account.email" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</left>
<right>
<VBox>
<BorderPane.margin>
<Insets left="15.0" />
</BorderPane.margin>
<Label fx:id="lblEmail" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</right>
</BorderPane>
<BorderPane fx:id="paneServer"> <!-- Name -->
<left>
<VBox>
<Label text="%account.injector.server" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</left>
<right>
<VBox>
<BorderPane.margin>
<Insets left="15.0" />
</BorderPane.margin>
<Label fx:id="lblServer" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</right>
</BorderPane>
</ComponentList>
<BorderPane pickOnBounds="false" style="-fx-padding: 4;">
<left>
<JFXButton BorderPane.alignment="BOTTOM_LEFT" fx:id="btnDelete" onMouseClicked="#onDelete"
styleClass="toggle-icon4" maxWidth="30" maxHeight="30" minWidth="30" minHeight="30"
prefWidth="30" prefHeight="30"/>
</left>
<right>
<JFXButton BorderPane.alignment="BOTTOM_RIGHT" fx:id="btnRefresh" onMouseClicked="#onRefresh"
styleClass="toggle-icon4" maxWidth="30" maxHeight="30" minWidth="30" minHeight="30"
prefWidth="30" prefHeight="30"/>
</right>
</BorderPane>
</VBox>
<JFXProgressBar fx:id="progressBar" StackPane.alignment="TOP_CENTER" visible="false" />
</fx:root>

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.*?>
<?import org.jackhuang.hmcl.ui.construct.SpinnerPane?>
<?import org.jackhuang.hmcl.ui.animation.TransitionPane?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<TransitionPane fx:id="root">
<JFXDialogLayout fx:id="addServerPane">
<heading>
<Label text="%account.injector.add" />
</heading>
<body>
<JFXTextField fx:id="txtServerUrl" promptText="%account.injector.server_url" onAction="#onAddNext" />
</body>
<actions>
<Label fx:id="lblCreationWarning" wrapText="true" />
<HBox>
<JFXButton onMouseClicked="#onAddCancel" text="%button.cancel" styleClass="dialog-cancel" />
<SpinnerPane fx:id="nextPane" styleClass="small-spinner-pane">
<JFXButton fx:id="btnAddNext" onMouseClicked="#onAddNext" text="%wizard.next" styleClass="dialog-accept" />
</SpinnerPane>
</HBox>
</actions>
</JFXDialogLayout>
<JFXDialogLayout fx:id="confirmServerPane">
<heading>
<Label text="%account.injector.add" />
</heading>
<body>
<GridPane vgap="15" hgap="15" style="-fx-padding: 15 0 0 0;">
<columnConstraints>
<ColumnConstraints maxWidth="100" />
<ColumnConstraints />
</columnConstraints>
<Label text="%account.injector.server_url" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label text="%account.injector.server_name" GridPane.columnIndex="0" GridPane.rowIndex="1" />
<Label fx:id="lblServerUrl" GridPane.columnIndex="1" GridPane.rowIndex="0" />
<Label fx:id="lblServerName" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label fx:id="lblServerWarning" text="%account.injector.http" style="-fx-text-fill: red;"
GridPane.rowIndex="2" GridPane.columnSpan="2" GridPane.columnIndex="0" />
</GridPane>
</body>
<actions>
<JFXButton onMouseClicked="#onAddPrev" text="%wizard.prev" styleClass="dialog-cancel" />
<JFXButton onMouseClicked="#onAddCancel" text="%button.cancel" styleClass="dialog-cancel" />
<JFXButton onMouseClicked="#onAddFinish" text="%wizard.finish" styleClass="dialog-accept" />
</actions>
</JFXDialogLayout>
</TransitionPane>
</fx:root>

View File

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane" style="-fx-padding: 16;">
<BorderPane>
<top>
<VBox alignment="CENTER" style="-fx-padding: 40px;" spacing="20">
<Label fx:id="lblGameVersion" alignment="CENTER"/>
<Label fx:id="lblVersionName" alignment="CENTER"/>
</VBox>
</top>
<center>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<JFXButton fx:id="btnFabric" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblFabric"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnForge" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblForge"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnLiteLoader" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblLiteLoader"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnOptiFine" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<Label fx:id="lblOptiFine"/>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
</VBox>
</center>
<bottom>
<HBox alignment="CENTER">
<JFXButton fx:id="btnInstall" prefWidth="100" prefHeight="40"
buttonType="RAISED" text="%button.install" styleClass="jfx-button-raised"/>
</HBox>
</bottom>
</BorderPane>
</fx:root>

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.construct.TwoLineListItem?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<fx:define>
<Insets fx:id="insets" topRightBottomLeft="8" />
</fx:define>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" spacing="8" maxWidth="400">
<Label padding="${insets}" text="%install.modpack" />
<JFXButton fx:id="btnLocal" styleClass="card" style="-fx-cursor: HAND" prefWidth="${list.width}" onMouseClicked="#onChooseLocalFile">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.choose.local" subtitle="%modpack.choose.local.detail" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnRemote" styleClass="card" style="-fx-cursor: HAND" prefWidth="${list.width}" onMouseClicked="#onChooseRemoteFile">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.choose.remote" subtitle="%modpack.choose.remote.detail" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
</VBox>
</fx:root>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
<?import org.jackhuang.hmcl.ui.FXUtils?>
<?import org.jackhuang.hmcl.ui.construct.SpinnerPane?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<fx:define>
<Insets fx:id="insets" bottom="12" />
</fx:define>
<SpinnerPane fx:id="spinnerPane" styleClass="large-spinner-pane">
<VBox fx:id="borderPane" alignment="CENTER" FXUtils.limitWidth="500">
<ComponentList>
<BorderPane><left><Label text="%modpack.task.install.will" /></left><center><Label BorderPane.alignment="CENTER_RIGHT" fx:id="lblModpackLocation" /></center></BorderPane>
<BorderPane><left><Label BorderPane.alignment="CENTER_LEFT" text="%archive.name" /></left><center><JFXTextField BorderPane.alignment="CENTER_RIGHT" fx:id="txtModpackName" StackPane.margin="$insets" /></center></BorderPane>
<BorderPane><left><Label text="%modpack.name"/></left><center><Label BorderPane.alignment="CENTER_RIGHT" fx:id="lblName" /></center></BorderPane>
<BorderPane><left><Label text="%archive.version"/></left><center><Label BorderPane.alignment="CENTER_RIGHT" fx:id="lblVersion" /></center></BorderPane>
<BorderPane><left><Label text="%archive.author"/></left><center><Label BorderPane.alignment="CENTER_RIGHT" fx:id="lblAuthor" /></center></BorderPane>
<BorderPane>
<left><JFXButton fx:id="btnDescription" onMouseClicked="#onDescribe" text="%modpack.description" styleClass="jfx-button-border" /></left>
<right><JFXButton buttonType="RAISED" fx:id="btnInstall" onMouseClicked="#onInstall" text="%button.install" styleClass="jfx-button-raised" /></right>
</BorderPane>
</ComponentList>
</VBox>
</SpinnerPane>
</fx:root>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.FXUtils?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane" mouseTransparent="true">
<VBox alignment="CENTER">
<Label alignment="CENTER" fx:id="lblGameVersion" style="-fx-color: gray;" />
</VBox>
<BorderPane>
<left>
<HBox fx:id="leftPane" alignment="CENTER_LEFT">
<StackPane fx:id="imageViewContainer" FXUtils.limitWidth="32" FXUtils.limitHeight="32">
<ImageView preserveRatio="true" fx:id="imageView" smooth="false">
<Image url="/assets/img/icon.png" />
</ImageView>
</StackPane>
<Label fx:id="lblSelfVersion" style="-fx-font-size: 15;" />
</HBox>
</left>
<right>
<fx:include source="/assets/svg/arrow-right.fxml" />
</right>
</BorderPane>
</fx:root>

View File

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.animation.TransitionPane?>
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
<?import org.jackhuang.hmcl.ui.construct.HintPane?>
<?import javafx.geometry.Insets?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="BorderPane"
prefHeight="400.0" prefWidth="600.0">
<top>
<HintPane onMouseClicked="#onSponsor" text="%sponsor.bmclapi" styleClass="sponsor-pane">
<BorderPane.margin>
<Insets top="10" right="10" left="10" />
</BorderPane.margin>
</HintPane>
</top>
<center>
<TransitionPane fx:id="root">
<JFXSpinner fx:id="spinner" styleClass="first-spinner" />
<StackPane fx:id="center" style="-fx-padding: 10;">
<ComponentList fx:id="centrePane" styleClass="no-padding">
<HBox fx:id="checkPane" spacing="10">
<JFXCheckBox fx:id="chkRelease" text="%version.game.releases" selected="true">
<HBox.margin>
<Insets top="10" bottom="10" />
</HBox.margin>
</JFXCheckBox>
<JFXCheckBox fx:id="chkSnapshot" text="%version.game.snapshots">
<HBox.margin>
<Insets top="10" bottom="10" />
</HBox.margin>
</JFXCheckBox>
<JFXCheckBox fx:id="chkOld" text="%version.game.old">
<HBox.margin>
<Insets top="10" bottom="10" />
</HBox.margin>
</JFXCheckBox>
<HBox HBox.hgrow="ALWAYS" />
<JFXButton fx:id="btnRefresh" styleClass="jfx-tool-bar-button" onMouseClicked="#onRefresh" text="%button.refresh" />
</HBox>
<JFXListView fx:id="list" styleClass="jfx-list-view-float" VBox.vgrow="ALWAYS">
</JFXListView>
</ComponentList>
</StackPane>
<StackPane fx:id="failedPane" styleClass="notice-pane">
<Label onMouseClicked="#onRefresh" text="%download.failed.refresh" />
</StackPane>
<StackPane fx:id="emptyPane" styleClass="notice-pane">
<Label onMouseClicked="#onBack" text="%download.failed.empty" />
</StackPane>
</TransitionPane>
</center>
</fx:root>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.StackPane?>
<?import org.jackhuang.hmcl.ui.construct.SpinnerPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<JFXDialogLayout>
<heading>
<HBox>
<Label fx:id="title" />
</HBox>
</heading>
<body>
<VBox fx:id="vbox">
</VBox>
</body>
<actions>
<Label fx:id="lblCreationWarning"/>
<SpinnerPane fx:id="acceptPane" styleClass="small-spinner-pane">
<JFXButton fx:id="acceptButton" text="%button.ok" styleClass="dialog-accept"/>
</SpinnerPane>
<JFXButton fx:id="cancelButton" styleClass="dialog-cancel" text="%button.cancel" />
</actions>
</JFXDialogLayout>
</fx:root>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import java.lang.String?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<HBox spacing="8" styleClass="jfx-dialog-layout">
<Label fx:id="graphic" translateX="10" translateY="10" minWidth="40" maxWidth="40" minHeight="40"
maxHeight="40"/>
<VBox HBox.hgrow="ALWAYS">
<StackPane>
<styleClass>
<String fx:value="jfx-layout-heading"/>
<String fx:value="title"/>
</styleClass>
<Label fx:id="title" text="%message.info"/>
</StackPane>
<StackPane fx:id="content" styleClass="jfx-layout-body"/>
<HBox fx:id="actions" styleClass="jfx-layout-actions"/>
</VBox>
</HBox>
</fx:root>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTreeView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<fx:define>
</fx:define>
<BorderPane>
<center>
<JFXTreeView fx:id="treeView" />
</center>
<bottom>
<HBox alignment="CENTER_RIGHT" style="-fx-padding: 16 16 16 0;">
<JFXButton fx:id="btnNext" onMouseClicked="#onNext" prefWidth="100" prefHeight="40" buttonType="RAISED"
text="%wizard.next" styleClass="jfx-button-raised"/>
</HBox>
</bottom>
</BorderPane>
</fx:root>

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.construct.TwoLineListItem?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<fx:define>
<Insets fx:id="insets" topRightBottomLeft="8" />
</fx:define>
<VBox fx:id="list" styleClass="jfx-list-view" maxHeight="150" maxWidth="300">
<Label padding="${insets}" text="%modpack.export.as" />
<JFXButton fx:id="btnMCBBS" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.type.mcbbs" subtitle="%modpack.type.mcbbs.export" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnMultiMC" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.type.multimc" subtitle="%modpack.type.multimc.export" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
<JFXButton fx:id="btnServer" prefWidth="${list.width}">
<graphic>
<BorderPane mouseTransparent="true">
<left>
<TwoLineListItem title="%modpack.type.server" subtitle="%modpack.type.server.export" />
</left>
<right>
<fx:include BorderPane.alignment="CENTER" source="/assets/svg/arrow-right.fxml"/>
</right>
</BorderPane>
</graphic>
</JFXButton>
</VBox>
</fx:root>

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXCheckBox?>
<?import com.jfoenix.controls.JFXTextField?>
<?import com.jfoenix.validation.RequiredFieldValidator?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
<?import org.jackhuang.hmcl.ui.construct.FileItem?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<ScrollPane fx:id="scroll" fitToHeight="true" fitToWidth="true">
<VBox fx:id="rootPane" style="-fx-padding: 20;">
<ComponentList depth="1">
<BorderPane> <!-- Name -->
<left>
<VBox alignment="CENTER_LEFT">
<Label text="%profile.name" BorderPane.alignment="CENTER_LEFT"/>
</VBox>
</left>
<right>
<JFXTextField fx:id="txtProfileName" BorderPane.alignment="CENTER_RIGHT">
<BorderPane.margin>
<Insets top="8" bottom="8" />
</BorderPane.margin>
<validators>
<RequiredFieldValidator message="%input.not_empty" />
</validators>
</JFXTextField>
</right>
</BorderPane>
<FileItem fx:id="gameDir" name="%profile.instance_directory" title="%profile.instance_directory.choose"/>
<JFXCheckBox fx:id="toggleUseRelativePath" text="%profile.use_relative_path" StackPane.alignment="CENTER_LEFT">
<StackPane.margin>
<Insets left="-10"/>
</StackPane.margin>
</JFXCheckBox>
</ComponentList>
</VBox>
</ScrollPane>
<BorderPane pickOnBounds="false" style="-fx-padding: 20;">
<right>
<JFXButton BorderPane.alignment="BOTTOM_RIGHT" fx:id="btnSave" onMouseClicked="#onSave" prefWidth="100" prefHeight="40"
buttonType="RAISED" text="%button.save" styleClass="jfx-button-raised"/>
</right>
</BorderPane>
</fx:root>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.*?>
<?import org.jackhuang.hmcl.ui.construct.TaskListPane?>
<?import org.jackhuang.hmcl.ui.FXUtils?>
<fx:root xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
type="StackPane" FXUtils.limitWidth="500" FXUtils.limitHeight="300">
<BorderPane>
<center>
<VBox style="-fx-padding: 16px;">
<Label fx:id="lblTitle" style="-fx-font-size: 14px; -fx-font-weight: BOLD;" />
<ScrollPane fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
<TaskListPane fx:id="taskListPane" />
</ScrollPane>
</VBox>
</center>
<bottom>
<StackPane style="-fx-padding: 0 8px 8px 8px;">
<Label StackPane.alignment="CENTER_LEFT" fx:id="lblProgress" />
<JFXButton StackPane.alignment="CENTER_RIGHT" fx:id="btnCancel" text="%button.cancel" />
</StackPane>
</bottom>
</BorderPane>
</fx:root>

View File

@ -28,7 +28,7 @@ data class Platform(
)
}
val jfxModules = listOf("base", "graphics", "controls", "fxml", "media", "web")
val jfxModules = listOf("base", "graphics", "controls", "media", "web")
val jfxMirrorRepos = listOf("https://maven.aliyun.com/repository/central")
val jfxDependenciesFile = project("HMCL").buildDir.resolve("openjfx-dependencies.json")
val jfxPlatforms = listOf(