div.rs

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