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