From 7ab22b0e079398f80f81e2289d7b645a55a477d4 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 21 Jan 2026 22:05:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8F=B3=E9=94=AE=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E4=BE=A7=E8=BE=B9=E6=A0=8F=E5=BC=B9=E5=87=BA=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=AE=9E=E4=BE=8B=E8=8F=9C=E5=8D=95=20(#5269)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jackhuang/hmcl/ui/FXUtils.java | 9 ++++++++ .../org/jackhuang/hmcl/ui/main/MainPage.java | 23 +++++++------------ .../org/jackhuang/hmcl/ui/main/RootPage.java | 21 +++++++++++------ .../hmcl/ui/terracotta/TerracottaPage.java | 9 ++++++++ .../hmcl/ui/versions/GameListPopupMenu.java | 15 ++++++++++++ 5 files changed, 55 insertions(+), 22 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index 60d8608b5..403350a53 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -1405,6 +1405,15 @@ public final class FXUtils { }); } + public static void onSecondaryButtonClicked(Node node, Runnable action) { + node.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> { + if (e.getButton() == MouseButton.SECONDARY) { + action.run(); + e.consume(); + } + }); + } + public static N prepareNode(N node) { Scene dummyScene = new Scene(node); StyleSheets.init(dummyScene); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java index 10ebffdc0..97d604cc8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java @@ -59,7 +59,6 @@ import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; -import org.jackhuang.hmcl.ui.versions.GameItem; import org.jackhuang.hmcl.ui.versions.GameListPopupMenu; import org.jackhuang.hmcl.ui.versions.Versions; import org.jackhuang.hmcl.upgrade.RemoteVersion; @@ -246,7 +245,14 @@ public final class MainPage extends StackPane implements DecoratorPage { menuButton = new JFXButton(); menuButton.getStyleClass().add("menu-button"); - menuButton.setOnAction(e -> onMenu()); + menuButton.setOnAction(e -> GameListPopupMenu.show( + menuButton, + JFXPopup.PopupVPosition.BOTTOM, + JFXPopup.PopupHPosition.RIGHT, + 0, + -menuButton.getHeight(), + profile, versions + )); FXUtils.installFastTooltip(menuButton, i18n("version.switch")); menuButton.setGraphic(SVG.ARROW_DROP_UP.createIcon(30)); @@ -342,19 +348,6 @@ public final class MainPage extends StackPane implements DecoratorPage { Controllers.taskDialog(task, i18n("version.launch.empty.installing"), TaskCancellationAction.NORMAL); } - private void onMenu() { - GameListPopupMenu menu = new GameListPopupMenu(); - menu.getItems().setAll(versions.stream().map(it -> new GameItem(profile, it.getId())).toList()); - JFXPopup popup = new JFXPopup(menu); - popup.show( - menuButton, - JFXPopup.PopupVPosition.BOTTOM, - JFXPopup.PopupHPosition.RIGHT, - 0, - -menuButton.getHeight() - ); - } - private void onUpgrade() { RemoteVersion target = UpdateChecker.getLatestVersion(); if (target == null) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java index 22f3d97ca..38a712291 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java @@ -20,7 +20,6 @@ package org.jackhuang.hmcl.ui.main; import com.jfoenix.controls.JFXPopup; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.scene.control.Label; -import javafx.scene.input.MouseButton; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.event.EventBus; @@ -49,6 +48,7 @@ import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; import org.jackhuang.hmcl.ui.nbt.NBTEditorPage; import org.jackhuang.hmcl.ui.nbt.NBTFileType; import org.jackhuang.hmcl.ui.versions.GameAdvancedListItem; +import org.jackhuang.hmcl.ui.versions.GameListPopupMenu; import org.jackhuang.hmcl.ui.versions.Versions; import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.util.Lang; @@ -148,12 +148,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { // first item in left sidebar AccountAdvancedListItem accountListItem = new AccountAdvancedListItem(); accountListItem.setOnAction(e -> Controllers.navigate(Controllers.getAccountListPage())); - accountListItem.setOnMouseClicked(e -> { - if (e.getButton() == MouseButton.SECONDARY) { - showAccountListPopupMenu(accountListItem); - e.consume(); - } - }); + FXUtils.onSecondaryButtonClicked(accountListItem, () -> showAccountListPopupMenu(accountListItem)); accountListItem.accountProperty().bind(Accounts.selectedAccountProperty()); // second item in left sidebar @@ -174,6 +169,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { if (AnimationUtils.isAnimationEnabled()) { FXUtils.prepareOnMouseEnter(gameListItem, Controllers::prepareVersionPage); } + FXUtils.onSecondaryButtonClicked(gameListItem, () -> showGameListPopupMenu(gameListItem)); // third item in left sidebar AdvancedListItem gameItem = new AdvancedListItem(); @@ -181,6 +177,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { gameItem.setActionButtonVisible(false); gameItem.setTitle(i18n("version.manage")); gameItem.setOnAction(e -> Controllers.navigate(Controllers.getGameListPage())); + FXUtils.onSecondaryButtonClicked(gameItem, () -> showGameListPopupMenu(gameItem)); // forth item in left sidebar AdvancedListItem downloadItem = new AdvancedListItem(); @@ -283,6 +280,16 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { popupMenu.getContent().add(scrollPane); popup.show(accountListItem, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.LEFT, accountListItem.getWidth(), 0); } + + public void showGameListPopupMenu(AdvancedListItem gameListItem) { + GameListPopupMenu.show(gameListItem, + JFXPopup.PopupVPosition.TOP, + JFXPopup.PopupHPosition.LEFT, + gameListItem.getWidth(), + 0, + getSkinnable().getMainPage().getProfile(), + getSkinnable().getMainPage().getVersions()); + } } private boolean checkedModpack = false; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java index 3dfde7e8c..d70e05eed 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.ui.terracotta; +import com.jfoenix.controls.JFXPopup; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -35,6 +36,7 @@ import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.ui.main.MainPage; +import org.jackhuang.hmcl.ui.versions.GameListPopupMenu; import org.jackhuang.hmcl.ui.versions.Versions; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.StringUtils; @@ -84,6 +86,13 @@ public class TerracottaPage extends DecoratorAnimatedPage implements DecoratorPa String currentId = mainPage.getCurrentGame(); return Lang.indexWhere(list, instance -> instance.getId().equals(currentId)); }, it -> mainPage.getProfile().setSelectedVersion(it.getId())); + + FXUtils.onSecondaryButtonClicked(item, () -> GameListPopupMenu.show(item, + JFXPopup.PopupVPosition.BOTTOM, + JFXPopup.PopupHPosition.LEFT, + item.getWidth(), + 0, + mainPage.getProfile(), mainPage.getVersions())); }) .addNavigationDrawerItem(i18n("terracotta.feedback.title"), SVG.FEEDBACK, () -> FXUtils.openLink(TerracottaMetadata.FEEDBACK_LINK)); BorderPane.setMargin(toolbar, new Insets(0, 0, 12, 0)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPopupMenu.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPopupMenu.java index 8210d8699..c26e982c2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPopupMenu.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPopupMenu.java @@ -26,6 +26,7 @@ import javafx.beans.property.StringProperty; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; @@ -34,15 +35,29 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.RipplerContainer; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.util.StringUtils; +import java.util.List; + import static org.jackhuang.hmcl.util.i18n.I18n.i18n; /// @author Glavo public final class GameListPopupMenu extends StackPane { + + public static void show(Node owner, JFXPopup.PopupVPosition vAlign, JFXPopup.PopupHPosition hAlign, + double initOffsetX, double initOffsetY, + Profile profile, List versions) { + GameListPopupMenu menu = new GameListPopupMenu(); + menu.getItems().setAll(versions.stream().map(it -> new GameItem(profile, it.getId())).toList()); + JFXPopup popup = new JFXPopup(menu); + popup.show(owner, vAlign, hAlign, initOffsetX, initOffsetY); + } + private final JFXListView listView = new JFXListView<>(); private final BooleanBinding isEmpty = Bindings.isEmpty(listView.getItems());