File size: 4,349 Bytes
2409829 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
use std::time::Duration;
use crate::messages::prelude::*;
use super::TimingInformation;
#[derive(PartialEq, Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
pub enum AnimationTimeMode {
#[default]
TimeBased,
FrameBased,
}
#[derive(Default, Debug, Clone, PartialEq)]
enum AnimationState {
#[default]
Stopped,
Playing {
start: f64,
},
Paused {
start: f64,
pause_time: f64,
},
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct AnimationMessageHandler {
/// Used to re-send the UI on the next frame after playback starts
live_preview_recently_zero: bool,
timestamp: f64,
frame_index: f64,
animation_state: AnimationState,
fps: f64,
animation_time_mode: AnimationTimeMode,
}
impl AnimationMessageHandler {
pub(crate) fn timing_information(&self) -> TimingInformation {
let animation_time = self.timestamp - self.animation_start();
let animation_time = match self.animation_time_mode {
AnimationTimeMode::TimeBased => Duration::from_millis(animation_time as u64),
AnimationTimeMode::FrameBased => Duration::from_secs((self.frame_index / self.fps) as u64),
};
TimingInformation { time: self.timestamp, animation_time }
}
pub(crate) fn animation_start(&self) -> f64 {
match self.animation_state {
AnimationState::Stopped => self.timestamp,
AnimationState::Playing { start } => start,
AnimationState::Paused { start, pause_time } => start + self.timestamp - pause_time,
}
}
pub fn is_playing(&self) -> bool {
matches!(self.animation_state, AnimationState::Playing { .. })
}
}
impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
fn process_message(&mut self, message: AnimationMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
AnimationMessage::ToggleLivePreview => match self.animation_state {
AnimationState::Stopped => responses.add(AnimationMessage::EnableLivePreview),
AnimationState::Playing { .. } => responses.add(AnimationMessage::DisableLivePreview),
AnimationState::Paused { .. } => responses.add(AnimationMessage::EnableLivePreview),
},
AnimationMessage::EnableLivePreview => {
self.animation_state = AnimationState::Playing { start: self.animation_start() };
// Update the restart and pause/play buttons
responses.add(PortfolioMessage::UpdateDocumentWidgets);
}
AnimationMessage::DisableLivePreview => {
match self.animation_state {
AnimationState::Stopped => (),
AnimationState::Playing { start } => self.animation_state = AnimationState::Paused { start, pause_time: self.timestamp },
AnimationState::Paused { .. } => (),
}
// Update the restart and pause/play buttons
responses.add(PortfolioMessage::UpdateDocumentWidgets);
}
AnimationMessage::SetFrameIndex(frame) => {
self.frame_index = frame;
responses.add(PortfolioMessage::SubmitActiveGraphRender);
// Update the restart and pause/play buttons
responses.add(PortfolioMessage::UpdateDocumentWidgets);
}
AnimationMessage::SetTime(time) => {
self.timestamp = time;
responses.add(AnimationMessage::UpdateTime);
}
AnimationMessage::IncrementFrameCounter => {
if self.is_playing() {
self.frame_index += 1.;
responses.add(AnimationMessage::UpdateTime);
}
}
AnimationMessage::UpdateTime => {
if self.is_playing() {
responses.add(PortfolioMessage::SubmitActiveGraphRender);
if self.live_preview_recently_zero {
// Update the restart and pause/play buttons
responses.add(PortfolioMessage::UpdateDocumentWidgets);
self.live_preview_recently_zero = false;
}
}
}
AnimationMessage::RestartAnimation => {
self.frame_index = 0.;
self.animation_state = match self.animation_state {
AnimationState::Playing { .. } => AnimationState::Playing { start: self.timestamp },
_ => AnimationState::Stopped,
};
self.live_preview_recently_zero = true;
responses.add(PortfolioMessage::SubmitActiveGraphRender);
// Update the restart and pause/play buttons
responses.add(PortfolioMessage::UpdateDocumentWidgets);
}
AnimationMessage::SetAnimationTimeMode(animation_time_mode) => {
self.animation_time_mode = animation_time_mode;
}
}
}
advertise_actions!(AnimationMessageDiscriminant;
ToggleLivePreview,
SetFrameIndex,
RestartAnimation,
);
}
|