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