div.rs

   1//! Div is the central, reusable element that most GPUI trees will be built from.
   2//! It functions as a container for other elements, and provides a number of
   3//! useful features for laying out and styling its children as well as binding
   4//! mouse events and action handlers. It is meant to be similar to the HTML `<div>`
   5//! element, but for GPUI.
   6//!
   7//! # Build your own div
   8//!
   9//! GPUI does not directly provide APIs for stateful, multi step events like `click`
  10//! and `drag`. We want GPUI users to be able to build their own abstractions for
  11//! their own needs. However, as a UI framework, we're also obliged to provide some
  12//! building blocks to make the process of building your own elements easier.
  13//! For this we have the [`Interactivity`] and the [`StyleRefinement`] structs, as well
  14//! as several associated traits. Together, these provide the full suite of Dom-like events
  15//! and Tailwind-like styling that you can use to build your own custom elements. Div is
  16//! constructed by combining these two systems into an all-in-one element.
  17
  18use crate::{
  19    point, px, size, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds,
  20    ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, Global, GlobalElementId, Hitbox,
  21    HitboxId, IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
  22    ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
  23    ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
  24    StyleRefinement, Styled, Task, TooltipId, View, Visibility, WindowContext,
  25};
  26use collections::HashMap;
  27use refineable::Refineable;
  28use smallvec::SmallVec;
  29use std::{
  30    any::{Any, TypeId},
  31    cell::RefCell,
  32    cmp::Ordering,
  33    fmt::Debug,
  34    marker::PhantomData,
  35    mem,
  36    ops::DerefMut,
  37    rc::Rc,
  38    sync::Arc,
  39    time::Duration,
  40};
  41use taffy::style::Overflow;
  42use util::ResultExt;
  43
  44const DRAG_THRESHOLD: f64 = 2.;
  45const TOOLTIP_SHOW_DELAY: Duration = Duration::from_millis(500);
  46const HOVERABLE_TOOLTIP_HIDE_DELAY: Duration = Duration::from_millis(500);
  47
  48/// The styling information for a given group.
  49pub struct GroupStyle {
  50    /// The identifier for this group.
  51    pub group: SharedString,
  52
  53    /// The specific style refinement that this group would apply
  54    /// to its children.
  55    pub style: Box<StyleRefinement>,
  56}
  57
  58/// An event for when a drag is moving over this element, with the given state type.
  59pub struct DragMoveEvent<T> {
  60    /// The mouse move event that triggered this drag move event.
  61    pub event: MouseMoveEvent,
  62
  63    /// The bounds of this element.
  64    pub bounds: Bounds<Pixels>,
  65    drag: PhantomData<T>,
  66    dragged_item: Arc<dyn Any>,
  67}
  68
  69impl<T: 'static> DragMoveEvent<T> {
  70    /// Returns the drag state for this event.
  71    pub fn drag<'b>(&self, cx: &'b AppContext) -> &'b T {
  72        cx.active_drag
  73            .as_ref()
  74            .and_then(|drag| drag.value.downcast_ref::<T>())
  75            .expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
  76    }
  77
  78    /// An item that is about to be dropped.
  79    pub fn dragged_item(&self) -> &dyn Any {
  80        self.dragged_item.as_ref()
  81    }
  82}
  83
  84impl Interactivity {
  85    /// Bind the given callback to the mouse down event for the given mouse button, during the bubble phase
  86    /// The imperative API equivalent of [`InteractiveElement::on_mouse_down`]
  87    ///
  88    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to the view state from this callback.
  89    pub fn on_mouse_down(
  90        &mut self,
  91        button: MouseButton,
  92        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
  93    ) {
  94        self.mouse_down_listeners
  95            .push(Box::new(move |event, phase, hitbox, cx| {
  96                if phase == DispatchPhase::Bubble && event.button == button && hitbox.is_hovered(cx)
  97                {
  98                    (listener)(event, cx)
  99                }
 100            }));
 101    }
 102
 103    /// Bind the given callback to the mouse down event for any button, during the capture phase
 104    /// The imperative API equivalent of [`InteractiveElement::capture_any_mouse_down`]
 105    ///
 106    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 107    pub fn capture_any_mouse_down(
 108        &mut self,
 109        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 110    ) {
 111        self.mouse_down_listeners
 112            .push(Box::new(move |event, phase, hitbox, cx| {
 113                if phase == DispatchPhase::Capture && hitbox.is_hovered(cx) {
 114                    (listener)(event, cx)
 115                }
 116            }));
 117    }
 118
 119    /// Bind the given callback to the mouse down event for any button, during the bubble phase
 120    /// the imperative API equivalent to [`InteractiveElement::on_any_mouse_down`]
 121    ///
 122    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 123    pub fn on_any_mouse_down(
 124        &mut self,
 125        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 126    ) {
 127        self.mouse_down_listeners
 128            .push(Box::new(move |event, phase, hitbox, cx| {
 129                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 130                    (listener)(event, cx)
 131                }
 132            }));
 133    }
 134
 135    /// Bind the given callback to the mouse up event for the given button, during the bubble phase
 136    /// the imperative API equivalent to [`InteractiveElement::on_mouse_up`]
 137    ///
 138    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 139    pub fn on_mouse_up(
 140        &mut self,
 141        button: MouseButton,
 142        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 143    ) {
 144        self.mouse_up_listeners
 145            .push(Box::new(move |event, phase, hitbox, cx| {
 146                if phase == DispatchPhase::Bubble && event.button == button && hitbox.is_hovered(cx)
 147                {
 148                    (listener)(event, cx)
 149                }
 150            }));
 151    }
 152
 153    /// Bind the given callback to the mouse up event for any button, during the capture phase
 154    /// the imperative API equivalent to [`InteractiveElement::capture_any_mouse_up`]
 155    ///
 156    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 157    pub fn capture_any_mouse_up(
 158        &mut self,
 159        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 160    ) {
 161        self.mouse_up_listeners
 162            .push(Box::new(move |event, phase, hitbox, cx| {
 163                if phase == DispatchPhase::Capture && hitbox.is_hovered(cx) {
 164                    (listener)(event, cx)
 165                }
 166            }));
 167    }
 168
 169    /// Bind the given callback to the mouse up event for any button, during the bubble phase
 170    /// the imperative API equivalent to [`Interactivity::on_any_mouse_up`]
 171    ///
 172    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 173    pub fn on_any_mouse_up(
 174        &mut self,
 175        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 176    ) {
 177        self.mouse_up_listeners
 178            .push(Box::new(move |event, phase, hitbox, cx| {
 179                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 180                    (listener)(event, cx)
 181                }
 182            }));
 183    }
 184
 185    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 186    /// when the mouse is outside of the bounds of this element.
 187    /// The imperative API equivalent to [`InteractiveElement::on_mouse_down_out`]
 188    ///
 189    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 190    pub fn on_mouse_down_out(
 191        &mut self,
 192        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 193    ) {
 194        self.mouse_down_listeners
 195            .push(Box::new(move |event, phase, hitbox, cx| {
 196                if phase == DispatchPhase::Capture && !hitbox.contains(&cx.mouse_position()) {
 197                    (listener)(event, cx)
 198                }
 199            }));
 200    }
 201
 202    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 203    /// when the mouse is outside of the bounds of this element.
 204    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up_out`]
 205    ///
 206    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 207    pub fn on_mouse_up_out(
 208        &mut self,
 209        button: MouseButton,
 210        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 211    ) {
 212        self.mouse_up_listeners
 213            .push(Box::new(move |event, phase, hitbox, cx| {
 214                if phase == DispatchPhase::Capture
 215                    && event.button == button
 216                    && !hitbox.is_hovered(cx)
 217                {
 218                    (listener)(event, cx);
 219                }
 220            }));
 221    }
 222
 223    /// Bind the given callback to the mouse move event, during the bubble phase
 224    /// The imperative API equivalent to [`InteractiveElement::on_mouse_move`]
 225    ///
 226    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 227    pub fn on_mouse_move(
 228        &mut self,
 229        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 230    ) {
 231        self.mouse_move_listeners
 232            .push(Box::new(move |event, phase, hitbox, cx| {
 233                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 234                    (listener)(event, cx);
 235                }
 236            }));
 237    }
 238
 239    /// Bind the given callback to the mouse drag event of the given type. Note that this
 240    /// will be called for all move events, inside or outside of this element, as long as the
 241    /// drag was started with this element under the mouse. Useful for implementing draggable
 242    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 243    /// The imperative API equivalent to [`InteractiveElement::on_drag_move`]
 244    ///
 245    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 246    pub fn on_drag_move<T>(
 247        &mut self,
 248        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 249    ) where
 250        T: 'static,
 251    {
 252        self.mouse_move_listeners
 253            .push(Box::new(move |event, phase, hitbox, cx| {
 254                if phase == DispatchPhase::Capture {
 255                    if let Some(drag) = &cx.active_drag {
 256                        if drag.value.as_ref().type_id() == TypeId::of::<T>() {
 257                            (listener)(
 258                                &DragMoveEvent {
 259                                    event: event.clone(),
 260                                    bounds: hitbox.bounds,
 261                                    drag: PhantomData,
 262                                    dragged_item: Arc::clone(&drag.value),
 263                                },
 264                                cx,
 265                            );
 266                        }
 267                    }
 268                }
 269            }));
 270    }
 271
 272    /// Bind the given callback to scroll wheel events during the bubble phase
 273    /// The imperative API equivalent to [`InteractiveElement::on_scroll_wheel`]
 274    ///
 275    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 276    pub fn on_scroll_wheel(
 277        &mut self,
 278        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 279    ) {
 280        self.scroll_wheel_listeners
 281            .push(Box::new(move |event, phase, hitbox, cx| {
 282                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 283                    (listener)(event, cx);
 284                }
 285            }));
 286    }
 287
 288    /// Bind the given callback to an action dispatch during the capture phase
 289    /// The imperative API equivalent to [`InteractiveElement::capture_action`]
 290    ///
 291    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 292    pub fn capture_action<A: Action>(
 293        &mut self,
 294        listener: impl Fn(&A, &mut WindowContext) + 'static,
 295    ) {
 296        self.action_listeners.push((
 297            TypeId::of::<A>(),
 298            Box::new(move |action, phase, cx| {
 299                let action = action.downcast_ref().unwrap();
 300                if phase == DispatchPhase::Capture {
 301                    (listener)(action, cx)
 302                } else {
 303                    cx.propagate();
 304                }
 305            }),
 306        ));
 307    }
 308
 309    /// Bind the given callback to an action dispatch during the bubble phase
 310    /// The imperative API equivalent to [`InteractiveElement::on_action`]
 311    ///
 312    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 313    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) {
 314        self.action_listeners.push((
 315            TypeId::of::<A>(),
 316            Box::new(move |action, phase, cx| {
 317                let action = action.downcast_ref().unwrap();
 318                if phase == DispatchPhase::Bubble {
 319                    (listener)(action, cx)
 320                }
 321            }),
 322        ));
 323    }
 324
 325    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 326    /// instead of a type parameter. Useful for component libraries that want to expose
 327    /// action bindings to their users.
 328    /// The imperative API equivalent to [`InteractiveElement::on_boxed_action`]
 329    ///
 330    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 331    pub fn on_boxed_action(
 332        &mut self,
 333        action: &dyn Action,
 334        listener: impl Fn(&dyn Action, &mut WindowContext) + 'static,
 335    ) {
 336        let action = action.boxed_clone();
 337        self.action_listeners.push((
 338            (*action).type_id(),
 339            Box::new(move |_, phase, cx| {
 340                if phase == DispatchPhase::Bubble {
 341                    (listener)(&*action, cx)
 342                }
 343            }),
 344        ));
 345    }
 346
 347    /// Bind the given callback to key down events during the bubble phase
 348    /// The imperative API equivalent to [`InteractiveElement::on_key_down`]
 349    ///
 350    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 351    pub fn on_key_down(&mut self, listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static) {
 352        self.key_down_listeners
 353            .push(Box::new(move |event, phase, cx| {
 354                if phase == DispatchPhase::Bubble {
 355                    (listener)(event, cx)
 356                }
 357            }));
 358    }
 359
 360    /// Bind the given callback to key down events during the capture phase
 361    /// The imperative API equivalent to [`InteractiveElement::capture_key_down`]
 362    ///
 363    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 364    pub fn capture_key_down(
 365        &mut self,
 366        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 367    ) {
 368        self.key_down_listeners
 369            .push(Box::new(move |event, phase, cx| {
 370                if phase == DispatchPhase::Capture {
 371                    listener(event, cx)
 372                }
 373            }));
 374    }
 375
 376    /// Bind the given callback to key up events during the bubble phase
 377    /// The imperative API equivalent to [`InteractiveElement::on_key_up`]
 378    ///
 379    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 380    pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 381        self.key_up_listeners
 382            .push(Box::new(move |event, phase, cx| {
 383                if phase == DispatchPhase::Bubble {
 384                    listener(event, cx)
 385                }
 386            }));
 387    }
 388
 389    /// Bind the given callback to key up events during the capture phase
 390    /// The imperative API equivalent to [`InteractiveElement::on_key_up`]
 391    ///
 392    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 393    pub fn capture_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 394        self.key_up_listeners
 395            .push(Box::new(move |event, phase, cx| {
 396                if phase == DispatchPhase::Capture {
 397                    listener(event, cx)
 398                }
 399            }));
 400    }
 401
 402    /// Bind the given callback to modifiers changing events.
 403    /// The imperative API equivalent to [`InteractiveElement::on_modifiers_changed`]
 404    ///
 405    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 406    pub fn on_modifiers_changed(
 407        &mut self,
 408        listener: impl Fn(&ModifiersChangedEvent, &mut WindowContext) + 'static,
 409    ) {
 410        self.modifiers_changed_listeners
 411            .push(Box::new(move |event, cx| listener(event, cx)));
 412    }
 413
 414    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element
 415    /// The imperative API equivalent to [`InteractiveElement::on_drop`]
 416    ///
 417    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 418    pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) {
 419        self.drop_listeners.push((
 420            TypeId::of::<T>(),
 421            Box::new(move |dragged_value, cx| {
 422                listener(dragged_value.downcast_ref().unwrap(), cx);
 423            }),
 424        ));
 425    }
 426
 427    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element
 428    /// The imperative API equivalent to [`InteractiveElement::can_drop`]
 429    pub fn can_drop(&mut self, predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static) {
 430        self.can_drop_predicate = Some(Box::new(predicate));
 431    }
 432
 433    /// Bind the given callback to click events of this element
 434    /// The imperative API equivalent to [`StatefulInteractiveElement::on_click`]
 435    ///
 436    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 437    pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static)
 438    where
 439        Self: Sized,
 440    {
 441        self.click_listeners
 442            .push(Box::new(move |event, cx| listener(event, cx)));
 443    }
 444
 445    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 446    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 447    /// the [`Self::on_drag_move`] API
 448    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`]
 449    ///
 450    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 451    pub fn on_drag<T, W>(
 452        &mut self,
 453        value: T,
 454        constructor: impl Fn(&T, Point<Pixels>, &mut WindowContext) -> View<W> + 'static,
 455    ) where
 456        Self: Sized,
 457        T: 'static,
 458        W: 'static + Render,
 459    {
 460        debug_assert!(
 461            self.drag_listener.is_none(),
 462            "calling on_drag more than once on the same element is not supported"
 463        );
 464        self.drag_listener = Some((
 465            Arc::new(value),
 466            Box::new(move |value, offset, cx| {
 467                constructor(value.downcast_ref().unwrap(), offset, cx).into()
 468            }),
 469        ));
 470    }
 471
 472    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 473    /// passed to the callback is true when the hover starts and false when it ends.
 474    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`]
 475    ///
 476    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 477    pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static)
 478    where
 479        Self: Sized,
 480    {
 481        debug_assert!(
 482            self.hover_listener.is_none(),
 483            "calling on_hover more than once on the same element is not supported"
 484        );
 485        self.hover_listener = Some(Box::new(listener));
 486    }
 487
 488    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 489    /// The imperative API equivalent to [`InteractiveElement::tooltip`]
 490    pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static)
 491    where
 492        Self: Sized,
 493    {
 494        debug_assert!(
 495            self.tooltip_builder.is_none(),
 496            "calling tooltip more than once on the same element is not supported"
 497        );
 498        self.tooltip_builder = Some(TooltipBuilder {
 499            build: Rc::new(build_tooltip),
 500            hoverable: false,
 501        });
 502    }
 503
 504    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 505    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
 506    /// the tooltip. The imperative API equivalent to [`InteractiveElement::hoverable_tooltip`]
 507    pub fn hoverable_tooltip(
 508        &mut self,
 509        build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static,
 510    ) where
 511        Self: Sized,
 512    {
 513        debug_assert!(
 514            self.tooltip_builder.is_none(),
 515            "calling tooltip more than once on the same element is not supported"
 516        );
 517        self.tooltip_builder = Some(TooltipBuilder {
 518            build: Rc::new(build_tooltip),
 519            hoverable: true,
 520        });
 521    }
 522
 523    /// Block the mouse from interacting with this element or any of its children
 524    /// The imperative API equivalent to [`InteractiveElement::occlude`]
 525    pub fn occlude_mouse(&mut self) {
 526        self.occlude_mouse = true;
 527    }
 528}
 529
 530/// A trait for elements that want to use the standard GPUI event handlers that don't
 531/// require any state.
 532pub trait InteractiveElement: Sized {
 533    /// Retrieve the interactivity state associated with this element
 534    fn interactivity(&mut self) -> &mut Interactivity;
 535
 536    /// Assign this element to a group of elements that can be styled together
 537    fn group(mut self, group: impl Into<SharedString>) -> Self {
 538        self.interactivity().group = Some(group.into());
 539        self
 540    }
 541
 542    /// Assign this element an ID, so that it can be used with interactivity
 543    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
 544        self.interactivity().element_id = Some(id.into());
 545
 546        Stateful { element: self }
 547    }
 548
 549    /// Track the focus state of the given focus handle on this element.
 550    /// If the focus handle is focused by the application, this element will
 551    /// apply its focused styles.
 552    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<Self> {
 553        self.interactivity().focusable = true;
 554        self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
 555        Focusable { element: self }
 556    }
 557
 558    /// Set the keymap context for this element. This will be used to determine
 559    /// which action to dispatch from the keymap.
 560    fn key_context<C, E>(mut self, key_context: C) -> Self
 561    where
 562        C: TryInto<KeyContext, Error = E>,
 563        E: Debug,
 564    {
 565        if let Some(key_context) = key_context.try_into().log_err() {
 566            self.interactivity().key_context = Some(key_context);
 567        }
 568        self
 569    }
 570
 571    /// Apply the given style to this element when the mouse hovers over it
 572    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 573        debug_assert!(
 574            self.interactivity().hover_style.is_none(),
 575            "hover style already set"
 576        );
 577        self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
 578        self
 579    }
 580
 581    /// Apply the given style to this element when the mouse hovers over a group member
 582    fn group_hover(
 583        mut self,
 584        group_name: impl Into<SharedString>,
 585        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 586    ) -> Self {
 587        self.interactivity().group_hover_style = Some(GroupStyle {
 588            group: group_name.into(),
 589            style: Box::new(f(StyleRefinement::default())),
 590        });
 591        self
 592    }
 593
 594    /// Bind the given callback to the mouse down event for the given mouse button,
 595    /// the fluent API equivalent to [`Interactivity::on_mouse_down`]
 596    ///
 597    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to the view state from this callback.
 598    fn on_mouse_down(
 599        mut self,
 600        button: MouseButton,
 601        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 602    ) -> Self {
 603        self.interactivity().on_mouse_down(button, listener);
 604        self
 605    }
 606
 607    #[cfg(any(test, feature = "test-support"))]
 608    /// Set a key that can be used to look up this element's bounds
 609    /// in the [`VisualTestContext::debug_bounds`] map
 610    /// This is a noop in release builds
 611    fn debug_selector(mut self, f: impl FnOnce() -> String) -> Self {
 612        self.interactivity().debug_selector = Some(f());
 613        self
 614    }
 615
 616    #[cfg(not(any(test, feature = "test-support")))]
 617    /// Set a key that can be used to look up this element's bounds
 618    /// in the [`VisualTestContext::debug_bounds`] map
 619    /// This is a noop in release builds
 620    #[inline]
 621    fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
 622        self
 623    }
 624
 625    /// Bind the given callback to the mouse down event for any button, during the capture phase
 626    /// the fluent API equivalent to [`Interactivity::capture_any_mouse_down`]
 627    ///
 628    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 629    fn capture_any_mouse_down(
 630        mut self,
 631        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 632    ) -> Self {
 633        self.interactivity().capture_any_mouse_down(listener);
 634        self
 635    }
 636
 637    /// Bind the given callback to the mouse down event for any button, during the capture phase
 638    /// the fluent API equivalent to [`Interactivity::on_any_mouse_down`]
 639    ///
 640    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 641    fn on_any_mouse_down(
 642        mut self,
 643        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 644    ) -> Self {
 645        self.interactivity().on_any_mouse_down(listener);
 646        self
 647    }
 648
 649    /// Bind the given callback to the mouse up event for the given button, during the bubble phase
 650    /// the fluent API equivalent to [`Interactivity::on_mouse_up`]
 651    ///
 652    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 653    fn on_mouse_up(
 654        mut self,
 655        button: MouseButton,
 656        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 657    ) -> Self {
 658        self.interactivity().on_mouse_up(button, listener);
 659        self
 660    }
 661
 662    /// Bind the given callback to the mouse up event for any button, during the capture phase
 663    /// the fluent API equivalent to [`Interactivity::capture_any_mouse_up`]
 664    ///
 665    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 666    fn capture_any_mouse_up(
 667        mut self,
 668        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 669    ) -> Self {
 670        self.interactivity().capture_any_mouse_up(listener);
 671        self
 672    }
 673
 674    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 675    /// when the mouse is outside of the bounds of this element.
 676    /// The fluent API equivalent to [`Interactivity::on_mouse_down_out`]
 677    ///
 678    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 679    fn on_mouse_down_out(
 680        mut self,
 681        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 682    ) -> Self {
 683        self.interactivity().on_mouse_down_out(listener);
 684        self
 685    }
 686
 687    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 688    /// when the mouse is outside of the bounds of this element.
 689    /// The fluent API equivalent to [`Interactivity::on_mouse_up_out`]
 690    ///
 691    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 692    fn on_mouse_up_out(
 693        mut self,
 694        button: MouseButton,
 695        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 696    ) -> Self {
 697        self.interactivity().on_mouse_up_out(button, listener);
 698        self
 699    }
 700
 701    /// Bind the given callback to the mouse move event, during the bubble phase
 702    /// The fluent API equivalent to [`Interactivity::on_mouse_move`]
 703    ///
 704    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 705    fn on_mouse_move(
 706        mut self,
 707        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 708    ) -> Self {
 709        self.interactivity().on_mouse_move(listener);
 710        self
 711    }
 712
 713    /// Bind the given callback to the mouse drag event of the given type. Note that this
 714    /// will be called for all move events, inside or outside of this element, as long as the
 715    /// drag was started with this element under the mouse. Useful for implementing draggable
 716    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 717    /// The fluent API equivalent to [`Interactivity::on_drag_move`]
 718    ///
 719    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 720    fn on_drag_move<T: 'static>(
 721        mut self,
 722        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 723    ) -> Self {
 724        self.interactivity().on_drag_move(listener);
 725        self
 726    }
 727
 728    /// Bind the given callback to scroll wheel events during the bubble phase
 729    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`]
 730    ///
 731    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 732    fn on_scroll_wheel(
 733        mut self,
 734        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 735    ) -> Self {
 736        self.interactivity().on_scroll_wheel(listener);
 737        self
 738    }
 739
 740    /// Capture the given action, before normal action dispatch can fire
 741    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`]
 742    ///
 743    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 744    fn capture_action<A: Action>(
 745        mut self,
 746        listener: impl Fn(&A, &mut WindowContext) + 'static,
 747    ) -> Self {
 748        self.interactivity().capture_action(listener);
 749        self
 750    }
 751
 752    /// Bind the given callback to an action dispatch during the bubble phase
 753    /// The fluent API equivalent to [`Interactivity::on_action`]
 754    ///
 755    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 756    fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
 757        self.interactivity().on_action(listener);
 758        self
 759    }
 760
 761    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 762    /// instead of a type parameter. Useful for component libraries that want to expose
 763    /// action bindings to their users.
 764    /// The fluent API equivalent to [`Interactivity::on_boxed_action`]
 765    ///
 766    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 767    fn on_boxed_action(
 768        mut self,
 769        action: &dyn Action,
 770        listener: impl Fn(&dyn Action, &mut WindowContext) + 'static,
 771    ) -> Self {
 772        self.interactivity().on_boxed_action(action, listener);
 773        self
 774    }
 775
 776    /// Bind the given callback to key down events during the bubble phase
 777    /// The fluent API equivalent to [`Interactivity::on_key_down`]
 778    ///
 779    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 780    fn on_key_down(
 781        mut self,
 782        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 783    ) -> Self {
 784        self.interactivity().on_key_down(listener);
 785        self
 786    }
 787
 788    /// Bind the given callback to key down events during the capture phase
 789    /// The fluent API equivalent to [`Interactivity::capture_key_down`]
 790    ///
 791    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 792    fn capture_key_down(
 793        mut self,
 794        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 795    ) -> Self {
 796        self.interactivity().capture_key_down(listener);
 797        self
 798    }
 799
 800    /// Bind the given callback to key up events during the bubble phase
 801    /// The fluent API equivalent to [`Interactivity::on_key_up`]
 802    ///
 803    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 804    fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
 805        self.interactivity().on_key_up(listener);
 806        self
 807    }
 808
 809    /// Bind the given callback to key up events during the capture phase
 810    /// The fluent API equivalent to [`Interactivity::capture_key_up`]
 811    ///
 812    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 813    fn capture_key_up(
 814        mut self,
 815        listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
 816    ) -> Self {
 817        self.interactivity().capture_key_up(listener);
 818        self
 819    }
 820
 821    /// Bind the given callback to modifiers changing events.
 822    /// The fluent API equivalent to [`Interactivity::on_modifiers_changed`]
 823    ///
 824    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 825    fn on_modifiers_changed(
 826        mut self,
 827        listener: impl Fn(&ModifiersChangedEvent, &mut WindowContext) + 'static,
 828    ) -> Self {
 829        self.interactivity().on_modifiers_changed(listener);
 830        self
 831    }
 832
 833    /// Apply the given style when the given data type is dragged over this element
 834    fn drag_over<S: 'static>(
 835        mut self,
 836        f: impl 'static + Fn(StyleRefinement, &S, &WindowContext) -> StyleRefinement,
 837    ) -> Self {
 838        self.interactivity().drag_over_styles.push((
 839            TypeId::of::<S>(),
 840            Box::new(move |currently_dragged: &dyn Any, cx| {
 841                f(
 842                    StyleRefinement::default(),
 843                    currently_dragged.downcast_ref::<S>().unwrap(),
 844                    cx,
 845                )
 846            }),
 847        ));
 848        self
 849    }
 850
 851    /// Apply the given style when the given data type is dragged over this element's group
 852    fn group_drag_over<S: 'static>(
 853        mut self,
 854        group_name: impl Into<SharedString>,
 855        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 856    ) -> Self {
 857        self.interactivity().group_drag_over_styles.push((
 858            TypeId::of::<S>(),
 859            GroupStyle {
 860                group: group_name.into(),
 861                style: Box::new(f(StyleRefinement::default())),
 862            },
 863        ));
 864        self
 865    }
 866
 867    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element
 868    /// The fluent API equivalent to [`Interactivity::on_drop`]
 869    ///
 870    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 871    fn on_drop<T: 'static>(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self {
 872        self.interactivity().on_drop(listener);
 873        self
 874    }
 875
 876    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element
 877    /// The fluent API equivalent to [`Interactivity::can_drop`]
 878    fn can_drop(
 879        mut self,
 880        predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static,
 881    ) -> Self {
 882        self.interactivity().can_drop(predicate);
 883        self
 884    }
 885
 886    /// Block the mouse from interacting with this element or any of its children
 887    /// The fluent API equivalent to [`Interactivity::occlude_mouse`]
 888    fn occlude(mut self) -> Self {
 889        self.interactivity().occlude_mouse();
 890        self
 891    }
 892
 893    /// Block the mouse from interacting with this element or any of its children
 894    /// The fluent API equivalent to [`Interactivity::occlude_mouse`]
 895    fn block_mouse_down(mut self) -> Self {
 896        self.on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
 897    }
 898}
 899
 900/// A trait for elements that want to use the standard GPUI interactivity features
 901/// that require state.
 902pub trait StatefulInteractiveElement: InteractiveElement {
 903    /// Set this element to focusable.
 904    fn focusable(mut self) -> Focusable<Self> {
 905        self.interactivity().focusable = true;
 906        Focusable { element: self }
 907    }
 908
 909    /// Set the overflow x and y to scroll.
 910    fn overflow_scroll(mut self) -> Self {
 911        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 912        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 913        self
 914    }
 915
 916    /// Set the overflow x to scroll.
 917    fn overflow_x_scroll(mut self) -> Self {
 918        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 919        self
 920    }
 921
 922    /// Set the overflow y to scroll.
 923    fn overflow_y_scroll(mut self) -> Self {
 924        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 925        self
 926    }
 927
 928    /// Track the scroll state of this element with the given handle.
 929    fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
 930        self.interactivity().tracked_scroll_handle = Some(scroll_handle.clone());
 931        self
 932    }
 933
 934    /// Track the scroll state of this element with the given handle.
 935    fn anchor_scroll(mut self, scroll_anchor: Option<ScrollAnchor>) -> Self {
 936        self.interactivity().scroll_anchor = scroll_anchor;
 937        self
 938    }
 939
 940    /// Set the given styles to be applied when this element is active.
 941    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 942    where
 943        Self: Sized,
 944    {
 945        self.interactivity().active_style = Some(Box::new(f(StyleRefinement::default())));
 946        self
 947    }
 948
 949    /// Set the given styles to be applied when this element's group is active.
 950    fn group_active(
 951        mut self,
 952        group_name: impl Into<SharedString>,
 953        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 954    ) -> Self
 955    where
 956        Self: Sized,
 957    {
 958        self.interactivity().group_active_style = Some(GroupStyle {
 959            group: group_name.into(),
 960            style: Box::new(f(StyleRefinement::default())),
 961        });
 962        self
 963    }
 964
 965    /// Bind the given callback to click events of this element
 966    /// The fluent API equivalent to [`Interactivity::on_click`]
 967    ///
 968    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 969    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self
 970    where
 971        Self: Sized,
 972    {
 973        self.interactivity().on_click(listener);
 974        self
 975    }
 976
 977    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 978    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 979    /// the [`Self::on_drag_move`] API.
 980    /// The callback also has access to the offset of triggering click from the origin of parent element.
 981    /// The fluent API equivalent to [`Interactivity::on_drag`]
 982    ///
 983    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 984    fn on_drag<T, W>(
 985        mut self,
 986        value: T,
 987        constructor: impl Fn(&T, Point<Pixels>, &mut WindowContext) -> View<W> + 'static,
 988    ) -> Self
 989    where
 990        Self: Sized,
 991        T: 'static,
 992        W: 'static + Render,
 993    {
 994        self.interactivity().on_drag(value, constructor);
 995        self
 996    }
 997
 998    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 999    /// passed to the callback is true when the hover starts and false when it ends.
1000    /// The fluent API equivalent to [`Interactivity::on_hover`]
1001    ///
1002    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
1003    fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self
1004    where
1005        Self: Sized,
1006    {
1007        self.interactivity().on_hover(listener);
1008        self
1009    }
1010
1011    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1012    /// The fluent API equivalent to [`Interactivity::tooltip`]
1013    fn tooltip(mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self
1014    where
1015        Self: Sized,
1016    {
1017        self.interactivity().tooltip(build_tooltip);
1018        self
1019    }
1020
1021    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1022    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
1023    /// the tooltip. The fluent API equivalent to [`Interactivity::hoverable_tooltip`]
1024    fn hoverable_tooltip(
1025        mut self,
1026        build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static,
1027    ) -> Self
1028    where
1029        Self: Sized,
1030    {
1031        self.interactivity().hoverable_tooltip(build_tooltip);
1032        self
1033    }
1034}
1035
1036/// A trait for providing focus related APIs to interactive elements
1037pub trait FocusableElement: InteractiveElement {
1038    /// Set the given styles to be applied when this element, specifically, is focused.
1039    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1040    where
1041        Self: Sized,
1042    {
1043        self.interactivity().focus_style = Some(Box::new(f(StyleRefinement::default())));
1044        self
1045    }
1046
1047    /// Set the given styles to be applied when this element is inside another element that is focused.
1048    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1049    where
1050        Self: Sized,
1051    {
1052        self.interactivity().in_focus_style = Some(Box::new(f(StyleRefinement::default())));
1053        self
1054    }
1055}
1056
1057pub(crate) type MouseDownListener =
1058    Box<dyn Fn(&MouseDownEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1059pub(crate) type MouseUpListener =
1060    Box<dyn Fn(&MouseUpEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1061
1062pub(crate) type MouseMoveListener =
1063    Box<dyn Fn(&MouseMoveEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1064
1065pub(crate) type ScrollWheelListener =
1066    Box<dyn Fn(&ScrollWheelEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1067
1068pub(crate) type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
1069
1070pub(crate) type DragListener =
1071    Box<dyn Fn(&dyn Any, Point<Pixels>, &mut WindowContext) -> AnyView + 'static>;
1072
1073type DropListener = Box<dyn Fn(&dyn Any, &mut WindowContext) + 'static>;
1074
1075type CanDropPredicate = Box<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>;
1076
1077pub(crate) struct TooltipBuilder {
1078    build: Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>,
1079    hoverable: bool,
1080}
1081
1082pub(crate) type KeyDownListener =
1083    Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
1084
1085pub(crate) type KeyUpListener =
1086    Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + 'static>;
1087
1088pub(crate) type ModifiersChangedListener =
1089    Box<dyn Fn(&ModifiersChangedEvent, &mut WindowContext) + 'static>;
1090
1091pub(crate) type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
1092
1093/// Construct a new [`Div`] element
1094#[track_caller]
1095pub fn div() -> Div {
1096    #[cfg(debug_assertions)]
1097    let interactivity = Interactivity {
1098        location: Some(*core::panic::Location::caller()),
1099        ..Default::default()
1100    };
1101
1102    #[cfg(not(debug_assertions))]
1103    let interactivity = Interactivity::default();
1104
1105    Div {
1106        interactivity,
1107        children: SmallVec::default(),
1108        prepaint_listener: None,
1109    }
1110}
1111
1112/// A [`Div`] element, the all-in-one element for building complex UIs in GPUI
1113pub struct Div {
1114    interactivity: Interactivity,
1115    children: SmallVec<[AnyElement; 2]>,
1116    prepaint_listener: Option<Box<dyn Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static>>,
1117}
1118
1119impl Div {
1120    /// Add a listener to be called when the children of this `Div` are prepainted.
1121    /// This allows you to store the [`Bounds`] of the children for later use.
1122    pub fn on_children_prepainted(
1123        mut self,
1124        listener: impl Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static,
1125    ) -> Self {
1126        self.prepaint_listener = Some(Box::new(listener));
1127        self
1128    }
1129}
1130
1131/// A frame state for a `Div` element, which contains layout IDs for its children.
1132///
1133/// This struct is used internally by the `Div` element to manage the layout state of its children
1134/// during the UI update cycle. It holds a small vector of `LayoutId` values, each corresponding to
1135/// a child element of the `Div`. These IDs are used to query the layout engine for the computed
1136/// bounds of the children after the layout phase is complete.
1137pub struct DivFrameState {
1138    child_layout_ids: SmallVec<[LayoutId; 2]>,
1139}
1140
1141impl Styled for Div {
1142    fn style(&mut self) -> &mut StyleRefinement {
1143        &mut self.interactivity.base_style
1144    }
1145}
1146
1147impl InteractiveElement for Div {
1148    fn interactivity(&mut self) -> &mut Interactivity {
1149        &mut self.interactivity
1150    }
1151}
1152
1153impl ParentElement for Div {
1154    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
1155        self.children.extend(elements)
1156    }
1157}
1158
1159impl Element for Div {
1160    type RequestLayoutState = DivFrameState;
1161    type PrepaintState = Option<Hitbox>;
1162
1163    fn id(&self) -> Option<ElementId> {
1164        self.interactivity.element_id.clone()
1165    }
1166
1167    fn request_layout(
1168        &mut self,
1169        global_id: Option<&GlobalElementId>,
1170        cx: &mut WindowContext,
1171    ) -> (LayoutId, Self::RequestLayoutState) {
1172        let mut child_layout_ids = SmallVec::new();
1173        let layout_id = self
1174            .interactivity
1175            .request_layout(global_id, cx, |style, cx| {
1176                cx.with_text_style(style.text_style().cloned(), |cx| {
1177                    child_layout_ids = self
1178                        .children
1179                        .iter_mut()
1180                        .map(|child| child.request_layout(cx))
1181                        .collect::<SmallVec<_>>();
1182                    cx.request_layout(style, child_layout_ids.iter().copied())
1183                })
1184            });
1185        (layout_id, DivFrameState { child_layout_ids })
1186    }
1187
1188    fn prepaint(
1189        &mut self,
1190        global_id: Option<&GlobalElementId>,
1191        bounds: Bounds<Pixels>,
1192        request_layout: &mut Self::RequestLayoutState,
1193        cx: &mut WindowContext,
1194    ) -> Option<Hitbox> {
1195        let has_prepaint_listener = self.prepaint_listener.is_some();
1196        let mut children_bounds = Vec::with_capacity(if has_prepaint_listener {
1197            request_layout.child_layout_ids.len()
1198        } else {
1199            0
1200        });
1201
1202        let mut child_min = point(Pixels::MAX, Pixels::MAX);
1203        let mut child_max = Point::default();
1204        if let Some(handle) = self.interactivity.scroll_anchor.as_ref() {
1205            *handle.last_origin.borrow_mut() = bounds.origin - cx.element_offset();
1206        }
1207        let content_size = if request_layout.child_layout_ids.is_empty() {
1208            bounds.size
1209        } else if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1210            let mut state = scroll_handle.0.borrow_mut();
1211            state.child_bounds = Vec::with_capacity(request_layout.child_layout_ids.len());
1212            state.bounds = bounds;
1213            let requested = state.requested_scroll_top.take();
1214            // TODO az
1215
1216            for (ix, child_layout_id) in request_layout.child_layout_ids.iter().enumerate() {
1217                let child_bounds = cx.layout_bounds(*child_layout_id);
1218                child_min = child_min.min(&child_bounds.origin);
1219                child_max = child_max.max(&child_bounds.bottom_right());
1220                state.child_bounds.push(child_bounds);
1221
1222                if let Some(requested) = requested.as_ref() {
1223                    if requested.0 == ix {
1224                        *state.offset.borrow_mut() =
1225                            bounds.origin - (child_bounds.origin - point(px(0.), requested.1));
1226                    }
1227                }
1228            }
1229            (child_max - child_min).into()
1230        } else {
1231            for child_layout_id in &request_layout.child_layout_ids {
1232                let child_bounds = cx.layout_bounds(*child_layout_id);
1233                child_min = child_min.min(&child_bounds.origin);
1234                child_max = child_max.max(&child_bounds.bottom_right());
1235
1236                if has_prepaint_listener {
1237                    children_bounds.push(child_bounds);
1238                }
1239            }
1240            (child_max - child_min).into()
1241        };
1242
1243        self.interactivity.prepaint(
1244            global_id,
1245            bounds,
1246            content_size,
1247            cx,
1248            |_style, scroll_offset, hitbox, cx| {
1249                cx.with_element_offset(scroll_offset, |cx| {
1250                    for child in &mut self.children {
1251                        child.prepaint(cx);
1252                    }
1253                });
1254
1255                if let Some(listener) = self.prepaint_listener.as_ref() {
1256                    listener(children_bounds, cx);
1257                }
1258
1259                hitbox
1260            },
1261        )
1262    }
1263
1264    fn paint(
1265        &mut self,
1266        global_id: Option<&GlobalElementId>,
1267        bounds: Bounds<Pixels>,
1268        _request_layout: &mut Self::RequestLayoutState,
1269        hitbox: &mut Option<Hitbox>,
1270        cx: &mut WindowContext,
1271    ) {
1272        self.interactivity
1273            .paint(global_id, bounds, hitbox.as_ref(), cx, |_style, cx| {
1274                for child in &mut self.children {
1275                    child.paint(cx);
1276                }
1277            });
1278    }
1279}
1280
1281impl IntoElement for Div {
1282    type Element = Self;
1283
1284    fn into_element(self) -> Self::Element {
1285        self
1286    }
1287}
1288
1289/// The interactivity struct. Powers all of the general-purpose
1290/// interactivity in the `Div` element.
1291#[derive(Default)]
1292pub struct Interactivity {
1293    /// The element ID of the element. In id is required to support a stateful subset of the interactivity such as on_click.
1294    pub element_id: Option<ElementId>,
1295    /// Whether the element was clicked. This will only be present after layout.
1296    pub active: Option<bool>,
1297    /// Whether the element was hovered. This will only be present after paint if an hitbox
1298    /// was created for the interactive element.
1299    pub hovered: Option<bool>,
1300    pub(crate) tooltip_id: Option<TooltipId>,
1301    pub(crate) content_size: Size<Pixels>,
1302    pub(crate) key_context: Option<KeyContext>,
1303    pub(crate) focusable: bool,
1304    pub(crate) tracked_focus_handle: Option<FocusHandle>,
1305    pub(crate) tracked_scroll_handle: Option<ScrollHandle>,
1306    pub(crate) scroll_anchor: Option<ScrollAnchor>,
1307    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
1308    pub(crate) group: Option<SharedString>,
1309    /// The base style of the element, before any modifications are applied
1310    /// by focus, active, etc.
1311    pub base_style: Box<StyleRefinement>,
1312    pub(crate) focus_style: Option<Box<StyleRefinement>>,
1313    pub(crate) in_focus_style: Option<Box<StyleRefinement>>,
1314    pub(crate) hover_style: Option<Box<StyleRefinement>>,
1315    pub(crate) group_hover_style: Option<GroupStyle>,
1316    pub(crate) active_style: Option<Box<StyleRefinement>>,
1317    pub(crate) group_active_style: Option<GroupStyle>,
1318    pub(crate) drag_over_styles: Vec<(
1319        TypeId,
1320        Box<dyn Fn(&dyn Any, &mut WindowContext) -> StyleRefinement>,
1321    )>,
1322    pub(crate) group_drag_over_styles: Vec<(TypeId, GroupStyle)>,
1323    pub(crate) mouse_down_listeners: Vec<MouseDownListener>,
1324    pub(crate) mouse_up_listeners: Vec<MouseUpListener>,
1325    pub(crate) mouse_move_listeners: Vec<MouseMoveListener>,
1326    pub(crate) scroll_wheel_listeners: Vec<ScrollWheelListener>,
1327    pub(crate) key_down_listeners: Vec<KeyDownListener>,
1328    pub(crate) key_up_listeners: Vec<KeyUpListener>,
1329    pub(crate) modifiers_changed_listeners: Vec<ModifiersChangedListener>,
1330    pub(crate) action_listeners: Vec<(TypeId, ActionListener)>,
1331    pub(crate) drop_listeners: Vec<(TypeId, DropListener)>,
1332    pub(crate) can_drop_predicate: Option<CanDropPredicate>,
1333    pub(crate) click_listeners: Vec<ClickListener>,
1334    pub(crate) drag_listener: Option<(Arc<dyn Any>, DragListener)>,
1335    pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
1336    pub(crate) tooltip_builder: Option<TooltipBuilder>,
1337    pub(crate) occlude_mouse: bool,
1338
1339    #[cfg(debug_assertions)]
1340    pub(crate) location: Option<core::panic::Location<'static>>,
1341
1342    #[cfg(any(test, feature = "test-support"))]
1343    pub(crate) debug_selector: Option<String>,
1344}
1345
1346impl Interactivity {
1347    /// Layout this element according to this interactivity state's configured styles
1348    pub fn request_layout(
1349        &mut self,
1350        global_id: Option<&GlobalElementId>,
1351        cx: &mut WindowContext,
1352        f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
1353    ) -> LayoutId {
1354        cx.with_optional_element_state::<InteractiveElementState, _>(
1355            global_id,
1356            |element_state, cx| {
1357                let mut element_state =
1358                    element_state.map(|element_state| element_state.unwrap_or_default());
1359
1360                if let Some(element_state) = element_state.as_ref() {
1361                    if cx.has_active_drag() {
1362                        if let Some(pending_mouse_down) = element_state.pending_mouse_down.as_ref()
1363                        {
1364                            *pending_mouse_down.borrow_mut() = None;
1365                        }
1366                        if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1367                            *clicked_state.borrow_mut() = ElementClickedState::default();
1368                        }
1369                    }
1370                }
1371
1372                // Ensure we store a focus handle in our element state if we're focusable.
1373                // If there's an explicit focus handle we're tracking, use that. Otherwise
1374                // create a new handle and store it in the element state, which lives for as
1375                // as frames contain an element with this id.
1376                if self.focusable && self.tracked_focus_handle.is_none() {
1377                    if let Some(element_state) = element_state.as_mut() {
1378                        self.tracked_focus_handle = Some(
1379                            element_state
1380                                .focus_handle
1381                                .get_or_insert_with(|| cx.focus_handle())
1382                                .clone(),
1383                        );
1384                    }
1385                }
1386
1387                if let Some(scroll_handle) = self.tracked_scroll_handle.as_ref() {
1388                    self.scroll_offset = Some(scroll_handle.0.borrow().offset.clone());
1389                } else if self.base_style.overflow.x == Some(Overflow::Scroll)
1390                    || self.base_style.overflow.y == Some(Overflow::Scroll)
1391                {
1392                    if let Some(element_state) = element_state.as_mut() {
1393                        self.scroll_offset = Some(
1394                            element_state
1395                                .scroll_offset
1396                                .get_or_insert_with(Rc::default)
1397                                .clone(),
1398                        );
1399                    }
1400                }
1401
1402                let style = self.compute_style_internal(None, element_state.as_mut(), cx);
1403                let layout_id = f(style, cx);
1404                (layout_id, element_state)
1405            },
1406        )
1407    }
1408
1409    /// Commit the bounds of this element according to this interactivity state's configured styles.
1410    pub fn prepaint<R>(
1411        &mut self,
1412        global_id: Option<&GlobalElementId>,
1413        bounds: Bounds<Pixels>,
1414        content_size: Size<Pixels>,
1415        cx: &mut WindowContext,
1416        f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut WindowContext) -> R,
1417    ) -> R {
1418        self.content_size = content_size;
1419        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1420            cx.set_focus_handle(focus_handle);
1421        }
1422        cx.with_optional_element_state::<InteractiveElementState, _>(
1423            global_id,
1424            |element_state, cx| {
1425                let mut element_state =
1426                    element_state.map(|element_state| element_state.unwrap_or_default());
1427                let style = self.compute_style_internal(None, element_state.as_mut(), cx);
1428
1429                if let Some(element_state) = element_state.as_mut() {
1430                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1431                        let clicked_state = clicked_state.borrow();
1432                        self.active = Some(clicked_state.element);
1433                    }
1434                    if let Some(active_tooltip) = element_state.active_tooltip.as_ref() {
1435                        if self.tooltip_builder.is_some() {
1436                            self.tooltip_id = set_tooltip_on_window(active_tooltip, cx);
1437                        } else {
1438                            // If there is no longer a tooltip builder, remove the active tooltip.
1439                            element_state.active_tooltip.take();
1440                        }
1441                    }
1442                }
1443
1444                cx.with_text_style(style.text_style().cloned(), |cx| {
1445                    cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
1446                        let hitbox = if self.should_insert_hitbox(&style) {
1447                            Some(cx.insert_hitbox(bounds, self.occlude_mouse))
1448                        } else {
1449                            None
1450                        };
1451
1452                        let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
1453                        let result = f(&style, scroll_offset, hitbox, cx);
1454                        (result, element_state)
1455                    })
1456                })
1457            },
1458        )
1459    }
1460
1461    fn should_insert_hitbox(&self, style: &Style) -> bool {
1462        self.occlude_mouse
1463            || style.mouse_cursor.is_some()
1464            || self.group.is_some()
1465            || self.scroll_offset.is_some()
1466            || self.tracked_focus_handle.is_some()
1467            || self.hover_style.is_some()
1468            || self.group_hover_style.is_some()
1469            || !self.mouse_up_listeners.is_empty()
1470            || !self.mouse_down_listeners.is_empty()
1471            || !self.mouse_move_listeners.is_empty()
1472            || !self.click_listeners.is_empty()
1473            || !self.scroll_wheel_listeners.is_empty()
1474            || self.drag_listener.is_some()
1475            || !self.drop_listeners.is_empty()
1476            || self.tooltip_builder.is_some()
1477    }
1478
1479    fn clamp_scroll_position(
1480        &self,
1481        bounds: Bounds<Pixels>,
1482        style: &Style,
1483        cx: &mut WindowContext,
1484    ) -> Point<Pixels> {
1485        if let Some(scroll_offset) = self.scroll_offset.as_ref() {
1486            if let Some(scroll_handle) = &self.tracked_scroll_handle {
1487                scroll_handle.0.borrow_mut().overflow = style.overflow;
1488            }
1489
1490            let rem_size = cx.rem_size();
1491            let padding_size = size(
1492                style
1493                    .padding
1494                    .left
1495                    .to_pixels(bounds.size.width.into(), rem_size)
1496                    + style
1497                        .padding
1498                        .right
1499                        .to_pixels(bounds.size.width.into(), rem_size),
1500                style
1501                    .padding
1502                    .top
1503                    .to_pixels(bounds.size.height.into(), rem_size)
1504                    + style
1505                        .padding
1506                        .bottom
1507                        .to_pixels(bounds.size.height.into(), rem_size),
1508            );
1509            let scroll_max = (self.content_size + padding_size - bounds.size).max(&Size::default());
1510            // Clamp scroll offset in case scroll max is smaller now (e.g., if children
1511            // were removed or the bounds became larger).
1512            let mut scroll_offset = scroll_offset.borrow_mut();
1513            scroll_offset.x = scroll_offset.x.clamp(-scroll_max.width, px(0.));
1514            scroll_offset.y = scroll_offset.y.clamp(-scroll_max.height, px(0.));
1515            *scroll_offset
1516        } else {
1517            Point::default()
1518        }
1519    }
1520
1521    /// Paint this element according to this interactivity state's configured styles
1522    /// and bind the element's mouse and keyboard events.
1523    ///
1524    /// content_size is the size of the content of the element, which may be larger than the
1525    /// element's bounds if the element is scrollable.
1526    ///
1527    /// the final computed style will be passed to the provided function, along
1528    /// with the current scroll offset
1529    pub fn paint(
1530        &mut self,
1531        global_id: Option<&GlobalElementId>,
1532        bounds: Bounds<Pixels>,
1533        hitbox: Option<&Hitbox>,
1534        cx: &mut WindowContext,
1535        f: impl FnOnce(&Style, &mut WindowContext),
1536    ) {
1537        self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(cx));
1538        cx.with_optional_element_state::<InteractiveElementState, _>(
1539            global_id,
1540            |element_state, cx| {
1541                let mut element_state =
1542                    element_state.map(|element_state| element_state.unwrap_or_default());
1543
1544                let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
1545
1546                #[cfg(any(feature = "test-support", test))]
1547                if let Some(debug_selector) = &self.debug_selector {
1548                    cx.window
1549                        .next_frame
1550                        .debug_bounds
1551                        .insert(debug_selector.clone(), bounds);
1552                }
1553
1554                self.paint_hover_group_handler(cx);
1555
1556                if style.visibility == Visibility::Hidden {
1557                    return ((), element_state);
1558                }
1559
1560                cx.with_element_opacity(style.opacity, |cx| {
1561                    style.paint(bounds, cx, |cx: &mut WindowContext| {
1562                        cx.with_text_style(style.text_style().cloned(), |cx| {
1563                            cx.with_content_mask(
1564                                style.overflow_mask(bounds, cx.rem_size()),
1565                                |cx| {
1566                                    if let Some(hitbox) = hitbox {
1567                                        #[cfg(debug_assertions)]
1568                                        self.paint_debug_info(global_id, hitbox, &style, cx);
1569
1570                                        if !cx.has_active_drag() {
1571                                            if let Some(mouse_cursor) = style.mouse_cursor {
1572                                                cx.set_cursor_style(mouse_cursor, hitbox);
1573                                            }
1574                                        }
1575
1576                                        if let Some(group) = self.group.clone() {
1577                                            GroupHitboxes::push(group, hitbox.id, cx);
1578                                        }
1579
1580                                        self.paint_mouse_listeners(
1581                                            hitbox,
1582                                            element_state.as_mut(),
1583                                            cx,
1584                                        );
1585                                        self.paint_scroll_listener(hitbox, &style, cx);
1586                                    }
1587
1588                                    self.paint_keyboard_listeners(cx);
1589                                    f(&style, cx);
1590
1591                                    if hitbox.is_some() {
1592                                        if let Some(group) = self.group.as_ref() {
1593                                            GroupHitboxes::pop(group, cx);
1594                                        }
1595                                    }
1596                                },
1597                            );
1598                        });
1599                    });
1600                });
1601
1602                ((), element_state)
1603            },
1604        );
1605    }
1606
1607    #[cfg(debug_assertions)]
1608    fn paint_debug_info(
1609        &self,
1610        global_id: Option<&GlobalElementId>,
1611        hitbox: &Hitbox,
1612        style: &Style,
1613        cx: &mut WindowContext,
1614    ) {
1615        if global_id.is_some()
1616            && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
1617            && hitbox.is_hovered(cx)
1618        {
1619            const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
1620            let element_id = format!("{:?}", global_id.unwrap());
1621            let str_len = element_id.len();
1622
1623            let render_debug_text = |cx: &mut WindowContext| {
1624                if let Some(text) = cx
1625                    .text_system()
1626                    .shape_text(
1627                        element_id.into(),
1628                        FONT_SIZE,
1629                        &[cx.text_style().to_run(str_len)],
1630                        None,
1631                    )
1632                    .ok()
1633                    .and_then(|mut text| text.pop())
1634                {
1635                    text.paint(hitbox.origin, FONT_SIZE, cx).ok();
1636
1637                    let text_bounds = crate::Bounds {
1638                        origin: hitbox.origin,
1639                        size: text.size(FONT_SIZE),
1640                    };
1641                    if self.location.is_some()
1642                        && text_bounds.contains(&cx.mouse_position())
1643                        && cx.modifiers().secondary()
1644                    {
1645                        let secondary_held = cx.modifiers().secondary();
1646                        cx.on_key_event({
1647                            move |e: &crate::ModifiersChangedEvent, _phase, cx| {
1648                                if e.modifiers.secondary() != secondary_held
1649                                    && text_bounds.contains(&cx.mouse_position())
1650                                {
1651                                    cx.refresh();
1652                                }
1653                            }
1654                        });
1655
1656                        let was_hovered = hitbox.is_hovered(cx);
1657                        cx.on_mouse_event({
1658                            let hitbox = hitbox.clone();
1659                            move |_: &MouseMoveEvent, phase, cx| {
1660                                if phase == DispatchPhase::Capture {
1661                                    let hovered = hitbox.is_hovered(cx);
1662                                    if hovered != was_hovered {
1663                                        cx.refresh();
1664                                    }
1665                                }
1666                            }
1667                        });
1668
1669                        cx.on_mouse_event({
1670                            let hitbox = hitbox.clone();
1671                            let location = self.location.unwrap();
1672                            move |e: &crate::MouseDownEvent, phase, cx| {
1673                                if text_bounds.contains(&e.position)
1674                                    && phase.capture()
1675                                    && hitbox.is_hovered(cx)
1676                                {
1677                                    cx.stop_propagation();
1678                                    let Ok(dir) = std::env::current_dir() else {
1679                                        return;
1680                                    };
1681
1682                                    eprintln!(
1683                                        "This element was created at:\n{}:{}:{}",
1684                                        dir.join(location.file()).to_string_lossy(),
1685                                        location.line(),
1686                                        location.column()
1687                                    );
1688                                }
1689                            }
1690                        });
1691                        cx.paint_quad(crate::outline(
1692                            crate::Bounds {
1693                                origin: hitbox.origin
1694                                    + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
1695                                size: crate::Size {
1696                                    width: text_bounds.size.width,
1697                                    height: crate::px(1.),
1698                                },
1699                            },
1700                            crate::red(),
1701                        ))
1702                    }
1703                }
1704            };
1705
1706            cx.with_text_style(
1707                Some(crate::TextStyleRefinement {
1708                    color: Some(crate::red()),
1709                    line_height: Some(FONT_SIZE.into()),
1710                    background_color: Some(crate::white()),
1711                    ..Default::default()
1712                }),
1713                render_debug_text,
1714            )
1715        }
1716    }
1717
1718    fn paint_mouse_listeners(
1719        &mut self,
1720        hitbox: &Hitbox,
1721        element_state: Option<&mut InteractiveElementState>,
1722        cx: &mut WindowContext,
1723    ) {
1724        // If this element can be focused, register a mouse down listener
1725        // that will automatically transfer focus when hitting the element.
1726        // This behavior can be suppressed by using `cx.prevent_default()`.
1727        if let Some(focus_handle) = self.tracked_focus_handle.clone() {
1728            let hitbox = hitbox.clone();
1729            cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1730                if phase == DispatchPhase::Bubble
1731                    && hitbox.is_hovered(cx)
1732                    && !cx.default_prevented()
1733                {
1734                    cx.focus(&focus_handle);
1735                    // If there is a parent that is also focusable, prevent it
1736                    // from transferring focus because we already did so.
1737                    cx.prevent_default();
1738                }
1739            });
1740        }
1741
1742        for listener in self.mouse_down_listeners.drain(..) {
1743            let hitbox = hitbox.clone();
1744            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
1745                listener(event, phase, &hitbox, cx);
1746            })
1747        }
1748
1749        for listener in self.mouse_up_listeners.drain(..) {
1750            let hitbox = hitbox.clone();
1751            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
1752                listener(event, phase, &hitbox, cx);
1753            })
1754        }
1755
1756        for listener in self.mouse_move_listeners.drain(..) {
1757            let hitbox = hitbox.clone();
1758            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1759                listener(event, phase, &hitbox, cx);
1760            })
1761        }
1762
1763        for listener in self.scroll_wheel_listeners.drain(..) {
1764            let hitbox = hitbox.clone();
1765            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1766                listener(event, phase, &hitbox, cx);
1767            })
1768        }
1769
1770        if self.hover_style.is_some()
1771            || self.base_style.mouse_cursor.is_some()
1772            || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
1773        {
1774            let hitbox = hitbox.clone();
1775            let was_hovered = hitbox.is_hovered(cx);
1776            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1777                let hovered = hitbox.is_hovered(cx);
1778                if phase == DispatchPhase::Capture && hovered != was_hovered {
1779                    cx.refresh();
1780                }
1781            });
1782        }
1783
1784        let mut drag_listener = mem::take(&mut self.drag_listener);
1785        let drop_listeners = mem::take(&mut self.drop_listeners);
1786        let click_listeners = mem::take(&mut self.click_listeners);
1787        let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
1788
1789        if !drop_listeners.is_empty() {
1790            let hitbox = hitbox.clone();
1791            cx.on_mouse_event({
1792                move |_: &MouseUpEvent, phase, cx| {
1793                    if let Some(drag) = &cx.active_drag {
1794                        if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
1795                            let drag_state_type = drag.value.as_ref().type_id();
1796                            for (drop_state_type, listener) in &drop_listeners {
1797                                if *drop_state_type == drag_state_type {
1798                                    let drag = cx
1799                                        .active_drag
1800                                        .take()
1801                                        .expect("checked for type drag state type above");
1802
1803                                    let mut can_drop = true;
1804                                    if let Some(predicate) = &can_drop_predicate {
1805                                        can_drop = predicate(drag.value.as_ref(), cx);
1806                                    }
1807
1808                                    if can_drop {
1809                                        listener(drag.value.as_ref(), cx);
1810                                        cx.refresh();
1811                                        cx.stop_propagation();
1812                                    }
1813                                }
1814                            }
1815                        }
1816                    }
1817                }
1818            });
1819        }
1820
1821        if let Some(element_state) = element_state {
1822            if !click_listeners.is_empty() || drag_listener.is_some() {
1823                let pending_mouse_down = element_state
1824                    .pending_mouse_down
1825                    .get_or_insert_with(Default::default)
1826                    .clone();
1827
1828                let clicked_state = element_state
1829                    .clicked_state
1830                    .get_or_insert_with(Default::default)
1831                    .clone();
1832
1833                cx.on_mouse_event({
1834                    let pending_mouse_down = pending_mouse_down.clone();
1835                    let hitbox = hitbox.clone();
1836                    move |event: &MouseDownEvent, phase, cx| {
1837                        if phase == DispatchPhase::Bubble
1838                            && event.button == MouseButton::Left
1839                            && hitbox.is_hovered(cx)
1840                        {
1841                            *pending_mouse_down.borrow_mut() = Some(event.clone());
1842                            cx.refresh();
1843                        }
1844                    }
1845                });
1846
1847                cx.on_mouse_event({
1848                    let pending_mouse_down = pending_mouse_down.clone();
1849                    let hitbox = hitbox.clone();
1850                    move |event: &MouseMoveEvent, phase, cx| {
1851                        if phase == DispatchPhase::Capture {
1852                            return;
1853                        }
1854
1855                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1856                        if let Some(mouse_down) = pending_mouse_down.clone() {
1857                            if !cx.has_active_drag()
1858                                && (event.position - mouse_down.position).magnitude()
1859                                    > DRAG_THRESHOLD
1860                            {
1861                                if let Some((drag_value, drag_listener)) = drag_listener.take() {
1862                                    *clicked_state.borrow_mut() = ElementClickedState::default();
1863                                    let cursor_offset = event.position - hitbox.origin;
1864                                    let drag =
1865                                        (drag_listener)(drag_value.as_ref(), cursor_offset, cx);
1866                                    cx.active_drag = Some(AnyDrag {
1867                                        view: drag,
1868                                        value: drag_value,
1869                                        cursor_offset,
1870                                    });
1871                                    pending_mouse_down.take();
1872                                    cx.refresh();
1873                                    cx.stop_propagation();
1874                                }
1875                            }
1876                        }
1877                    }
1878                });
1879
1880                cx.on_mouse_event({
1881                    let mut captured_mouse_down = None;
1882                    let hitbox = hitbox.clone();
1883                    move |event: &MouseUpEvent, phase, cx| match phase {
1884                        // Clear the pending mouse down during the capture phase,
1885                        // so that it happens even if another event handler stops
1886                        // propagation.
1887                        DispatchPhase::Capture => {
1888                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1889                            if pending_mouse_down.is_some() && hitbox.is_hovered(cx) {
1890                                captured_mouse_down = pending_mouse_down.take();
1891                                cx.refresh();
1892                            }
1893                        }
1894                        // Fire click handlers during the bubble phase.
1895                        DispatchPhase::Bubble => {
1896                            if let Some(mouse_down) = captured_mouse_down.take() {
1897                                let mouse_click = ClickEvent {
1898                                    down: mouse_down,
1899                                    up: event.clone(),
1900                                };
1901                                for listener in &click_listeners {
1902                                    listener(&mouse_click, cx);
1903                                }
1904                            }
1905                        }
1906                    }
1907                });
1908            }
1909
1910            if let Some(hover_listener) = self.hover_listener.take() {
1911                let hitbox = hitbox.clone();
1912                let was_hovered = element_state
1913                    .hover_state
1914                    .get_or_insert_with(Default::default)
1915                    .clone();
1916                let has_mouse_down = element_state
1917                    .pending_mouse_down
1918                    .get_or_insert_with(Default::default)
1919                    .clone();
1920
1921                cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1922                    if phase != DispatchPhase::Bubble {
1923                        return;
1924                    }
1925                    let is_hovered = has_mouse_down.borrow().is_none()
1926                        && !cx.has_active_drag()
1927                        && hitbox.is_hovered(cx);
1928                    let mut was_hovered = was_hovered.borrow_mut();
1929
1930                    if is_hovered != *was_hovered {
1931                        *was_hovered = is_hovered;
1932                        drop(was_hovered);
1933
1934                        hover_listener(&is_hovered, cx);
1935                    }
1936                });
1937            }
1938
1939            if let Some(tooltip_builder) = self.tooltip_builder.take() {
1940                let active_tooltip = element_state
1941                    .active_tooltip
1942                    .get_or_insert_with(Default::default)
1943                    .clone();
1944                let pending_mouse_down = element_state
1945                    .pending_mouse_down
1946                    .get_or_insert_with(Default::default)
1947                    .clone();
1948
1949                let tooltip_is_hoverable = tooltip_builder.hoverable;
1950                let build_tooltip = Rc::new(move |cx: &mut WindowContext| {
1951                    Some(((tooltip_builder.build)(cx), tooltip_is_hoverable))
1952                });
1953                // Use bounds instead of testing hitbox since check_is_hovered is also called
1954                // during prepaint.
1955                let source_bounds = hitbox.bounds;
1956                let check_is_hovered = Rc::new(move |cx: &WindowContext| {
1957                    pending_mouse_down.borrow().is_none()
1958                        && source_bounds.contains(&cx.mouse_position())
1959                });
1960                register_tooltip_mouse_handlers(
1961                    &active_tooltip,
1962                    self.tooltip_id,
1963                    build_tooltip,
1964                    check_is_hovered,
1965                    cx,
1966                );
1967            }
1968
1969            let active_state = element_state
1970                .clicked_state
1971                .get_or_insert_with(Default::default)
1972                .clone();
1973            if active_state.borrow().is_clicked() {
1974                cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
1975                    if phase == DispatchPhase::Capture {
1976                        *active_state.borrow_mut() = ElementClickedState::default();
1977                        cx.refresh();
1978                    }
1979                });
1980            } else {
1981                let active_group_hitbox = self
1982                    .group_active_style
1983                    .as_ref()
1984                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
1985                let hitbox = hitbox.clone();
1986                cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1987                    if phase == DispatchPhase::Bubble && !cx.default_prevented() {
1988                        let group_hovered = active_group_hitbox
1989                            .map_or(false, |group_hitbox_id| group_hitbox_id.is_hovered(cx));
1990                        let element_hovered = hitbox.is_hovered(cx);
1991                        if group_hovered || element_hovered {
1992                            *active_state.borrow_mut() = ElementClickedState {
1993                                group: group_hovered,
1994                                element: element_hovered,
1995                            };
1996                            cx.refresh();
1997                        }
1998                    }
1999                });
2000            }
2001        }
2002    }
2003
2004    fn paint_keyboard_listeners(&mut self, cx: &mut WindowContext) {
2005        let key_down_listeners = mem::take(&mut self.key_down_listeners);
2006        let key_up_listeners = mem::take(&mut self.key_up_listeners);
2007        let modifiers_changed_listeners = mem::take(&mut self.modifiers_changed_listeners);
2008        let action_listeners = mem::take(&mut self.action_listeners);
2009        if let Some(context) = self.key_context.clone() {
2010            cx.set_key_context(context);
2011        }
2012
2013        for listener in key_down_listeners {
2014            cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
2015                listener(event, phase, cx);
2016            })
2017        }
2018
2019        for listener in key_up_listeners {
2020            cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
2021                listener(event, phase, cx);
2022            })
2023        }
2024
2025        for listener in modifiers_changed_listeners {
2026            cx.on_modifiers_changed(move |event: &ModifiersChangedEvent, cx| {
2027                listener(event, cx);
2028            })
2029        }
2030
2031        for (action_type, listener) in action_listeners {
2032            cx.on_action(action_type, listener)
2033        }
2034    }
2035
2036    fn paint_hover_group_handler(&self, cx: &mut WindowContext) {
2037        let group_hitbox = self
2038            .group_hover_style
2039            .as_ref()
2040            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
2041
2042        if let Some(group_hitbox) = group_hitbox {
2043            let was_hovered = group_hitbox.is_hovered(cx);
2044            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
2045                let hovered = group_hitbox.is_hovered(cx);
2046                if phase == DispatchPhase::Capture && hovered != was_hovered {
2047                    cx.refresh();
2048                }
2049            });
2050        }
2051    }
2052
2053    fn paint_scroll_listener(&self, hitbox: &Hitbox, style: &Style, cx: &mut WindowContext) {
2054        if let Some(scroll_offset) = self.scroll_offset.clone() {
2055            let overflow = style.overflow;
2056            let allow_concurrent_scroll = style.allow_concurrent_scroll;
2057            let line_height = cx.line_height();
2058            let hitbox = hitbox.clone();
2059            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
2060                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
2061                    let mut scroll_offset = scroll_offset.borrow_mut();
2062                    let old_scroll_offset = *scroll_offset;
2063                    let delta = event.delta.pixel_delta(line_height);
2064
2065                    let mut delta_x = Pixels::ZERO;
2066                    if overflow.x == Overflow::Scroll {
2067                        if !delta.x.is_zero() {
2068                            delta_x = delta.x;
2069                        } else if overflow.y != Overflow::Scroll {
2070                            delta_x = delta.y;
2071                        }
2072                    }
2073                    let mut delta_y = Pixels::ZERO;
2074                    if overflow.y == Overflow::Scroll {
2075                        if !delta.y.is_zero() {
2076                            delta_y = delta.y;
2077                        } else if overflow.x != Overflow::Scroll {
2078                            delta_y = delta.x;
2079                        }
2080                    }
2081                    if !allow_concurrent_scroll && !delta_x.is_zero() && !delta_y.is_zero() {
2082                        if delta_x.abs() > delta_y.abs() {
2083                            delta_y = Pixels::ZERO;
2084                        } else {
2085                            delta_x = Pixels::ZERO;
2086                        }
2087                    }
2088                    scroll_offset.y += delta_y;
2089                    scroll_offset.x += delta_x;
2090                    cx.stop_propagation();
2091                    if *scroll_offset != old_scroll_offset {
2092                        cx.refresh();
2093                    }
2094                }
2095            });
2096        }
2097    }
2098
2099    /// Compute the visual style for this element, based on the current bounds and the element's state.
2100    pub fn compute_style(
2101        &self,
2102        global_id: Option<&GlobalElementId>,
2103        hitbox: Option<&Hitbox>,
2104        cx: &mut WindowContext,
2105    ) -> Style {
2106        cx.with_optional_element_state(global_id, |element_state, cx| {
2107            let mut element_state =
2108                element_state.map(|element_state| element_state.unwrap_or_default());
2109            let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
2110            (style, element_state)
2111        })
2112    }
2113
2114    /// Called from internal methods that have already called with_element_state.
2115    fn compute_style_internal(
2116        &self,
2117        hitbox: Option<&Hitbox>,
2118        element_state: Option<&mut InteractiveElementState>,
2119        cx: &mut WindowContext,
2120    ) -> Style {
2121        let mut style = Style::default();
2122        style.refine(&self.base_style);
2123
2124        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
2125            if let Some(in_focus_style) = self.in_focus_style.as_ref() {
2126                if focus_handle.within_focused(cx) {
2127                    style.refine(in_focus_style);
2128                }
2129            }
2130
2131            if let Some(focus_style) = self.focus_style.as_ref() {
2132                if focus_handle.is_focused(cx) {
2133                    style.refine(focus_style);
2134                }
2135            }
2136        }
2137
2138        if let Some(hitbox) = hitbox {
2139            if !cx.has_active_drag() {
2140                if let Some(group_hover) = self.group_hover_style.as_ref() {
2141                    if let Some(group_hitbox_id) =
2142                        GroupHitboxes::get(&group_hover.group, cx.deref_mut())
2143                    {
2144                        if group_hitbox_id.is_hovered(cx) {
2145                            style.refine(&group_hover.style);
2146                        }
2147                    }
2148                }
2149
2150                if let Some(hover_style) = self.hover_style.as_ref() {
2151                    if hitbox.is_hovered(cx) {
2152                        style.refine(hover_style);
2153                    }
2154                }
2155            }
2156
2157            if let Some(drag) = cx.active_drag.take() {
2158                let mut can_drop = true;
2159                if let Some(can_drop_predicate) = &self.can_drop_predicate {
2160                    can_drop = can_drop_predicate(drag.value.as_ref(), cx);
2161                }
2162
2163                if can_drop {
2164                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
2165                        if let Some(group_hitbox_id) =
2166                            GroupHitboxes::get(&group_drag_style.group, cx.deref_mut())
2167                        {
2168                            if *state_type == drag.value.as_ref().type_id()
2169                                && group_hitbox_id.is_hovered(cx)
2170                            {
2171                                style.refine(&group_drag_style.style);
2172                            }
2173                        }
2174                    }
2175
2176                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
2177                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(cx) {
2178                            style.refine(&build_drag_over_style(drag.value.as_ref(), cx));
2179                        }
2180                    }
2181                }
2182
2183                cx.active_drag = Some(drag);
2184            }
2185        }
2186
2187        if let Some(element_state) = element_state {
2188            let clicked_state = element_state
2189                .clicked_state
2190                .get_or_insert_with(Default::default)
2191                .borrow();
2192            if clicked_state.group {
2193                if let Some(group) = self.group_active_style.as_ref() {
2194                    style.refine(&group.style)
2195                }
2196            }
2197
2198            if let Some(active_style) = self.active_style.as_ref() {
2199                if clicked_state.element {
2200                    style.refine(active_style)
2201                }
2202            }
2203        }
2204
2205        style
2206    }
2207}
2208
2209/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
2210/// and scroll offsets.
2211#[derive(Default)]
2212pub struct InteractiveElementState {
2213    pub(crate) focus_handle: Option<FocusHandle>,
2214    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
2215    pub(crate) hover_state: Option<Rc<RefCell<bool>>>,
2216    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
2217    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
2218    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
2219}
2220
2221/// Whether or not the element or a group that contains it is clicked by the mouse.
2222#[derive(Copy, Clone, Default, Eq, PartialEq)]
2223pub struct ElementClickedState {
2224    /// True if this element's group has been clicked, false otherwise
2225    pub group: bool,
2226
2227    /// True if this element has been clicked, false otherwise
2228    pub element: bool,
2229}
2230
2231impl ElementClickedState {
2232    fn is_clicked(&self) -> bool {
2233        self.group || self.element
2234    }
2235}
2236
2237pub(crate) enum ActiveTooltip {
2238    /// Currently delaying before showing the tooltip.
2239    WaitingForShow { _task: Task<()> },
2240    /// Tooltip is visible, element was hovered or for hoverable tooltips, the tooltip was hovered.
2241    Visible {
2242        tooltip: AnyTooltip,
2243        is_hoverable: bool,
2244    },
2245    /// Tooltip is visible and hoverable, but the mouse is no longer hovering. Currently delaying
2246    /// before hiding it.
2247    WaitingForHide {
2248        tooltip: AnyTooltip,
2249        _task: Task<()>,
2250    },
2251}
2252
2253pub(crate) fn clear_active_tooltip(
2254    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2255    cx: &mut WindowContext,
2256) {
2257    match active_tooltip.borrow_mut().take() {
2258        None => {}
2259        Some(ActiveTooltip::WaitingForShow { .. }) => {}
2260        Some(ActiveTooltip::Visible { .. }) => cx.refresh(),
2261        Some(ActiveTooltip::WaitingForHide { .. }) => cx.refresh(),
2262    }
2263}
2264
2265pub(crate) fn clear_active_tooltip_if_not_hoverable(
2266    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2267    cx: &mut WindowContext,
2268) {
2269    let should_clear = match active_tooltip.borrow().as_ref() {
2270        None => false,
2271        Some(ActiveTooltip::WaitingForShow { .. }) => false,
2272        Some(ActiveTooltip::Visible { is_hoverable, .. }) => !is_hoverable,
2273        Some(ActiveTooltip::WaitingForHide { .. }) => false,
2274    };
2275    if should_clear {
2276        active_tooltip.borrow_mut().take();
2277        cx.refresh();
2278    }
2279}
2280
2281pub(crate) fn set_tooltip_on_window(
2282    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2283    cx: &mut WindowContext,
2284) -> Option<TooltipId> {
2285    let tooltip = match active_tooltip.borrow().as_ref() {
2286        None => return None,
2287        Some(ActiveTooltip::WaitingForShow { .. }) => return None,
2288        Some(ActiveTooltip::Visible { tooltip, .. }) => tooltip.clone(),
2289        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => tooltip.clone(),
2290    };
2291    Some(cx.set_tooltip(tooltip))
2292}
2293
2294pub(crate) fn register_tooltip_mouse_handlers(
2295    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2296    tooltip_id: Option<TooltipId>,
2297    build_tooltip: Rc<dyn Fn(&mut WindowContext) -> Option<(AnyView, bool)>>,
2298    check_is_hovered: Rc<dyn Fn(&WindowContext) -> bool>,
2299    cx: &mut WindowContext,
2300) {
2301    cx.on_mouse_event({
2302        let active_tooltip = active_tooltip.clone();
2303        let build_tooltip = build_tooltip.clone();
2304        let check_is_hovered = check_is_hovered.clone();
2305        move |_: &MouseMoveEvent, phase, cx| {
2306            handle_tooltip_mouse_move(
2307                &active_tooltip,
2308                &build_tooltip,
2309                &check_is_hovered,
2310                phase,
2311                cx,
2312            )
2313        }
2314    });
2315
2316    cx.on_mouse_event({
2317        let active_tooltip = active_tooltip.clone();
2318        move |_: &MouseDownEvent, _, cx| {
2319            if !tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx)) {
2320                clear_active_tooltip_if_not_hoverable(&active_tooltip, cx);
2321            }
2322        }
2323    });
2324
2325    cx.on_mouse_event({
2326        let active_tooltip = active_tooltip.clone();
2327        move |_: &ScrollWheelEvent, _, cx| {
2328            if !tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx)) {
2329                clear_active_tooltip_if_not_hoverable(&active_tooltip, cx);
2330            }
2331        }
2332    });
2333}
2334
2335fn handle_tooltip_mouse_move(
2336    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2337    build_tooltip: &Rc<dyn Fn(&mut WindowContext) -> Option<(AnyView, bool)>>,
2338    check_is_hovered: &Rc<dyn Fn(&WindowContext) -> bool>,
2339    phase: DispatchPhase,
2340    cx: &mut WindowContext,
2341) {
2342    // Separates logic for what mutation should occur from applying it, to avoid overlapping
2343    // RefCell borrows.
2344    enum Action {
2345        None,
2346        CancelShow,
2347        ScheduleShow,
2348    }
2349
2350    let action = match active_tooltip.borrow().as_ref() {
2351        None => {
2352            let is_hovered = check_is_hovered(cx);
2353            if is_hovered && phase.bubble() {
2354                Action::ScheduleShow
2355            } else {
2356                Action::None
2357            }
2358        }
2359        Some(ActiveTooltip::WaitingForShow { .. }) => {
2360            let is_hovered = check_is_hovered(cx);
2361            if is_hovered {
2362                Action::None
2363            } else {
2364                Action::CancelShow
2365            }
2366        }
2367        // These are handled in check_visible_and_update.
2368        Some(ActiveTooltip::Visible { .. }) | Some(ActiveTooltip::WaitingForHide { .. }) => {
2369            Action::None
2370        }
2371    };
2372
2373    match action {
2374        Action::None => {}
2375        Action::CancelShow => {
2376            // Cancel waiting to show tooltip when it is no longer hovered.
2377            active_tooltip.borrow_mut().take();
2378        }
2379        Action::ScheduleShow => {
2380            let delayed_show_task = cx.spawn({
2381                let active_tooltip = active_tooltip.clone();
2382                let build_tooltip = build_tooltip.clone();
2383                let check_is_hovered = check_is_hovered.clone();
2384                move |mut cx| async move {
2385                    cx.background_executor().timer(TOOLTIP_SHOW_DELAY).await;
2386                    cx.update(|cx| {
2387                        let new_tooltip = build_tooltip(cx).map(|(view, tooltip_is_hoverable)| {
2388                            let active_tooltip = active_tooltip.clone();
2389                            ActiveTooltip::Visible {
2390                                tooltip: AnyTooltip {
2391                                    view,
2392                                    mouse_position: cx.mouse_position(),
2393                                    check_visible_and_update: Rc::new(move |tooltip_bounds, cx| {
2394                                        handle_tooltip_check_visible_and_update(
2395                                            &active_tooltip,
2396                                            tooltip_is_hoverable,
2397                                            &check_is_hovered,
2398                                            tooltip_bounds,
2399                                            cx,
2400                                        )
2401                                    }),
2402                                },
2403                                is_hoverable: tooltip_is_hoverable,
2404                            }
2405                        });
2406                        *active_tooltip.borrow_mut() = new_tooltip;
2407                        cx.refresh();
2408                    })
2409                    .ok();
2410                }
2411            });
2412            active_tooltip
2413                .borrow_mut()
2414                .replace(ActiveTooltip::WaitingForShow {
2415                    _task: delayed_show_task,
2416                });
2417        }
2418    }
2419}
2420
2421/// Returns a callback which will be called by window prepaint to update tooltip visibility. The
2422/// purpose of doing this logic here instead of the mouse move handler is that the mouse move
2423/// handler won't get called when the element is not painted (e.g. via use of `visible_on_hover`).
2424fn handle_tooltip_check_visible_and_update(
2425    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2426    tooltip_is_hoverable: bool,
2427    check_is_hovered: &Rc<dyn Fn(&WindowContext) -> bool>,
2428    tooltip_bounds: Bounds<Pixels>,
2429    cx: &mut WindowContext,
2430) -> bool {
2431    // Separates logic for what mutation should occur from applying it, to avoid overlapping RefCell
2432    // borrows.
2433    enum Action {
2434        None,
2435        Hide,
2436        ScheduleHide(AnyTooltip),
2437        CancelHide(AnyTooltip),
2438    }
2439
2440    let is_hovered = check_is_hovered(cx)
2441        || (tooltip_is_hoverable && tooltip_bounds.contains(&cx.mouse_position()));
2442    let action = match active_tooltip.borrow().as_ref() {
2443        Some(ActiveTooltip::Visible { tooltip, .. }) => {
2444            if is_hovered {
2445                Action::None
2446            } else {
2447                if tooltip_is_hoverable {
2448                    Action::ScheduleHide(tooltip.clone())
2449                } else {
2450                    Action::Hide
2451                }
2452            }
2453        }
2454        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => {
2455            if is_hovered {
2456                Action::CancelHide(tooltip.clone())
2457            } else {
2458                Action::None
2459            }
2460        }
2461        None | Some(ActiveTooltip::WaitingForShow { .. }) => Action::None,
2462    };
2463
2464    match action {
2465        Action::None => {}
2466        Action::Hide => {
2467            clear_active_tooltip(&active_tooltip, cx);
2468        }
2469        Action::ScheduleHide(tooltip) => {
2470            let delayed_hide_task = cx.spawn({
2471                let active_tooltip = active_tooltip.clone();
2472                move |mut cx| async move {
2473                    cx.background_executor()
2474                        .timer(HOVERABLE_TOOLTIP_HIDE_DELAY)
2475                        .await;
2476                    if active_tooltip.borrow_mut().take().is_some() {
2477                        cx.update(|cx| cx.refresh()).ok();
2478                    }
2479                }
2480            });
2481            active_tooltip
2482                .borrow_mut()
2483                .replace(ActiveTooltip::WaitingForHide {
2484                    tooltip,
2485                    _task: delayed_hide_task,
2486                });
2487        }
2488        Action::CancelHide(tooltip) => {
2489            // Cancel waiting to hide tooltip when it becomes hovered.
2490            active_tooltip.borrow_mut().replace(ActiveTooltip::Visible {
2491                tooltip,
2492                is_hoverable: true,
2493            });
2494        }
2495    }
2496
2497    active_tooltip.borrow().is_some()
2498}
2499
2500#[derive(Default)]
2501pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
2502
2503impl Global for GroupHitboxes {}
2504
2505impl GroupHitboxes {
2506    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<HitboxId> {
2507        cx.default_global::<Self>()
2508            .0
2509            .get(name)
2510            .and_then(|bounds_stack| bounds_stack.last())
2511            .cloned()
2512    }
2513
2514    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut AppContext) {
2515        cx.default_global::<Self>()
2516            .0
2517            .entry(name)
2518            .or_default()
2519            .push(hitbox_id);
2520    }
2521
2522    pub fn pop(name: &SharedString, cx: &mut AppContext) {
2523        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
2524    }
2525}
2526
2527/// A wrapper around an element that can be focused.
2528pub struct Focusable<E> {
2529    /// The element that is focusable
2530    pub element: E,
2531}
2532
2533impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
2534
2535impl<E> InteractiveElement for Focusable<E>
2536where
2537    E: InteractiveElement,
2538{
2539    fn interactivity(&mut self) -> &mut Interactivity {
2540        self.element.interactivity()
2541    }
2542}
2543
2544impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
2545
2546impl<E> Styled for Focusable<E>
2547where
2548    E: Styled,
2549{
2550    fn style(&mut self) -> &mut StyleRefinement {
2551        self.element.style()
2552    }
2553}
2554
2555impl Focusable<Div> {
2556    /// Add a listener to be called when the children of this `Div` are prepainted.
2557    /// This allows you to store the [`Bounds`] of the children for later use.
2558    pub fn on_children_prepainted(
2559        mut self,
2560        listener: impl Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static,
2561    ) -> Self {
2562        self.element = self.element.on_children_prepainted(listener);
2563        self
2564    }
2565}
2566
2567impl<E> Element for Focusable<E>
2568where
2569    E: Element,
2570{
2571    type RequestLayoutState = E::RequestLayoutState;
2572    type PrepaintState = E::PrepaintState;
2573
2574    fn id(&self) -> Option<ElementId> {
2575        self.element.id()
2576    }
2577
2578    fn request_layout(
2579        &mut self,
2580        id: Option<&GlobalElementId>,
2581        cx: &mut WindowContext,
2582    ) -> (LayoutId, Self::RequestLayoutState) {
2583        self.element.request_layout(id, cx)
2584    }
2585
2586    fn prepaint(
2587        &mut self,
2588        id: Option<&GlobalElementId>,
2589        bounds: Bounds<Pixels>,
2590        state: &mut Self::RequestLayoutState,
2591        cx: &mut WindowContext,
2592    ) -> E::PrepaintState {
2593        self.element.prepaint(id, bounds, state, cx)
2594    }
2595
2596    fn paint(
2597        &mut self,
2598        id: Option<&GlobalElementId>,
2599        bounds: Bounds<Pixels>,
2600        request_layout: &mut Self::RequestLayoutState,
2601        prepaint: &mut Self::PrepaintState,
2602        cx: &mut WindowContext,
2603    ) {
2604        self.element.paint(id, bounds, request_layout, prepaint, cx)
2605    }
2606}
2607
2608impl<E> IntoElement for Focusable<E>
2609where
2610    E: IntoElement,
2611{
2612    type Element = E::Element;
2613
2614    fn into_element(self) -> Self::Element {
2615        self.element.into_element()
2616    }
2617}
2618
2619impl<E> ParentElement for Focusable<E>
2620where
2621    E: ParentElement,
2622{
2623    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
2624        self.element.extend(elements)
2625    }
2626}
2627
2628/// A wrapper around an element that can store state, produced after assigning an ElementId.
2629pub struct Stateful<E> {
2630    pub(crate) element: E,
2631}
2632
2633impl<E> Styled for Stateful<E>
2634where
2635    E: Styled,
2636{
2637    fn style(&mut self) -> &mut StyleRefinement {
2638        self.element.style()
2639    }
2640}
2641
2642impl<E> StatefulInteractiveElement for Stateful<E>
2643where
2644    E: Element,
2645    Self: InteractiveElement,
2646{
2647}
2648
2649impl<E> InteractiveElement for Stateful<E>
2650where
2651    E: InteractiveElement,
2652{
2653    fn interactivity(&mut self) -> &mut Interactivity {
2654        self.element.interactivity()
2655    }
2656}
2657
2658impl<E: FocusableElement> FocusableElement for Stateful<E> {}
2659
2660impl<E> Element for Stateful<E>
2661where
2662    E: Element,
2663{
2664    type RequestLayoutState = E::RequestLayoutState;
2665    type PrepaintState = E::PrepaintState;
2666
2667    fn id(&self) -> Option<ElementId> {
2668        self.element.id()
2669    }
2670
2671    fn request_layout(
2672        &mut self,
2673        id: Option<&GlobalElementId>,
2674        cx: &mut WindowContext,
2675    ) -> (LayoutId, Self::RequestLayoutState) {
2676        self.element.request_layout(id, cx)
2677    }
2678
2679    fn prepaint(
2680        &mut self,
2681        id: Option<&GlobalElementId>,
2682        bounds: Bounds<Pixels>,
2683        state: &mut Self::RequestLayoutState,
2684        cx: &mut WindowContext,
2685    ) -> E::PrepaintState {
2686        self.element.prepaint(id, bounds, state, cx)
2687    }
2688
2689    fn paint(
2690        &mut self,
2691        id: Option<&GlobalElementId>,
2692        bounds: Bounds<Pixels>,
2693        request_layout: &mut Self::RequestLayoutState,
2694        prepaint: &mut Self::PrepaintState,
2695        cx: &mut WindowContext,
2696    ) {
2697        self.element.paint(id, bounds, request_layout, prepaint, cx);
2698    }
2699}
2700
2701impl<E> IntoElement for Stateful<E>
2702where
2703    E: Element,
2704{
2705    type Element = Self;
2706
2707    fn into_element(self) -> Self::Element {
2708        self
2709    }
2710}
2711
2712impl<E> ParentElement for Stateful<E>
2713where
2714    E: ParentElement,
2715{
2716    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
2717        self.element.extend(elements)
2718    }
2719}
2720
2721/// Represents an element that can be scrolled *to* in its parent element.
2722///
2723/// Contrary to [ScrollHandle::scroll_to_item], an anchored element does not have to be an immediate child of the parent.
2724#[derive(Clone)]
2725pub struct ScrollAnchor {
2726    handle: ScrollHandle,
2727    last_origin: Rc<RefCell<Point<Pixels>>>,
2728}
2729
2730impl ScrollAnchor {
2731    /// Creates a [ScrollAnchor] associated with a given [ScrollHandle].
2732    pub fn for_handle(handle: ScrollHandle) -> Self {
2733        Self {
2734            handle,
2735            last_origin: Default::default(),
2736        }
2737    }
2738    /// Request scroll to this item on the next frame.
2739    pub fn scroll_to(&self, cx: &mut WindowContext) {
2740        let this = self.clone();
2741
2742        cx.on_next_frame(move |_| {
2743            let viewport_bounds = this.handle.bounds();
2744            let self_bounds = *this.last_origin.borrow();
2745            this.handle.set_offset(viewport_bounds.origin - self_bounds);
2746        });
2747    }
2748}
2749#[derive(Default, Debug)]
2750struct ScrollHandleState {
2751    offset: Rc<RefCell<Point<Pixels>>>,
2752    bounds: Bounds<Pixels>,
2753    child_bounds: Vec<Bounds<Pixels>>,
2754    requested_scroll_top: Option<(usize, Pixels)>,
2755    overflow: Point<Overflow>,
2756}
2757
2758/// A handle to the scrollable aspects of an element.
2759/// Used for accessing scroll state, like the current scroll offset,
2760/// and for mutating the scroll state, like scrolling to a specific child.
2761#[derive(Clone, Debug)]
2762pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
2763
2764impl Default for ScrollHandle {
2765    fn default() -> Self {
2766        Self::new()
2767    }
2768}
2769
2770impl ScrollHandle {
2771    /// Construct a new scroll handle.
2772    pub fn new() -> Self {
2773        Self(Rc::default())
2774    }
2775
2776    /// Get the current scroll offset.
2777    pub fn offset(&self) -> Point<Pixels> {
2778        *self.0.borrow().offset.borrow()
2779    }
2780
2781    /// Get the top child that's scrolled into view.
2782    pub fn top_item(&self) -> usize {
2783        let state = self.0.borrow();
2784        let top = state.bounds.top() - state.offset.borrow().y;
2785
2786        match state.child_bounds.binary_search_by(|bounds| {
2787            if top < bounds.top() {
2788                Ordering::Greater
2789            } else if top > bounds.bottom() {
2790                Ordering::Less
2791            } else {
2792                Ordering::Equal
2793            }
2794        }) {
2795            Ok(ix) => ix,
2796            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
2797        }
2798    }
2799
2800    /// Return the bounds into which this child is painted
2801    pub fn bounds(&self) -> Bounds<Pixels> {
2802        self.0.borrow().bounds
2803    }
2804
2805    /// Set the bounds into which this child is painted
2806    pub(super) fn set_bounds(&self, bounds: Bounds<Pixels>) {
2807        self.0.borrow_mut().bounds = bounds;
2808    }
2809
2810    /// Get the bounds for a specific child.
2811    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
2812        self.0.borrow().child_bounds.get(ix).cloned()
2813    }
2814
2815    /// scroll_to_item scrolls the minimal amount to ensure that the child is
2816    /// fully visible
2817    pub fn scroll_to_item(&self, ix: usize) {
2818        let state = self.0.borrow();
2819
2820        let Some(bounds) = state.child_bounds.get(ix) else {
2821            return;
2822        };
2823
2824        let mut scroll_offset = state.offset.borrow_mut();
2825
2826        if state.overflow.y == Overflow::Scroll {
2827            if bounds.top() + scroll_offset.y < state.bounds.top() {
2828                scroll_offset.y = state.bounds.top() - bounds.top();
2829            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
2830                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
2831            }
2832        }
2833
2834        if state.overflow.x == Overflow::Scroll {
2835            if bounds.left() + scroll_offset.x < state.bounds.left() {
2836                scroll_offset.x = state.bounds.left() - bounds.left();
2837            } else if bounds.right() + scroll_offset.x > state.bounds.right() {
2838                scroll_offset.x = state.bounds.right() - bounds.right();
2839            }
2840        }
2841    }
2842
2843    /// Set the offset explicitly. The offset is the distance from the top left of the
2844    /// parent container to the top left of the first child.
2845    /// As you scroll further down the offset becomes more negative.
2846    pub fn set_offset(&self, mut position: Point<Pixels>) {
2847        let state = self.0.borrow();
2848        *state.offset.borrow_mut() = position;
2849    }
2850
2851    /// Get the logical scroll top, based on a child index and a pixel offset.
2852    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
2853        let ix = self.top_item();
2854        let state = self.0.borrow();
2855
2856        if let Some(child_bounds) = state.child_bounds.get(ix) {
2857            (
2858                ix,
2859                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
2860            )
2861        } else {
2862            (ix, px(0.))
2863        }
2864    }
2865
2866    /// Set the logical scroll top, based on a child index and a pixel offset.
2867    pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
2868        self.0.borrow_mut().requested_scroll_top = Some((ix, px));
2869    }
2870
2871    /// Get the count of children for scrollable item.
2872    pub fn children_count(&self) -> usize {
2873        self.0.borrow().child_bounds.len()
2874    }
2875}