div.rs

   1//! Div is the central, reusable element that most GPUI trees will be built from.
   2//! It functions as a container for other elements, and provides a number of
   3//! useful features for laying out and styling its children as well as binding
   4//! mouse events and action handlers. It is meant to be similar to the HTML `<div>`
   5//! element, but for GPUI.
   6//!
   7//! # Build your own div
   8//!
   9//! GPUI does not directly provide APIs for stateful, multi step events like `click`
  10//! and `drag`. We want GPUI users to be able to build their own abstractions for
  11//! their own needs. However, as a UI framework, we're also obliged to provide some
  12//! building blocks to make the process of building your own elements easier.
  13//! For this we have the [`Interactivity`] and the [`StyleRefinement`] structs, as well
  14//! as several associated traits. Together, these provide the full suite of Dom-like events
  15//! and Tailwind-like styling that you can use to build your own custom elements. Div is
  16//! constructed by combining these two systems into an all-in-one element.
  17
  18use crate::{
  19    point, px, size, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds,
  20    ClickEvent, DispatchPhase, Element, ElementContext, ElementId, FocusHandle, Global, Hitbox,
  21    HitboxId, IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton,
  22    MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render,
  23    ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, View, Visibility,
  24    WindowContext,
  25};
  26use collections::HashMap;
  27use refineable::Refineable;
  28use smallvec::SmallVec;
  29use std::{
  30    any::{Any, TypeId},
  31    cell::RefCell,
  32    cmp::Ordering,
  33    fmt::Debug,
  34    marker::PhantomData,
  35    mem,
  36    ops::DerefMut,
  37    rc::Rc,
  38    time::Duration,
  39};
  40use taffy::style::Overflow;
  41use util::ResultExt;
  42
  43const DRAG_THRESHOLD: f64 = 2.;
  44pub(crate) const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
  45
  46/// The styling information for a given group.
  47pub struct GroupStyle {
  48    /// The identifier for this group.
  49    pub group: SharedString,
  50
  51    /// The specific style refinement that this group would apply
  52    /// to its children.
  53    pub style: Box<StyleRefinement>,
  54}
  55
  56/// An event for when a drag is moving over this element, with the given state type.
  57pub struct DragMoveEvent<T> {
  58    /// The mouse move event that triggered this drag move event.
  59    pub event: MouseMoveEvent,
  60
  61    /// The bounds of this element.
  62    pub bounds: Bounds<Pixels>,
  63    drag: PhantomData<T>,
  64}
  65
  66impl<T: 'static> DragMoveEvent<T> {
  67    /// Returns the drag state for this event.
  68    pub fn drag<'b>(&self, cx: &'b AppContext) -> &'b T {
  69        cx.active_drag
  70            .as_ref()
  71            .and_then(|drag| drag.value.downcast_ref::<T>())
  72            .expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
  73    }
  74}
  75
  76impl Interactivity {
  77    /// Bind the given callback to the mouse down event for the given mouse button, during the bubble phase
  78    /// The imperative API equivalent of [`InteractiveElement::on_mouse_down`]
  79    ///
  80    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to the view state from this callback.
  81    pub fn on_mouse_down(
  82        &mut self,
  83        button: MouseButton,
  84        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
  85    ) {
  86        self.mouse_down_listeners
  87            .push(Box::new(move |event, phase, hitbox, cx| {
  88                if phase == DispatchPhase::Bubble && event.button == button && hitbox.is_hovered(cx)
  89                {
  90                    (listener)(event, cx)
  91                }
  92            }));
  93    }
  94
  95    /// Bind the given callback to the mouse down event for any button, during the capture phase
  96    /// The imperative API equivalent of [`InteractiveElement::capture_any_mouse_down`]
  97    ///
  98    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
  99    pub fn capture_any_mouse_down(
 100        &mut self,
 101        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 102    ) {
 103        self.mouse_down_listeners
 104            .push(Box::new(move |event, phase, hitbox, cx| {
 105                if phase == DispatchPhase::Capture && hitbox.is_hovered(cx) {
 106                    (listener)(event, cx)
 107                }
 108            }));
 109    }
 110
 111    /// Bind the given callback to the mouse down event for any button, during the bubble phase
 112    /// the imperative API equivalent to [`InteractiveElement::on_any_mouse_down`]
 113    ///
 114    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 115    pub fn on_any_mouse_down(
 116        &mut self,
 117        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 118    ) {
 119        self.mouse_down_listeners
 120            .push(Box::new(move |event, phase, hitbox, cx| {
 121                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 122                    (listener)(event, cx)
 123                }
 124            }));
 125    }
 126
 127    /// Bind the given callback to the mouse up event for the given button, during the bubble phase
 128    /// the imperative API equivalent to [`InteractiveElement::on_mouse_up`]
 129    ///
 130    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 131    pub fn on_mouse_up(
 132        &mut self,
 133        button: MouseButton,
 134        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 135    ) {
 136        self.mouse_up_listeners
 137            .push(Box::new(move |event, phase, hitbox, cx| {
 138                if phase == DispatchPhase::Bubble && event.button == button && hitbox.is_hovered(cx)
 139                {
 140                    (listener)(event, cx)
 141                }
 142            }));
 143    }
 144
 145    /// Bind the given callback to the mouse up event for any button, during the capture phase
 146    /// the imperative API equivalent to [`InteractiveElement::capture_any_mouse_up`]
 147    ///
 148    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 149    pub fn capture_any_mouse_up(
 150        &mut self,
 151        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 152    ) {
 153        self.mouse_up_listeners
 154            .push(Box::new(move |event, phase, hitbox, cx| {
 155                if phase == DispatchPhase::Capture && hitbox.is_hovered(cx) {
 156                    (listener)(event, cx)
 157                }
 158            }));
 159    }
 160
 161    /// Bind the given callback to the mouse up event for any button, during the bubble phase
 162    /// the imperative API equivalent to [`Interactivity::on_any_mouse_up`]
 163    ///
 164    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 165    pub fn on_any_mouse_up(
 166        &mut self,
 167        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 168    ) {
 169        self.mouse_up_listeners
 170            .push(Box::new(move |event, phase, hitbox, cx| {
 171                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 172                    (listener)(event, cx)
 173                }
 174            }));
 175    }
 176
 177    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 178    /// when the mouse is outside of the bounds of this element.
 179    /// The imperative API equivalent to [`InteractiveElement::on_mouse_down_out`]
 180    ///
 181    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 182    pub fn on_mouse_down_out(
 183        &mut self,
 184        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 185    ) {
 186        self.mouse_down_listeners
 187            .push(Box::new(move |event, phase, hitbox, cx| {
 188                if phase == DispatchPhase::Capture && !hitbox.contains(&cx.mouse_position()) {
 189                    (listener)(event, cx)
 190                }
 191            }));
 192    }
 193
 194    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 195    /// when the mouse is outside of the bounds of this element.
 196    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up_out`]
 197    ///
 198    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 199    pub fn on_mouse_up_out(
 200        &mut self,
 201        button: MouseButton,
 202        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 203    ) {
 204        self.mouse_up_listeners
 205            .push(Box::new(move |event, phase, hitbox, cx| {
 206                if phase == DispatchPhase::Capture
 207                    && event.button == button
 208                    && !hitbox.is_hovered(cx)
 209                {
 210                    (listener)(event, cx);
 211                }
 212            }));
 213    }
 214
 215    /// Bind the given callback to the mouse move event, during the bubble phase
 216    /// The imperative API equivalent to [`InteractiveElement::on_mouse_move`]
 217    ///
 218    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 219    pub fn on_mouse_move(
 220        &mut self,
 221        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 222    ) {
 223        self.mouse_move_listeners
 224            .push(Box::new(move |event, phase, hitbox, cx| {
 225                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 226                    (listener)(event, cx);
 227                }
 228            }));
 229    }
 230
 231    /// Bind the given callback to the mouse drag event of the given type. Note that this
 232    /// will be called for all move events, inside or outside of this element, as long as the
 233    /// drag was started with this element under the mouse. Useful for implementing draggable
 234    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 235    /// The imperative API equivalent to [`InteractiveElement::on_drag_move`]
 236    ///
 237    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 238    pub fn on_drag_move<T>(
 239        &mut self,
 240        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 241    ) where
 242        T: 'static,
 243    {
 244        self.mouse_move_listeners
 245            .push(Box::new(move |event, phase, hitbox, cx| {
 246                if phase == DispatchPhase::Capture
 247                    && cx
 248                        .active_drag
 249                        .as_ref()
 250                        .is_some_and(|drag| drag.value.as_ref().type_id() == TypeId::of::<T>())
 251                {
 252                    (listener)(
 253                        &DragMoveEvent {
 254                            event: event.clone(),
 255                            bounds: hitbox.bounds,
 256                            drag: PhantomData,
 257                        },
 258                        cx,
 259                    );
 260                }
 261            }));
 262    }
 263
 264    /// Bind the given callback to scroll wheel events during the bubble phase
 265    /// The imperative API equivalent to [`InteractiveElement::on_scroll_wheel`]
 266    ///
 267    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 268    pub fn on_scroll_wheel(
 269        &mut self,
 270        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 271    ) {
 272        self.scroll_wheel_listeners
 273            .push(Box::new(move |event, phase, hitbox, cx| {
 274                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 275                    (listener)(event, cx);
 276                }
 277            }));
 278    }
 279
 280    /// Bind the given callback to an action dispatch during the capture phase
 281    /// The imperative API equivalent to [`InteractiveElement::capture_action`]
 282    ///
 283    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 284    pub fn capture_action<A: Action>(
 285        &mut self,
 286        listener: impl Fn(&A, &mut WindowContext) + 'static,
 287    ) {
 288        self.action_listeners.push((
 289            TypeId::of::<A>(),
 290            Box::new(move |action, phase, cx| {
 291                let action = action.downcast_ref().unwrap();
 292                if phase == DispatchPhase::Capture {
 293                    (listener)(action, cx)
 294                }
 295            }),
 296        ));
 297    }
 298
 299    /// Bind the given callback to an action dispatch during the bubble phase
 300    /// The imperative API equivalent to [`InteractiveElement::on_action`]
 301    ///
 302    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 303    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) {
 304        self.action_listeners.push((
 305            TypeId::of::<A>(),
 306            Box::new(move |action, phase, cx| {
 307                let action = action.downcast_ref().unwrap();
 308                if phase == DispatchPhase::Bubble {
 309                    (listener)(action, cx)
 310                }
 311            }),
 312        ));
 313    }
 314
 315    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 316    /// instead of a type parameter. Useful for component libraries that want to expose
 317    /// action bindings to their users.
 318    /// The imperative API equivalent to [`InteractiveElement::on_boxed_action`]
 319    ///
 320    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 321    pub fn on_boxed_action(
 322        &mut self,
 323        action: &dyn Action,
 324        listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
 325    ) {
 326        let action = action.boxed_clone();
 327        self.action_listeners.push((
 328            (*action).type_id(),
 329            Box::new(move |_, phase, cx| {
 330                if phase == DispatchPhase::Bubble {
 331                    (listener)(&action, cx)
 332                }
 333            }),
 334        ));
 335    }
 336
 337    /// Bind the given callback to key down events during the bubble phase
 338    /// The imperative API equivalent to [`InteractiveElement::on_key_down`]
 339    ///
 340    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 341    pub fn on_key_down(&mut self, listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static) {
 342        self.key_down_listeners
 343            .push(Box::new(move |event, phase, cx| {
 344                if phase == DispatchPhase::Bubble {
 345                    (listener)(event, cx)
 346                }
 347            }));
 348    }
 349
 350    /// Bind the given callback to key down events during the capture phase
 351    /// The imperative API equivalent to [`InteractiveElement::capture_key_down`]
 352    ///
 353    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 354    pub fn capture_key_down(
 355        &mut self,
 356        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 357    ) {
 358        self.key_down_listeners
 359            .push(Box::new(move |event, phase, cx| {
 360                if phase == DispatchPhase::Capture {
 361                    listener(event, cx)
 362                }
 363            }));
 364    }
 365
 366    /// Bind the given callback to key up events during the bubble phase
 367    /// The imperative API equivalent to [`InteractiveElement::on_key_up`]
 368    ///
 369    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 370    pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 371        self.key_up_listeners
 372            .push(Box::new(move |event, phase, cx| {
 373                if phase == DispatchPhase::Bubble {
 374                    listener(event, cx)
 375                }
 376            }));
 377    }
 378
 379    /// Bind the given callback to key up events during the capture phase
 380    /// The imperative API equivalent to [`InteractiveElement::on_key_up`]
 381    ///
 382    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 383    pub fn capture_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 384        self.key_up_listeners
 385            .push(Box::new(move |event, phase, cx| {
 386                if phase == DispatchPhase::Capture {
 387                    listener(event, cx)
 388                }
 389            }));
 390    }
 391
 392    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element
 393    /// The imperative API equivalent to [`InteractiveElement::on_drop`]
 394    ///
 395    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 396    pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) {
 397        self.drop_listeners.push((
 398            TypeId::of::<T>(),
 399            Box::new(move |dragged_value, cx| {
 400                listener(dragged_value.downcast_ref().unwrap(), cx);
 401            }),
 402        ));
 403    }
 404
 405    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element
 406    /// The imperative API equivalent to [`InteractiveElement::can_drop`]
 407    pub fn can_drop(&mut self, predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static) {
 408        self.can_drop_predicate = Some(Box::new(predicate));
 409    }
 410
 411    /// Bind the given callback to click events of this element
 412    /// The imperative API equivalent to [`StatefulInteractiveElement::on_click`]
 413    ///
 414    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 415    pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static)
 416    where
 417        Self: Sized,
 418    {
 419        self.click_listeners
 420            .push(Box::new(move |event, cx| listener(event, cx)));
 421    }
 422
 423    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 424    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 425    /// the [`Self::on_drag_move`] API
 426    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`]
 427    ///
 428    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 429    pub fn on_drag<T, W>(
 430        &mut self,
 431        value: T,
 432        constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
 433    ) where
 434        Self: Sized,
 435        T: 'static,
 436        W: 'static + Render,
 437    {
 438        debug_assert!(
 439            self.drag_listener.is_none(),
 440            "calling on_drag more than once on the same element is not supported"
 441        );
 442        self.drag_listener = Some((
 443            Box::new(value),
 444            Box::new(move |value, cx| constructor(value.downcast_ref().unwrap(), cx).into()),
 445        ));
 446    }
 447
 448    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 449    /// passed to the callback is true when the hover starts and false when it ends.
 450    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`]
 451    ///
 452    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 453    pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static)
 454    where
 455        Self: Sized,
 456    {
 457        debug_assert!(
 458            self.hover_listener.is_none(),
 459            "calling on_hover more than once on the same element is not supported"
 460        );
 461        self.hover_listener = Some(Box::new(listener));
 462    }
 463
 464    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 465    /// The imperative API equivalent to [`InteractiveElement::tooltip`]
 466    pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static)
 467    where
 468        Self: Sized,
 469    {
 470        debug_assert!(
 471            self.tooltip_builder.is_none(),
 472            "calling tooltip more than once on the same element is not supported"
 473        );
 474        self.tooltip_builder = Some(Rc::new(build_tooltip));
 475    }
 476
 477    /// Block the mouse from interacting with this element or any of its children
 478    /// The imperative API equivalent to [`InteractiveElement::block_mouse`]
 479    pub fn occlude_mouse(&mut self) {
 480        self.occlude_mouse = true;
 481    }
 482}
 483
 484/// A trait for elements that want to use the standard GPUI event handlers that don't
 485/// require any state.
 486pub trait InteractiveElement: Sized {
 487    /// Retrieve the interactivity state associated with this element
 488    fn interactivity(&mut self) -> &mut Interactivity;
 489
 490    /// Assign this element to a group of elements that can be styled together
 491    fn group(mut self, group: impl Into<SharedString>) -> Self {
 492        self.interactivity().group = Some(group.into());
 493        self
 494    }
 495
 496    /// Assign this element an ID, so that it can be used with interactivity
 497    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
 498        self.interactivity().element_id = Some(id.into());
 499
 500        Stateful { element: self }
 501    }
 502
 503    /// Track the focus state of the given focus handle on this element.
 504    /// If the focus handle is focused by the application, this element will
 505    /// apply its focused styles.
 506    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<Self> {
 507        self.interactivity().focusable = true;
 508        self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
 509        Focusable { element: self }
 510    }
 511
 512    /// Set the keymap context for this element. This will be used to determine
 513    /// which action to dispatch from the keymap.
 514    fn key_context<C, E>(mut self, key_context: C) -> Self
 515    where
 516        C: TryInto<KeyContext, Error = E>,
 517        E: Debug,
 518    {
 519        if let Some(key_context) = key_context.try_into().log_err() {
 520            self.interactivity().key_context = Some(key_context);
 521        }
 522        self
 523    }
 524
 525    /// Apply the given style to this element when the mouse hovers over it
 526    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 527        debug_assert!(
 528            self.interactivity().hover_style.is_none(),
 529            "hover style already set"
 530        );
 531        self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
 532        self
 533    }
 534
 535    /// Apply the given style to this element when the mouse hovers over a group member
 536    fn group_hover(
 537        mut self,
 538        group_name: impl Into<SharedString>,
 539        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 540    ) -> Self {
 541        self.interactivity().group_hover_style = Some(GroupStyle {
 542            group: group_name.into(),
 543            style: Box::new(f(StyleRefinement::default())),
 544        });
 545        self
 546    }
 547
 548    /// Bind the given callback to the mouse down event for the given mouse button,
 549    /// the fluent API equivalent to [`Interactivity::on_mouse_down`]
 550    ///
 551    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to the view state from this callback.
 552    fn on_mouse_down(
 553        mut self,
 554        button: MouseButton,
 555        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 556    ) -> Self {
 557        self.interactivity().on_mouse_down(button, listener);
 558        self
 559    }
 560
 561    #[cfg(any(test, feature = "test-support"))]
 562    /// Set a key that can be used to look up this element's bounds
 563    /// in the [`VisualTestContext::debug_bounds`] map
 564    /// This is a noop in release builds
 565    fn debug_selector(mut self, f: impl FnOnce() -> String) -> Self {
 566        self.interactivity().debug_selector = Some(f());
 567        self
 568    }
 569
 570    #[cfg(not(any(test, feature = "test-support")))]
 571    /// Set a key that can be used to look up this element's bounds
 572    /// in the [`VisualTestContext::debug_bounds`] map
 573    /// This is a noop in release builds
 574    #[inline]
 575    fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
 576        self
 577    }
 578
 579    /// Bind the given callback to the mouse down event for any button, during the capture phase
 580    /// the fluent API equivalent to [`Interactivity::capture_any_mouse_down`]
 581    ///
 582    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 583    fn capture_any_mouse_down(
 584        mut self,
 585        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 586    ) -> Self {
 587        self.interactivity().capture_any_mouse_down(listener);
 588        self
 589    }
 590
 591    /// Bind the given callback to the mouse down event for any button, during the capture phase
 592    /// the fluent API equivalent to [`Interactivity::on_any_mouse_down`]
 593    ///
 594    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 595    fn on_any_mouse_down(
 596        mut self,
 597        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 598    ) -> Self {
 599        self.interactivity().on_any_mouse_down(listener);
 600        self
 601    }
 602
 603    /// Bind the given callback to the mouse up event for the given button, during the bubble phase
 604    /// the fluent API equivalent to [`Interactivity::on_mouse_up`]
 605    ///
 606    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 607    fn on_mouse_up(
 608        mut self,
 609        button: MouseButton,
 610        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 611    ) -> Self {
 612        self.interactivity().on_mouse_up(button, listener);
 613        self
 614    }
 615
 616    /// Bind the given callback to the mouse up event for any button, during the capture phase
 617    /// the fluent API equivalent to [`Interactivity::capture_any_mouse_up`]
 618    ///
 619    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 620    fn capture_any_mouse_up(
 621        mut self,
 622        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 623    ) -> Self {
 624        self.interactivity().capture_any_mouse_up(listener);
 625        self
 626    }
 627
 628    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 629    /// when the mouse is outside of the bounds of this element.
 630    /// The fluent API equivalent to [`Interactivity::on_mouse_down_out`]
 631    ///
 632    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 633    fn on_mouse_down_out(
 634        mut self,
 635        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 636    ) -> Self {
 637        self.interactivity().on_mouse_down_out(listener);
 638        self
 639    }
 640
 641    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 642    /// when the mouse is outside of the bounds of this element.
 643    /// The fluent API equivalent to [`Interactivity::on_mouse_up_out`]
 644    ///
 645    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 646    fn on_mouse_up_out(
 647        mut self,
 648        button: MouseButton,
 649        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 650    ) -> Self {
 651        self.interactivity().on_mouse_up_out(button, listener);
 652        self
 653    }
 654
 655    /// Bind the given callback to the mouse move event, during the bubble phase
 656    /// The fluent API equivalent to [`Interactivity::on_mouse_move`]
 657    ///
 658    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 659    fn on_mouse_move(
 660        mut self,
 661        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 662    ) -> Self {
 663        self.interactivity().on_mouse_move(listener);
 664        self
 665    }
 666
 667    /// Bind the given callback to the mouse drag event of the given type. Note that this
 668    /// will be called for all move events, inside or outside of this element, as long as the
 669    /// drag was started with this element under the mouse. Useful for implementing draggable
 670    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 671    /// The fluent API equivalent to [`Interactivity::on_drag_move`]
 672    ///
 673    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 674    fn on_drag_move<T: 'static>(
 675        mut self,
 676        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 677    ) -> Self
 678    where
 679        T: 'static,
 680    {
 681        self.interactivity().on_drag_move(listener);
 682        self
 683    }
 684
 685    /// Bind the given callback to scroll wheel events during the bubble phase
 686    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`]
 687    ///
 688    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 689    fn on_scroll_wheel(
 690        mut self,
 691        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 692    ) -> Self {
 693        self.interactivity().on_scroll_wheel(listener);
 694        self
 695    }
 696
 697    /// Capture the given action, before normal action dispatch can fire
 698    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`]
 699    ///
 700    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 701    fn capture_action<A: Action>(
 702        mut self,
 703        listener: impl Fn(&A, &mut WindowContext) + 'static,
 704    ) -> Self {
 705        self.interactivity().capture_action(listener);
 706        self
 707    }
 708
 709    /// Bind the given callback to an action dispatch during the bubble phase
 710    /// The fluent API equivalent to [`Interactivity::on_action`]
 711    ///
 712    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 713    fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
 714        self.interactivity().on_action(listener);
 715        self
 716    }
 717
 718    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 719    /// instead of a type parameter. Useful for component libraries that want to expose
 720    /// action bindings to their users.
 721    /// The fluent API equivalent to [`Interactivity::on_boxed_action`]
 722    ///
 723    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 724    fn on_boxed_action(
 725        mut self,
 726        action: &dyn Action,
 727        listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
 728    ) -> Self {
 729        self.interactivity().on_boxed_action(action, listener);
 730        self
 731    }
 732
 733    /// Bind the given callback to key down events during the bubble phase
 734    /// The fluent API equivalent to [`Interactivity::on_key_down`]
 735    ///
 736    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 737    fn on_key_down(
 738        mut self,
 739        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 740    ) -> Self {
 741        self.interactivity().on_key_down(listener);
 742        self
 743    }
 744
 745    /// Bind the given callback to key down events during the capture phase
 746    /// The fluent API equivalent to [`Interactivity::capture_key_down`]
 747    ///
 748    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 749    fn capture_key_down(
 750        mut self,
 751        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 752    ) -> Self {
 753        self.interactivity().capture_key_down(listener);
 754        self
 755    }
 756
 757    /// Bind the given callback to key up events during the bubble phase
 758    /// The fluent API equivalent to [`Interactivity::on_key_up`]
 759    ///
 760    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 761    fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
 762        self.interactivity().on_key_up(listener);
 763        self
 764    }
 765
 766    /// Bind the given callback to key up events during the capture phase
 767    /// The fluent API equivalent to [`Interactivity::capture_key_up`]
 768    ///
 769    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 770    fn capture_key_up(
 771        mut self,
 772        listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
 773    ) -> Self {
 774        self.interactivity().capture_key_up(listener);
 775        self
 776    }
 777
 778    /// Apply the given style when the given data type is dragged over this element
 779    fn drag_over<S: 'static>(
 780        mut self,
 781        f: impl 'static + Fn(StyleRefinement, &S, &WindowContext) -> StyleRefinement,
 782    ) -> Self {
 783        self.interactivity().drag_over_styles.push((
 784            TypeId::of::<S>(),
 785            Box::new(move |currently_dragged: &dyn Any, cx| {
 786                f(
 787                    StyleRefinement::default(),
 788                    currently_dragged.downcast_ref::<S>().unwrap(),
 789                    cx,
 790                )
 791            }),
 792        ));
 793        self
 794    }
 795
 796    /// Apply the given style when the given data type is dragged over this element's group
 797    fn group_drag_over<S: 'static>(
 798        mut self,
 799        group_name: impl Into<SharedString>,
 800        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 801    ) -> Self {
 802        self.interactivity().group_drag_over_styles.push((
 803            TypeId::of::<S>(),
 804            GroupStyle {
 805                group: group_name.into(),
 806                style: Box::new(f(StyleRefinement::default())),
 807            },
 808        ));
 809        self
 810    }
 811
 812    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element
 813    /// The fluent API equivalent to [`Interactivity::on_drop`]
 814    ///
 815    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 816    fn on_drop<T: 'static>(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self {
 817        self.interactivity().on_drop(listener);
 818        self
 819    }
 820
 821    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element
 822    /// The fluent API equivalent to [`Interactivity::can_drop`]
 823    fn can_drop(
 824        mut self,
 825        predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static,
 826    ) -> Self {
 827        self.interactivity().can_drop(predicate);
 828        self
 829    }
 830
 831    /// Block the mouse from interacting with this element or any of its children
 832    /// The fluent API equivalent to [`Interactivity::block_mouse`]
 833    fn occlude(mut self) -> Self {
 834        self.interactivity().occlude_mouse();
 835        self
 836    }
 837}
 838
 839/// A trait for elements that want to use the standard GPUI interactivity features
 840/// that require state.
 841pub trait StatefulInteractiveElement: InteractiveElement {
 842    /// Set this element to focusable.
 843    fn focusable(mut self) -> Focusable<Self> {
 844        self.interactivity().focusable = true;
 845        Focusable { element: self }
 846    }
 847
 848    /// Set the overflow x and y to scroll.
 849    fn overflow_scroll(mut self) -> Self {
 850        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 851        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 852        self
 853    }
 854
 855    /// Set the overflow x to scroll.
 856    fn overflow_x_scroll(mut self) -> Self {
 857        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 858        self
 859    }
 860
 861    /// Set the overflow y to scroll.
 862    fn overflow_y_scroll(mut self) -> Self {
 863        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 864        self
 865    }
 866
 867    /// Track the scroll state of this element with the given handle.
 868    fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
 869        self.interactivity().tracked_scroll_handle = Some(scroll_handle.clone());
 870        self
 871    }
 872
 873    /// Set the given styles to be applied when this element is active.
 874    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 875    where
 876        Self: Sized,
 877    {
 878        self.interactivity().active_style = Some(Box::new(f(StyleRefinement::default())));
 879        self
 880    }
 881
 882    /// Set the given styles to be applied when this element's group is active.
 883    fn group_active(
 884        mut self,
 885        group_name: impl Into<SharedString>,
 886        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 887    ) -> Self
 888    where
 889        Self: Sized,
 890    {
 891        self.interactivity().group_active_style = Some(GroupStyle {
 892            group: group_name.into(),
 893            style: Box::new(f(StyleRefinement::default())),
 894        });
 895        self
 896    }
 897
 898    /// Bind the given callback to click events of this element
 899    /// The fluent API equivalent to [`Interactivity::on_click`]
 900    ///
 901    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 902    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self
 903    where
 904        Self: Sized,
 905    {
 906        self.interactivity().on_click(listener);
 907        self
 908    }
 909
 910    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 911    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 912    /// the [`Self::on_drag_move`] API
 913    /// The fluent API equivalent to [`Interactivity::on_drag`]
 914    ///
 915    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 916    fn on_drag<T, W>(
 917        mut self,
 918        value: T,
 919        constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
 920    ) -> Self
 921    where
 922        Self: Sized,
 923        T: 'static,
 924        W: 'static + Render,
 925    {
 926        self.interactivity().on_drag(value, constructor);
 927        self
 928    }
 929
 930    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 931    /// passed to the callback is true when the hover starts and false when it ends.
 932    /// The fluent API equivalent to [`Interactivity::on_hover`]
 933    ///
 934    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 935    fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self
 936    where
 937        Self: Sized,
 938    {
 939        self.interactivity().on_hover(listener);
 940        self
 941    }
 942
 943    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 944    /// The fluent API equivalent to [`Interactivity::tooltip`]
 945    fn tooltip(mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self
 946    where
 947        Self: Sized,
 948    {
 949        self.interactivity().tooltip(build_tooltip);
 950        self
 951    }
 952}
 953
 954/// A trait for providing focus related APIs to interactive elements
 955pub trait FocusableElement: InteractiveElement {
 956    /// Set the given styles to be applied when this element, specifically, is focused.
 957    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 958    where
 959        Self: Sized,
 960    {
 961        self.interactivity().focus_style = Some(Box::new(f(StyleRefinement::default())));
 962        self
 963    }
 964
 965    /// Set the given styles to be applied when this element is inside another element that is focused.
 966    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 967    where
 968        Self: Sized,
 969    {
 970        self.interactivity().in_focus_style = Some(Box::new(f(StyleRefinement::default())));
 971        self
 972    }
 973}
 974
 975pub(crate) type MouseDownListener =
 976    Box<dyn Fn(&MouseDownEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
 977pub(crate) type MouseUpListener =
 978    Box<dyn Fn(&MouseUpEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
 979
 980pub(crate) type MouseMoveListener =
 981    Box<dyn Fn(&MouseMoveEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
 982
 983pub(crate) type ScrollWheelListener =
 984    Box<dyn Fn(&ScrollWheelEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
 985
 986pub(crate) type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
 987
 988pub(crate) type DragListener = Box<dyn Fn(&dyn Any, &mut WindowContext) -> AnyView + 'static>;
 989
 990type DropListener = Box<dyn Fn(&dyn Any, &mut WindowContext) + 'static>;
 991
 992type CanDropPredicate = Box<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>;
 993
 994pub(crate) type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>;
 995
 996pub(crate) type KeyDownListener =
 997    Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
 998
 999pub(crate) type KeyUpListener =
1000    Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + 'static>;
1001
1002pub(crate) type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
1003
1004/// Construct a new [`Div`] element
1005#[track_caller]
1006pub fn div() -> Div {
1007    #[cfg(debug_assertions)]
1008    let interactivity = Interactivity {
1009        location: Some(*core::panic::Location::caller()),
1010        ..Default::default()
1011    };
1012
1013    #[cfg(not(debug_assertions))]
1014    let interactivity = Interactivity::default();
1015
1016    Div {
1017        interactivity,
1018        children: SmallVec::default(),
1019    }
1020}
1021
1022/// A [`Div`] element, the all-in-one element for building complex UIs in GPUI
1023pub struct Div {
1024    interactivity: Interactivity,
1025    children: SmallVec<[AnyElement; 2]>,
1026}
1027
1028/// A frame state for a `Div` element, which contains layout IDs for its children.
1029///
1030/// This struct is used internally by the `Div` element to manage the layout state of its children
1031/// during the UI update cycle. It holds a small vector of `LayoutId` values, each corresponding to
1032/// a child element of the `Div`. These IDs are used to query the layout engine for the computed
1033/// bounds of the children after the layout phase is complete.
1034pub struct DivFrameState {
1035    child_layout_ids: SmallVec<[LayoutId; 2]>,
1036}
1037
1038impl Styled for Div {
1039    fn style(&mut self) -> &mut StyleRefinement {
1040        &mut self.interactivity.base_style
1041    }
1042}
1043
1044impl InteractiveElement for Div {
1045    fn interactivity(&mut self) -> &mut Interactivity {
1046        &mut self.interactivity
1047    }
1048}
1049
1050impl ParentElement for Div {
1051    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
1052        self.children.extend(elements)
1053    }
1054}
1055
1056impl Element for Div {
1057    type BeforeLayout = DivFrameState;
1058    type AfterLayout = Option<Hitbox>;
1059
1060    fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
1061        let mut child_layout_ids = SmallVec::new();
1062        let layout_id = self.interactivity.before_layout(cx, |style, cx| {
1063            cx.with_text_style(style.text_style().cloned(), |cx| {
1064                child_layout_ids = self
1065                    .children
1066                    .iter_mut()
1067                    .map(|child| child.before_layout(cx))
1068                    .collect::<SmallVec<_>>();
1069                cx.request_layout(&style, child_layout_ids.iter().copied())
1070            })
1071        });
1072        (layout_id, DivFrameState { child_layout_ids })
1073    }
1074
1075    fn after_layout(
1076        &mut self,
1077        bounds: Bounds<Pixels>,
1078        before_layout: &mut Self::BeforeLayout,
1079        cx: &mut ElementContext,
1080    ) -> Option<Hitbox> {
1081        let mut child_min = point(Pixels::MAX, Pixels::MAX);
1082        let mut child_max = Point::default();
1083        let content_size = if before_layout.child_layout_ids.is_empty() {
1084            bounds.size
1085        } else if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1086            let mut state = scroll_handle.0.borrow_mut();
1087            state.child_bounds = Vec::with_capacity(before_layout.child_layout_ids.len());
1088            state.bounds = bounds;
1089            let requested = state.requested_scroll_top.take();
1090
1091            for (ix, child_layout_id) in before_layout.child_layout_ids.iter().enumerate() {
1092                let child_bounds = cx.layout_bounds(*child_layout_id);
1093                child_min = child_min.min(&child_bounds.origin);
1094                child_max = child_max.max(&child_bounds.lower_right());
1095                state.child_bounds.push(child_bounds);
1096
1097                if let Some(requested) = requested.as_ref() {
1098                    if requested.0 == ix {
1099                        *state.offset.borrow_mut() =
1100                            bounds.origin - (child_bounds.origin - point(px(0.), requested.1));
1101                    }
1102                }
1103            }
1104            (child_max - child_min).into()
1105        } else {
1106            for child_layout_id in &before_layout.child_layout_ids {
1107                let child_bounds = cx.layout_bounds(*child_layout_id);
1108                child_min = child_min.min(&child_bounds.origin);
1109                child_max = child_max.max(&child_bounds.lower_right());
1110            }
1111            (child_max - child_min).into()
1112        };
1113
1114        self.interactivity.after_layout(
1115            bounds,
1116            content_size,
1117            cx,
1118            |_style, scroll_offset, hitbox, cx| {
1119                cx.with_element_offset(scroll_offset, |cx| {
1120                    for child in &mut self.children {
1121                        child.after_layout(cx);
1122                    }
1123                });
1124                hitbox
1125            },
1126        )
1127    }
1128
1129    fn paint(
1130        &mut self,
1131        bounds: Bounds<Pixels>,
1132        _before_layout: &mut Self::BeforeLayout,
1133        hitbox: &mut Option<Hitbox>,
1134        cx: &mut ElementContext,
1135    ) {
1136        self.interactivity
1137            .paint(bounds, hitbox.as_ref(), cx, |_style, cx| {
1138                for child in &mut self.children {
1139                    child.paint(cx);
1140                }
1141            });
1142    }
1143}
1144
1145impl IntoElement for Div {
1146    type Element = Self;
1147
1148    fn into_element(self) -> Self::Element {
1149        self
1150    }
1151}
1152
1153/// The interactivity struct. Powers all of the general-purpose
1154/// interactivity in the `Div` element.
1155#[derive(Default)]
1156pub struct Interactivity {
1157    /// The element ID of the element
1158    pub element_id: Option<ElementId>,
1159    /// Whether the element was clicked. This will only be present after layout.
1160    pub active: Option<bool>,
1161    /// Whether the element was hovered. This will only be present after paint if an hitbox
1162    /// was created for the interactive element.
1163    pub hovered: Option<bool>,
1164    pub(crate) content_size: Size<Pixels>,
1165    pub(crate) key_context: Option<KeyContext>,
1166    pub(crate) focusable: bool,
1167    pub(crate) tracked_focus_handle: Option<FocusHandle>,
1168    pub(crate) tracked_scroll_handle: Option<ScrollHandle>,
1169    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
1170    pub(crate) group: Option<SharedString>,
1171    /// The base style of the element, before any modifications are applied
1172    /// by focus, active, etc.
1173    pub base_style: Box<StyleRefinement>,
1174    pub(crate) focus_style: Option<Box<StyleRefinement>>,
1175    pub(crate) in_focus_style: Option<Box<StyleRefinement>>,
1176    pub(crate) hover_style: Option<Box<StyleRefinement>>,
1177    pub(crate) group_hover_style: Option<GroupStyle>,
1178    pub(crate) active_style: Option<Box<StyleRefinement>>,
1179    pub(crate) group_active_style: Option<GroupStyle>,
1180    pub(crate) drag_over_styles: Vec<(
1181        TypeId,
1182        Box<dyn Fn(&dyn Any, &mut WindowContext) -> StyleRefinement>,
1183    )>,
1184    pub(crate) group_drag_over_styles: Vec<(TypeId, GroupStyle)>,
1185    pub(crate) mouse_down_listeners: Vec<MouseDownListener>,
1186    pub(crate) mouse_up_listeners: Vec<MouseUpListener>,
1187    pub(crate) mouse_move_listeners: Vec<MouseMoveListener>,
1188    pub(crate) scroll_wheel_listeners: Vec<ScrollWheelListener>,
1189    pub(crate) key_down_listeners: Vec<KeyDownListener>,
1190    pub(crate) key_up_listeners: Vec<KeyUpListener>,
1191    pub(crate) action_listeners: Vec<(TypeId, ActionListener)>,
1192    pub(crate) drop_listeners: Vec<(TypeId, DropListener)>,
1193    pub(crate) can_drop_predicate: Option<CanDropPredicate>,
1194    pub(crate) click_listeners: Vec<ClickListener>,
1195    pub(crate) drag_listener: Option<(Box<dyn Any>, DragListener)>,
1196    pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
1197    pub(crate) tooltip_builder: Option<TooltipBuilder>,
1198    pub(crate) occlude_mouse: bool,
1199
1200    #[cfg(debug_assertions)]
1201    pub(crate) location: Option<core::panic::Location<'static>>,
1202
1203    #[cfg(any(test, feature = "test-support"))]
1204    pub(crate) debug_selector: Option<String>,
1205}
1206
1207impl Interactivity {
1208    /// Layout this element according to this interactivity state's configured styles
1209    pub fn before_layout(
1210        &mut self,
1211        cx: &mut ElementContext,
1212        f: impl FnOnce(Style, &mut ElementContext) -> LayoutId,
1213    ) -> LayoutId {
1214        cx.with_element_state::<InteractiveElementState, _>(
1215            self.element_id.clone(),
1216            |element_state, cx| {
1217                let mut element_state =
1218                    element_state.map(|element_state| element_state.unwrap_or_default());
1219
1220                if let Some(element_state) = element_state.as_ref() {
1221                    if cx.has_active_drag() {
1222                        if let Some(pending_mouse_down) = element_state.pending_mouse_down.as_ref()
1223                        {
1224                            *pending_mouse_down.borrow_mut() = None;
1225                        }
1226                        if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1227                            *clicked_state.borrow_mut() = ElementClickedState::default();
1228                        }
1229                    }
1230                }
1231
1232                // Ensure we store a focus handle in our element state if we're focusable.
1233                // If there's an explicit focus handle we're tracking, use that. Otherwise
1234                // create a new handle and store it in the element state, which lives for as
1235                // as frames contain an element with this id.
1236                if self.focusable {
1237                    if self.tracked_focus_handle.is_none() {
1238                        if let Some(element_state) = element_state.as_mut() {
1239                            self.tracked_focus_handle = Some(
1240                                element_state
1241                                    .focus_handle
1242                                    .get_or_insert_with(|| cx.focus_handle())
1243                                    .clone(),
1244                            );
1245                        }
1246                    }
1247                }
1248
1249                if let Some(scroll_handle) = self.tracked_scroll_handle.as_ref() {
1250                    self.scroll_offset = Some(scroll_handle.0.borrow().offset.clone());
1251                } else if self.base_style.overflow.x == Some(Overflow::Scroll)
1252                    || self.base_style.overflow.y == Some(Overflow::Scroll)
1253                {
1254                    if let Some(element_state) = element_state.as_mut() {
1255                        self.scroll_offset = Some(
1256                            element_state
1257                                .scroll_offset
1258                                .get_or_insert_with(|| Rc::default())
1259                                .clone(),
1260                        );
1261                    }
1262                }
1263
1264                let style = self.compute_style_internal(None, element_state.as_mut(), cx);
1265                let layout_id = f(style, cx);
1266                (layout_id, element_state)
1267            },
1268        )
1269    }
1270
1271    /// Commit the bounds of this element according to this interactivity state's configured styles.
1272    pub fn after_layout<R>(
1273        &mut self,
1274        bounds: Bounds<Pixels>,
1275        content_size: Size<Pixels>,
1276        cx: &mut ElementContext,
1277        f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut ElementContext) -> R,
1278    ) -> R {
1279        self.content_size = content_size;
1280        cx.with_element_state::<InteractiveElementState, _>(
1281            self.element_id.clone(),
1282            |element_state, cx| {
1283                let mut element_state =
1284                    element_state.map(|element_state| element_state.unwrap_or_default());
1285                let style = self.compute_style_internal(None, element_state.as_mut(), cx);
1286
1287                if let Some(element_state) = element_state.as_ref() {
1288                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1289                        let clicked_state = clicked_state.borrow();
1290                        self.active = Some(clicked_state.element);
1291                    }
1292
1293                    if let Some(active_tooltip) = element_state.active_tooltip.as_ref() {
1294                        if let Some(active_tooltip) = active_tooltip.borrow().as_ref() {
1295                            if let Some(tooltip) = active_tooltip.tooltip.clone() {
1296                                cx.set_tooltip(tooltip);
1297                            }
1298                        }
1299                    }
1300                }
1301
1302                cx.with_text_style(style.text_style().cloned(), |cx| {
1303                    cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
1304                        let hitbox = if self.occlude_mouse
1305                            || style.mouse_cursor.is_some()
1306                            || self.group.is_some()
1307                            || self.has_hover_styles()
1308                            || self.has_mouse_listeners()
1309                            || self.scroll_offset.is_some()
1310                            || self.tracked_focus_handle.is_some()
1311                        {
1312                            Some(cx.insert_hitbox(bounds, self.occlude_mouse))
1313                        } else {
1314                            None
1315                        };
1316
1317                        let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
1318                        let result = f(&style, scroll_offset, hitbox, cx);
1319                        (result, element_state)
1320                    })
1321                })
1322            },
1323        )
1324    }
1325
1326    fn has_hover_styles(&self) -> bool {
1327        self.hover_style.is_some() || self.group_hover_style.is_some()
1328    }
1329
1330    fn has_mouse_listeners(&self) -> bool {
1331        !self.mouse_up_listeners.is_empty()
1332            || !self.mouse_down_listeners.is_empty()
1333            || !self.mouse_move_listeners.is_empty()
1334            || !self.click_listeners.is_empty()
1335            || !self.scroll_wheel_listeners.is_empty()
1336            || self.drag_listener.is_some()
1337            || !self.drop_listeners.is_empty()
1338    }
1339
1340    fn clamp_scroll_position(
1341        &mut self,
1342        bounds: Bounds<Pixels>,
1343        style: &Style,
1344        cx: &mut ElementContext,
1345    ) -> Point<Pixels> {
1346        if let Some(scroll_offset) = self.scroll_offset.as_ref() {
1347            if let Some(scroll_handle) = &self.tracked_scroll_handle {
1348                scroll_handle.0.borrow_mut().overflow = style.overflow;
1349            }
1350
1351            let rem_size = cx.rem_size();
1352            let padding_size = size(
1353                style
1354                    .padding
1355                    .left
1356                    .to_pixels(bounds.size.width.into(), rem_size)
1357                    + style
1358                        .padding
1359                        .right
1360                        .to_pixels(bounds.size.width.into(), rem_size),
1361                style
1362                    .padding
1363                    .top
1364                    .to_pixels(bounds.size.height.into(), rem_size)
1365                    + style
1366                        .padding
1367                        .bottom
1368                        .to_pixels(bounds.size.height.into(), rem_size),
1369            );
1370            let scroll_max = (self.content_size + padding_size - bounds.size).max(&Size::default());
1371            // Clamp scroll offset in case scroll max is smaller now (e.g., if children
1372            // were removed or the bounds became larger).
1373            let mut scroll_offset = scroll_offset.borrow_mut();
1374            scroll_offset.x = scroll_offset.x.clamp(-scroll_max.width, px(0.));
1375            scroll_offset.y = scroll_offset.y.clamp(-scroll_max.height, px(0.));
1376            *scroll_offset
1377        } else {
1378            Point::default()
1379        }
1380    }
1381
1382    /// Paint this element according to this interactivity state's configured styles
1383    /// and bind the element's mouse and keyboard events.
1384    ///
1385    /// content_size is the size of the content of the element, which may be larger than the
1386    /// element's bounds if the element is scrollable.
1387    ///
1388    /// the final computed style will be passed to the provided function, along
1389    /// with the current scroll offset
1390    pub fn paint(
1391        &mut self,
1392        bounds: Bounds<Pixels>,
1393        hitbox: Option<&Hitbox>,
1394        cx: &mut ElementContext,
1395        f: impl FnOnce(&Style, &mut ElementContext),
1396    ) {
1397        self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(cx));
1398        cx.with_element_state::<InteractiveElementState, _>(
1399            self.element_id.clone(),
1400            |element_state, cx| {
1401                let mut element_state =
1402                    element_state.map(|element_state| element_state.unwrap_or_default());
1403
1404                let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
1405
1406                #[cfg(any(feature = "test-support", test))]
1407                if let Some(debug_selector) = &self.debug_selector {
1408                    cx.window
1409                        .next_frame
1410                        .debug_bounds
1411                        .insert(debug_selector.clone(), bounds);
1412                }
1413
1414                self.paint_hover_group_handler(cx);
1415
1416                if style.visibility == Visibility::Hidden {
1417                    return ((), element_state);
1418                }
1419
1420                style.paint(bounds, cx, |cx: &mut ElementContext| {
1421                    cx.with_text_style(style.text_style().cloned(), |cx| {
1422                        cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
1423                            if let Some(hitbox) = hitbox {
1424                                #[cfg(debug_assertions)]
1425                                self.paint_debug_info(hitbox, &style, cx);
1426
1427                                if !cx.has_active_drag() {
1428                                    if let Some(mouse_cursor) = style.mouse_cursor {
1429                                        cx.set_cursor_style(mouse_cursor, hitbox);
1430                                    }
1431                                }
1432
1433                                if let Some(group) = self.group.clone() {
1434                                    GroupHitboxes::push(group, hitbox.id, cx);
1435                                }
1436
1437                                self.paint_mouse_listeners(hitbox, element_state.as_mut(), cx);
1438                                self.paint_scroll_listener(hitbox, &style, cx);
1439                            }
1440
1441                            self.paint_keyboard_listeners(cx);
1442                            f(&style, cx);
1443
1444                            if hitbox.is_some() {
1445                                if let Some(group) = self.group.as_ref() {
1446                                    GroupHitboxes::pop(group, cx);
1447                                }
1448                            }
1449                        });
1450                    });
1451                });
1452
1453                ((), element_state)
1454            },
1455        );
1456    }
1457
1458    #[cfg(debug_assertions)]
1459    fn paint_debug_info(&mut self, hitbox: &Hitbox, style: &Style, cx: &mut ElementContext) {
1460        if self.element_id.is_some()
1461            && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
1462            && hitbox.is_hovered(cx)
1463        {
1464            const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
1465            let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
1466            let str_len = element_id.len();
1467
1468            let render_debug_text = |cx: &mut ElementContext| {
1469                if let Some(text) = cx
1470                    .text_system()
1471                    .shape_text(
1472                        element_id.into(),
1473                        FONT_SIZE,
1474                        &[cx.text_style().to_run(str_len)],
1475                        None,
1476                    )
1477                    .ok()
1478                    .and_then(|mut text| text.pop())
1479                {
1480                    text.paint(hitbox.origin, FONT_SIZE, cx).ok();
1481
1482                    let text_bounds = crate::Bounds {
1483                        origin: hitbox.origin,
1484                        size: text.size(FONT_SIZE),
1485                    };
1486                    if self.location.is_some()
1487                        && text_bounds.contains(&cx.mouse_position())
1488                        && cx.modifiers().command
1489                    {
1490                        let command_held = cx.modifiers().command;
1491                        cx.on_key_event({
1492                            move |e: &crate::ModifiersChangedEvent, _phase, cx| {
1493                                if e.modifiers.command != command_held
1494                                    && text_bounds.contains(&cx.mouse_position())
1495                                {
1496                                    cx.refresh();
1497                                }
1498                            }
1499                        });
1500
1501                        let was_hovered = hitbox.is_hovered(cx);
1502                        cx.on_mouse_event({
1503                            let hitbox = hitbox.clone();
1504                            move |_: &MouseMoveEvent, phase, cx| {
1505                                if phase == DispatchPhase::Capture {
1506                                    let hovered = hitbox.is_hovered(cx);
1507                                    if hovered != was_hovered {
1508                                        cx.refresh();
1509                                    }
1510                                }
1511                            }
1512                        });
1513
1514                        cx.on_mouse_event({
1515                            let hitbox = hitbox.clone();
1516                            let location = self.location.unwrap();
1517                            move |e: &crate::MouseDownEvent, phase, cx| {
1518                                if text_bounds.contains(&e.position)
1519                                    && phase.capture()
1520                                    && hitbox.is_hovered(cx)
1521                                {
1522                                    cx.stop_propagation();
1523                                    let Ok(dir) = std::env::current_dir() else {
1524                                        return;
1525                                    };
1526
1527                                    eprintln!(
1528                                        "This element was created at:\n{}:{}:{}",
1529                                        dir.join(location.file()).to_string_lossy(),
1530                                        location.line(),
1531                                        location.column()
1532                                    );
1533                                }
1534                            }
1535                        });
1536                        cx.paint_quad(crate::outline(
1537                            crate::Bounds {
1538                                origin: hitbox.origin
1539                                    + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
1540                                size: crate::Size {
1541                                    width: text_bounds.size.width,
1542                                    height: crate::px(1.),
1543                                },
1544                            },
1545                            crate::red(),
1546                        ))
1547                    }
1548                }
1549            };
1550
1551            cx.with_text_style(
1552                Some(crate::TextStyleRefinement {
1553                    color: Some(crate::red()),
1554                    line_height: Some(FONT_SIZE.into()),
1555                    background_color: Some(crate::white()),
1556                    ..Default::default()
1557                }),
1558                render_debug_text,
1559            )
1560        }
1561    }
1562
1563    fn paint_mouse_listeners(
1564        &mut self,
1565        hitbox: &Hitbox,
1566        element_state: Option<&mut InteractiveElementState>,
1567        cx: &mut ElementContext,
1568    ) {
1569        // If this element can be focused, register a mouse down listener
1570        // that will automatically transfer focus when hitting the element.
1571        // This behavior can be suppressed by using `cx.prevent_default()`.
1572        if let Some(focus_handle) = self.tracked_focus_handle.clone() {
1573            let hitbox = hitbox.clone();
1574            cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1575                if phase == DispatchPhase::Bubble
1576                    && hitbox.is_hovered(cx)
1577                    && !cx.default_prevented()
1578                {
1579                    cx.focus(&focus_handle);
1580                    // If there is a parent that is also focusable, prevent it
1581                    // from transferring focus because we already did so.
1582                    cx.prevent_default();
1583                }
1584            });
1585        }
1586
1587        for listener in self.mouse_down_listeners.drain(..) {
1588            let hitbox = hitbox.clone();
1589            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
1590                listener(event, phase, &hitbox, cx);
1591            })
1592        }
1593
1594        for listener in self.mouse_up_listeners.drain(..) {
1595            let hitbox = hitbox.clone();
1596            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
1597                listener(event, phase, &hitbox, cx);
1598            })
1599        }
1600
1601        for listener in self.mouse_move_listeners.drain(..) {
1602            let hitbox = hitbox.clone();
1603            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1604                listener(event, phase, &hitbox, cx);
1605            })
1606        }
1607
1608        for listener in self.scroll_wheel_listeners.drain(..) {
1609            let hitbox = hitbox.clone();
1610            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1611                listener(event, phase, &hitbox, cx);
1612            })
1613        }
1614
1615        if self.hover_style.is_some()
1616            || self.base_style.mouse_cursor.is_some()
1617            || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
1618        {
1619            let hitbox = hitbox.clone();
1620            let was_hovered = hitbox.is_hovered(cx);
1621            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1622                let hovered = hitbox.is_hovered(cx);
1623                if phase == DispatchPhase::Capture && hovered != was_hovered {
1624                    cx.refresh();
1625                }
1626            });
1627        }
1628
1629        let mut drag_listener = mem::take(&mut self.drag_listener);
1630        let drop_listeners = mem::take(&mut self.drop_listeners);
1631        let click_listeners = mem::take(&mut self.click_listeners);
1632        let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
1633
1634        if !drop_listeners.is_empty() {
1635            let hitbox = hitbox.clone();
1636            cx.on_mouse_event({
1637                move |_: &MouseUpEvent, phase, cx| {
1638                    if let Some(drag) = &cx.active_drag {
1639                        if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
1640                            let drag_state_type = drag.value.as_ref().type_id();
1641                            for (drop_state_type, listener) in &drop_listeners {
1642                                if *drop_state_type == drag_state_type {
1643                                    let drag = cx
1644                                        .active_drag
1645                                        .take()
1646                                        .expect("checked for type drag state type above");
1647
1648                                    let mut can_drop = true;
1649                                    if let Some(predicate) = &can_drop_predicate {
1650                                        can_drop = predicate(drag.value.as_ref(), cx.deref_mut());
1651                                    }
1652
1653                                    if can_drop {
1654                                        listener(drag.value.as_ref(), cx.deref_mut());
1655                                        cx.refresh();
1656                                        cx.stop_propagation();
1657                                    }
1658                                }
1659                            }
1660                        }
1661                    }
1662                }
1663            });
1664        }
1665
1666        if let Some(element_state) = element_state {
1667            if !click_listeners.is_empty() || drag_listener.is_some() {
1668                let pending_mouse_down = element_state
1669                    .pending_mouse_down
1670                    .get_or_insert_with(Default::default)
1671                    .clone();
1672
1673                let clicked_state = element_state
1674                    .clicked_state
1675                    .get_or_insert_with(Default::default)
1676                    .clone();
1677
1678                cx.on_mouse_event({
1679                    let pending_mouse_down = pending_mouse_down.clone();
1680                    let hitbox = hitbox.clone();
1681                    move |event: &MouseDownEvent, phase, cx| {
1682                        if phase == DispatchPhase::Bubble
1683                            && event.button == MouseButton::Left
1684                            && hitbox.is_hovered(cx)
1685                        {
1686                            *pending_mouse_down.borrow_mut() = Some(event.clone());
1687                            cx.refresh();
1688                        }
1689                    }
1690                });
1691
1692                cx.on_mouse_event({
1693                    let pending_mouse_down = pending_mouse_down.clone();
1694                    let hitbox = hitbox.clone();
1695                    move |event: &MouseMoveEvent, phase, cx| {
1696                        if phase == DispatchPhase::Capture {
1697                            return;
1698                        }
1699
1700                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1701                        if let Some(mouse_down) = pending_mouse_down.clone() {
1702                            if !cx.has_active_drag()
1703                                && (event.position - mouse_down.position).magnitude()
1704                                    > DRAG_THRESHOLD
1705                            {
1706                                if let Some((drag_value, drag_listener)) = drag_listener.take() {
1707                                    *clicked_state.borrow_mut() = ElementClickedState::default();
1708                                    let cursor_offset = event.position - hitbox.origin;
1709                                    let drag = (drag_listener)(drag_value.as_ref(), cx);
1710                                    cx.active_drag = Some(AnyDrag {
1711                                        view: drag,
1712                                        value: drag_value,
1713                                        cursor_offset,
1714                                    });
1715                                    pending_mouse_down.take();
1716                                    cx.refresh();
1717                                    cx.stop_propagation();
1718                                }
1719                            }
1720                        }
1721                    }
1722                });
1723
1724                cx.on_mouse_event({
1725                    let mut captured_mouse_down = None;
1726                    let hitbox = hitbox.clone();
1727                    move |event: &MouseUpEvent, phase, cx| match phase {
1728                        // Clear the pending mouse down during the capture phase,
1729                        // so that it happens even if another event handler stops
1730                        // propagation.
1731                        DispatchPhase::Capture => {
1732                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1733                            if pending_mouse_down.is_some() && hitbox.is_hovered(cx) {
1734                                captured_mouse_down = pending_mouse_down.take();
1735                                cx.refresh();
1736                            }
1737                        }
1738                        // Fire click handlers during the bubble phase.
1739                        DispatchPhase::Bubble => {
1740                            if let Some(mouse_down) = captured_mouse_down.take() {
1741                                let mouse_click = ClickEvent {
1742                                    down: mouse_down,
1743                                    up: event.clone(),
1744                                };
1745                                for listener in &click_listeners {
1746                                    listener(&mouse_click, cx);
1747                                }
1748                            }
1749                        }
1750                    }
1751                });
1752            }
1753
1754            if let Some(hover_listener) = self.hover_listener.take() {
1755                let hitbox = hitbox.clone();
1756                let was_hovered = element_state
1757                    .hover_state
1758                    .get_or_insert_with(Default::default)
1759                    .clone();
1760                let has_mouse_down = element_state
1761                    .pending_mouse_down
1762                    .get_or_insert_with(Default::default)
1763                    .clone();
1764
1765                cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1766                    if phase != DispatchPhase::Bubble {
1767                        return;
1768                    }
1769                    let is_hovered = has_mouse_down.borrow().is_none()
1770                        && !cx.has_active_drag()
1771                        && hitbox.is_hovered(cx);
1772                    let mut was_hovered = was_hovered.borrow_mut();
1773
1774                    if is_hovered != *was_hovered {
1775                        *was_hovered = is_hovered;
1776                        drop(was_hovered);
1777
1778                        hover_listener(&is_hovered, cx.deref_mut());
1779                    }
1780                });
1781            }
1782
1783            if let Some(tooltip_builder) = self.tooltip_builder.take() {
1784                let active_tooltip = element_state
1785                    .active_tooltip
1786                    .get_or_insert_with(Default::default)
1787                    .clone();
1788                let pending_mouse_down = element_state
1789                    .pending_mouse_down
1790                    .get_or_insert_with(Default::default)
1791                    .clone();
1792                let hitbox = hitbox.clone();
1793
1794                cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1795                    let is_hovered = pending_mouse_down.borrow().is_none() && hitbox.is_hovered(cx);
1796                    if !is_hovered {
1797                        active_tooltip.borrow_mut().take();
1798                        return;
1799                    }
1800
1801                    if phase != DispatchPhase::Bubble {
1802                        return;
1803                    }
1804
1805                    if active_tooltip.borrow().is_none() {
1806                        let task = cx.spawn({
1807                            let active_tooltip = active_tooltip.clone();
1808                            let tooltip_builder = tooltip_builder.clone();
1809
1810                            move |mut cx| async move {
1811                                cx.background_executor().timer(TOOLTIP_DELAY).await;
1812                                cx.update(|cx| {
1813                                    active_tooltip.borrow_mut().replace(ActiveTooltip {
1814                                        tooltip: Some(AnyTooltip {
1815                                            view: tooltip_builder(cx),
1816                                            cursor_offset: cx.mouse_position(),
1817                                        }),
1818                                        _task: None,
1819                                    });
1820                                    cx.refresh();
1821                                })
1822                                .ok();
1823                            }
1824                        });
1825                        active_tooltip.borrow_mut().replace(ActiveTooltip {
1826                            tooltip: None,
1827                            _task: Some(task),
1828                        });
1829                    }
1830                });
1831
1832                let active_tooltip = element_state
1833                    .active_tooltip
1834                    .get_or_insert_with(Default::default)
1835                    .clone();
1836                cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
1837                    active_tooltip.borrow_mut().take();
1838                });
1839            }
1840
1841            let active_state = element_state
1842                .clicked_state
1843                .get_or_insert_with(Default::default)
1844                .clone();
1845            if active_state.borrow().is_clicked() {
1846                cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
1847                    if phase == DispatchPhase::Capture {
1848                        *active_state.borrow_mut() = ElementClickedState::default();
1849                        cx.refresh();
1850                    }
1851                });
1852            } else {
1853                let active_group_hitbox = self
1854                    .group_active_style
1855                    .as_ref()
1856                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
1857                let hitbox = hitbox.clone();
1858                cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1859                    if phase == DispatchPhase::Bubble && !cx.default_prevented() {
1860                        let group_hovered = active_group_hitbox
1861                            .map_or(false, |group_hitbox_id| group_hitbox_id.is_hovered(cx));
1862                        let element_hovered = hitbox.is_hovered(cx);
1863                        if group_hovered || element_hovered {
1864                            *active_state.borrow_mut() = ElementClickedState {
1865                                group: group_hovered,
1866                                element: element_hovered,
1867                            };
1868                            cx.refresh();
1869                        }
1870                    }
1871                });
1872            }
1873        }
1874    }
1875
1876    fn paint_keyboard_listeners(&mut self, cx: &mut ElementContext) {
1877        let key_down_listeners = mem::take(&mut self.key_down_listeners);
1878        let key_up_listeners = mem::take(&mut self.key_up_listeners);
1879        let action_listeners = mem::take(&mut self.action_listeners);
1880        if let Some(context) = self.key_context.clone() {
1881            cx.set_key_context(context);
1882        }
1883        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1884            cx.set_focus_handle(focus_handle);
1885        }
1886
1887        for listener in key_down_listeners {
1888            cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
1889                listener(event, phase, cx);
1890            })
1891        }
1892
1893        for listener in key_up_listeners {
1894            cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
1895                listener(event, phase, cx);
1896            })
1897        }
1898
1899        for (action_type, listener) in action_listeners {
1900            cx.on_action(action_type, listener)
1901        }
1902    }
1903
1904    fn paint_hover_group_handler(&self, cx: &mut ElementContext) {
1905        let group_hitbox = self
1906            .group_hover_style
1907            .as_ref()
1908            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
1909
1910        if let Some(group_hitbox) = group_hitbox {
1911            let was_hovered = group_hitbox.is_hovered(cx);
1912            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1913                let hovered = group_hitbox.is_hovered(cx);
1914                if phase == DispatchPhase::Capture && hovered != was_hovered {
1915                    cx.refresh();
1916                }
1917            });
1918        }
1919    }
1920
1921    fn paint_scroll_listener(&self, hitbox: &Hitbox, style: &Style, cx: &mut ElementContext) {
1922        if let Some(scroll_offset) = self.scroll_offset.clone() {
1923            let overflow = style.overflow;
1924            let line_height = cx.line_height();
1925            let hitbox = hitbox.clone();
1926            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1927                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
1928                    let mut scroll_offset = scroll_offset.borrow_mut();
1929                    let old_scroll_offset = *scroll_offset;
1930                    let delta = event.delta.pixel_delta(line_height);
1931
1932                    if overflow.x == Overflow::Scroll {
1933                        let mut delta_x = Pixels::ZERO;
1934                        if !delta.x.is_zero() {
1935                            delta_x = delta.x;
1936                        } else if overflow.y != Overflow::Scroll {
1937                            delta_x = delta.y;
1938                        }
1939
1940                        scroll_offset.x += delta_x;
1941                    }
1942
1943                    if overflow.y == Overflow::Scroll {
1944                        let mut delta_y = Pixels::ZERO;
1945                        if !delta.y.is_zero() {
1946                            delta_y = delta.y;
1947                        } else if overflow.x != Overflow::Scroll {
1948                            delta_y = delta.x;
1949                        }
1950
1951                        scroll_offset.y += delta_y;
1952                    }
1953
1954                    cx.stop_propagation();
1955                    if *scroll_offset != old_scroll_offset {
1956                        cx.refresh();
1957                    }
1958                }
1959            });
1960        }
1961    }
1962
1963    /// Compute the visual style for this element, based on the current bounds and the element's state.
1964    pub fn compute_style(&self, hitbox: Option<&Hitbox>, cx: &mut ElementContext) -> Style {
1965        cx.with_element_state(self.element_id.clone(), |element_state, cx| {
1966            let mut element_state =
1967                element_state.map(|element_state| element_state.unwrap_or_default());
1968            let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
1969            (style, element_state)
1970        })
1971    }
1972
1973    /// Called from internal methods that have already called with_element_state.
1974    fn compute_style_internal(
1975        &self,
1976        hitbox: Option<&Hitbox>,
1977        element_state: Option<&mut InteractiveElementState>,
1978        cx: &mut ElementContext,
1979    ) -> Style {
1980        let mut style = Style::default();
1981        style.refine(&self.base_style);
1982
1983        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1984            if let Some(in_focus_style) = self.in_focus_style.as_ref() {
1985                if focus_handle.within_focused(cx) {
1986                    style.refine(in_focus_style);
1987                }
1988            }
1989
1990            if let Some(focus_style) = self.focus_style.as_ref() {
1991                if focus_handle.is_focused(cx) {
1992                    style.refine(focus_style);
1993                }
1994            }
1995        }
1996
1997        if let Some(hitbox) = hitbox {
1998            if !cx.has_active_drag() {
1999                if let Some(group_hover) = self.group_hover_style.as_ref() {
2000                    if let Some(group_hitbox_id) =
2001                        GroupHitboxes::get(&group_hover.group, cx.deref_mut())
2002                    {
2003                        if group_hitbox_id.is_hovered(cx) {
2004                            style.refine(&group_hover.style);
2005                        }
2006                    }
2007                }
2008
2009                if let Some(hover_style) = self.hover_style.as_ref() {
2010                    if hitbox.is_hovered(cx) {
2011                        style.refine(hover_style);
2012                    }
2013                }
2014            }
2015
2016            if let Some(drag) = cx.active_drag.take() {
2017                let mut can_drop = true;
2018                if let Some(can_drop_predicate) = &self.can_drop_predicate {
2019                    can_drop = can_drop_predicate(drag.value.as_ref(), cx.deref_mut());
2020                }
2021
2022                if can_drop {
2023                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
2024                        if let Some(group_hitbox_id) =
2025                            GroupHitboxes::get(&group_drag_style.group, cx.deref_mut())
2026                        {
2027                            if *state_type == drag.value.as_ref().type_id()
2028                                && group_hitbox_id.is_hovered(cx)
2029                            {
2030                                style.refine(&group_drag_style.style);
2031                            }
2032                        }
2033                    }
2034
2035                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
2036                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(cx) {
2037                            style.refine(&build_drag_over_style(drag.value.as_ref(), cx));
2038                        }
2039                    }
2040                }
2041
2042                cx.active_drag = Some(drag);
2043            }
2044        }
2045
2046        if let Some(element_state) = element_state {
2047            let clicked_state = element_state
2048                .clicked_state
2049                .get_or_insert_with(Default::default)
2050                .borrow();
2051            if clicked_state.group {
2052                if let Some(group) = self.group_active_style.as_ref() {
2053                    style.refine(&group.style)
2054                }
2055            }
2056
2057            if let Some(active_style) = self.active_style.as_ref() {
2058                if clicked_state.element {
2059                    style.refine(active_style)
2060                }
2061            }
2062        }
2063
2064        style
2065    }
2066}
2067
2068/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
2069/// and scroll offsets.
2070#[derive(Default)]
2071pub struct InteractiveElementState {
2072    pub(crate) focus_handle: Option<FocusHandle>,
2073    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
2074    pub(crate) hover_state: Option<Rc<RefCell<bool>>>,
2075    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
2076    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
2077    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
2078}
2079
2080/// The current active tooltip
2081pub struct ActiveTooltip {
2082    pub(crate) tooltip: Option<AnyTooltip>,
2083    pub(crate) _task: Option<Task<()>>,
2084}
2085
2086/// Whether or not the element or a group that contains it is clicked by the mouse.
2087#[derive(Copy, Clone, Default, Eq, PartialEq)]
2088pub struct ElementClickedState {
2089    /// True if this element's group has been clicked, false otherwise
2090    pub group: bool,
2091
2092    /// True if this element has been clicked, false otherwise
2093    pub element: bool,
2094}
2095
2096impl ElementClickedState {
2097    fn is_clicked(&self) -> bool {
2098        self.group || self.element
2099    }
2100}
2101
2102#[derive(Default)]
2103pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
2104
2105impl Global for GroupHitboxes {}
2106
2107impl GroupHitboxes {
2108    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<HitboxId> {
2109        cx.default_global::<Self>()
2110            .0
2111            .get(name)
2112            .and_then(|bounds_stack| bounds_stack.last())
2113            .cloned()
2114    }
2115
2116    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut AppContext) {
2117        cx.default_global::<Self>()
2118            .0
2119            .entry(name)
2120            .or_default()
2121            .push(hitbox_id);
2122    }
2123
2124    pub fn pop(name: &SharedString, cx: &mut AppContext) {
2125        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
2126    }
2127}
2128
2129/// A wrapper around an element that can be focused.
2130pub struct Focusable<E> {
2131    /// The element that is focusable
2132    pub element: E,
2133}
2134
2135impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
2136
2137impl<E> InteractiveElement for Focusable<E>
2138where
2139    E: InteractiveElement,
2140{
2141    fn interactivity(&mut self) -> &mut Interactivity {
2142        self.element.interactivity()
2143    }
2144}
2145
2146impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
2147
2148impl<E> Styled for Focusable<E>
2149where
2150    E: Styled,
2151{
2152    fn style(&mut self) -> &mut StyleRefinement {
2153        self.element.style()
2154    }
2155}
2156
2157impl<E> Element for Focusable<E>
2158where
2159    E: Element,
2160{
2161    type BeforeLayout = E::BeforeLayout;
2162    type AfterLayout = E::AfterLayout;
2163
2164    fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
2165        self.element.before_layout(cx)
2166    }
2167
2168    fn after_layout(
2169        &mut self,
2170        bounds: Bounds<Pixels>,
2171        state: &mut Self::BeforeLayout,
2172        cx: &mut ElementContext,
2173    ) -> E::AfterLayout {
2174        self.element.after_layout(bounds, state, cx)
2175    }
2176
2177    fn paint(
2178        &mut self,
2179        bounds: Bounds<Pixels>,
2180        before_layout: &mut Self::BeforeLayout,
2181        after_layout: &mut Self::AfterLayout,
2182        cx: &mut ElementContext,
2183    ) {
2184        self.element.paint(bounds, before_layout, after_layout, cx)
2185    }
2186}
2187
2188impl<E> IntoElement for Focusable<E>
2189where
2190    E: IntoElement,
2191{
2192    type Element = E::Element;
2193
2194    fn into_element(self) -> Self::Element {
2195        self.element.into_element()
2196    }
2197}
2198
2199impl<E> ParentElement for Focusable<E>
2200where
2201    E: ParentElement,
2202{
2203    fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
2204        self.element.extend(elements)
2205    }
2206}
2207
2208/// A wrapper around an element that can store state, produced after assigning an ElementId.
2209pub struct Stateful<E> {
2210    element: E,
2211}
2212
2213impl<E> Styled for Stateful<E>
2214where
2215    E: Styled,
2216{
2217    fn style(&mut self) -> &mut StyleRefinement {
2218        self.element.style()
2219    }
2220}
2221
2222impl<E> StatefulInteractiveElement for Stateful<E>
2223where
2224    E: Element,
2225    Self: InteractiveElement,
2226{
2227}
2228
2229impl<E> InteractiveElement for Stateful<E>
2230where
2231    E: InteractiveElement,
2232{
2233    fn interactivity(&mut self) -> &mut Interactivity {
2234        self.element.interactivity()
2235    }
2236}
2237
2238impl<E: FocusableElement> FocusableElement for Stateful<E> {}
2239
2240impl<E> Element for Stateful<E>
2241where
2242    E: Element,
2243{
2244    type BeforeLayout = E::BeforeLayout;
2245    type AfterLayout = E::AfterLayout;
2246
2247    fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
2248        self.element.before_layout(cx)
2249    }
2250
2251    fn after_layout(
2252        &mut self,
2253        bounds: Bounds<Pixels>,
2254        state: &mut Self::BeforeLayout,
2255        cx: &mut ElementContext,
2256    ) -> E::AfterLayout {
2257        self.element.after_layout(bounds, state, cx)
2258    }
2259
2260    fn paint(
2261        &mut self,
2262        bounds: Bounds<Pixels>,
2263        before_layout: &mut Self::BeforeLayout,
2264        after_layout: &mut Self::AfterLayout,
2265        cx: &mut ElementContext,
2266    ) {
2267        self.element.paint(bounds, before_layout, after_layout, cx);
2268    }
2269}
2270
2271impl<E> IntoElement for Stateful<E>
2272where
2273    E: Element,
2274{
2275    type Element = Self;
2276
2277    fn into_element(self) -> Self::Element {
2278        self
2279    }
2280}
2281
2282impl<E> ParentElement for Stateful<E>
2283where
2284    E: ParentElement,
2285{
2286    fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
2287        self.element.extend(elements)
2288    }
2289}
2290
2291#[derive(Default)]
2292struct ScrollHandleState {
2293    offset: Rc<RefCell<Point<Pixels>>>,
2294    bounds: Bounds<Pixels>,
2295    child_bounds: Vec<Bounds<Pixels>>,
2296    requested_scroll_top: Option<(usize, Pixels)>,
2297    overflow: Point<Overflow>,
2298}
2299
2300/// A handle to the scrollable aspects of an element.
2301/// Used for accessing scroll state, like the current scroll offset,
2302/// and for mutating the scroll state, like scrolling to a specific child.
2303#[derive(Clone)]
2304pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
2305
2306impl Default for ScrollHandle {
2307    fn default() -> Self {
2308        Self::new()
2309    }
2310}
2311
2312impl ScrollHandle {
2313    /// Construct a new scroll handle.
2314    pub fn new() -> Self {
2315        Self(Rc::default())
2316    }
2317
2318    /// Get the current scroll offset.
2319    pub fn offset(&self) -> Point<Pixels> {
2320        *self.0.borrow().offset.borrow()
2321    }
2322
2323    /// Get the top child that's scrolled into view.
2324    pub fn top_item(&self) -> usize {
2325        let state = self.0.borrow();
2326        let top = state.bounds.top() - state.offset.borrow().y;
2327
2328        match state.child_bounds.binary_search_by(|bounds| {
2329            if top < bounds.top() {
2330                Ordering::Greater
2331            } else if top > bounds.bottom() {
2332                Ordering::Less
2333            } else {
2334                Ordering::Equal
2335            }
2336        }) {
2337            Ok(ix) => ix,
2338            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
2339        }
2340    }
2341
2342    /// Get the bounds for a specific child.
2343    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
2344        self.0.borrow().child_bounds.get(ix).cloned()
2345    }
2346
2347    /// scroll_to_item scrolls the minimal amount to ensure that the child is
2348    /// fully visible
2349    pub fn scroll_to_item(&self, ix: usize) {
2350        let state = self.0.borrow();
2351
2352        let Some(bounds) = state.child_bounds.get(ix) else {
2353            return;
2354        };
2355
2356        let mut scroll_offset = state.offset.borrow_mut();
2357
2358        if state.overflow.y == Overflow::Scroll {
2359            if bounds.top() + scroll_offset.y < state.bounds.top() {
2360                scroll_offset.y = state.bounds.top() - bounds.top();
2361            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
2362                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
2363            }
2364        }
2365
2366        if state.overflow.x == Overflow::Scroll {
2367            if bounds.left() + scroll_offset.x < state.bounds.left() {
2368                scroll_offset.x = state.bounds.left() - bounds.left();
2369            } else if bounds.right() + scroll_offset.x > state.bounds.right() {
2370                scroll_offset.x = state.bounds.right() - bounds.right();
2371            }
2372        }
2373    }
2374
2375    /// Get the logical scroll top, based on a child index and a pixel offset.
2376    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
2377        let ix = self.top_item();
2378        let state = self.0.borrow();
2379
2380        if let Some(child_bounds) = state.child_bounds.get(ix) {
2381            (
2382                ix,
2383                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
2384            )
2385        } else {
2386            (ix, px(0.))
2387        }
2388    }
2389
2390    /// Set the logical scroll top, based on a child index and a pixel offset.
2391    pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
2392        self.0.borrow_mut().requested_scroll_top = Some((ix, px));
2393    }
2394}