1use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::time::{Duration, Instant};
7use crate::core::widget;
8use crate::core::widget::tree::{self, Tree};
9use crate::core::window;
10use crate::core::{
11 self, Element, Event, Layout, Length, Pixels, Rectangle, Shell, Size, Vector, Widget,
12};
13
14pub struct Sensor<'a, Key, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
18 content: Element<'a, Message, Theme, Renderer>,
19 key: Key,
20 on_show: Option<Box<dyn Fn(Size) -> Message + 'a>>,
21 on_resize: Option<Box<dyn Fn(Size) -> Message + 'a>>,
22 on_hide: Option<Message>,
23 anticipate: Pixels,
24 delay: Duration,
25}
26
27impl<'a, Message, Theme, Renderer> Sensor<'a, (), Message, Theme, Renderer>
28where
29 Renderer: core::Renderer,
30{
31 pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {
33 Self {
34 content: content.into(),
35 key: (),
36 on_show: None,
37 on_resize: None,
38 on_hide: None,
39 anticipate: Pixels::ZERO,
40 delay: Duration::ZERO,
41 }
42 }
43}
44
45impl<'a, Key, Message, Theme, Renderer> Sensor<'a, Key, Message, Theme, Renderer>
46where
47 Key: self::Key,
48 Renderer: core::Renderer,
49{
50 pub fn on_show(mut self, on_show: impl Fn(Size) -> Message + 'a) -> Self {
54 self.on_show = Some(Box::new(on_show));
55 self
56 }
57
58 pub fn on_resize(mut self, on_resize: impl Fn(Size) -> Message + 'a) -> Self {
62 self.on_resize = Some(Box::new(on_resize));
63 self
64 }
65
66 pub fn on_hide(mut self, on_hide: Message) -> Self {
68 self.on_hide = Some(on_hide);
69 self
70 }
71
72 pub fn key<K>(self, key: K) -> Sensor<'a, impl self::Key, Message, Theme, Renderer>
76 where
77 K: Clone + PartialEq + 'static,
78 {
79 Sensor {
80 content: self.content,
81 key: OwnedKey(key),
82 on_show: self.on_show,
83 on_resize: self.on_resize,
84 on_hide: self.on_hide,
85 anticipate: self.anticipate,
86 delay: self.delay,
87 }
88 }
89
90 pub fn key_ref<K>(self, key: &'a K) -> Sensor<'a, &'a K, Message, Theme, Renderer>
94 where
95 K: ToOwned + PartialEq<K::Owned> + ?Sized,
96 K::Owned: 'static,
97 {
98 Sensor {
99 content: self.content,
100 key,
101 on_show: self.on_show,
102 on_resize: self.on_resize,
103 on_hide: self.on_hide,
104 anticipate: self.anticipate,
105 delay: self.delay,
106 }
107 }
108
109 pub fn anticipate(mut self, distance: impl Into<Pixels>) -> Self {
115 self.anticipate = distance.into();
116 self
117 }
118
119 pub fn delay(mut self, delay: impl Into<Duration>) -> Self {
128 self.delay = delay.into();
129 self
130 }
131}
132
133#[derive(Debug, Clone)]
134struct State<Key> {
135 has_popped_in: bool,
136 should_notify_at: Option<(bool, Instant)>,
137 last_size: Option<Size>,
138 last_key: Key,
139}
140
141impl<Key, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
142 for Sensor<'_, Key, Message, Theme, Renderer>
143where
144 Key: self::Key,
145 Renderer: core::Renderer,
146{
147 fn tag(&self) -> tree::Tag {
148 tree::Tag::of::<State<Key::Owned>>()
149 }
150
151 fn state(&self) -> tree::State {
152 tree::State::new(State {
153 has_popped_in: false,
154 should_notify_at: None,
155 last_size: None,
156 last_key: self.key.to_owned(),
157 })
158 }
159
160 fn children(&self) -> Vec<Tree> {
161 vec![Tree::new(&self.content)]
162 }
163
164 fn diff(&self, tree: &mut Tree) {
165 tree.diff_children(&[&self.content]);
166 }
167
168 fn update(
169 &mut self,
170 tree: &mut Tree,
171 event: &Event,
172 layout: Layout<'_>,
173 cursor: mouse::Cursor,
174 renderer: &Renderer,
175 shell: &mut Shell<'_, Message>,
176 viewport: &Rectangle,
177 ) {
178 if let Event::Window(window::Event::RedrawRequested(now)) = &event {
179 let state = tree.state.downcast_mut::<State<Key::Owned>>();
180
181 if state.has_popped_in && !self.key.eq(&state.last_key) {
182 state.has_popped_in = false;
183 state.should_notify_at = None;
184 state.last_key = self.key.to_owned();
185 }
186
187 let bounds = layout.bounds();
188 let top_left_distance = viewport.distance(bounds.position());
189
190 let bottom_right_distance =
191 viewport.distance(bounds.position() + Vector::from(bounds.size()));
192
193 let distance = top_left_distance.min(bottom_right_distance);
194
195 if self.on_show.is_none() {
196 if let Some(on_resize) = &self.on_resize {
197 let size = bounds.size();
198
199 if Some(size) != state.last_size {
200 state.last_size = Some(size);
201 shell.publish(on_resize(size));
202 }
203 }
204 } else if state.has_popped_in {
205 if distance <= self.anticipate.0 {
206 if let Some(on_resize) = &self.on_resize {
207 let size = bounds.size();
208
209 if Some(size) != state.last_size {
210 state.last_size = Some(size);
211 shell.publish(on_resize(size));
212 }
213 }
214 } else if self.on_hide.is_some() {
215 state.has_popped_in = false;
216 state.should_notify_at = Some((false, *now + self.delay));
217 }
218 } else if distance <= self.anticipate.0 {
219 let size = bounds.size();
220
221 state.has_popped_in = true;
222 state.should_notify_at = Some((true, *now + self.delay));
223 state.last_size = Some(size);
224 }
225
226 match &state.should_notify_at {
227 Some((has_popped_in, at)) if at <= now => {
228 if *has_popped_in {
229 if let Some(on_show) = &self.on_show {
230 shell.publish(on_show(layout.bounds().size()));
231 }
232 } else if let Some(on_hide) = self.on_hide.take() {
233 shell.publish(on_hide);
234 }
235
236 state.should_notify_at = None;
237 }
238 Some((_, at)) => {
239 shell.request_redraw_at(*at);
240 }
241 None => {}
242 }
243 }
244
245 self.content.as_widget_mut().update(
246 &mut tree.children[0],
247 event,
248 layout,
249 cursor,
250 renderer,
251 shell,
252 viewport,
253 );
254 }
255
256 fn size(&self) -> Size<Length> {
257 self.content.as_widget().size()
258 }
259
260 fn size_hint(&self) -> Size<Length> {
261 self.content.as_widget().size_hint()
262 }
263
264 fn layout(
265 &mut self,
266 tree: &mut Tree,
267 renderer: &Renderer,
268 limits: &layout::Limits,
269 ) -> layout::Node {
270 self.content
271 .as_widget_mut()
272 .layout(&mut tree.children[0], renderer, limits)
273 }
274
275 fn draw(
276 &self,
277 tree: &Tree,
278 renderer: &mut Renderer,
279 theme: &Theme,
280 style: &renderer::Style,
281 layout: layout::Layout<'_>,
282 cursor: mouse::Cursor,
283 viewport: &Rectangle,
284 ) {
285 self.content.as_widget().draw(
286 &tree.children[0],
287 renderer,
288 theme,
289 style,
290 layout,
291 cursor,
292 viewport,
293 );
294 }
295
296 fn operate(
297 &mut self,
298 tree: &mut Tree,
299 layout: core::Layout<'_>,
300 renderer: &Renderer,
301 operation: &mut dyn widget::Operation,
302 ) {
303 self.content
304 .as_widget_mut()
305 .operate(&mut tree.children[0], layout, renderer, operation);
306 }
307
308 fn mouse_interaction(
309 &self,
310 tree: &Tree,
311 layout: core::Layout<'_>,
312 cursor: mouse::Cursor,
313 viewport: &Rectangle,
314 renderer: &Renderer,
315 ) -> mouse::Interaction {
316 self.content.as_widget().mouse_interaction(
317 &tree.children[0],
318 layout,
319 cursor,
320 viewport,
321 renderer,
322 )
323 }
324
325 fn overlay<'b>(
326 &'b mut self,
327 tree: &'b mut Tree,
328 layout: core::Layout<'b>,
329 renderer: &Renderer,
330 viewport: &Rectangle,
331 translation: core::Vector,
332 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
333 self.content.as_widget_mut().overlay(
334 &mut tree.children[0],
335 layout,
336 renderer,
337 viewport,
338 translation,
339 )
340 }
341}
342
343impl<'a, Key, Message, Theme, Renderer> From<Sensor<'a, Key, Message, Theme, Renderer>>
344 for Element<'a, Message, Theme, Renderer>
345where
346 Message: 'a,
347 Key: self::Key + 'a,
348 Renderer: core::Renderer + 'a,
349 Theme: 'a,
350{
351 fn from(pop: Sensor<'a, Key, Message, Theme, Renderer>) -> Self {
352 Element::new(pop)
353 }
354}
355
356pub trait Key {
360 type Owned: 'static;
362
363 fn to_owned(&self) -> Self::Owned;
365
366 fn eq(&self, other: &Self::Owned) -> bool;
368}
369
370impl<T> Key for &T
371where
372 T: ToOwned + PartialEq<T::Owned> + ?Sized,
373 T::Owned: 'static,
374{
375 type Owned = T::Owned;
376
377 fn to_owned(&self) -> <Self as Key>::Owned {
378 ToOwned::to_owned(*self)
379 }
380
381 fn eq(&self, other: &Self::Owned) -> bool {
382 *self == other
383 }
384}
385
386struct OwnedKey<T>(T);
387
388impl<T> Key for OwnedKey<T>
389where
390 T: PartialEq + Clone + 'static,
391{
392 type Owned = T;
393
394 fn to_owned(&self) -> Self::Owned {
395 self.0.clone()
396 }
397
398 fn eq(&self, other: &Self::Owned) -> bool {
399 &self.0 == other
400 }
401}
402
403impl<T> PartialEq<T> for OwnedKey<T>
404where
405 T: PartialEq,
406{
407 fn eq(&self, other: &T) -> bool {
408 &self.0 == other
409 }
410}
411
412impl Key for () {
413 type Owned = ();
414
415 fn to_owned(&self) -> Self::Owned {}
416
417 fn eq(&self, _other: &Self::Owned) -> bool {
418 true
419 }
420}