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