From 3adc39f288a8a1c20e903f9c8f0e6d9875756ec6 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 8 Sep 2017 19:45:54 +0300 Subject: [PATCH] Ability to pause and seek animation --- .../ui/controller/EditorController.java | 13 ++++++++- .../annimon/hotarufx/visual/Composition.java | 27 +++++++++++++++++- .../com/annimon/hotarufx/visual/TimeLine.java | 28 +++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/annimon/hotarufx/ui/controller/EditorController.java b/app/src/main/java/com/annimon/hotarufx/ui/controller/EditorController.java index a89446b..810ad03 100644 --- a/app/src/main/java/com/annimon/hotarufx/ui/controller/EditorController.java +++ b/app/src/main/java/com/annimon/hotarufx/ui/controller/EditorController.java @@ -34,6 +34,7 @@ import javafx.scene.control.TitledPane; import javafx.scene.layout.Pane; import javafx.stage.Modality; import javafx.stage.Stage; +import javafx.util.Duration; import lombok.val; import org.fxmisc.richtext.CodeArea; import org.fxmisc.richtext.LineNumberFactory; @@ -157,7 +158,17 @@ public class EditorController implements Initializable, DocumentListener { stage.initOwner(primaryStage); stage.initModality(Modality.WINDOW_MODAL); stage.setScene(composition.produceAnimationScene()); - composition.getTimeline().getFxTimeline().play(); + val timeline = composition.getTimeline(); + timeline.getFxTimeline().currentTimeProperty().addListener((o, oldValue, d) -> { + val min = (int) d.toMinutes(); + val durationSec = d.subtract(Duration.minutes(min)); + val sec = (int) durationSec.toSeconds(); + val durationMs = durationSec.subtract(Duration.seconds(sec)); + val frame = (int) (durationMs.toMillis() * timeline.getFrameRate() / 1000d); + val allFrame = (int) (d.toMillis() * timeline.getFrameRate() / 1000d); + stage.setTitle(String.format("%02d:%02d.%02d %d", min, sec, frame, allFrame)); + }); + stage.setOnShown(e -> timeline.getFxTimeline().play()); stage.show(); } diff --git a/app/src/main/java/com/annimon/hotarufx/visual/Composition.java b/app/src/main/java/com/annimon/hotarufx/visual/Composition.java index 04ed06d..c8420a7 100644 --- a/app/src/main/java/com/annimon/hotarufx/visual/Composition.java +++ b/app/src/main/java/com/annimon/hotarufx/visual/Composition.java @@ -2,6 +2,7 @@ package com.annimon.hotarufx.visual; import javafx.scene.Group; import javafx.scene.Scene; +import javafx.scene.input.KeyCode; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import lombok.Getter; @@ -62,6 +63,30 @@ public class Composition { } public Scene produceAnimationScene() { - return new Scene(scene.getGroup(), sceneWidth, sceneHeight, background); + val fxScene = new Scene(scene.getGroup(), sceneWidth, sceneHeight, background); + fxScene.setOnKeyPressed(e -> { + switch (e.getCode()) { + case SPACE: + timeline.togglePause(); + break; + case BACK_SPACE: + timeline.getFxTimeline().playFromStart(); + break; + case LEFT: + case RIGHT: + int sign = e.getCode() == KeyCode.LEFT ? -1 : 1; + if (e.isShiftDown()) { + timeline.seek(sign); + } else if (e.isControlDown()) { + timeline.seek(10 * sign); + } else if (e.isAltDown()) { + timeline.seek(30 * sign); + } else { + timeline.seekFrame(sign); + } + break; + } + }); + return fxScene; } } diff --git a/app/src/main/java/com/annimon/hotarufx/visual/TimeLine.java b/app/src/main/java/com/annimon/hotarufx/visual/TimeLine.java index 2be0cb2..dc5454d 100644 --- a/app/src/main/java/com/annimon/hotarufx/visual/TimeLine.java +++ b/app/src/main/java/com/annimon/hotarufx/visual/TimeLine.java @@ -4,6 +4,7 @@ import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.util.Duration; import lombok.Getter; +import lombok.val; public class TimeLine { @@ -26,4 +27,31 @@ public class TimeLine { private Duration duration(KeyFrame keyFrame) { return Duration.millis(1000d * keyFrame.getFrame() / frameRate); } + + public void togglePause() { + switch (fxTimeline.getStatus()) { + case PAUSED: + fxTimeline.play(); + break; + case RUNNING: + fxTimeline.pause(); + break; + case STOPPED: + fxTimeline.playFromStart(); + break; + } + } + + public void seekFrame(final int value) { + fxTimeline.pause(); + val offset = Duration.millis(1000d * Math.abs(value) / frameRate); + val now = fxTimeline.getCurrentTime(); + val newDuration = value > 0 ? now.add(offset) : now.subtract(offset); + fxTimeline.jumpTo(newDuration); + } + + public void seek(final int sec) { + val now = fxTimeline.getCurrentTime(); + fxTimeline.jumpTo(now.add(Duration.seconds(sec))); + } }