/**
*
* Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); You may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.speedment.tool.core.util;
import javafx.animation.TranslateTransition;
import javafx.beans.property.DoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.util.Duration;
import java.util.HashMap;
import java.util.Map;
/**
* Animates an object when its position is changed. For instance, when
* additional items are added to a Region, and the layout has changed, then the
* layout animator makes the transition by sliding each item into its final
* place.
*
* @author jewelsea
* @since 2.3.0
* @see <a href="https://gist.github.com/jewelsea/5683558">Original Gist</a>
*/
public final class LayoutAnimator implements ChangeListener<Number>, ListChangeListener<Node> {
private final Map<Node, TranslateTransition> nodeXTransitions = new HashMap<>();
private final Map<Node, TranslateTransition> nodeYTransitions = new HashMap<>();
/**
* Animates all the children of a Region.
* <code>
* VBox myVbox = new VBox();
* LayoutAnimator animator = new LayoutAnimator();
* animator.observe(myVbox.getChildren());
* </code>
*
* @param nodes the nodes to observe
*/
public void observe(ObservableList<Node> nodes) {
nodes.forEach((node) -> {
this.observe(node);
});
nodes.addListener(this);
}
public void unobserve(ObservableList<Node> nodes) {
nodes.removeListener(this);
}
private void observe(Node n) {
n.layoutXProperty().addListener(this);
n.layoutYProperty().addListener(this);
}
private void unobserve(Node n) {
n.layoutXProperty().removeListener(this);
n.layoutYProperty().removeListener(this);
}
@Override
public void changed(ObservableValue<? extends Number> ov, Number oldValue, Number newValue) {
final double delta = newValue.doubleValue() - oldValue.doubleValue();
final DoubleProperty doubleProperty = (DoubleProperty) ov;
final Node node = (Node) doubleProperty.getBean();
TranslateTransition t;
switch (doubleProperty.getName()) {
case "layoutX":
t = nodeXTransitions.get(node);
if (t == null) {
t = new TranslateTransition(Duration.millis(150), node);
t.setToX(0);
nodeXTransitions.put(node, t);
}
t.setFromX(node.getTranslateX() - delta);
node.setTranslateX(node.getTranslateX() - delta);
break;
default: // "layoutY"
t = nodeYTransitions.get(node);
if (t == null) {
t = new TranslateTransition(Duration.millis(150), node);
t.setToY(0);
nodeYTransitions.put(node, t);
}
t.setFromY(node.getTranslateY() - delta);
node.setTranslateY(node.getTranslateY() - delta);
}
t.playFromStart();
}
@Override
public void onChanged(Change<? extends Node> change) {
while (change.next()) {
if (change.wasAdded()) {
change.getAddedSubList().forEach(this::observe);
} else if (change.wasRemoved()) {
change.getRemoved().forEach(this::unobserve);
}
}
}
}