Skip to content

Commit e303247

Browse files
committed
Fix toggler widget & generall toggler improvements
1 parent 36610c7 commit e303247

File tree

8 files changed

+162
-120
lines changed

8 files changed

+162
-120
lines changed

src/keyframes.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
pub mod toggler;
2-
31
mod button;
42
mod column;
53
mod container;
@@ -8,6 +6,7 @@ mod row;
86
mod space;
97
mod style_button;
108
mod style_container;
9+
mod toggler;
1110

1211
#[cfg(feature = "libcosmic")]
1312
use cosmic::iced_core::{widget, Length};
@@ -19,7 +18,9 @@ pub use column::Column;
1918
pub use container::Container;
2019
pub use helpers::id;
2120
pub use helpers::lazy;
22-
pub use helpers::{button, column, container, row, space, style_button, style_container, chain};
21+
pub use helpers::{
22+
button, chain, column, container, row, space, style_button, style_container, toggler,
23+
};
2324
pub use row::Row;
2425
pub use space::Space;
2526
pub use style_button::StyleButton;

src/keyframes/helpers.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::keyframes::{Button, Column, Container, Row, Space, StyleButton, StyleContainer};
1+
use crate::keyframes::{
2+
Button, Column, Container, Row, Space, StyleButton, StyleContainer, Toggler,
3+
};
24
use crate::MovementType;
35

46
/// Create a button keyframe.
@@ -31,6 +33,12 @@ pub fn space(at: impl Into<MovementType>) -> Space {
3133
Space::new(at)
3234
}
3335

36+
/// Create a toggler keyframe.
37+
/// Needs to be added into a chain. See [`crate::chain!`] macro.
38+
pub fn toggler(at: impl Into<MovementType>) -> Toggler {
39+
Toggler::new(at)
40+
}
41+
3442
/// Create a style_button keyframe.
3543
/// Needs to be added into a chain. See [`crate::chain!`] macro.
3644
pub fn style_button(at: impl Into<MovementType>) -> StyleButton {
@@ -103,5 +111,5 @@ pub mod id {
103111
/// Direct access to `Chain`s for widget that may return an animation
104112
/// in a message.
105113
pub mod chain {
106-
pub use crate::keyframes::toggler::Chain as Toggler;
114+
pub use crate::keyframes::toggler::Chain as Toggler;
107115
}

src/keyframes/toggler.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,22 @@ impl Id {
3636
pub fn into_chain_with_children(self, children: Vec<Toggler>) -> Chain {
3737
Chain::with_children(self, children)
3838
}
39+
40+
/// Used by [`crate::anim!`] macro
41+
pub fn as_widget<'a, Message, Renderer, F>(
42+
self,
43+
timeline: &crate::Timeline,
44+
label: impl Into<Option<String>>,
45+
is_toggled: bool,
46+
f: F,
47+
) -> crate::widget::Toggler<'a, Message, Renderer>
48+
where
49+
Renderer: IcedRenderer + text::Renderer,
50+
Renderer::Theme: widget::toggler::StyleSheet,
51+
F: 'a + Fn(Chain, bool) -> Message,
52+
{
53+
Toggler::as_widget(self, timeline, label, is_toggled, f)
54+
}
3955
}
4056

4157
impl From<Id> for IcedId {
@@ -115,6 +131,7 @@ impl From<Chain> for crate::timeline::Chain {
115131

116132
#[must_use = "Keyframes are intended to be used in an animation chain."]
117133
#[derive(Debug, Clone, Copy)]
134+
///
118135
pub struct Toggler {
119136
at: MovementType,
120137
ease: Ease,

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub mod widget;
138138
mod keyframes;
139139

140140
pub use crate::keyframes::{
141-
button, column, container, id, lazy, row, space, style_button, style_container, chain,
141+
button, chain, column, container, id, lazy, row, space, style_button, style_container, toggler,
142142
};
143143
pub use crate::timeline::{Chain, Timeline};
144144

src/widget/container.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ where
127127
self
128128
}
129129

130-
/// Sets the animatable style variant of this [`Container`].
130+
/// Set the appearance this [`Container`] to a blend of two styles.
131+
///
132+
/// Percent is a f32 of 0.0 -> 1.0.
133+
/// Where 0 is 100% style1 and 1 is 100% style2.
131134
pub fn blend_style(
132135
mut self,
133136
style1: <Renderer::Theme as StyleSheet>::Style,

src/widget/cosmic_button.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//! A [`Button`] has some local [`State`].
44
use cosmic::iced_runtime::core::widget::Id;
55
use cosmic::iced_runtime::{keyboard, Command};
6-
use std::borrow::Cow;
76

87
use crate::widget::StyleType;
98
use cosmic::iced_core::event::{self, Event};
@@ -458,7 +457,7 @@ impl State {
458457
/// Processes the given [`Event`] and updates the [`State`] of a [`Button`]
459458
/// accordingly.
460459
pub fn update<'a, Message: Clone>(
461-
id: Id,
460+
_id: Id,
462461
event: Event,
463462
layout: Layout<'_>,
464463
cursor_position: Point,

src/widget/cosmic_toggler.rs

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use cosmic::iced_core::{
1212
};
1313
use cosmic::iced_widget::{Row, Text};
1414

15-
use crate::keyframes::{self, toggler::Chain};
15+
use crate::{chain, id, lerp, toggler};
1616
pub use cosmic::iced_style::toggler::{Appearance, StyleSheet};
1717

1818
/// The default animation duration. Change here for custom widgets. Or at runtime with `.anim_multiplier`
@@ -40,9 +40,9 @@ where
4040
Renderer: text::Renderer,
4141
Renderer::Theme: StyleSheet,
4242
{
43-
id: crate::keyframes::toggler::Id,
43+
id: id::Toggler,
4444
is_toggled: bool,
45-
on_toggle: Box<dyn Fn(Chain, bool) -> Message + 'a>,
45+
on_toggle: Box<dyn Fn(chain::Toggler, bool) -> Message + 'a>,
4646
label: Option<String>,
4747
width: Length,
4848
size: f32,
@@ -73,14 +73,9 @@ where
7373
/// * a function that will be called when the [`Toggler`] is toggled. It
7474
/// will receive the new state of the [`Toggler`] and must produce a
7575
/// `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
76+
pub fn new<F>(id: id::Toggler, label: impl Into<Option<String>>, is_toggled: bool, f: F) -> Self
8277
where
83-
F: 'a + Fn(Chain, bool) -> Message,
78+
F: 'a + Fn(chain::Toggler, bool) -> Message,
8479
{
8580
Toggler {
8681
id,
@@ -221,25 +216,20 @@ where
221216
// TODO this should be possible to fix once redirectable
222217
// animations are implemented.
223218
if mouse_over && (self.percent == 0.0 || self.percent == 1.0) {
219+
let duration = (ANIM_DURATION * self.anim_multiplier.round()) as u64;
224220
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-
);
221+
let off_animation = chain!(
222+
self.id.clone(),
223+
toggler(Duration::ZERO).percent(1.0),
224+
toggler(Duration::from_millis(duration)).percent(0.0),
225+
);
233226
shell.publish((self.on_toggle)(off_animation, !self.is_toggled));
234227
} 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-
);
228+
let on_animation = chain!(
229+
self.id.clone(),
230+
toggler(Duration::ZERO).percent(0.0),
231+
toggler(Duration::from_millis(duration)).percent(1.0),
232+
);
243233
shell.publish((self.on_toggle)(on_animation, !self.is_toggled));
244234
}
245235

@@ -310,9 +300,17 @@ where
310300
let is_mouse_over = bounds.contains(cursor_position);
311301

312302
let style = if is_mouse_over {
313-
theme.hovered(&self.style, self.is_toggled)
303+
blend_appearances(
304+
theme.hovered(&self.style, false),
305+
theme.hovered(&self.style, true),
306+
self.percent,
307+
)
314308
} else {
315-
theme.active(&self.style, self.is_toggled)
309+
blend_appearances(
310+
theme.active(&self.style, false),
311+
theme.active(&self.style, true),
312+
self.percent,
313+
)
316314
};
317315

318316
let border_radius = bounds.height / BORDER_RADIUS_RATIO;
@@ -337,11 +335,11 @@ where
337335

338336
let toggler_foreground_bounds = Rectangle {
339337
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-
},
338+
+ lerp(
339+
2.0 * space,
340+
bounds.width - 2.0 * space - (bounds.height - (4.0 * space)),
341+
self.percent,
342+
),
345343
y: bounds.y + (2.0 * space),
346344
width: bounds.height - (4.0 * space),
347345
height: bounds.height - (4.0 * space),
@@ -369,3 +367,24 @@ where
369367
Element::new(toggler)
370368
}
371369
}
370+
371+
fn blend_appearances(one: Appearance, mut two: Appearance, percent: f32) -> Appearance {
372+
if percent == 0. {
373+
one
374+
} else if percent == 1. {
375+
two
376+
} else {
377+
let background: [f32; 4] = one
378+
.background
379+
.into_linear()
380+
.iter()
381+
.zip(two.background.into_linear().iter())
382+
.map(|(o, t)| o * (1.0 - percent) + t * percent)
383+
.collect::<Vec<f32>>()
384+
.try_into()
385+
.unwrap();
386+
387+
two.background = background.into();
388+
two
389+
}
390+
}

0 commit comments

Comments
 (0)