@@ -5,19 +5,15 @@ use cosmic::iced_core::layout;
55use cosmic:: iced_core:: mouse;
66use cosmic:: iced_core:: renderer;
77use cosmic:: iced_core:: text;
8- use cosmic:: iced_core:: time:: Duration ;
98use cosmic:: iced_core:: widget:: Tree ;
109use cosmic:: iced_core:: {
1110 Alignment , Clipboard , Element , Event , Layout , Length , Pixels , Point , Rectangle , Shell , Widget ,
1211} ;
1312use cosmic:: iced_widget:: { Row , Text } ;
1413
15- use crate :: keyframes :: { self , toggler :: Chain } ;
14+ use crate :: { chain , id , lerp } ;
1615pub use cosmic:: iced_style:: toggler:: { Appearance , StyleSheet } ;
1716
18- /// The default animation duration. Change here for custom widgets. Or at runtime with `.anim_multiplier`
19- const ANIM_DURATION : f32 = 100. ;
20-
2117/// A toggler widget.
2218///
2319/// # Example
4036 Renderer : text:: Renderer ,
4137 Renderer :: Theme : StyleSheet ,
4238{
43- id : crate :: keyframes :: toggler :: Id ,
39+ id : id :: Toggler ,
4440 is_toggled : bool ,
45- on_toggle : Box < dyn Fn ( Chain , bool ) -> Message + ' a > ,
41+ on_toggle : Box < dyn Fn ( chain :: Toggler , bool ) -> Message + ' a > ,
4642 label : Option < String > ,
4743 width : Length ,
4844 size : f32 ,
7369 /// * a function that will be called when the [`Toggler`] is toggled. It
7470 /// will receive the new state of the [`Toggler`] and must produce a
7571 /// `Message`.
76- pub fn new < F > (
77- id : crate :: keyframes:: toggler:: Id ,
78- label : impl Into < Option < String > > ,
79- is_toggled : bool ,
80- f : F ,
81- ) -> Self
72+ pub fn new < F > ( id : id:: Toggler , label : impl Into < Option < String > > , is_toggled : bool , f : F ) -> Self
8273 where
83- F : ' a + Fn ( Chain , bool ) -> Message ,
74+ F : ' a + Fn ( chain :: Toggler , bool ) -> Message ,
8475 {
8576 Toggler {
8677 id,
@@ -216,30 +207,14 @@ where
216207 Event :: Mouse ( mouse:: Event :: ButtonPressed ( mouse:: Button :: Left ) ) => {
217208 let mouse_over = layout. bounds ( ) . contains ( cursor_position) ;
218209
219- // To prevent broken animations, only send message if
220- // toggler is clicked after animation is finished.
221- // TODO this should be possible to fix once redirectable
222- // animations are implemented.
223- if mouse_over && ( self . percent == 0.0 || self . percent == 1.0 ) {
210+ if mouse_over {
224211 if self . is_toggled {
225- let off_animation = Chain :: new ( self . id . clone ( ) )
226- . link ( keyframes:: toggler:: Toggler :: new ( Duration :: ZERO ) . percent ( 1.0 ) )
227- . link (
228- keyframes:: toggler:: Toggler :: new ( Duration :: from_millis (
229- ( ANIM_DURATION * self . anim_multiplier . round ( ) ) as u64 ,
230- ) )
231- . percent ( 0.0 ) ,
232- ) ;
212+ let off_animation =
213+ chain:: Toggler :: off ( self . id . clone ( ) , self . anim_multiplier ) ;
233214 shell. publish ( ( self . on_toggle ) ( off_animation, !self . is_toggled ) ) ;
234215 } else {
235- let on_animation = Chain :: new ( self . id . clone ( ) )
236- . link ( keyframes:: toggler:: Toggler :: new ( Duration :: ZERO ) . percent ( 0.0 ) )
237- . link (
238- keyframes:: toggler:: Toggler :: new ( Duration :: from_millis (
239- ( ANIM_DURATION * self . anim_multiplier . round ( ) ) as u64 ,
240- ) )
241- . percent ( 1.0 ) ,
242- ) ;
216+ let on_animation =
217+ chain:: Toggler :: on ( self . id . clone ( ) , self . anim_multiplier ) ;
243218 shell. publish ( ( self . on_toggle ) ( on_animation, !self . is_toggled ) ) ;
244219 }
245220
@@ -310,9 +285,17 @@ where
310285 let is_mouse_over = bounds. contains ( cursor_position) ;
311286
312287 let style = if is_mouse_over {
313- theme. hovered ( & self . style , self . is_toggled )
288+ blend_appearances (
289+ theme. hovered ( & self . style , false ) ,
290+ theme. hovered ( & self . style , true ) ,
291+ self . percent ,
292+ )
314293 } else {
315- theme. active ( & self . style , self . is_toggled )
294+ blend_appearances (
295+ theme. active ( & self . style , false ) ,
296+ theme. active ( & self . style , true ) ,
297+ self . percent ,
298+ )
316299 } ;
317300
318301 let border_radius = bounds. height / BORDER_RADIUS_RATIO ;
@@ -337,11 +320,11 @@ where
337320
338321 let toggler_foreground_bounds = Rectangle {
339322 x : bounds. x
340- + if self . is_toggled {
341- bounds . width - 2.0 * space - ( bounds . height - ( 4.0 * space ) )
342- } else {
343- 2.0 * space
344- } ,
323+ + lerp (
324+ 2.0 * space,
325+ bounds . width - 2.0 * space - ( bounds . height - ( 4.0 * space ) ) ,
326+ self . percent ,
327+ ) ,
345328 y : bounds. y + ( 2.0 * space) ,
346329 width : bounds. height - ( 4.0 * space) ,
347330 height : bounds. height - ( 4.0 * space) ,
@@ -369,3 +352,24 @@ where
369352 Element :: new ( toggler)
370353 }
371354}
355+
356+ fn blend_appearances ( one : Appearance , mut two : Appearance , percent : f32 ) -> Appearance {
357+ if percent == 0. {
358+ one
359+ } else if percent == 1. {
360+ two
361+ } else {
362+ let background: [ f32 ; 4 ] = one
363+ . background
364+ . into_linear ( )
365+ . iter ( )
366+ . zip ( two. background . into_linear ( ) . iter ( ) )
367+ . map ( |( o, t) | o * ( 1.0 - percent) + t * percent)
368+ . collect :: < Vec < f32 > > ( )
369+ . try_into ( )
370+ . unwrap ( ) ;
371+
372+ two. background = background. into ( ) ;
373+ two
374+ }
375+ }
0 commit comments