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>: InteractiveComponent<V> {
278    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
279    where
280        Self: Sized,
281    {
282        self.interactivity().active_style = f(StyleRefinement::default());
283        self
284    }
285
286    fn group_active(
287        mut self,
288        group_name: impl Into<SharedString>,
289        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
290    ) -> Self
291    where
292        Self: Sized,
293    {
294        self.interactivity().group_active_style = Some(GroupStyle {
295            group: group_name.into(),
296            style: f(StyleRefinement::default()),
297        });
298        self
299    }
300
301    fn on_click(
302        mut self,
303        listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
304    ) -> Self
305    where
306        Self: Sized,
307    {
308        self.interactivity()
309            .click_listeners
310            .push(Box::new(move |view, event, cx| listener(view, event, cx)));
311        self
312    }
313
314    fn on_drag<W>(
315        mut self,
316        listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
317    ) -> Self
318    where
319        Self: Sized,
320        W: 'static + Render,
321    {
322        debug_assert!(
323            self.interactivity().drag_listener.is_none(),
324            "calling on_drag more than once on the same element is not supported"
325        );
326        self.interactivity().drag_listener =
327            Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
328                view: listener(view_state, cx).into(),
329                cursor_offset,
330            }));
331        self
332    }
333
334    fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
335    where
336        Self: Sized,
337    {
338        debug_assert!(
339            self.interactivity().hover_listener.is_none(),
340            "calling on_hover more than once on the same element is not supported"
341        );
342        self.interactivity().hover_listener = Some(Box::new(listener));
343        self
344    }
345
346    fn tooltip<W>(
347        mut self,
348        build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
349    ) -> Self
350    where
351        Self: Sized,
352        W: 'static + Render,
353    {
354        debug_assert!(
355            self.interactivity().tooltip_builder.is_none(),
356            "calling tooltip more than once on the same element is not supported"
357        );
358        self.interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
359            build_tooltip(view_state, cx).into()
360        }));
361
362        self
363    }
364}
365
366pub trait FocusableComponent<V> {
367    fn focusability(&mut self) -> &mut Focusability<V>;
368
369    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
370    where
371        Self: Sized,
372    {
373        self.focusability().focus_style = f(StyleRefinement::default());
374        self
375    }
376
377    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
378    where
379        Self: Sized,
380    {
381        self.focusability().focus_in_style = f(StyleRefinement::default());
382        self
383    }
384
385    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
386    where
387        Self: Sized,
388    {
389        self.focusability().in_focus_style = f(StyleRefinement::default());
390        self
391    }
392
393    fn on_focus(
394        mut self,
395        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
396    ) -> Self
397    where
398        Self: Sized,
399    {
400        self.focusability()
401            .focus_listeners
402            .push(Box::new(move |view, focus_handle, event, cx| {
403                if event.focused.as_ref() == Some(focus_handle) {
404                    listener(view, event, cx)
405                }
406            }));
407        self
408    }
409
410    fn on_blur(
411        mut self,
412        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
413    ) -> Self
414    where
415        Self: Sized,
416    {
417        self.focusability()
418            .focus_listeners
419            .push(Box::new(move |view, focus_handle, event, cx| {
420                if event.blurred.as_ref() == Some(focus_handle) {
421                    listener(view, event, cx)
422                }
423            }));
424        self
425    }
426
427    fn on_focus_in(
428        mut self,
429        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
430    ) -> Self
431    where
432        Self: Sized,
433    {
434        self.focusability()
435            .focus_listeners
436            .push(Box::new(move |view, focus_handle, event, cx| {
437                let descendant_blurred = event
438                    .blurred
439                    .as_ref()
440                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
441                let descendant_focused = event
442                    .focused
443                    .as_ref()
444                    .map_or(false, |focused| focus_handle.contains(focused, cx));
445
446                if !descendant_blurred && descendant_focused {
447                    listener(view, event, cx)
448                }
449            }));
450        self
451    }
452
453    fn on_focus_out(
454        mut self,
455        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
456    ) -> Self
457    where
458        Self: Sized,
459    {
460        self.focusability()
461            .focus_listeners
462            .push(Box::new(move |view, focus_handle, event, cx| {
463                let descendant_blurred = event
464                    .blurred
465                    .as_ref()
466                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
467                let descendant_focused = event
468                    .focused
469                    .as_ref()
470                    .map_or(false, |focused| focus_handle.contains(focused, cx));
471                if descendant_blurred && !descendant_focused {
472                    listener(view, event, cx)
473                }
474            }));
475        self
476    }
477}
478
479pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
480
481pub type FocusListener<V> =
482    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
483
484pub type MouseDownListener<V> = Box<
485    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
486>;
487pub type MouseUpListener<V> = Box<
488    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
489>;
490
491pub type MouseMoveListener<V> = Box<
492    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
493>;
494
495pub type ScrollWheelListener<V> = Box<
496    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
497        + 'static,
498>;
499
500pub type ClickListener<V> = Box<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static>;
501
502pub type DragListener<V> =
503    Box<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + 'static>;
504
505type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
506
507pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
508
509pub type TooltipBuilder<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
510
511pub type KeyDownListener<V> =
512    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
513
514pub type KeyUpListener<V> =
515    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
516
517pub type ActionListener<V> =
518    Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
519
520pub struct FocusEvent {
521    pub blurred: Option<FocusHandle>,
522    pub focused: Option<FocusHandle>,
523}
524
525pub struct Node<V> {
526    interactivity: Interactivity<V>,
527    children: Vec<AnyElement<V>>,
528}
529
530impl<V> Styled for Node<V> {
531    fn style(&mut self) -> &mut StyleRefinement {
532        &mut self.interactivity.base_style
533    }
534}
535
536impl<V: 'static> InteractiveComponent<V> for Node<V> {
537    fn interactivity(&mut self) -> &mut Interactivity<V> {
538        &mut self.interactivity
539    }
540}
541
542pub struct NodeState {
543    child_layout_ids: SmallVec<[LayoutId; 4]>,
544}
545
546impl<V: 'static> Element<V> for Node<V> {
547    type ElementState = NodeState;
548
549    fn id(&self) -> Option<crate::ElementId> {
550        None
551    }
552
553    fn initialize(
554        &mut self,
555        view_state: &mut V,
556        _: Option<Self::ElementState>,
557        cx: &mut ViewContext<V>,
558    ) -> Self::ElementState {
559        for child in &mut self.children {
560            child.initialize(view_state, cx);
561        }
562        NodeState {
563            child_layout_ids: SmallVec::new(),
564        }
565    }
566
567    fn layout(
568        &mut self,
569        view_state: &mut V,
570        element_state: &mut Self::ElementState,
571        cx: &mut ViewContext<V>,
572    ) -> crate::LayoutId {
573        let style = self.interactivity().compute_style(None, cx);
574        style.with_text_style(cx, |cx| {
575            element_state.child_layout_ids = self
576                .children
577                .iter_mut()
578                .map(|child| child.layout(view_state, cx))
579                .collect::<SmallVec<_>>();
580            cx.request_layout(&style, element_state.child_layout_ids.iter().copied())
581        })
582    }
583
584    fn paint(
585        &mut self,
586        bounds: Bounds<Pixels>,
587        view_state: &mut V,
588        element_state: &mut Self::ElementState,
589        cx: &mut ViewContext<V>,
590    ) {
591        let style = self.interactivity.compute_style(Some(bounds), cx);
592        if style.visibility == Visibility::Hidden {
593            return;
594        }
595
596        if let Some(mouse_cursor) = style.mouse_cursor {
597            let hovered = bounds.contains_point(&cx.mouse_position());
598            if hovered {
599                cx.set_cursor_style(mouse_cursor);
600            }
601        }
602
603        if let Some(group) = self.interactivity.group.clone() {
604            GroupBounds::push(group, bounds, cx);
605        }
606
607        let z_index = style.z_index.unwrap_or(0);
608
609        let mut child_min = point(Pixels::MAX, Pixels::MAX);
610        let mut child_max = Point::default();
611
612        let content_size = if element_state.child_layout_ids.is_empty() {
613            bounds.size
614        } else {
615            for child_layout_id in &element_state.child_layout_ids {
616                let child_bounds = cx.layout_bounds(*child_layout_id);
617                child_min = child_min.min(&child_bounds.origin);
618                child_max = child_max.max(&child_bounds.lower_right());
619            }
620            (child_max - child_min).into()
621        };
622
623        let mut interactivity = mem::take(&mut self.interactivity);
624        interactivity.paint(bounds, cx, |cx| {
625            cx.with_z_index(z_index, |cx| {
626                cx.with_z_index(0, |cx| {
627                    style.paint(bounds, cx);
628                });
629                cx.with_z_index(1, |cx| {
630                    style.with_text_style(cx, |cx| {
631                        style.apply_overflow(bounds, cx, |cx| {
632                            let scroll_offset = self.interactivity.scroll_offset;
633                            cx.with_element_offset2(scroll_offset, |cx| {
634                                for child in &mut self.children {
635                                    child.paint(view_state, cx);
636                                }
637                            });
638                        })
639                    })
640                });
641            });
642        });
643        self.interactivity = interactivity;
644
645        if let Some(group) = self.interactivity.group.as_ref() {
646            GroupBounds::pop(group, cx);
647        }
648    }
649}
650
651pub enum FocusState {
652    /// The current element is not focused, and does not contain or descend from the focused element.
653    None,
654    /// The current element is focused.
655    Focus,
656    /// The current element contains the focused element
657    FocusIn,
658    /// The current element descends from the focused element
659    InFocus,
660}
661
662pub struct Interactivity<V> {
663    pub active: bool,
664    pub group_active: bool,
665    pub hovered: bool,
666    pub group_hovered: bool,
667    pub focus: FocusState,
668    pub key_context: KeyContext,
669    pub focus_handle: Option<FocusHandle>,
670    pub scroll_offset: Point<Pixels>,
671    pub base_style: StyleRefinement,
672    pub focus_style: StyleRefinement,
673    pub focus_in_style: StyleRefinement,
674    pub in_focus_style: StyleRefinement,
675    pub hover_style: StyleRefinement,
676    pub group_hover_style: Option<GroupStyle>,
677    pub active_style: StyleRefinement,
678    pub group_active_style: Option<GroupStyle>,
679    pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
680    pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
681    pub group: Option<SharedString>,
682    pub dispatch_context: KeyContext,
683    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
684    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
685    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
686    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
687    pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
688    pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
689    pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
690    pub drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
691    pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
692    pub drag_listener: Option<DragListener<V>>,
693    pub hover_listener: Option<HoverListener<V>>,
694    pub tooltip_builder: Option<TooltipBuilder<V>>,
695}
696
697impl<V: 'static> Interactivity<V> {
698    fn compute_style(&self, bounds: Option<Bounds<Pixels>>, cx: &mut ViewContext<V>) -> Style {
699        let mut style = Style::default();
700        style.refine(&self.base_style);
701
702        match self.focus {
703            FocusState::None => {}
704            FocusState::Focus => {
705                style.refine(&self.focus_style);
706                style.refine(&self.focus_in_style);
707                style.refine(&self.in_focus_style);
708            }
709            FocusState::FocusIn => {
710                style.refine(&self.focus_in_style);
711            }
712            FocusState::InFocus => {
713                style.refine(&self.in_focus_style);
714            }
715        }
716
717        if let Some(bounds) = bounds {
718            let mouse_position = cx.mouse_position();
719            if let Some(group_hover) = self.group_hover_style.as_ref() {
720                if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
721                    if group_bounds.contains_point(&mouse_position) {
722                        style.refine(&group_hover.style);
723                    }
724                }
725            }
726            if bounds.contains_point(&mouse_position) {
727                style.refine(&self.hover_style);
728            }
729
730            if let Some(drag) = cx.active_drag.take() {
731                for (state_type, group_drag_style) in &self.group_drag_over_styles {
732                    if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
733                        if *state_type == drag.view.entity_type()
734                            && group_bounds.contains_point(&mouse_position)
735                        {
736                            style.refine(&group_drag_style.style);
737                        }
738                    }
739                }
740
741                for (state_type, drag_over_style) in &self.drag_over_styles {
742                    if *state_type == drag.view.entity_type()
743                        && bounds.contains_point(&mouse_position)
744                    {
745                        style.refine(drag_over_style);
746                    }
747                }
748
749                cx.active_drag = Some(drag);
750            }
751        }
752
753        if self.group_active {
754            if let Some(group) = self.group_active_style.as_ref() {
755                style.refine(&group.style)
756            }
757        }
758
759        if self.active {
760            style.refine(&self.active_style)
761        }
762
763        style
764    }
765
766    fn paint(
767        &mut self,
768        bounds: Bounds<Pixels>,
769        cx: &mut ViewContext<V>,
770        f: impl FnOnce(&mut ViewContext<V>),
771    ) {
772        for listener in self.mouse_down_listeners.drain(..) {
773            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
774                listener(state, event, &bounds, phase, cx);
775            })
776        }
777
778        for listener in self.mouse_up_listeners.drain(..) {
779            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
780                listener(state, event, &bounds, phase, cx);
781            })
782        }
783
784        for listener in self.mouse_move_listeners.drain(..) {
785            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
786                listener(state, event, &bounds, phase, cx);
787            })
788        }
789
790        for listener in self.scroll_wheel_listeners.drain(..) {
791            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
792                listener(state, event, &bounds, phase, cx);
793            })
794        }
795
796        let hover_group_bounds = self
797            .group_hover_style
798            .as_ref()
799            .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
800
801        if let Some(group_bounds) = hover_group_bounds {
802            let hovered = group_bounds.contains_point(&cx.mouse_position());
803            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
804                if phase == DispatchPhase::Capture {
805                    if group_bounds.contains_point(&event.position) != hovered {
806                        cx.notify();
807                    }
808                }
809            });
810        }
811
812        if self.hover_style.is_some()
813            || (cx.active_drag.is_some() && !self.drag_over_styles.is_empty())
814        {
815            let hovered = bounds.contains_point(&cx.mouse_position());
816            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
817                if phase == DispatchPhase::Capture {
818                    if bounds.contains_point(&event.position) != hovered {
819                        cx.notify();
820                    }
821                }
822            });
823        }
824
825        if cx.active_drag.is_some() {
826            let drop_listeners = mem::take(&mut self.drop_listeners);
827            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
828                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
829                    if let Some(drag_state_type) =
830                        cx.active_drag.as_ref().map(|drag| drag.view.entity_type())
831                    {
832                        for (drop_state_type, listener) in &drop_listeners {
833                            if *drop_state_type == drag_state_type {
834                                let drag = cx
835                                    .active_drag
836                                    .take()
837                                    .expect("checked for type drag state type above");
838                                listener(view, drag.view.clone(), cx);
839                                cx.notify();
840                                cx.stop_propagation();
841                            }
842                        }
843                    }
844                }
845            });
846        }
847
848        cx.with_key_dispatch(
849            self.key_context.clone(),
850            self.focus_handle.clone(),
851            |_, cx| f(cx),
852        );
853    }
854}
855
856impl<V: 'static> Default for Interactivity<V> {
857    fn default() -> Self {
858        Self {
859            active: false,
860            group_active: false,
861            hovered: false,
862            group_hovered: false,
863            focus: FocusState::None,
864            key_context: KeyContext::default(),
865            focus_handle: None,
866            scroll_offset: Point::default(),
867            base_style: StyleRefinement::default(),
868            focus_style: StyleRefinement::default(),
869            focus_in_style: StyleRefinement::default(),
870            in_focus_style: StyleRefinement::default(),
871            hover_style: StyleRefinement::default(),
872            group_hover_style: None,
873            active_style: StyleRefinement::default(),
874            group_active_style: None,
875            drag_over_styles: SmallVec::new(),
876            group_drag_over_styles: SmallVec::new(),
877            group: None,
878            dispatch_context: KeyContext::default(),
879            mouse_down_listeners: SmallVec::new(),
880            mouse_up_listeners: SmallVec::new(),
881            mouse_move_listeners: SmallVec::new(),
882            scroll_wheel_listeners: SmallVec::new(),
883            key_down_listeners: SmallVec::new(),
884            key_up_listeners: SmallVec::new(),
885            action_listeners: SmallVec::new(),
886            drop_listeners: SmallVec::new(),
887            click_listeners: SmallVec::new(),
888            drag_listener: None,
889            hover_listener: None,
890            tooltip_builder: None,
891        }
892    }
893}
894
895#[derive(Default)]
896pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
897
898impl GroupBounds {
899    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
900        cx.default_global::<Self>()
901            .0
902            .get(name)
903            .and_then(|bounds_stack| bounds_stack.last())
904            .cloned()
905    }
906
907    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
908        cx.default_global::<Self>()
909            .0
910            .entry(name)
911            .or_default()
912            .push(bounds);
913    }
914
915    pub fn pop(name: &SharedString, cx: &mut AppContext) {
916        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
917    }
918}
919
920pub struct Focusable<V, E> {
921    focusability: Focusability<V>,
922    view_type: PhantomData<V>,
923    element: E,
924}
925
926pub struct Focusability<V> {
927    focus_handle: Option<FocusHandle>,
928    focus_listeners: FocusListeners<V>,
929    focus_style: StyleRefinement,
930    focus_in_style: StyleRefinement,
931    in_focus_style: StyleRefinement,
932}
933
934impl<V, E> FocusableComponent<V> for Focusable<V, E> {
935    fn focusability(&mut self) -> &mut Focusability<V> {
936        &mut self.focusability
937    }
938}
939
940impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Focusable<V, E> {
941    fn interactivity(&mut self) -> &mut Interactivity<V> {
942        self.element.interactivity()
943    }
944}
945
946impl<V: 'static, E: StatefulInteractiveComponent<V>> StatefulInteractiveComponent<V>
947    for Focusable<V, E>
948{
949}
950
951pub struct Stateful<V, E> {
952    id: SharedString,
953    view_type: PhantomData<V>,
954    element: E,
955}
956
957impl<V: 'static, E: InteractiveComponent<V>> StatefulInteractiveComponent<V> for Stateful<V, E> {}
958
959impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Stateful<V, E> {
960    fn interactivity(&mut self) -> &mut Interactivity<V> {
961        self.element.interactivity()
962    }
963}
964
965impl<V, E: FocusableComponent<V>> FocusableComponent<V> for Stateful<V, E> {
966    fn focusability(&mut self) -> &mut Focusability<V> {
967        self.element.focusability()
968    }
969}