node.rs

   1use crate::{
   2    point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
   3    BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusEvent, FocusHandle,
   4    KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
   5    MouseUpEvent, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
   6    StyleRefinement, Styled, Task, View, ViewContext, Visibility,
   7};
   8use collections::HashMap;
   9use parking_lot::Mutex;
  10use refineable::Refineable;
  11use smallvec::SmallVec;
  12use std::{
  13    any::{Any, TypeId},
  14    fmt::Debug,
  15    marker::PhantomData,
  16    mem,
  17    sync::Arc,
  18    time::Duration,
  19};
  20use taffy::style::Overflow;
  21use util::ResultExt;
  22
  23const DRAG_THRESHOLD: f64 = 2.;
  24const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
  25const TOOLTIP_OFFSET: Point<Pixels> = Point::new(px(10.0), px(8.0));
  26
  27pub struct GroupStyle {
  28    pub group: SharedString,
  29    pub style: StyleRefinement,
  30}
  31
  32pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
  33    fn interactivity(&mut self) -> &mut Interactivity<V>;
  34
  35    fn id(mut self, id: impl Into<ElementId>) -> Stateful<V, Self> {
  36        self.interactivity().element_id = Some(id.into());
  37
  38        Stateful {
  39            element: self,
  40            view_type: PhantomData,
  41        }
  42    }
  43
  44    fn track_focus(mut self, focus_handle: FocusHandle) -> Focusable<V, Self> {
  45        self.interactivity().focusable = true;
  46        self.interactivity().tracked_focus_handle = Some(focus_handle);
  47        Focusable {
  48            element: self,
  49            view_type: PhantomData,
  50        }
  51    }
  52
  53    fn key_context<C, E>(mut self, key_context: C) -> Self
  54    where
  55        C: TryInto<KeyContext, Error = E>,
  56        E: Debug,
  57    {
  58        if let Some(key_context) = key_context.try_into().log_err() {
  59            self.interactivity().key_context = key_context;
  60        }
  61        self
  62    }
  63
  64    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
  65        self.interactivity().hover_style = f(StyleRefinement::default());
  66        self
  67    }
  68
  69    fn group_hover(
  70        mut self,
  71        group_name: impl Into<SharedString>,
  72        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
  73    ) -> Self {
  74        self.interactivity().group_hover_style = Some(GroupStyle {
  75            group: group_name.into(),
  76            style: f(StyleRefinement::default()),
  77        });
  78        self
  79    }
  80
  81    fn on_mouse_down(
  82        mut self,
  83        button: MouseButton,
  84        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
  85    ) -> Self {
  86        self.interactivity().mouse_down_listeners.push(Box::new(
  87            move |view, event, bounds, phase, cx| {
  88                if phase == DispatchPhase::Bubble
  89                    && event.button == button
  90                    && bounds.contains_point(&event.position)
  91                {
  92                    handler(view, event, cx)
  93                }
  94            },
  95        ));
  96        self
  97    }
  98
  99    fn on_mouse_up(
 100        mut self,
 101        button: MouseButton,
 102        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
 103    ) -> Self {
 104        self.interactivity().mouse_up_listeners.push(Box::new(
 105            move |view, event, bounds, phase, cx| {
 106                if phase == DispatchPhase::Bubble
 107                    && event.button == button
 108                    && bounds.contains_point(&event.position)
 109                {
 110                    handler(view, event, cx)
 111                }
 112            },
 113        ));
 114        self
 115    }
 116
 117    fn on_mouse_down_out(
 118        mut self,
 119        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
 120    ) -> Self {
 121        self.interactivity().mouse_down_listeners.push(Box::new(
 122            move |view, event, bounds, phase, cx| {
 123                if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
 124                    handler(view, event, cx)
 125                }
 126            },
 127        ));
 128        self
 129    }
 130
 131    fn on_mouse_up_out(
 132        mut self,
 133        button: MouseButton,
 134        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
 135    ) -> Self {
 136        self.interactivity().mouse_up_listeners.push(Box::new(
 137            move |view, event, bounds, phase, cx| {
 138                if phase == DispatchPhase::Capture
 139                    && event.button == button
 140                    && !bounds.contains_point(&event.position)
 141                {
 142                    handler(view, event, cx);
 143                }
 144            },
 145        ));
 146        self
 147    }
 148
 149    fn on_mouse_move(
 150        mut self,
 151        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + 'static,
 152    ) -> Self {
 153        self.interactivity().mouse_move_listeners.push(Box::new(
 154            move |view, event, bounds, phase, cx| {
 155                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 156                    handler(view, event, cx);
 157                }
 158            },
 159        ));
 160        self
 161    }
 162
 163    fn on_scroll_wheel(
 164        mut self,
 165        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + 'static,
 166    ) -> Self {
 167        self.interactivity().scroll_wheel_listeners.push(Box::new(
 168            move |view, event, bounds, phase, cx| {
 169                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 170                    handler(view, event, cx);
 171                }
 172            },
 173        ));
 174        self
 175    }
 176
 177    /// Capture the given action, fires during the capture phase
 178    fn capture_action<A: Action>(
 179        mut self,
 180        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
 181    ) -> Self {
 182        self.interactivity().action_listeners.push((
 183            TypeId::of::<A>(),
 184            Box::new(move |view, action, phase, cx| {
 185                let action = action.downcast_ref().unwrap();
 186                if phase == DispatchPhase::Capture {
 187                    listener(view, action, cx)
 188                }
 189            }),
 190        ));
 191        self
 192    }
 193
 194    /// Add a listener for the given action, fires during the bubble event phase
 195    fn on_action<A: Action>(
 196        mut self,
 197        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
 198    ) -> Self {
 199        self.interactivity().action_listeners.push((
 200            TypeId::of::<A>(),
 201            Box::new(move |view, action, phase, cx| {
 202                let action = action.downcast_ref().unwrap();
 203                if phase == DispatchPhase::Bubble {
 204                    listener(view, action, cx)
 205                }
 206            }),
 207        ));
 208        self
 209    }
 210
 211    fn on_key_down(
 212        mut self,
 213        listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
 214    ) -> Self {
 215        self.interactivity()
 216            .key_down_listeners
 217            .push(Box::new(move |view, event, phase, cx| {
 218                listener(view, event, phase, cx)
 219            }));
 220        self
 221    }
 222
 223    fn on_key_up(
 224        mut self,
 225        listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
 226    ) -> Self {
 227        self.interactivity()
 228            .key_up_listeners
 229            .push(Box::new(move |view, event, phase, cx| {
 230                listener(view, event, phase, cx)
 231            }));
 232        self
 233    }
 234
 235    fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 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        self.interactivity().group_drag_over_styles.push((
 248            TypeId::of::<S>(),
 249            GroupStyle {
 250                group: group_name.into(),
 251                style: f(StyleRefinement::default()),
 252            },
 253        ));
 254        self
 255    }
 256
 257    fn on_drop<W: 'static>(
 258        mut self,
 259        listener: impl Fn(&mut V, View<W>, &mut ViewContext<V>) + 'static,
 260    ) -> Self {
 261        self.interactivity().drop_listeners.push((
 262            TypeId::of::<W>(),
 263            Box::new(move |view, dragged_view, cx| {
 264                listener(view, dragged_view.downcast().unwrap(), cx);
 265            }),
 266        ));
 267        self
 268    }
 269}
 270
 271pub trait StatefulInteractiveComponent<V: 'static, E: Element<V>>: InteractiveComponent<V> {
 272    fn focusable(mut self) -> Self {
 273        self.interactivity().focusable = true;
 274        self
 275    }
 276
 277    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 278    where
 279        Self: Sized,
 280    {
 281        self.interactivity().active_style = f(StyleRefinement::default());
 282        self
 283    }
 284
 285    fn group_active(
 286        mut self,
 287        group_name: impl Into<SharedString>,
 288        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 289    ) -> Self
 290    where
 291        Self: Sized,
 292    {
 293        self.interactivity().group_active_style = Some(GroupStyle {
 294            group: group_name.into(),
 295            style: f(StyleRefinement::default()),
 296        });
 297        self
 298    }
 299
 300    fn on_click(
 301        mut self,
 302        listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
 303    ) -> Self
 304    where
 305        Self: Sized,
 306    {
 307        self.interactivity()
 308            .click_listeners
 309            .push(Box::new(move |view, event, cx| listener(view, event, cx)));
 310        self
 311    }
 312
 313    fn on_drag<W>(
 314        mut self,
 315        listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
 316    ) -> Self
 317    where
 318        Self: Sized,
 319        W: 'static + Render,
 320    {
 321        debug_assert!(
 322            self.interactivity().drag_listener.is_none(),
 323            "calling on_drag more than once on the same element is not supported"
 324        );
 325        self.interactivity().drag_listener =
 326            Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
 327                view: listener(view_state, cx).into(),
 328                cursor_offset,
 329            }));
 330        self
 331    }
 332
 333    fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
 334    where
 335        Self: Sized,
 336    {
 337        debug_assert!(
 338            self.interactivity().hover_listener.is_none(),
 339            "calling on_hover more than once on the same element is not supported"
 340        );
 341        self.interactivity().hover_listener = Some(Box::new(listener));
 342        self
 343    }
 344
 345    fn tooltip<W>(
 346        mut self,
 347        build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
 348    ) -> Self
 349    where
 350        Self: Sized,
 351        W: 'static + Render,
 352    {
 353        debug_assert!(
 354            self.interactivity().tooltip_builder.is_none(),
 355            "calling tooltip more than once on the same element is not supported"
 356        );
 357        self.interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
 358            build_tooltip(view_state, cx).into()
 359        }));
 360
 361        self
 362    }
 363}
 364
 365pub trait FocusableComponent<V: 'static>: InteractiveComponent<V> {
 366    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 367    where
 368        Self: Sized,
 369    {
 370        self.interactivity().focus_style = f(StyleRefinement::default());
 371        self
 372    }
 373
 374    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 375    where
 376        Self: Sized,
 377    {
 378        self.interactivity().focus_in_style = f(StyleRefinement::default());
 379        self
 380    }
 381
 382    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 383    where
 384        Self: Sized,
 385    {
 386        self.interactivity().in_focus_style = f(StyleRefinement::default());
 387        self
 388    }
 389
 390    fn on_focus(
 391        mut self,
 392        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
 393    ) -> Self
 394    where
 395        Self: Sized,
 396    {
 397        self.interactivity().focus_listeners.push(Box::new(
 398            move |view, focus_handle, event, cx| {
 399                if event.focused.as_ref() == Some(focus_handle) {
 400                    listener(view, event, cx)
 401                }
 402            },
 403        ));
 404        self
 405    }
 406
 407    fn on_blur(
 408        mut self,
 409        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
 410    ) -> Self
 411    where
 412        Self: Sized,
 413    {
 414        self.interactivity().focus_listeners.push(Box::new(
 415            move |view, focus_handle, event, cx| {
 416                if event.blurred.as_ref() == Some(focus_handle) {
 417                    listener(view, event, cx)
 418                }
 419            },
 420        ));
 421        self
 422    }
 423
 424    fn on_focus_in(
 425        mut self,
 426        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
 427    ) -> Self
 428    where
 429        Self: Sized,
 430    {
 431        self.interactivity().focus_listeners.push(Box::new(
 432            move |view, focus_handle, event, cx| {
 433                let descendant_blurred = event
 434                    .blurred
 435                    .as_ref()
 436                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
 437                let descendant_focused = event
 438                    .focused
 439                    .as_ref()
 440                    .map_or(false, |focused| focus_handle.contains(focused, cx));
 441
 442                if !descendant_blurred && descendant_focused {
 443                    listener(view, event, cx)
 444                }
 445            },
 446        ));
 447        self
 448    }
 449
 450    fn on_focus_out(
 451        mut self,
 452        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
 453    ) -> Self
 454    where
 455        Self: Sized,
 456    {
 457        self.interactivity().focus_listeners.push(Box::new(
 458            move |view, focus_handle, event, cx| {
 459                let descendant_blurred = event
 460                    .blurred
 461                    .as_ref()
 462                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
 463                let descendant_focused = event
 464                    .focused
 465                    .as_ref()
 466                    .map_or(false, |focused| focus_handle.contains(focused, cx));
 467                if descendant_blurred && !descendant_focused {
 468                    listener(view, event, cx)
 469                }
 470            },
 471        ));
 472        self
 473    }
 474}
 475
 476pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
 477
 478pub type FocusListener<V> =
 479    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
 480
 481pub type MouseDownListener<V> = Box<
 482    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
 483>;
 484pub type MouseUpListener<V> = Box<
 485    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
 486>;
 487
 488pub type MouseMoveListener<V> = Box<
 489    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
 490>;
 491
 492pub type ScrollWheelListener<V> = Box<
 493    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
 494        + 'static,
 495>;
 496
 497pub type ClickListener<V> = Box<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static>;
 498
 499pub type DragListener<V> =
 500    Box<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + 'static>;
 501
 502type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
 503
 504pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
 505
 506pub type TooltipBuilder<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
 507
 508pub type KeyDownListener<V> =
 509    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
 510
 511pub type KeyUpListener<V> =
 512    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
 513
 514pub type ActionListener<V> =
 515    Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
 516
 517pub fn node<V: 'static>() -> Node<V> {
 518    Node {
 519        interactivity: Interactivity::default(),
 520        children: Vec::default(),
 521    }
 522}
 523
 524pub struct Node<V> {
 525    interactivity: Interactivity<V>,
 526    children: Vec<AnyElement<V>>,
 527}
 528
 529impl<V> Styled for Node<V> {
 530    fn style(&mut self) -> &mut StyleRefinement {
 531        &mut self.interactivity.base_style
 532    }
 533}
 534
 535impl<V: 'static> InteractiveComponent<V> for Node<V> {
 536    fn interactivity(&mut self) -> &mut Interactivity<V> {
 537        &mut self.interactivity
 538    }
 539}
 540
 541impl<V: 'static> Element<V> for Node<V> {
 542    type ElementState = NodeState;
 543
 544    fn id(&self) -> Option<ElementId> {
 545        self.interactivity.element_id.clone()
 546    }
 547
 548    fn initialize(
 549        &mut self,
 550        view_state: &mut V,
 551        element_state: Option<Self::ElementState>,
 552        cx: &mut ViewContext<V>,
 553    ) -> Self::ElementState {
 554        let interactive_state = self
 555            .interactivity
 556            .initialize(element_state.map(|s| s.interactive_state), cx);
 557        for child in &mut self.children {
 558            child.initialize(view_state, cx);
 559        }
 560
 561        NodeState {
 562            interactive_state,
 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 mut interactivity = mem::take(&mut self.interactivity);
 574        let layout_id =
 575            interactivity.layout(&mut element_state.interactive_state, cx, |style, cx| {
 576                cx.with_text_style(style.text_style().cloned(), |cx| {
 577                    element_state.child_layout_ids = self
 578                        .children
 579                        .iter_mut()
 580                        .map(|child| child.layout(view_state, cx))
 581                        .collect::<SmallVec<_>>();
 582                    cx.request_layout(&style, element_state.child_layout_ids.iter().copied())
 583                })
 584            });
 585        self.interactivity = interactivity;
 586        layout_id
 587    }
 588
 589    fn paint(
 590        &mut self,
 591        bounds: Bounds<Pixels>,
 592        view_state: &mut V,
 593        element_state: &mut Self::ElementState,
 594        cx: &mut ViewContext<V>,
 595    ) {
 596        let mut child_min = point(Pixels::MAX, Pixels::MAX);
 597        let mut child_max = Point::default();
 598        let content_size = if element_state.child_layout_ids.is_empty() {
 599            bounds.size
 600        } else {
 601            for child_layout_id in &element_state.child_layout_ids {
 602                let child_bounds = cx.layout_bounds(*child_layout_id);
 603                child_min = child_min.min(&child_bounds.origin);
 604                child_max = child_max.max(&child_bounds.lower_right());
 605            }
 606            (child_max - child_min).into()
 607        };
 608
 609        let mut interactivity = mem::take(&mut self.interactivity);
 610        interactivity.paint(
 611            bounds,
 612            content_size,
 613            &mut element_state.interactive_state,
 614            cx,
 615            |style, scroll_offset, cx| {
 616                if style.visibility == Visibility::Hidden {
 617                    return;
 618                }
 619
 620                let z_index = style.z_index.unwrap_or(0);
 621
 622                cx.with_z_index(z_index, |cx| {
 623                    cx.with_z_index(0, |cx| {
 624                        style.paint(bounds, cx);
 625                    });
 626                    cx.with_z_index(1, |cx| {
 627                        cx.with_text_style(style.text_style().cloned(), |cx| {
 628                            cx.with_content_mask(style.overflow_mask(bounds), |cx| {
 629                                cx.with_element_offset(scroll_offset, |cx| {
 630                                    for child in &mut self.children {
 631                                        child.paint(view_state, cx);
 632                                    }
 633                                })
 634                            })
 635                        })
 636                    })
 637                })
 638            },
 639        );
 640        self.interactivity = interactivity;
 641    }
 642}
 643
 644pub struct NodeState {
 645    child_layout_ids: SmallVec<[LayoutId; 4]>,
 646    interactive_state: InteractiveElementState,
 647}
 648
 649pub struct Interactivity<V> {
 650    element_id: Option<ElementId>,
 651    key_context: KeyContext,
 652    focusable: bool,
 653    tracked_focus_handle: Option<FocusHandle>,
 654    focus_listeners: FocusListeners<V>,
 655    scroll_offset: Point<Pixels>,
 656    group: Option<SharedString>,
 657    base_style: StyleRefinement,
 658    focus_style: StyleRefinement,
 659    focus_in_style: StyleRefinement,
 660    in_focus_style: StyleRefinement,
 661    hover_style: StyleRefinement,
 662    group_hover_style: Option<GroupStyle>,
 663    active_style: StyleRefinement,
 664    group_active_style: Option<GroupStyle>,
 665    drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
 666    group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
 667    mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
 668    mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
 669    mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
 670    scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
 671    key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
 672    key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
 673    action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
 674    drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
 675    click_listeners: SmallVec<[ClickListener<V>; 2]>,
 676    drag_listener: Option<DragListener<V>>,
 677    hover_listener: Option<HoverListener<V>>,
 678    tooltip_builder: Option<TooltipBuilder<V>>,
 679}
 680
 681impl<V> Interactivity<V>
 682where
 683    V: 'static,
 684{
 685    fn initialize(
 686        &mut self,
 687        element_state: Option<InteractiveElementState>,
 688        cx: &mut ViewContext<V>,
 689    ) -> InteractiveElementState {
 690        let mut element_state = element_state.unwrap_or_default();
 691
 692        // Ensure we store a focus handle in our element state if we're focusable.
 693        // If there's an explicit focus handle we're tracking, use that. Otherwise
 694        // create a new handle and store it in the element state, which lives for as
 695        // as frames contain an element with this id.
 696        if self.focusable {
 697            element_state.focus_handle.get_or_insert_with(|| {
 698                self.tracked_focus_handle
 699                    .clone()
 700                    .unwrap_or_else(|| cx.focus_handle())
 701            });
 702        }
 703        element_state
 704    }
 705
 706    fn layout(
 707        &mut self,
 708        element_state: &mut InteractiveElementState,
 709        cx: &mut ViewContext<V>,
 710        f: impl FnOnce(Style, &mut ViewContext<V>) -> LayoutId,
 711    ) -> LayoutId {
 712        let style = self.compute_style(None, element_state, cx);
 713        cx.with_element_id(self.element_id.clone(), |cx| {
 714            cx.with_key_dispatch(
 715                self.key_context.clone(),
 716                self.tracked_focus_handle.clone(),
 717                |_, cx| f(style, cx),
 718            )
 719        })
 720    }
 721
 722    fn paint(
 723        &mut self,
 724        bounds: Bounds<Pixels>,
 725        content_size: Size<Pixels>,
 726        element_state: &mut InteractiveElementState,
 727        cx: &mut ViewContext<V>,
 728        f: impl FnOnce(Style, Point<Pixels>, &mut ViewContext<V>),
 729    ) {
 730        let style = self.compute_style(Some(bounds), element_state, cx);
 731
 732        if let Some(mouse_cursor) = style.mouse_cursor {
 733            let hovered = bounds.contains_point(&cx.mouse_position());
 734            if hovered {
 735                cx.set_cursor_style(mouse_cursor);
 736            }
 737        }
 738
 739        for listener in self.mouse_down_listeners.drain(..) {
 740            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
 741                listener(state, event, &bounds, phase, cx);
 742            })
 743        }
 744
 745        for listener in self.mouse_up_listeners.drain(..) {
 746            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
 747                listener(state, event, &bounds, phase, cx);
 748            })
 749        }
 750
 751        for listener in self.mouse_move_listeners.drain(..) {
 752            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
 753                listener(state, event, &bounds, phase, cx);
 754            })
 755        }
 756
 757        for listener in self.scroll_wheel_listeners.drain(..) {
 758            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
 759                listener(state, event, &bounds, phase, cx);
 760            })
 761        }
 762
 763        let hover_group_bounds = self
 764            .group_hover_style
 765            .as_ref()
 766            .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
 767
 768        if let Some(group_bounds) = hover_group_bounds {
 769            let hovered = group_bounds.contains_point(&cx.mouse_position());
 770            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
 771                if phase == DispatchPhase::Capture {
 772                    if group_bounds.contains_point(&event.position) != hovered {
 773                        cx.notify();
 774                    }
 775                }
 776            });
 777        }
 778
 779        if self.hover_style.is_some()
 780            || (cx.active_drag.is_some() && !self.drag_over_styles.is_empty())
 781        {
 782            let hovered = bounds.contains_point(&cx.mouse_position());
 783            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
 784                if phase == DispatchPhase::Capture {
 785                    if bounds.contains_point(&event.position) != hovered {
 786                        cx.notify();
 787                    }
 788                }
 789            });
 790        }
 791
 792        if cx.active_drag.is_some() {
 793            let drop_listeners = mem::take(&mut self.drop_listeners);
 794            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
 795                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 796                    if let Some(drag_state_type) =
 797                        cx.active_drag.as_ref().map(|drag| drag.view.entity_type())
 798                    {
 799                        for (drop_state_type, listener) in &drop_listeners {
 800                            if *drop_state_type == drag_state_type {
 801                                let drag = cx
 802                                    .active_drag
 803                                    .take()
 804                                    .expect("checked for type drag state type above");
 805                                listener(view, drag.view.clone(), cx);
 806                                cx.notify();
 807                                cx.stop_propagation();
 808                            }
 809                        }
 810                    }
 811                }
 812            });
 813        }
 814
 815        let click_listeners = mem::take(&mut self.click_listeners);
 816        let drag_listener = mem::take(&mut self.drag_listener);
 817
 818        if !click_listeners.is_empty() || drag_listener.is_some() {
 819            let pending_mouse_down = element_state.pending_mouse_down.clone();
 820            let mouse_down = pending_mouse_down.lock().clone();
 821            if let Some(mouse_down) = mouse_down {
 822                if let Some(drag_listener) = drag_listener {
 823                    let active_state = element_state.clicked_state.clone();
 824
 825                    cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
 826                        if cx.active_drag.is_some() {
 827                            if phase == DispatchPhase::Capture {
 828                                cx.notify();
 829                            }
 830                        } else if phase == DispatchPhase::Bubble
 831                            && bounds.contains_point(&event.position)
 832                            && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD
 833                        {
 834                            *active_state.lock() = ElementClickedState::default();
 835                            let cursor_offset = event.position - bounds.origin;
 836                            let drag = drag_listener(view_state, cursor_offset, cx);
 837                            cx.active_drag = Some(drag);
 838                            cx.notify();
 839                            cx.stop_propagation();
 840                        }
 841                    });
 842                }
 843
 844                cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
 845                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 846                        let mouse_click = ClickEvent {
 847                            down: mouse_down.clone(),
 848                            up: event.clone(),
 849                        };
 850                        for listener in &click_listeners {
 851                            listener(view_state, &mouse_click, cx);
 852                        }
 853                    }
 854                    *pending_mouse_down.lock() = None;
 855                });
 856            } else {
 857                cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
 858                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 859                        *pending_mouse_down.lock() = Some(event.clone());
 860                    }
 861                });
 862            }
 863        }
 864
 865        if let Some(hover_listener) = self.hover_listener.take() {
 866            let was_hovered = element_state.hover_state.clone();
 867            let has_mouse_down = element_state.pending_mouse_down.clone();
 868
 869            cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
 870                if phase != DispatchPhase::Bubble {
 871                    return;
 872                }
 873                let is_hovered =
 874                    bounds.contains_point(&event.position) && has_mouse_down.lock().is_none();
 875                let mut was_hovered = was_hovered.lock();
 876
 877                if is_hovered != was_hovered.clone() {
 878                    *was_hovered = is_hovered;
 879                    drop(was_hovered);
 880
 881                    hover_listener(view_state, is_hovered, cx);
 882                }
 883            });
 884        }
 885
 886        if let Some(tooltip_builder) = self.tooltip_builder.take() {
 887            let active_tooltip = element_state.active_tooltip.clone();
 888            let pending_mouse_down = element_state.pending_mouse_down.clone();
 889
 890            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
 891                if phase != DispatchPhase::Bubble {
 892                    return;
 893                }
 894
 895                let is_hovered =
 896                    bounds.contains_point(&event.position) && pending_mouse_down.lock().is_none();
 897                if !is_hovered {
 898                    active_tooltip.lock().take();
 899                    return;
 900                }
 901
 902                if active_tooltip.lock().is_none() {
 903                    let task = cx.spawn({
 904                        let active_tooltip = active_tooltip.clone();
 905                        let tooltip_builder = tooltip_builder.clone();
 906
 907                        move |view, mut cx| async move {
 908                            cx.background_executor().timer(TOOLTIP_DELAY).await;
 909                            view.update(&mut cx, move |view_state, cx| {
 910                                active_tooltip.lock().replace(ActiveTooltip {
 911                                    waiting: None,
 912                                    tooltip: Some(AnyTooltip {
 913                                        view: tooltip_builder(view_state, cx),
 914                                        cursor_offset: cx.mouse_position() + TOOLTIP_OFFSET,
 915                                    }),
 916                                });
 917                                cx.notify();
 918                            })
 919                            .ok();
 920                        }
 921                    });
 922                    active_tooltip.lock().replace(ActiveTooltip {
 923                        waiting: Some(task),
 924                        tooltip: None,
 925                    });
 926                }
 927            });
 928
 929            if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() {
 930                if active_tooltip.tooltip.is_some() {
 931                    cx.active_tooltip = active_tooltip.tooltip.clone()
 932                }
 933            }
 934        }
 935
 936        let active_state = element_state.clicked_state.clone();
 937        if !active_state.lock().is_clicked() {
 938            cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
 939                if phase == DispatchPhase::Capture {
 940                    *active_state.lock() = ElementClickedState::default();
 941                    cx.notify();
 942                }
 943            });
 944        } else {
 945            let active_group_bounds = self
 946                .group_active_style
 947                .as_ref()
 948                .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
 949            cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
 950                if phase == DispatchPhase::Bubble {
 951                    let group = active_group_bounds
 952                        .map_or(false, |bounds| bounds.contains_point(&down.position));
 953                    let element = bounds.contains_point(&down.position);
 954                    if group || element {
 955                        *active_state.lock() = ElementClickedState { group, element };
 956                        cx.notify();
 957                    }
 958                }
 959            });
 960        }
 961
 962        let overflow = style.overflow;
 963        if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
 964            let scroll_offset = element_state
 965                .scroll_offset
 966                .get_or_insert_with(Arc::default)
 967                .clone();
 968            let line_height = cx.line_height();
 969            let scroll_max = (content_size - bounds.size).max(&Size::default());
 970
 971            cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
 972                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 973                    let mut scroll_offset = scroll_offset.lock();
 974                    let old_scroll_offset = *scroll_offset;
 975                    let delta = event.delta.pixel_delta(line_height);
 976
 977                    if overflow.x == Overflow::Scroll {
 978                        scroll_offset.x =
 979                            (scroll_offset.x + delta.x).clamp(-scroll_max.width, px(0.));
 980                    }
 981
 982                    if overflow.y == Overflow::Scroll {
 983                        scroll_offset.y =
 984                            (scroll_offset.y + delta.y).clamp(-scroll_max.height, px(0.));
 985                    }
 986
 987                    if *scroll_offset != old_scroll_offset {
 988                        cx.notify();
 989                        cx.stop_propagation();
 990                    }
 991                }
 992            });
 993        }
 994
 995        if let Some(group) = self.group.clone() {
 996            GroupBounds::push(group, bounds, cx);
 997        }
 998
 999        cx.with_element_id(self.element_id.clone(), |cx| {
1000            cx.with_key_dispatch(
1001                self.key_context.clone(),
1002                element_state.focus_handle.clone(),
1003                |_, cx| {
1004                    for listener in self.key_down_listeners.drain(..) {
1005                        cx.on_key_event(move |state, event: &KeyDownEvent, phase, cx| {
1006                            listener(state, event, phase, cx);
1007                        })
1008                    }
1009
1010                    for listener in self.key_up_listeners.drain(..) {
1011                        cx.on_key_event(move |state, event: &KeyUpEvent, phase, cx| {
1012                            listener(state, event, phase, cx);
1013                        })
1014                    }
1015
1016                    for (action_type, listener) in self.action_listeners.drain(..) {
1017                        cx.on_action(action_type, listener)
1018                    }
1019
1020                    if let Some(focus_handle) = element_state.focus_handle.as_ref() {
1021                        for listener in self.focus_listeners.drain(..) {
1022                            let focus_handle = focus_handle.clone();
1023                            cx.on_focus_changed(move |view, event, cx| {
1024                                listener(view, &focus_handle, event, cx)
1025                            });
1026                        }
1027                    }
1028
1029                    f(style, self.scroll_offset, cx)
1030                },
1031            );
1032        });
1033
1034        if let Some(group) = self.group.as_ref() {
1035            GroupBounds::pop(group, cx);
1036        }
1037    }
1038
1039    fn compute_style(
1040        &self,
1041        bounds: Option<Bounds<Pixels>>,
1042        element_state: &mut InteractiveElementState,
1043        cx: &mut ViewContext<V>,
1044    ) -> Style {
1045        let mut style = Style::default();
1046        style.refine(&self.base_style);
1047
1048        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1049            if focus_handle.contains_focused(cx) {
1050                style.refine(&self.focus_in_style);
1051            }
1052
1053            if focus_handle.within_focused(cx) {
1054                style.refine(&self.in_focus_style);
1055            }
1056
1057            if focus_handle.is_focused(cx) {
1058                style.refine(&self.focus_style);
1059            }
1060        }
1061
1062        if let Some(bounds) = bounds {
1063            let mouse_position = cx.mouse_position();
1064            if let Some(group_hover) = self.group_hover_style.as_ref() {
1065                if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
1066                    if group_bounds.contains_point(&mouse_position) {
1067                        style.refine(&group_hover.style);
1068                    }
1069                }
1070            }
1071            if bounds.contains_point(&mouse_position) {
1072                style.refine(&self.hover_style);
1073            }
1074
1075            if let Some(drag) = cx.active_drag.take() {
1076                for (state_type, group_drag_style) in &self.group_drag_over_styles {
1077                    if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
1078                        if *state_type == drag.view.entity_type()
1079                            && group_bounds.contains_point(&mouse_position)
1080                        {
1081                            style.refine(&group_drag_style.style);
1082                        }
1083                    }
1084                }
1085
1086                for (state_type, drag_over_style) in &self.drag_over_styles {
1087                    if *state_type == drag.view.entity_type()
1088                        && bounds.contains_point(&mouse_position)
1089                    {
1090                        style.refine(drag_over_style);
1091                    }
1092                }
1093
1094                cx.active_drag = Some(drag);
1095            }
1096        }
1097
1098        let clicked_state = element_state.clicked_state.lock();
1099        if clicked_state.group {
1100            if let Some(group) = self.group_active_style.as_ref() {
1101                style.refine(&group.style)
1102            }
1103        }
1104
1105        if clicked_state.element {
1106            style.refine(&self.active_style)
1107        }
1108
1109        style
1110    }
1111}
1112
1113impl<V: 'static> Default for Interactivity<V> {
1114    fn default() -> Self {
1115        Self {
1116            element_id: None,
1117            key_context: KeyContext::default(),
1118            focusable: false,
1119            tracked_focus_handle: None,
1120            focus_listeners: SmallVec::default(),
1121            scroll_offset: Point::default(),
1122            group: None,
1123            base_style: StyleRefinement::default(),
1124            focus_style: StyleRefinement::default(),
1125            focus_in_style: StyleRefinement::default(),
1126            in_focus_style: StyleRefinement::default(),
1127            hover_style: StyleRefinement::default(),
1128            group_hover_style: None,
1129            active_style: StyleRefinement::default(),
1130            group_active_style: None,
1131            drag_over_styles: SmallVec::new(),
1132            group_drag_over_styles: SmallVec::new(),
1133            mouse_down_listeners: SmallVec::new(),
1134            mouse_up_listeners: SmallVec::new(),
1135            mouse_move_listeners: SmallVec::new(),
1136            scroll_wheel_listeners: SmallVec::new(),
1137            key_down_listeners: SmallVec::new(),
1138            key_up_listeners: SmallVec::new(),
1139            action_listeners: SmallVec::new(),
1140            drop_listeners: SmallVec::new(),
1141            click_listeners: SmallVec::new(),
1142            drag_listener: None,
1143            hover_listener: None,
1144            tooltip_builder: None,
1145        }
1146    }
1147}
1148
1149#[derive(Default)]
1150pub struct InteractiveElementState {
1151    focus_handle: Option<FocusHandle>,
1152    clicked_state: Arc<Mutex<ElementClickedState>>,
1153    hover_state: Arc<Mutex<bool>>,
1154    pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
1155    scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
1156    active_tooltip: Arc<Mutex<Option<ActiveTooltip>>>,
1157}
1158
1159struct ActiveTooltip {
1160    #[allow(unused)] // used to drop the task
1161    waiting: Option<Task<()>>,
1162    tooltip: Option<AnyTooltip>,
1163}
1164
1165/// Whether or not the element or a group that contains it is clicked by the mouse.
1166#[derive(Copy, Clone, Default, Eq, PartialEq)]
1167struct ElementClickedState {
1168    pub group: bool,
1169    pub element: bool,
1170}
1171
1172impl ElementClickedState {
1173    fn is_clicked(&self) -> bool {
1174        self.group || self.element
1175    }
1176}
1177
1178#[derive(Default)]
1179pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
1180
1181impl GroupBounds {
1182    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
1183        cx.default_global::<Self>()
1184            .0
1185            .get(name)
1186            .and_then(|bounds_stack| bounds_stack.last())
1187            .cloned()
1188    }
1189
1190    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
1191        cx.default_global::<Self>()
1192            .0
1193            .entry(name)
1194            .or_default()
1195            .push(bounds);
1196    }
1197
1198    pub fn pop(name: &SharedString, cx: &mut AppContext) {
1199        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
1200    }
1201}
1202
1203pub struct Focusable<V, E> {
1204    element: E,
1205    view_type: PhantomData<V>,
1206}
1207
1208impl<V: 'static, E: InteractiveComponent<V>> FocusableComponent<V> for Focusable<V, E> {}
1209
1210impl<V, E> InteractiveComponent<V> for Focusable<V, E>
1211where
1212    V: 'static,
1213    E: InteractiveComponent<V>,
1214{
1215    fn interactivity(&mut self) -> &mut Interactivity<V> {
1216        self.element.interactivity()
1217    }
1218}
1219
1220impl<V: 'static, E: StatefulInteractiveComponent<V, E>> StatefulInteractiveComponent<V, E>
1221    for Focusable<V, E>
1222{
1223}
1224
1225impl<V, E> Element<V> for Focusable<V, E>
1226where
1227    V: 'static,
1228    E: Element<V>,
1229{
1230    type ElementState = E::ElementState;
1231
1232    fn id(&self) -> Option<ElementId> {
1233        self.element.id()
1234    }
1235
1236    fn initialize(
1237        &mut self,
1238        view_state: &mut V,
1239        element_state: Option<Self::ElementState>,
1240        cx: &mut ViewContext<V>,
1241    ) -> Self::ElementState {
1242        self.element.initialize(view_state, element_state, cx)
1243    }
1244
1245    fn layout(
1246        &mut self,
1247        view_state: &mut V,
1248        element_state: &mut Self::ElementState,
1249        cx: &mut ViewContext<V>,
1250    ) -> LayoutId {
1251        self.element.layout(view_state, element_state, cx)
1252    }
1253
1254    fn paint(
1255        &mut self,
1256        bounds: Bounds<Pixels>,
1257        view_state: &mut V,
1258        element_state: &mut Self::ElementState,
1259        cx: &mut ViewContext<V>,
1260    ) {
1261        self.element.paint(bounds, view_state, element_state, cx);
1262    }
1263}
1264
1265pub struct Stateful<V, E> {
1266    element: E,
1267    view_type: PhantomData<V>,
1268}
1269
1270impl<V, E> StatefulInteractiveComponent<V, E> for Stateful<V, E>
1271where
1272    V: 'static,
1273    E: Element<V>,
1274    Self: InteractiveComponent<V>,
1275{
1276}
1277
1278impl<V, E> InteractiveComponent<V> for Stateful<V, E>
1279where
1280    V: 'static,
1281    E: InteractiveComponent<V>,
1282{
1283    fn interactivity(&mut self) -> &mut Interactivity<V> {
1284        self.element.interactivity()
1285    }
1286}
1287
1288impl<V: 'static, E: FocusableComponent<V>> FocusableComponent<V> for Stateful<V, E> {}
1289
1290impl<V, E> Element<V> for Stateful<V, E>
1291where
1292    V: 'static,
1293    E: Element<V>,
1294{
1295    type ElementState = E::ElementState;
1296
1297    fn id(&self) -> Option<ElementId> {
1298        self.element.id()
1299    }
1300
1301    fn initialize(
1302        &mut self,
1303        view_state: &mut V,
1304        element_state: Option<Self::ElementState>,
1305        cx: &mut ViewContext<V>,
1306    ) -> Self::ElementState {
1307        self.element.initialize(view_state, element_state, cx)
1308    }
1309
1310    fn layout(
1311        &mut self,
1312        view_state: &mut V,
1313        element_state: &mut Self::ElementState,
1314        cx: &mut ViewContext<V>,
1315    ) -> LayoutId {
1316        self.element.layout(view_state, element_state, cx)
1317    }
1318
1319    fn paint(
1320        &mut self,
1321        bounds: Bounds<Pixels>,
1322        view_state: &mut V,
1323        element_state: &mut Self::ElementState,
1324        cx: &mut ViewContext<V>,
1325    ) {
1326        self.element.paint(bounds, view_state, element_state, cx)
1327    }
1328}