32 | * @return this for concatenation
33 | */
34 | T custom(Function settings);
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/SingleChildParent.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding;
2 |
3 | import javafx.beans.property.ObjectProperty;
4 | import javafx.beans.property.SimpleObjectProperty;
5 | import javafx.scene.Node;
6 | import javafx.scene.Parent;
7 |
8 | /**
9 | * Parent node that has only one child
10 | * @author Giorgio Garofalo
11 | */
12 | public class SingleChildParent extends Parent {
13 |
14 | protected final ObjectProperty child = new SimpleObjectProperty<>();
15 |
16 | protected SingleChildParent() {
17 | // Registers child listener
18 | this.child.addListener((observable, oldChild, newChild) -> {
19 | if (newChild != null) {
20 | getChildren().setAll(newChild);
21 | } else {
22 | getChildren().clear();
23 | }
24 | });
25 | }
26 |
27 | protected SingleChildParent(Node child) {
28 | this();
29 | this.child.set(child);
30 | }
31 |
32 | /**
33 | * @return the current child
34 | */
35 | public ObjectProperty childProperty() {
36 | return this.child;
37 | }
38 |
39 | /**
40 | * @return the current child
41 | */
42 | public Node getChild() {
43 | return this.child.get();
44 | }
45 |
46 | /**
47 | * Sets the new child.
48 | * @param child new child. If null, the current child is removed and nothing is added.
49 | */
50 | public void setChild(Node child) {
51 | this.childProperty().set(child);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/event/AnimationEvent.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.event;
2 |
3 | import javafx.event.Event;
4 | import javafx.event.EventType;
5 |
6 | /**
7 | * An animation-related event.
8 | * @see ListenableAnimation
9 | */
10 | public final class AnimationEvent extends Event {
11 |
12 | private static final EventType ANIMATION = new EventType<>("ANIMATION");
13 |
14 | private final boolean interrupted;
15 |
16 | public AnimationEvent(boolean interrupted) {
17 | super(ANIMATION);
18 | this.interrupted = interrupted;
19 | }
20 |
21 | /**
22 | * @return whether this animation was interrupted.
23 | * Note:
24 | *
25 | *
26 | * If this event represents the end of an animation, the interrupted status
27 | * means the animation stopped before the expected time because the wrapped value
28 | * was externally changed and a new animation has to be played.
29 | *
30 | *
31 | * If this event represents the start of an animation, the interrupted status
32 | * means the animation started right after an interrupted end animation.
33 | *
34 | *
35 | */
36 | public boolean isInterrupted() {
37 | return this.interrupted;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/event/ListenableAnimation.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.event;
2 |
3 | import javafx.beans.property.ObjectProperty;
4 | import javafx.event.EventHandler;
5 |
6 | /**
7 | * A provider of listeners for animation-related events.
8 | * @see AnimationEvent
9 | */
10 | public interface ListenableAnimation {
11 |
12 | /**
13 | * @return the action to run when an animation begins
14 | */
15 | ObjectProperty> onAnimationStartedProperty();
16 |
17 | /**
18 | * @param handler the action to run when an animation begins
19 | */
20 | default void setOnAnimationStarted(EventHandler handler) {
21 | onAnimationStartedProperty().set(handler);
22 | }
23 |
24 | /**
25 | * @return the action to run when an animation finishes
26 | */
27 | ObjectProperty> onAnimationEndedProperty();
28 |
29 | /**
30 | * @param handler the action to run when an animation finishes
31 | */
32 | default void setOnAnimationEnded(EventHandler handler) {
33 | onAnimationEndedProperty().set(handler);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/misc/AnimatedSlider.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.misc;
2 |
3 | import eu.iamgio.animated.binding.AnimationSettings;
4 | import eu.iamgio.animated.binding.CustomizableAnimation;
5 | import eu.iamgio.animated.binding.event.AnimationEvent;
6 | import eu.iamgio.animated.binding.event.ListenableAnimation;
7 | import eu.iamgio.animated.binding.property.animation.AnimationProperty;
8 | import javafx.beans.property.ObjectProperty;
9 | import javafx.event.EventHandler;
10 | import javafx.scene.control.Slider;
11 |
12 | import java.util.function.Function;
13 |
14 | /**
15 | * A {@link Slider} implementation that animates its value when an external change occurs.
16 | * The animation does not play when the value is changed by mouse-dragging.
17 | *
18 | * @see Slider
19 | */
20 | public final class AnimatedSlider extends Slider implements CustomizableAnimation, ListenableAnimation {
21 |
22 | private final AnimationProperty property = AnimationProperty.of(valueProperty());
23 |
24 | /**
25 | * Instantiates an {@link AnimatedSlider}.
26 | */
27 | public AnimatedSlider() {
28 | super();
29 | this.init();
30 | }
31 |
32 | /**
33 | * Instantiates an {@link AnimatedSlider}.
34 | * @param min minimum value
35 | * @param max maximum value
36 | * @param value initial value
37 | */
38 | public AnimatedSlider(double min, double max, double value) {
39 | super(min, max, value);
40 | this.init();
41 | }
42 |
43 | private void init() {
44 | property.register(this);
45 |
46 | // Animation is paused when mouse-dragging
47 | setOnMouseDragged(e -> property.pause());
48 | setOnMouseReleased(e -> property.resume());
49 | }
50 |
51 | /**
52 | * {@inheritDoc}
53 | */
54 | @Override
55 | public void setSettings(AnimationSettings settings) {
56 | property.setSettings(settings);
57 | }
58 |
59 | /**
60 | * {@inheritDoc}
61 | */
62 | @Override
63 | public AnimatedSlider custom(Function settings) {
64 | property.custom(settings);
65 | return this;
66 | }
67 |
68 | /**
69 | * {@inheritDoc}
70 | */
71 | @Override
72 | public ObjectProperty> onAnimationStartedProperty() {
73 | return this.property.onAnimationStartedProperty();
74 | }
75 |
76 | /**
77 | * {@inheritDoc}
78 | */
79 | @Override
80 | public ObjectProperty> onAnimationEndedProperty() {
81 | return this.property.onAnimationEndedProperty();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedBlur.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationProperty;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.Node;
6 | import javafx.scene.effect.GaussianBlur;
7 |
8 | /**
9 | * Property that animates its child's {@link GaussianBlur} radius.
10 | * If the target node does not have an {@link javafx.scene.effect.Effect}
11 | * or if its effect is not a {@link GaussianBlur} at initialization time,
12 | * a new {@link GaussianBlur} with default radius will be set as its new effect.
13 | */
14 | public class AnimatedBlur extends OnDemandAnimationProperty {
15 |
16 | public AnimatedBlur() {
17 | super(node -> PropertyWrapper.of(getEffectOrCreate(node).radiusProperty()));
18 | }
19 |
20 | public AnimatedBlur(Node child) {
21 | this();
22 | targetNodeProperty().set(child);
23 | }
24 |
25 | private static GaussianBlur getEffectOrCreate(Node node) {
26 | if (node.getEffect() == null || !(node.getEffect() instanceof GaussianBlur)) {
27 | GaussianBlur blur = new GaussianBlur();
28 | node.setEffect(blur);
29 | return blur;
30 | } else {
31 | return (GaussianBlur) node.getEffect();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedColor.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationProperty;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.paint.Paint;
6 | import javafx.scene.shape.Shape;
7 |
8 | /**
9 | * Property that animates its child's color, for {@link Shape} nodes.
10 | * @author Giorgio Garofalo
11 | */
12 | public class AnimatedColor extends OnDemandAnimationProperty {
13 |
14 | public AnimatedColor() {
15 | super(node -> PropertyWrapper.of(node.fillProperty()));
16 | }
17 |
18 | public AnimatedColor(Shape child) {
19 | this();
20 | targetNodeProperty().set(child);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedDropShadow.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationProperty;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.Node;
6 | import javafx.scene.effect.DropShadow;
7 |
8 | /**
9 | * Container of different drop shadow properties.
10 | * If the target node does not have an {@link javafx.scene.effect.Effect}
11 | * or if its effect is not a {@link DropShadow} at initialization time,
12 | * a new {@link DropShadow} with default color and radius will be set as its new effect.
13 | */
14 | public class AnimatedDropShadow {
15 |
16 | /**
17 | * Property that animates its child's {@link DropShadow} color.
18 | * If the target node does not have an {@link javafx.scene.effect.Effect}
19 | * or if its effect is not a {@link DropShadow} at initialization time,
20 | * a new {@link DropShadow} with default color and radius will be set as its new effect.
21 | */
22 | public static class Color extends OnDemandAnimationProperty {
23 |
24 | public Color() {
25 | super(node -> PropertyWrapper.of(getEffectOrCreate(node).colorProperty()));
26 | }
27 |
28 | public Color(Node child) {
29 | this();
30 | targetNodeProperty().set(child);
31 | }
32 | }
33 |
34 | /**
35 | * Property that animates its child's {@link DropShadow} radius.
36 | * If the target node does not have an {@link javafx.scene.effect.Effect}
37 | * or if its effect is not a {@link DropShadow} at initialization time,
38 | * a new {@link DropShadow} with default color and radius will be set as its new effect.
39 | */
40 | public static class Radius extends OnDemandAnimationProperty {
41 |
42 | public Radius() {
43 | super(node -> PropertyWrapper.of(getEffectOrCreate(node).radiusProperty()));
44 | }
45 |
46 | public Radius(Node child) {
47 | this();
48 | targetNodeProperty().set(child);
49 | }
50 | }
51 |
52 | private static DropShadow getEffectOrCreate(Node node) {
53 | if (node.getEffect() == null || !(node.getEffect() instanceof DropShadow)) {
54 | final DropShadow shadow = new DropShadow();
55 | node.setEffect(shadow);
56 | return shadow;
57 | } else {
58 | return (DropShadow) node.getEffect();
59 | }
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedLayout.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationPropertyGroup;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.beans.property.BooleanProperty;
6 | import javafx.beans.property.SimpleBooleanProperty;
7 | import javafx.geometry.Bounds;
8 | import javafx.geometry.HPos;
9 | import javafx.geometry.Pos;
10 | import javafx.geometry.VPos;
11 | import javafx.scene.Node;
12 | import javafx.scene.layout.Region;
13 |
14 | import java.util.Arrays;
15 |
16 | /**
17 | * Node that animates its child's position based on an alignment relative to an anchor root.
18 | *
19 | * @author Giorgio Garofalo
20 | */
21 | public class AnimatedLayout extends OnDemandAnimationPropertyGroup {
22 |
23 | private final Node child;
24 | private final Region root;
25 | private final Pos alignment;
26 |
27 | private final BooleanProperty animateShrinking = new SimpleBooleanProperty();
28 |
29 | // The latest registered child size
30 | private Bounds bounds;
31 |
32 | /**
33 | * Instantiates an {@link AnimatedLayout} node.
34 | * @param child the node to wrap, whose layout should be animated
35 | * @param root root to rely relayouts on
36 | * @param alignment position of the node relative to its root
37 | * @param animateShrinking whether the animation should be played when the root is shrunk
38 | */
39 | public AnimatedLayout(Node child, Region root, Pos alignment, boolean animateShrinking) {
40 | super(Arrays.asList(
41 | node -> PropertyWrapper.of(node.layoutXProperty()),
42 | node -> PropertyWrapper.of(node.layoutYProperty())
43 | ));
44 |
45 | targetNodeProperty().set(child);
46 |
47 | this.child = child;
48 | this.root = root;
49 | this.alignment = alignment;
50 | this.bounds = child.getLayoutBounds();
51 | this.animateShrinking.set(animateShrinking);
52 |
53 | HPos hPos = alignment.getHpos();
54 | VPos vPos = alignment.getVpos();
55 |
56 | // Update the coordinates whenever the root gets resized
57 | bindX(hPos);
58 | bindY(vPos);
59 |
60 | // Register child size
61 | registerBoundsListener(hPos, vPos);
62 | }
63 |
64 | /**
65 | * Instantiates an {@link AnimatedLayout} node.
66 | * @param child the node to wrap, whose layout should be animated
67 | * @param root root to rely relayouts on
68 | * @param alignment position of the node relative to its root
69 | */
70 | public AnimatedLayout(Node child, Region root, Pos alignment) {
71 | this(child, root, alignment, false);
72 | }
73 |
74 | /**
75 | * @return alignment of the child relative to the root
76 | */
77 | public Pos getAlignment() {
78 | return alignment;
79 | }
80 |
81 | /**
82 | * @return whether the animation should be played when the root is shrunk
83 | */
84 | public BooleanProperty animateShrinkingProperty() {
85 | return animateShrinking;
86 | }
87 |
88 | /**
89 | * @return whether the animation should be played when the root is shrunk. Does not affect centered alignments
90 | */
91 | public boolean isAnimateShrinking() {
92 | return animateShrinking.get();
93 | }
94 |
95 | /**
96 | * Enables or disables shrinking animation.
97 | * @param animateShrinking whether the animation should be played when the root is shrunk
98 | */
99 | public void setAnimateShrinking(boolean animateShrinking) {
100 | this.animateShrinking.set(animateShrinking);
101 | }
102 |
103 | /**
104 | * Whenever the size of the node changes, it gets saved to a local variable
105 | * @param hPos horizontal position of the alignment
106 | * @param vPos vertical position of the alignment
107 | */
108 | private void registerBoundsListener(HPos hPos, VPos vPos) {
109 | child.layoutBoundsProperty().addListener((o, oldValue, newValue) -> {
110 | if (oldValue != newValue || newValue != bounds) {
111 | bounds = newValue;
112 |
113 | // Don't animate if this is the first update
114 | boolean wasEmpty = oldValue.getWidth() == 0 && oldValue.getHeight() == 0;
115 | if (wasEmpty) {
116 | pause();
117 | }
118 |
119 | // Update coordinates
120 | if (requiresBinding(hPos)) {
121 | updateX(isCenter(hPos));
122 | }
123 | if (requiresBinding(vPos)) {
124 | updateY(isCenter(vPos));
125 | }
126 |
127 | if (wasEmpty) {
128 | resume();
129 | }
130 | }
131 | });
132 | }
133 |
134 | /**
135 | * Updates the layout X coordinate of the node: either to the end of the root or to its center.
136 | * @param center whether the node should be centered to the root
137 | */
138 | private void updateX(boolean center) {
139 | if (bounds == null) {
140 | return;
141 | }
142 |
143 | double x = root.getPrefWidth() - bounds.getWidth();
144 | child.setLayoutX(center ? x / 2 : x);
145 | }
146 |
147 | /**
148 | * Updates the layout Y coordinate of the node: either to the end of the root or to its center.
149 | * @param center whether the node should be centered to the root
150 | */
151 | private void updateY(boolean center) {
152 | if (bounds == null) {
153 | return;
154 | }
155 |
156 | double y = root.getPrefHeight() - bounds.getHeight();
157 | child.setLayoutY(center ? y / 2 : y);
158 | }
159 |
160 | /**
161 | * Updates the layout X coordinate of the node whenever the width of the root changes.
162 | * @param hPos horizontal position of the alignment
163 | */
164 | private void bindX(HPos hPos) {
165 | if (requiresBinding(hPos)) {
166 | root.prefWidthProperty().addListener((observable, oldValue, newValue) -> {
167 | boolean isShrunk = !isAnimateShrinking() && (double) newValue < (double) oldValue && !isCenter(hPos);
168 |
169 | if (isShrunk) {
170 | pause();
171 | }
172 |
173 | updateX(isCenter(hPos));
174 |
175 | if (isShrunk) {
176 | resume();
177 | }
178 | });
179 | }
180 | }
181 |
182 | /**
183 | * Updates the layout Y coordinate of the node whenever the height of the root changes.
184 | * @param vPos vertical position of the alignment
185 | */
186 | private void bindY(VPos vPos) {
187 | if (requiresBinding(vPos)) {
188 | boolean center = vPos == VPos.CENTER;
189 | root.prefHeightProperty().addListener((observable, oldValue, newValue) -> {
190 | boolean isShrunk = !isAnimateShrinking() && (double) newValue < (double) oldValue && !isCenter(vPos);
191 | if (isShrunk) {
192 | pause();
193 | }
194 |
195 | updateY(isCenter(vPos));
196 |
197 | if (isShrunk) {
198 | resume();
199 | }
200 | });
201 | }
202 | }
203 |
204 | private boolean requiresBinding(HPos hPos) {
205 | return child != null && root != null && hPos != HPos.LEFT;
206 | }
207 |
208 | private boolean requiresBinding(VPos vPos) {
209 | return child != null && root != null && vPos != VPos.TOP;
210 | }
211 |
212 | private boolean isCenter(HPos hPos) {
213 | return hPos == HPos.CENTER;
214 | }
215 |
216 | private boolean isCenter(VPos vPos) {
217 | return vPos == VPos.CENTER;
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedOpacity.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationProperty;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.Node;
6 |
7 | /**
8 | * Property that animates its child's opacity.
9 | */
10 | public class AnimatedOpacity extends OnDemandAnimationProperty {
11 |
12 | public AnimatedOpacity() {
13 | super(node -> PropertyWrapper.of(node.opacityProperty()));
14 | }
15 |
16 | public AnimatedOpacity(Node child) {
17 | this();
18 | targetNodeProperty().set(child);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedPrefSize.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationPropertyGroup;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.layout.Region;
6 |
7 | import java.util.Arrays;
8 |
9 | /**
10 | * Property that animates its child's preferred size.
11 | */
12 | public class AnimatedPrefSize extends OnDemandAnimationPropertyGroup {
13 |
14 | public AnimatedPrefSize() {
15 | super(Arrays.asList(
16 | node -> PropertyWrapper.of(node.prefWidthProperty()),
17 | node -> PropertyWrapper.of(node.prefHeightProperty())
18 | ));
19 | }
20 |
21 | public AnimatedPrefSize(Region child) {
22 | this();
23 | targetNodeProperty().set(child);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedRotation.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationProperty;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.Node;
6 |
7 | /**
8 | * Property that animates its child's rotation.
9 | */
10 | public class AnimatedRotation extends OnDemandAnimationProperty {
11 |
12 | public AnimatedRotation() {
13 | super(node -> PropertyWrapper.of(node.opacityProperty()));
14 | }
15 |
16 | public AnimatedRotation(Node child) {
17 | this();
18 | targetNodeProperty().set(child);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedScale.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationPropertyGroup;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.Node;
6 | import javafx.scene.layout.Region;
7 |
8 | import java.util.Arrays;
9 |
10 | /**
11 | * Property that animates its child's scale X/Y.
12 | */
13 | public class AnimatedScale extends OnDemandAnimationPropertyGroup {
14 |
15 | public AnimatedScale() {
16 | super(Arrays.asList(
17 | node -> PropertyWrapper.of(node.scaleXProperty()),
18 | node -> PropertyWrapper.of(node.scaleYProperty())
19 | ));
20 | }
21 |
22 | public AnimatedScale(Region child) {
23 | this();
24 | targetNodeProperty().set(child);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/presets/AnimatedTranslatePosition.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.presets;
2 |
3 | import eu.iamgio.animated.binding.property.animation.OnDemandAnimationPropertyGroup;
4 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
5 | import javafx.scene.Node;
6 | import javafx.scene.layout.Region;
7 |
8 | import java.util.Arrays;
9 |
10 | /**
11 | * Property that animates its child's translate X/Y coordinates.
12 | */
13 | public class AnimatedTranslatePosition extends OnDemandAnimationPropertyGroup {
14 |
15 | public AnimatedTranslatePosition() {
16 | super(Arrays.asList(
17 | node -> PropertyWrapper.of(node.translateXProperty()),
18 | node -> PropertyWrapper.of(node.translateYProperty())
19 | ));
20 | }
21 |
22 | public AnimatedTranslatePosition(Region child) {
23 | this();
24 | targetNodeProperty().set(child);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/eu/iamgio/animated/binding/property/animation/AnimationProperty.java:
--------------------------------------------------------------------------------
1 | package eu.iamgio.animated.binding.property.animation;
2 |
3 | import eu.iamgio.animated.binding.Animated;
4 | import eu.iamgio.animated.binding.AnimationSettings;
5 | import eu.iamgio.animated.binding.CustomizableAnimation;
6 | import eu.iamgio.animated.binding.event.AnimationEvent;
7 | import eu.iamgio.animated.binding.event.ListenableAnimation;
8 | import eu.iamgio.animated.binding.property.wrapper.PropertyWrapper;
9 | import eu.iamgio.animated.common.Pausable;
10 | import javafx.beans.property.*;
11 | import javafx.event.EventHandler;
12 | import javafx.scene.Node;
13 |
14 | import java.util.function.Function;
15 |
16 | /**
17 | * An animation property wraps a JavaFX property and describes its behavior when it is affected by a change.
18 | * The property has to be wrapped inside a {@link PropertyWrapper}.
19 | * @param type of the wrapped value
20 | * @author Giorgio Garofalo
21 | */
22 | public abstract class AnimationProperty implements CustomizableAnimation>, ListenableAnimation, Pausable {
23 |
24 | // The target property
25 | private final PropertyWrapper property;
26 |
27 | // Whether the property should be animated
28 | private final BooleanProperty paused = new SimpleBooleanProperty(false);
29 |
30 | // Animation settings
31 | private final ObjectProperty settings;
32 |
33 | // Event handlers
34 | private final ObjectProperty> onAnimationStarted = new SimpleObjectProperty<>();
35 | private final ObjectProperty> onAnimationEnded = new SimpleObjectProperty<>();
36 |
37 | /**
38 | * Instantiates an implicitly animated property
39 | * @param property target property
40 | * @param settings animation settings
41 | */
42 | public AnimationProperty(PropertyWrapper property, AnimationSettings settings) {
43 | this.property = property;
44 | this.settings = new SimpleObjectProperty<>(settings);
45 | }
46 |
47 | /**
48 | * Instantiates an implicitly animated property with default settings.
49 | * @param property target property
50 | */
51 | public AnimationProperty(PropertyWrapper property) {
52 | this(property, new AnimationSettings());
53 | }
54 |
55 | /**
56 | * @return the current animation settings
57 | */
58 | public ObjectProperty settingsProperty() {
59 | return this.settings;
60 | }
61 |
62 | /**
63 | * @return the current animation settings
64 | */
65 | public AnimationSettings getSettings() {
66 | return this.settings.get();
67 | }
68 |
69 | /**
70 | * {@inheritDoc}
71 | */
72 | @Override
73 | public void setSettings(AnimationSettings settings) {
74 | this.settings.set(settings);
75 | }
76 |
77 | /**
78 | * {@inheritDoc}
79 | */
80 | @Override
81 | public AnimationProperty custom(Function settings) {
82 | return withSettings(settings.apply(getSettings()));
83 | }
84 |
85 | /**
86 | * Registers the listener
87 | * @param target nullable target {@link Node}. If present, the animation is not played when it is not in scene.
88 | */
89 | public abstract void register(Node target);
90 |
91 | /**
92 | * Registers the listener
93 | */
94 | public void register() {
95 | register(null);
96 | }
97 |
98 | /**
99 | * Attaches this property to an {@link Animated} node.
100 | * @param animated animated node to link this property to
101 | */
102 | public abstract void attachTo(Animated animated);
103 |
104 | /**
105 | * Adds a binding to a target property: when the value of the wrapped property changes,
106 | * the target property is updated too, based on a mapper function.
107 | * The following example binds a label text to this property, converted to a string:
108 | *