/* * Copyright 2016 MovingBlocks * * 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 org.terasology.rendering.nui.animation; import org.terasology.math.geom.Rect2i; import org.terasology.rendering.animation.Animation; import org.terasology.rendering.animation.AnimationListener; import org.terasology.rendering.animation.TimeModifiers; /** * Controls animations to and from different screens */ public class SwipeMenuAnimationSystem implements MenuAnimationSystem { public enum Direction { LEFT_TO_RIGHT(1, 0), RIGHT_TO_LEFT(-1, 0), TOP_TO_BOTTOM(0, -1), BOTTOM_TO_TOP(0, 1); private final float horzScale; private final float vertScale; Direction(float horzScale, float vertScale) { this.horzScale = horzScale; this.vertScale = vertScale; } public float getHorzScale() { return horzScale; } public float getVertScale() { return vertScale; } } private final Direction direction; private final Animation flyIn; private final Animation flyOut; private float scale; /** * Creates default animations * @param duration the duration of the animation in seconds */ public SwipeMenuAnimationSystem(float duration) { this(duration, Direction.LEFT_TO_RIGHT); } /** * Creates default animations * @param duration the duration of the animation in seconds * @param direction the swipe direction */ public SwipeMenuAnimationSystem(float duration, Direction direction) { // down from 1 (fast) to 0 (slow) flyIn = Animation.once(v -> scale = v, duration, TimeModifiers.inverse().andThen(TimeModifiers.square())); // down from 0 (slow) to -1 (fast) flyOut = Animation.once(v -> scale = -v, duration, TimeModifiers.square()); this.direction = direction; } /** * Trigger animation from previous screen to this one */ @Override public void triggerFromPrev() { if (flyOut.isStopped()) { flyIn.setForwardMode(); flyIn.start(); } } /** * Trigger animation from this one back to the previous screen */ @Override public void triggerToPrev() { if (flyOut.isStopped()) { flyIn.setReverseMode(); flyIn.start(); } } /** * Trigger animation from the next screen to this one */ @Override public void triggerFromNext() { if (flyIn.isStopped()) { flyOut.setReverseMode(); flyOut.start(); } } /** * Trigger animation from this one to the next screen */ @Override public void triggerToNext() { if (flyIn.isStopped()) { flyOut.setForwardMode(); flyOut.start(); } } @Override public void skip() { // set the animation to the end point and trigger onEnd() if (flyIn.isRunning()) { flyIn.update(flyIn.getDuration()); } if (flyOut.isRunning()) { flyOut.update(flyOut.getDuration()); } } @Override public void stop() { if (flyOut.isRunning()) { flyOut.setReverseMode(); } if (flyIn.isRunning()) { flyIn.setForwardMode(); } } /** * @param listener the listener to trigger when the animation has ended */ @Override public void onEnd(Runnable listener) { flyOut.removeAllListeners(); flyOut.addListener(new AnimationListener() { @Override public void onEnd() { if (!flyOut.isReverse()) { listener.run(); } } }); flyIn.removeAllListeners(); flyIn.addListener(new AnimationListener() { @Override public void onEnd() { if (flyIn.isReverse()) { listener.run(); } } }); } /** * @param delta time difference in seconds */ @Override public void update(float delta) { float animDelta = delta; if (animDelta > 0.1f) { // avoid skipping over fast animations on heavy load animDelta = 0.1f; } flyIn.update(animDelta); flyOut.update(animDelta); } @Override public Rect2i animateRegion(Rect2i rc) { if (scale == 0.0) { // this should cover most of the cases return rc; } int left = (int) (direction.getHorzScale() * scale * rc.width()); int top = (int) (direction.getVertScale() * scale * rc.height()); return Rect2i.createFromMinAndSize(left, top, rc.width(), rc.height()); } }