-
Notifications
You must be signed in to change notification settings - Fork 922
优化鼠标光标 & 添加按钮等悬停效果 & 关闭动画时禁用水波纹动画 [Gemini] #5757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3fc11b9
b863bca
3de4af0
b3d2410
dbde4e4
74cca51
1c3999f
35bc538
1b0b36a
8a770df
9974f6d
bc44508
ad0caf0
c53fb66
7db6ba5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |
| import javafx.css.converter.BooleanConverter; | ||
| import javafx.css.converter.PaintConverter; | ||
| import javafx.css.converter.SizeConverter; | ||
| import javafx.event.EventHandler; | ||
| import javafx.geometry.Bounds; | ||
| import javafx.scene.CacheHint; | ||
| import javafx.scene.Group; | ||
|
|
@@ -45,6 +46,8 @@ | |
| import javafx.scene.shape.Rectangle; | ||
| import javafx.scene.shape.Shape; | ||
| import javafx.util.Duration; | ||
| import org.jackhuang.hmcl.ui.animation.AnimationUtils; | ||
| import org.jackhuang.hmcl.ui.animation.Motion; | ||
|
|
||
| import java.util.*; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
|
|
@@ -76,6 +79,8 @@ public enum RipplerMask { | |
| protected RippleGenerator rippler; | ||
| protected Pane ripplerPane; | ||
| protected Node control; | ||
| private Animation coverAnimation; | ||
| private Rectangle hoverOverlay; | ||
|
|
||
| protected static final double RIPPLE_MAX_RADIUS = 300; | ||
| private static final Interpolator RIPPLE_INTERPOLATOR = Interpolator.SPLINE(0.0825, | ||
|
|
@@ -128,14 +133,53 @@ public JFXRippler(Node control, RipplerMask mask, RipplerPos pos) { | |
| setCache(true); | ||
| setCacheHint(CacheHint.SPEED); | ||
| setCacheShape(true); | ||
|
|
||
| EventHandler<MouseEvent> mouseEventHandler = event -> { | ||
| if (coverAnimation != null) { | ||
| coverAnimation.stop(); | ||
| } | ||
| boolean isEntered = event.getEventType() == MouseEvent.MOUSE_ENTERED; | ||
|
|
||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| coverAnimation = new Timeline(new KeyFrame(Motion.SHORT4, | ||
| new KeyValue(hoverOverlay.opacityProperty(), isEntered ? 1 : 0, isEntered ? Motion.EASE_IN : Motion.EASE_OUT))); | ||
| coverAnimation.play(); | ||
| } else { | ||
| interpolateBackground(isEntered ? 1 : 0); | ||
| } | ||
| }; | ||
|
|
||
| addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEventHandler); | ||
| addEventHandler(MouseEvent.MOUSE_EXITED, mouseEventHandler); | ||
| } | ||
|
|
||
| private void interpolateBackground(double frac) { | ||
| if (hoverOverlay == null) return; | ||
| hoverOverlay.setOpacity(frac); | ||
| } | ||
|
CiiLu marked this conversation as resolved.
|
||
|
|
||
| protected final void createRippleUI() { | ||
| // create rippler panels | ||
| rippler = new RippleGenerator(); | ||
| ripplerPane = new StackPane(); | ||
| ripplerPane.setMouseTransparent(true); | ||
| ripplerPane.getChildren().add(rippler); | ||
|
|
||
| hoverOverlay = new Rectangle(); | ||
| hoverOverlay.setManaged(false); | ||
| hoverOverlay.setCache(true); | ||
| hoverOverlay.setCacheHint(CacheHint.SPEED); | ||
| hoverOverlay.setOpacity(0); | ||
|
|
||
| hoverOverlay.fillProperty().bind(Bindings.createObjectBinding(() -> { | ||
| Paint currentFill = getRipplerFill(); | ||
| if (currentFill instanceof Color fill) { | ||
| return Color.color(fill.getRed(), fill.getGreen(), fill.getBlue(), 0.15); | ||
| } else { | ||
| return currentFill; | ||
| } | ||
| }, ripplerFillProperty())); | ||
|
|
||
| ripplerPane.getChildren().addAll(hoverOverlay, rippler); | ||
| getChildren().add(ripplerPane); | ||
| } | ||
|
|
||
|
|
@@ -325,16 +369,25 @@ public void showOverlay() { | |
| rippler.overlayRect.outAnimation.stop(); | ||
| } | ||
| rippler.createOverlay(); | ||
| rippler.overlayRect.inAnimation.play(); | ||
|
|
||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| rippler.overlayRect.inAnimation.play(); | ||
| } else { | ||
| rippler.overlayRect.inAnimation.stop(); | ||
| rippler.overlayRect.setOpacity(1); | ||
| } | ||
| } | ||
|
|
||
| public void hideOverlay() { | ||
| if (!forceOverlay) { | ||
| if (rippler.overlayRect != null) { | ||
| rippler.overlayRect.inAnimation.stop(); | ||
| } | ||
| if (rippler.overlayRect != null) { | ||
| rippler.overlayRect.outAnimation.play(); | ||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| rippler.overlayRect.outAnimation.play(); | ||
| } else { | ||
| rippler.overlayRect.outAnimation.stop(); | ||
| rippler.overlayRect.setOpacity(0); | ||
| } | ||
| } | ||
| } else { | ||
| System.err.println("Ripple Overlay is forced!"); | ||
|
|
@@ -373,32 +426,48 @@ void createRipple() { | |
| } | ||
| this.resetClip = false; | ||
|
|
||
| // create the ripple effect | ||
| final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY); | ||
| getChildren().add(ripple); | ||
| ripplesQueue.add(ripple); | ||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| // create the ripple effect | ||
| final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY); | ||
| getChildren().add(ripple); | ||
| ripplesQueue.add(ripple); | ||
|
|
||
| // animate the ripple | ||
| overlayRect.outAnimation.stop(); | ||
| overlayRect.inAnimation.play(); | ||
| ripple.inAnimation.play(); | ||
| // animate the ripple | ||
| overlayRect.outAnimation.stop(); | ||
| overlayRect.inAnimation.play(); | ||
| ripple.inAnimation.play(); | ||
| } else { | ||
| // apply simple press effect when animation is disabled | ||
| overlayRect.outAnimation.stop(); | ||
| overlayRect.inAnimation.stop(); | ||
| overlayRect.setOpacity(1); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void releaseRipple() { | ||
| Ripple ripple = ripplesQueue.poll(); | ||
| if (ripple != null) { | ||
| ripple.inAnimation.stop(); | ||
| ripple.outAnimation = new Timeline( | ||
| new KeyFrame(Duration.millis(Math.min(800, (0.9 * 500) / ripple.getScaleX())) | ||
| , ripple.outKeyValues)); | ||
| ripple.outAnimation.setOnFinished((event) -> getChildren().remove(ripple)); | ||
| ripple.outAnimation.play(); | ||
| if (generating.getAndSet(false)) { | ||
| if (overlayRect != null) { | ||
| overlayRect.inAnimation.stop(); | ||
| if (!forceOverlay) { | ||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| ripple.outAnimation = new Timeline( | ||
| new KeyFrame(Duration.millis(Math.min(800, (0.9 * 500) / ripple.getScaleX())) | ||
| , ripple.outKeyValues)); | ||
| ripple.outAnimation.setOnFinished((event) -> getChildren().remove(ripple)); | ||
| ripple.outAnimation.play(); | ||
| } else { | ||
| getChildren().remove(ripple); | ||
| } | ||
| } | ||
| if (generating.getAndSet(false)) { | ||
| if (overlayRect != null) { | ||
| overlayRect.inAnimation.stop(); | ||
| if (!forceOverlay) { | ||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| overlayRect.outAnimation.play(); | ||
| } else { | ||
| overlayRect.outAnimation.stop(); | ||
| overlayRect.setOpacity(0); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -548,8 +617,14 @@ private void resetOverLay() { | |
| if (rippler.overlayRect != null) { | ||
| rippler.overlayRect.inAnimation.stop(); | ||
| final RippleGenerator.OverLayRipple oldOverlay = rippler.overlayRect; | ||
| rippler.overlayRect.outAnimation.setOnFinished((finish) -> rippler.getChildren().remove(oldOverlay)); | ||
| rippler.overlayRect.outAnimation.play(); | ||
|
|
||
| if (AnimationUtils.isAnimationEnabled()) { | ||
| rippler.overlayRect.outAnimation.setOnFinished((finish) -> rippler.getChildren().remove(oldOverlay)); | ||
| rippler.overlayRect.outAnimation.play(); | ||
| } else { | ||
| rippler.overlayRect.outAnimation.stop(); | ||
| rippler.getChildren().remove(oldOverlay); | ||
| } | ||
| rippler.overlayRect = null; | ||
| } | ||
| } | ||
|
|
@@ -561,6 +636,17 @@ private void resetClip() { | |
| protected void resetRippler() { | ||
| resetOverLay(); | ||
| resetClip(); | ||
|
|
||
| if (hoverOverlay != null && control != null) { | ||
| Bounds bounds = control.getBoundsInParent(); | ||
| double diffMinX = Math.abs(control.getBoundsInLocal().getMinX() - control.getLayoutBounds().getMinX()); | ||
| double diffMinY = Math.abs(control.getBoundsInLocal().getMinY() - control.getLayoutBounds().getMinY()); | ||
| hoverOverlay.setX(bounds.getMinX() + diffMinX - snappedLeftInset()); | ||
| hoverOverlay.setY(bounds.getMinY() + diffMinY - snappedTopInset()); | ||
| hoverOverlay.setWidth(control.getLayoutBounds().getWidth()); | ||
| hoverOverlay.setHeight(control.getLayoutBounds().getHeight()); | ||
| hoverOverlay.setClip(getMask()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
|
Comment on lines
+640
to
+649
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 当 if (hoverOverlay != null && control != null) {
Bounds bounds = control.getBoundsInParent();
double diffMinX = Math.abs(control.getBoundsInLocal().getMinX() - control.getLayoutBounds().getMinX());
double diffMinY = Math.abs(control.getBoundsInLocal().getMinY() - control.getLayoutBounds().getMinY());
hoverOverlay.setX(bounds.getMinX() + diffMinX - snappedLeftInset());
hoverOverlay.setY(bounds.getMinY() + diffMinY - snappedTopInset());
hoverOverlay.setWidth(control.getLayoutBounds().getWidth());
hoverOverlay.setHeight(control.getLayoutBounds().getHeight());
if (getMaskType() == RipplerMask.RECT) {
hoverOverlay.setClip(null);
} else {
hoverOverlay.setClip(getMask());
}
} |
||
| } | ||
|
|
||
| /*************************************************************************** | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.