animation: implement an animation module
This commit is contained in:
160
src/animation.rs
Normal file
160
src/animation.rs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use figments::surface::Surface;
|
||||||
|
use core::{fmt::Debug, ops::{Deref, DerefMut}};
|
||||||
|
use log::*;
|
||||||
|
|
||||||
|
use crate::events::DisplayControls;
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
|
pub struct Animation {
|
||||||
|
from: Option<u8>,
|
||||||
|
to: Option<u8>,
|
||||||
|
duration: Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AnimationActor {
|
||||||
|
fn get_opacity(&self) -> u8;
|
||||||
|
fn set_opacity(&mut self, opacity: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Surface> AnimationActor for S {
|
||||||
|
fn get_opacity(&self) -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_opacity(&mut self, opacity: u8) {
|
||||||
|
self.set_opacity(opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AnimDisplay<'a>(pub &'a DisplayControls);
|
||||||
|
|
||||||
|
impl<'a> AnimationActor for AnimDisplay<'a> {
|
||||||
|
fn get_opacity(&self) -> u8 {
|
||||||
|
self.0.brightness()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_opacity(&mut self, opacity: u8) {
|
||||||
|
self.0.set_brightness(opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Surface> AnimationActor for AnimatedSurface<S> {
|
||||||
|
fn get_opacity(&self) -> u8 {
|
||||||
|
self.opacity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_opacity(&mut self, opacity: u8) {
|
||||||
|
self.surface.set_opacity(opacity);
|
||||||
|
self.opacity = opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Animation {
|
||||||
|
pub fn from(self, from: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
from: Some(from),
|
||||||
|
to: self.to,
|
||||||
|
duration: self.duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to(self, to: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
from: self.from,
|
||||||
|
to: Some(to),
|
||||||
|
duration: self.duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duration(self, duration: Duration) -> Self {
|
||||||
|
Self {
|
||||||
|
from: self.from,
|
||||||
|
to: self.to,
|
||||||
|
duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn apply<S: AnimationActor + Debug>(&self, sfc: &mut S) {
|
||||||
|
let from = if let Some(val) = self.from {
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
sfc.get_opacity()
|
||||||
|
};
|
||||||
|
let to = if let Some(val) = self.to {
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
sfc.get_opacity()
|
||||||
|
};
|
||||||
|
let steps = from.abs_diff(to);
|
||||||
|
if steps == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let step_time = self.duration / steps.into();
|
||||||
|
trace!("fade={self:?} steps={steps} time={step_time} sfc={sfc:?}");
|
||||||
|
if from > to {
|
||||||
|
let range = (to..=from).rev();
|
||||||
|
for opacity in range {
|
||||||
|
sfc.set_opacity(opacity);
|
||||||
|
Timer::after(step_time).await;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let range = from..=to;
|
||||||
|
|
||||||
|
for opacity in range {
|
||||||
|
sfc.set_opacity(opacity);
|
||||||
|
Timer::after(step_time).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AnimatedSurface<S: Surface> {
|
||||||
|
surface: S,
|
||||||
|
is_on: bool,
|
||||||
|
opacity: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Surface> Deref for AnimatedSurface<S> {
|
||||||
|
type Target = S;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.surface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Surface> DerefMut for AnimatedSurface<S> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.surface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Surface> From<S> for AnimatedSurface<S> {
|
||||||
|
fn from(surface: S) -> Self {
|
||||||
|
AnimatedSurface {
|
||||||
|
surface,
|
||||||
|
is_on: false,
|
||||||
|
opacity: 255
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Surface + Debug> AnimatedSurface<S> {
|
||||||
|
pub async fn set_on(&mut self, is_on: bool) {
|
||||||
|
if self.is_on != is_on {
|
||||||
|
let anim = if is_on {
|
||||||
|
self.surface.set_visible(true);
|
||||||
|
Animation::default().duration(Duration::from_secs(1)).from(0).to(255)
|
||||||
|
} else {
|
||||||
|
Animation::default().duration(Duration::from_secs(1)).from(255).to(0)
|
||||||
|
};
|
||||||
|
anim.apply(&mut self.surface).await;
|
||||||
|
self.is_on = true;
|
||||||
|
if !is_on {
|
||||||
|
self.surface.set_visible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user