Skip to content

Commit 66685b0

Browse files
authored
Merge pull request #7 from pop-os/pause
Pause
2 parents dd7a8aa + d7db2b4 commit 66685b0

File tree

9 files changed

+453
-107
lines changed

9 files changed

+453
-107
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TODOs before release:
1717
- [ ] Documentation
1818
- [ ] Add `Cosmic` cargo feature for compatibility with both iced and System76's temporary fork.
1919
- [x] optimize for `as_subscription` logic
20-
- [ ] Add pause for looping animations
20+
- [x] Add pause for animations
2121

2222
Other TODOs:
2323
- [x] test for easing

examples/counter/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl Application for Counter {
9797
}
9898

9999
fn title(&self) -> String {
100-
String::from("Counter - Iced")
100+
String::from("Counter - Cosmic-Time")
101101
}
102102

103103
fn subscription(&self) -> Subscription<Message> {

examples/pokedex/src/main.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@ use once_cell::sync::Lazy;
1313

1414
static SPACE: Lazy<keyframes::space::Id> = Lazy::new(keyframes::space::Id::unique);
1515

16-
//Linear,
17-
//Quadratic,
18-
//Cubic,
19-
//Quartic,
20-
//Quintic,
21-
//Sinusoidal,
22-
//Exponential,
23-
//Circular,
24-
//Elastic,
25-
//Back,
26-
//Bounce
2716
const EASE_IN: [Ease; 10] = [
2817
Ease::Linear(Linear::InOut),
2918
Ease::Quadratic(Quadratic::In),

examples/stopwatch/src/main.rs

Lines changed: 116 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use iced::alignment;
22
use iced::executor;
3-
use iced::theme::{self, Theme};
4-
use iced::time;
5-
use iced::widget::{button, column, container, row, text};
6-
use iced::{Alignment, Application, Command, Element, Event, Length, Settings, Subscription};
3+
use iced::widget::{button, column, row, text};
4+
use iced::{Alignment, Application, Command, Event, Length, Settings, Subscription};
5+
6+
mod theme;
7+
use self::widget::Element;
8+
use theme::Theme;
79

810
use cosmic_time::{
911
self,
1012
style_button::{self, StyleButton},
11-
Timeline,
13+
style_container::{self, StyleContainer},
14+
Sinusoidal, Timeline,
1215
};
1316
use once_cell::sync::Lazy;
1417

1518
static BUTTON: Lazy<style_button::Id> = Lazy::new(style_button::Id::unique);
19+
static CONTAINER: Lazy<style_container::Id> = Lazy::new(style_container::Id::unique);
1620

1721
use std::time::{Duration, Instant};
1822

@@ -45,9 +49,11 @@ impl Application for Stopwatch {
4549
type Flags = ();
4650

4751
fn new(_flags: ()) -> (Stopwatch, Command<Message>) {
52+
let mut timeline = Timeline::new();
53+
timeline.set_chain_paused(anim_background()).start();
4854
(
4955
Stopwatch {
50-
timeline: Timeline::new(),
56+
timeline,
5157
duration: Duration::default(),
5258
state: State::Idle,
5359
},
@@ -56,7 +62,7 @@ impl Application for Stopwatch {
5662
}
5763

5864
fn title(&self) -> String {
59-
String::from("Stopwatch - Iced")
65+
String::from("Stopwatch - Cosmic-Time")
6066
}
6167

6268
fn update(&mut self, message: Message) -> Command<Message> {
@@ -66,11 +72,17 @@ impl Application for Stopwatch {
6672
self.state = State::Ticking {
6773
last_tick: Instant::now(),
6874
};
69-
self.timeline.set_chain(anim_to_destructive()).start();
75+
self.timeline
76+
.set_chain(anim_to_destructive())
77+
.resume(CONTAINER.clone())
78+
.start();
7079
}
7180
State::Ticking { .. } => {
7281
self.state = State::Idle;
73-
self.timeline.set_chain(anim_to_primary()).start();
82+
self.timeline
83+
.set_chain(anim_to_primary())
84+
.pause(CONTAINER.clone())
85+
.start();
7486
}
7587
},
7688
Message::Tick(now) => {
@@ -82,20 +94,18 @@ impl Application for Stopwatch {
8294
}
8395
Message::Reset => {
8496
self.duration = Duration::default();
97+
match self.state {
98+
State::Idle => self.timeline.set_chain_paused(anim_background()).start(),
99+
State::Ticking { .. } => self.timeline.set_chain(anim_background()).start(),
100+
}
85101
}
86102
}
87103

88104
Command::none()
89105
}
90106

91107
fn subscription(&self) -> Subscription<Message> {
92-
Subscription::batch(vec![
93-
match self.state {
94-
State::Idle => Subscription::none(),
95-
State::Ticking { .. } => time::every(Duration::from_millis(10)).map(Message::Tick),
96-
},
97-
self.timeline.as_subscription::<Event>().map(Message::Tick),
98-
])
108+
self.timeline.as_subscription::<Event>().map(Message::Tick)
99109
}
100110

101111
fn view(&self) -> Element<Message> {
@@ -156,31 +166,73 @@ impl Application for Stopwatch {
156166
.align_items(Alignment::Center)
157167
.spacing(20);
158168

159-
container(content)
160-
.width(Length::Fill)
161-
.height(Length::Fill)
162-
.center_x()
163-
.center_y()
164-
.into()
169+
StyleContainer::as_widget(
170+
CONTAINER.clone(),
171+
// Cool! Because we implemented the function on our custom, theme's type, adding
172+
// the map argument is easy!
173+
theme::Container::map(),
174+
&self.timeline,
175+
content,
176+
)
177+
.width(Length::Fill)
178+
.height(Length::Fill)
179+
.center_x()
180+
.center_y()
181+
.into()
165182
}
166183
}
167184

168185
fn anim_to_primary() -> style_button::Chain {
169186
style_button::Chain::new(BUTTON.clone())
170-
.link(StyleButton::new(Duration::ZERO).style(as_u8(theme::Button::Destructive)))
171-
.link(StyleButton::new(Duration::from_millis(500)).style(as_u8(theme::Button::Primary)))
187+
.link(StyleButton::new(Duration::ZERO).style(button_u8(theme::Button::Destructive)))
188+
.link(StyleButton::new(Duration::from_millis(500)).style(button_u8(theme::Button::Primary)))
172189
}
173190

174191
fn anim_to_destructive() -> style_button::Chain {
175192
style_button::Chain::new(BUTTON.clone())
176-
.link(StyleButton::new(Duration::ZERO).style(as_u8(theme::Button::Primary)))
177-
.link(StyleButton::new(Duration::from_millis(500)).style(as_u8(theme::Button::Destructive)))
193+
.link(StyleButton::new(Duration::ZERO).style(button_u8(theme::Button::Primary)))
194+
.link(
195+
StyleButton::new(Duration::from_millis(500))
196+
.style(button_u8(theme::Button::Destructive)),
197+
)
198+
}
199+
200+
fn anim_background() -> style_container::Chain {
201+
style_container::Chain::new(CONTAINER.clone())
202+
.link(StyleContainer::new(Duration::ZERO).style(theme::Container::Red))
203+
.link(
204+
StyleContainer::new(Duration::from_secs(1))
205+
// Notice how we can just pass the enum value here, where in the `anim_to_primary/destructive`
206+
// we have to use the fucntion `button_u8`? Because we use a implemented a custom iced theme,
207+
// we can just impl Into<u8> on the enum, and it works here!
208+
.style(theme::Container::Green)
209+
.ease(Sinusoidal::In),
210+
)
211+
.link(
212+
StyleContainer::new(Duration::from_secs(2))
213+
.style(theme::Container::Blue)
214+
.ease(Sinusoidal::In),
215+
)
216+
.link(
217+
StyleContainer::new(Duration::from_secs(3))
218+
.style(theme::Container::Red)
219+
.ease(Sinusoidal::In),
220+
)
221+
.loop_forever()
178222
}
179223

180224
// Style implementations
181225

226+
// Here the button example uses Iced's default theme
227+
// enum. So we have to have some helper functions to make it work.
228+
// we also have another closture, `buttons`, in `fn view()`
229+
//
230+
// For themining reasons, this actually isn't iced's default
231+
// button theme, but the implementation here for button is what you
232+
// would have to do to use the iced type in your project.
233+
182234
// the enum's default must be 0
183-
fn as_u8(style: theme::Button) -> u8 {
235+
fn button_u8(style: theme::Button) -> u8 {
184236
match style {
185237
theme::Button::Primary => 0,
186238
theme::Button::Secondary => 1,
@@ -190,3 +242,40 @@ fn as_u8(style: theme::Button) -> u8 {
190242
_ => panic!("Custom is not supported"),
191243
}
192244
}
245+
246+
// But! if we are useing a custom theme then
247+
// the code cleans up quite a bit.
248+
249+
impl From<theme::Container> for u8 {
250+
fn from(style: theme::Container) -> Self {
251+
match style {
252+
theme::Container::White => 0,
253+
theme::Container::Red => 1,
254+
theme::Container::Green => 2,
255+
theme::Container::Blue => 3,
256+
}
257+
}
258+
}
259+
260+
impl theme::Container {
261+
fn map() -> fn(u8) -> theme::Container {
262+
|i: u8| match i {
263+
0 => theme::Container::White,
264+
1 => theme::Container::Red,
265+
2 => theme::Container::Green,
266+
3 => theme::Container::Blue,
267+
_ => panic!("Impossible"),
268+
}
269+
}
270+
}
271+
272+
// Just for themeing, not a part of this example.
273+
mod widget {
274+
#![allow(dead_code)]
275+
use crate::theme::Theme;
276+
277+
pub type Renderer = iced::Renderer<Theme>;
278+
pub type Element<'a, Message> = iced::Element<'a, Message, Renderer>;
279+
pub type Container<'a, Message> = iced::widget::Container<'a, Message, Renderer>;
280+
pub type Button<'a, Message> = iced::widget::Button<'a, Message, Renderer>;
281+
}

examples/stopwatch/src/theme.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* This file is not specific to cosmic-time.
3+
* The relevant code to this example is in main.rs.
4+
* This is just code to make an iced theme, so
5+
* the stopwatch example can be prettier, and
6+
* show the andvantages of style animations
7+
* with a custom theme.
8+
*
9+
*/
10+
11+
use iced::widget::{button, container, text};
12+
use iced::Background as B;
13+
use iced::{application, color, Vector};
14+
15+
#[derive(Default)]
16+
pub struct Theme;
17+
18+
impl application::StyleSheet for Theme {
19+
type Style = ();
20+
21+
fn appearance(&self, _style: &Self::Style) -> application::Appearance {
22+
application::Appearance {
23+
background_color: color!(0xff, 0xff, 0xff),
24+
text_color: color!(0xff, 0x00, 0x00),
25+
}
26+
}
27+
}
28+
29+
impl text::StyleSheet for Theme {
30+
type Style = ();
31+
32+
fn appearance(&self, _style: Self::Style) -> text::Appearance {
33+
text::Appearance {
34+
color: color!(0xff, 0xff, 0xff).into(),
35+
}
36+
}
37+
}
38+
39+
#[derive(Debug, Clone, Copy, Default)]
40+
pub enum Container {
41+
#[default]
42+
White,
43+
Red,
44+
Green,
45+
Blue,
46+
}
47+
48+
impl container::StyleSheet for Theme {
49+
type Style = Container;
50+
51+
fn appearance(&self, style: &Self::Style) -> container::Appearance {
52+
match style {
53+
Container::White => container::Appearance {
54+
background: Some(B::Color(color!(0xd1, 0xd5, 0xdb))),
55+
text_color: Some(color!(0x00, 0x00, 0x00)),
56+
..Default::default()
57+
},
58+
Container::Red => container::Appearance {
59+
background: Some(B::Color(color!(0xfc, 0xa5, 0xa5))),
60+
text_color: Some(color!(0x00, 0x00, 0x00)),
61+
..Default::default()
62+
},
63+
Container::Green => container::Appearance {
64+
background: Some(B::Color(color!(0xb3, 0xf2, 0x64))),
65+
text_color: Some(color!(0x00, 0x00, 0x00)),
66+
..Default::default()
67+
},
68+
Container::Blue => container::Appearance {
69+
background: Some(B::Color(color!(0x93, 0xc5, 0xfd))),
70+
text_color: Some(color!(0x00, 0x00, 0x00)),
71+
..Default::default()
72+
},
73+
}
74+
}
75+
}
76+
77+
#[derive(Default)]
78+
#[allow(dead_code)]
79+
pub enum Button {
80+
#[default]
81+
Primary,
82+
Secondary,
83+
Positive,
84+
Destructive,
85+
Text,
86+
Custom(Box<dyn button::StyleSheet<Style = Theme>>),
87+
}
88+
89+
impl button::StyleSheet for Theme {
90+
type Style = Button;
91+
92+
fn active(&self, style: &Self::Style) -> button::Appearance {
93+
match style {
94+
Button::Primary => button::Appearance {
95+
background: color!(0x25, 0x63, 0xeb).into(),
96+
text_color: color!(0x00, 0x00, 0x00),
97+
border_radius: 10.0,
98+
border_width: 10.0,
99+
shadow_offset: Vector::new(3., 3.),
100+
border_color: color!(0x25, 0x63, 0xeb),
101+
},
102+
Button::Secondary => button::Appearance {
103+
background: color!(0x3c, 0x38, 0x36).into(),
104+
border_radius: 10.0,
105+
shadow_offset: Vector::new(3., 3.),
106+
text_color: color!(0xff, 0xff, 0xff),
107+
..Default::default()
108+
},
109+
Button::Destructive => button::Appearance {
110+
background: color!(0xdc, 0x26, 0x26).into(),
111+
text_color: color!(0xff, 0xff, 0xff),
112+
border_radius: 10.0,
113+
shadow_offset: Vector::new(5., 5.),
114+
border_color: color!(0xdc, 0x26, 0x26),
115+
border_width: 10.0,
116+
},
117+
_ => panic!("This isn't a custom style exmaple, just skipping these for now"),
118+
}
119+
}
120+
121+
fn hovered(&self, style: &Self::Style) -> button::Appearance {
122+
self.active(style)
123+
}
124+
125+
fn pressed(&self, style: &Self::Style) -> button::Appearance {
126+
self.active(style)
127+
}
128+
}

src/keyframes/style_button.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ impl StyleButton {
154154
self
155155
}
156156

157-
pub fn style(mut self, style: u8) -> Self {
157+
pub fn style(mut self, style: impl Into<u8>) -> Self {
158+
let style = style.into();
158159
self.style = Some(style);
159160
self
160161
}

0 commit comments

Comments
 (0)