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