|
@@ -1,6 +1,5 @@
|
|
|
package it.paprojects.materialfx.effects;
|
|
|
|
|
|
-import it.paprojects.materialfx.controls.MFXButton;
|
|
|
import javafx.animation.*;
|
|
|
import javafx.beans.property.DoubleProperty;
|
|
|
import javafx.beans.property.ObjectProperty;
|
|
@@ -10,6 +9,7 @@ import javafx.css.*;
|
|
|
import javafx.scene.Group;
|
|
|
import javafx.scene.control.Control;
|
|
|
import javafx.scene.effect.DropShadow;
|
|
|
+import javafx.scene.layout.Region;
|
|
|
import javafx.scene.paint.Color;
|
|
|
import javafx.scene.shape.Circle;
|
|
|
import javafx.scene.shape.Rectangle;
|
|
@@ -26,31 +26,31 @@ public class RippleGenerator extends Group {
|
|
|
private final String STYLE_CLASS = "ripple-generator";
|
|
|
private static final StyleablePropertyFactory<RippleGenerator> FACTORY = new StyleablePropertyFactory<>(Group.getClassCssMetaData());
|
|
|
|
|
|
- private final Control control;
|
|
|
+ private final Region region;
|
|
|
|
|
|
+ private RippleClipType rippleClipType = RippleClipType.RECTANGLE;
|
|
|
+ private DepthLevel level = null;
|
|
|
+ private boolean animateBackground = true;
|
|
|
private final Interpolator rippleInterpolator = Interpolator.SPLINE(0.0825, 0.3025, 0.0875, 0.9975);
|
|
|
//private final Interpolator rippleInterpolator = Interpolator.SPLINE(0.1, 0.50, 0.3, 0.85);
|
|
|
- private final Interpolator easeIn = Interpolator.EASE_IN;
|
|
|
- private final Interpolator easeOut = Interpolator.EASE_OUT;
|
|
|
- private final Interpolator easeBoth = Interpolator.EASE_BOTH;
|
|
|
- private ObjectProperty<Color> rippleColor = new StyleableObjectProperty<>(Color.ROYALBLUE)
|
|
|
+ private final ObjectProperty<Color> rippleColor = new StyleableObjectProperty<>(Color.ROYALBLUE)
|
|
|
{
|
|
|
@Override public CssMetaData getCssMetaData() { return StyleableProperties.RIPPLE_COLOR; }
|
|
|
@Override public Object getBean() { return this; }
|
|
|
- @Override public String getName() { return "ledColor"; }
|
|
|
+ @Override public String getName() { return "rippleColor"; }
|
|
|
};
|
|
|
private final DoubleProperty rippleRadius = new SimpleDoubleProperty(10.0);
|
|
|
private final ObjectProperty<Duration> inDuration = new SimpleObjectProperty<>(Duration.millis(700));
|
|
|
private final ObjectProperty<Duration> outDuration = new SimpleObjectProperty<>(inDuration.get().divide(2));
|
|
|
|
|
|
- private double generatorCenterX = 100.0;
|
|
|
- private double generatorCenterY = 100.0;
|
|
|
+ private double generatorCenterX = 0.0;
|
|
|
+ private double generatorCenterY = 0.0;
|
|
|
|
|
|
//================================================================================
|
|
|
// Constructors
|
|
|
//================================================================================
|
|
|
- public RippleGenerator(Control control) {
|
|
|
- this.control = control;
|
|
|
+ public RippleGenerator(Region region) {
|
|
|
+ this.region = region;
|
|
|
getStyleClass().add(STYLE_CLASS);
|
|
|
inDuration.addListener((observable, oldValue, newValue) -> {
|
|
|
if (!newValue.equals(oldValue)) {
|
|
@@ -64,24 +64,47 @@ public class RippleGenerator extends Group {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ public RippleGenerator(Region region, DepthLevel shadowLevel) {
|
|
|
+ this(region);
|
|
|
+ this.level = shadowLevel;
|
|
|
+ }
|
|
|
+
|
|
|
+ public RippleGenerator(Region region, RippleClipType rippleClipType) {
|
|
|
+ this(region);
|
|
|
+ this.rippleClipType = rippleClipType;
|
|
|
+ }
|
|
|
+
|
|
|
+ public RippleGenerator(Region region, DepthLevel shadowLevel, RippleClipType rippleClipType) {
|
|
|
+ this(region, shadowLevel);
|
|
|
+ this.rippleClipType = rippleClipType;
|
|
|
+ }
|
|
|
+
|
|
|
//================================================================================
|
|
|
// Methods
|
|
|
//================================================================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates a new {@code Ripple} at the specified coordinates.
|
|
|
+ * <p>
|
|
|
+ * Each {@code Ripple} is a new instance, this allows multiple ripples to be generated at the same time.
|
|
|
+ */
|
|
|
public void createRipple() {
|
|
|
final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY);
|
|
|
getChildren().add(ripple);
|
|
|
|
|
|
- Rectangle fillRect = new Rectangle(control.getWidth(), control.getHeight());
|
|
|
- fillRect.setFill(rippleColor.get());
|
|
|
- fillRect.setOpacity(0);
|
|
|
- getChildren().add(0, fillRect);
|
|
|
-
|
|
|
- KeyValue keyValueIn = new KeyValue(fillRect.opacityProperty(), 0.3);
|
|
|
- KeyValue keyValueOut = new KeyValue(fillRect.opacityProperty(), 0);
|
|
|
- KeyFrame keyFrameIn = new KeyFrame(inDuration.get(), keyValueIn);
|
|
|
- KeyFrame keyFrameOut = new KeyFrame(outDuration.get(), keyValueOut);
|
|
|
- ripple.inAnimation.getKeyFrames().add(keyFrameIn);
|
|
|
- ripple.outAnimation.getKeyFrames().add(keyFrameOut);
|
|
|
+ if (animateBackground) {
|
|
|
+ Rectangle fillRect = new Rectangle(region.getWidth(), region.getHeight());
|
|
|
+ fillRect.setFill(rippleColor.get());
|
|
|
+ fillRect.setOpacity(0);
|
|
|
+ getChildren().add(0, fillRect);
|
|
|
+
|
|
|
+ KeyValue keyValueIn = new KeyValue(fillRect.opacityProperty(), 0.3);
|
|
|
+ KeyValue keyValueOut = new KeyValue(fillRect.opacityProperty(), 0);
|
|
|
+ KeyFrame keyFrameIn = new KeyFrame(inDuration.get(), keyValueIn);
|
|
|
+ KeyFrame keyFrameOut = new KeyFrame(outDuration.get(), keyValueOut);
|
|
|
+ ripple.inAnimation.getKeyFrames().add(keyFrameIn);
|
|
|
+ ripple.outAnimation.getKeyFrames().add(keyFrameOut);
|
|
|
+ }
|
|
|
|
|
|
ripple.parallelTransition.setOnFinished(event -> getChildren().remove(ripple));
|
|
|
ripple.parallelTransition.play();
|
|
@@ -96,6 +119,14 @@ public class RippleGenerator extends Group {
|
|
|
this.generatorCenterY = generatorCenterY;
|
|
|
}
|
|
|
|
|
|
+ public void setAnimateBackground(boolean animateBackground) {
|
|
|
+ this.animateBackground = animateBackground;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setRippleClipType(RippleClipType rippleClipType) {
|
|
|
+ this.rippleClipType = rippleClipType;
|
|
|
+ }
|
|
|
+
|
|
|
public Color getRippleColor() {
|
|
|
return rippleColor.get();
|
|
|
}
|
|
@@ -144,11 +175,15 @@ public class RippleGenerator extends Group {
|
|
|
this.outDuration.set(outDuration);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * This class defines a ripple as a {@code Circle} and contains all it's properties, mainly
|
|
|
+ * it builds the animation of the ripple.
|
|
|
+ */
|
|
|
private class Ripple extends Circle {
|
|
|
//================================================================================
|
|
|
// Properties
|
|
|
//================================================================================
|
|
|
- private final int shadowDelta = 2;
|
|
|
+ private final int shadowDelta = 1;
|
|
|
|
|
|
private final Timeline inAnimation = new Timeline();
|
|
|
private final Timeline outAnimation = new Timeline();
|
|
@@ -162,20 +197,18 @@ public class RippleGenerator extends Group {
|
|
|
private Ripple(double centerX, double centerY) {
|
|
|
super(centerX, centerY, 0, Color.TRANSPARENT);
|
|
|
setFill(rippleColor.get());
|
|
|
- Rectangle rectangle = new Rectangle(control.getWidth(), control.getHeight());
|
|
|
- setClip(rectangle);
|
|
|
+ setClip(rippleClipType.buildClip(region));
|
|
|
buildAnimation();
|
|
|
}
|
|
|
|
|
|
//================================================================================
|
|
|
// Methods
|
|
|
//================================================================================
|
|
|
- private void buildAnimation() {
|
|
|
- DropShadow buttonShadow = (DropShadow) ((MFXButton) control.getSkin().getSkinnable()).getEffect();
|
|
|
- DepthLevel depthLevel = ((MFXButton) control).getDepthLevel();
|
|
|
- DropShadow startShadow = shadowOf(depthLevel);
|
|
|
- DropShadow endShadow = shadowOf(depthLevel, shadowDelta);
|
|
|
|
|
|
+ /**
|
|
|
+ * Build the ripple's animation
|
|
|
+ */
|
|
|
+ private void buildAnimation() {
|
|
|
KeyValue keyValue1 = new KeyValue(radiusProperty(), rippleRadius.get());
|
|
|
KeyValue keyValue2 = new KeyValue(opacityProperty(), 1.0);
|
|
|
KeyFrame keyFrame1 = new KeyFrame(inDuration.get(), keyValue1);
|
|
@@ -188,25 +221,32 @@ public class RippleGenerator extends Group {
|
|
|
KeyFrame keyFrame4 = new KeyFrame(outDuration.get(), keyValue4);
|
|
|
outAnimation.getKeyFrames().addAll(keyFrame3, keyFrame4);
|
|
|
|
|
|
- // Button shadow
|
|
|
- // Spread
|
|
|
- KeyValue keyValue5 = new KeyValue(buttonShadow.spreadProperty(), endShadow.getSpread(), easeBoth);
|
|
|
- KeyValue keyValue6 = new KeyValue(buttonShadow.spreadProperty(), startShadow.getSpread(), easeBoth);
|
|
|
- //Radius
|
|
|
- KeyValue keyValue7 = new KeyValue(buttonShadow.radiusProperty(), endShadow.getRadius(), easeBoth);
|
|
|
- KeyValue keyValue8 = new KeyValue(buttonShadow.radiusProperty(), startShadow.getRadius(), easeBoth);
|
|
|
- // Offsets
|
|
|
- KeyValue keyValue9 = new KeyValue(buttonShadow.offsetXProperty(), endShadow.getOffsetX(), easeBoth);
|
|
|
- KeyValue keyValue10 = new KeyValue(buttonShadow.offsetXProperty(), startShadow.getOffsetX(), easeBoth);
|
|
|
- KeyValue keyValue11 = new KeyValue(buttonShadow.offsetYProperty(), endShadow.getOffsetY(), easeBoth);
|
|
|
- KeyValue keyValue12 = new KeyValue(buttonShadow.offsetYProperty(), startShadow.getOffsetY(), easeBoth);
|
|
|
- KeyFrame keyFrame5 = new KeyFrame(Duration.ZERO, keyValue5, keyValue7, keyValue9, keyValue11);
|
|
|
- KeyFrame keyFrame6 = new KeyFrame(inDuration.get(), keyValue6, keyValue8, keyValue10, keyValue12);
|
|
|
- shadowAnimation.getKeyFrames().addAll(keyFrame5, keyFrame6);
|
|
|
+ if (level != null) {
|
|
|
+ Control control = (Control) region;
|
|
|
+ DropShadow shadowEffect = (DropShadow) ((Control) control.getSkin().getSkinnable()).getEffect();
|
|
|
+ DropShadow startShadow = shadowOf(level);
|
|
|
+ DropShadow endShadow = shadowOf(level, shadowDelta);
|
|
|
+
|
|
|
+ // Spread
|
|
|
+ KeyValue keyValue5 = new KeyValue(shadowEffect.spreadProperty(), endShadow.getSpread(), Interpolator.LINEAR);
|
|
|
+ KeyValue keyValue6 = new KeyValue(shadowEffect.spreadProperty(), startShadow.getSpread(), Interpolator.LINEAR);
|
|
|
+ //Radius
|
|
|
+ KeyValue keyValue7 = new KeyValue(shadowEffect.radiusProperty(), endShadow.getRadius(), Interpolator.LINEAR);
|
|
|
+ KeyValue keyValue8 = new KeyValue(shadowEffect.radiusProperty(), startShadow.getRadius(), Interpolator.LINEAR);
|
|
|
+ // Offsets
|
|
|
+ KeyValue keyValue9 = new KeyValue(shadowEffect.offsetXProperty(), endShadow.getOffsetX(), Interpolator.LINEAR);
|
|
|
+ KeyValue keyValue10 = new KeyValue(shadowEffect.offsetXProperty(), startShadow.getOffsetX(), Interpolator.LINEAR);
|
|
|
+ KeyValue keyValue11 = new KeyValue(shadowEffect.offsetYProperty(), endShadow.getOffsetY(), Interpolator.LINEAR);
|
|
|
+ KeyValue keyValue12 = new KeyValue(shadowEffect.offsetYProperty(), startShadow.getOffsetY(), Interpolator.LINEAR);
|
|
|
+ KeyFrame keyFrame5 = new KeyFrame(Duration.ZERO, keyValue5, keyValue7, keyValue9, keyValue11);
|
|
|
+ KeyFrame keyFrame6 = new KeyFrame(inDuration.get(), keyValue6, keyValue8, keyValue10, keyValue12);
|
|
|
+ shadowAnimation.getKeyFrames().addAll(keyFrame5, keyFrame6);
|
|
|
+ parallelTransition.getChildren().add(0, shadowAnimation);
|
|
|
+ }
|
|
|
|
|
|
sequentialTransition.getChildren().addAll(inAnimation, outAnimation);
|
|
|
parallelTransition.setInterpolator(rippleInterpolator);
|
|
|
- parallelTransition.getChildren().addAll(shadowAnimation, sequentialTransition);
|
|
|
+ parallelTransition.getChildren().add(sequentialTransition);
|
|
|
}
|
|
|
}
|
|
|
|