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