Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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);
}
Expand Down