11use iced:: alignment;
22use 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
810use cosmic_time:: {
911 self ,
1012 style_button:: { self , StyleButton } ,
11- Timeline ,
13+ style_container:: { self , StyleContainer } ,
14+ Sinusoidal , Timeline ,
1215} ;
1316use once_cell:: sync:: Lazy ;
1417
1518static 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
1721use 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
168185fn 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
174191fn 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+ }
0 commit comments