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