node.rs

  1use crate::{
  2    point, Action, AnyDrag, AnyElement, AnyView, AppContext, BorrowWindow, Bounds, ClickEvent,
  3    DispatchPhase, Element, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
  4    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, Render,
  5    ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, View, ViewContext, Visibility,
  6};
  7use collections::HashMap;
  8use refineable::Refineable;
  9use smallvec::SmallVec;
 10use std::{
 11    any::{Any, TypeId},
 12    marker::PhantomData,
 13    mem,
 14    sync::Arc,
 15};
 16
 17pub struct GroupStyle {
 18    pub group: SharedString,
 19    pub style: StyleRefinement,
 20}
 21
 22pub trait InteractiveComponent<V: 'static> {
 23    fn interactivity(&mut self) -> &mut Interactivity<V>;
 24
 25    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 26    where
 27        Self: Sized,
 28    {
 29        self.interactivity().hover_style = f(StyleRefinement::default());
 30        self
 31    }
 32
 33    fn group_hover(
 34        mut self,
 35        group_name: impl Into<SharedString>,
 36        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 37    ) -> Self
 38    where
 39        Self: Sized,
 40    {
 41        self.interactivity().group_hover_style = Some(GroupStyle {
 42            group: group_name.into(),
 43            style: f(StyleRefinement::default()),
 44        });
 45        self
 46    }
 47
 48    fn on_mouse_down(
 49        mut self,
 50        button: MouseButton,
 51        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
 52    ) -> Self
 53    where
 54        Self: Sized,
 55    {
 56        self.interactivity().mouse_down_listeners.push(Box::new(
 57            move |view, event, bounds, phase, cx| {
 58                if phase == DispatchPhase::Bubble
 59                    && event.button == button
 60                    && bounds.contains_point(&event.position)
 61                {
 62                    handler(view, event, cx)
 63                }
 64            },
 65        ));
 66        self
 67    }
 68
 69    fn on_mouse_up(
 70        mut self,
 71        button: MouseButton,
 72        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
 73    ) -> Self
 74    where
 75        Self: Sized,
 76    {
 77        self.interactivity().mouse_up_listeners.push(Box::new(
 78            move |view, event, bounds, phase, cx| {
 79                if phase == DispatchPhase::Bubble
 80                    && event.button == button
 81                    && bounds.contains_point(&event.position)
 82                {
 83                    handler(view, event, cx)
 84                }
 85            },
 86        ));
 87        self
 88    }
 89
 90    fn on_mouse_down_out(
 91        mut self,
 92        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
 93    ) -> Self
 94    where
 95        Self: Sized,
 96    {
 97        self.interactivity().mouse_down_listeners.push(Box::new(
 98            move |view, event, bounds, phase, cx| {
 99                if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
100                    handler(view, event, cx)
101                }
102            },
103        ));
104        self
105    }
106
107    fn on_mouse_up_out(
108        mut self,
109        button: MouseButton,
110        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
111    ) -> Self
112    where
113        Self: Sized,
114    {
115        self.interactivity().mouse_up_listeners.push(Box::new(
116            move |view, event, bounds, phase, cx| {
117                if phase == DispatchPhase::Capture
118                    && event.button == button
119                    && !bounds.contains_point(&event.position)
120                {
121                    handler(view, event, cx);
122                }
123            },
124        ));
125        self
126    }
127
128    fn on_mouse_move(
129        mut self,
130        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + 'static,
131    ) -> Self
132    where
133        Self: Sized,
134    {
135        self.interactivity().mouse_move_listeners.push(Box::new(
136            move |view, event, bounds, phase, cx| {
137                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
138                    handler(view, event, cx);
139                }
140            },
141        ));
142        self
143    }
144
145    fn on_scroll_wheel(
146        mut self,
147        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + 'static,
148    ) -> Self
149    where
150        Self: Sized,
151    {
152        self.interactivity().scroll_wheel_listeners.push(Box::new(
153            move |view, event, bounds, phase, cx| {
154                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
155                    handler(view, event, cx);
156                }
157            },
158        ));
159        self
160    }
161
162    /// Capture the given action, fires during the capture phase
163    fn capture_action<A: Action>(
164        mut self,
165        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
166    ) -> Self
167    where
168        Self: Sized,
169    {
170        self.interactivity().action_listeners.push((
171            TypeId::of::<A>(),
172            Box::new(move |view, action, phase, cx| {
173                let action = action.downcast_ref().unwrap();
174                if phase == DispatchPhase::Capture {
175                    listener(view, action, cx)
176                }
177            }),
178        ));
179        self
180    }
181
182    /// Add a listener for the given action, fires during the bubble event phase
183    fn on_action<A: Action>(
184        mut self,
185        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
186    ) -> Self
187    where
188        Self: Sized,
189    {
190        self.interactivity().action_listeners.push((
191            TypeId::of::<A>(),
192            Box::new(move |view, action, phase, cx| {
193                let action = action.downcast_ref().unwrap();
194                if phase == DispatchPhase::Bubble {
195                    listener(view, action, cx)
196                }
197            }),
198        ));
199        self
200    }
201
202    fn on_key_down(
203        mut self,
204        listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
205    ) -> Self
206    where
207        Self: Sized,
208    {
209        self.interactivity()
210            .key_down_listeners
211            .push(Box::new(move |view, event, phase, cx| {
212                listener(view, event, phase, cx)
213            }));
214        self
215    }
216
217    fn on_key_up(
218        mut self,
219        listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
220    ) -> Self
221    where
222        Self: Sized,
223    {
224        self.interactivity()
225            .key_up_listeners
226            .push(Box::new(move |view, event, phase, cx| {
227                listener(view, event, phase, cx)
228            }));
229        self
230    }
231
232    fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
233    where
234        Self: Sized,
235    {
236        self.interactivity()
237            .drag_over_styles
238            .push((TypeId::of::<S>(), f(StyleRefinement::default())));
239        self
240    }
241
242    fn group_drag_over<S: 'static>(
243        mut self,
244        group_name: impl Into<SharedString>,
245        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
246    ) -> Self
247    where
248        Self: Sized,
249    {
250        self.interactivity().group_drag_over_styles.push((
251            TypeId::of::<S>(),
252            GroupStyle {
253                group: group_name.into(),
254                style: f(StyleRefinement::default()),
255            },
256        ));
257        self
258    }
259
260    fn on_drop<W: 'static>(
261        mut self,
262        listener: impl Fn(&mut V, View<W>, &mut ViewContext<V>) + 'static,
263    ) -> Self
264    where
265        Self: Sized,
266    {
267        self.interactivity().drop_listeners.push((
268            TypeId::of::<W>(),
269            Box::new(move |view, dragged_view, cx| {
270                listener(view, dragged_view.downcast().unwrap(), cx);
271            }),
272        ));
273        self
274    }
275}
276
277pub trait StatefulInteractiveComponent<V: 'static> {
278    fn interactivity(&mut self) -> &mut StatefulInteractivity<V>;
279
280    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
281    where
282        Self: Sized,
283    {
284        self.interactivity().active_style = f(StyleRefinement::default());
285        self
286    }
287
288    fn group_active(
289        mut self,
290        group_name: impl Into<SharedString>,
291        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
292    ) -> Self
293    where
294        Self: Sized,
295    {
296        self.interactivity().group_active_style = Some(GroupStyle {
297            group: group_name.into(),
298            style: f(StyleRefinement::default()),
299        });
300        self
301    }
302
303    fn on_click(
304        mut self,
305        listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
306    ) -> Self
307    where
308        Self: Sized,
309    {
310        self.interactivity()
311            .click_listeners
312            .push(Box::new(move |view, event, cx| listener(view, event, cx)));
313        self
314    }
315
316    fn on_drag<W>(
317        mut self,
318        listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
319    ) -> Self
320    where
321        Self: Sized,
322        W: 'static + Render,
323    {
324        debug_assert!(
325            self.interactivity().drag_listener.is_none(),
326            "calling on_drag more than once on the same element is not supported"
327        );
328        self.interactivity().drag_listener =
329            Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
330                view: listener(view_state, cx).into(),
331                cursor_offset,
332            }));
333        self
334    }
335
336    fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
337    where
338        Self: Sized,
339    {
340        debug_assert!(
341            self.interactivity().hover_listener.is_none(),
342            "calling on_hover more than once on the same element is not supported"
343        );
344        self.interactivity().hover_listener = Some(Box::new(listener));
345        self
346    }
347
348    fn tooltip<W>(
349        mut self,
350        build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
351    ) -> Self
352    where
353        Self: Sized,
354        W: 'static + Render,
355    {
356        debug_assert!(
357            self.interactivity().tooltip_builder.is_none(),
358            "calling tooltip more than once on the same element is not supported"
359        );
360        self.interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
361            build_tooltip(view_state, cx).into()
362        }));
363
364        self
365    }
366}
367
368pub trait FocusableComponent<V> {
369    fn focusability(&mut self) -> &mut Focusability<V>;
370
371    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
372    where
373        Self: Sized,
374    {
375        self.focusability().focus_style = f(StyleRefinement::default());
376        self
377    }
378
379    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
380    where
381        Self: Sized,
382    {
383        self.focusability().focus_in_style = f(StyleRefinement::default());
384        self
385    }
386
387    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
388    where
389        Self: Sized,
390    {
391        // self.focusability(). (f(StyleRefinement::default()));
392        self
393    }
394
395    fn on_focus(
396        mut self,
397        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
398    ) -> Self
399    where
400        Self: Sized,
401    {
402        self.focusability()
403            .focus_listeners
404            .push(Box::new(move |view, focus_handle, event, cx| {
405                if event.focused.as_ref() == Some(focus_handle) {
406                    listener(view, event, cx)
407                }
408            }));
409        self
410    }
411
412    fn on_blur(
413        mut self,
414        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
415    ) -> Self
416    where
417        Self: Sized,
418    {
419        self.focusability()
420            .focus_listeners
421            .push(Box::new(move |view, focus_handle, event, cx| {
422                if event.blurred.as_ref() == Some(focus_handle) {
423                    listener(view, event, cx)
424                }
425            }));
426        self
427    }
428
429    fn on_focus_in(
430        mut self,
431        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
432    ) -> Self
433    where
434        Self: Sized,
435    {
436        self.focusability()
437            .focus_listeners
438            .push(Box::new(move |view, focus_handle, event, cx| {
439                let descendant_blurred = event
440                    .blurred
441                    .as_ref()
442                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
443                let descendant_focused = event
444                    .focused
445                    .as_ref()
446                    .map_or(false, |focused| focus_handle.contains(focused, cx));
447
448                if !descendant_blurred && descendant_focused {
449                    listener(view, event, cx)
450                }
451            }));
452        self
453    }
454
455    fn on_focus_out(
456        mut self,
457        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
458    ) -> Self
459    where
460        Self: Sized,
461    {
462        self.focusability()
463            .focus_listeners
464            .push(Box::new(move |view, focus_handle, event, cx| {
465                let descendant_blurred = event
466                    .blurred
467                    .as_ref()
468                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
469                let descendant_focused = event
470                    .focused
471                    .as_ref()
472                    .map_or(false, |focused| focus_handle.contains(focused, cx));
473                if descendant_blurred && !descendant_focused {
474                    listener(view, event, cx)
475                }
476            }));
477        self
478    }
479}
480
481pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
482
483pub type FocusListener<V> =
484    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
485
486pub type MouseDownListener<V> = Box<
487    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
488>;
489pub type MouseUpListener<V> = Box<
490    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
491>;
492
493pub type MouseMoveListener<V> = Box<
494    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
495>;
496
497pub type ScrollWheelListener<V> = Box<
498    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
499        + 'static,
500>;
501
502pub type ClickListener<V> = Box<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static>;
503
504pub type DragListener<V> =
505    Box<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + 'static>;
506
507type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
508
509pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
510
511pub type TooltipBuilder<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
512
513pub type KeyDownListener<V> =
514    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
515
516pub type KeyUpListener<V> =
517    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
518
519pub type ActionListener<V> =
520    Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
521
522pub struct FocusEvent {
523    pub blurred: Option<FocusHandle>,
524    pub focused: Option<FocusHandle>,
525}
526
527pub struct Node<V> {
528    style: StyleRefinement,
529    key_context: KeyContext,
530    interactivity: Interactivity<V>,
531    children: Vec<AnyElement<V>>,
532}
533
534impl<V> Node<V> {
535    fn compute_style(&self) -> Style {
536        let mut style = Style::default();
537        style.refine(&self.style);
538        style
539    }
540}
541
542impl<V> Styled for Node<V> {
543    fn style(&mut self) -> &mut StyleRefinement {
544        &mut self.style
545    }
546}
547
548impl<V: 'static> InteractiveComponent<V> for Node<V> {
549    fn interactivity(&mut self) -> &mut Interactivity<V> {
550        &mut self.interactivity
551    }
552}
553
554pub struct NodeState {
555    child_layout_ids: SmallVec<[LayoutId; 4]>,
556}
557
558impl<V: 'static> Element<V> for Node<V> {
559    type ElementState = NodeState;
560
561    fn id(&self) -> Option<crate::ElementId> {
562        None
563    }
564
565    fn initialize(
566        &mut self,
567        view_state: &mut V,
568        _: Option<Self::ElementState>,
569        cx: &mut ViewContext<V>,
570    ) -> Self::ElementState {
571        for child in &mut self.children {
572            child.initialize(view_state, cx);
573        }
574        NodeState {
575            child_layout_ids: SmallVec::new(),
576        }
577    }
578
579    fn layout(
580        &mut self,
581        view_state: &mut V,
582        element_state: &mut Self::ElementState,
583        cx: &mut ViewContext<V>,
584    ) -> crate::LayoutId {
585        let style = self.compute_style();
586        style.with_text_style(cx, |cx| {
587            element_state.child_layout_ids = self
588                .children
589                .iter_mut()
590                .map(|child| child.layout(view_state, cx))
591                .collect::<SmallVec<_>>();
592            cx.request_layout(&style, element_state.child_layout_ids.iter().copied())
593        })
594    }
595
596    fn prepaint(
597        &mut self,
598        bounds: Bounds<Pixels>,
599        view_state: &mut V,
600        _: &mut Self::ElementState,
601        cx: &mut ViewContext<V>,
602    ) {
603        for child in &mut self.children {
604            child.prepaint(view_state, cx);
605        }
606        self.interactivity
607            .refine_style(&mut self.style, bounds, view_state, cx);
608    }
609
610    fn paint(
611        &mut self,
612        bounds: Bounds<Pixels>,
613        view_state: &mut V,
614        element_state: &mut Self::ElementState,
615        cx: &mut ViewContext<V>,
616    ) {
617        let style = self.compute_style();
618        if style.visibility == Visibility::Hidden {
619            return;
620        }
621
622        if let Some(mouse_cursor) = style.mouse_cursor {
623            let hovered = bounds.contains_point(&cx.mouse_position());
624            if hovered {
625                cx.set_cursor_style(mouse_cursor);
626            }
627        }
628
629        if let Some(group) = self.interactivity.group.clone() {
630            GroupBounds::push(group, bounds, cx);
631        }
632
633        let z_index = style.z_index.unwrap_or(0);
634
635        let mut child_min = point(Pixels::MAX, Pixels::MAX);
636        let mut child_max = Point::default();
637
638        let content_size = if element_state.child_layout_ids.is_empty() {
639            bounds.size
640        } else {
641            for child_layout_id in &element_state.child_layout_ids {
642                let child_bounds = cx.layout_bounds(*child_layout_id);
643                child_min = child_min.min(&child_bounds.origin);
644                child_max = child_max.max(&child_bounds.lower_right());
645            }
646            (child_max - child_min).into()
647        };
648
649        cx.with_z_index(z_index, |cx| {
650            cx.with_z_index(0, |cx| {
651                style.paint(bounds, cx);
652                self.interactivity.paint(bounds, cx);
653            });
654            cx.with_z_index(1, |cx| {
655                style.with_text_style(cx, |cx| {
656                    style.apply_overflow(bounds, cx, |cx| {
657                        let scroll_offset = self.interactivity.scroll_offset;
658                        cx.with_element_offset2(scroll_offset, |cx| {
659                            for child in &mut self.children {
660                                child.paint(view_state, cx);
661                            }
662                        });
663                    })
664                })
665            });
666        });
667
668        if let Some(group) = self.interactivity.group.as_ref() {
669            GroupBounds::pop(group, cx);
670        }
671    }
672}
673
674pub struct Interactivity<V> {
675    pub hover_style: StyleRefinement,
676    pub group_hover_style: Option<GroupStyle>,
677    pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
678    pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
679    group: Option<SharedString>,
680    pub dispatch_context: KeyContext,
681    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
682    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
683    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
684    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
685    pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
686    pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
687    pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
688    drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
689    scroll_offset: Point<Pixels>,
690}
691
692impl<V: 'static> Interactivity<V> {
693    fn refine_style(
694        &self,
695        style: &mut StyleRefinement,
696        bounds: Bounds<Pixels>,
697        cx: &mut ViewContext<V>,
698    ) {
699        let mouse_position = cx.mouse_position();
700        if let Some(group_hover) = self.group_hover_style.as_ref() {
701            if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
702                if group_bounds.contains_point(&mouse_position) {
703                    style.refine(&group_hover.style);
704                }
705            }
706        }
707        if bounds.contains_point(&mouse_position) {
708            style.refine(&self.hover_style);
709        }
710
711        if let Some(drag) = cx.active_drag.take() {
712            for (state_type, group_drag_style) in &self.group_drag_over_styles {
713                if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
714                    if *state_type == drag.view.entity_type()
715                        && group_bounds.contains_point(&mouse_position)
716                    {
717                        style.refine(&group_drag_style.style);
718                    }
719                }
720            }
721
722            for (state_type, drag_over_style) in &self.drag_over_styles {
723                if *state_type == drag.view.entity_type() && bounds.contains_point(&mouse_position)
724                {
725                    style.refine(drag_over_style);
726                }
727            }
728
729            cx.active_drag = Some(drag);
730        }
731    }
732
733    fn paint(&mut self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
734        for listener in self.mouse_down_listeners.drain(..) {
735            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
736                listener(state, event, &bounds, phase, cx);
737            })
738        }
739
740        for listener in self.mouse_up_listeners.drain(..) {
741            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
742                listener(state, event, &bounds, phase, cx);
743            })
744        }
745
746        for listener in self.mouse_move_listeners.drain(..) {
747            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
748                listener(state, event, &bounds, phase, cx);
749            })
750        }
751
752        for listener in self.scroll_wheel_listeners.drain(..) {
753            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
754                listener(state, event, &bounds, phase, cx);
755            })
756        }
757
758        let hover_group_bounds = self
759            .group_hover_style
760            .as_ref()
761            .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
762
763        if let Some(group_bounds) = hover_group_bounds {
764            let hovered = group_bounds.contains_point(&cx.mouse_position());
765            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
766                if phase == DispatchPhase::Capture {
767                    if group_bounds.contains_point(&event.position) != hovered {
768                        cx.notify();
769                    }
770                }
771            });
772        }
773
774        if self.hover_style.is_some()
775            || (cx.active_drag.is_some() && !self.drag_over_styles.is_empty())
776        {
777            let hovered = bounds.contains_point(&cx.mouse_position());
778            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
779                if phase == DispatchPhase::Capture {
780                    if bounds.contains_point(&event.position) != hovered {
781                        cx.notify();
782                    }
783                }
784            });
785        }
786
787        if cx.active_drag.is_some() {
788            let drop_listeners = mem::take(&mut self.drop_listeners);
789            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
790                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
791                    if let Some(drag_state_type) =
792                        cx.active_drag.as_ref().map(|drag| drag.view.entity_type())
793                    {
794                        for (drop_state_type, listener) in &drop_listeners {
795                            if *drop_state_type == drag_state_type {
796                                let drag = cx
797                                    .active_drag
798                                    .take()
799                                    .expect("checked for type drag state type above");
800                                listener(view, drag.view.clone(), cx);
801                                cx.notify();
802                                cx.stop_propagation();
803                            }
804                        }
805                    }
806                }
807            });
808        }
809    }
810}
811
812#[derive(Default)]
813pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
814
815impl GroupBounds {
816    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
817        cx.default_global::<Self>()
818            .0
819            .get(name)
820            .and_then(|bounds_stack| bounds_stack.last())
821            .cloned()
822    }
823
824    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
825        cx.default_global::<Self>()
826            .0
827            .entry(name)
828            .or_default()
829            .push(bounds);
830    }
831
832    pub fn pop(name: &SharedString, cx: &mut AppContext) {
833        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
834    }
835}
836
837pub struct Focusable<V, E> {
838    focusability: Focusability<V>,
839    view_type: PhantomData<V>,
840    element: E,
841}
842
843pub struct Focusability<V> {
844    focus_handle: Option<FocusHandle>,
845    focus_listeners: FocusListeners<V>,
846    focus_style: StyleRefinement,
847    focus_in_style: StyleRefinement,
848    in_focus_style: StyleRefinement,
849}
850
851impl<V, E> FocusableComponent<V> for Focusable<V, E> {
852    fn focusability(&mut self) -> &mut Focusability<V> {
853        &mut self.focusability
854    }
855}
856
857impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Focusable<V, E> {
858    fn interactivity(&mut self) -> &mut Interactivity<V> {
859        self.element.interactivity()
860    }
861}
862
863impl<V: 'static, E: StatefulInteractiveComponent<V>> StatefulInteractiveComponent<V>
864    for Focusable<V, E>
865{
866    fn interactivity(&mut self) -> &mut StatefulInteractivity<V> {
867        self.element.interactivity()
868    }
869}
870
871pub struct Stateful<V, E> {
872    id: SharedString,
873    interactivity: StatefulInteractivity<V>,
874    view_type: PhantomData<V>,
875    element: E,
876}
877
878pub struct StatefulInteractivity<V> {
879    click_listeners: SmallVec<[ClickListener<V>; 2]>,
880    active_style: StyleRefinement,
881    group_active_style: Option<GroupStyle>,
882    drag_listener: Option<DragListener<V>>,
883    hover_listener: Option<HoverListener<V>>,
884    tooltip_builder: Option<TooltipBuilder<V>>,
885}
886
887impl<V: 'static, E> StatefulInteractiveComponent<V> for Stateful<V, E> {
888    fn interactivity(&mut self) -> &mut StatefulInteractivity<V> {
889        &mut self.interactivity
890    }
891}
892
893impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Stateful<V, E> {
894    fn interactivity(&mut self) -> &mut Interactivity<V> {
895        self.element.interactivity()
896    }
897}
898
899impl<V, E: FocusableComponent<V>> FocusableComponent<V> for Stateful<V, E> {
900    fn focusability(&mut self) -> &mut Focusability<V> {
901        self.element.focusability()
902    }
903}