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