freya_components/
overflowed_content.rs1use std::time::Duration;
2
3use freya_animation::prelude::{
4 AnimDirection,
5 AnimNum,
6 Ease,
7 Function,
8 OnFinish,
9 use_animation,
10};
11use freya_core::prelude::*;
12use torin::{
13 prelude::Area,
14 size::Size,
15};
16
17#[derive(Clone, PartialEq)]
36pub struct OverflowedContent {
37 children: Vec<Element>,
38 width: Size,
39 height: Size,
40 duration: Duration,
41 key: DiffKey,
42}
43
44impl Default for OverflowedContent {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl ChildrenExt for OverflowedContent {
51 fn get_children(&mut self) -> &mut Vec<Element> {
52 &mut self.children
53 }
54}
55
56impl KeyExt for OverflowedContent {
57 fn write_key(&mut self) -> &mut DiffKey {
58 &mut self.key
59 }
60}
61
62impl OverflowedContent {
63 pub fn new() -> Self {
64 Self {
65 children: Vec::new(),
66 width: Size::fill(),
67 height: Size::auto(),
68 duration: Duration::from_secs(4),
69 key: DiffKey::None,
70 }
71 }
72
73 pub fn width(mut self, width: impl Into<Size>) -> Self {
74 self.width = width.into();
75 self
76 }
77
78 pub fn height(mut self, height: impl Into<Size>) -> Self {
79 self.height = height.into();
80 self
81 }
82
83 pub fn duration(mut self, duration: Duration) -> Self {
84 self.duration = duration;
85 self
86 }
87}
88
89impl Render for OverflowedContent {
90 fn render(&self) -> impl IntoElement {
91 let mut label_size = use_state(Area::default);
92 let mut rect_size = use_state(Area::default);
93
94 let rect_width = rect_size.read().width();
95 let label_width = label_size.read().width();
96 let does_overflow = label_width > rect_width;
97
98 let duration = self.duration;
99 let animation = use_animation(move |conf| {
100 conf.on_finish(OnFinish::restart());
101
102 AnimNum::new(0., 100.)
103 .duration(duration)
104 .ease(Ease::InOut)
105 .function(Function::Linear)
106 });
107
108 use_side_effect_with_deps(&does_overflow, move |does_overflow| {
109 if *does_overflow {
110 animation.run(AnimDirection::Forward);
111 }
112 });
113
114 let progress = animation.get().value();
115 let offset_x = if does_overflow {
116 ((label_width + rect_width) * progress / 100.) - rect_width
117 } else {
118 0.
119 };
120
121 rect()
122 .width(self.width.clone())
123 .height(self.height.clone())
124 .offset_x(-offset_x)
125 .overflow(Overflow::Clip)
126 .on_sized(move |e: Event<SizedEventData>| rect_size.set(e.area))
127 .child(
128 rect()
129 .on_sized(move |e: Event<SizedEventData>| label_size.set(e.area))
130 .children(self.children.clone()),
131 )
132 }
133
134 fn render_key(&self) -> DiffKey {
135 self.key.clone().or(self.default_key())
136 }
137}