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