use std::ops::Deref;
use crate::easing::Easing;
use crate::signal::{Signal, Tweenable};
use crate::timeline::{parallel, Action};
use super::text::{HighlightStage, HighlightTween, TextMotion, TextTween};
use super::{Padding, Shape, TextPos, NOT_TEXT};
fn bind_to_timeline(mut action: Action, shape: &Shape) -> Action {
action.attach_timeline(shape.timeline_weak());
action
}
pub struct Tween<T: Tweenable> {
shape: Shape,
signal: Signal<T>,
from: T,
to: T,
}
impl<T: Tweenable> Tween<T> {
pub(super) fn new(shape: Shape, signal: Signal<T>, from: T, to: T) -> Self {
Tween { shape, signal, from, to }
}
pub fn over(self, duration: f64, easing: Easing) -> Action {
let action = self.signal.tween_from(self.from, self.to, duration, easing);
bind_to_timeline(action, &self.shape)
}
}
impl<T: Tweenable> Deref for Tween<T> {
type Target = Shape;
fn deref(&self) -> &Shape {
&self.shape
}
}
impl<T: Tweenable> From<Tween<T>> for Shape {
fn from(t: Tween<T>) -> Shape {
t.shape
}
}
pub struct PaddingTween {
shape: Shape,
from: Padding,
to: Padding,
}
impl PaddingTween {
pub(super) fn new(shape: Shape, from: Padding, to: Padding) -> Self {
PaddingTween { shape, from, to }
}
pub fn over(self, duration: f64, easing: Easing) -> Action {
let action = {
let d = self.shape.inner.borrow();
parallel(vec![
d.pad_top.tween_from(self.from.top, self.to.top, duration, easing),
d.pad_right.tween_from(self.from.right, self.to.right, duration, easing),
d.pad_bottom.tween_from(self.from.bottom, self.to.bottom, duration, easing),
d.pad_left.tween_from(self.from.left, self.to.left, duration, easing),
])
};
bind_to_timeline(action, &self.shape)
}
}
impl Deref for PaddingTween {
type Target = Shape;
fn deref(&self) -> &Shape {
&self.shape
}
}
impl From<PaddingTween> for Shape {
fn from(t: PaddingTween) -> Shape {
t.shape
}
}
pub struct TextEdit {
shape: Shape,
old: String,
new: String,
}
impl TextEdit {
pub(super) fn new(shape: Shape, old: String, new: String) -> Self {
TextEdit { shape, old, new }
}
fn stage(&self) -> std::rc::Rc<std::cell::RefCell<super::text::TextStage>> {
self.shape.inner.borrow().text.as_ref().expect(NOT_TEXT).stage_handle()
}
fn chain(self, apply: impl FnOnce(&Shape) -> TextEdit) -> TextEdit {
let next = apply(&self.shape).new;
TextEdit { shape: self.shape, old: self.old, new: next }
}
pub fn content(self, content: impl Into<String>) -> TextEdit {
self.chain(|s| s.content(content))
}
pub fn append(self, content: impl Into<String>) -> TextEdit {
self.chain(|s| s.append(content))
}
pub fn prepend(self, content: impl Into<String>) -> TextEdit {
self.chain(|s| s.prepend(content))
}
pub fn insert(self, char_index: usize, content: impl Into<String>) -> TextEdit {
self.chain(|s| s.insert(char_index, content))
}
pub fn rewrite(
self,
from: impl Into<super::TextPos>,
to: impl Into<super::TextPos>,
content: impl Into<String>,
) -> TextEdit {
self.chain(|s| s.rewrite(from, to, content))
}
pub fn spawn(self) -> Action {
let stage = self.stage();
let action = TextTween::action(stage, TextMotion::Spawn, self.old, self.new, 0.0, Easing::Linear);
bind_to_timeline(action, &self.shape)
}
pub fn typing(self, over: f64, easing: Easing) -> Action {
let stage = self.stage();
let action = TextTween::action(stage, TextMotion::Typing, self.old, self.new, over, easing);
bind_to_timeline(action, &self.shape)
}
pub fn smooth(self, over: f64, easing: Easing) -> Action {
let stage = self.stage();
let action = TextTween::action(stage, TextMotion::Smooth, self.old, self.new, over, easing);
bind_to_timeline(action, &self.shape)
}
}
impl Deref for TextEdit {
type Target = Shape;
fn deref(&self) -> &Shape {
&self.shape
}
}
impl From<TextEdit> for Shape {
fn from(t: TextEdit) -> Shape {
t.shape
}
}
pub struct HighlightEdit {
shape: Shape,
old: Vec<(TextPos, TextPos)>,
new: Vec<(TextPos, TextPos)>,
}
impl HighlightEdit {
pub(super) fn new(shape: Shape, old: Vec<(TextPos, TextPos)>, new: Vec<(TextPos, TextPos)>) -> Self {
HighlightEdit { shape, old, new }
}
fn stage(&self) -> std::rc::Rc<std::cell::RefCell<HighlightStage>> {
self.shape.inner.borrow().text.as_ref().expect(NOT_TEXT).highlight_stage_handle()
}
pub fn over(self, over: f64, easing: Easing) -> Action {
let stage = self.stage();
let action = HighlightTween::action(stage, self.old, self.new, over, easing);
bind_to_timeline(action, &self.shape)
}
}
impl Deref for HighlightEdit {
type Target = Shape;
fn deref(&self) -> &Shape {
&self.shape
}
}
impl From<HighlightEdit> for Shape {
fn from(t: HighlightEdit) -> Shape {
t.shape
}
}