From c75d0fd075b2e3c709497cd8f5942efb1c54592c Mon Sep 17 00:00:00 2001 From: postyizhan <185839426@qq.com> Date: Mon, 3 Aug 2026 11:41:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=E6=B8=B8=E6=88=8F=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E8=B7=AF=E5=BE=84=E6=B7=BB=E5=8A=A0=E6=82=AC=E6=B5=AE?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/ui/construct/RipplerContainer.java | 40 ++++++++++++++++++- .../directory/GameDirectoryListItemSkin.java | 8 +++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/RipplerContainer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/RipplerContainer.java index 4c6fae21bee..811d5298218 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/RipplerContainer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/RipplerContainer.java @@ -23,7 +23,9 @@ import javafx.css.converter.PaintConverter; import javafx.event.EventHandler; import javafx.geometry.Insets; +import javafx.geometry.Point2D; import javafx.scene.Node; +import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; @@ -47,9 +49,15 @@ public class RipplerContainer extends StackPane { private final Node container; private final StackPane buttonContainer = new StackPane(); - private final JFXRippler buttonRippler = new JFXRippler(new StackPane()) { + private final ButtonRippler buttonRippler = new ButtonRippler(); + + private final class ButtonRippler extends JFXRippler { private static final Background DEFAULT_MASK_BACKGROUND = new Background(new BackgroundFill(Color.WHITE, DEFAULT_RADII, Insets.EMPTY)); + private ButtonRippler() { + super(new StackPane()); + } + @Override protected Node getMask() { StackPane mask = new StackPane(); @@ -61,7 +69,18 @@ protected Node getMask() { ); return mask; } - }; + + private void createRippleAtScene(double sceneX, double sceneY) { + Point2D localPoint = getControl().sceneToLocal(sceneX, sceneY); + if (localPoint != null) { + super.createRipple(localPoint.getX(), localPoint.getY()); + } + } + + private void releaseCurrentRipple() { + super.releaseRipple(); + } + } private Transition coverAnimation; @@ -167,6 +186,23 @@ public JFXRippler getRippler() { return buttonRippler; } + /// Installs ripple event handlers on an interactive descendant of [#getContainer()]. + /// + /// This preserves the ripple effect when the node participates in mouse picking and therefore + /// prevents events from reaching the rippler control behind the container. + public void installRippleTrigger(Node node) { + node.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> { + if (event.getButton() == MouseButton.PRIMARY) { + buttonRippler.createRippleAtScene(event.getSceneX(), event.getSceneY()); + } + }); + node.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> { + if (event.getButton() == MouseButton.PRIMARY) { + buttonRippler.releaseCurrentRipple(); + } + }); + } + public Node getContainer() { return container; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/directory/GameDirectoryListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/directory/GameDirectoryListItemSkin.java index c68eb053af2..6c48522baab 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/directory/GameDirectoryListItemSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/directory/GameDirectoryListItemSkin.java @@ -22,6 +22,7 @@ import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.SkinBase; +import javafx.scene.control.Tooltip; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import org.jackhuang.hmcl.setting.GameDirectoryManager; @@ -67,10 +68,13 @@ public GameDirectoryListItemSkin(GameDirectoryListItem skinnable) { FXUtils.onClicked(getSkinnable(), () -> GameDirectoryManager.setSelectedGameDirectory(skinnable.getGameDirectory())); TwoLineListItem item = new TwoLineListItem(); + item.setMouseTransparent(false); item.setPickOnBounds(false); BorderPane.setAlignment(item, Pos.CENTER); root.setCenter(item); + container.installRippleTrigger(item); + HBox right = new HBox(); right.setAlignment(Pos.CENTER_RIGHT); @@ -81,7 +85,9 @@ public GameDirectoryListItemSkin(GameDirectoryListItem skinnable) { root.setRight(right); item.titleProperty().set(GameDirectoryManager.getGameDirectoryDisplayName(skinnable.getGameDirectory())); - item.subtitleProperty().set(skinnable.getGameDirectory().getPath().toString()); + String gameDirectoryPath = skinnable.getGameDirectory().getPath().toString(); + item.subtitleProperty().set(gameDirectoryPath); + FXUtils.installSlowTooltip(item.getSubtitleLabel(), new Tooltip(gameDirectoryPath)); getChildren().setAll(container); }