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
1215            for (ix, child_layout_id) in request_layout.child_layout_ids.iter().enumerate() {
1216                let child_bounds = cx.layout_bounds(*child_layout_id);
1217                child_min = child_min.min(&child_bounds.origin);
1218                child_max = child_max.max(&child_bounds.bottom_right());
1219                state.child_bounds.push(child_bounds);
1220
1221                if let Some(requested) = requested.as_ref() {
1222                    if requested.0 == ix {
1223                        *state.offset.borrow_mut() =
1224                            bounds.origin - (child_bounds.origin - point(px(0.), requested.1));
1225                    }
1226                }
1227            }
1228            (child_max - child_min).into()
1229        } else {
1230            for child_layout_id in &request_layout.child_layout_ids {
1231                let child_bounds = cx.layout_bounds(*child_layout_id);
1232                child_min = child_min.min(&child_bounds.origin);
1233                child_max = child_max.max(&child_bounds.bottom_right());
1234
1235                if has_prepaint_listener {
1236                    children_bounds.push(child_bounds);
1237                }
1238            }
1239            (child_max - child_min).into()
1240        };
1241
1242        self.interactivity.prepaint(
1243            global_id,
1244            bounds,
1245            content_size,
1246            cx,
1247            |_style, scroll_offset, hitbox, cx| {
1248                cx.with_element_offset(scroll_offset, |cx| {
1249                    for child in &mut self.children {
1250                        child.prepaint(cx);
1251                    }
1252                });
1253
1254                if let Some(listener) = self.prepaint_listener.as_ref() {
1255                    listener(children_bounds, cx);
1256                }
1257
1258                hitbox
1259            },
1260        )
1261    }
1262
1263    fn paint(
1264        &mut self,
1265        global_id: Option<&GlobalElementId>,
1266        bounds: Bounds<Pixels>,
1267        _request_layout: &mut Self::RequestLayoutState,
1268        hitbox: &mut Option<Hitbox>,
1269        cx: &mut WindowContext,
1270    ) {
1271        self.interactivity
1272            .paint(global_id, bounds, hitbox.as_ref(), cx, |_style, cx| {
1273                for child in &mut self.children {
1274                    child.paint(cx);
1275                }
1276            });
1277    }
1278}
1279
1280impl IntoElement for Div {
1281    type Element = Self;
1282
1283    fn into_element(self) -> Self::Element {
1284        self
1285    }
1286}
1287
1288/// The interactivity struct. Powers all of the general-purpose
1289/// interactivity in the `Div` element.
1290#[derive(Default)]
1291pub struct Interactivity {
1292    /// The element ID of the element. In id is required to support a stateful subset of the interactivity such as on_click.
1293    pub element_id: Option<ElementId>,
1294    /// Whether the element was clicked. This will only be present after layout.
1295    pub active: Option<bool>,
1296    /// Whether the element was hovered. This will only be present after paint if an hitbox
1297    /// was created for the interactive element.
1298    pub hovered: Option<bool>,
1299    pub(crate) tooltip_id: Option<TooltipId>,
1300    pub(crate) content_size: Size<Pixels>,
1301    pub(crate) key_context: Option<KeyContext>,
1302    pub(crate) focusable: bool,
1303    pub(crate) tracked_focus_handle: Option<FocusHandle>,
1304    pub(crate) tracked_scroll_handle: Option<ScrollHandle>,
1305    pub(crate) scroll_anchor: Option<ScrollAnchor>,
1306    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
1307    pub(crate) group: Option<SharedString>,
1308    /// The base style of the element, before any modifications are applied
1309    /// by focus, active, etc.
1310    pub base_style: Box<StyleRefinement>,
1311    pub(crate) focus_style: Option<Box<StyleRefinement>>,
1312    pub(crate) in_focus_style: Option<Box<StyleRefinement>>,
1313    pub(crate) hover_style: Option<Box<StyleRefinement>>,
1314    pub(crate) group_hover_style: Option<GroupStyle>,
1315    pub(crate) active_style: Option<Box<StyleRefinement>>,
1316    pub(crate) group_active_style: Option<GroupStyle>,
1317    pub(crate) drag_over_styles: Vec<(
1318        TypeId,
1319        Box<dyn Fn(&dyn Any, &mut WindowContext) -> StyleRefinement>,
1320    )>,
1321    pub(crate) group_drag_over_styles: Vec<(TypeId, GroupStyle)>,
1322    pub(crate) mouse_down_listeners: Vec<MouseDownListener>,
1323    pub(crate) mouse_up_listeners: Vec<MouseUpListener>,
1324    pub(crate) mouse_move_listeners: Vec<MouseMoveListener>,
1325    pub(crate) scroll_wheel_listeners: Vec<ScrollWheelListener>,
1326    pub(crate) key_down_listeners: Vec<KeyDownListener>,
1327    pub(crate) key_up_listeners: Vec<KeyUpListener>,
1328    pub(crate) modifiers_changed_listeners: Vec<ModifiersChangedListener>,
1329    pub(crate) action_listeners: Vec<(TypeId, ActionListener)>,
1330    pub(crate) drop_listeners: Vec<(TypeId, DropListener)>,
1331    pub(crate) can_drop_predicate: Option<CanDropPredicate>,
1332    pub(crate) click_listeners: Vec<ClickListener>,
1333    pub(crate) drag_listener: Option<(Arc<dyn Any>, DragListener)>,
1334    pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
1335    pub(crate) tooltip_builder: Option<TooltipBuilder>,
1336    pub(crate) occlude_mouse: bool,
1337
1338    #[cfg(debug_assertions)]
1339    pub(crate) location: Option<core::panic::Location<'static>>,
1340
1341    #[cfg(any(test, feature = "test-support"))]
1342    pub(crate) debug_selector: Option<String>,
1343}
1344
1345impl Interactivity {
1346    /// Layout this element according to this interactivity state's configured styles
1347    pub fn request_layout(
1348        &mut self,
1349        global_id: Option<&GlobalElementId>,
1350        cx: &mut WindowContext,
1351        f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
1352    ) -> LayoutId {
1353        cx.with_optional_element_state::<InteractiveElementState, _>(
1354            global_id,
1355            |element_state, cx| {
1356                let mut element_state =
1357                    element_state.map(|element_state| element_state.unwrap_or_default());
1358
1359                if let Some(element_state) = element_state.as_ref() {
1360                    if cx.has_active_drag() {
1361                        if let Some(pending_mouse_down) = element_state.pending_mouse_down.as_ref()
1362                        {
1363                            *pending_mouse_down.borrow_mut() = None;
1364                        }
1365                        if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1366                            *clicked_state.borrow_mut() = ElementClickedState::default();
1367                        }
1368                    }
1369                }
1370
1371                // Ensure we store a focus handle in our element state if we're focusable.
1372                // If there's an explicit focus handle we're tracking, use that. Otherwise
1373                // create a new handle and store it in the element state, which lives for as
1374                // as frames contain an element with this id.
1375                if self.focusable && self.tracked_focus_handle.is_none() {
1376                    if let Some(element_state) = element_state.as_mut() {
1377                        self.tracked_focus_handle = Some(
1378                            element_state
1379                                .focus_handle
1380                                .get_or_insert_with(|| cx.focus_handle())
1381                                .clone(),
1382                        );
1383                    }
1384                }
1385
1386                if let Some(scroll_handle) = self.tracked_scroll_handle.as_ref() {
1387                    self.scroll_offset = Some(scroll_handle.0.borrow().offset.clone());
1388                } else if self.base_style.overflow.x == Some(Overflow::Scroll)
1389                    || self.base_style.overflow.y == Some(Overflow::Scroll)
1390                {
1391                    if let Some(element_state) = element_state.as_mut() {
1392                        self.scroll_offset = Some(
1393                            element_state
1394                                .scroll_offset
1395                                .get_or_insert_with(Rc::default)
1396                                .clone(),
1397                        );
1398                    }
1399                }
1400
1401                let style = self.compute_style_internal(None, element_state.as_mut(), cx);
1402                let layout_id = f(style, cx);
1403                (layout_id, element_state)
1404            },
1405        )
1406    }
1407
1408    /// Commit the bounds of this element according to this interactivity state's configured styles.
1409    pub fn prepaint<R>(
1410        &mut self,
1411        global_id: Option<&GlobalElementId>,
1412        bounds: Bounds<Pixels>,
1413        content_size: Size<Pixels>,
1414        cx: &mut WindowContext,
1415        f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut WindowContext) -> R,
1416    ) -> R {
1417        self.content_size = content_size;
1418        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1419            cx.set_focus_handle(focus_handle);
1420        }
1421        cx.with_optional_element_state::<InteractiveElementState, _>(
1422            global_id,
1423            |element_state, cx| {
1424                let mut element_state =
1425                    element_state.map(|element_state| element_state.unwrap_or_default());
1426                let style = self.compute_style_internal(None, element_state.as_mut(), cx);
1427
1428                if let Some(element_state) = element_state.as_mut() {
1429                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1430                        let clicked_state = clicked_state.borrow();
1431                        self.active = Some(clicked_state.element);
1432                    }
1433                    if let Some(active_tooltip) = element_state.active_tooltip.as_ref() {
1434                        if self.tooltip_builder.is_some() {
1435                            self.tooltip_id = set_tooltip_on_window(active_tooltip, cx);
1436                        } else {
1437                            // If there is no longer a tooltip builder, remove the active tooltip.
1438                            element_state.active_tooltip.take();
1439                        }
1440                    }
1441                }
1442
1443                cx.with_text_style(style.text_style().cloned(), |cx| {
1444                    cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
1445                        let hitbox = if self.should_insert_hitbox(&style) {
1446                            Some(cx.insert_hitbox(bounds, self.occlude_mouse))
1447                        } else {
1448                            None
1449                        };
1450
1451                        let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
1452                        let result = f(&style, scroll_offset, hitbox, cx);
1453                        (result, element_state)
1454                    })
1455                })
1456            },
1457        )
1458    }
1459
1460    fn should_insert_hitbox(&self, style: &Style) -> bool {
1461        self.occlude_mouse
1462            || style.mouse_cursor.is_some()
1463            || self.group.is_some()
1464            || self.scroll_offset.is_some()
1465            || self.tracked_focus_handle.is_some()
1466            || self.hover_style.is_some()
1467            || self.group_hover_style.is_some()
1468            || !self.mouse_up_listeners.is_empty()
1469            || !self.mouse_down_listeners.is_empty()
1470            || !self.mouse_move_listeners.is_empty()
1471            || !self.click_listeners.is_empty()
1472            || !self.scroll_wheel_listeners.is_empty()
1473            || self.drag_listener.is_some()
1474            || !self.drop_listeners.is_empty()
1475            || self.tooltip_builder.is_some()
1476    }
1477
1478    fn clamp_scroll_position(
1479        &self,
1480        bounds: Bounds<Pixels>,
1481        style: &Style,
1482        cx: &mut WindowContext,
1483    ) -> Point<Pixels> {
1484        if let Some(scroll_offset) = self.scroll_offset.as_ref() {
1485            if let Some(scroll_handle) = &self.tracked_scroll_handle {
1486                scroll_handle.0.borrow_mut().overflow = style.overflow;
1487            }
1488
1489            let rem_size = cx.rem_size();
1490            let padding_size = size(
1491                style
1492                    .padding
1493                    .left
1494                    .to_pixels(bounds.size.width.into(), rem_size)
1495                    + style
1496                        .padding
1497                        .right
1498                        .to_pixels(bounds.size.width.into(), rem_size),
1499                style
1500                    .padding
1501                    .top
1502                    .to_pixels(bounds.size.height.into(), rem_size)
1503                    + style
1504                        .padding
1505                        .bottom
1506                        .to_pixels(bounds.size.height.into(), rem_size),
1507            );
1508            let scroll_max = (self.content_size + padding_size - bounds.size).max(&Size::default());
1509            // Clamp scroll offset in case scroll max is smaller now (e.g., if children
1510            // were removed or the bounds became larger).
1511            let mut scroll_offset = scroll_offset.borrow_mut();
1512            scroll_offset.x = scroll_offset.x.clamp(-scroll_max.width, px(0.));
1513            scroll_offset.y = scroll_offset.y.clamp(-scroll_max.height, px(0.));
1514            *scroll_offset
1515        } else {
1516            Point::default()
1517        }
1518    }
1519
1520    /// Paint this element according to this interactivity state's configured styles
1521    /// and bind the element's mouse and keyboard events.
1522    ///
1523    /// content_size is the size of the content of the element, which may be larger than the
1524    /// element's bounds if the element is scrollable.
1525    ///
1526    /// the final computed style will be passed to the provided function, along
1527    /// with the current scroll offset
1528    pub fn paint(
1529        &mut self,
1530        global_id: Option<&GlobalElementId>,
1531        bounds: Bounds<Pixels>,
1532        hitbox: Option<&Hitbox>,
1533        cx: &mut WindowContext,
1534        f: impl FnOnce(&Style, &mut WindowContext),
1535    ) {
1536        self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(cx));
1537        cx.with_optional_element_state::<InteractiveElementState, _>(
1538            global_id,
1539            |element_state, cx| {
1540                let mut element_state =
1541                    element_state.map(|element_state| element_state.unwrap_or_default());
1542
1543                let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
1544
1545                #[cfg(any(feature = "test-support", test))]
1546                if let Some(debug_selector) = &self.debug_selector {
1547                    cx.window
1548                        .next_frame
1549                        .debug_bounds
1550                        .insert(debug_selector.clone(), bounds);
1551                }
1552
1553                self.paint_hover_group_handler(cx);
1554
1555                if style.visibility == Visibility::Hidden {
1556                    return ((), element_state);
1557                }
1558
1559                cx.with_element_opacity(style.opacity, |cx| {
1560                    style.paint(bounds, cx, |cx: &mut WindowContext| {
1561                        cx.with_text_style(style.text_style().cloned(), |cx| {
1562                            cx.with_content_mask(
1563                                style.overflow_mask(bounds, cx.rem_size()),
1564                                |cx| {
1565                                    if let Some(hitbox) = hitbox {
1566                                        #[cfg(debug_assertions)]
1567                                        self.paint_debug_info(global_id, hitbox, &style, cx);
1568
1569                                        if !cx.has_active_drag() {
1570                                            if let Some(mouse_cursor) = style.mouse_cursor {
1571                                                cx.set_cursor_style(mouse_cursor, hitbox);
1572                                            }
1573                                        }
1574
1575                                        if let Some(group) = self.group.clone() {
1576                                            GroupHitboxes::push(group, hitbox.id, cx);
1577                                        }
1578
1579                                        self.paint_mouse_listeners(
1580                                            hitbox,
1581                                            element_state.as_mut(),
1582                                            cx,
1583                                        );
1584                                        self.paint_scroll_listener(hitbox, &style, cx);
1585                                    }
1586
1587                                    self.paint_keyboard_listeners(cx);
1588                                    f(&style, cx);
1589
1590                                    if hitbox.is_some() {
1591                                        if let Some(group) = self.group.as_ref() {
1592                                            GroupHitboxes::pop(group, cx);
1593                                        }
1594                                    }
1595                                },
1596                            );
1597                        });
1598                    });
1599                });
1600
1601                ((), element_state)
1602            },
1603        );
1604    }
1605
1606    #[cfg(debug_assertions)]
1607    fn paint_debug_info(
1608        &self,
1609        global_id: Option<&GlobalElementId>,
1610        hitbox: &Hitbox,
1611        style: &Style,
1612        cx: &mut WindowContext,
1613    ) {
1614        if global_id.is_some()
1615            && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
1616            && hitbox.is_hovered(cx)
1617        {
1618            const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
1619            let element_id = format!("{:?}", global_id.unwrap());
1620            let str_len = element_id.len();
1621
1622            let render_debug_text = |cx: &mut WindowContext| {
1623                if let Some(text) = cx
1624                    .text_system()
1625                    .shape_text(
1626                        element_id.into(),
1627                        FONT_SIZE,
1628                        &[cx.text_style().to_run(str_len)],
1629                        None,
1630                    )
1631                    .ok()
1632                    .and_then(|mut text| text.pop())
1633                {
1634                    text.paint(hitbox.origin, FONT_SIZE, cx).ok();
1635
1636                    let text_bounds = crate::Bounds {
1637                        origin: hitbox.origin,
1638                        size: text.size(FONT_SIZE),
1639                    };
1640                    if self.location.is_some()
1641                        && text_bounds.contains(&cx.mouse_position())
1642                        && cx.modifiers().secondary()
1643                    {
1644                        let secondary_held = cx.modifiers().secondary();
1645                        cx.on_key_event({
1646                            move |e: &crate::ModifiersChangedEvent, _phase, cx| {
1647                                if e.modifiers.secondary() != secondary_held
1648                                    && text_bounds.contains(&cx.mouse_position())
1649                                {
1650                                    cx.refresh();
1651                                }
1652                            }
1653                        });
1654
1655                        let was_hovered = hitbox.is_hovered(cx);
1656                        cx.on_mouse_event({
1657                            let hitbox = hitbox.clone();
1658                            move |_: &MouseMoveEvent, phase, cx| {
1659                                if phase == DispatchPhase::Capture {
1660                                    let hovered = hitbox.is_hovered(cx);
1661                                    if hovered != was_hovered {
1662                                        cx.refresh();
1663                                    }
1664                                }
1665                            }
1666                        });
1667
1668                        cx.on_mouse_event({
1669                            let hitbox = hitbox.clone();
1670                            let location = self.location.unwrap();
1671                            move |e: &crate::MouseDownEvent, phase, cx| {
1672                                if text_bounds.contains(&e.position)
1673                                    && phase.capture()
1674                                    && hitbox.is_hovered(cx)
1675                                {
1676                                    cx.stop_propagation();
1677                                    let Ok(dir) = std::env::current_dir() else {
1678                                        return;
1679                                    };
1680
1681                                    eprintln!(
1682                                        "This element was created at:\n{}:{}:{}",
1683                                        dir.join(location.file()).to_string_lossy(),
1684                                        location.line(),
1685                                        location.column()
1686                                    );
1687                                }
1688                            }
1689                        });
1690                        cx.paint_quad(crate::outline(
1691                            crate::Bounds {
1692                                origin: hitbox.origin
1693                                    + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
1694                                size: crate::Size {
1695                                    width: text_bounds.size.width,
1696                                    height: crate::px(1.),
1697                                },
1698                            },
1699                            crate::red(),
1700                        ))
1701                    }
1702                }
1703            };
1704
1705            cx.with_text_style(
1706                Some(crate::TextStyleRefinement {
1707                    color: Some(crate::red()),
1708                    line_height: Some(FONT_SIZE.into()),
1709                    background_color: Some(crate::white()),
1710                    ..Default::default()
1711                }),
1712                render_debug_text,
1713            )
1714        }
1715    }
1716
1717    fn paint_mouse_listeners(
1718        &mut self,
1719        hitbox: &Hitbox,
1720        element_state: Option<&mut InteractiveElementState>,
1721        cx: &mut WindowContext,
1722    ) {
1723        // If this element can be focused, register a mouse down listener
1724        // that will automatically transfer focus when hitting the element.
1725        // This behavior can be suppressed by using `cx.prevent_default()`.
1726        if let Some(focus_handle) = self.tracked_focus_handle.clone() {
1727            let hitbox = hitbox.clone();
1728            cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1729                if phase == DispatchPhase::Bubble
1730                    && hitbox.is_hovered(cx)
1731                    && !cx.default_prevented()
1732                {
1733                    cx.focus(&focus_handle);
1734                    // If there is a parent that is also focusable, prevent it
1735                    // from transferring focus because we already did so.
1736                    cx.prevent_default();
1737                }
1738            });
1739        }
1740
1741        for listener in self.mouse_down_listeners.drain(..) {
1742            let hitbox = hitbox.clone();
1743            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
1744                listener(event, phase, &hitbox, cx);
1745            })
1746        }
1747
1748        for listener in self.mouse_up_listeners.drain(..) {
1749            let hitbox = hitbox.clone();
1750            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
1751                listener(event, phase, &hitbox, cx);
1752            })
1753        }
1754
1755        for listener in self.mouse_move_listeners.drain(..) {
1756            let hitbox = hitbox.clone();
1757            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1758                listener(event, phase, &hitbox, cx);
1759            })
1760        }
1761
1762        for listener in self.scroll_wheel_listeners.drain(..) {
1763            let hitbox = hitbox.clone();
1764            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1765                listener(event, phase, &hitbox, cx);
1766            })
1767        }
1768
1769        if self.hover_style.is_some()
1770            || self.base_style.mouse_cursor.is_some()
1771            || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
1772        {
1773            let hitbox = hitbox.clone();
1774            let was_hovered = hitbox.is_hovered(cx);
1775            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1776                let hovered = hitbox.is_hovered(cx);
1777                if phase == DispatchPhase::Capture && hovered != was_hovered {
1778                    cx.refresh();
1779                }
1780            });
1781        }
1782
1783        let mut drag_listener = mem::take(&mut self.drag_listener);
1784        let drop_listeners = mem::take(&mut self.drop_listeners);
1785        let click_listeners = mem::take(&mut self.click_listeners);
1786        let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
1787
1788        if !drop_listeners.is_empty() {
1789            let hitbox = hitbox.clone();
1790            cx.on_mouse_event({
1791                move |_: &MouseUpEvent, phase, cx| {
1792                    if let Some(drag) = &cx.active_drag {
1793                        if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
1794                            let drag_state_type = drag.value.as_ref().type_id();
1795                            for (drop_state_type, listener) in &drop_listeners {
1796                                if *drop_state_type == drag_state_type {
1797                                    let drag = cx
1798                                        .active_drag
1799                                        .take()
1800                                        .expect("checked for type drag state type above");
1801
1802                                    let mut can_drop = true;
1803                                    if let Some(predicate) = &can_drop_predicate {
1804                                        can_drop = predicate(drag.value.as_ref(), cx);
1805                                    }
1806
1807                                    if can_drop {
1808                                        listener(drag.value.as_ref(), cx);
1809                                        cx.refresh();
1810                                        cx.stop_propagation();
1811                                    }
1812                                }
1813                            }
1814                        }
1815                    }
1816                }
1817            });
1818        }
1819
1820        if let Some(element_state) = element_state {
1821            if !click_listeners.is_empty() || drag_listener.is_some() {
1822                let pending_mouse_down = element_state
1823                    .pending_mouse_down
1824                    .get_or_insert_with(Default::default)
1825                    .clone();
1826
1827                let clicked_state = element_state
1828                    .clicked_state
1829                    .get_or_insert_with(Default::default)
1830                    .clone();
1831
1832                cx.on_mouse_event({
1833                    let pending_mouse_down = pending_mouse_down.clone();
1834                    let hitbox = hitbox.clone();
1835                    move |event: &MouseDownEvent, phase, cx| {
1836                        if phase == DispatchPhase::Bubble
1837                            && event.button == MouseButton::Left
1838                            && hitbox.is_hovered(cx)
1839                        {
1840                            *pending_mouse_down.borrow_mut() = Some(event.clone());
1841                            cx.refresh();
1842                        }
1843                    }
1844                });
1845
1846                cx.on_mouse_event({
1847                    let pending_mouse_down = pending_mouse_down.clone();
1848                    let hitbox = hitbox.clone();
1849                    move |event: &MouseMoveEvent, phase, cx| {
1850                        if phase == DispatchPhase::Capture {
1851                            return;
1852                        }
1853
1854                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1855                        if let Some(mouse_down) = pending_mouse_down.clone() {
1856                            if !cx.has_active_drag()
1857                                && (event.position - mouse_down.position).magnitude()
1858                                    > DRAG_THRESHOLD
1859                            {
1860                                if let Some((drag_value, drag_listener)) = drag_listener.take() {
1861                                    *clicked_state.borrow_mut() = ElementClickedState::default();
1862                                    let cursor_offset = event.position - hitbox.origin;
1863                                    let drag =
1864                                        (drag_listener)(drag_value.as_ref(), cursor_offset, cx);
1865                                    cx.active_drag = Some(AnyDrag {
1866                                        view: drag,
1867                                        value: drag_value,
1868                                        cursor_offset,
1869                                    });
1870                                    pending_mouse_down.take();
1871                                    cx.refresh();
1872                                    cx.stop_propagation();
1873                                }
1874                            }
1875                        }
1876                    }
1877                });
1878
1879                cx.on_mouse_event({
1880                    let mut captured_mouse_down = None;
1881                    let hitbox = hitbox.clone();
1882                    move |event: &MouseUpEvent, phase, cx| match phase {
1883                        // Clear the pending mouse down during the capture phase,
1884                        // so that it happens even if another event handler stops
1885                        // propagation.
1886                        DispatchPhase::Capture => {
1887                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1888                            if pending_mouse_down.is_some() && hitbox.is_hovered(cx) {
1889                                captured_mouse_down = pending_mouse_down.take();
1890                                cx.refresh();
1891                            }
1892                        }
1893                        // Fire click handlers during the bubble phase.
1894                        DispatchPhase::Bubble => {
1895                            if let Some(mouse_down) = captured_mouse_down.take() {
1896                                let mouse_click = ClickEvent {
1897                                    down: mouse_down,
1898                                    up: event.clone(),
1899                                };
1900                                for listener in &click_listeners {
1901                                    listener(&mouse_click, cx);
1902                                }
1903                            }
1904                        }
1905                    }
1906                });
1907            }
1908
1909            if let Some(hover_listener) = self.hover_listener.take() {
1910                let hitbox = hitbox.clone();
1911                let was_hovered = element_state
1912                    .hover_state
1913                    .get_or_insert_with(Default::default)
1914                    .clone();
1915                let has_mouse_down = element_state
1916                    .pending_mouse_down
1917                    .get_or_insert_with(Default::default)
1918                    .clone();
1919
1920                cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
1921                    if phase != DispatchPhase::Bubble {
1922                        return;
1923                    }
1924                    let is_hovered = has_mouse_down.borrow().is_none()
1925                        && !cx.has_active_drag()
1926                        && hitbox.is_hovered(cx);
1927                    let mut was_hovered = was_hovered.borrow_mut();
1928
1929                    if is_hovered != *was_hovered {
1930                        *was_hovered = is_hovered;
1931                        drop(was_hovered);
1932
1933                        hover_listener(&is_hovered, cx);
1934                    }
1935                });
1936            }
1937
1938            if let Some(tooltip_builder) = self.tooltip_builder.take() {
1939                let active_tooltip = element_state
1940                    .active_tooltip
1941                    .get_or_insert_with(Default::default)
1942                    .clone();
1943                let pending_mouse_down = element_state
1944                    .pending_mouse_down
1945                    .get_or_insert_with(Default::default)
1946                    .clone();
1947
1948                let tooltip_is_hoverable = tooltip_builder.hoverable;
1949                let build_tooltip = Rc::new(move |cx: &mut WindowContext| {
1950                    Some(((tooltip_builder.build)(cx), tooltip_is_hoverable))
1951                });
1952                // Use bounds instead of testing hitbox since check_is_hovered is also called
1953                // during prepaint.
1954                let source_bounds = hitbox.bounds;
1955                let check_is_hovered = Rc::new(move |cx: &WindowContext| {
1956                    pending_mouse_down.borrow().is_none()
1957                        && source_bounds.contains(&cx.mouse_position())
1958                });
1959                register_tooltip_mouse_handlers(
1960                    &active_tooltip,
1961                    self.tooltip_id,
1962                    build_tooltip,
1963                    check_is_hovered,
1964                    cx,
1965                );
1966            }
1967
1968            let active_state = element_state
1969                .clicked_state
1970                .get_or_insert_with(Default::default)
1971                .clone();
1972            if active_state.borrow().is_clicked() {
1973                cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
1974                    if phase == DispatchPhase::Capture {
1975                        *active_state.borrow_mut() = ElementClickedState::default();
1976                        cx.refresh();
1977                    }
1978                });
1979            } else {
1980                let active_group_hitbox = self
1981                    .group_active_style
1982                    .as_ref()
1983                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
1984                let hitbox = hitbox.clone();
1985                cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
1986                    if phase == DispatchPhase::Bubble && !cx.default_prevented() {
1987                        let group_hovered = active_group_hitbox
1988                            .map_or(false, |group_hitbox_id| group_hitbox_id.is_hovered(cx));
1989                        let element_hovered = hitbox.is_hovered(cx);
1990                        if group_hovered || element_hovered {
1991                            *active_state.borrow_mut() = ElementClickedState {
1992                                group: group_hovered,
1993                                element: element_hovered,
1994                            };
1995                            cx.refresh();
1996                        }
1997                    }
1998                });
1999            }
2000        }
2001    }
2002
2003    fn paint_keyboard_listeners(&mut self, cx: &mut WindowContext) {
2004        let key_down_listeners = mem::take(&mut self.key_down_listeners);
2005        let key_up_listeners = mem::take(&mut self.key_up_listeners);
2006        let modifiers_changed_listeners = mem::take(&mut self.modifiers_changed_listeners);
2007        let action_listeners = mem::take(&mut self.action_listeners);
2008        if let Some(context) = self.key_context.clone() {
2009            cx.set_key_context(context);
2010        }
2011
2012        for listener in key_down_listeners {
2013            cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
2014                listener(event, phase, cx);
2015            })
2016        }
2017
2018        for listener in key_up_listeners {
2019            cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
2020                listener(event, phase, cx);
2021            })
2022        }
2023
2024        for listener in modifiers_changed_listeners {
2025            cx.on_modifiers_changed(move |event: &ModifiersChangedEvent, cx| {
2026                listener(event, cx);
2027            })
2028        }
2029
2030        for (action_type, listener) in action_listeners {
2031            cx.on_action(action_type, listener)
2032        }
2033    }
2034
2035    fn paint_hover_group_handler(&self, cx: &mut WindowContext) {
2036        let group_hitbox = self
2037            .group_hover_style
2038            .as_ref()
2039            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
2040
2041        if let Some(group_hitbox) = group_hitbox {
2042            let was_hovered = group_hitbox.is_hovered(cx);
2043            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
2044                let hovered = group_hitbox.is_hovered(cx);
2045                if phase == DispatchPhase::Capture && hovered != was_hovered {
2046                    cx.refresh();
2047                }
2048            });
2049        }
2050    }
2051
2052    fn paint_scroll_listener(&self, hitbox: &Hitbox, style: &Style, cx: &mut WindowContext) {
2053        if let Some(scroll_offset) = self.scroll_offset.clone() {
2054            let overflow = style.overflow;
2055            let allow_concurrent_scroll = style.allow_concurrent_scroll;
2056            let line_height = cx.line_height();
2057            let hitbox = hitbox.clone();
2058            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
2059                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
2060                    let mut scroll_offset = scroll_offset.borrow_mut();
2061                    let old_scroll_offset = *scroll_offset;
2062                    let delta = event.delta.pixel_delta(line_height);
2063
2064                    let mut delta_x = Pixels::ZERO;
2065                    if overflow.x == Overflow::Scroll {
2066                        if !delta.x.is_zero() {
2067                            delta_x = delta.x;
2068                        } else if overflow.y != Overflow::Scroll {
2069                            delta_x = delta.y;
2070                        }
2071                    }
2072                    let mut delta_y = Pixels::ZERO;
2073                    if overflow.y == Overflow::Scroll {
2074                        if !delta.y.is_zero() {
2075                            delta_y = delta.y;
2076                        } else if overflow.x != Overflow::Scroll {
2077                            delta_y = delta.x;
2078                        }
2079                    }
2080                    if !allow_concurrent_scroll && !delta_x.is_zero() && !delta_y.is_zero() {
2081                        if delta_x.abs() > delta_y.abs() {
2082                            delta_y = Pixels::ZERO;
2083                        } else {
2084                            delta_x = Pixels::ZERO;
2085                        }
2086                    }
2087                    scroll_offset.y += delta_y;
2088                    scroll_offset.x += delta_x;
2089                    cx.stop_propagation();
2090                    if *scroll_offset != old_scroll_offset {
2091                        cx.refresh();
2092                    }
2093                }
2094            });
2095        }
2096    }
2097
2098    /// Compute the visual style for this element, based on the current bounds and the element's state.
2099    pub fn compute_style(
2100        &self,
2101        global_id: Option<&GlobalElementId>,
2102        hitbox: Option<&Hitbox>,
2103        cx: &mut WindowContext,
2104    ) -> Style {
2105        cx.with_optional_element_state(global_id, |element_state, cx| {
2106            let mut element_state =
2107                element_state.map(|element_state| element_state.unwrap_or_default());
2108            let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
2109            (style, element_state)
2110        })
2111    }
2112
2113    /// Called from internal methods that have already called with_element_state.
2114    fn compute_style_internal(
2115        &self,
2116        hitbox: Option<&Hitbox>,
2117        element_state: Option<&mut InteractiveElementState>,
2118        cx: &mut WindowContext,
2119    ) -> Style {
2120        let mut style = Style::default();
2121        style.refine(&self.base_style);
2122
2123        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
2124            if let Some(in_focus_style) = self.in_focus_style.as_ref() {
2125                if focus_handle.within_focused(cx) {
2126                    style.refine(in_focus_style);
2127                }
2128            }
2129
2130            if let Some(focus_style) = self.focus_style.as_ref() {
2131                if focus_handle.is_focused(cx) {
2132                    style.refine(focus_style);
2133                }
2134            }
2135        }
2136
2137        if let Some(hitbox) = hitbox {
2138            if !cx.has_active_drag() {
2139                if let Some(group_hover) = self.group_hover_style.as_ref() {
2140                    if let Some(group_hitbox_id) =
2141                        GroupHitboxes::get(&group_hover.group, cx.deref_mut())
2142                    {
2143                        if group_hitbox_id.is_hovered(cx) {
2144                            style.refine(&group_hover.style);
2145                        }
2146                    }
2147                }
2148
2149                if let Some(hover_style) = self.hover_style.as_ref() {
2150                    if hitbox.is_hovered(cx) {
2151                        style.refine(hover_style);
2152                    }
2153                }
2154            }
2155
2156            if let Some(drag) = cx.active_drag.take() {
2157                let mut can_drop = true;
2158                if let Some(can_drop_predicate) = &self.can_drop_predicate {
2159                    can_drop = can_drop_predicate(drag.value.as_ref(), cx);
2160                }
2161
2162                if can_drop {
2163                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
2164                        if let Some(group_hitbox_id) =
2165                            GroupHitboxes::get(&group_drag_style.group, cx.deref_mut())
2166                        {
2167                            if *state_type == drag.value.as_ref().type_id()
2168                                && group_hitbox_id.is_hovered(cx)
2169                            {
2170                                style.refine(&group_drag_style.style);
2171                            }
2172                        }
2173                    }
2174
2175                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
2176                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(cx) {
2177                            style.refine(&build_drag_over_style(drag.value.as_ref(), cx));
2178                        }
2179                    }
2180                }
2181
2182                cx.active_drag = Some(drag);
2183            }
2184        }
2185
2186        if let Some(element_state) = element_state {
2187            let clicked_state = element_state
2188                .clicked_state
2189                .get_or_insert_with(Default::default)
2190                .borrow();
2191            if clicked_state.group {
2192                if let Some(group) = self.group_active_style.as_ref() {
2193                    style.refine(&group.style)
2194                }
2195            }
2196
2197            if let Some(active_style) = self.active_style.as_ref() {
2198                if clicked_state.element {
2199                    style.refine(active_style)
2200                }
2201            }
2202        }
2203
2204        style
2205    }
2206}
2207
2208/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
2209/// and scroll offsets.
2210#[derive(Default)]
2211pub struct InteractiveElementState {
2212    pub(crate) focus_handle: Option<FocusHandle>,
2213    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
2214    pub(crate) hover_state: Option<Rc<RefCell<bool>>>,
2215    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
2216    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
2217    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
2218}
2219
2220/// Whether or not the element or a group that contains it is clicked by the mouse.
2221#[derive(Copy, Clone, Default, Eq, PartialEq)]
2222pub struct ElementClickedState {
2223    /// True if this element's group has been clicked, false otherwise
2224    pub group: bool,
2225
2226    /// True if this element has been clicked, false otherwise
2227    pub element: bool,
2228}
2229
2230impl ElementClickedState {
2231    fn is_clicked(&self) -> bool {
2232        self.group || self.element
2233    }
2234}
2235
2236pub(crate) enum ActiveTooltip {
2237    /// Currently delaying before showing the tooltip.
2238    WaitingForShow { _task: Task<()> },
2239    /// Tooltip is visible, element was hovered or for hoverable tooltips, the tooltip was hovered.
2240    Visible {
2241        tooltip: AnyTooltip,
2242        is_hoverable: bool,
2243    },
2244    /// Tooltip is visible and hoverable, but the mouse is no longer hovering. Currently delaying
2245    /// before hiding it.
2246    WaitingForHide {
2247        tooltip: AnyTooltip,
2248        _task: Task<()>,
2249    },
2250}
2251
2252pub(crate) fn clear_active_tooltip(
2253    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2254    cx: &mut WindowContext,
2255) {
2256    match active_tooltip.borrow_mut().take() {
2257        None => {}
2258        Some(ActiveTooltip::WaitingForShow { .. }) => {}
2259        Some(ActiveTooltip::Visible { .. }) => cx.refresh(),
2260        Some(ActiveTooltip::WaitingForHide { .. }) => cx.refresh(),
2261    }
2262}
2263
2264pub(crate) fn clear_active_tooltip_if_not_hoverable(
2265    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2266    cx: &mut WindowContext,
2267) {
2268    let should_clear = match active_tooltip.borrow().as_ref() {
2269        None => false,
2270        Some(ActiveTooltip::WaitingForShow { .. }) => false,
2271        Some(ActiveTooltip::Visible { is_hoverable, .. }) => !is_hoverable,
2272        Some(ActiveTooltip::WaitingForHide { .. }) => false,
2273    };
2274    if should_clear {
2275        active_tooltip.borrow_mut().take();
2276        cx.refresh();
2277    }
2278}
2279
2280pub(crate) fn set_tooltip_on_window(
2281    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2282    cx: &mut WindowContext,
2283) -> Option<TooltipId> {
2284    let tooltip = match active_tooltip.borrow().as_ref() {
2285        None => return None,
2286        Some(ActiveTooltip::WaitingForShow { .. }) => return None,
2287        Some(ActiveTooltip::Visible { tooltip, .. }) => tooltip.clone(),
2288        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => tooltip.clone(),
2289    };
2290    Some(cx.set_tooltip(tooltip))
2291}
2292
2293pub(crate) fn register_tooltip_mouse_handlers(
2294    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2295    tooltip_id: Option<TooltipId>,
2296    build_tooltip: Rc<dyn Fn(&mut WindowContext) -> Option<(AnyView, bool)>>,
2297    check_is_hovered: Rc<dyn Fn(&WindowContext) -> bool>,
2298    cx: &mut WindowContext,
2299) {
2300    cx.on_mouse_event({
2301        let active_tooltip = active_tooltip.clone();
2302        let build_tooltip = build_tooltip.clone();
2303        let check_is_hovered = check_is_hovered.clone();
2304        move |_: &MouseMoveEvent, phase, cx| {
2305            handle_tooltip_mouse_move(
2306                &active_tooltip,
2307                &build_tooltip,
2308                &check_is_hovered,
2309                phase,
2310                cx,
2311            )
2312        }
2313    });
2314
2315    cx.on_mouse_event({
2316        let active_tooltip = active_tooltip.clone();
2317        move |_: &MouseDownEvent, _, cx| {
2318            if !tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx)) {
2319                clear_active_tooltip_if_not_hoverable(&active_tooltip, cx);
2320            }
2321        }
2322    });
2323
2324    cx.on_mouse_event({
2325        let active_tooltip = active_tooltip.clone();
2326        move |_: &ScrollWheelEvent, _, cx| {
2327            if !tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx)) {
2328                clear_active_tooltip_if_not_hoverable(&active_tooltip, cx);
2329            }
2330        }
2331    });
2332}
2333
2334fn handle_tooltip_mouse_move(
2335    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2336    build_tooltip: &Rc<dyn Fn(&mut WindowContext) -> Option<(AnyView, bool)>>,
2337    check_is_hovered: &Rc<dyn Fn(&WindowContext) -> bool>,
2338    phase: DispatchPhase,
2339    cx: &mut WindowContext,
2340) {
2341    // Separates logic for what mutation should occur from applying it, to avoid overlapping
2342    // RefCell borrows.
2343    enum Action {
2344        None,
2345        CancelShow,
2346        ScheduleShow,
2347    }
2348
2349    let action = match active_tooltip.borrow().as_ref() {
2350        None => {
2351            let is_hovered = check_is_hovered(cx);
2352            if is_hovered && phase.bubble() {
2353                Action::ScheduleShow
2354            } else {
2355                Action::None
2356            }
2357        }
2358        Some(ActiveTooltip::WaitingForShow { .. }) => {
2359            let is_hovered = check_is_hovered(cx);
2360            if is_hovered {
2361                Action::None
2362            } else {
2363                Action::CancelShow
2364            }
2365        }
2366        // These are handled in check_visible_and_update.
2367        Some(ActiveTooltip::Visible { .. }) | Some(ActiveTooltip::WaitingForHide { .. }) => {
2368            Action::None
2369        }
2370    };
2371
2372    match action {
2373        Action::None => {}
2374        Action::CancelShow => {
2375            // Cancel waiting to show tooltip when it is no longer hovered.
2376            active_tooltip.borrow_mut().take();
2377        }
2378        Action::ScheduleShow => {
2379            let delayed_show_task = cx.spawn({
2380                let active_tooltip = active_tooltip.clone();
2381                let build_tooltip = build_tooltip.clone();
2382                let check_is_hovered = check_is_hovered.clone();
2383                move |mut cx| async move {
2384                    cx.background_executor().timer(TOOLTIP_SHOW_DELAY).await;
2385                    cx.update(|cx| {
2386                        let new_tooltip = build_tooltip(cx).map(|(view, tooltip_is_hoverable)| {
2387                            let active_tooltip = active_tooltip.clone();
2388                            ActiveTooltip::Visible {
2389                                tooltip: AnyTooltip {
2390                                    view,
2391                                    mouse_position: cx.mouse_position(),
2392                                    check_visible_and_update: Rc::new(move |tooltip_bounds, cx| {
2393                                        handle_tooltip_check_visible_and_update(
2394                                            &active_tooltip,
2395                                            tooltip_is_hoverable,
2396                                            &check_is_hovered,
2397                                            tooltip_bounds,
2398                                            cx,
2399                                        )
2400                                    }),
2401                                },
2402                                is_hoverable: tooltip_is_hoverable,
2403                            }
2404                        });
2405                        *active_tooltip.borrow_mut() = new_tooltip;
2406                        cx.refresh();
2407                    })
2408                    .ok();
2409                }
2410            });
2411            active_tooltip
2412                .borrow_mut()
2413                .replace(ActiveTooltip::WaitingForShow {
2414                    _task: delayed_show_task,
2415                });
2416        }
2417    }
2418}
2419
2420/// Returns a callback which will be called by window prepaint to update tooltip visibility. The
2421/// purpose of doing this logic here instead of the mouse move handler is that the mouse move
2422/// handler won't get called when the element is not painted (e.g. via use of `visible_on_hover`).
2423fn handle_tooltip_check_visible_and_update(
2424    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
2425    tooltip_is_hoverable: bool,
2426    check_is_hovered: &Rc<dyn Fn(&WindowContext) -> bool>,
2427    tooltip_bounds: Bounds<Pixels>,
2428    cx: &mut WindowContext,
2429) -> bool {
2430    // Separates logic for what mutation should occur from applying it, to avoid overlapping RefCell
2431    // borrows.
2432    enum Action {
2433        None,
2434        Hide,
2435        ScheduleHide(AnyTooltip),
2436        CancelHide(AnyTooltip),
2437    }
2438
2439    let is_hovered = check_is_hovered(cx)
2440        || (tooltip_is_hoverable && tooltip_bounds.contains(&cx.mouse_position()));
2441    let action = match active_tooltip.borrow().as_ref() {
2442        Some(ActiveTooltip::Visible { tooltip, .. }) => {
2443            if is_hovered {
2444                Action::None
2445            } else {
2446                if tooltip_is_hoverable {
2447                    Action::ScheduleHide(tooltip.clone())
2448                } else {
2449                    Action::Hide
2450                }
2451            }
2452        }
2453        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => {
2454            if is_hovered {
2455                Action::CancelHide(tooltip.clone())
2456            } else {
2457                Action::None
2458            }
2459        }
2460        None | Some(ActiveTooltip::WaitingForShow { .. }) => Action::None,
2461    };
2462
2463    match action {
2464        Action::None => {}
2465        Action::Hide => {
2466            clear_active_tooltip(&active_tooltip, cx);
2467        }
2468        Action::ScheduleHide(tooltip) => {
2469            let delayed_hide_task = cx.spawn({
2470                let active_tooltip = active_tooltip.clone();
2471                move |mut cx| async move {
2472                    cx.background_executor()
2473                        .timer(HOVERABLE_TOOLTIP_HIDE_DELAY)
2474                        .await;
2475                    if active_tooltip.borrow_mut().take().is_some() {
2476                        cx.update(|cx| cx.refresh()).ok();
2477                    }
2478                }
2479            });
2480            active_tooltip
2481                .borrow_mut()
2482                .replace(ActiveTooltip::WaitingForHide {
2483                    tooltip,
2484                    _task: delayed_hide_task,
2485                });
2486        }
2487        Action::CancelHide(tooltip) => {
2488            // Cancel waiting to hide tooltip when it becomes hovered.
2489            active_tooltip.borrow_mut().replace(ActiveTooltip::Visible {
2490                tooltip,
2491                is_hoverable: true,
2492            });
2493        }
2494    }
2495
2496    active_tooltip.borrow().is_some()
2497}
2498
2499#[derive(Default)]
2500pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
2501
2502impl Global for GroupHitboxes {}
2503
2504impl GroupHitboxes {
2505    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<HitboxId> {
2506        cx.default_global::<Self>()
2507            .0
2508            .get(name)
2509            .and_then(|bounds_stack| bounds_stack.last())
2510            .cloned()
2511    }
2512
2513    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut AppContext) {
2514        cx.default_global::<Self>()
2515            .0
2516            .entry(name)
2517            .or_default()
2518            .push(hitbox_id);
2519    }
2520
2521    pub fn pop(name: &SharedString, cx: &mut AppContext) {
2522        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
2523    }
2524}
2525
2526/// A wrapper around an element that can be focused.
2527pub struct Focusable<E> {
2528    /// The element that is focusable
2529    pub element: E,
2530}
2531
2532impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
2533
2534impl<E> InteractiveElement for Focusable<E>
2535where
2536    E: InteractiveElement,
2537{
2538    fn interactivity(&mut self) -> &mut Interactivity {
2539        self.element.interactivity()
2540    }
2541}
2542
2543impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
2544
2545impl<E> Styled for Focusable<E>
2546where
2547    E: Styled,
2548{
2549    fn style(&mut self) -> &mut StyleRefinement {
2550        self.element.style()
2551    }
2552}
2553
2554impl Focusable<Div> {
2555    /// Add a listener to be called when the children of this `Div` are prepainted.
2556    /// This allows you to store the [`Bounds`] of the children for later use.
2557    pub fn on_children_prepainted(
2558        mut self,
2559        listener: impl Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static,
2560    ) -> Self {
2561        self.element = self.element.on_children_prepainted(listener);
2562        self
2563    }
2564}
2565
2566impl<E> Element for Focusable<E>
2567where
2568    E: Element,
2569{
2570    type RequestLayoutState = E::RequestLayoutState;
2571    type PrepaintState = E::PrepaintState;
2572
2573    fn id(&self) -> Option<ElementId> {
2574        self.element.id()
2575    }
2576
2577    fn request_layout(
2578        &mut self,
2579        id: Option<&GlobalElementId>,
2580        cx: &mut WindowContext,
2581    ) -> (LayoutId, Self::RequestLayoutState) {
2582        self.element.request_layout(id, cx)
2583    }
2584
2585    fn prepaint(
2586        &mut self,
2587        id: Option<&GlobalElementId>,
2588        bounds: Bounds<Pixels>,
2589        state: &mut Self::RequestLayoutState,
2590        cx: &mut WindowContext,
2591    ) -> E::PrepaintState {
2592        self.element.prepaint(id, bounds, state, cx)
2593    }
2594
2595    fn paint(
2596        &mut self,
2597        id: Option<&GlobalElementId>,
2598        bounds: Bounds<Pixels>,
2599        request_layout: &mut Self::RequestLayoutState,
2600        prepaint: &mut Self::PrepaintState,
2601        cx: &mut WindowContext,
2602    ) {
2603        self.element.paint(id, bounds, request_layout, prepaint, cx)
2604    }
2605}
2606
2607impl<E> IntoElement for Focusable<E>
2608where
2609    E: IntoElement,
2610{
2611    type Element = E::Element;
2612
2613    fn into_element(self) -> Self::Element {
2614        self.element.into_element()
2615    }
2616}
2617
2618impl<E> ParentElement for Focusable<E>
2619where
2620    E: ParentElement,
2621{
2622    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
2623        self.element.extend(elements)
2624    }
2625}
2626
2627/// A wrapper around an element that can store state, produced after assigning an ElementId.
2628pub struct Stateful<E> {
2629    pub(crate) element: E,
2630}
2631
2632impl<E> Styled for Stateful<E>
2633where
2634    E: Styled,
2635{
2636    fn style(&mut self) -> &mut StyleRefinement {
2637        self.element.style()
2638    }
2639}
2640
2641impl<E> StatefulInteractiveElement for Stateful<E>
2642where
2643    E: Element,
2644    Self: InteractiveElement,
2645{
2646}
2647
2648impl<E> InteractiveElement for Stateful<E>
2649where
2650    E: InteractiveElement,
2651{
2652    fn interactivity(&mut self) -> &mut Interactivity {
2653        self.element.interactivity()
2654    }
2655}
2656
2657impl<E: FocusableElement> FocusableElement for Stateful<E> {}
2658
2659impl<E> Element for Stateful<E>
2660where
2661    E: Element,
2662{
2663    type RequestLayoutState = E::RequestLayoutState;
2664    type PrepaintState = E::PrepaintState;
2665
2666    fn id(&self) -> Option<ElementId> {
2667        self.element.id()
2668    }
2669
2670    fn request_layout(
2671        &mut self,
2672        id: Option<&GlobalElementId>,
2673        cx: &mut WindowContext,
2674    ) -> (LayoutId, Self::RequestLayoutState) {
2675        self.element.request_layout(id, cx)
2676    }
2677
2678    fn prepaint(
2679        &mut self,
2680        id: Option<&GlobalElementId>,
2681        bounds: Bounds<Pixels>,
2682        state: &mut Self::RequestLayoutState,
2683        cx: &mut WindowContext,
2684    ) -> E::PrepaintState {
2685        self.element.prepaint(id, bounds, state, cx)
2686    }
2687
2688    fn paint(
2689        &mut self,
2690        id: Option<&GlobalElementId>,
2691        bounds: Bounds<Pixels>,
2692        request_layout: &mut Self::RequestLayoutState,
2693        prepaint: &mut Self::PrepaintState,
2694        cx: &mut WindowContext,
2695    ) {
2696        self.element.paint(id, bounds, request_layout, prepaint, cx);
2697    }
2698}
2699
2700impl<E> IntoElement for Stateful<E>
2701where
2702    E: Element,
2703{
2704    type Element = Self;
2705
2706    fn into_element(self) -> Self::Element {
2707        self
2708    }
2709}
2710
2711impl<E> ParentElement for Stateful<E>
2712where
2713    E: ParentElement,
2714{
2715    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
2716        self.element.extend(elements)
2717    }
2718}
2719
2720/// Represents an element that can be scrolled *to* in its parent element.
2721///
2722/// Contrary to [ScrollHandle::scroll_to_item], an anchored element does not have to be an immediate child of the parent.
2723#[derive(Clone)]
2724pub struct ScrollAnchor {
2725    handle: ScrollHandle,
2726    last_origin: Rc<RefCell<Point<Pixels>>>,
2727}
2728
2729impl ScrollAnchor {
2730    /// Creates a [ScrollAnchor] associated with a given [ScrollHandle].
2731    pub fn for_handle(handle: ScrollHandle) -> Self {
2732        Self {
2733            handle,
2734            last_origin: Default::default(),
2735        }
2736    }
2737    /// Request scroll to this item on the next frame.
2738    pub fn scroll_to(&self, cx: &mut WindowContext) {
2739        let this = self.clone();
2740
2741        cx.on_next_frame(move |_| {
2742            let viewport_bounds = this.handle.bounds();
2743            let self_bounds = *this.last_origin.borrow();
2744            this.handle.set_offset(viewport_bounds.origin - self_bounds);
2745        });
2746    }
2747}
2748#[derive(Default, Debug)]
2749struct ScrollHandleState {
2750    offset: Rc<RefCell<Point<Pixels>>>,
2751    bounds: Bounds<Pixels>,
2752    child_bounds: Vec<Bounds<Pixels>>,
2753    requested_scroll_top: Option<(usize, Pixels)>,
2754    overflow: Point<Overflow>,
2755}
2756
2757/// A handle to the scrollable aspects of an element.
2758/// Used for accessing scroll state, like the current scroll offset,
2759/// and for mutating the scroll state, like scrolling to a specific child.
2760#[derive(Clone, Debug)]
2761pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
2762
2763impl Default for ScrollHandle {
2764    fn default() -> Self {
2765        Self::new()
2766    }
2767}
2768
2769impl ScrollHandle {
2770    /// Construct a new scroll handle.
2771    pub fn new() -> Self {
2772        Self(Rc::default())
2773    }
2774
2775    /// Get the current scroll offset.
2776    pub fn offset(&self) -> Point<Pixels> {
2777        *self.0.borrow().offset.borrow()
2778    }
2779
2780    /// Get the top child that's scrolled into view.
2781    pub fn top_item(&self) -> usize {
2782        let state = self.0.borrow();
2783        let top = state.bounds.top() - state.offset.borrow().y;
2784
2785        match state.child_bounds.binary_search_by(|bounds| {
2786            if top < bounds.top() {
2787                Ordering::Greater
2788            } else if top > bounds.bottom() {
2789                Ordering::Less
2790            } else {
2791                Ordering::Equal
2792            }
2793        }) {
2794            Ok(ix) => ix,
2795            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
2796        }
2797    }
2798
2799    /// Return the bounds into which this child is painted
2800    pub fn bounds(&self) -> Bounds<Pixels> {
2801        self.0.borrow().bounds
2802    }
2803
2804    /// Set the bounds into which this child is painted
2805    pub(super) fn set_bounds(&self, bounds: Bounds<Pixels>) {
2806        self.0.borrow_mut().bounds = bounds;
2807    }
2808
2809    /// Get the bounds for a specific child.
2810    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
2811        self.0.borrow().child_bounds.get(ix).cloned()
2812    }
2813
2814    /// scroll_to_item scrolls the minimal amount to ensure that the child is
2815    /// fully visible
2816    pub fn scroll_to_item(&self, ix: usize) {
2817        let state = self.0.borrow();
2818
2819        let Some(bounds) = state.child_bounds.get(ix) else {
2820            return;
2821        };
2822
2823        let mut scroll_offset = state.offset.borrow_mut();
2824
2825        if state.overflow.y == Overflow::Scroll {
2826            if bounds.top() + scroll_offset.y < state.bounds.top() {
2827                scroll_offset.y = state.bounds.top() - bounds.top();
2828            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
2829                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
2830            }
2831        }
2832
2833        if state.overflow.x == Overflow::Scroll {
2834            if bounds.left() + scroll_offset.x < state.bounds.left() {
2835                scroll_offset.x = state.bounds.left() - bounds.left();
2836            } else if bounds.right() + scroll_offset.x > state.bounds.right() {
2837                scroll_offset.x = state.bounds.right() - bounds.right();
2838            }
2839        }
2840    }
2841
2842    /// Set the offset explicitly. The offset is the distance from the top left of the
2843    /// parent container to the top left of the first child.
2844    /// As you scroll further down the offset becomes more negative.
2845    pub fn set_offset(&self, mut position: Point<Pixels>) {
2846        let state = self.0.borrow();
2847        *state.offset.borrow_mut() = position;
2848    }
2849
2850    /// Get the logical scroll top, based on a child index and a pixel offset.
2851    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
2852        let ix = self.top_item();
2853        let state = self.0.borrow();
2854
2855        if let Some(child_bounds) = state.child_bounds.get(ix) {
2856            (
2857                ix,
2858                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
2859            )
2860        } else {
2861            (ix, px(0.))
2862        }
2863    }
2864
2865    /// Set the logical scroll top, based on a child index and a pixel offset.
2866    pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
2867        self.0.borrow_mut().requested_scroll_top = Some((ix, px));
2868    }
2869
2870    /// Get the count of children for scrollable item.
2871    pub fn children_count(&self) -> usize {
2872        self.0.borrow().child_bounds.len()
2873    }
2874}