cosmic_time/keyframes/
button.rs

1use iced_native::{widget, Element, Length, Padding};
2
3use crate::keyframes::{as_f32, get_length, Repeat};
4use crate::timeline::Frame;
5use crate::{Ease, Linear, MovementType};
6
7/// A Button's animation Id. Used for linking animation built in `update()` with widget output in `view()`
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Id(iced_native::widget::Id);
10
11impl Id {
12    /// Creates a custom [`Id`].
13    pub fn new(id: impl Into<std::borrow::Cow<'static, str>>) -> Self {
14        Self(widget::Id::new(id))
15    }
16
17    /// Creates a unique [`Id`].
18    ///
19    /// This function produces a different [`Id`] every time it is called.
20    pub fn unique() -> Self {
21        Self(widget::Id::unique())
22    }
23
24    /// Used by [`crate::chain!`] macro
25    pub fn into_chain(self) -> Chain {
26        Chain::new(self)
27    }
28
29    /// Used by [`crate::chain!`] macro
30    pub fn into_chain_with_children(self, children: Vec<Button>) -> Chain {
31        Chain::with_children(self, children)
32    }
33
34    /// Used by [`crate::anim!`] macro
35    pub fn as_widget<'a, Message, Renderer>(
36        self,
37        timeline: &crate::Timeline,
38        content: impl Into<Element<'a, Message, Renderer>>,
39    ) -> widget::Button<'a, Message, Renderer>
40    where
41        Renderer: iced_native::Renderer,
42        Renderer::Theme: widget::button::StyleSheet,
43    {
44        Button::as_widget(self, timeline, content)
45    }
46}
47
48impl From<Id> for widget::Id {
49    fn from(id: Id) -> Self {
50        id.0
51    }
52}
53
54#[derive(Debug)]
55pub struct Chain {
56    id: Id,
57    links: Vec<Button>,
58    repeat: Repeat,
59}
60
61impl Chain {
62    pub fn new(id: Id) -> Self {
63        Chain {
64            id,
65            links: Vec::new(),
66            repeat: Repeat::Never,
67        }
68    }
69
70    pub fn with_children(id: Id, children: Vec<Button>) -> Self {
71        Chain {
72            id,
73            links: children,
74            repeat: Repeat::Never,
75        }
76    }
77
78    pub fn link(mut self, button: Button) -> Self {
79        self.links.push(button);
80        self
81    }
82
83    pub fn loop_forever(mut self) -> Self {
84        self.repeat = Repeat::Forever;
85        self
86    }
87
88    pub fn loop_once(mut self) -> Self {
89        self.repeat = Repeat::Never;
90        self
91    }
92}
93
94impl From<Chain> for crate::timeline::Chain {
95    fn from(chain: Chain) -> Self {
96        crate::timeline::Chain::new(
97            chain.id.into(),
98            chain.repeat,
99            chain
100                .links
101                .into_iter()
102                .map(|b| b.into())
103                .collect::<Vec<_>>(),
104        )
105    }
106}
107
108#[must_use = "Keyframes are intended to be used in an animation chain."]
109#[derive(Debug, Clone, Copy)]
110pub struct Button {
111    at: MovementType,
112    ease: Ease,
113    width: Option<Length>,
114    height: Option<Length>,
115    padding: Option<Padding>,
116    is_eager: bool,
117}
118
119impl Button {
120    pub fn new(at: impl Into<MovementType>) -> Button {
121        let at = at.into();
122        Button {
123            at,
124            ease: Linear::InOut.into(),
125            width: None,
126            height: None,
127            padding: None,
128            is_eager: true,
129        }
130    }
131
132    pub fn lazy(at: impl Into<MovementType>) -> Button {
133        let at = at.into();
134        Button {
135            at,
136            ease: Linear::InOut.into(),
137            width: None,
138            height: None,
139            padding: None,
140            is_eager: false,
141        }
142    }
143
144    pub fn as_widget<'a, Message, Renderer>(
145        id: Id,
146        timeline: &crate::Timeline,
147        content: impl Into<Element<'a, Message, Renderer>>,
148    ) -> widget::Button<'a, Message, Renderer>
149    where
150        Renderer: iced_native::Renderer,
151        Renderer::Theme: widget::button::StyleSheet,
152    {
153        let id: widget::Id = id.into();
154
155        widget::Button::new(content)
156            .width(get_length(&id, timeline, 0, Length::Shrink))
157            .height(get_length(&id, timeline, 1, Length::Shrink))
158            .padding([
159                timeline.get(&id, 2).map(|m| m.value).unwrap_or(5.0),
160                timeline.get(&id, 3).map(|m| m.value).unwrap_or(5.0),
161                timeline.get(&id, 4).map(|m| m.value).unwrap_or(5.0),
162                timeline.get(&id, 5).map(|m| m.value).unwrap_or(5.0),
163            ])
164    }
165
166    pub fn width(mut self, width: Length) -> Self {
167        self.width = Some(width);
168        self
169    }
170
171    pub fn height(mut self, height: Length) -> Self {
172        self.height = Some(height);
173        self
174    }
175
176    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
177        self.padding = Some(padding.into());
178        self
179    }
180
181    pub fn ease<E: Into<Ease>>(mut self, ease: E) -> Self {
182        self.ease = ease.into();
183        self
184    }
185}
186
187#[rustfmt::skip]
188impl From<Button> for Vec<Option<Frame>> {
189    fn from(button: Button) -> Vec<Option<Frame>> {
190      if button.is_eager {
191        vec![as_f32(button.width).map(|w| Frame::eager(button.at, w, button.ease)),  // 0 = width
192             as_f32(button.height).map(|h| Frame::eager(button.at, h, button.ease)), // 1 = height
193             button.padding.map(|p| Frame::eager(button.at, p.top, button.ease)),    // 2 = padding[0] (top)
194             button.padding.map(|p| Frame::eager(button.at, p.right, button.ease)),  // 3 = padding[1] (right)
195             button.padding.map(|p| Frame::eager(button.at, p.bottom, button.ease)), // 4 = padding[2] (bottom)
196             button.padding.map(|p| Frame::eager(button.at, p.left, button.ease)),   // 5 = padding[3] (left)
197        ]
198      } else {
199        vec![Some(Frame::lazy(button.at, 0., button.ease)), // 0 = width
200             Some(Frame::lazy(button.at, 0., button.ease)), // 1 = height
201             Some(Frame::lazy(button.at, 5., button.ease)), // 2 = padding[0] (top)
202             Some(Frame::lazy(button.at, 5., button.ease)), // 3 = padding[1] (right)
203             Some(Frame::lazy(button.at, 5., button.ease)), // 4 = padding[2] (bottom)
204             Some(Frame::lazy(button.at, 5., button.ease)), // 5 = padding[3] (left)
205        ]
206      }
207    }
208}