freya_components/
overflowed_content.rs1use std::time::Duration;
2
3use freya_animation::prelude::{
4 AnimDirection,
5 AnimNum,
6 Ease,
7 Function,
8 use_animation,
9};
10use freya_core::prelude::*;
11use torin::{
12 node::Node,
13 prelude::Area,
14 size::Size,
15};
16
17#[derive(Clone, PartialEq, Default)]
19pub enum OverflowedContentDirection {
20 #[default]
22 RightToLeft,
23 LeftToRight,
25}
26
27#[derive(Clone, PartialEq, Default)]
29pub enum OverflowedContentStart {
30 #[default]
32 Edge,
33 Visible,
35}
36
37#[derive(Clone, PartialEq)]
56pub struct OverflowedContent {
57 children: Vec<Element>,
58 layout: LayoutData,
59 duration: Duration,
60 direction: OverflowedContentDirection,
61 start: OverflowedContentStart,
62 key: DiffKey,
63}
64
65impl LayoutExt for OverflowedContent {
66 fn get_layout(&mut self) -> &mut LayoutData {
67 &mut self.layout
68 }
69}
70
71impl ContainerSizeExt for OverflowedContent {}
72impl ContainerPositionExt for OverflowedContent {}
73
74impl Default for OverflowedContent {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80impl ChildrenExt for OverflowedContent {
81 fn get_children(&mut self) -> &mut Vec<Element> {
82 &mut self.children
83 }
84}
85
86impl KeyExt for OverflowedContent {
87 fn write_key(&mut self) -> &mut DiffKey {
88 &mut self.key
89 }
90}
91
92impl OverflowedContent {
93 pub fn new() -> Self {
94 Self {
95 children: Vec::new(),
96 layout: Node {
97 width: Size::fill(),
98 height: Size::Inner,
99 ..Default::default()
100 }
101 .into(),
102 duration: Duration::from_secs(4),
103 direction: OverflowedContentDirection::default(),
104 start: OverflowedContentStart::default(),
105 key: DiffKey::None,
106 }
107 }
108
109 pub fn width(mut self, width: impl Into<Size>) -> Self {
110 self.layout.width = width.into();
111 self
112 }
113
114 pub fn height(mut self, height: impl Into<Size>) -> Self {
115 self.layout.height = height.into();
116 self
117 }
118
119 pub fn duration(mut self, duration: Duration) -> Self {
120 self.duration = duration;
121 self
122 }
123
124 pub fn direction(mut self, direction: OverflowedContentDirection) -> Self {
125 self.direction = direction;
126 self
127 }
128
129 pub fn right_to_left(self) -> Self {
130 self.direction(OverflowedContentDirection::RightToLeft)
131 }
132
133 pub fn left_to_right(self) -> Self {
134 self.direction(OverflowedContentDirection::LeftToRight)
135 }
136
137 pub fn start(mut self, start: OverflowedContentStart) -> Self {
138 self.start = start;
139 self
140 }
141
142 pub fn start_edge(self) -> Self {
143 self.start(OverflowedContentStart::Edge)
144 }
145
146 pub fn start_visible(self) -> Self {
147 self.start(OverflowedContentStart::Visible)
148 }
149}
150
151impl Component for OverflowedContent {
152 fn render(&self) -> impl IntoElement {
153 let mut content_area = use_state(Area::default);
154 let mut container_area = use_state(Area::default);
155
156 let container_width = container_area.read().width();
157 let content_width = content_area.read().width();
158 let does_overflow = content_width > container_width;
159
160 let duration = self.duration;
161
162 let animation = use_animation(move |_| {
163 AnimNum::new(0., 100.)
164 .duration(duration)
165 .ease(Ease::InOut)
166 .function(Function::Linear)
167 });
168
169 let is_running = *animation.is_running().read();
170 let has_run = *animation.has_run_yet().read();
171
172 use_side_effect_with_deps(
173 &(does_overflow, is_running, has_run),
174 move |&(does_overflow, is_running, has_run)| {
175 if does_overflow && (!has_run || !is_running) {
176 animation.run(AnimDirection::Forward);
177 }
178 },
179 );
180
181 let progress = animation.get().value();
182 let is_first_cycle =
183 *animation.runs().read() <= 1 && self.start == OverflowedContentStart::Visible;
184
185 let offset_x = if does_overflow {
186 match (&self.direction, is_first_cycle) {
187 (OverflowedContentDirection::RightToLeft, false) => {
188 container_width - (content_width + container_width) * progress / 100.
189 }
190 (OverflowedContentDirection::RightToLeft, true) => {
191 -(content_width * progress / 100.)
192 }
193 (OverflowedContentDirection::LeftToRight, false) => {
194 (content_width + container_width) * progress / 100. - content_width
195 }
196 (OverflowedContentDirection::LeftToRight, true) => {
197 container_width * progress / 100.
198 }
199 }
200 } else {
201 0.
202 };
203
204 rect()
205 .width(self.layout.width.clone())
206 .height(self.layout.height.clone())
207 .overflow(Overflow::Clip)
208 .on_sized(move |e: Event<SizedEventData>| container_area.set(e.area))
209 .child(
210 rect()
211 .offset_x(offset_x)
212 .on_sized(move |e: Event<SizedEventData>| content_area.set(e.area))
213 .children(self.children.clone()),
214 )
215 }
216
217 fn render_key(&self) -> DiffKey {
218 self.key.clone().or(self.default_key())
219 }
220}