Skip to content

Commit e62c952

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

File tree

8 files changed

+164
-121
lines changed

8 files changed

+164
-121
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: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ use cosmic::iced_core::text;
88
use cosmic::iced_core::time::Duration;
99
use cosmic::iced_core::widget::Tree;
1010
use cosmic::iced_core::{
11-
Alignment, Clipboard, Element, Event, Layout, Length, Pixels, Point, Rectangle, Shell, Widget,
11+
Alignment, Clipboard, Element, Event, Layout, Length, Pixels, Point, Rectangle,
12+
Shell, Widget,
1213
};
1314
use cosmic::iced_widget::{Row, Text};
1415

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

1819
/// The default animation duration. Change here for custom widgets. Or at runtime with `.anim_multiplier`
@@ -40,9 +41,9 @@ where
4041
Renderer: text::Renderer,
4142
Renderer::Theme: StyleSheet,
4243
{
43-
id: crate::keyframes::toggler::Id,
44+
id: id::Toggler,
4445
is_toggled: bool,
45-
on_toggle: Box<dyn Fn(Chain, bool) -> Message + 'a>,
46+
on_toggle: Box<dyn Fn(chain::Toggler, bool) -> Message + 'a>,
4647
label: Option<String>,
4748
width: Length,
4849
size: f32,
@@ -73,14 +74,9 @@ where
7374
/// * a function that will be called when the [`Toggler`] is toggled. It
7475
/// will receive the new state of the [`Toggler`] and must produce a
7576
/// `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
77+
pub fn new<F>(id: id::Toggler, label: impl Into<Option<String>>, is_toggled: bool, f: F) -> Self
8278
where
83-
F: 'a + Fn(Chain, bool) -> Message,
79+
F: 'a + Fn(chain::Toggler, bool) -> Message,
8480
{
8581
Toggler {
8682
id,
@@ -221,25 +217,20 @@ where
221217
// TODO this should be possible to fix once redirectable
222218
// animations are implemented.
223219
if mouse_over && (self.percent == 0.0 || self.percent == 1.0) {
220+
let duration = (ANIM_DURATION * self.anim_multiplier.round()) as u64;
224221
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-
);
222+
let off_animation = chain!(
223+
self.id.clone(),
224+
toggler(Duration::ZERO).percent(1.0),
225+
toggler(Duration::from_millis(duration)).percent(0.0),
226+
);
233227
shell.publish((self.on_toggle)(off_animation, !self.is_toggled));
234228
} 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-
);
229+
let on_animation = chain!(
230+
self.id.clone(),
231+
toggler(Duration::ZERO).percent(0.0),
232+
toggler(Duration::from_millis(duration)).percent(1.0),
233+
);
243234
shell.publish((self.on_toggle)(on_animation, !self.is_toggled));
244235
}
245236

@@ -310,9 +301,17 @@ where
310301
let is_mouse_over = bounds.contains(cursor_position);
311302

312303
let style = if is_mouse_over {
313-
theme.hovered(&self.style, self.is_toggled)
304+
blend_appearances(
305+
theme.hovered(&self.style, false),
306+
theme.hovered(&self.style, true),
307+
self.percent,
308+
)
314309
} else {
315-
theme.active(&self.style, self.is_toggled)
310+
blend_appearances(
311+
theme.active(&self.style, false),
312+
theme.active(&self.style, true),
313+
self.percent,
314+
)
316315
};
317316

318317
let border_radius = bounds.height / BORDER_RADIUS_RATIO;
@@ -337,11 +336,11 @@ where
337336

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

0 commit comments

Comments
 (0)