div.rs

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