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    AbsoluteLength, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, App, Bounds, ClickEvent,
  20    DispatchPhase, Display, Element, ElementId, Entity, FocusHandle, Global, GlobalElementId,
  21    Hitbox, HitboxBehavior, HitboxId, InspectorElementId, IntoElement, IsZero, KeyContext,
  22    KeyDownEvent, KeyUpEvent, KeyboardButton, KeyboardClickEvent, LayoutId, ModifiersChangedEvent,
  23    MouseButton, MouseClickEvent, MouseDownEvent, MouseMoveEvent, MousePressureEvent, MouseUpEvent,
  24    Overflow, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
  25    StyleRefinement, Styled, Task, TooltipId, Visibility, Window, WindowControlArea, point, px,
  26    size,
  27};
  28use collections::HashMap;
  29use gpui_util::ResultExt;
  30use refineable::Refineable;
  31use smallvec::SmallVec;
  32use stacksafe::{StackSafe, stacksafe};
  33use std::{
  34    any::{Any, TypeId},
  35    cell::RefCell,
  36    cmp::Ordering,
  37    fmt::Debug,
  38    marker::PhantomData,
  39    mem,
  40    rc::Rc,
  41    sync::Arc,
  42    time::Duration,
  43};
  44
  45use super::ImageCacheProvider;
  46
  47const DRAG_THRESHOLD: f64 = 2.;
  48const TOOLTIP_SHOW_DELAY: Duration = Duration::from_millis(500);
  49const HOVERABLE_TOOLTIP_HIDE_DELAY: Duration = Duration::from_millis(500);
  50
  51/// The styling information for a given group.
  52pub struct GroupStyle {
  53    /// The identifier for this group.
  54    pub group: SharedString,
  55
  56    /// The specific style refinement that this group would apply
  57    /// to its children.
  58    pub style: Box<StyleRefinement>,
  59}
  60
  61/// An event for when a drag is moving over this element, with the given state type.
  62pub struct DragMoveEvent<T> {
  63    /// The mouse move event that triggered this drag move event.
  64    pub event: MouseMoveEvent,
  65
  66    /// The bounds of this element.
  67    pub bounds: Bounds<Pixels>,
  68    drag: PhantomData<T>,
  69    dragged_item: Arc<dyn Any>,
  70}
  71
  72impl<T: 'static> DragMoveEvent<T> {
  73    /// Returns the drag state for this event.
  74    pub fn drag<'b>(&self, cx: &'b App) -> &'b T {
  75        cx.active_drag
  76            .as_ref()
  77            .and_then(|drag| drag.value.downcast_ref::<T>())
  78            .expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
  79    }
  80
  81    /// An item that is about to be dropped.
  82    pub fn dragged_item(&self) -> &dyn Any {
  83        self.dragged_item.as_ref()
  84    }
  85}
  86
  87impl Interactivity {
  88    /// Create an `Interactivity`, capturing the caller location in debug mode.
  89    #[cfg(any(feature = "inspector", debug_assertions))]
  90    #[track_caller]
  91    pub fn new() -> Interactivity {
  92        Interactivity {
  93            source_location: Some(core::panic::Location::caller()),
  94            ..Default::default()
  95        }
  96    }
  97
  98    /// Create an `Interactivity`, capturing the caller location in debug mode.
  99    #[cfg(not(any(feature = "inspector", debug_assertions)))]
 100    pub fn new() -> Interactivity {
 101        Interactivity::default()
 102    }
 103
 104    /// Gets the source location of construction. Returns `None` when not in debug mode.
 105    pub fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
 106        #[cfg(any(feature = "inspector", debug_assertions))]
 107        {
 108            self.source_location
 109        }
 110
 111        #[cfg(not(any(feature = "inspector", debug_assertions)))]
 112        {
 113            None
 114        }
 115    }
 116
 117    /// Bind the given callback to the mouse down event for the given mouse button, during the bubble phase.
 118    /// The imperative API equivalent of [`InteractiveElement::on_mouse_down`].
 119    ///
 120    /// See [`Context::listener`](crate::Context::listener) to get access to the view state from this callback.
 121    pub fn on_mouse_down(
 122        &mut self,
 123        button: MouseButton,
 124        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 125    ) {
 126        self.mouse_down_listeners
 127            .push(Box::new(move |event, phase, hitbox, window, cx| {
 128                if phase == DispatchPhase::Bubble
 129                    && event.button == button
 130                    && hitbox.is_hovered(window)
 131                {
 132                    (listener)(event, window, cx)
 133                }
 134            }));
 135    }
 136
 137    /// Bind the given callback to the mouse down event for any button, during the capture phase.
 138    /// The imperative API equivalent of [`InteractiveElement::capture_any_mouse_down`].
 139    ///
 140    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 141    pub fn capture_any_mouse_down(
 142        &mut self,
 143        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 144    ) {
 145        self.mouse_down_listeners
 146            .push(Box::new(move |event, phase, hitbox, window, cx| {
 147                if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
 148                    (listener)(event, window, cx)
 149                }
 150            }));
 151    }
 152
 153    /// Bind the given callback to the mouse down event for any button, during the bubble phase.
 154    /// The imperative API equivalent to [`InteractiveElement::on_any_mouse_down`].
 155    ///
 156    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 157    pub fn on_any_mouse_down(
 158        &mut self,
 159        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 160    ) {
 161        self.mouse_down_listeners
 162            .push(Box::new(move |event, phase, hitbox, window, cx| {
 163                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
 164                    (listener)(event, window, cx)
 165                }
 166            }));
 167    }
 168
 169    /// Bind the given callback to the mouse pressure event, during the bubble phase
 170    /// the imperative API equivalent to [`InteractiveElement::on_mouse_pressure`].
 171    ///
 172    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 173    pub fn on_mouse_pressure(
 174        &mut self,
 175        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
 176    ) {
 177        self.mouse_pressure_listeners
 178            .push(Box::new(move |event, phase, hitbox, window, cx| {
 179                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
 180                    (listener)(event, window, cx)
 181                }
 182            }));
 183    }
 184
 185    /// Bind the given callback to the mouse pressure event, during the capture phase
 186    /// the imperative API equivalent to [`InteractiveElement::on_mouse_pressure`].
 187    ///
 188    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 189    pub fn capture_mouse_pressure(
 190        &mut self,
 191        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
 192    ) {
 193        self.mouse_pressure_listeners
 194            .push(Box::new(move |event, phase, hitbox, window, cx| {
 195                if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
 196                    (listener)(event, window, cx)
 197                }
 198            }));
 199    }
 200
 201    /// Bind the given callback to the mouse up event for the given button, during the bubble phase.
 202    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up`].
 203    ///
 204    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 205    pub fn on_mouse_up(
 206        &mut self,
 207        button: MouseButton,
 208        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 209    ) {
 210        self.mouse_up_listeners
 211            .push(Box::new(move |event, phase, hitbox, window, cx| {
 212                if phase == DispatchPhase::Bubble
 213                    && event.button == button
 214                    && hitbox.is_hovered(window)
 215                {
 216                    (listener)(event, window, cx)
 217                }
 218            }));
 219    }
 220
 221    /// Bind the given callback to the mouse up event for any button, during the capture phase.
 222    /// The imperative API equivalent to [`InteractiveElement::capture_any_mouse_up`].
 223    ///
 224    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 225    pub fn capture_any_mouse_up(
 226        &mut self,
 227        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 228    ) {
 229        self.mouse_up_listeners
 230            .push(Box::new(move |event, phase, hitbox, window, cx| {
 231                if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
 232                    (listener)(event, window, cx)
 233                }
 234            }));
 235    }
 236
 237    /// Bind the given callback to the mouse up event for any button, during the bubble phase.
 238    /// The imperative API equivalent to [`Interactivity::on_any_mouse_up`].
 239    ///
 240    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 241    pub fn on_any_mouse_up(
 242        &mut self,
 243        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 244    ) {
 245        self.mouse_up_listeners
 246            .push(Box::new(move |event, phase, hitbox, window, cx| {
 247                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
 248                    (listener)(event, window, cx)
 249                }
 250            }));
 251    }
 252
 253    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 254    /// when the mouse is outside of the bounds of this element.
 255    /// The imperative API equivalent to [`InteractiveElement::on_mouse_down_out`].
 256    ///
 257    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 258    pub fn on_mouse_down_out(
 259        &mut self,
 260        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 261    ) {
 262        self.mouse_down_listeners
 263            .push(Box::new(move |event, phase, hitbox, window, cx| {
 264                if phase == DispatchPhase::Capture && !hitbox.contains(&window.mouse_position()) {
 265                    (listener)(event, window, cx)
 266                }
 267            }));
 268    }
 269
 270    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 271    /// when the mouse is outside of the bounds of this element.
 272    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up_out`].
 273    ///
 274    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 275    pub fn on_mouse_up_out(
 276        &mut self,
 277        button: MouseButton,
 278        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 279    ) {
 280        self.mouse_up_listeners
 281            .push(Box::new(move |event, phase, hitbox, window, cx| {
 282                if phase == DispatchPhase::Capture
 283                    && event.button == button
 284                    && !hitbox.is_hovered(window)
 285                {
 286                    (listener)(event, window, cx);
 287                }
 288            }));
 289    }
 290
 291    /// Bind the given callback to the mouse move event, during the bubble phase.
 292    /// The imperative API equivalent to [`InteractiveElement::on_mouse_move`].
 293    ///
 294    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 295    pub fn on_mouse_move(
 296        &mut self,
 297        listener: impl Fn(&MouseMoveEvent, &mut Window, &mut App) + 'static,
 298    ) {
 299        self.mouse_move_listeners
 300            .push(Box::new(move |event, phase, hitbox, window, cx| {
 301                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
 302                    (listener)(event, window, cx);
 303                }
 304            }));
 305    }
 306
 307    /// Bind the given callback to the mouse drag event of the given type. Note that this
 308    /// will be called for all move events, inside or outside of this element, as long as the
 309    /// drag was started with this element under the mouse. Useful for implementing draggable
 310    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 311    /// The imperative API equivalent to [`InteractiveElement::on_drag_move`].
 312    ///
 313    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 314    pub fn on_drag_move<T>(
 315        &mut self,
 316        listener: impl Fn(&DragMoveEvent<T>, &mut Window, &mut App) + 'static,
 317    ) where
 318        T: 'static,
 319    {
 320        self.mouse_move_listeners
 321            .push(Box::new(move |event, phase, hitbox, window, cx| {
 322                if phase == DispatchPhase::Capture
 323                    && let Some(drag) = &cx.active_drag
 324                    && drag.value.as_ref().type_id() == TypeId::of::<T>()
 325                {
 326                    (listener)(
 327                        &DragMoveEvent {
 328                            event: event.clone(),
 329                            bounds: hitbox.bounds,
 330                            drag: PhantomData,
 331                            dragged_item: Arc::clone(&drag.value),
 332                        },
 333                        window,
 334                        cx,
 335                    );
 336                }
 337            }));
 338    }
 339
 340    /// Bind the given callback to scroll wheel events during the bubble phase.
 341    /// The imperative API equivalent to [`InteractiveElement::on_scroll_wheel`].
 342    ///
 343    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 344    pub fn on_scroll_wheel(
 345        &mut self,
 346        listener: impl Fn(&ScrollWheelEvent, &mut Window, &mut App) + 'static,
 347    ) {
 348        self.scroll_wheel_listeners
 349            .push(Box::new(move |event, phase, hitbox, window, cx| {
 350                if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
 351                    (listener)(event, window, cx);
 352                }
 353            }));
 354    }
 355
 356    /// Bind the given callback to an action dispatch during the capture phase.
 357    /// The imperative API equivalent to [`InteractiveElement::capture_action`].
 358    ///
 359    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 360    pub fn capture_action<A: Action>(
 361        &mut self,
 362        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
 363    ) {
 364        self.action_listeners.push((
 365            TypeId::of::<A>(),
 366            Box::new(move |action, phase, window, cx| {
 367                let action = action.downcast_ref().unwrap();
 368                if phase == DispatchPhase::Capture {
 369                    (listener)(action, window, cx)
 370                } else {
 371                    cx.propagate();
 372                }
 373            }),
 374        ));
 375    }
 376
 377    /// Bind the given callback to an action dispatch during the bubble phase.
 378    /// The imperative API equivalent to [`InteractiveElement::on_action`].
 379    ///
 380    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 381    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Window, &mut App) + 'static) {
 382        self.action_listeners.push((
 383            TypeId::of::<A>(),
 384            Box::new(move |action, phase, window, cx| {
 385                let action = action.downcast_ref().unwrap();
 386                if phase == DispatchPhase::Bubble {
 387                    (listener)(action, window, cx)
 388                }
 389            }),
 390        ));
 391    }
 392
 393    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 394    /// instead of a type parameter. Useful for component libraries that want to expose
 395    /// action bindings to their users.
 396    /// The imperative API equivalent to [`InteractiveElement::on_boxed_action`].
 397    ///
 398    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 399    pub fn on_boxed_action(
 400        &mut self,
 401        action: &dyn Action,
 402        listener: impl Fn(&dyn Action, &mut Window, &mut App) + 'static,
 403    ) {
 404        let action = action.boxed_clone();
 405        self.action_listeners.push((
 406            (*action).type_id(),
 407            Box::new(move |_, phase, window, cx| {
 408                if phase == DispatchPhase::Bubble {
 409                    (listener)(&*action, window, cx)
 410                }
 411            }),
 412        ));
 413    }
 414
 415    /// Bind the given callback to key down events during the bubble phase.
 416    /// The imperative API equivalent to [`InteractiveElement::on_key_down`].
 417    ///
 418    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 419    pub fn on_key_down(
 420        &mut self,
 421        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
 422    ) {
 423        self.key_down_listeners
 424            .push(Box::new(move |event, phase, window, cx| {
 425                if phase == DispatchPhase::Bubble {
 426                    (listener)(event, window, cx)
 427                }
 428            }));
 429    }
 430
 431    /// Bind the given callback to key down events during the capture phase.
 432    /// The imperative API equivalent to [`InteractiveElement::capture_key_down`].
 433    ///
 434    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 435    pub fn capture_key_down(
 436        &mut self,
 437        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
 438    ) {
 439        self.key_down_listeners
 440            .push(Box::new(move |event, phase, window, cx| {
 441                if phase == DispatchPhase::Capture {
 442                    listener(event, window, cx)
 443                }
 444            }));
 445    }
 446
 447    /// Bind the given callback to key up events during the bubble phase.
 448    /// The imperative API equivalent to [`InteractiveElement::on_key_up`].
 449    ///
 450    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 451    pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static) {
 452        self.key_up_listeners
 453            .push(Box::new(move |event, phase, window, cx| {
 454                if phase == DispatchPhase::Bubble {
 455                    listener(event, window, cx)
 456                }
 457            }));
 458    }
 459
 460    /// Bind the given callback to key up events during the capture phase.
 461    /// The imperative API equivalent to [`InteractiveElement::on_key_up`].
 462    ///
 463    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 464    pub fn capture_key_up(
 465        &mut self,
 466        listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static,
 467    ) {
 468        self.key_up_listeners
 469            .push(Box::new(move |event, phase, window, cx| {
 470                if phase == DispatchPhase::Capture {
 471                    listener(event, window, cx)
 472                }
 473            }));
 474    }
 475
 476    /// Bind the given callback to modifiers changing events.
 477    /// The imperative API equivalent to [`InteractiveElement::on_modifiers_changed`].
 478    ///
 479    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 480    pub fn on_modifiers_changed(
 481        &mut self,
 482        listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
 483    ) {
 484        self.modifiers_changed_listeners
 485            .push(Box::new(move |event, window, cx| {
 486                listener(event, window, cx)
 487            }));
 488    }
 489
 490    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element.
 491    /// The imperative API equivalent to [`InteractiveElement::on_drop`].
 492    ///
 493    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 494    pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut Window, &mut App) + 'static) {
 495        self.drop_listeners.push((
 496            TypeId::of::<T>(),
 497            Box::new(move |dragged_value, window, cx| {
 498                listener(dragged_value.downcast_ref().unwrap(), window, cx);
 499            }),
 500        ));
 501    }
 502
 503    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element.
 504    /// The imperative API equivalent to [`InteractiveElement::can_drop`].
 505    pub fn can_drop(
 506        &mut self,
 507        predicate: impl Fn(&dyn Any, &mut Window, &mut App) -> bool + 'static,
 508    ) {
 509        self.can_drop_predicate = Some(Box::new(predicate));
 510    }
 511
 512    /// Bind the given callback to click events of this element.
 513    /// The imperative API equivalent to [`StatefulInteractiveElement::on_click`].
 514    ///
 515    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 516    pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static)
 517    where
 518        Self: Sized,
 519    {
 520        self.click_listeners.push(Rc::new(move |event, window, cx| {
 521            listener(event, window, cx)
 522        }));
 523    }
 524
 525    /// Bind the given callback to non-primary click events of this element.
 526    /// The imperative API equivalent to [`StatefulInteractiveElement::on_aux_click`].
 527    ///
 528    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 529    pub fn on_aux_click(&mut self, listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static)
 530    where
 531        Self: Sized,
 532    {
 533        self.aux_click_listeners
 534            .push(Rc::new(move |event, window, cx| {
 535                listener(event, window, cx)
 536            }));
 537    }
 538
 539    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 540    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 541    /// the [`Self::on_drag_move`] API.
 542    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`].
 543    ///
 544    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 545    pub fn on_drag<T, W>(
 546        &mut self,
 547        value: T,
 548        constructor: impl Fn(&T, Point<Pixels>, &mut Window, &mut App) -> Entity<W> + 'static,
 549    ) where
 550        Self: Sized,
 551        T: 'static,
 552        W: 'static + Render,
 553    {
 554        debug_assert!(
 555            self.drag_listener.is_none(),
 556            "calling on_drag more than once on the same element is not supported"
 557        );
 558        self.drag_listener = Some((
 559            Arc::new(value),
 560            Box::new(move |value, offset, window, cx| {
 561                constructor(value.downcast_ref().unwrap(), offset, window, cx).into()
 562            }),
 563        ));
 564    }
 565
 566    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 567    /// passed to the callback is true when the hover starts and false when it ends.
 568    /// The imperative API equivalent to [`StatefulInteractiveElement::on_hover`].
 569    ///
 570    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 571    pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut Window, &mut App) + 'static)
 572    where
 573        Self: Sized,
 574    {
 575        debug_assert!(
 576            self.hover_listener.is_none(),
 577            "calling on_hover more than once on the same element is not supported"
 578        );
 579        self.hover_listener = Some(Box::new(listener));
 580    }
 581
 582    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 583    /// The imperative API equivalent to [`StatefulInteractiveElement::tooltip`].
 584    pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static)
 585    where
 586        Self: Sized,
 587    {
 588        debug_assert!(
 589            self.tooltip_builder.is_none(),
 590            "calling tooltip more than once on the same element is not supported"
 591        );
 592        self.tooltip_builder = Some(TooltipBuilder {
 593            build: Rc::new(build_tooltip),
 594            hoverable: false,
 595        });
 596    }
 597
 598    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 599    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
 600    /// the tooltip. The imperative API equivalent to [`StatefulInteractiveElement::hoverable_tooltip`].
 601    pub fn hoverable_tooltip(
 602        &mut self,
 603        build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
 604    ) where
 605        Self: Sized,
 606    {
 607        debug_assert!(
 608            self.tooltip_builder.is_none(),
 609            "calling tooltip more than once on the same element is not supported"
 610        );
 611        self.tooltip_builder = Some(TooltipBuilder {
 612            build: Rc::new(build_tooltip),
 613            hoverable: true,
 614        });
 615    }
 616
 617    /// Block the mouse from all interactions with elements behind this element's hitbox. Typically
 618    /// `block_mouse_except_scroll` should be preferred.
 619    ///
 620    /// The imperative API equivalent to [`InteractiveElement::occlude`]
 621    pub fn occlude_mouse(&mut self) {
 622        self.hitbox_behavior = HitboxBehavior::BlockMouse;
 623    }
 624
 625    /// Set the bounds of this element as a window control area for the platform window.
 626    /// The imperative API equivalent to [`InteractiveElement::window_control_area`]
 627    pub fn window_control_area(&mut self, area: WindowControlArea) {
 628        self.window_control = Some(area);
 629    }
 630
 631    /// Block non-scroll mouse interactions with elements behind this element's hitbox.
 632    /// The imperative API equivalent to [`InteractiveElement::block_mouse_except_scroll`].
 633    ///
 634    /// See [`Hitbox::is_hovered`] for details.
 635    pub fn block_mouse_except_scroll(&mut self) {
 636        self.hitbox_behavior = HitboxBehavior::BlockMouseExceptScroll;
 637    }
 638}
 639
 640/// A trait for elements that want to use the standard GPUI event handlers that don't
 641/// require any state.
 642pub trait InteractiveElement: Sized {
 643    /// Retrieve the interactivity state associated with this element
 644    fn interactivity(&mut self) -> &mut Interactivity;
 645
 646    /// Assign this element to a group of elements that can be styled together
 647    fn group(mut self, group: impl Into<SharedString>) -> Self {
 648        self.interactivity().group = Some(group.into());
 649        self
 650    }
 651
 652    /// Assign this element an ID, so that it can be used with interactivity
 653    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
 654        self.interactivity().element_id = Some(id.into());
 655
 656        Stateful { element: self }
 657    }
 658
 659    /// Track the focus state of the given focus handle on this element.
 660    /// If the focus handle is focused by the application, this element will
 661    /// apply its focused styles.
 662    fn track_focus(mut self, focus_handle: &FocusHandle) -> Self {
 663        self.interactivity().focusable = true;
 664        self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
 665        self
 666    }
 667
 668    /// Set whether this element is a tab stop.
 669    ///
 670    /// When false, the element remains in tab-index order but cannot be reached via keyboard navigation.
 671    /// Useful for container elements: focus the container, then call `window.focus_next(cx)` to focus
 672    /// the first tab stop inside it while having the container element itself be unreachable via the keyboard.
 673    /// Should only be used with `tab_index`.
 674    fn tab_stop(mut self, tab_stop: bool) -> Self {
 675        self.interactivity().tab_stop = tab_stop;
 676        self
 677    }
 678
 679    /// Set index of the tab stop order, and set this node as a tab stop.
 680    /// This will default the element to being a tab stop. See [`Self::tab_stop`] for more information.
 681    /// This should only be used in conjunction with `tab_group`
 682    /// in order to not interfere with the tab index of other elements.
 683    fn tab_index(mut self, index: isize) -> Self {
 684        self.interactivity().focusable = true;
 685        self.interactivity().tab_index = Some(index);
 686        self.interactivity().tab_stop = true;
 687        self
 688    }
 689
 690    /// Designate this div as a "tab group". Tab groups have their own location in the tab-index order,
 691    /// but for children of the tab group, the tab index is reset to 0. This can be useful for swapping
 692    /// the order of tab stops within the group, without having to renumber all the tab stops in the whole
 693    /// application.
 694    fn tab_group(mut self) -> Self {
 695        self.interactivity().tab_group = true;
 696        if self.interactivity().tab_index.is_none() {
 697            self.interactivity().tab_index = Some(0);
 698        }
 699        self
 700    }
 701
 702    /// Set the keymap context for this element. This will be used to determine
 703    /// which action to dispatch from the keymap.
 704    fn key_context<C, E>(mut self, key_context: C) -> Self
 705    where
 706        C: TryInto<KeyContext, Error = E>,
 707        E: Debug,
 708    {
 709        if let Some(key_context) = key_context.try_into().log_err() {
 710            self.interactivity().key_context = Some(key_context);
 711        }
 712        self
 713    }
 714
 715    /// Apply the given style to this element when the mouse hovers over it
 716    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 717        debug_assert!(
 718            self.interactivity().hover_style.is_none(),
 719            "hover style already set"
 720        );
 721        self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
 722        self
 723    }
 724
 725    /// Apply the given style to this element when the mouse hovers over a group member
 726    fn group_hover(
 727        mut self,
 728        group_name: impl Into<SharedString>,
 729        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 730    ) -> Self {
 731        self.interactivity().group_hover_style = Some(GroupStyle {
 732            group: group_name.into(),
 733            style: Box::new(f(StyleRefinement::default())),
 734        });
 735        self
 736    }
 737
 738    /// Bind the given callback to the mouse down event for the given mouse button.
 739    /// The fluent API equivalent to [`Interactivity::on_mouse_down`].
 740    ///
 741    /// See [`Context::listener`](crate::Context::listener) to get access to the view state from this callback.
 742    fn on_mouse_down(
 743        mut self,
 744        button: MouseButton,
 745        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 746    ) -> Self {
 747        self.interactivity().on_mouse_down(button, listener);
 748        self
 749    }
 750
 751    #[cfg(any(test, feature = "test-support"))]
 752    /// Set a key that can be used to look up this element's bounds
 753    /// in the [`crate::VisualTestContext::debug_bounds`] map
 754    /// This is a noop in release builds
 755    fn debug_selector(mut self, f: impl FnOnce() -> String) -> Self {
 756        self.interactivity().debug_selector = Some(f());
 757        self
 758    }
 759
 760    #[cfg(not(any(test, feature = "test-support")))]
 761    /// Set a key that can be used to look up this element's bounds
 762    /// in the [`crate::VisualTestContext::debug_bounds`] map
 763    /// This is a noop in release builds
 764    #[inline]
 765    fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
 766        self
 767    }
 768
 769    /// Bind the given callback to the mouse down event for any button, during the capture phase.
 770    /// The fluent API equivalent to [`Interactivity::capture_any_mouse_down`].
 771    ///
 772    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 773    fn capture_any_mouse_down(
 774        mut self,
 775        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 776    ) -> Self {
 777        self.interactivity().capture_any_mouse_down(listener);
 778        self
 779    }
 780
 781    /// Bind the given callback to the mouse down event for any button, during the capture phase.
 782    /// The fluent API equivalent to [`Interactivity::on_any_mouse_down`].
 783    ///
 784    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 785    fn on_any_mouse_down(
 786        mut self,
 787        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 788    ) -> Self {
 789        self.interactivity().on_any_mouse_down(listener);
 790        self
 791    }
 792
 793    /// Bind the given callback to the mouse up event for the given button, during the bubble phase.
 794    /// The fluent API equivalent to [`Interactivity::on_mouse_up`].
 795    ///
 796    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 797    fn on_mouse_up(
 798        mut self,
 799        button: MouseButton,
 800        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 801    ) -> Self {
 802        self.interactivity().on_mouse_up(button, listener);
 803        self
 804    }
 805
 806    /// Bind the given callback to the mouse up event for any button, during the capture phase.
 807    /// The fluent API equivalent to [`Interactivity::capture_any_mouse_up`].
 808    ///
 809    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 810    fn capture_any_mouse_up(
 811        mut self,
 812        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 813    ) -> Self {
 814        self.interactivity().capture_any_mouse_up(listener);
 815        self
 816    }
 817
 818    /// Bind the given callback to the mouse pressure event, during the bubble phase
 819    /// the fluent API equivalent to [`Interactivity::on_mouse_pressure`]
 820    ///
 821    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 822    fn on_mouse_pressure(
 823        mut self,
 824        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
 825    ) -> Self {
 826        self.interactivity().on_mouse_pressure(listener);
 827        self
 828    }
 829
 830    /// Bind the given callback to the mouse pressure event, during the capture phase
 831    /// the fluent API equivalent to [`Interactivity::on_mouse_pressure`]
 832    ///
 833    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 834    fn capture_mouse_pressure(
 835        mut self,
 836        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
 837    ) -> Self {
 838        self.interactivity().capture_mouse_pressure(listener);
 839        self
 840    }
 841
 842    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 843    /// when the mouse is outside of the bounds of this element.
 844    /// The fluent API equivalent to [`Interactivity::on_mouse_down_out`].
 845    ///
 846    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 847    fn on_mouse_down_out(
 848        mut self,
 849        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
 850    ) -> Self {
 851        self.interactivity().on_mouse_down_out(listener);
 852        self
 853    }
 854
 855    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 856    /// when the mouse is outside of the bounds of this element.
 857    /// The fluent API equivalent to [`Interactivity::on_mouse_up_out`].
 858    ///
 859    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 860    fn on_mouse_up_out(
 861        mut self,
 862        button: MouseButton,
 863        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
 864    ) -> Self {
 865        self.interactivity().on_mouse_up_out(button, listener);
 866        self
 867    }
 868
 869    /// Bind the given callback to the mouse move event, during the bubble phase.
 870    /// The fluent API equivalent to [`Interactivity::on_mouse_move`].
 871    ///
 872    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 873    fn on_mouse_move(
 874        mut self,
 875        listener: impl Fn(&MouseMoveEvent, &mut Window, &mut App) + 'static,
 876    ) -> Self {
 877        self.interactivity().on_mouse_move(listener);
 878        self
 879    }
 880
 881    /// Bind the given callback to the mouse drag event of the given type. Note that this
 882    /// will be called for all move events, inside or outside of this element, as long as the
 883    /// drag was started with this element under the mouse. Useful for implementing draggable
 884    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 885    /// The fluent API equivalent to [`Interactivity::on_drag_move`].
 886    ///
 887    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 888    fn on_drag_move<T: 'static>(
 889        mut self,
 890        listener: impl Fn(&DragMoveEvent<T>, &mut Window, &mut App) + 'static,
 891    ) -> Self {
 892        self.interactivity().on_drag_move(listener);
 893        self
 894    }
 895
 896    /// Bind the given callback to scroll wheel events during the bubble phase.
 897    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`].
 898    ///
 899    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 900    fn on_scroll_wheel(
 901        mut self,
 902        listener: impl Fn(&ScrollWheelEvent, &mut Window, &mut App) + 'static,
 903    ) -> Self {
 904        self.interactivity().on_scroll_wheel(listener);
 905        self
 906    }
 907
 908    /// Capture the given action, before normal action dispatch can fire.
 909    /// The fluent API equivalent to [`Interactivity::capture_action`].
 910    ///
 911    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 912    fn capture_action<A: Action>(
 913        mut self,
 914        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
 915    ) -> Self {
 916        self.interactivity().capture_action(listener);
 917        self
 918    }
 919
 920    /// Bind the given callback to an action dispatch during the bubble phase.
 921    /// The fluent API equivalent to [`Interactivity::on_action`].
 922    ///
 923    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 924    fn on_action<A: Action>(
 925        mut self,
 926        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
 927    ) -> Self {
 928        self.interactivity().on_action(listener);
 929        self
 930    }
 931
 932    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 933    /// instead of a type parameter. Useful for component libraries that want to expose
 934    /// action bindings to their users.
 935    /// The fluent API equivalent to [`Interactivity::on_boxed_action`].
 936    ///
 937    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 938    fn on_boxed_action(
 939        mut self,
 940        action: &dyn Action,
 941        listener: impl Fn(&dyn Action, &mut Window, &mut App) + 'static,
 942    ) -> Self {
 943        self.interactivity().on_boxed_action(action, listener);
 944        self
 945    }
 946
 947    /// Bind the given callback to key down events during the bubble phase.
 948    /// The fluent API equivalent to [`Interactivity::on_key_down`].
 949    ///
 950    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 951    fn on_key_down(
 952        mut self,
 953        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
 954    ) -> Self {
 955        self.interactivity().on_key_down(listener);
 956        self
 957    }
 958
 959    /// Bind the given callback to key down events during the capture phase.
 960    /// The fluent API equivalent to [`Interactivity::capture_key_down`].
 961    ///
 962    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 963    fn capture_key_down(
 964        mut self,
 965        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
 966    ) -> Self {
 967        self.interactivity().capture_key_down(listener);
 968        self
 969    }
 970
 971    /// Bind the given callback to key up events during the bubble phase.
 972    /// The fluent API equivalent to [`Interactivity::on_key_up`].
 973    ///
 974    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 975    fn on_key_up(
 976        mut self,
 977        listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static,
 978    ) -> Self {
 979        self.interactivity().on_key_up(listener);
 980        self
 981    }
 982
 983    /// Bind the given callback to key up events during the capture phase.
 984    /// The fluent API equivalent to [`Interactivity::capture_key_up`].
 985    ///
 986    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 987    fn capture_key_up(
 988        mut self,
 989        listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static,
 990    ) -> Self {
 991        self.interactivity().capture_key_up(listener);
 992        self
 993    }
 994
 995    /// Bind the given callback to modifiers changing events.
 996    /// The fluent API equivalent to [`Interactivity::on_modifiers_changed`].
 997    ///
 998    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
 999    fn on_modifiers_changed(
1000        mut self,
1001        listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
1002    ) -> Self {
1003        self.interactivity().on_modifiers_changed(listener);
1004        self
1005    }
1006
1007    /// Apply the given style when the given data type is dragged over this element
1008    fn drag_over<S: 'static>(
1009        mut self,
1010        f: impl 'static + Fn(StyleRefinement, &S, &mut Window, &mut App) -> StyleRefinement,
1011    ) -> Self {
1012        self.interactivity().drag_over_styles.push((
1013            TypeId::of::<S>(),
1014            Box::new(move |currently_dragged: &dyn Any, window, cx| {
1015                f(
1016                    StyleRefinement::default(),
1017                    currently_dragged.downcast_ref::<S>().unwrap(),
1018                    window,
1019                    cx,
1020                )
1021            }),
1022        ));
1023        self
1024    }
1025
1026    /// Apply the given style when the given data type is dragged over this element's group
1027    fn group_drag_over<S: 'static>(
1028        mut self,
1029        group_name: impl Into<SharedString>,
1030        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
1031    ) -> Self {
1032        self.interactivity().group_drag_over_styles.push((
1033            TypeId::of::<S>(),
1034            GroupStyle {
1035                group: group_name.into(),
1036                style: Box::new(f(StyleRefinement::default())),
1037            },
1038        ));
1039        self
1040    }
1041
1042    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element.
1043    /// The fluent API equivalent to [`Interactivity::on_drop`].
1044    ///
1045    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1046    fn on_drop<T: 'static>(
1047        mut self,
1048        listener: impl Fn(&T, &mut Window, &mut App) + 'static,
1049    ) -> Self {
1050        self.interactivity().on_drop(listener);
1051        self
1052    }
1053
1054    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element.
1055    /// The fluent API equivalent to [`Interactivity::can_drop`].
1056    fn can_drop(
1057        mut self,
1058        predicate: impl Fn(&dyn Any, &mut Window, &mut App) -> bool + 'static,
1059    ) -> Self {
1060        self.interactivity().can_drop(predicate);
1061        self
1062    }
1063
1064    /// Block the mouse from all interactions with elements behind this element's hitbox. Typically
1065    /// `block_mouse_except_scroll` should be preferred.
1066    /// The fluent API equivalent to [`Interactivity::occlude_mouse`].
1067    fn occlude(mut self) -> Self {
1068        self.interactivity().occlude_mouse();
1069        self
1070    }
1071
1072    /// Set the bounds of this element as a window control area for the platform window.
1073    /// The fluent API equivalent to [`Interactivity::window_control_area`].
1074    fn window_control_area(mut self, area: WindowControlArea) -> Self {
1075        self.interactivity().window_control_area(area);
1076        self
1077    }
1078
1079    /// Block non-scroll mouse interactions with elements behind this element's hitbox.
1080    /// The fluent API equivalent to [`Interactivity::block_mouse_except_scroll`].
1081    ///
1082    /// See [`Hitbox::is_hovered`] for details.
1083    fn block_mouse_except_scroll(mut self) -> Self {
1084        self.interactivity().block_mouse_except_scroll();
1085        self
1086    }
1087
1088    /// Set the given styles to be applied when this element, specifically, is focused.
1089    /// Requires that the element is focusable. Elements can be made focusable using [`InteractiveElement::track_focus`].
1090    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1091    where
1092        Self: Sized,
1093    {
1094        self.interactivity().focus_style = Some(Box::new(f(StyleRefinement::default())));
1095        self
1096    }
1097
1098    /// Set the given styles to be applied when this element is inside another element that is focused.
1099    /// Requires that the element is focusable. Elements can be made focusable using [`InteractiveElement::track_focus`].
1100    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1101    where
1102        Self: Sized,
1103    {
1104        self.interactivity().in_focus_style = Some(Box::new(f(StyleRefinement::default())));
1105        self
1106    }
1107
1108    /// Set the given styles to be applied when this element is focused via keyboard navigation.
1109    /// This is similar to CSS's `:focus-visible` pseudo-class - it only applies when the element
1110    /// is focused AND the user is navigating via keyboard (not mouse clicks).
1111    /// Requires that the element is focusable. Elements can be made focusable using [`InteractiveElement::track_focus`].
1112    fn focus_visible(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1113    where
1114        Self: Sized,
1115    {
1116        self.interactivity().focus_visible_style = Some(Box::new(f(StyleRefinement::default())));
1117        self
1118    }
1119}
1120
1121/// A trait for elements that want to use the standard GPUI interactivity features
1122/// that require state.
1123pub trait StatefulInteractiveElement: InteractiveElement {
1124    /// Set this element to focusable.
1125    fn focusable(mut self) -> Self {
1126        self.interactivity().focusable = true;
1127        self
1128    }
1129
1130    /// Set the overflow x and y to scroll.
1131    fn overflow_scroll(mut self) -> Self {
1132        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
1133        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
1134        self
1135    }
1136
1137    /// Set the overflow x to scroll.
1138    fn overflow_x_scroll(mut self) -> Self {
1139        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
1140        self
1141    }
1142
1143    /// Set the overflow y to scroll.
1144    fn overflow_y_scroll(mut self) -> Self {
1145        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
1146        self
1147    }
1148
1149    /// Set the space to be reserved for rendering the scrollbar.
1150    ///
1151    /// This will only affect the layout of the element when overflow for this element is set to
1152    /// `Overflow::Scroll`.
1153    fn scrollbar_width(mut self, width: impl Into<AbsoluteLength>) -> Self {
1154        self.interactivity().base_style.scrollbar_width = Some(width.into());
1155        self
1156    }
1157
1158    /// Track the scroll state of this element with the given handle.
1159    fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
1160        self.interactivity().tracked_scroll_handle = Some(scroll_handle.clone());
1161        self
1162    }
1163
1164    /// Track the scroll state of this element with the given handle.
1165    fn anchor_scroll(mut self, scroll_anchor: Option<ScrollAnchor>) -> Self {
1166        self.interactivity().scroll_anchor = scroll_anchor;
1167        self
1168    }
1169
1170    /// Set the given styles to be applied when this element is active.
1171    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1172    where
1173        Self: Sized,
1174    {
1175        self.interactivity().active_style = Some(Box::new(f(StyleRefinement::default())));
1176        self
1177    }
1178
1179    /// Set the given styles to be applied when this element's group is active.
1180    fn group_active(
1181        mut self,
1182        group_name: impl Into<SharedString>,
1183        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
1184    ) -> Self
1185    where
1186        Self: Sized,
1187    {
1188        self.interactivity().group_active_style = Some(GroupStyle {
1189            group: group_name.into(),
1190            style: Box::new(f(StyleRefinement::default())),
1191        });
1192        self
1193    }
1194
1195    /// Bind the given callback to click events of this element.
1196    /// The fluent API equivalent to [`Interactivity::on_click`].
1197    ///
1198    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1199    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self
1200    where
1201        Self: Sized,
1202    {
1203        self.interactivity().on_click(listener);
1204        self
1205    }
1206
1207    /// Bind the given callback to non-primary click events of this element.
1208    /// The fluent API equivalent to [`Interactivity::on_aux_click`].
1209    ///
1210    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1211    fn on_aux_click(
1212        mut self,
1213        listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
1214    ) -> Self
1215    where
1216        Self: Sized,
1217    {
1218        self.interactivity().on_aux_click(listener);
1219        self
1220    }
1221
1222    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
1223    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
1224    /// the [`InteractiveElement::on_drag_move`] API.
1225    /// The callback also has access to the offset of triggering click from the origin of parent element.
1226    /// The fluent API equivalent to [`Interactivity::on_drag`].
1227    ///
1228    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1229    fn on_drag<T, W>(
1230        mut self,
1231        value: T,
1232        constructor: impl Fn(&T, Point<Pixels>, &mut Window, &mut App) -> Entity<W> + 'static,
1233    ) -> Self
1234    where
1235        Self: Sized,
1236        T: 'static,
1237        W: 'static + Render,
1238    {
1239        self.interactivity().on_drag(value, constructor);
1240        self
1241    }
1242
1243    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
1244    /// passed to the callback is true when the hover starts and false when it ends.
1245    /// The fluent API equivalent to [`Interactivity::on_hover`].
1246    ///
1247    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1248    fn on_hover(mut self, listener: impl Fn(&bool, &mut Window, &mut App) + 'static) -> Self
1249    where
1250        Self: Sized,
1251    {
1252        self.interactivity().on_hover(listener);
1253        self
1254    }
1255
1256    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1257    /// The fluent API equivalent to [`Interactivity::tooltip`].
1258    fn tooltip(mut self, build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self
1259    where
1260        Self: Sized,
1261    {
1262        self.interactivity().tooltip(build_tooltip);
1263        self
1264    }
1265
1266    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1267    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
1268    /// the tooltip. The fluent API equivalent to [`Interactivity::hoverable_tooltip`].
1269    fn hoverable_tooltip(
1270        mut self,
1271        build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
1272    ) -> Self
1273    where
1274        Self: Sized,
1275    {
1276        self.interactivity().hoverable_tooltip(build_tooltip);
1277        self
1278    }
1279}
1280
1281pub(crate) type MouseDownListener =
1282    Box<dyn Fn(&MouseDownEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1283pub(crate) type MouseUpListener =
1284    Box<dyn Fn(&MouseUpEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1285pub(crate) type MousePressureListener =
1286    Box<dyn Fn(&MousePressureEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1287pub(crate) type MouseMoveListener =
1288    Box<dyn Fn(&MouseMoveEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1289
1290pub(crate) type ScrollWheelListener =
1291    Box<dyn Fn(&ScrollWheelEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1292
1293pub(crate) type ClickListener = Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>;
1294
1295pub(crate) type DragListener =
1296    Box<dyn Fn(&dyn Any, Point<Pixels>, &mut Window, &mut App) -> AnyView + 'static>;
1297
1298type DropListener = Box<dyn Fn(&dyn Any, &mut Window, &mut App) + 'static>;
1299
1300type CanDropPredicate = Box<dyn Fn(&dyn Any, &mut Window, &mut App) -> bool + 'static>;
1301
1302pub(crate) struct TooltipBuilder {
1303    build: Rc<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>,
1304    hoverable: bool,
1305}
1306
1307pub(crate) type KeyDownListener =
1308    Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut Window, &mut App) + 'static>;
1309
1310pub(crate) type KeyUpListener =
1311    Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut Window, &mut App) + 'static>;
1312
1313pub(crate) type ModifiersChangedListener =
1314    Box<dyn Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static>;
1315
1316pub(crate) type ActionListener =
1317    Box<dyn Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
1318
1319/// Construct a new [`Div`] element
1320#[track_caller]
1321pub fn div() -> Div {
1322    Div {
1323        interactivity: Interactivity::new(),
1324        children: SmallVec::default(),
1325        prepaint_listener: None,
1326        image_cache: None,
1327        prepaint_order_fn: None,
1328    }
1329}
1330
1331/// A [`Div`] element, the all-in-one element for building complex UIs in GPUI
1332pub struct Div {
1333    interactivity: Interactivity,
1334    children: SmallVec<[StackSafe<AnyElement>; 2]>,
1335    prepaint_listener: Option<Box<dyn Fn(Vec<Bounds<Pixels>>, &mut Window, &mut App) + 'static>>,
1336    image_cache: Option<Box<dyn ImageCacheProvider>>,
1337    prepaint_order_fn: Option<Box<dyn Fn(&mut Window, &mut App) -> SmallVec<[usize; 8]>>>,
1338}
1339
1340impl Div {
1341    /// Add a listener to be called when the children of this `Div` are prepainted.
1342    /// This allows you to store the [`Bounds`] of the children for later use.
1343    pub fn on_children_prepainted(
1344        mut self,
1345        listener: impl Fn(Vec<Bounds<Pixels>>, &mut Window, &mut App) + 'static,
1346    ) -> Self {
1347        self.prepaint_listener = Some(Box::new(listener));
1348        self
1349    }
1350
1351    /// Add an image cache at the location of this div in the element tree.
1352    pub fn image_cache(mut self, cache: impl ImageCacheProvider) -> Self {
1353        self.image_cache = Some(Box::new(cache));
1354        self
1355    }
1356
1357    /// Specify a function that determines the order in which children are prepainted.
1358    ///
1359    /// The function is called at prepaint time and should return a vector of child indices
1360    /// in the desired prepaint order. Each index should appear exactly once.
1361    ///
1362    /// This is useful when the prepaint of one child affects state that another child reads.
1363    /// For example, in split editor views, the editor with an autoscroll request should
1364    /// be prepainted first so its scroll position update is visible to the other editor.
1365    pub fn with_dynamic_prepaint_order(
1366        mut self,
1367        order_fn: impl Fn(&mut Window, &mut App) -> SmallVec<[usize; 8]> + 'static,
1368    ) -> Self {
1369        self.prepaint_order_fn = Some(Box::new(order_fn));
1370        self
1371    }
1372}
1373
1374/// A frame state for a `Div` element, which contains layout IDs for its children.
1375///
1376/// This struct is used internally by the `Div` element to manage the layout state of its children
1377/// during the UI update cycle. It holds a small vector of `LayoutId` values, each corresponding to
1378/// a child element of the `Div`. These IDs are used to query the layout engine for the computed
1379/// bounds of the children after the layout phase is complete.
1380pub struct DivFrameState {
1381    child_layout_ids: SmallVec<[LayoutId; 2]>,
1382}
1383
1384/// Interactivity state displayed an manipulated in the inspector.
1385#[derive(Clone)]
1386pub struct DivInspectorState {
1387    /// The inspected element's base style. This is used for both inspecting and modifying the
1388    /// state. In the future it will make sense to separate the read and write, possibly tracking
1389    /// the modifications.
1390    #[cfg(any(feature = "inspector", debug_assertions))]
1391    pub base_style: Box<StyleRefinement>,
1392    /// Inspects the bounds of the element.
1393    pub bounds: Bounds<Pixels>,
1394    /// Size of the children of the element, or `bounds.size` if it has no children.
1395    pub content_size: Size<Pixels>,
1396}
1397
1398impl Styled for Div {
1399    fn style(&mut self) -> &mut StyleRefinement {
1400        &mut self.interactivity.base_style
1401    }
1402}
1403
1404impl InteractiveElement for Div {
1405    fn interactivity(&mut self) -> &mut Interactivity {
1406        &mut self.interactivity
1407    }
1408}
1409
1410impl ParentElement for Div {
1411    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
1412        self.children
1413            .extend(elements.into_iter().map(StackSafe::new))
1414    }
1415}
1416
1417impl Element for Div {
1418    type RequestLayoutState = DivFrameState;
1419    type PrepaintState = Option<Hitbox>;
1420
1421    fn id(&self) -> Option<ElementId> {
1422        self.interactivity.element_id.clone()
1423    }
1424
1425    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
1426        self.interactivity.source_location()
1427    }
1428
1429    #[stacksafe]
1430    fn request_layout(
1431        &mut self,
1432        global_id: Option<&GlobalElementId>,
1433        inspector_id: Option<&InspectorElementId>,
1434        window: &mut Window,
1435        cx: &mut App,
1436    ) -> (LayoutId, Self::RequestLayoutState) {
1437        let mut child_layout_ids = SmallVec::new();
1438        let image_cache = self
1439            .image_cache
1440            .as_mut()
1441            .map(|provider| provider.provide(window, cx));
1442
1443        let layout_id = window.with_image_cache(image_cache, |window| {
1444            self.interactivity.request_layout(
1445                global_id,
1446                inspector_id,
1447                window,
1448                cx,
1449                |style, window, cx| {
1450                    window.with_text_style(style.text_style().cloned(), |window| {
1451                        child_layout_ids = self
1452                            .children
1453                            .iter_mut()
1454                            .map(|child| child.request_layout(window, cx))
1455                            .collect::<SmallVec<_>>();
1456                        window.request_layout(style, child_layout_ids.iter().copied(), cx)
1457                    })
1458                },
1459            )
1460        });
1461
1462        (layout_id, DivFrameState { child_layout_ids })
1463    }
1464
1465    #[stacksafe]
1466    fn prepaint(
1467        &mut self,
1468        global_id: Option<&GlobalElementId>,
1469        inspector_id: Option<&InspectorElementId>,
1470        bounds: Bounds<Pixels>,
1471        request_layout: &mut Self::RequestLayoutState,
1472        window: &mut Window,
1473        cx: &mut App,
1474    ) -> Option<Hitbox> {
1475        let image_cache = self
1476            .image_cache
1477            .as_mut()
1478            .map(|provider| provider.provide(window, cx));
1479
1480        let has_prepaint_listener = self.prepaint_listener.is_some();
1481        let mut children_bounds = Vec::with_capacity(if has_prepaint_listener {
1482            request_layout.child_layout_ids.len()
1483        } else {
1484            0
1485        });
1486
1487        let mut child_min = point(Pixels::MAX, Pixels::MAX);
1488        let mut child_max = Point::default();
1489        if let Some(handle) = self.interactivity.scroll_anchor.as_ref() {
1490            *handle.last_origin.borrow_mut() = bounds.origin - window.element_offset();
1491        }
1492        let content_size = if request_layout.child_layout_ids.is_empty() {
1493            bounds.size
1494        } else if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1495            let mut state = scroll_handle.0.borrow_mut();
1496            state.child_bounds = Vec::with_capacity(request_layout.child_layout_ids.len());
1497            for child_layout_id in &request_layout.child_layout_ids {
1498                let child_bounds = window.layout_bounds(*child_layout_id);
1499                child_min = child_min.min(&child_bounds.origin);
1500                child_max = child_max.max(&child_bounds.bottom_right());
1501                state.child_bounds.push(child_bounds);
1502            }
1503            (child_max - child_min).into()
1504        } else {
1505            for child_layout_id in &request_layout.child_layout_ids {
1506                let child_bounds = window.layout_bounds(*child_layout_id);
1507                child_min = child_min.min(&child_bounds.origin);
1508                child_max = child_max.max(&child_bounds.bottom_right());
1509
1510                if has_prepaint_listener {
1511                    children_bounds.push(child_bounds);
1512                }
1513            }
1514            (child_max - child_min).into()
1515        };
1516
1517        if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1518            scroll_handle.scroll_to_active_item();
1519        }
1520
1521        self.interactivity.prepaint(
1522            global_id,
1523            inspector_id,
1524            bounds,
1525            content_size,
1526            window,
1527            cx,
1528            |style, scroll_offset, hitbox, window, cx| {
1529                // skip children
1530                if style.display == Display::None {
1531                    return hitbox;
1532                }
1533
1534                window.with_image_cache(image_cache, |window| {
1535                    window.with_element_offset(scroll_offset, |window| {
1536                        if let Some(order_fn) = &self.prepaint_order_fn {
1537                            let order = order_fn(window, cx);
1538                            for idx in order {
1539                                if let Some(child) = self.children.get_mut(idx) {
1540                                    child.prepaint(window, cx);
1541                                }
1542                            }
1543                        } else {
1544                            for child in &mut self.children {
1545                                child.prepaint(window, cx);
1546                            }
1547                        }
1548                    });
1549
1550                    if let Some(listener) = self.prepaint_listener.as_ref() {
1551                        listener(children_bounds, window, cx);
1552                    }
1553                });
1554
1555                hitbox
1556            },
1557        )
1558    }
1559
1560    #[stacksafe]
1561    fn paint(
1562        &mut self,
1563        global_id: Option<&GlobalElementId>,
1564        inspector_id: Option<&InspectorElementId>,
1565        bounds: Bounds<Pixels>,
1566        _request_layout: &mut Self::RequestLayoutState,
1567        hitbox: &mut Option<Hitbox>,
1568        window: &mut Window,
1569        cx: &mut App,
1570    ) {
1571        let image_cache = self
1572            .image_cache
1573            .as_mut()
1574            .map(|provider| provider.provide(window, cx));
1575
1576        window.with_image_cache(image_cache, |window| {
1577            self.interactivity.paint(
1578                global_id,
1579                inspector_id,
1580                bounds,
1581                hitbox.as_ref(),
1582                window,
1583                cx,
1584                |style, window, cx| {
1585                    // skip children
1586                    if style.display == Display::None {
1587                        return;
1588                    }
1589
1590                    for child in &mut self.children {
1591                        child.paint(window, cx);
1592                    }
1593                },
1594            )
1595        });
1596    }
1597}
1598
1599impl IntoElement for Div {
1600    type Element = Self;
1601
1602    fn into_element(self) -> Self::Element {
1603        self
1604    }
1605}
1606
1607/// The interactivity struct. Powers all of the general-purpose
1608/// interactivity in the `Div` element.
1609#[derive(Default)]
1610pub struct Interactivity {
1611    /// The element ID of the element. In id is required to support a stateful subset of the interactivity such as on_click.
1612    pub element_id: Option<ElementId>,
1613    /// Whether the element was clicked. This will only be present after layout.
1614    pub active: Option<bool>,
1615    /// Whether the element was hovered. This will only be present after paint if an hitbox
1616    /// was created for the interactive element.
1617    pub hovered: Option<bool>,
1618    pub(crate) tooltip_id: Option<TooltipId>,
1619    pub(crate) content_size: Size<Pixels>,
1620    pub(crate) key_context: Option<KeyContext>,
1621    pub(crate) focusable: bool,
1622    pub(crate) tracked_focus_handle: Option<FocusHandle>,
1623    pub(crate) tracked_scroll_handle: Option<ScrollHandle>,
1624    pub(crate) scroll_anchor: Option<ScrollAnchor>,
1625    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
1626    pub(crate) group: Option<SharedString>,
1627    /// The base style of the element, before any modifications are applied
1628    /// by focus, active, etc.
1629    pub base_style: Box<StyleRefinement>,
1630    pub(crate) focus_style: Option<Box<StyleRefinement>>,
1631    pub(crate) in_focus_style: Option<Box<StyleRefinement>>,
1632    pub(crate) focus_visible_style: Option<Box<StyleRefinement>>,
1633    pub(crate) hover_style: Option<Box<StyleRefinement>>,
1634    pub(crate) group_hover_style: Option<GroupStyle>,
1635    pub(crate) active_style: Option<Box<StyleRefinement>>,
1636    pub(crate) group_active_style: Option<GroupStyle>,
1637    pub(crate) drag_over_styles: Vec<(
1638        TypeId,
1639        Box<dyn Fn(&dyn Any, &mut Window, &mut App) -> StyleRefinement>,
1640    )>,
1641    pub(crate) group_drag_over_styles: Vec<(TypeId, GroupStyle)>,
1642    pub(crate) mouse_down_listeners: Vec<MouseDownListener>,
1643    pub(crate) mouse_up_listeners: Vec<MouseUpListener>,
1644    pub(crate) mouse_pressure_listeners: Vec<MousePressureListener>,
1645    pub(crate) mouse_move_listeners: Vec<MouseMoveListener>,
1646    pub(crate) scroll_wheel_listeners: Vec<ScrollWheelListener>,
1647    pub(crate) key_down_listeners: Vec<KeyDownListener>,
1648    pub(crate) key_up_listeners: Vec<KeyUpListener>,
1649    pub(crate) modifiers_changed_listeners: Vec<ModifiersChangedListener>,
1650    pub(crate) action_listeners: Vec<(TypeId, ActionListener)>,
1651    pub(crate) drop_listeners: Vec<(TypeId, DropListener)>,
1652    pub(crate) can_drop_predicate: Option<CanDropPredicate>,
1653    pub(crate) click_listeners: Vec<ClickListener>,
1654    pub(crate) aux_click_listeners: Vec<ClickListener>,
1655    pub(crate) drag_listener: Option<(Arc<dyn Any>, DragListener)>,
1656    pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut Window, &mut App)>>,
1657    pub(crate) tooltip_builder: Option<TooltipBuilder>,
1658    pub(crate) window_control: Option<WindowControlArea>,
1659    pub(crate) hitbox_behavior: HitboxBehavior,
1660    pub(crate) tab_index: Option<isize>,
1661    pub(crate) tab_group: bool,
1662    pub(crate) tab_stop: bool,
1663
1664    #[cfg(any(feature = "inspector", debug_assertions))]
1665    pub(crate) source_location: Option<&'static core::panic::Location<'static>>,
1666
1667    #[cfg(any(test, feature = "test-support"))]
1668    pub(crate) debug_selector: Option<String>,
1669}
1670
1671impl Interactivity {
1672    /// Layout this element according to this interactivity state's configured styles
1673    pub fn request_layout(
1674        &mut self,
1675        global_id: Option<&GlobalElementId>,
1676        _inspector_id: Option<&InspectorElementId>,
1677        window: &mut Window,
1678        cx: &mut App,
1679        f: impl FnOnce(Style, &mut Window, &mut App) -> LayoutId,
1680    ) -> LayoutId {
1681        #[cfg(any(feature = "inspector", debug_assertions))]
1682        window.with_inspector_state(
1683            _inspector_id,
1684            cx,
1685            |inspector_state: &mut Option<DivInspectorState>, _window| {
1686                if let Some(inspector_state) = inspector_state {
1687                    self.base_style = inspector_state.base_style.clone();
1688                } else {
1689                    *inspector_state = Some(DivInspectorState {
1690                        base_style: self.base_style.clone(),
1691                        bounds: Default::default(),
1692                        content_size: Default::default(),
1693                    })
1694                }
1695            },
1696        );
1697
1698        window.with_optional_element_state::<InteractiveElementState, _>(
1699            global_id,
1700            |element_state, window| {
1701                let mut element_state =
1702                    element_state.map(|element_state| element_state.unwrap_or_default());
1703
1704                if let Some(element_state) = element_state.as_ref()
1705                    && cx.has_active_drag()
1706                {
1707                    if let Some(pending_mouse_down) = element_state.pending_mouse_down.as_ref() {
1708                        *pending_mouse_down.borrow_mut() = None;
1709                    }
1710                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1711                        *clicked_state.borrow_mut() = ElementClickedState::default();
1712                    }
1713                }
1714
1715                // Ensure we store a focus handle in our element state if we're focusable.
1716                // If there's an explicit focus handle we're tracking, use that. Otherwise
1717                // create a new handle and store it in the element state, which lives for as
1718                // as frames contain an element with this id.
1719                if self.focusable
1720                    && self.tracked_focus_handle.is_none()
1721                    && let Some(element_state) = element_state.as_mut()
1722                {
1723                    let mut handle = element_state
1724                        .focus_handle
1725                        .get_or_insert_with(|| cx.focus_handle())
1726                        .clone()
1727                        .tab_stop(self.tab_stop);
1728
1729                    if let Some(index) = self.tab_index {
1730                        handle = handle.tab_index(index);
1731                    }
1732
1733                    self.tracked_focus_handle = Some(handle);
1734                }
1735
1736                if let Some(scroll_handle) = self.tracked_scroll_handle.as_ref() {
1737                    self.scroll_offset = Some(scroll_handle.0.borrow().offset.clone());
1738                } else if (self.base_style.overflow.x == Some(Overflow::Scroll)
1739                    || self.base_style.overflow.y == Some(Overflow::Scroll))
1740                    && let Some(element_state) = element_state.as_mut()
1741                {
1742                    self.scroll_offset = Some(
1743                        element_state
1744                            .scroll_offset
1745                            .get_or_insert_with(Rc::default)
1746                            .clone(),
1747                    );
1748                }
1749
1750                let style = self.compute_style_internal(None, element_state.as_mut(), window, cx);
1751                let layout_id = f(style, window, cx);
1752                (layout_id, element_state)
1753            },
1754        )
1755    }
1756
1757    /// Commit the bounds of this element according to this interactivity state's configured styles.
1758    pub fn prepaint<R>(
1759        &mut self,
1760        global_id: Option<&GlobalElementId>,
1761        _inspector_id: Option<&InspectorElementId>,
1762        bounds: Bounds<Pixels>,
1763        content_size: Size<Pixels>,
1764        window: &mut Window,
1765        cx: &mut App,
1766        f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut Window, &mut App) -> R,
1767    ) -> R {
1768        self.content_size = content_size;
1769
1770        #[cfg(any(feature = "inspector", debug_assertions))]
1771        window.with_inspector_state(
1772            _inspector_id,
1773            cx,
1774            |inspector_state: &mut Option<DivInspectorState>, _window| {
1775                if let Some(inspector_state) = inspector_state {
1776                    inspector_state.bounds = bounds;
1777                    inspector_state.content_size = content_size;
1778                }
1779            },
1780        );
1781
1782        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1783            window.set_focus_handle(focus_handle, cx);
1784        }
1785        window.with_optional_element_state::<InteractiveElementState, _>(
1786            global_id,
1787            |element_state, window| {
1788                let mut element_state =
1789                    element_state.map(|element_state| element_state.unwrap_or_default());
1790                let style = self.compute_style_internal(None, element_state.as_mut(), window, cx);
1791
1792                if let Some(element_state) = element_state.as_mut() {
1793                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1794                        let clicked_state = clicked_state.borrow();
1795                        self.active = Some(clicked_state.element);
1796                    }
1797                    if self.hover_style.is_some() || self.group_hover_style.is_some() {
1798                        element_state
1799                            .hover_state
1800                            .get_or_insert_with(Default::default);
1801                    }
1802                    if let Some(active_tooltip) = element_state.active_tooltip.as_ref() {
1803                        if self.tooltip_builder.is_some() {
1804                            self.tooltip_id = set_tooltip_on_window(active_tooltip, window);
1805                        } else {
1806                            // If there is no longer a tooltip builder, remove the active tooltip.
1807                            element_state.active_tooltip.take();
1808                        }
1809                    }
1810                }
1811
1812                window.with_text_style(style.text_style().cloned(), |window| {
1813                    window.with_content_mask(
1814                        style.overflow_mask(bounds, window.rem_size()),
1815                        |window| {
1816                            let hitbox = if self.should_insert_hitbox(&style, window, cx) {
1817                                Some(window.insert_hitbox(bounds, self.hitbox_behavior))
1818                            } else {
1819                                None
1820                            };
1821
1822                            let scroll_offset =
1823                                self.clamp_scroll_position(bounds, &style, window, cx);
1824                            let result = f(&style, scroll_offset, hitbox, window, cx);
1825                            (result, element_state)
1826                        },
1827                    )
1828                })
1829            },
1830        )
1831    }
1832
1833    fn should_insert_hitbox(&self, style: &Style, window: &Window, cx: &App) -> bool {
1834        self.hitbox_behavior != HitboxBehavior::Normal
1835            || self.window_control.is_some()
1836            || style.mouse_cursor.is_some()
1837            || self.group.is_some()
1838            || self.scroll_offset.is_some()
1839            || self.tracked_focus_handle.is_some()
1840            || self.hover_style.is_some()
1841            || self.group_hover_style.is_some()
1842            || self.hover_listener.is_some()
1843            || !self.mouse_up_listeners.is_empty()
1844            || !self.mouse_pressure_listeners.is_empty()
1845            || !self.mouse_down_listeners.is_empty()
1846            || !self.mouse_move_listeners.is_empty()
1847            || !self.click_listeners.is_empty()
1848            || !self.aux_click_listeners.is_empty()
1849            || !self.scroll_wheel_listeners.is_empty()
1850            || self.drag_listener.is_some()
1851            || !self.drop_listeners.is_empty()
1852            || self.tooltip_builder.is_some()
1853            || window.is_inspector_picking(cx)
1854    }
1855
1856    fn clamp_scroll_position(
1857        &self,
1858        bounds: Bounds<Pixels>,
1859        style: &Style,
1860        window: &mut Window,
1861        _cx: &mut App,
1862    ) -> Point<Pixels> {
1863        fn round_to_two_decimals(pixels: Pixels) -> Pixels {
1864            const ROUNDING_FACTOR: f32 = 100.0;
1865            (pixels * ROUNDING_FACTOR).round() / ROUNDING_FACTOR
1866        }
1867
1868        if let Some(scroll_offset) = self.scroll_offset.as_ref() {
1869            let mut scroll_to_bottom = false;
1870            let mut tracked_scroll_handle = self
1871                .tracked_scroll_handle
1872                .as_ref()
1873                .map(|handle| handle.0.borrow_mut());
1874            if let Some(mut scroll_handle_state) = tracked_scroll_handle.as_deref_mut() {
1875                scroll_handle_state.overflow = style.overflow;
1876                scroll_to_bottom = mem::take(&mut scroll_handle_state.scroll_to_bottom);
1877            }
1878
1879            let rem_size = window.rem_size();
1880            let padding = style.padding.to_pixels(bounds.size.into(), rem_size);
1881            let padding_size = size(padding.left + padding.right, padding.top + padding.bottom);
1882            // The floating point values produced by Taffy and ours often vary
1883            // slightly after ~5 decimal places. This can lead to cases where after
1884            // subtracting these, the container becomes scrollable for less than
1885            // 0.00000x pixels. As we generally don't benefit from a precision that
1886            // high for the maximum scroll, we round the scroll max to 2 decimal
1887            // places here.
1888            let padded_content_size = self.content_size + padding_size;
1889            let scroll_max = Point::from(padded_content_size - bounds.size)
1890                .map(round_to_two_decimals)
1891                .max(&Default::default());
1892            // Clamp scroll offset in case scroll max is smaller now (e.g., if children
1893            // were removed or the bounds became larger).
1894            let mut scroll_offset = scroll_offset.borrow_mut();
1895
1896            scroll_offset.x = scroll_offset.x.clamp(-scroll_max.x, px(0.));
1897            if scroll_to_bottom {
1898                scroll_offset.y = -scroll_max.y;
1899            } else {
1900                scroll_offset.y = scroll_offset.y.clamp(-scroll_max.y, px(0.));
1901            }
1902
1903            if let Some(mut scroll_handle_state) = tracked_scroll_handle {
1904                scroll_handle_state.max_offset = scroll_max;
1905                scroll_handle_state.bounds = bounds;
1906            }
1907
1908            *scroll_offset
1909        } else {
1910            Point::default()
1911        }
1912    }
1913
1914    /// Paint this element according to this interactivity state's configured styles
1915    /// and bind the element's mouse and keyboard events.
1916    ///
1917    /// content_size is the size of the content of the element, which may be larger than the
1918    /// element's bounds if the element is scrollable.
1919    ///
1920    /// the final computed style will be passed to the provided function, along
1921    /// with the current scroll offset
1922    pub fn paint(
1923        &mut self,
1924        global_id: Option<&GlobalElementId>,
1925        _inspector_id: Option<&InspectorElementId>,
1926        bounds: Bounds<Pixels>,
1927        hitbox: Option<&Hitbox>,
1928        window: &mut Window,
1929        cx: &mut App,
1930        f: impl FnOnce(&Style, &mut Window, &mut App),
1931    ) {
1932        self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(window));
1933        window.with_optional_element_state::<InteractiveElementState, _>(
1934            global_id,
1935            |element_state, window| {
1936                let mut element_state =
1937                    element_state.map(|element_state| element_state.unwrap_or_default());
1938
1939                let style = self.compute_style_internal(hitbox, element_state.as_mut(), window, cx);
1940
1941                #[cfg(any(feature = "test-support", test))]
1942                if let Some(debug_selector) = &self.debug_selector {
1943                    window
1944                        .next_frame
1945                        .debug_bounds
1946                        .insert(debug_selector.clone(), bounds);
1947                }
1948
1949                self.paint_hover_group_handler(window, cx);
1950
1951                if style.visibility == Visibility::Hidden {
1952                    return ((), element_state);
1953                }
1954
1955                let mut tab_group = None;
1956                if self.tab_group {
1957                    tab_group = self.tab_index;
1958                }
1959                if let Some(focus_handle) = &self.tracked_focus_handle {
1960                    window.next_frame.tab_stops.insert(focus_handle);
1961                }
1962
1963                window.with_element_opacity(style.opacity, |window| {
1964                    style.paint(bounds, window, cx, |window: &mut Window, cx: &mut App| {
1965                        window.with_text_style(style.text_style().cloned(), |window| {
1966                            window.with_content_mask(
1967                                style.overflow_mask(bounds, window.rem_size()),
1968                                |window| {
1969                                    window.with_tab_group(tab_group, |window| {
1970                                        if let Some(hitbox) = hitbox {
1971                                            #[cfg(debug_assertions)]
1972                                            self.paint_debug_info(
1973                                                global_id, hitbox, &style, window, cx,
1974                                            );
1975
1976                                            if let Some(drag) = cx.active_drag.as_ref() {
1977                                                if let Some(mouse_cursor) = drag.cursor_style {
1978                                                    window.set_window_cursor_style(mouse_cursor);
1979                                                }
1980                                            } else {
1981                                                if let Some(mouse_cursor) = style.mouse_cursor {
1982                                                    window.set_cursor_style(mouse_cursor, hitbox);
1983                                                }
1984                                            }
1985
1986                                            if let Some(group) = self.group.clone() {
1987                                                GroupHitboxes::push(group, hitbox.id, cx);
1988                                            }
1989
1990                                            if let Some(area) = self.window_control {
1991                                                window.insert_window_control_hitbox(
1992                                                    area,
1993                                                    hitbox.clone(),
1994                                                );
1995                                            }
1996
1997                                            self.paint_mouse_listeners(
1998                                                hitbox,
1999                                                element_state.as_mut(),
2000                                                window,
2001                                                cx,
2002                                            );
2003                                            self.paint_scroll_listener(hitbox, &style, window, cx);
2004                                        }
2005
2006                                        self.paint_keyboard_listeners(window, cx);
2007                                        f(&style, window, cx);
2008
2009                                        if let Some(_hitbox) = hitbox {
2010                                            #[cfg(any(feature = "inspector", debug_assertions))]
2011                                            window.insert_inspector_hitbox(
2012                                                _hitbox.id,
2013                                                _inspector_id,
2014                                                cx,
2015                                            );
2016
2017                                            if let Some(group) = self.group.as_ref() {
2018                                                GroupHitboxes::pop(group, cx);
2019                                            }
2020                                        }
2021                                    })
2022                                },
2023                            );
2024                        });
2025                    });
2026                });
2027
2028                ((), element_state)
2029            },
2030        );
2031    }
2032
2033    #[cfg(debug_assertions)]
2034    fn paint_debug_info(
2035        &self,
2036        global_id: Option<&GlobalElementId>,
2037        hitbox: &Hitbox,
2038        style: &Style,
2039        window: &mut Window,
2040        cx: &mut App,
2041    ) {
2042        use crate::{BorderStyle, TextAlign};
2043
2044        if let Some(global_id) = global_id
2045            && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
2046            && hitbox.is_hovered(window)
2047        {
2048            const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
2049            let element_id = format!("{global_id:?}");
2050            let str_len = element_id.len();
2051
2052            let render_debug_text = |window: &mut Window| {
2053                if let Some(text) = window
2054                    .text_system()
2055                    .shape_text(
2056                        element_id.into(),
2057                        FONT_SIZE,
2058                        &[window.text_style().to_run(str_len)],
2059                        None,
2060                        None,
2061                    )
2062                    .ok()
2063                    .and_then(|mut text| text.pop())
2064                {
2065                    text.paint(hitbox.origin, FONT_SIZE, TextAlign::Left, None, window, cx)
2066                        .ok();
2067
2068                    let text_bounds = crate::Bounds {
2069                        origin: hitbox.origin,
2070                        size: text.size(FONT_SIZE),
2071                    };
2072                    if let Some(source_location) = self.source_location
2073                        && text_bounds.contains(&window.mouse_position())
2074                        && window.modifiers().secondary()
2075                    {
2076                        let secondary_held = window.modifiers().secondary();
2077                        window.on_key_event({
2078                            move |e: &crate::ModifiersChangedEvent, _phase, window, _cx| {
2079                                if e.modifiers.secondary() != secondary_held
2080                                    && text_bounds.contains(&window.mouse_position())
2081                                {
2082                                    window.refresh();
2083                                }
2084                            }
2085                        });
2086
2087                        let was_hovered = hitbox.is_hovered(window);
2088                        let current_view = window.current_view();
2089                        window.on_mouse_event({
2090                            let hitbox = hitbox.clone();
2091                            move |_: &MouseMoveEvent, phase, window, cx| {
2092                                if phase == DispatchPhase::Capture {
2093                                    let hovered = hitbox.is_hovered(window);
2094                                    if hovered != was_hovered {
2095                                        cx.notify(current_view)
2096                                    }
2097                                }
2098                            }
2099                        });
2100
2101                        window.on_mouse_event({
2102                            let hitbox = hitbox.clone();
2103                            move |e: &crate::MouseDownEvent, phase, window, cx| {
2104                                if text_bounds.contains(&e.position)
2105                                    && phase.capture()
2106                                    && hitbox.is_hovered(window)
2107                                {
2108                                    cx.stop_propagation();
2109                                    let Ok(dir) = std::env::current_dir() else {
2110                                        return;
2111                                    };
2112
2113                                    eprintln!(
2114                                        "This element was created at:\n{}:{}:{}",
2115                                        dir.join(source_location.file()).to_string_lossy(),
2116                                        source_location.line(),
2117                                        source_location.column()
2118                                    );
2119                                }
2120                            }
2121                        });
2122                        window.paint_quad(crate::outline(
2123                            crate::Bounds {
2124                                origin: hitbox.origin
2125                                    + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
2126                                size: crate::Size {
2127                                    width: text_bounds.size.width,
2128                                    height: crate::px(1.),
2129                                },
2130                            },
2131                            crate::red(),
2132                            BorderStyle::default(),
2133                        ))
2134                    }
2135                }
2136            };
2137
2138            window.with_text_style(
2139                Some(crate::TextStyleRefinement {
2140                    color: Some(crate::red()),
2141                    line_height: Some(FONT_SIZE.into()),
2142                    background_color: Some(crate::white()),
2143                    ..Default::default()
2144                }),
2145                render_debug_text,
2146            )
2147        }
2148    }
2149
2150    fn paint_mouse_listeners(
2151        &mut self,
2152        hitbox: &Hitbox,
2153        element_state: Option<&mut InteractiveElementState>,
2154        window: &mut Window,
2155        cx: &mut App,
2156    ) {
2157        let is_focused = self
2158            .tracked_focus_handle
2159            .as_ref()
2160            .map(|handle| handle.is_focused(window))
2161            .unwrap_or(false);
2162
2163        // If this element can be focused, register a mouse down listener
2164        // that will automatically transfer focus when hitting the element.
2165        // This behavior can be suppressed by using `cx.prevent_default()`.
2166        if let Some(focus_handle) = self.tracked_focus_handle.clone() {
2167            let hitbox = hitbox.clone();
2168            window.on_mouse_event(move |_: &MouseDownEvent, phase, window, cx| {
2169                if phase == DispatchPhase::Bubble
2170                    && hitbox.is_hovered(window)
2171                    && !window.default_prevented()
2172                {
2173                    window.focus(&focus_handle, cx);
2174                    // If there is a parent that is also focusable, prevent it
2175                    // from transferring focus because we already did so.
2176                    window.prevent_default();
2177                }
2178            });
2179        }
2180
2181        for listener in self.mouse_down_listeners.drain(..) {
2182            let hitbox = hitbox.clone();
2183            window.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {
2184                listener(event, phase, &hitbox, window, cx);
2185            })
2186        }
2187
2188        for listener in self.mouse_up_listeners.drain(..) {
2189            let hitbox = hitbox.clone();
2190            window.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {
2191                listener(event, phase, &hitbox, window, cx);
2192            })
2193        }
2194
2195        for listener in self.mouse_pressure_listeners.drain(..) {
2196            let hitbox = hitbox.clone();
2197            window.on_mouse_event(move |event: &MousePressureEvent, phase, window, cx| {
2198                listener(event, phase, &hitbox, window, cx);
2199            })
2200        }
2201
2202        for listener in self.mouse_move_listeners.drain(..) {
2203            let hitbox = hitbox.clone();
2204            window.on_mouse_event(move |event: &MouseMoveEvent, phase, window, cx| {
2205                listener(event, phase, &hitbox, window, cx);
2206            })
2207        }
2208
2209        for listener in self.scroll_wheel_listeners.drain(..) {
2210            let hitbox = hitbox.clone();
2211            window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {
2212                listener(event, phase, &hitbox, window, cx);
2213            })
2214        }
2215
2216        if self.hover_style.is_some()
2217            || self.base_style.mouse_cursor.is_some()
2218            || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
2219        {
2220            let hitbox = hitbox.clone();
2221            let hover_state = self.hover_style.as_ref().and_then(|_| {
2222                element_state
2223                    .as_ref()
2224                    .and_then(|state| state.hover_state.as_ref())
2225                    .cloned()
2226            });
2227            let current_view = window.current_view();
2228
2229            window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2230                let hovered = hitbox.is_hovered(window);
2231                let was_hovered = hover_state
2232                    .as_ref()
2233                    .is_some_and(|state| state.borrow().element);
2234                if phase == DispatchPhase::Capture && hovered != was_hovered {
2235                    if let Some(hover_state) = &hover_state {
2236                        hover_state.borrow_mut().element = hovered;
2237                        cx.notify(current_view);
2238                    }
2239                }
2240            });
2241        }
2242
2243        if let Some(group_hover) = self.group_hover_style.as_ref() {
2244            if let Some(group_hitbox_id) = GroupHitboxes::get(&group_hover.group, cx) {
2245                let hover_state = element_state
2246                    .as_ref()
2247                    .and_then(|element| element.hover_state.as_ref())
2248                    .cloned();
2249                let current_view = window.current_view();
2250
2251                window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2252                    let group_hovered = group_hitbox_id.is_hovered(window);
2253                    let was_group_hovered = hover_state
2254                        .as_ref()
2255                        .is_some_and(|state| state.borrow().group);
2256                    if phase == DispatchPhase::Capture && group_hovered != was_group_hovered {
2257                        if let Some(hover_state) = &hover_state {
2258                            hover_state.borrow_mut().group = group_hovered;
2259                        }
2260                        cx.notify(current_view);
2261                    }
2262                });
2263            }
2264        }
2265
2266        let drag_cursor_style = self.base_style.as_ref().mouse_cursor;
2267
2268        let mut drag_listener = mem::take(&mut self.drag_listener);
2269        let drop_listeners = mem::take(&mut self.drop_listeners);
2270        let click_listeners = mem::take(&mut self.click_listeners);
2271        let aux_click_listeners = mem::take(&mut self.aux_click_listeners);
2272        let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
2273
2274        if !drop_listeners.is_empty() {
2275            let hitbox = hitbox.clone();
2276            window.on_mouse_event({
2277                move |_: &MouseUpEvent, phase, window, cx| {
2278                    if let Some(drag) = &cx.active_drag
2279                        && phase == DispatchPhase::Bubble
2280                        && hitbox.is_hovered(window)
2281                    {
2282                        let drag_state_type = drag.value.as_ref().type_id();
2283                        for (drop_state_type, listener) in &drop_listeners {
2284                            if *drop_state_type == drag_state_type {
2285                                let drag = cx
2286                                    .active_drag
2287                                    .take()
2288                                    .expect("checked for type drag state type above");
2289
2290                                let mut can_drop = true;
2291                                if let Some(predicate) = &can_drop_predicate {
2292                                    can_drop = predicate(drag.value.as_ref(), window, cx);
2293                                }
2294
2295                                if can_drop {
2296                                    listener(drag.value.as_ref(), window, cx);
2297                                    window.refresh();
2298                                    cx.stop_propagation();
2299                                }
2300                            }
2301                        }
2302                    }
2303                }
2304            });
2305        }
2306
2307        if let Some(element_state) = element_state {
2308            if !click_listeners.is_empty()
2309                || !aux_click_listeners.is_empty()
2310                || drag_listener.is_some()
2311            {
2312                let pending_mouse_down = element_state
2313                    .pending_mouse_down
2314                    .get_or_insert_with(Default::default)
2315                    .clone();
2316
2317                let clicked_state = element_state
2318                    .clicked_state
2319                    .get_or_insert_with(Default::default)
2320                    .clone();
2321
2322                window.on_mouse_event({
2323                    let pending_mouse_down = pending_mouse_down.clone();
2324                    let hitbox = hitbox.clone();
2325                    let has_aux_click_listeners = !aux_click_listeners.is_empty();
2326                    move |event: &MouseDownEvent, phase, window, _cx| {
2327                        if phase == DispatchPhase::Bubble
2328                            && (event.button == MouseButton::Left || has_aux_click_listeners)
2329                            && hitbox.is_hovered(window)
2330                        {
2331                            *pending_mouse_down.borrow_mut() = Some(event.clone());
2332                            window.refresh();
2333                        }
2334                    }
2335                });
2336
2337                window.on_mouse_event({
2338                    let pending_mouse_down = pending_mouse_down.clone();
2339                    let hitbox = hitbox.clone();
2340                    move |event: &MouseMoveEvent, phase, window, cx| {
2341                        if phase == DispatchPhase::Capture {
2342                            return;
2343                        }
2344
2345                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
2346                        if let Some(mouse_down) = pending_mouse_down.clone()
2347                            && !cx.has_active_drag()
2348                            && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD
2349                            && let Some((drag_value, drag_listener)) = drag_listener.take()
2350                            && mouse_down.button == MouseButton::Left
2351                        {
2352                            *clicked_state.borrow_mut() = ElementClickedState::default();
2353                            let cursor_offset = event.position - hitbox.origin;
2354                            let drag =
2355                                (drag_listener)(drag_value.as_ref(), cursor_offset, window, cx);
2356                            cx.active_drag = Some(AnyDrag {
2357                                view: drag,
2358                                value: drag_value,
2359                                cursor_offset,
2360                                cursor_style: drag_cursor_style,
2361                            });
2362                            pending_mouse_down.take();
2363                            window.refresh();
2364                            cx.stop_propagation();
2365                        }
2366                    }
2367                });
2368
2369                if is_focused {
2370                    // Press enter, space to trigger click, when the element is focused.
2371                    window.on_key_event({
2372                        let click_listeners = click_listeners.clone();
2373                        let hitbox = hitbox.clone();
2374                        move |event: &KeyUpEvent, phase, window, cx| {
2375                            if phase.bubble() && !window.default_prevented() {
2376                                let stroke = &event.keystroke;
2377                                let keyboard_button = if stroke.key.eq("enter") {
2378                                    Some(KeyboardButton::Enter)
2379                                } else if stroke.key.eq("space") {
2380                                    Some(KeyboardButton::Space)
2381                                } else {
2382                                    None
2383                                };
2384
2385                                if let Some(button) = keyboard_button
2386                                    && !stroke.modifiers.modified()
2387                                {
2388                                    let click_event = ClickEvent::Keyboard(KeyboardClickEvent {
2389                                        button,
2390                                        bounds: hitbox.bounds,
2391                                    });
2392
2393                                    for listener in &click_listeners {
2394                                        listener(&click_event, window, cx);
2395                                    }
2396                                }
2397                            }
2398                        }
2399                    });
2400                }
2401
2402                window.on_mouse_event({
2403                    let mut captured_mouse_down = None;
2404                    let hitbox = hitbox.clone();
2405                    move |event: &MouseUpEvent, phase, window, cx| match phase {
2406                        // Clear the pending mouse down during the capture phase,
2407                        // so that it happens even if another event handler stops
2408                        // propagation.
2409                        DispatchPhase::Capture => {
2410                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
2411                            if pending_mouse_down.is_some() && hitbox.is_hovered(window) {
2412                                captured_mouse_down = pending_mouse_down.take();
2413                                window.refresh();
2414                            } else if pending_mouse_down.is_some() {
2415                                // Clear the pending mouse down event (without firing click handlers)
2416                                // if the hitbox is not being hovered.
2417                                // This avoids dragging elements that changed their position
2418                                // immediately after being clicked.
2419                                // See https://github.com/zed-industries/zed/issues/24600 for more details
2420                                pending_mouse_down.take();
2421                                window.refresh();
2422                            }
2423                        }
2424                        // Fire click handlers during the bubble phase.
2425                        DispatchPhase::Bubble => {
2426                            if let Some(mouse_down) = captured_mouse_down.take() {
2427                                let btn = mouse_down.button;
2428
2429                                let mouse_click = ClickEvent::Mouse(MouseClickEvent {
2430                                    down: mouse_down,
2431                                    up: event.clone(),
2432                                });
2433
2434                                match btn {
2435                                    MouseButton::Left => {
2436                                        for listener in &click_listeners {
2437                                            listener(&mouse_click, window, cx);
2438                                        }
2439                                    }
2440                                    _ => {
2441                                        for listener in &aux_click_listeners {
2442                                            listener(&mouse_click, window, cx);
2443                                        }
2444                                    }
2445                                }
2446                            }
2447                        }
2448                    }
2449                });
2450            }
2451
2452            if let Some(hover_listener) = self.hover_listener.take() {
2453                let hitbox = hitbox.clone();
2454                let was_hovered = element_state
2455                    .hover_listener_state
2456                    .get_or_insert_with(Default::default)
2457                    .clone();
2458                let has_mouse_down = element_state
2459                    .pending_mouse_down
2460                    .get_or_insert_with(Default::default)
2461                    .clone();
2462
2463                window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2464                    if phase != DispatchPhase::Bubble {
2465                        return;
2466                    }
2467                    let is_hovered = has_mouse_down.borrow().is_none()
2468                        && !cx.has_active_drag()
2469                        && hitbox.is_hovered(window);
2470                    let mut was_hovered = was_hovered.borrow_mut();
2471
2472                    if is_hovered != *was_hovered {
2473                        *was_hovered = is_hovered;
2474                        drop(was_hovered);
2475
2476                        hover_listener(&is_hovered, window, cx);
2477                    }
2478                });
2479            }
2480
2481            if let Some(tooltip_builder) = self.tooltip_builder.take() {
2482                let active_tooltip = element_state
2483                    .active_tooltip
2484                    .get_or_insert_with(Default::default)
2485                    .clone();
2486                let pending_mouse_down = element_state
2487                    .pending_mouse_down
2488                    .get_or_insert_with(Default::default)
2489                    .clone();
2490
2491                let tooltip_is_hoverable = tooltip_builder.hoverable;
2492                let build_tooltip = Rc::new(move |window: &mut Window, cx: &mut App| {
2493                    Some(((tooltip_builder.build)(window, cx), tooltip_is_hoverable))
2494                });
2495                // Use bounds instead of testing hitbox since this is called during prepaint.
2496                let check_is_hovered_during_prepaint = Rc::new({
2497                    let pending_mouse_down = pending_mouse_down.clone();
2498                    let source_bounds = hitbox.bounds;
2499                    move |window: &Window| {
2500                        pending_mouse_down.borrow().is_none()
2501                            && source_bounds.contains(&window.mouse_position())
2502                    }
2503                });
2504                let check_is_hovered = Rc::new({
2505                    let hitbox = hitbox.clone();
2506                    move |window: &Window| {
2507                        pending_mouse_down.borrow().is_none() && hitbox.is_hovered(window)
2508                    }
2509                });
2510                register_tooltip_mouse_handlers(
2511                    &active_tooltip,
2512                    self.tooltip_id,
2513                    build_tooltip,
2514                    check_is_hovered,
2515                    check_is_hovered_during_prepaint,
2516                    window,
2517                );
2518            }
2519
2520            // We unconditionally bind both the mouse up and mouse down active state handlers
2521            // Because we might not get a chance to render a frame before the mouse up event arrives.
2522            let active_state = element_state
2523                .clicked_state
2524                .get_or_insert_with(Default::default)
2525                .clone();
2526
2527            {
2528                let active_state = active_state.clone();
2529                window.on_mouse_event(move |_: &MouseUpEvent, phase, window, _cx| {
2530                    if phase == DispatchPhase::Capture && active_state.borrow().is_clicked() {
2531                        *active_state.borrow_mut() = ElementClickedState::default();
2532                        window.refresh();
2533                    }
2534                });
2535            }
2536
2537            {
2538                let active_group_hitbox = self
2539                    .group_active_style
2540                    .as_ref()
2541                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
2542                let hitbox = hitbox.clone();
2543                window.on_mouse_event(move |_: &MouseDownEvent, phase, window, _cx| {
2544                    if phase == DispatchPhase::Bubble && !window.default_prevented() {
2545                        let group_hovered = active_group_hitbox
2546                            .is_some_and(|group_hitbox_id| group_hitbox_id.is_hovered(window));
2547                        let element_hovered = hitbox.is_hovered(window);
2548                        if group_hovered || element_hovered {
2549                            *active_state.borrow_mut() = ElementClickedState {
2550                                group: group_hovered,
2551                                element: element_hovered,
2552                            };
2553                            window.refresh();
2554                        }
2555                    }
2556                });
2557            }
2558        }
2559    }
2560
2561    fn paint_keyboard_listeners(&mut self, window: &mut Window, _cx: &mut App) {
2562        let key_down_listeners = mem::take(&mut self.key_down_listeners);
2563        let key_up_listeners = mem::take(&mut self.key_up_listeners);
2564        let modifiers_changed_listeners = mem::take(&mut self.modifiers_changed_listeners);
2565        let action_listeners = mem::take(&mut self.action_listeners);
2566        if let Some(context) = self.key_context.clone() {
2567            window.set_key_context(context);
2568        }
2569
2570        for listener in key_down_listeners {
2571            window.on_key_event(move |event: &KeyDownEvent, phase, window, cx| {
2572                listener(event, phase, window, cx);
2573            })
2574        }
2575
2576        for listener in key_up_listeners {
2577            window.on_key_event(move |event: &KeyUpEvent, phase, window, cx| {
2578                listener(event, phase, window, cx);
2579            })
2580        }
2581
2582        for listener in modifiers_changed_listeners {
2583            window.on_modifiers_changed(move |event: &ModifiersChangedEvent, window, cx| {
2584                listener(event, window, cx);
2585            })
2586        }
2587
2588        for (action_type, listener) in action_listeners {
2589            window.on_action(action_type, listener)
2590        }
2591    }
2592
2593    fn paint_hover_group_handler(&self, window: &mut Window, cx: &mut App) {
2594        let group_hitbox = self
2595            .group_hover_style
2596            .as_ref()
2597            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
2598
2599        if let Some(group_hitbox) = group_hitbox {
2600            let was_hovered = group_hitbox.is_hovered(window);
2601            let current_view = window.current_view();
2602            window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2603                let hovered = group_hitbox.is_hovered(window);
2604                if phase == DispatchPhase::Capture && hovered != was_hovered {
2605                    cx.notify(current_view);
2606                }
2607            });
2608        }
2609    }
2610
2611    fn paint_scroll_listener(
2612        &self,
2613        hitbox: &Hitbox,
2614        style: &Style,
2615        window: &mut Window,
2616        _cx: &mut App,
2617    ) {
2618        if let Some(scroll_offset) = self.scroll_offset.clone() {
2619            let overflow = style.overflow;
2620            let allow_concurrent_scroll = style.allow_concurrent_scroll;
2621            let restrict_scroll_to_axis = style.restrict_scroll_to_axis;
2622            let line_height = window.line_height();
2623            let hitbox = hitbox.clone();
2624            let current_view = window.current_view();
2625            window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {
2626                if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
2627                    let mut scroll_offset = scroll_offset.borrow_mut();
2628                    let old_scroll_offset = *scroll_offset;
2629                    let delta = event.delta.pixel_delta(line_height);
2630
2631                    let mut delta_x = Pixels::ZERO;
2632                    if overflow.x == Overflow::Scroll {
2633                        if !delta.x.is_zero() {
2634                            delta_x = delta.x;
2635                        } else if !restrict_scroll_to_axis && overflow.y != Overflow::Scroll {
2636                            delta_x = delta.y;
2637                        }
2638                    }
2639                    let mut delta_y = Pixels::ZERO;
2640                    if overflow.y == Overflow::Scroll {
2641                        if !delta.y.is_zero() {
2642                            delta_y = delta.y;
2643                        } else if !restrict_scroll_to_axis && overflow.x != Overflow::Scroll {
2644                            delta_y = delta.x;
2645                        }
2646                    }
2647                    if !allow_concurrent_scroll && !delta_x.is_zero() && !delta_y.is_zero() {
2648                        if delta_x.abs() > delta_y.abs() {
2649                            delta_y = Pixels::ZERO;
2650                        } else {
2651                            delta_x = Pixels::ZERO;
2652                        }
2653                    }
2654                    scroll_offset.y += delta_y;
2655                    scroll_offset.x += delta_x;
2656                    if *scroll_offset != old_scroll_offset {
2657                        cx.notify(current_view);
2658                    }
2659                }
2660            });
2661        }
2662    }
2663
2664    /// Compute the visual style for this element, based on the current bounds and the element's state.
2665    pub fn compute_style(
2666        &self,
2667        global_id: Option<&GlobalElementId>,
2668        hitbox: Option<&Hitbox>,
2669        window: &mut Window,
2670        cx: &mut App,
2671    ) -> Style {
2672        window.with_optional_element_state(global_id, |element_state, window| {
2673            let mut element_state =
2674                element_state.map(|element_state| element_state.unwrap_or_default());
2675            let style = self.compute_style_internal(hitbox, element_state.as_mut(), window, cx);
2676            (style, element_state)
2677        })
2678    }
2679
2680    /// Called from internal methods that have already called with_element_state.
2681    fn compute_style_internal(
2682        &self,
2683        hitbox: Option<&Hitbox>,
2684        element_state: Option<&mut InteractiveElementState>,
2685        window: &mut Window,
2686        cx: &mut App,
2687    ) -> Style {
2688        let mut style = Style::default();
2689        style.refine(&self.base_style);
2690
2691        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
2692            if let Some(in_focus_style) = self.in_focus_style.as_ref()
2693                && focus_handle.within_focused(window, cx)
2694            {
2695                style.refine(in_focus_style);
2696            }
2697
2698            if let Some(focus_style) = self.focus_style.as_ref()
2699                && focus_handle.is_focused(window)
2700            {
2701                style.refine(focus_style);
2702            }
2703
2704            if let Some(focus_visible_style) = self.focus_visible_style.as_ref()
2705                && focus_handle.is_focused(window)
2706                && window.last_input_was_keyboard()
2707            {
2708                style.refine(focus_visible_style);
2709            }
2710        }
2711
2712        if !cx.has_active_drag() {
2713            if let Some(group_hover) = self.group_hover_style.as_ref() {
2714                let is_group_hovered =
2715                    if let Some(group_hitbox_id) = GroupHitboxes::get(&group_hover.group, cx) {
2716                        group_hitbox_id.is_hovered(window)
2717                    } else if let Some(element_state) = element_state.as_ref() {
2718                        element_state
2719                            .hover_state
2720                            .as_ref()
2721                            .map(|state| state.borrow().group)
2722                            .unwrap_or(false)
2723                    } else {
2724                        false
2725                    };
2726
2727                if is_group_hovered {
2728                    style.refine(&group_hover.style);
2729                }
2730            }
2731
2732            if let Some(hover_style) = self.hover_style.as_ref() {
2733                let is_hovered = if let Some(hitbox) = hitbox {
2734                    hitbox.is_hovered(window)
2735                } else if let Some(element_state) = element_state.as_ref() {
2736                    element_state
2737                        .hover_state
2738                        .as_ref()
2739                        .map(|state| state.borrow().element)
2740                        .unwrap_or(false)
2741                } else {
2742                    false
2743                };
2744
2745                if is_hovered {
2746                    style.refine(hover_style);
2747                }
2748            }
2749        }
2750
2751        if let Some(hitbox) = hitbox {
2752            if let Some(drag) = cx.active_drag.take() {
2753                let mut can_drop = true;
2754                if let Some(can_drop_predicate) = &self.can_drop_predicate {
2755                    can_drop = can_drop_predicate(drag.value.as_ref(), window, cx);
2756                }
2757
2758                if can_drop {
2759                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
2760                        if let Some(group_hitbox_id) =
2761                            GroupHitboxes::get(&group_drag_style.group, cx)
2762                            && *state_type == drag.value.as_ref().type_id()
2763                            && group_hitbox_id.is_hovered(window)
2764                        {
2765                            style.refine(&group_drag_style.style);
2766                        }
2767                    }
2768
2769                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
2770                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(window)
2771                        {
2772                            style.refine(&build_drag_over_style(drag.value.as_ref(), window, cx));
2773                        }
2774                    }
2775                }
2776
2777                style.mouse_cursor = drag.cursor_style;
2778                cx.active_drag = Some(drag);
2779            }
2780        }
2781
2782        if let Some(element_state) = element_state {
2783            let clicked_state = element_state
2784                .clicked_state
2785                .get_or_insert_with(Default::default)
2786                .borrow();
2787            if clicked_state.group
2788                && let Some(group) = self.group_active_style.as_ref()
2789            {
2790                style.refine(&group.style)
2791            }
2792
2793            if let Some(active_style) = self.active_style.as_ref()
2794                && clicked_state.element
2795            {
2796                style.refine(active_style)
2797            }
2798        }
2799
2800        style
2801    }
2802}
2803
2804/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
2805/// and scroll offsets.
2806#[derive(Default)]
2807pub struct InteractiveElementState {
2808    pub(crate) focus_handle: Option<FocusHandle>,
2809    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
2810    pub(crate) hover_state: Option<Rc<RefCell<ElementHoverState>>>,
2811    pub(crate) hover_listener_state: Option<Rc<RefCell<bool>>>,
2812    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
2813    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
2814    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
2815}
2816
2817/// Whether or not the element or a group that contains it is clicked by the mouse.
2818#[derive(Copy, Clone, Default, Eq, PartialEq)]
2819pub struct ElementClickedState {
2820    /// True if this element's group has been clicked, false otherwise
2821    pub group: bool,
2822
2823    /// True if this element has been clicked, false otherwise
2824    pub element: bool,
2825}
2826
2827impl ElementClickedState {
2828    fn is_clicked(&self) -> bool {
2829        self.group || self.element
2830    }
2831}
2832
2833/// Whether or not the element or a group that contains it is hovered.
2834#[derive(Copy, Clone, Default, Eq, PartialEq)]
2835pub struct ElementHoverState {
2836    /// True if this element's group is hovered, false otherwise
2837    pub group: bool,
2838
2839    /// True if this element is hovered, false otherwise
2840    pub element: bool,
2841}
2842
2843pub(crate) enum ActiveTooltip {
2844    /// Currently delaying before showing the tooltip.
2845    WaitingForShow { _task: Task<()> },
2846    /// Tooltip is visible, element was hovered or for hoverable tooltips, the tooltip was hovered.
2847    Visible {
2848        tooltip: AnyTooltip,
2849        is_hoverable: bool,
2850    },
2851    /// Tooltip is visible and hoverable, but the mouse is no longer hovering. Currently delaying
2852    /// before hiding it.
2853    WaitingForHide {
2854        tooltip: AnyTooltip,
2855        _task: Task<()>,
2856    },
2857}
2858
2859pub(crate) fn clear_active_tooltip(
2860    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2861    window: &mut Window,
2862) {
2863    match active_tooltip.borrow_mut().take() {
2864        None => {}
2865        Some(ActiveTooltip::WaitingForShow { .. }) => {}
2866        Some(ActiveTooltip::Visible { .. }) => window.refresh(),
2867        Some(ActiveTooltip::WaitingForHide { .. }) => window.refresh(),
2868    }
2869}
2870
2871pub(crate) fn clear_active_tooltip_if_not_hoverable(
2872    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2873    window: &mut Window,
2874) {
2875    let should_clear = match active_tooltip.borrow().as_ref() {
2876        None => false,
2877        Some(ActiveTooltip::WaitingForShow { .. }) => false,
2878        Some(ActiveTooltip::Visible { is_hoverable, .. }) => !is_hoverable,
2879        Some(ActiveTooltip::WaitingForHide { .. }) => false,
2880    };
2881    if should_clear {
2882        active_tooltip.borrow_mut().take();
2883        window.refresh();
2884    }
2885}
2886
2887pub(crate) fn set_tooltip_on_window(
2888    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2889    window: &mut Window,
2890) -> Option<TooltipId> {
2891    let tooltip = match active_tooltip.borrow().as_ref() {
2892        None => return None,
2893        Some(ActiveTooltip::WaitingForShow { .. }) => return None,
2894        Some(ActiveTooltip::Visible { tooltip, .. }) => tooltip.clone(),
2895        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => tooltip.clone(),
2896    };
2897    Some(window.set_tooltip(tooltip))
2898}
2899
2900pub(crate) fn register_tooltip_mouse_handlers(
2901    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2902    tooltip_id: Option<TooltipId>,
2903    build_tooltip: Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
2904    check_is_hovered: Rc<dyn Fn(&Window) -> bool>,
2905    check_is_hovered_during_prepaint: Rc<dyn Fn(&Window) -> bool>,
2906    window: &mut Window,
2907) {
2908    window.on_mouse_event({
2909        let active_tooltip = active_tooltip.clone();
2910        let build_tooltip = build_tooltip.clone();
2911        let check_is_hovered = check_is_hovered.clone();
2912        move |_: &MouseMoveEvent, phase, window, cx| {
2913            handle_tooltip_mouse_move(
2914                &active_tooltip,
2915                &build_tooltip,
2916                &check_is_hovered,
2917                &check_is_hovered_during_prepaint,
2918                phase,
2919                window,
2920                cx,
2921            )
2922        }
2923    });
2924
2925    window.on_mouse_event({
2926        let active_tooltip = active_tooltip.clone();
2927        move |_: &MouseDownEvent, _phase, window: &mut Window, _cx| {
2928            if !tooltip_id.is_some_and(|tooltip_id| tooltip_id.is_hovered(window)) {
2929                clear_active_tooltip_if_not_hoverable(&active_tooltip, window);
2930            }
2931        }
2932    });
2933
2934    window.on_mouse_event({
2935        let active_tooltip = active_tooltip.clone();
2936        move |_: &ScrollWheelEvent, _phase, window: &mut Window, _cx| {
2937            if !tooltip_id.is_some_and(|tooltip_id| tooltip_id.is_hovered(window)) {
2938                clear_active_tooltip_if_not_hoverable(&active_tooltip, window);
2939            }
2940        }
2941    });
2942}
2943
2944/// Handles displaying tooltips when an element is hovered.
2945///
2946/// The mouse hovering logic also relies on being called from window prepaint in order to handle the
2947/// case where the element the tooltip is on is not rendered - in that case its mouse listeners are
2948/// also not registered. During window prepaint, the hitbox information is not available, so
2949/// `check_is_hovered_during_prepaint` is used which bases the check off of the absolute bounds of
2950/// the element.
2951///
2952/// TODO: There's a minor bug due to the use of absolute bounds while checking during prepaint - it
2953/// does not know if the hitbox is occluded. In the case where a tooltip gets displayed and then
2954/// gets occluded after display, it will stick around until the mouse exits the hover bounds.
2955fn handle_tooltip_mouse_move(
2956    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2957    build_tooltip: &Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
2958    check_is_hovered: &Rc<dyn Fn(&Window) -> bool>,
2959    check_is_hovered_during_prepaint: &Rc<dyn Fn(&Window) -> bool>,
2960    phase: DispatchPhase,
2961    window: &mut Window,
2962    cx: &mut App,
2963) {
2964    // Separates logic for what mutation should occur from applying it, to avoid overlapping
2965    // RefCell borrows.
2966    enum Action {
2967        None,
2968        CancelShow,
2969        ScheduleShow,
2970    }
2971
2972    let action = match active_tooltip.borrow().as_ref() {
2973        None => {
2974            let is_hovered = check_is_hovered(window);
2975            if is_hovered && phase.bubble() {
2976                Action::ScheduleShow
2977            } else {
2978                Action::None
2979            }
2980        }
2981        Some(ActiveTooltip::WaitingForShow { .. }) => {
2982            let is_hovered = check_is_hovered(window);
2983            if is_hovered {
2984                Action::None
2985            } else {
2986                Action::CancelShow
2987            }
2988        }
2989        // These are handled in check_visible_and_update.
2990        Some(ActiveTooltip::Visible { .. }) | Some(ActiveTooltip::WaitingForHide { .. }) => {
2991            Action::None
2992        }
2993    };
2994
2995    match action {
2996        Action::None => {}
2997        Action::CancelShow => {
2998            // Cancel waiting to show tooltip when it is no longer hovered.
2999            active_tooltip.borrow_mut().take();
3000        }
3001        Action::ScheduleShow => {
3002            let delayed_show_task = window.spawn(cx, {
3003                let active_tooltip = active_tooltip.clone();
3004                let build_tooltip = build_tooltip.clone();
3005                let check_is_hovered_during_prepaint = check_is_hovered_during_prepaint.clone();
3006                async move |cx| {
3007                    cx.background_executor().timer(TOOLTIP_SHOW_DELAY).await;
3008                    cx.update(|window, cx| {
3009                        let new_tooltip =
3010                            build_tooltip(window, cx).map(|(view, tooltip_is_hoverable)| {
3011                                let active_tooltip = active_tooltip.clone();
3012                                ActiveTooltip::Visible {
3013                                    tooltip: AnyTooltip {
3014                                        view,
3015                                        mouse_position: window.mouse_position(),
3016                                        check_visible_and_update: Rc::new(
3017                                            move |tooltip_bounds, window, cx| {
3018                                                handle_tooltip_check_visible_and_update(
3019                                                    &active_tooltip,
3020                                                    tooltip_is_hoverable,
3021                                                    &check_is_hovered_during_prepaint,
3022                                                    tooltip_bounds,
3023                                                    window,
3024                                                    cx,
3025                                                )
3026                                            },
3027                                        ),
3028                                    },
3029                                    is_hoverable: tooltip_is_hoverable,
3030                                }
3031                            });
3032                        *active_tooltip.borrow_mut() = new_tooltip;
3033                        window.refresh();
3034                    })
3035                    .ok();
3036                }
3037            });
3038            active_tooltip
3039                .borrow_mut()
3040                .replace(ActiveTooltip::WaitingForShow {
3041                    _task: delayed_show_task,
3042                });
3043        }
3044    }
3045}
3046
3047/// Returns a callback which will be called by window prepaint to update tooltip visibility. The
3048/// purpose of doing this logic here instead of the mouse move handler is that the mouse move
3049/// handler won't get called when the element is not painted (e.g. via use of `visible_on_hover`).
3050fn handle_tooltip_check_visible_and_update(
3051    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3052    tooltip_is_hoverable: bool,
3053    check_is_hovered: &Rc<dyn Fn(&Window) -> bool>,
3054    tooltip_bounds: Bounds<Pixels>,
3055    window: &mut Window,
3056    cx: &mut App,
3057) -> bool {
3058    // Separates logic for what mutation should occur from applying it, to avoid overlapping RefCell
3059    // borrows.
3060    enum Action {
3061        None,
3062        Hide,
3063        ScheduleHide(AnyTooltip),
3064        CancelHide(AnyTooltip),
3065    }
3066
3067    let is_hovered = check_is_hovered(window)
3068        || (tooltip_is_hoverable && tooltip_bounds.contains(&window.mouse_position()));
3069    let action = match active_tooltip.borrow().as_ref() {
3070        Some(ActiveTooltip::Visible { tooltip, .. }) => {
3071            if is_hovered {
3072                Action::None
3073            } else {
3074                if tooltip_is_hoverable {
3075                    Action::ScheduleHide(tooltip.clone())
3076                } else {
3077                    Action::Hide
3078                }
3079            }
3080        }
3081        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => {
3082            if is_hovered {
3083                Action::CancelHide(tooltip.clone())
3084            } else {
3085                Action::None
3086            }
3087        }
3088        None | Some(ActiveTooltip::WaitingForShow { .. }) => Action::None,
3089    };
3090
3091    match action {
3092        Action::None => {}
3093        Action::Hide => clear_active_tooltip(active_tooltip, window),
3094        Action::ScheduleHide(tooltip) => {
3095            let delayed_hide_task = window.spawn(cx, {
3096                let active_tooltip = active_tooltip.clone();
3097                async move |cx| {
3098                    cx.background_executor()
3099                        .timer(HOVERABLE_TOOLTIP_HIDE_DELAY)
3100                        .await;
3101                    if active_tooltip.borrow_mut().take().is_some() {
3102                        cx.update(|window, _cx| window.refresh()).ok();
3103                    }
3104                }
3105            });
3106            active_tooltip
3107                .borrow_mut()
3108                .replace(ActiveTooltip::WaitingForHide {
3109                    tooltip,
3110                    _task: delayed_hide_task,
3111                });
3112        }
3113        Action::CancelHide(tooltip) => {
3114            // Cancel waiting to hide tooltip when it becomes hovered.
3115            active_tooltip.borrow_mut().replace(ActiveTooltip::Visible {
3116                tooltip,
3117                is_hoverable: true,
3118            });
3119        }
3120    }
3121
3122    active_tooltip.borrow().is_some()
3123}
3124
3125#[derive(Default)]
3126pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
3127
3128impl Global for GroupHitboxes {}
3129
3130impl GroupHitboxes {
3131    pub fn get(name: &SharedString, cx: &mut App) -> Option<HitboxId> {
3132        cx.default_global::<Self>()
3133            .0
3134            .get(name)
3135            .and_then(|bounds_stack| bounds_stack.last())
3136            .cloned()
3137    }
3138
3139    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut App) {
3140        cx.default_global::<Self>()
3141            .0
3142            .entry(name)
3143            .or_default()
3144            .push(hitbox_id);
3145    }
3146
3147    pub fn pop(name: &SharedString, cx: &mut App) {
3148        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
3149    }
3150}
3151
3152/// A wrapper around an element that can store state, produced after assigning an ElementId.
3153pub struct Stateful<E> {
3154    pub(crate) element: E,
3155}
3156
3157impl<E> Styled for Stateful<E>
3158where
3159    E: Styled,
3160{
3161    fn style(&mut self) -> &mut StyleRefinement {
3162        self.element.style()
3163    }
3164}
3165
3166impl<E> StatefulInteractiveElement for Stateful<E>
3167where
3168    E: Element,
3169    Self: InteractiveElement,
3170{
3171}
3172
3173impl<E> InteractiveElement for Stateful<E>
3174where
3175    E: InteractiveElement,
3176{
3177    fn interactivity(&mut self) -> &mut Interactivity {
3178        self.element.interactivity()
3179    }
3180}
3181
3182impl<E> Element for Stateful<E>
3183where
3184    E: Element,
3185{
3186    type RequestLayoutState = E::RequestLayoutState;
3187    type PrepaintState = E::PrepaintState;
3188
3189    fn id(&self) -> Option<ElementId> {
3190        self.element.id()
3191    }
3192
3193    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
3194        self.element.source_location()
3195    }
3196
3197    fn request_layout(
3198        &mut self,
3199        id: Option<&GlobalElementId>,
3200        inspector_id: Option<&InspectorElementId>,
3201        window: &mut Window,
3202        cx: &mut App,
3203    ) -> (LayoutId, Self::RequestLayoutState) {
3204        self.element.request_layout(id, inspector_id, window, cx)
3205    }
3206
3207    fn prepaint(
3208        &mut self,
3209        id: Option<&GlobalElementId>,
3210        inspector_id: Option<&InspectorElementId>,
3211        bounds: Bounds<Pixels>,
3212        state: &mut Self::RequestLayoutState,
3213        window: &mut Window,
3214        cx: &mut App,
3215    ) -> E::PrepaintState {
3216        self.element
3217            .prepaint(id, inspector_id, bounds, state, window, cx)
3218    }
3219
3220    fn paint(
3221        &mut self,
3222        id: Option<&GlobalElementId>,
3223        inspector_id: Option<&InspectorElementId>,
3224        bounds: Bounds<Pixels>,
3225        request_layout: &mut Self::RequestLayoutState,
3226        prepaint: &mut Self::PrepaintState,
3227        window: &mut Window,
3228        cx: &mut App,
3229    ) {
3230        self.element.paint(
3231            id,
3232            inspector_id,
3233            bounds,
3234            request_layout,
3235            prepaint,
3236            window,
3237            cx,
3238        );
3239    }
3240}
3241
3242impl<E> IntoElement for Stateful<E>
3243where
3244    E: Element,
3245{
3246    type Element = Self;
3247
3248    fn into_element(self) -> Self::Element {
3249        self
3250    }
3251}
3252
3253impl<E> ParentElement for Stateful<E>
3254where
3255    E: ParentElement,
3256{
3257    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
3258        self.element.extend(elements)
3259    }
3260}
3261
3262/// Represents an element that can be scrolled *to* in its parent element.
3263/// Contrary to [ScrollHandle::scroll_to_active_item], an anchored element does not have to be an immediate child of the parent.
3264#[derive(Clone)]
3265pub struct ScrollAnchor {
3266    handle: ScrollHandle,
3267    last_origin: Rc<RefCell<Point<Pixels>>>,
3268}
3269
3270impl ScrollAnchor {
3271    /// Creates a [ScrollAnchor] associated with a given [ScrollHandle].
3272    pub fn for_handle(handle: ScrollHandle) -> Self {
3273        Self {
3274            handle,
3275            last_origin: Default::default(),
3276        }
3277    }
3278    /// Request scroll to this item on the next frame.
3279    pub fn scroll_to(&self, window: &mut Window, _cx: &mut App) {
3280        let this = self.clone();
3281
3282        window.on_next_frame(move |_, _| {
3283            let viewport_bounds = this.handle.bounds();
3284            let self_bounds = *this.last_origin.borrow();
3285            this.handle.set_offset(viewport_bounds.origin - self_bounds);
3286        });
3287    }
3288}
3289
3290#[derive(Default, Debug)]
3291struct ScrollHandleState {
3292    offset: Rc<RefCell<Point<Pixels>>>,
3293    bounds: Bounds<Pixels>,
3294    max_offset: Point<Pixels>,
3295    child_bounds: Vec<Bounds<Pixels>>,
3296    scroll_to_bottom: bool,
3297    overflow: Point<Overflow>,
3298    active_item: Option<ScrollActiveItem>,
3299}
3300
3301#[derive(Default, Debug, Clone, Copy)]
3302struct ScrollActiveItem {
3303    index: usize,
3304    strategy: ScrollStrategy,
3305}
3306
3307#[derive(Default, Debug, Clone, Copy)]
3308enum ScrollStrategy {
3309    #[default]
3310    FirstVisible,
3311    Top,
3312}
3313
3314/// A handle to the scrollable aspects of an element.
3315/// Used for accessing scroll state, like the current scroll offset,
3316/// and for mutating the scroll state, like scrolling to a specific child.
3317#[derive(Clone, Debug)]
3318pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
3319
3320impl Default for ScrollHandle {
3321    fn default() -> Self {
3322        Self::new()
3323    }
3324}
3325
3326impl ScrollHandle {
3327    /// Construct a new scroll handle.
3328    pub fn new() -> Self {
3329        Self(Rc::default())
3330    }
3331
3332    /// Get the current scroll offset.
3333    pub fn offset(&self) -> Point<Pixels> {
3334        *self.0.borrow().offset.borrow()
3335    }
3336
3337    /// Get the maximum scroll offset.
3338    pub fn max_offset(&self) -> Point<Pixels> {
3339        self.0.borrow().max_offset
3340    }
3341
3342    /// Get the top child that's scrolled into view.
3343    pub fn top_item(&self) -> usize {
3344        let state = self.0.borrow();
3345        let top = state.bounds.top() - state.offset.borrow().y;
3346
3347        match state.child_bounds.binary_search_by(|bounds| {
3348            if top < bounds.top() {
3349                Ordering::Greater
3350            } else if top > bounds.bottom() {
3351                Ordering::Less
3352            } else {
3353                Ordering::Equal
3354            }
3355        }) {
3356            Ok(ix) => ix,
3357            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
3358        }
3359    }
3360
3361    /// Get the bottom child that's scrolled into view.
3362    pub fn bottom_item(&self) -> usize {
3363        let state = self.0.borrow();
3364        let bottom = state.bounds.bottom() - state.offset.borrow().y;
3365
3366        match state.child_bounds.binary_search_by(|bounds| {
3367            if bottom < bounds.top() {
3368                Ordering::Greater
3369            } else if bottom > bounds.bottom() {
3370                Ordering::Less
3371            } else {
3372                Ordering::Equal
3373            }
3374        }) {
3375            Ok(ix) => ix,
3376            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
3377        }
3378    }
3379
3380    /// Return the bounds into which this child is painted
3381    pub fn bounds(&self) -> Bounds<Pixels> {
3382        self.0.borrow().bounds
3383    }
3384
3385    /// Get the bounds for a specific child.
3386    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
3387        self.0.borrow().child_bounds.get(ix).cloned()
3388    }
3389
3390    /// Update [ScrollHandleState]'s active item for scrolling to in prepaint
3391    pub fn scroll_to_item(&self, ix: usize) {
3392        let mut state = self.0.borrow_mut();
3393        state.active_item = Some(ScrollActiveItem {
3394            index: ix,
3395            strategy: ScrollStrategy::default(),
3396        });
3397    }
3398
3399    /// Update [ScrollHandleState]'s active item for scrolling to in prepaint
3400    /// This scrolls the minimal amount to ensure that the child is the first visible element
3401    pub fn scroll_to_top_of_item(&self, ix: usize) {
3402        let mut state = self.0.borrow_mut();
3403        state.active_item = Some(ScrollActiveItem {
3404            index: ix,
3405            strategy: ScrollStrategy::Top,
3406        });
3407    }
3408
3409    /// Scrolls the minimal amount to either ensure that the child is
3410    /// fully visible or the top element of the view depends on the
3411    /// scroll strategy
3412    fn scroll_to_active_item(&self) {
3413        let mut state = self.0.borrow_mut();
3414
3415        let Some(active_item) = state.active_item else {
3416            return;
3417        };
3418
3419        let active_item = match state.child_bounds.get(active_item.index) {
3420            Some(bounds) => {
3421                let mut scroll_offset = state.offset.borrow_mut();
3422
3423                match active_item.strategy {
3424                    ScrollStrategy::FirstVisible => {
3425                        if state.overflow.y == Overflow::Scroll {
3426                            let child_height = bounds.size.height;
3427                            let viewport_height = state.bounds.size.height;
3428                            if child_height > viewport_height {
3429                                scroll_offset.y = state.bounds.top() - bounds.top();
3430                            } else if bounds.top() + scroll_offset.y < state.bounds.top() {
3431                                scroll_offset.y = state.bounds.top() - bounds.top();
3432                            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
3433                                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
3434                            }
3435                        }
3436                    }
3437                    ScrollStrategy::Top => {
3438                        scroll_offset.y = state.bounds.top() - bounds.top();
3439                    }
3440                }
3441
3442                if state.overflow.x == Overflow::Scroll {
3443                    let child_width = bounds.size.width;
3444                    let viewport_width = state.bounds.size.width;
3445                    if child_width > viewport_width {
3446                        scroll_offset.x = state.bounds.left() - bounds.left();
3447                    } else if bounds.left() + scroll_offset.x < state.bounds.left() {
3448                        scroll_offset.x = state.bounds.left() - bounds.left();
3449                    } else if bounds.right() + scroll_offset.x > state.bounds.right() {
3450                        scroll_offset.x = state.bounds.right() - bounds.right();
3451                    }
3452                }
3453                None
3454            }
3455            None => Some(active_item),
3456        };
3457        state.active_item = active_item;
3458    }
3459
3460    /// Scrolls to the bottom.
3461    pub fn scroll_to_bottom(&self) {
3462        let mut state = self.0.borrow_mut();
3463        state.scroll_to_bottom = true;
3464    }
3465
3466    /// Set the offset explicitly. The offset is the distance from the top left of the
3467    /// parent container to the top left of the first child.
3468    /// As you scroll further down the offset becomes more negative.
3469    pub fn set_offset(&self, mut position: Point<Pixels>) {
3470        let state = self.0.borrow();
3471        *state.offset.borrow_mut() = position;
3472    }
3473
3474    /// Get the logical scroll top, based on a child index and a pixel offset.
3475    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
3476        let ix = self.top_item();
3477        let state = self.0.borrow();
3478
3479        if let Some(child_bounds) = state.child_bounds.get(ix) {
3480            (
3481                ix,
3482                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
3483            )
3484        } else {
3485            (ix, px(0.))
3486        }
3487    }
3488
3489    /// Get the logical scroll bottom, based on a child index and a pixel offset.
3490    pub fn logical_scroll_bottom(&self) -> (usize, Pixels) {
3491        let ix = self.bottom_item();
3492        let state = self.0.borrow();
3493
3494        if let Some(child_bounds) = state.child_bounds.get(ix) {
3495            (
3496                ix,
3497                child_bounds.bottom() + state.offset.borrow().y - state.bounds.bottom(),
3498            )
3499        } else {
3500            (ix, px(0.))
3501        }
3502    }
3503
3504    /// Get the count of children for scrollable item.
3505    pub fn children_count(&self) -> usize {
3506        self.0.borrow().child_bounds.len()
3507    }
3508}
3509
3510#[cfg(test)]
3511mod tests {
3512    use super::*;
3513
3514    #[test]
3515    fn scroll_handle_aligns_wide_children_to_left_edge() {
3516        let handle = ScrollHandle::new();
3517        {
3518            let mut state = handle.0.borrow_mut();
3519            state.bounds = Bounds::new(point(px(0.), px(0.)), size(px(80.), px(20.)));
3520            state.child_bounds = vec![Bounds::new(point(px(25.), px(0.)), size(px(200.), px(20.)))];
3521            state.overflow.x = Overflow::Scroll;
3522            state.active_item = Some(ScrollActiveItem {
3523                index: 0,
3524                strategy: ScrollStrategy::default(),
3525            });
3526        }
3527
3528        handle.scroll_to_active_item();
3529
3530        assert_eq!(handle.offset().x, px(-25.));
3531    }
3532
3533    #[test]
3534    fn scroll_handle_aligns_tall_children_to_top_edge() {
3535        let handle = ScrollHandle::new();
3536        {
3537            let mut state = handle.0.borrow_mut();
3538            state.bounds = Bounds::new(point(px(0.), px(0.)), size(px(20.), px(80.)));
3539            state.child_bounds = vec![Bounds::new(point(px(0.), px(25.)), size(px(20.), px(200.)))];
3540            state.overflow.y = Overflow::Scroll;
3541            state.active_item = Some(ScrollActiveItem {
3542                index: 0,
3543                strategy: ScrollStrategy::default(),
3544            });
3545        }
3546
3547        handle.scroll_to_active_item();
3548
3549        assert_eq!(handle.offset().y, px(-25.));
3550    }
3551}