feat: press esc key to close dialog

This commit is contained in:
Haowei Wen 2021-08-20 07:16:50 +08:00
parent 588fe5cb5f
commit 28d6f1f19a
No known key found for this signature in database
GPG Key ID: 5BC167F73EA558E4
15 changed files with 182 additions and 81 deletions

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -51,6 +51,7 @@ import org.jackhuang.hmcl.ui.DialogController;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.LogWindow;
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
import org.jackhuang.hmcl.util.*;
@ -328,9 +329,18 @@ public final class LauncherHelper {
if (acceptableJava.isPresent()) {
setting.setJavaVersion(acceptableJava.get());
} else {
MessageDialogPane dialog = new MessageDialogPane(
i18n("launch.advice.require_newer_java_version",
gameVersion.toString(),
version.getJavaVersion().getMajorVersion()),
i18n("message.warning"),
MessageType.QUESTION);
JFXButton linkButton = new JFXButton(i18n("download.external_link"));
linkButton.setOnAction(e -> FXUtils.openLink("https://adoptopenjdk.net/"));
linkButton.getStyleClass().add("dialog-accept");
dialog.addButton(linkButton);
JFXButton yesButton = new JFXButton(i18n("button.ok"));
yesButton.setOnAction(event -> {
downloadJava(version.getJavaVersion(), profile)
@ -346,16 +356,14 @@ public final class LauncherHelper {
}, Platform::runLater).thenAccept(x -> onAccept.run());
});
yesButton.getStyleClass().add("dialog-accept");
dialog.addButton(yesButton);
JFXButton noButton = new JFXButton(i18n("button.cancel"));
noButton.getStyleClass().add("dialog-cancel");
dialog.addButton(noButton);
dialog.setCancelButton(noButton);
Controllers.dialogWithButtons(
i18n("launch.advice.require_newer_java_version",
gameVersion.toString(),
version.getJavaVersion().getMajorVersion()),
i18n("message.warning"),
MessageType.QUESTION,
linkButton, yesButton, noButton);
Controllers.dialog(dialog);
flag = true;
}
}

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -17,11 +17,11 @@
*/
package org.jackhuang.hmcl.ui;
import com.jfoenix.controls.JFXButton;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ButtonBase;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
@ -194,20 +194,24 @@ public final class Controllers {
dialog(text, title, type, null);
}
public static void dialog(String text, String title, MessageType type, Runnable onAccept) {
dialog(new MessageDialogPane(text, title, type, onAccept));
public static void dialog(String text, String title, MessageType type, Runnable ok) {
dialog(MessageDialogPane.ok(text, title, type, ok));
}
public static void confirm(String text, String title, Runnable onAccept, Runnable onCancel) {
confirm(text, title, MessageType.QUESTION, onAccept, onCancel);
public static void confirm(String text, String title, Runnable yes, Runnable no) {
confirm(text, title, MessageType.QUESTION, yes, no);
}
public static void confirm(String text, String title, MessageType type, Runnable onAccept, Runnable onCancel) {
dialog(new MessageDialogPane(text, title, type, onAccept, onCancel));
public static void confirm(String text, String title, MessageType type, Runnable yes, Runnable no) {
dialog(MessageDialogPane.yesOrNo(text, title, type, yes, no));
}
public static void dialogWithButtons(String text, String title, MessageType type, JFXButton... buttons) {
dialog(MessageDialogPane.fromButtons(text, title, type, buttons));
public static void confirmAction(String text, String title, MessageType type, ButtonBase actionButton) {
dialog(MessageDialogPane.actionOrCancel(text, title, type, actionButton, null));
}
public static void confirmAction(String text, String title, MessageType type, ButtonBase actionButton, Runnable cancel) {
dialog(MessageDialogPane.actionOrCancel(text, title, type, actionButton, cancel));
}
public static CompletableFuture<String> prompt(String title, FutureCallback<String> onResult) {

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -38,6 +38,8 @@ import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
@ -541,4 +543,13 @@ public final class FXUtils {
popup.hide();
};
}
public static void onEscPressed(Node node, Runnable action) {
node.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.ESCAPE) {
action.run();
e.consume();
}
});
}
}

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -27,6 +27,7 @@ import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class UpgradeDialog extends JFXDialogLayout {
@ -60,6 +61,7 @@ public class UpgradeDialog extends JFXDialogLayout {
cancelButton.setOnMouseClicked(e -> fireEvent(new DialogCloseEvent()));
setActions(updateButton, cancelButton);
onEscPressed(this, cancelButton::fire);
}
}
}

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -33,6 +33,7 @@ import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import java.util.function.Consumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
public class AccountLoginPane extends StackPane {
@ -54,6 +55,8 @@ public class AccountLoginPane extends StackPane {
lblUsername.setText(oldAccount.getUsername());
txtPassword.setOnAction(e -> onAccept());
onEscPressed(this, this::onCancel);
}
@FXML

View File

@ -137,6 +137,8 @@ public class AddAccountPane extends StackPane {
.map(FXCollections::observableList));
Bindings.bindContent(linksContainer.getChildren(), links);
linksContainer.visibleProperty().bind(cboServers.visibleProperty());
onEscPressed(this, this::onCreationCancel);
}
private boolean validateUsername(String username) {
@ -283,6 +285,8 @@ public class AddAccountPane extends StackPane {
hbox.setAlignment(Pos.CENTER_RIGHT);
hbox.getChildren().add(cancel);
setBottom(hbox);
onEscPressed(this, cancel::fire);
}
@Override

View File

@ -38,6 +38,7 @@ 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;
@ -68,6 +69,8 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
btnAddNext.disableProperty().bind(txtServerUrl.textProperty().isEmpty());
nextPane.hideSpinner();
onEscPressed(this, this::onAddCancel);
}
@Override

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -18,17 +18,20 @@
package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXButton;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class MessageDialogPane extends StackPane {
@ -41,10 +44,6 @@ public final class MessageDialogPane extends StackPane {
FINE,
}
@FXML
private JFXButton acceptButton;
@FXML
private JFXButton cancelButton;
@FXML
private Label content;
@FXML
@ -54,20 +53,16 @@ public final class MessageDialogPane extends StackPane {
@FXML
private HBox actions;
public MessageDialogPane(String text, String title, MessageType type, Runnable onAccept) {
private @Nullable ButtonBase cancelButton;
public MessageDialogPane(@NotNull String text, @Nullable String title, @NotNull MessageType type) {
FXUtils.loadFXML(this, "/assets/fxml/message-dialog.fxml");
content.setText(text);
if (title != null)
this.title.setText(title);
content.setText(text);
acceptButton.setOnMouseClicked(e -> {
fireEvent(new DialogCloseEvent());
Optional.ofNullable(onAccept).ifPresent(Runnable::run);
});
actions.getChildren().remove(cancelButton);
switch (type) {
case INFORMATION:
graphic.setGraphic(SVG.infoCircle(Theme.blackFillBinding(), 40, 40));
@ -87,33 +82,70 @@ public final class MessageDialogPane extends StackPane {
default:
throw new IllegalArgumentException("Unrecognized message box message type " + type);
}
}
public MessageDialogPane(String text, String title, MessageType type, Runnable onAccept, Runnable onCancel) {
this(text, title, type, onAccept);
cancelButton.setVisible(true);
cancelButton.setOnMouseClicked(e -> {
fireEvent(new DialogCloseEvent());
Optional.ofNullable(onCancel).ifPresent(Runnable::run);
onEscPressed(this, () -> {
if (cancelButton != null) {
cancelButton.fire();
}
});
acceptButton.setText(i18n("button.yes"));
cancelButton.setText(i18n("button.no"));
actions.getChildren().add(cancelButton);
}
public static MessageDialogPane fromButtons(String text, String title, MessageType type, JFXButton[] buttons) {
MessageDialogPane pane = new MessageDialogPane(text, title, type, null);
public void addButton(ButtonBase btn) {
btn.addEventHandler(ActionEvent.ACTION, e -> fireEvent(new DialogCloseEvent()));
actions.getChildren().add(btn);
}
for (JFXButton button : buttons) {
button.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> {
pane.fireEvent(new DialogCloseEvent());
});
public void setCancelButton(@Nullable ButtonBase btn) {
cancelButton = btn;
}
public static MessageDialogPane ok(String text, String title, MessageType type, Runnable ok) {
MessageDialogPane dialog = new MessageDialogPane(text, title, type);
JFXButton btnOk = new JFXButton(i18n("button.ok"));
btnOk.getStyleClass().add("dialog-accept");
if (ok != null) {
btnOk.setOnAction(e -> ok.run());
}
dialog.addButton(btnOk);
dialog.setCancelButton(btnOk);
pane.actions.getChildren().setAll(buttons);
return pane;
return dialog;
}
public static MessageDialogPane yesOrNo(String text, String title, MessageType type, Runnable yes, Runnable no) {
MessageDialogPane dialog = new MessageDialogPane(text, title, type);
JFXButton btnYes = new JFXButton(i18n("button.yes"));
btnYes.getStyleClass().add("dialog-accept");
if (yes != null) {
btnYes.setOnAction(e -> yes.run());
}
dialog.addButton(btnYes);
JFXButton btnNo = new JFXButton(i18n("button.no"));
btnNo.getStyleClass().add("dialog-cancel");
if (no != null) {
btnNo.setOnAction(e -> no.run());
}
dialog.addButton(btnNo);
dialog.setCancelButton(btnNo);
return dialog;
}
public static MessageDialogPane actionOrCancel(String text, String title, MessageType type, ButtonBase actionButton, Runnable cancel) {
MessageDialogPane dialog = new MessageDialogPane(text, title, type);
dialog.addButton(actionButton);
JFXButton btnCancel = new JFXButton(i18n("button.cancel"));
btnCancel.getStyleClass().add("dialog-cancel");
if (cancel != null) {
btnCancel.setOnAction(e -> cancel.run());
}
dialog.addButton(btnCancel);
dialog.setCancelButton(btnCancel);
return dialog;
}
}

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -34,6 +34,8 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.FutureCallback;
import org.jackhuang.hmcl.util.StringUtils;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -115,6 +117,8 @@ public class PromptDialogPane extends StackPane {
lblCreationWarning.setText(msg);
});
});
onEscPressed(this, cancelButton::fire);
}
public CompletableFuture<List<Builder.Question<?>>> getCompletableFuture() {

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -21,11 +21,20 @@ import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.util.Logging;
import java.util.Optional;
import java.util.Stack;
public class StackContainerPane extends StackPane {
private final Stack<Node> stack = new Stack<>();
public Optional<Node> peek() {
if (stack.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(stack.peek());
}
}
public void push(Node node) {
stack.push(node);
getChildren().setAll(node);

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -32,6 +32,7 @@ import org.jackhuang.hmcl.ui.FXUtils;
import java.util.Optional;
import java.util.function.Consumer;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
public class TaskExecutorDialogPane extends StackPane {
@ -53,7 +54,7 @@ public class TaskExecutorDialogPane extends StackPane {
setCancel(cancel);
btnCancel.setOnMouseClicked(e -> {
btnCancel.setOnAction(e -> {
Optional.ofNullable(executor).ifPresent(TaskExecutor::cancel);
onCancel.accept(this);
});
@ -76,6 +77,8 @@ public class TaskExecutorDialogPane extends StackPane {
});
};
FileDownloadTask.speedEvent.channel(FileDownloadTask.SpeedEvent.class).registerWeak(speedEventHandler);
onEscPressed(this, btnCancel::fire);
}
public void setExecutor(TaskExecutor executor) {

View File

@ -26,6 +26,7 @@ import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.input.DragEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import org.jackhuang.hmcl.Launcher;
@ -84,6 +85,34 @@ public class DecoratorController {
setupBackground();
setupAuthlibInjectorDnD();
// pass key events to current dialog
decorator.addEventFilter(KeyEvent.ANY, e -> {
if (dialogPane == null || !dialogPane.peek().isPresent()) {
return;
}
Node currentDialog = dialogPane.peek().get();
if (!(e.getTarget() instanceof Node)) {
return;
}
boolean targetInDialog = false;
Node t = (Node) e.getTarget();
while (t != null) {
if (t == currentDialog) {
targetInDialog = true;
break;
}
t = t.getParent();
}
if (targetInDialog) {
return;
}
e.consume();
currentDialog.fireEvent(e.copyFor(e.getSource(), currentDialog));
});
}
public Decorator getDecorator() {
@ -216,14 +245,6 @@ public class DecoratorController {
}
}
private void onNavigating(Navigator.NavigationEvent event) {
if (event.getSource() != this.navigator) return;
Node from = event.getNode();
if (from instanceof DecoratorPage)
((DecoratorPage) from).back();
}
private void onNavigated(Navigator.NavigationEvent event) {
if (event.getSource() != this.navigator) return;
Node to = event.getNode();

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -58,6 +58,7 @@ import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.createToolbarButton;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair;
@ -225,6 +226,8 @@ class ModListPageSkin extends SkinBase<ModListPage> {
} else {
setActions(okButton, searchButton);
}
onEscPressed(this, okButton::fire);
}
}

View File

@ -1,6 +1,6 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
* Copyright (C) 2021 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
@ -118,10 +118,7 @@ public final class Versions {
deleteButton.getStyleClass().add("dialog-error");
deleteButton.setOnAction(e -> profile.getRepository().removeVersionFromDisk(version));
JFXButton cancelButton = new JFXButton(i18n("button.cancel"));
cancelButton.getStyleClass().add("dialog-cancel");
Controllers.dialogWithButtons(message, i18n("message.warning"), MessageDialogPane.MessageType.WARNING, deleteButton, cancelButton);
Controllers.confirmAction(message, i18n("message.warning"), MessageDialogPane.MessageType.WARNING, deleteButton);
}
public static CompletableFuture<String> renameVersion(Profile profile, String version) {

View File

@ -20,10 +20,7 @@
<StackPane styleClass="jfx-layout-body">
<Label fx:id="content" wrapText="true" />
</StackPane>
<HBox fx:id="actions" styleClass="jfx-layout-actions">
<JFXButton fx:id="acceptButton" styleClass="dialog-accept" text="%button.ok" />
<JFXButton fx:id="cancelButton" visible="false" styleClass="dialog-cancel" text="%button.cancel" />
</HBox>
<HBox fx:id="actions" styleClass="jfx-layout-actions" />
</VBox>
</HBox>
</fx:root>