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.should_insert_hitbox(&style) {
1305                            Some(cx.insert_hitbox(bounds, self.occlude_mouse))
1306                        } else {
1307                            None
1308                        };
1309
1310                        let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
1311                        let result = f(&style, scroll_offset, hitbox, cx);
1312                        (result, element_state)
1313                    })
1314                })
1315            },
1316        )
1317    }
1318
1319    fn should_insert_hitbox(&self, style: &Style) -> bool {
1320        self.occlude_mouse
1321            || style.mouse_cursor.is_some()
1322            || self.group.is_some()
1323            || self.scroll_offset.is_some()
1324            || self.tracked_focus_handle.is_some()
1325            || self.hover_style.is_some()
1326            || self.group_hover_style.is_some()
1327            || !self.mouse_up_listeners.is_empty()
1328            || !self.mouse_down_listeners.is_empty()
1329            || !self.mouse_move_listeners.is_empty()
1330            || !self.click_listeners.is_empty()
1331            || !self.scroll_wheel_listeners.is_empty()
1332            || self.drag_listener.is_some()
1333            || !self.drop_listeners.is_empty()
1334            || self.tooltip_builder.is_some()
1335    }
1336
1337    fn clamp_scroll_position(
1338        &mut self,
1339        bounds: Bounds<Pixels>,
1340        style: &Style,
1341        cx: &mut ElementContext,
1342    ) -> Point<Pixels> {
1343        if let Some(scroll_offset) = self.scroll_offset.as_ref() {
1344            if let Some(scroll_handle) = &self.tracked_scroll_handle {
1345                scroll_handle.0.borrow_mut().overflow = style.overflow;
1346            }
1347
1348            let rem_size = cx.rem_size();
1349            let padding_size = size(
1350                style
1351                    .padding
1352                    .left
1353                    .to_pixels(bounds.size.width.into(), rem_size)
1354                    + style
1355                        .padding
1356                        .right
1357                        .to_pixels(bounds.size.width.into(), rem_size),
1358                style
1359                    .padding
1360                    .top
1361                    .to_pixels(bounds.size.height.into(), rem_size)
1362                    + style
1363                        .padding
1364                        .bottom
1365                        .to_pixels(bounds.size.height.into(), rem_size),
1366            );
1367            let scroll_max = (self.content_size + padding_size - bounds.size).max(&Size::default());
1368            // Clamp scroll offset in case scroll max is smaller now (e.g., if children
1369            // were removed or the bounds became larger).
1370            let mut scroll_offset = scroll_offset.borrow_mut();
1371            scroll_offset.x = scroll_offset.x.clamp(-scroll_max.width, px(0.));
1372            scroll_offset.y = scroll_offset.y.clamp(-scroll_max.height, px(0.));
1373            *scroll_offset
1374        } else {
1375            Point::default()
1376        }
1377    }
1378
1379    /// Paint this element according to this interactivity state's configured styles
1380    /// and bind the element's mouse and keyboard events.
1381    ///
1382    /// content_size is the size of the content of the element, which may be larger than the
1383    /// element's bounds if the element is scrollable.
1384    ///
1385    /// the final computed style will be passed to the provided function, along
1386    /// with the current scroll offset
1387    pub fn paint(
1388        &mut self,
1389        bounds: Bounds<Pixels>,
1390        hitbox: Option<&Hitbox>,
1391        cx: &mut ElementContext,
1392        f: impl FnOnce(&Style, &mut ElementContext),
1393    ) {
1394        self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(cx));
1395        cx.with_element_state::<InteractiveElementState, _>(
1396            self.element_id.clone(),
1397            |element_state, cx| {
1398                let mut element_state =
1399                    element_state.map(|element_state| element_state.unwrap_or_default());
1400
1401                let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
1402
1403                #[cfg(any(feature = "test-support", test))]
1404                if let Some(debug_selector) = &self.debug_selector {
1405                    cx.window
1406                        .next_frame
1407                        .debug_bounds
1408                        .insert(debug_selector.clone(), bounds);
1409                }
1410
1411                self.paint_hover_group_handler(cx);
1412
1413                if style.visibility == Visibility::Hidden {
1414                    return ((), element_state);
1415                }
1416
1417                style.paint(bounds, cx, |cx: &mut ElementContext| {
1418                    cx.with_text_style(style.text_style().cloned(), |cx| {
1419                        cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
1420                            if let Some(hitbox) = hitbox {
1421                                #[cfg(debug_assertions)]
1422                                self.paint_debug_info(hitbox, &style, cx);
1423
1424                                if !cx.has_active_drag() {
1425                                    if let Some(mouse_cursor) = style.mouse_cursor {
1426                                        cx.set_cursor_style(mouse_cursor, hitbox);
1427                                    }
1428                                }
1429
1430                                if let Some(group) = self.group.clone() {
1431                                    GroupHitboxes::push(group, hitbox.id, cx);
1432                                }
1433
1434                                self.paint_mouse_listeners(hitbox, element_state.as_mut(), cx);
1435                                self.paint_scroll_listener(hitbox, &style, cx);
1436                            }
1437
1438                            self.paint_keyboard_listeners(cx);
1439                            f(&style, cx);
1440
1441                            if hitbox.is_some() {
1442                                if let Some(group) = self.group.as_ref() {
1443                                    GroupHitboxes::pop(group, cx);
1444                                }
1445                            }
1446                        });
1447                    });
1448                });
1449
1450                ((), element_state)
1451            },
1452        );
1453    }
1454
1455    #[cfg(debug_assertions)]
1456    fn paint_debug_info(&mut self, hitbox: &Hitbox, style: &Style, cx: &mut ElementContext) {
1457        if self.element_id.is_some()
1458            && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
1459            && hitbox.is_hovered(cx)
1460        {
1461            const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
1462            let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
1463            let str_len = element_id.len();
1464
1465            let render_debug_text = |cx: &mut ElementContext| {
1466                if let Some(text) = cx
1467                    .text_system()
1468                    .shape_text(
1469                        element_id.into(),
1470                        FONT_SIZE,
1471                        &[cx.text_style().to_run(str_len)],
1472                        None,
1473                    )
1474                    .ok()
1475                    .and_then(|mut text| text.pop())
1476                {
1477                    text.paint(hitbox.origin, FONT_SIZE, cx).ok();
1478
1479                    let text_bounds = crate::Bounds {
1480                        origin: hitbox.origin,
1481                        size: text.size(FONT_SIZE),
1482                    };
1483                    if self.location.is_some()
1484                        && text_bounds.contains(&cx.mouse_position())
1485                        && cx.modifiers().command
1486                    {
1487                        let command_held = cx.modifiers().command;
1488                        cx.on_key_event({
1489                            move |e: &crate::ModifiersChangedEvent, _phase, cx| {
1490                                if e.modifiers.command != command_held
1491                                    && text_bounds.contains(&cx.mouse_position())
1492                                {
1493                                    cx.refresh();
1494                                }
1495                            }
1496                        });
1497
1498                        let was_hovered = hitbox.is_hovered(cx);
1499                        cx.on_mouse_event({
1500                            let hitbox = hitbox.clone();
1501                            move |_: &MouseMoveEvent, phase, cx| {
1502                                if phase == DispatchPhase::Capture {
1503                                    let hovered = hitbox.is_hovered(cx);
1504                                    if hovered != was_hovered {
1505                                        cx.refresh();
1506                                    }
1507                                }
1508                            }
1509                        });
1510
1511                        cx.on_mouse_event({
1512                            let hitbox = hitbox.clone();
1513                            let location = self.location.unwrap();
1514                            move |e: &crate::MouseDownEvent, phase, cx| {
1515                                if text_bounds.contains(&e.position)
1516                                    && phase.capture()
1517                                    && hitbox.is_hovered(cx)
1518                                {
1519                                    cx.stop_propagation();
1520                                    let Ok(dir) = std::env::current_dir() else {
1521                                        return;
1522                                    };
1523
1524                                    eprintln!(
1525                                        "This element was created at:\n{}:{}:{}",
1526                                        dir.join(location.file()).to_string_lossy(),
1527                                        location.line(),
1528                                        location.column()
1529                                    );
1530                                }
1531                            }
1532                        });
1533                        cx.paint_quad(crate::outline(
1534                            crate::Bounds {
1535                                origin: hitbox.origin
1536                                    + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
1537                                size: crate::Size {
1538                                    width: text_bounds.size.width,
1539                                    height: crate::px(1.),
1540                                },
1541                            },
1542                            crate::red(),
1543                        ))
1544                    }
1545                }
1546            };
1547
1548            cx.with_text_style(
1549                Some(crate::TextStyleRefinement {
1550                    color: Some(crate::red()),
1551                    line_height: Some(FONT_SIZE.into()),
1552                    background_color: Some(crate::white()),
1553                    ..Default::default()
1554                }),
1555                render_debug_text,
1556            )
1557        }
1558    }
1559
1560    fn paint_mouse_listeners(
1561        &mut self,
1562        hitbox: &Hitbox,
1563        element_state: Option<&mut InteractiveElementState>,
1564        cx: &mut ElementContext,
1565    ) {
1566        // If this element can be focused, register a mouse down listener
1567        // that will automatically transfer focus when hitting the element.
1568        // This behavior can be suppressed by using `cx.prevent_default()`.
1569        if let Some(focus_handle) = self.tracked_focus_handle.clone() {
1570            let hitbox = hitbox.clone();
1571            cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1572                if phase == DispatchPhase::Bubble
1573                    && hitbox.is_hovered(cx)
1574                    && !cx.default_prevented()
1575                {
1576                    cx.focus(&focus_handle);
1577                    // If there is a parent that is also focusable, prevent it
1578                    // from transferring focus because we already did so.
1579                    cx.prevent_default();
1580                }
1581            });
1582        }
1583
1584        for listener in self.mouse_down_listeners.drain(..) {
1585            let hitbox = hitbox.clone();
1586            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
1587                listener(event, phase, &hitbox, cx);
1588            })
1589        }
1590
1591        for listener in self.mouse_up_listeners.drain(..) {
1592            let hitbox = hitbox.clone();
1593            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
1594                listener(event, phase, &hitbox, cx);
1595            })
1596        }
1597
1598        for listener in self.mouse_move_listeners.drain(..) {
1599            let hitbox = hitbox.clone();
1600            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1601                listener(event, phase, &hitbox, cx);
1602            })
1603        }
1604
1605        for listener in self.scroll_wheel_listeners.drain(..) {
1606            let hitbox = hitbox.clone();
1607            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1608                listener(event, phase, &hitbox, cx);
1609            })
1610        }
1611
1612        if self.hover_style.is_some()
1613            || self.base_style.mouse_cursor.is_some()
1614            || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
1615        {
1616            let hitbox = hitbox.clone();
1617            let was_hovered = hitbox.is_hovered(cx);
1618            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1619                let hovered = hitbox.is_hovered(cx);
1620                if phase == DispatchPhase::Capture && hovered != was_hovered {
1621                    cx.refresh();
1622                }
1623            });
1624        }
1625
1626        let mut drag_listener = mem::take(&mut self.drag_listener);
1627        let drop_listeners = mem::take(&mut self.drop_listeners);
1628        let click_listeners = mem::take(&mut self.click_listeners);
1629        let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
1630
1631        if !drop_listeners.is_empty() {
1632            let hitbox = hitbox.clone();
1633            cx.on_mouse_event({
1634                move |_: &MouseUpEvent, phase, cx| {
1635                    if let Some(drag) = &cx.active_drag {
1636                        if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
1637                            let drag_state_type = drag.value.as_ref().type_id();
1638                            for (drop_state_type, listener) in &drop_listeners {
1639                                if *drop_state_type == drag_state_type {
1640                                    let drag = cx
1641                                        .active_drag
1642                                        .take()
1643                                        .expect("checked for type drag state type above");
1644
1645                                    let mut can_drop = true;
1646                                    if let Some(predicate) = &can_drop_predicate {
1647                                        can_drop = predicate(drag.value.as_ref(), cx.deref_mut());
1648                                    }
1649
1650                                    if can_drop {
1651                                        listener(drag.value.as_ref(), cx.deref_mut());
1652                                        cx.refresh();
1653                                        cx.stop_propagation();
1654                                    }
1655                                }
1656                            }
1657                        }
1658                    }
1659                }
1660            });
1661        }
1662
1663        if let Some(element_state) = element_state {
1664            if !click_listeners.is_empty() || drag_listener.is_some() {
1665                let pending_mouse_down = element_state
1666                    .pending_mouse_down
1667                    .get_or_insert_with(Default::default)
1668                    .clone();
1669
1670                let clicked_state = element_state
1671                    .clicked_state
1672                    .get_or_insert_with(Default::default)
1673                    .clone();
1674
1675                cx.on_mouse_event({
1676                    let pending_mouse_down = pending_mouse_down.clone();
1677                    let hitbox = hitbox.clone();
1678                    move |event: &MouseDownEvent, phase, cx| {
1679                        if phase == DispatchPhase::Bubble
1680                            && event.button == MouseButton::Left
1681                            && hitbox.is_hovered(cx)
1682                        {
1683                            *pending_mouse_down.borrow_mut() = Some(event.clone());
1684                            cx.refresh();
1685                        }
1686                    }
1687                });
1688
1689                cx.on_mouse_event({
1690                    let pending_mouse_down = pending_mouse_down.clone();
1691                    let hitbox = hitbox.clone();
1692                    move |event: &MouseMoveEvent, phase, cx| {
1693                        if phase == DispatchPhase::Capture {
1694                            return;
1695                        }
1696
1697                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1698                        if let Some(mouse_down) = pending_mouse_down.clone() {
1699                            if !cx.has_active_drag()
1700                                && (event.position - mouse_down.position).magnitude()
1701                                    > DRAG_THRESHOLD
1702                            {
1703                                if let Some((drag_value, drag_listener)) = drag_listener.take() {
1704                                    *clicked_state.borrow_mut() = ElementClickedState::default();
1705                                    let cursor_offset = event.position - hitbox.origin;
1706                                    let drag = (drag_listener)(drag_value.as_ref(), cx);
1707                                    cx.active_drag = Some(AnyDrag {
1708                                        view: drag,
1709                                        value: drag_value,
1710                                        cursor_offset,
1711                                    });
1712                                    pending_mouse_down.take();
1713                                    cx.refresh();
1714                                    cx.stop_propagation();
1715                                }
1716                            }
1717                        }
1718                    }
1719                });
1720
1721                cx.on_mouse_event({
1722                    let mut captured_mouse_down = None;
1723                    let hitbox = hitbox.clone();
1724                    move |event: &MouseUpEvent, phase, cx| match phase {
1725                        // Clear the pending mouse down during the capture phase,
1726                        // so that it happens even if another event handler stops
1727                        // propagation.
1728                        DispatchPhase::Capture => {
1729                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1730                            if pending_mouse_down.is_some() && hitbox.is_hovered(cx) {
1731                                captured_mouse_down = pending_mouse_down.take();
1732                                cx.refresh();
1733                            }
1734                        }
1735                        // Fire click handlers during the bubble phase.
1736                        DispatchPhase::Bubble => {
1737                            if let Some(mouse_down) = captured_mouse_down.take() {
1738                                let mouse_click = ClickEvent {
1739                                    down: mouse_down,
1740                                    up: event.clone(),
1741                                };
1742                                for listener in &click_listeners {
1743                                    listener(&mouse_click, cx);
1744                                }
1745                            }
1746                        }
1747                    }
1748                });
1749            }
1750
1751            if let Some(hover_listener) = self.hover_listener.take() {
1752                let hitbox = hitbox.clone();
1753                let was_hovered = element_state
1754                    .hover_state
1755                    .get_or_insert_with(Default::default)
1756                    .clone();
1757                let has_mouse_down = element_state
1758                    .pending_mouse_down
1759                    .get_or_insert_with(Default::default)
1760                    .clone();
1761
1762                cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1763                    if phase != DispatchPhase::Bubble {
1764                        return;
1765                    }
1766                    let is_hovered = has_mouse_down.borrow().is_none()
1767                        && !cx.has_active_drag()
1768                        && hitbox.is_hovered(cx);
1769                    let mut was_hovered = was_hovered.borrow_mut();
1770
1771                    if is_hovered != *was_hovered {
1772                        *was_hovered = is_hovered;
1773                        drop(was_hovered);
1774
1775                        hover_listener(&is_hovered, cx.deref_mut());
1776                    }
1777                });
1778            }
1779
1780            if let Some(tooltip_builder) = self.tooltip_builder.take() {
1781                let active_tooltip = element_state
1782                    .active_tooltip
1783                    .get_or_insert_with(Default::default)
1784                    .clone();
1785                let pending_mouse_down = element_state
1786                    .pending_mouse_down
1787                    .get_or_insert_with(Default::default)
1788                    .clone();
1789                let hitbox = hitbox.clone();
1790
1791                cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1792                    let is_hovered = pending_mouse_down.borrow().is_none() && hitbox.is_hovered(cx);
1793                    if !is_hovered {
1794                        active_tooltip.borrow_mut().take();
1795                        return;
1796                    }
1797
1798                    if phase != DispatchPhase::Bubble {
1799                        return;
1800                    }
1801
1802                    if active_tooltip.borrow().is_none() {
1803                        let task = cx.spawn({
1804                            let active_tooltip = active_tooltip.clone();
1805                            let tooltip_builder = tooltip_builder.clone();
1806
1807                            move |mut cx| async move {
1808                                cx.background_executor().timer(TOOLTIP_DELAY).await;
1809                                cx.update(|cx| {
1810                                    active_tooltip.borrow_mut().replace(ActiveTooltip {
1811                                        tooltip: Some(AnyTooltip {
1812                                            view: tooltip_builder(cx),
1813                                            cursor_offset: cx.mouse_position(),
1814                                        }),
1815                                        _task: None,
1816                                    });
1817                                    cx.refresh();
1818                                })
1819                                .ok();
1820                            }
1821                        });
1822                        active_tooltip.borrow_mut().replace(ActiveTooltip {
1823                            tooltip: None,
1824                            _task: Some(task),
1825                        });
1826                    }
1827                });
1828
1829                let active_tooltip = element_state
1830                    .active_tooltip
1831                    .get_or_insert_with(Default::default)
1832                    .clone();
1833                cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
1834                    active_tooltip.borrow_mut().take();
1835                });
1836            }
1837
1838            let active_state = element_state
1839                .clicked_state
1840                .get_or_insert_with(Default::default)
1841                .clone();
1842            if active_state.borrow().is_clicked() {
1843                cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
1844                    if phase == DispatchPhase::Capture {
1845                        *active_state.borrow_mut() = ElementClickedState::default();
1846                        cx.refresh();
1847                    }
1848                });
1849            } else {
1850                let active_group_hitbox = self
1851                    .group_active_style
1852                    .as_ref()
1853                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
1854                let hitbox = hitbox.clone();
1855                cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1856                    if phase == DispatchPhase::Bubble && !cx.default_prevented() {
1857                        let group_hovered = active_group_hitbox
1858                            .map_or(false, |group_hitbox_id| group_hitbox_id.is_hovered(cx));
1859                        let element_hovered = hitbox.is_hovered(cx);
1860                        if group_hovered || element_hovered {
1861                            *active_state.borrow_mut() = ElementClickedState {
1862                                group: group_hovered,
1863                                element: element_hovered,
1864                            };
1865                            cx.refresh();
1866                        }
1867                    }
1868                });
1869            }
1870        }
1871    }
1872
1873    fn paint_keyboard_listeners(&mut self, cx: &mut ElementContext) {
1874        let key_down_listeners = mem::take(&mut self.key_down_listeners);
1875        let key_up_listeners = mem::take(&mut self.key_up_listeners);
1876        let action_listeners = mem::take(&mut self.action_listeners);
1877        if let Some(context) = self.key_context.clone() {
1878            cx.set_key_context(context);
1879        }
1880        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1881            cx.set_focus_handle(focus_handle);
1882        }
1883
1884        for listener in key_down_listeners {
1885            cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
1886                listener(event, phase, cx);
1887            })
1888        }
1889
1890        for listener in key_up_listeners {
1891            cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
1892                listener(event, phase, cx);
1893            })
1894        }
1895
1896        for (action_type, listener) in action_listeners {
1897            cx.on_action(action_type, listener)
1898        }
1899    }
1900
1901    fn paint_hover_group_handler(&self, cx: &mut ElementContext) {
1902        let group_hitbox = self
1903            .group_hover_style
1904            .as_ref()
1905            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
1906
1907        if let Some(group_hitbox) = group_hitbox {
1908            let was_hovered = group_hitbox.is_hovered(cx);
1909            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1910                let hovered = group_hitbox.is_hovered(cx);
1911                if phase == DispatchPhase::Capture && hovered != was_hovered {
1912                    cx.refresh();
1913                }
1914            });
1915        }
1916    }
1917
1918    fn paint_scroll_listener(&self, hitbox: &Hitbox, style: &Style, cx: &mut ElementContext) {
1919        if let Some(scroll_offset) = self.scroll_offset.clone() {
1920            let overflow = style.overflow;
1921            let line_height = cx.line_height();
1922            let hitbox = hitbox.clone();
1923            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1924                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
1925                    let mut scroll_offset = scroll_offset.borrow_mut();
1926                    let old_scroll_offset = *scroll_offset;
1927                    let delta = event.delta.pixel_delta(line_height);
1928
1929                    if overflow.x == Overflow::Scroll {
1930                        let mut delta_x = Pixels::ZERO;
1931                        if !delta.x.is_zero() {
1932                            delta_x = delta.x;
1933                        } else if overflow.y != Overflow::Scroll {
1934                            delta_x = delta.y;
1935                        }
1936
1937                        scroll_offset.x += delta_x;
1938                    }
1939
1940                    if overflow.y == Overflow::Scroll {
1941                        let mut delta_y = Pixels::ZERO;
1942                        if !delta.y.is_zero() {
1943                            delta_y = delta.y;
1944                        } else if overflow.x != Overflow::Scroll {
1945                            delta_y = delta.x;
1946                        }
1947
1948                        scroll_offset.y += delta_y;
1949                    }
1950
1951                    cx.stop_propagation();
1952                    if *scroll_offset != old_scroll_offset {
1953                        cx.refresh();
1954                    }
1955                }
1956            });
1957        }
1958    }
1959
1960    /// Compute the visual style for this element, based on the current bounds and the element's state.
1961    pub fn compute_style(&self, hitbox: Option<&Hitbox>, cx: &mut ElementContext) -> Style {
1962        cx.with_element_state(self.element_id.clone(), |element_state, cx| {
1963            let mut element_state =
1964                element_state.map(|element_state| element_state.unwrap_or_default());
1965            let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
1966            (style, element_state)
1967        })
1968    }
1969
1970    /// Called from internal methods that have already called with_element_state.
1971    fn compute_style_internal(
1972        &self,
1973        hitbox: Option<&Hitbox>,
1974        element_state: Option<&mut InteractiveElementState>,
1975        cx: &mut ElementContext,
1976    ) -> Style {
1977        let mut style = Style::default();
1978        style.refine(&self.base_style);
1979
1980        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1981            if let Some(in_focus_style) = self.in_focus_style.as_ref() {
1982                if focus_handle.within_focused(cx) {
1983                    style.refine(in_focus_style);
1984                }
1985            }
1986
1987            if let Some(focus_style) = self.focus_style.as_ref() {
1988                if focus_handle.is_focused(cx) {
1989                    style.refine(focus_style);
1990                }
1991            }
1992        }
1993
1994        if let Some(hitbox) = hitbox {
1995            if !cx.has_active_drag() {
1996                if let Some(group_hover) = self.group_hover_style.as_ref() {
1997                    if let Some(group_hitbox_id) =
1998                        GroupHitboxes::get(&group_hover.group, cx.deref_mut())
1999                    {
2000                        if group_hitbox_id.is_hovered(cx) {
2001                            style.refine(&group_hover.style);
2002                        }
2003                    }
2004                }
2005
2006                if let Some(hover_style) = self.hover_style.as_ref() {
2007                    if hitbox.is_hovered(cx) {
2008                        style.refine(hover_style);
2009                    }
2010                }
2011            }
2012
2013            if let Some(drag) = cx.active_drag.take() {
2014                let mut can_drop = true;
2015                if let Some(can_drop_predicate) = &self.can_drop_predicate {
2016                    can_drop = can_drop_predicate(drag.value.as_ref(), cx.deref_mut());
2017                }
2018
2019                if can_drop {
2020                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
2021                        if let Some(group_hitbox_id) =
2022                            GroupHitboxes::get(&group_drag_style.group, cx.deref_mut())
2023                        {
2024                            if *state_type == drag.value.as_ref().type_id()
2025                                && group_hitbox_id.is_hovered(cx)
2026                            {
2027                                style.refine(&group_drag_style.style);
2028                            }
2029                        }
2030                    }
2031
2032                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
2033                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(cx) {
2034                            style.refine(&build_drag_over_style(drag.value.as_ref(), cx));
2035                        }
2036                    }
2037                }
2038
2039                cx.active_drag = Some(drag);
2040            }
2041        }
2042
2043        if let Some(element_state) = element_state {
2044            let clicked_state = element_state
2045                .clicked_state
2046                .get_or_insert_with(Default::default)
2047                .borrow();
2048            if clicked_state.group {
2049                if let Some(group) = self.group_active_style.as_ref() {
2050                    style.refine(&group.style)
2051                }
2052            }
2053
2054            if let Some(active_style) = self.active_style.as_ref() {
2055                if clicked_state.element {
2056                    style.refine(active_style)
2057                }
2058            }
2059        }
2060
2061        style
2062    }
2063}
2064
2065/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
2066/// and scroll offsets.
2067#[derive(Default)]
2068pub struct InteractiveElementState {
2069    pub(crate) focus_handle: Option<FocusHandle>,
2070    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
2071    pub(crate) hover_state: Option<Rc<RefCell<bool>>>,
2072    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
2073    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
2074    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
2075}
2076
2077/// The current active tooltip
2078pub struct ActiveTooltip {
2079    pub(crate) tooltip: Option<AnyTooltip>,
2080    pub(crate) _task: Option<Task<()>>,
2081}
2082
2083/// Whether or not the element or a group that contains it is clicked by the mouse.
2084#[derive(Copy, Clone, Default, Eq, PartialEq)]
2085pub struct ElementClickedState {
2086    /// True if this element's group has been clicked, false otherwise
2087    pub group: bool,
2088
2089    /// True if this element has been clicked, false otherwise
2090    pub element: bool,
2091}
2092
2093impl ElementClickedState {
2094    fn is_clicked(&self) -> bool {
2095        self.group || self.element
2096    }
2097}
2098
2099#[derive(Default)]
2100pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
2101
2102impl Global for GroupHitboxes {}
2103
2104impl GroupHitboxes {
2105    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<HitboxId> {
2106        cx.default_global::<Self>()
2107            .0
2108            .get(name)
2109            .and_then(|bounds_stack| bounds_stack.last())
2110            .cloned()
2111    }
2112
2113    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut AppContext) {
2114        cx.default_global::<Self>()
2115            .0
2116            .entry(name)
2117            .or_default()
2118            .push(hitbox_id);
2119    }
2120
2121    pub fn pop(name: &SharedString, cx: &mut AppContext) {
2122        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
2123    }
2124}
2125
2126/// A wrapper around an element that can be focused.
2127pub struct Focusable<E> {
2128    /// The element that is focusable
2129    pub element: E,
2130}
2131
2132impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
2133
2134impl<E> InteractiveElement for Focusable<E>
2135where
2136    E: InteractiveElement,
2137{
2138    fn interactivity(&mut self) -> &mut Interactivity {
2139        self.element.interactivity()
2140    }
2141}
2142
2143impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
2144
2145impl<E> Styled for Focusable<E>
2146where
2147    E: Styled,
2148{
2149    fn style(&mut self) -> &mut StyleRefinement {
2150        self.element.style()
2151    }
2152}
2153
2154impl<E> Element for Focusable<E>
2155where
2156    E: Element,
2157{
2158    type BeforeLayout = E::BeforeLayout;
2159    type AfterLayout = E::AfterLayout;
2160
2161    fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
2162        self.element.before_layout(cx)
2163    }
2164
2165    fn after_layout(
2166        &mut self,
2167        bounds: Bounds<Pixels>,
2168        state: &mut Self::BeforeLayout,
2169        cx: &mut ElementContext,
2170    ) -> E::AfterLayout {
2171        self.element.after_layout(bounds, state, cx)
2172    }
2173
2174    fn paint(
2175        &mut self,
2176        bounds: Bounds<Pixels>,
2177        before_layout: &mut Self::BeforeLayout,
2178        after_layout: &mut Self::AfterLayout,
2179        cx: &mut ElementContext,
2180    ) {
2181        self.element.paint(bounds, before_layout, after_layout, cx)
2182    }
2183}
2184
2185impl<E> IntoElement for Focusable<E>
2186where
2187    E: IntoElement,
2188{
2189    type Element = E::Element;
2190
2191    fn into_element(self) -> Self::Element {
2192        self.element.into_element()
2193    }
2194}
2195
2196impl<E> ParentElement for Focusable<E>
2197where
2198    E: ParentElement,
2199{
2200    fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
2201        self.element.extend(elements)
2202    }
2203}
2204
2205/// A wrapper around an element that can store state, produced after assigning an ElementId.
2206pub struct Stateful<E> {
2207    element: E,
2208}
2209
2210impl<E> Styled for Stateful<E>
2211where
2212    E: Styled,
2213{
2214    fn style(&mut self) -> &mut StyleRefinement {
2215        self.element.style()
2216    }
2217}
2218
2219impl<E> StatefulInteractiveElement for Stateful<E>
2220where
2221    E: Element,
2222    Self: InteractiveElement,
2223{
2224}
2225
2226impl<E> InteractiveElement for Stateful<E>
2227where
2228    E: InteractiveElement,
2229{
2230    fn interactivity(&mut self) -> &mut Interactivity {
2231        self.element.interactivity()
2232    }
2233}
2234
2235impl<E: FocusableElement> FocusableElement for Stateful<E> {}
2236
2237impl<E> Element for Stateful<E>
2238where
2239    E: Element,
2240{
2241    type BeforeLayout = E::BeforeLayout;
2242    type AfterLayout = E::AfterLayout;
2243
2244    fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
2245        self.element.before_layout(cx)
2246    }
2247
2248    fn after_layout(
2249        &mut self,
2250        bounds: Bounds<Pixels>,
2251        state: &mut Self::BeforeLayout,
2252        cx: &mut ElementContext,
2253    ) -> E::AfterLayout {
2254        self.element.after_layout(bounds, state, cx)
2255    }
2256
2257    fn paint(
2258        &mut self,
2259        bounds: Bounds<Pixels>,
2260        before_layout: &mut Self::BeforeLayout,
2261        after_layout: &mut Self::AfterLayout,
2262        cx: &mut ElementContext,
2263    ) {
2264        self.element.paint(bounds, before_layout, after_layout, cx);
2265    }
2266}
2267
2268impl<E> IntoElement for Stateful<E>
2269where
2270    E: Element,
2271{
2272    type Element = Self;
2273
2274    fn into_element(self) -> Self::Element {
2275        self
2276    }
2277}
2278
2279impl<E> ParentElement for Stateful<E>
2280where
2281    E: ParentElement,
2282{
2283    fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
2284        self.element.extend(elements)
2285    }
2286}
2287
2288#[derive(Default)]
2289struct ScrollHandleState {
2290    offset: Rc<RefCell<Point<Pixels>>>,
2291    bounds: Bounds<Pixels>,
2292    child_bounds: Vec<Bounds<Pixels>>,
2293    requested_scroll_top: Option<(usize, Pixels)>,
2294    overflow: Point<Overflow>,
2295}
2296
2297/// A handle to the scrollable aspects of an element.
2298/// Used for accessing scroll state, like the current scroll offset,
2299/// and for mutating the scroll state, like scrolling to a specific child.
2300#[derive(Clone)]
2301pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
2302
2303impl Default for ScrollHandle {
2304    fn default() -> Self {
2305        Self::new()
2306    }
2307}
2308
2309impl ScrollHandle {
2310    /// Construct a new scroll handle.
2311    pub fn new() -> Self {
2312        Self(Rc::default())
2313    }
2314
2315    /// Get the current scroll offset.
2316    pub fn offset(&self) -> Point<Pixels> {
2317        *self.0.borrow().offset.borrow()
2318    }
2319
2320    /// Get the top child that's scrolled into view.
2321    pub fn top_item(&self) -> usize {
2322        let state = self.0.borrow();
2323        let top = state.bounds.top() - state.offset.borrow().y;
2324
2325        match state.child_bounds.binary_search_by(|bounds| {
2326            if top < bounds.top() {
2327                Ordering::Greater
2328            } else if top > bounds.bottom() {
2329                Ordering::Less
2330            } else {
2331                Ordering::Equal
2332            }
2333        }) {
2334            Ok(ix) => ix,
2335            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
2336        }
2337    }
2338
2339    /// Get the bounds for a specific child.
2340    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
2341        self.0.borrow().child_bounds.get(ix).cloned()
2342    }
2343
2344    /// scroll_to_item scrolls the minimal amount to ensure that the child is
2345    /// fully visible
2346    pub fn scroll_to_item(&self, ix: usize) {
2347        let state = self.0.borrow();
2348
2349        let Some(bounds) = state.child_bounds.get(ix) else {
2350            return;
2351        };
2352
2353        let mut scroll_offset = state.offset.borrow_mut();
2354
2355        if state.overflow.y == Overflow::Scroll {
2356            if bounds.top() + scroll_offset.y < state.bounds.top() {
2357                scroll_offset.y = state.bounds.top() - bounds.top();
2358            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
2359                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
2360            }
2361        }
2362
2363        if state.overflow.x == Overflow::Scroll {
2364            if bounds.left() + scroll_offset.x < state.bounds.left() {
2365                scroll_offset.x = state.bounds.left() - bounds.left();
2366            } else if bounds.right() + scroll_offset.x > state.bounds.right() {
2367                scroll_offset.x = state.bounds.right() - bounds.right();
2368            }
2369        }
2370    }
2371
2372    /// Get the logical scroll top, based on a child index and a pixel offset.
2373    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
2374        let ix = self.top_item();
2375        let state = self.0.borrow();
2376
2377        if let Some(child_bounds) = state.child_bounds.get(ix) {
2378            (
2379                ix,
2380                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
2381            )
2382        } else {
2383            (ix, px(0.))
2384        }
2385    }
2386
2387    /// Set the logical scroll top, based on a child index and a pixel offset.
2388    pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
2389        self.0.borrow_mut().requested_scroll_top = Some((ix, px));
2390    }
2391}