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.;
  45pub(crate) const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
  46
  47/// The styling information for a given group.
  48pub struct GroupStyle {
  49    /// The identifier for this group.
  50    pub group: SharedString,
  51
  52    /// The specific style refinement that this group would apply
  53    /// to its children.
  54    pub style: Box<StyleRefinement>,
  55}
  56
  57/// An event for when a drag is moving over this element, with the given state type.
  58pub struct DragMoveEvent<T> {
  59    /// The mouse move event that triggered this drag move event.
  60    pub event: MouseMoveEvent,
  61
  62    /// The bounds of this element.
  63    pub bounds: Bounds<Pixels>,
  64    drag: PhantomData<T>,
  65    dragged_item: Arc<dyn Any>,
  66}
  67
  68impl<T: 'static> DragMoveEvent<T> {
  69    /// Returns the drag state for this event.
  70    pub fn drag<'b>(&self, cx: &'b AppContext) -> &'b T {
  71        cx.active_drag
  72            .as_ref()
  73            .and_then(|drag| drag.value.downcast_ref::<T>())
  74            .expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
  75    }
  76
  77    /// An item that is about to be dropped.
  78    pub fn dragged_item(&self) -> &dyn Any {
  79        self.dragged_item.as_ref()
  80    }
  81}
  82
  83impl Interactivity {
  84    /// Bind the given callback to the mouse down event for the given mouse button, during the bubble phase
  85    /// The imperative API equivalent of [`InteractiveElement::on_mouse_down`]
  86    ///
  87    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to the view state from this callback.
  88    pub fn on_mouse_down(
  89        &mut self,
  90        button: MouseButton,
  91        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
  92    ) {
  93        self.mouse_down_listeners
  94            .push(Box::new(move |event, phase, hitbox, cx| {
  95                if phase == DispatchPhase::Bubble && event.button == button && hitbox.is_hovered(cx)
  96                {
  97                    (listener)(event, cx)
  98                }
  99            }));
 100    }
 101
 102    /// Bind the given callback to the mouse down event for any button, during the capture phase
 103    /// The imperative API equivalent of [`InteractiveElement::capture_any_mouse_down`]
 104    ///
 105    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 106    pub fn capture_any_mouse_down(
 107        &mut self,
 108        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 109    ) {
 110        self.mouse_down_listeners
 111            .push(Box::new(move |event, phase, hitbox, cx| {
 112                if phase == DispatchPhase::Capture && hitbox.is_hovered(cx) {
 113                    (listener)(event, cx)
 114                }
 115            }));
 116    }
 117
 118    /// Bind the given callback to the mouse down event for any button, during the bubble phase
 119    /// the imperative API equivalent to [`InteractiveElement::on_any_mouse_down`]
 120    ///
 121    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 122    pub fn on_any_mouse_down(
 123        &mut self,
 124        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 125    ) {
 126        self.mouse_down_listeners
 127            .push(Box::new(move |event, phase, hitbox, cx| {
 128                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 129                    (listener)(event, cx)
 130                }
 131            }));
 132    }
 133
 134    /// Bind the given callback to the mouse up event for the given button, during the bubble phase
 135    /// the imperative API equivalent to [`InteractiveElement::on_mouse_up`]
 136    ///
 137    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 138    pub fn on_mouse_up(
 139        &mut self,
 140        button: MouseButton,
 141        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 142    ) {
 143        self.mouse_up_listeners
 144            .push(Box::new(move |event, phase, hitbox, cx| {
 145                if phase == DispatchPhase::Bubble && event.button == button && hitbox.is_hovered(cx)
 146                {
 147                    (listener)(event, cx)
 148                }
 149            }));
 150    }
 151
 152    /// Bind the given callback to the mouse up event for any button, during the capture phase
 153    /// the imperative API equivalent to [`InteractiveElement::capture_any_mouse_up`]
 154    ///
 155    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 156    pub fn capture_any_mouse_up(
 157        &mut self,
 158        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 159    ) {
 160        self.mouse_up_listeners
 161            .push(Box::new(move |event, phase, hitbox, cx| {
 162                if phase == DispatchPhase::Capture && hitbox.is_hovered(cx) {
 163                    (listener)(event, cx)
 164                }
 165            }));
 166    }
 167
 168    /// Bind the given callback to the mouse up event for any button, during the bubble phase
 169    /// the imperative API equivalent to [`Interactivity::on_any_mouse_up`]
 170    ///
 171    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 172    pub fn on_any_mouse_up(
 173        &mut self,
 174        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 175    ) {
 176        self.mouse_up_listeners
 177            .push(Box::new(move |event, phase, hitbox, cx| {
 178                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 179                    (listener)(event, cx)
 180                }
 181            }));
 182    }
 183
 184    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 185    /// when the mouse is outside of the bounds of this element.
 186    /// The imperative API equivalent to [`InteractiveElement::on_mouse_down_out`]
 187    ///
 188    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 189    pub fn on_mouse_down_out(
 190        &mut self,
 191        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 192    ) {
 193        self.mouse_down_listeners
 194            .push(Box::new(move |event, phase, hitbox, cx| {
 195                if phase == DispatchPhase::Capture && !hitbox.contains(&cx.mouse_position()) {
 196                    (listener)(event, cx)
 197                }
 198            }));
 199    }
 200
 201    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 202    /// when the mouse is outside of the bounds of this element.
 203    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up_out`]
 204    ///
 205    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 206    pub fn on_mouse_up_out(
 207        &mut self,
 208        button: MouseButton,
 209        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 210    ) {
 211        self.mouse_up_listeners
 212            .push(Box::new(move |event, phase, hitbox, cx| {
 213                if phase == DispatchPhase::Capture
 214                    && event.button == button
 215                    && !hitbox.is_hovered(cx)
 216                {
 217                    (listener)(event, cx);
 218                }
 219            }));
 220    }
 221
 222    /// Bind the given callback to the mouse move event, during the bubble phase
 223    /// The imperative API equivalent to [`InteractiveElement::on_mouse_move`]
 224    ///
 225    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 226    pub fn on_mouse_move(
 227        &mut self,
 228        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 229    ) {
 230        self.mouse_move_listeners
 231            .push(Box::new(move |event, phase, hitbox, cx| {
 232                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 233                    (listener)(event, cx);
 234                }
 235            }));
 236    }
 237
 238    /// Bind the given callback to the mouse drag event of the given type. Note that this
 239    /// will be called for all move events, inside or outside of this element, as long as the
 240    /// drag was started with this element under the mouse. Useful for implementing draggable
 241    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 242    /// The imperative API equivalent to [`InteractiveElement::on_drag_move`]
 243    ///
 244    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 245    pub fn on_drag_move<T>(
 246        &mut self,
 247        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 248    ) where
 249        T: 'static,
 250    {
 251        self.mouse_move_listeners
 252            .push(Box::new(move |event, phase, hitbox, cx| {
 253                if phase == DispatchPhase::Capture {
 254                    if let Some(drag) = &cx.active_drag {
 255                        if drag.value.as_ref().type_id() == TypeId::of::<T>() {
 256                            (listener)(
 257                                &DragMoveEvent {
 258                                    event: event.clone(),
 259                                    bounds: hitbox.bounds,
 260                                    drag: PhantomData,
 261                                    dragged_item: Arc::clone(&drag.value),
 262                                },
 263                                cx,
 264                            );
 265                        }
 266                    }
 267                }
 268            }));
 269    }
 270
 271    /// Bind the given callback to scroll wheel events during the bubble phase
 272    /// The imperative API equivalent to [`InteractiveElement::on_scroll_wheel`]
 273    ///
 274    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 275    pub fn on_scroll_wheel(
 276        &mut self,
 277        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 278    ) {
 279        self.scroll_wheel_listeners
 280            .push(Box::new(move |event, phase, hitbox, cx| {
 281                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
 282                    (listener)(event, cx);
 283                }
 284            }));
 285    }
 286
 287    /// Bind the given callback to an action dispatch during the capture phase
 288    /// The imperative API equivalent to [`InteractiveElement::capture_action`]
 289    ///
 290    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 291    pub fn capture_action<A: Action>(
 292        &mut self,
 293        listener: impl Fn(&A, &mut WindowContext) + 'static,
 294    ) {
 295        self.action_listeners.push((
 296            TypeId::of::<A>(),
 297            Box::new(move |action, phase, cx| {
 298                let action = action.downcast_ref().unwrap();
 299                if phase == DispatchPhase::Capture {
 300                    (listener)(action, cx)
 301                } else {
 302                    cx.propagate();
 303                }
 304            }),
 305        ));
 306    }
 307
 308    /// Bind the given callback to an action dispatch during the bubble phase
 309    /// The imperative API equivalent to [`InteractiveElement::on_action`]
 310    ///
 311    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 312    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) {
 313        self.action_listeners.push((
 314            TypeId::of::<A>(),
 315            Box::new(move |action, phase, cx| {
 316                let action = action.downcast_ref().unwrap();
 317                if phase == DispatchPhase::Bubble {
 318                    (listener)(action, cx)
 319                }
 320            }),
 321        ));
 322    }
 323
 324    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 325    /// instead of a type parameter. Useful for component libraries that want to expose
 326    /// action bindings to their users.
 327    /// The imperative API equivalent to [`InteractiveElement::on_boxed_action`]
 328    ///
 329    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 330    pub fn on_boxed_action(
 331        &mut self,
 332        action: &dyn Action,
 333        listener: impl Fn(&dyn Action, &mut WindowContext) + 'static,
 334    ) {
 335        let action = action.boxed_clone();
 336        self.action_listeners.push((
 337            (*action).type_id(),
 338            Box::new(move |_, phase, cx| {
 339                if phase == DispatchPhase::Bubble {
 340                    (listener)(&*action, cx)
 341                }
 342            }),
 343        ));
 344    }
 345
 346    /// Bind the given callback to key down events during the bubble phase
 347    /// The imperative API equivalent to [`InteractiveElement::on_key_down`]
 348    ///
 349    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 350    pub fn on_key_down(&mut self, listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static) {
 351        self.key_down_listeners
 352            .push(Box::new(move |event, phase, cx| {
 353                if phase == DispatchPhase::Bubble {
 354                    (listener)(event, cx)
 355                }
 356            }));
 357    }
 358
 359    /// Bind the given callback to key down events during the capture phase
 360    /// The imperative API equivalent to [`InteractiveElement::capture_key_down`]
 361    ///
 362    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 363    pub fn capture_key_down(
 364        &mut self,
 365        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 366    ) {
 367        self.key_down_listeners
 368            .push(Box::new(move |event, phase, cx| {
 369                if phase == DispatchPhase::Capture {
 370                    listener(event, cx)
 371                }
 372            }));
 373    }
 374
 375    /// Bind the given callback to key up events during the bubble phase
 376    /// The imperative API equivalent to [`InteractiveElement::on_key_up`]
 377    ///
 378    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 379    pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 380        self.key_up_listeners
 381            .push(Box::new(move |event, phase, cx| {
 382                if phase == DispatchPhase::Bubble {
 383                    listener(event, cx)
 384                }
 385            }));
 386    }
 387
 388    /// Bind the given callback to key up events during the capture phase
 389    /// The imperative API equivalent to [`InteractiveElement::on_key_up`]
 390    ///
 391    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 392    pub fn capture_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 393        self.key_up_listeners
 394            .push(Box::new(move |event, phase, cx| {
 395                if phase == DispatchPhase::Capture {
 396                    listener(event, cx)
 397                }
 398            }));
 399    }
 400
 401    /// Bind the given callback to modifiers changing events.
 402    /// The imperative API equivalent to [`InteractiveElement::on_modifiers_changed`]
 403    ///
 404    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 405    pub fn on_modifiers_changed(
 406        &mut self,
 407        listener: impl Fn(&ModifiersChangedEvent, &mut WindowContext) + 'static,
 408    ) {
 409        self.modifiers_changed_listeners
 410            .push(Box::new(move |event, cx| listener(event, cx)));
 411    }
 412
 413    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element
 414    /// The imperative API equivalent to [`InteractiveElement::on_drop`]
 415    ///
 416    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 417    pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) {
 418        self.drop_listeners.push((
 419            TypeId::of::<T>(),
 420            Box::new(move |dragged_value, cx| {
 421                listener(dragged_value.downcast_ref().unwrap(), cx);
 422            }),
 423        ));
 424    }
 425
 426    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element
 427    /// The imperative API equivalent to [`InteractiveElement::can_drop`]
 428    pub fn can_drop(&mut self, predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static) {
 429        self.can_drop_predicate = Some(Box::new(predicate));
 430    }
 431
 432    /// Bind the given callback to click events of this element
 433    /// The imperative API equivalent to [`StatefulInteractiveElement::on_click`]
 434    ///
 435    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 436    pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static)
 437    where
 438        Self: Sized,
 439    {
 440        self.click_listeners
 441            .push(Box::new(move |event, cx| listener(event, cx)));
 442    }
 443
 444    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 445    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 446    /// the [`Self::on_drag_move`] API
 447    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`]
 448    ///
 449    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 450    pub fn on_drag<T, W>(
 451        &mut self,
 452        value: T,
 453        constructor: impl Fn(&T, Point<Pixels>, &mut WindowContext) -> View<W> + 'static,
 454    ) where
 455        Self: Sized,
 456        T: 'static,
 457        W: 'static + Render,
 458    {
 459        debug_assert!(
 460            self.drag_listener.is_none(),
 461            "calling on_drag more than once on the same element is not supported"
 462        );
 463        self.drag_listener = Some((
 464            Arc::new(value),
 465            Box::new(move |value, offset, cx| {
 466                constructor(value.downcast_ref().unwrap(), offset, cx).into()
 467            }),
 468        ));
 469    }
 470
 471    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 472    /// passed to the callback is true when the hover starts and false when it ends.
 473    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`]
 474    ///
 475    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 476    pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static)
 477    where
 478        Self: Sized,
 479    {
 480        debug_assert!(
 481            self.hover_listener.is_none(),
 482            "calling on_hover more than once on the same element is not supported"
 483        );
 484        self.hover_listener = Some(Box::new(listener));
 485    }
 486
 487    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 488    /// The imperative API equivalent to [`InteractiveElement::tooltip`]
 489    pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static)
 490    where
 491        Self: Sized,
 492    {
 493        debug_assert!(
 494            self.tooltip_builder.is_none(),
 495            "calling tooltip more than once on the same element is not supported"
 496        );
 497        self.tooltip_builder = Some(TooltipBuilder {
 498            build: Rc::new(build_tooltip),
 499            hoverable: false,
 500        });
 501    }
 502
 503    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
 504    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
 505    /// the tooltip. The imperative API equivalent to [`InteractiveElement::hoverable_tooltip`]
 506    pub fn hoverable_tooltip(
 507        &mut self,
 508        build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static,
 509    ) where
 510        Self: Sized,
 511    {
 512        debug_assert!(
 513            self.tooltip_builder.is_none(),
 514            "calling tooltip more than once on the same element is not supported"
 515        );
 516        self.tooltip_builder = Some(TooltipBuilder {
 517            build: Rc::new(build_tooltip),
 518            hoverable: true,
 519        });
 520    }
 521
 522    /// Block the mouse from interacting with this element or any of its children
 523    /// The imperative API equivalent to [`InteractiveElement::occlude`]
 524    pub fn occlude_mouse(&mut self) {
 525        self.occlude_mouse = true;
 526    }
 527}
 528
 529/// A trait for elements that want to use the standard GPUI event handlers that don't
 530/// require any state.
 531pub trait InteractiveElement: Sized {
 532    /// Retrieve the interactivity state associated with this element
 533    fn interactivity(&mut self) -> &mut Interactivity;
 534
 535    /// Assign this element to a group of elements that can be styled together
 536    fn group(mut self, group: impl Into<SharedString>) -> Self {
 537        self.interactivity().group = Some(group.into());
 538        self
 539    }
 540
 541    /// Assign this element an ID, so that it can be used with interactivity
 542    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
 543        self.interactivity().element_id = Some(id.into());
 544
 545        Stateful { element: self }
 546    }
 547
 548    /// Track the focus state of the given focus handle on this element.
 549    /// If the focus handle is focused by the application, this element will
 550    /// apply its focused styles.
 551    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<Self> {
 552        self.interactivity().focusable = true;
 553        self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
 554        Focusable { element: self }
 555    }
 556
 557    /// Set the keymap context for this element. This will be used to determine
 558    /// which action to dispatch from the keymap.
 559    fn key_context<C, E>(mut self, key_context: C) -> Self
 560    where
 561        C: TryInto<KeyContext, Error = E>,
 562        E: Debug,
 563    {
 564        if let Some(key_context) = key_context.try_into().log_err() {
 565            self.interactivity().key_context = Some(key_context);
 566        }
 567        self
 568    }
 569
 570    /// Apply the given style to this element when the mouse hovers over it
 571    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 572        debug_assert!(
 573            self.interactivity().hover_style.is_none(),
 574            "hover style already set"
 575        );
 576        self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
 577        self
 578    }
 579
 580    /// Apply the given style to this element when the mouse hovers over a group member
 581    fn group_hover(
 582        mut self,
 583        group_name: impl Into<SharedString>,
 584        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 585    ) -> Self {
 586        self.interactivity().group_hover_style = Some(GroupStyle {
 587            group: group_name.into(),
 588            style: Box::new(f(StyleRefinement::default())),
 589        });
 590        self
 591    }
 592
 593    /// Bind the given callback to the mouse down event for the given mouse button,
 594    /// the fluent API equivalent to [`Interactivity::on_mouse_down`]
 595    ///
 596    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to the view state from this callback.
 597    fn on_mouse_down(
 598        mut self,
 599        button: MouseButton,
 600        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 601    ) -> Self {
 602        self.interactivity().on_mouse_down(button, listener);
 603        self
 604    }
 605
 606    #[cfg(any(test, feature = "test-support"))]
 607    /// Set a key that can be used to look up this element's bounds
 608    /// in the [`VisualTestContext::debug_bounds`] map
 609    /// This is a noop in release builds
 610    fn debug_selector(mut self, f: impl FnOnce() -> String) -> Self {
 611        self.interactivity().debug_selector = Some(f());
 612        self
 613    }
 614
 615    #[cfg(not(any(test, feature = "test-support")))]
 616    /// Set a key that can be used to look up this element's bounds
 617    /// in the [`VisualTestContext::debug_bounds`] map
 618    /// This is a noop in release builds
 619    #[inline]
 620    fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
 621        self
 622    }
 623
 624    /// Bind the given callback to the mouse down event for any button, during the capture phase
 625    /// the fluent API equivalent to [`Interactivity::capture_any_mouse_down`]
 626    ///
 627    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 628    fn capture_any_mouse_down(
 629        mut self,
 630        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 631    ) -> Self {
 632        self.interactivity().capture_any_mouse_down(listener);
 633        self
 634    }
 635
 636    /// Bind the given callback to the mouse down event for any button, during the capture phase
 637    /// the fluent API equivalent to [`Interactivity::on_any_mouse_down`]
 638    ///
 639    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 640    fn on_any_mouse_down(
 641        mut self,
 642        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 643    ) -> Self {
 644        self.interactivity().on_any_mouse_down(listener);
 645        self
 646    }
 647
 648    /// Bind the given callback to the mouse up event for the given button, during the bubble phase
 649    /// the fluent API equivalent to [`Interactivity::on_mouse_up`]
 650    ///
 651    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 652    fn on_mouse_up(
 653        mut self,
 654        button: MouseButton,
 655        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 656    ) -> Self {
 657        self.interactivity().on_mouse_up(button, listener);
 658        self
 659    }
 660
 661    /// Bind the given callback to the mouse up event for any button, during the capture phase
 662    /// the fluent API equivalent to [`Interactivity::capture_any_mouse_up`]
 663    ///
 664    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 665    fn capture_any_mouse_up(
 666        mut self,
 667        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 668    ) -> Self {
 669        self.interactivity().capture_any_mouse_up(listener);
 670        self
 671    }
 672
 673    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
 674    /// when the mouse is outside of the bounds of this element.
 675    /// The fluent API equivalent to [`Interactivity::on_mouse_down_out`]
 676    ///
 677    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 678    fn on_mouse_down_out(
 679        mut self,
 680        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 681    ) -> Self {
 682        self.interactivity().on_mouse_down_out(listener);
 683        self
 684    }
 685
 686    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
 687    /// when the mouse is outside of the bounds of this element.
 688    /// The fluent API equivalent to [`Interactivity::on_mouse_up_out`]
 689    ///
 690    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 691    fn on_mouse_up_out(
 692        mut self,
 693        button: MouseButton,
 694        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 695    ) -> Self {
 696        self.interactivity().on_mouse_up_out(button, listener);
 697        self
 698    }
 699
 700    /// Bind the given callback to the mouse move event, during the bubble phase
 701    /// The fluent API equivalent to [`Interactivity::on_mouse_move`]
 702    ///
 703    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 704    fn on_mouse_move(
 705        mut self,
 706        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 707    ) -> Self {
 708        self.interactivity().on_mouse_move(listener);
 709        self
 710    }
 711
 712    /// Bind the given callback to the mouse drag event of the given type. Note that this
 713    /// will be called for all move events, inside or outside of this element, as long as the
 714    /// drag was started with this element under the mouse. Useful for implementing draggable
 715    /// UIs that don't conform to a drag and drop style interaction, like resizing.
 716    /// The fluent API equivalent to [`Interactivity::on_drag_move`]
 717    ///
 718    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 719    fn on_drag_move<T: 'static>(
 720        mut self,
 721        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 722    ) -> Self {
 723        self.interactivity().on_drag_move(listener);
 724        self
 725    }
 726
 727    /// Bind the given callback to scroll wheel events during the bubble phase
 728    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`]
 729    ///
 730    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 731    fn on_scroll_wheel(
 732        mut self,
 733        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 734    ) -> Self {
 735        self.interactivity().on_scroll_wheel(listener);
 736        self
 737    }
 738
 739    /// Capture the given action, before normal action dispatch can fire
 740    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`]
 741    ///
 742    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 743    fn capture_action<A: Action>(
 744        mut self,
 745        listener: impl Fn(&A, &mut WindowContext) + 'static,
 746    ) -> Self {
 747        self.interactivity().capture_action(listener);
 748        self
 749    }
 750
 751    /// Bind the given callback to an action dispatch during the bubble phase
 752    /// The fluent API equivalent to [`Interactivity::on_action`]
 753    ///
 754    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 755    fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
 756        self.interactivity().on_action(listener);
 757        self
 758    }
 759
 760    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
 761    /// instead of a type parameter. Useful for component libraries that want to expose
 762    /// action bindings to their users.
 763    /// The fluent API equivalent to [`Interactivity::on_boxed_action`]
 764    ///
 765    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 766    fn on_boxed_action(
 767        mut self,
 768        action: &dyn Action,
 769        listener: impl Fn(&dyn Action, &mut WindowContext) + 'static,
 770    ) -> Self {
 771        self.interactivity().on_boxed_action(action, listener);
 772        self
 773    }
 774
 775    /// Bind the given callback to key down events during the bubble phase
 776    /// The fluent API equivalent to [`Interactivity::on_key_down`]
 777    ///
 778    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 779    fn on_key_down(
 780        mut self,
 781        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 782    ) -> Self {
 783        self.interactivity().on_key_down(listener);
 784        self
 785    }
 786
 787    /// Bind the given callback to key down events during the capture phase
 788    /// The fluent API equivalent to [`Interactivity::capture_key_down`]
 789    ///
 790    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 791    fn capture_key_down(
 792        mut self,
 793        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 794    ) -> Self {
 795        self.interactivity().capture_key_down(listener);
 796        self
 797    }
 798
 799    /// Bind the given callback to key up events during the bubble phase
 800    /// The fluent API equivalent to [`Interactivity::on_key_up`]
 801    ///
 802    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 803    fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
 804        self.interactivity().on_key_up(listener);
 805        self
 806    }
 807
 808    /// Bind the given callback to key up events during the capture phase
 809    /// The fluent API equivalent to [`Interactivity::capture_key_up`]
 810    ///
 811    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 812    fn capture_key_up(
 813        mut self,
 814        listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
 815    ) -> Self {
 816        self.interactivity().capture_key_up(listener);
 817        self
 818    }
 819
 820    /// Bind the given callback to modifiers changing events.
 821    /// The fluent API equivalent to [`Interactivity::on_modifiers_changed`]
 822    ///
 823    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 824    fn on_modifiers_changed(
 825        mut self,
 826        listener: impl Fn(&ModifiersChangedEvent, &mut WindowContext) + 'static,
 827    ) -> Self {
 828        self.interactivity().on_modifiers_changed(listener);
 829        self
 830    }
 831
 832    /// Apply the given style when the given data type is dragged over this element
 833    fn drag_over<S: 'static>(
 834        mut self,
 835        f: impl 'static + Fn(StyleRefinement, &S, &WindowContext) -> StyleRefinement,
 836    ) -> Self {
 837        self.interactivity().drag_over_styles.push((
 838            TypeId::of::<S>(),
 839            Box::new(move |currently_dragged: &dyn Any, cx| {
 840                f(
 841                    StyleRefinement::default(),
 842                    currently_dragged.downcast_ref::<S>().unwrap(),
 843                    cx,
 844                )
 845            }),
 846        ));
 847        self
 848    }
 849
 850    /// Apply the given style when the given data type is dragged over this element's group
 851    fn group_drag_over<S: 'static>(
 852        mut self,
 853        group_name: impl Into<SharedString>,
 854        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 855    ) -> Self {
 856        self.interactivity().group_drag_over_styles.push((
 857            TypeId::of::<S>(),
 858            GroupStyle {
 859                group: group_name.into(),
 860                style: Box::new(f(StyleRefinement::default())),
 861            },
 862        ));
 863        self
 864    }
 865
 866    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element
 867    /// The fluent API equivalent to [`Interactivity::on_drop`]
 868    ///
 869    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 870    fn on_drop<T: 'static>(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self {
 871        self.interactivity().on_drop(listener);
 872        self
 873    }
 874
 875    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element
 876    /// The fluent API equivalent to [`Interactivity::can_drop`]
 877    fn can_drop(
 878        mut self,
 879        predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static,
 880    ) -> Self {
 881        self.interactivity().can_drop(predicate);
 882        self
 883    }
 884
 885    /// Block the mouse from interacting with this element or any of its children
 886    /// The fluent API equivalent to [`Interactivity::occlude_mouse`]
 887    fn occlude(mut self) -> Self {
 888        self.interactivity().occlude_mouse();
 889        self
 890    }
 891
 892    /// Block the mouse from interacting with this element or any of its children
 893    /// The fluent API equivalent to [`Interactivity::occlude_mouse`]
 894    fn block_mouse_down(mut self) -> Self {
 895        self.on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
 896    }
 897}
 898
 899/// A trait for elements that want to use the standard GPUI interactivity features
 900/// that require state.
 901pub trait StatefulInteractiveElement: InteractiveElement {
 902    /// Set this element to focusable.
 903    fn focusable(mut self) -> Focusable<Self> {
 904        self.interactivity().focusable = true;
 905        Focusable { element: self }
 906    }
 907
 908    /// Set the overflow x and y to scroll.
 909    fn overflow_scroll(mut self) -> Self {
 910        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 911        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 912        self
 913    }
 914
 915    /// Set the overflow x to scroll.
 916    fn overflow_x_scroll(mut self) -> Self {
 917        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 918        self
 919    }
 920
 921    /// Set the overflow y to scroll.
 922    fn overflow_y_scroll(mut self) -> Self {
 923        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 924        self
 925    }
 926
 927    /// Track the scroll state of this element with the given handle.
 928    fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
 929        self.interactivity().tracked_scroll_handle = Some(scroll_handle.clone());
 930        self
 931    }
 932
 933    /// Track the scroll state of this element with the given handle.
 934    fn anchor_scroll(mut self, scroll_anchor: Option<ScrollAnchor>) -> Self {
 935        self.interactivity().scroll_anchor = scroll_anchor;
 936        self
 937    }
 938
 939    /// Set the given styles to be applied when this element is active.
 940    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 941    where
 942        Self: Sized,
 943    {
 944        self.interactivity().active_style = Some(Box::new(f(StyleRefinement::default())));
 945        self
 946    }
 947
 948    /// Set the given styles to be applied when this element's group is active.
 949    fn group_active(
 950        mut self,
 951        group_name: impl Into<SharedString>,
 952        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 953    ) -> Self
 954    where
 955        Self: Sized,
 956    {
 957        self.interactivity().group_active_style = Some(GroupStyle {
 958            group: group_name.into(),
 959            style: Box::new(f(StyleRefinement::default())),
 960        });
 961        self
 962    }
 963
 964    /// Bind the given callback to click events of this element
 965    /// The fluent API equivalent to [`Interactivity::on_click`]
 966    ///
 967    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 968    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self
 969    where
 970        Self: Sized,
 971    {
 972        self.interactivity().on_click(listener);
 973        self
 974    }
 975
 976    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
 977    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
 978    /// the [`Self::on_drag_move`] API.
 979    /// The callback also has access to the offset of triggering click from the origin of parent element.
 980    /// The fluent API equivalent to [`Interactivity::on_drag`]
 981    ///
 982    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
 983    fn on_drag<T, W>(
 984        mut self,
 985        value: T,
 986        constructor: impl Fn(&T, Point<Pixels>, &mut WindowContext) -> View<W> + 'static,
 987    ) -> Self
 988    where
 989        Self: Sized,
 990        T: 'static,
 991        W: 'static + Render,
 992    {
 993        self.interactivity().on_drag(value, constructor);
 994        self
 995    }
 996
 997    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
 998    /// passed to the callback is true when the hover starts and false when it ends.
 999    /// The fluent API equivalent to [`Interactivity::on_hover`]
1000    ///
1001    /// See [`ViewContext::listener`](crate::ViewContext::listener) to get access to a view's state from this callback.
1002    fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self
1003    where
1004        Self: Sized,
1005    {
1006        self.interactivity().on_hover(listener);
1007        self
1008    }
1009
1010    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1011    /// The fluent API equivalent to [`Interactivity::tooltip`]
1012    fn tooltip(mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self
1013    where
1014        Self: Sized,
1015    {
1016        self.interactivity().tooltip(build_tooltip);
1017        self
1018    }
1019
1020    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1021    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
1022    /// the tooltip. The fluent API equivalent to [`Interactivity::hoverable_tooltip`]
1023    fn hoverable_tooltip(
1024        mut self,
1025        build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static,
1026    ) -> Self
1027    where
1028        Self: Sized,
1029    {
1030        self.interactivity().hoverable_tooltip(build_tooltip);
1031        self
1032    }
1033}
1034
1035/// A trait for providing focus related APIs to interactive elements
1036pub trait FocusableElement: InteractiveElement {
1037    /// Set the given styles to be applied when this element, specifically, is focused.
1038    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1039    where
1040        Self: Sized,
1041    {
1042        self.interactivity().focus_style = Some(Box::new(f(StyleRefinement::default())));
1043        self
1044    }
1045
1046    /// Set the given styles to be applied when this element is inside another element that is focused.
1047    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1048    where
1049        Self: Sized,
1050    {
1051        self.interactivity().in_focus_style = Some(Box::new(f(StyleRefinement::default())));
1052        self
1053    }
1054}
1055
1056pub(crate) type MouseDownListener =
1057    Box<dyn Fn(&MouseDownEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1058pub(crate) type MouseUpListener =
1059    Box<dyn Fn(&MouseUpEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1060
1061pub(crate) type MouseMoveListener =
1062    Box<dyn Fn(&MouseMoveEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1063
1064pub(crate) type ScrollWheelListener =
1065    Box<dyn Fn(&ScrollWheelEvent, DispatchPhase, &Hitbox, &mut WindowContext) + 'static>;
1066
1067pub(crate) type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
1068
1069pub(crate) type DragListener =
1070    Box<dyn Fn(&dyn Any, Point<Pixels>, &mut WindowContext) -> AnyView + 'static>;
1071
1072type DropListener = Box<dyn Fn(&dyn Any, &mut WindowContext) + 'static>;
1073
1074type CanDropPredicate = Box<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>;
1075
1076pub(crate) struct TooltipBuilder {
1077    build: Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>,
1078    hoverable: bool,
1079}
1080
1081pub(crate) type KeyDownListener =
1082    Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
1083
1084pub(crate) type KeyUpListener =
1085    Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + 'static>;
1086
1087pub(crate) type ModifiersChangedListener =
1088    Box<dyn Fn(&ModifiersChangedEvent, &mut WindowContext) + 'static>;
1089
1090pub(crate) type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
1091
1092/// Construct a new [`Div`] element
1093#[track_caller]
1094pub fn div() -> Div {
1095    #[cfg(debug_assertions)]
1096    let interactivity = Interactivity {
1097        location: Some(*core::panic::Location::caller()),
1098        ..Default::default()
1099    };
1100
1101    #[cfg(not(debug_assertions))]
1102    let interactivity = Interactivity::default();
1103
1104    Div {
1105        interactivity,
1106        children: SmallVec::default(),
1107        prepaint_listener: None,
1108    }
1109}
1110
1111/// A [`Div`] element, the all-in-one element for building complex UIs in GPUI
1112pub struct Div {
1113    interactivity: Interactivity,
1114    children: SmallVec<[AnyElement; 2]>,
1115    prepaint_listener: Option<Box<dyn Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static>>,
1116}
1117
1118impl Div {
1119    /// Add a listener to be called when the children of this `Div` are prepainted.
1120    /// This allows you to store the [`Bounds`] of the children for later use.
1121    pub fn on_children_prepainted(
1122        mut self,
1123        listener: impl Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static,
1124    ) -> Self {
1125        self.prepaint_listener = Some(Box::new(listener));
1126        self
1127    }
1128}
1129
1130/// A frame state for a `Div` element, which contains layout IDs for its children.
1131///
1132/// This struct is used internally by the `Div` element to manage the layout state of its children
1133/// during the UI update cycle. It holds a small vector of `LayoutId` values, each corresponding to
1134/// a child element of the `Div`. These IDs are used to query the layout engine for the computed
1135/// bounds of the children after the layout phase is complete.
1136pub struct DivFrameState {
1137    child_layout_ids: SmallVec<[LayoutId; 2]>,
1138}
1139
1140impl Styled for Div {
1141    fn style(&mut self) -> &mut StyleRefinement {
1142        &mut self.interactivity.base_style
1143    }
1144}
1145
1146impl InteractiveElement for Div {
1147    fn interactivity(&mut self) -> &mut Interactivity {
1148        &mut self.interactivity
1149    }
1150}
1151
1152impl ParentElement for Div {
1153    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
1154        self.children.extend(elements)
1155    }
1156}
1157
1158impl Element for Div {
1159    type RequestLayoutState = DivFrameState;
1160    type PrepaintState = Option<Hitbox>;
1161
1162    fn id(&self) -> Option<ElementId> {
1163        self.interactivity.element_id.clone()
1164    }
1165
1166    fn request_layout(
1167        &mut self,
1168        global_id: Option<&GlobalElementId>,
1169        cx: &mut WindowContext,
1170    ) -> (LayoutId, Self::RequestLayoutState) {
1171        let mut child_layout_ids = SmallVec::new();
1172        let layout_id = self
1173            .interactivity
1174            .request_layout(global_id, cx, |style, cx| {
1175                cx.with_text_style(style.text_style().cloned(), |cx| {
1176                    child_layout_ids = self
1177                        .children
1178                        .iter_mut()
1179                        .map(|child| child.request_layout(cx))
1180                        .collect::<SmallVec<_>>();
1181                    cx.request_layout(style, child_layout_ids.iter().copied())
1182                })
1183            });
1184        (layout_id, DivFrameState { child_layout_ids })
1185    }
1186
1187    fn prepaint(
1188        &mut self,
1189        global_id: Option<&GlobalElementId>,
1190        bounds: Bounds<Pixels>,
1191        request_layout: &mut Self::RequestLayoutState,
1192        cx: &mut WindowContext,
1193    ) -> Option<Hitbox> {
1194        let has_prepaint_listener = self.prepaint_listener.is_some();
1195        let mut children_bounds = Vec::with_capacity(if has_prepaint_listener {
1196            request_layout.child_layout_ids.len()
1197        } else {
1198            0
1199        });
1200
1201        let mut child_min = point(Pixels::MAX, Pixels::MAX);
1202        let mut child_max = Point::default();
1203        if let Some(handle) = self.interactivity.scroll_anchor.as_ref() {
1204            *handle.last_origin.borrow_mut() = bounds.origin - cx.element_offset();
1205        }
1206        let content_size = if request_layout.child_layout_ids.is_empty() {
1207            bounds.size
1208        } else if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1209            let mut state = scroll_handle.0.borrow_mut();
1210            state.child_bounds = Vec::with_capacity(request_layout.child_layout_ids.len());
1211            state.bounds = bounds;
1212            let requested = state.requested_scroll_top.take();
1213            // TODO az
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_ref() {
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
1434                    if let Some(active_tooltip) = element_state.active_tooltip.as_ref() {
1435                        if let Some(active_tooltip) = active_tooltip.borrow().as_ref() {
1436                            if let Some(tooltip) = active_tooltip.tooltip.clone() {
1437                                self.tooltip_id = Some(cx.set_tooltip(tooltip));
1438                            }
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            // Ensure to remove active tooltip if tooltip builder is none
1939            if self.tooltip_builder.is_none() {
1940                element_state.active_tooltip.take();
1941            }
1942
1943            if let Some(tooltip_builder) = self.tooltip_builder.take() {
1944                let tooltip_is_hoverable = tooltip_builder.hoverable;
1945                let active_tooltip = element_state
1946                    .active_tooltip
1947                    .get_or_insert_with(Default::default)
1948                    .clone();
1949                let pending_mouse_down = element_state
1950                    .pending_mouse_down
1951                    .get_or_insert_with(Default::default)
1952                    .clone();
1953
1954                cx.on_mouse_event({
1955                    let active_tooltip = active_tooltip.clone();
1956                    let hitbox = hitbox.clone();
1957                    let source_bounds = hitbox.bounds;
1958                    let tooltip_id = self.tooltip_id;
1959                    move |_: &MouseMoveEvent, phase, cx| {
1960                        let is_hovered =
1961                            pending_mouse_down.borrow().is_none() && hitbox.is_hovered(cx);
1962                        let tooltip_is_hovered =
1963                            tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx));
1964                        if !is_hovered && (!tooltip_is_hoverable || !tooltip_is_hovered) {
1965                            if active_tooltip.borrow_mut().take().is_some() {
1966                                cx.refresh();
1967                            }
1968
1969                            return;
1970                        }
1971
1972                        if phase != DispatchPhase::Bubble {
1973                            return;
1974                        }
1975
1976                        if active_tooltip.borrow().is_none() {
1977                            let task = cx.spawn({
1978                                let active_tooltip = active_tooltip.clone();
1979                                let build_tooltip = tooltip_builder.build.clone();
1980                                move |mut cx| async move {
1981                                    cx.background_executor().timer(TOOLTIP_DELAY).await;
1982                                    cx.update(|cx| {
1983                                        active_tooltip.borrow_mut().replace(ActiveTooltip {
1984                                            tooltip: Some(AnyTooltip {
1985                                                view: build_tooltip(cx),
1986                                                mouse_position: cx.mouse_position(),
1987                                                hoverable: tooltip_is_hoverable,
1988                                                origin_bounds: source_bounds,
1989                                            }),
1990                                            _task: None,
1991                                        });
1992                                        cx.refresh();
1993                                    })
1994                                    .ok();
1995                                }
1996                            });
1997                            active_tooltip.borrow_mut().replace(ActiveTooltip {
1998                                tooltip: None,
1999                                _task: Some(task),
2000                            });
2001                        }
2002                    }
2003                });
2004
2005                cx.on_mouse_event({
2006                    let active_tooltip = active_tooltip.clone();
2007                    let tooltip_id = self.tooltip_id;
2008                    move |_: &MouseDownEvent, _, cx| {
2009                        let tooltip_is_hovered =
2010                            tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx));
2011
2012                        if (!tooltip_is_hoverable || !tooltip_is_hovered)
2013                            && active_tooltip.borrow_mut().take().is_some()
2014                        {
2015                            cx.refresh();
2016                        }
2017                    }
2018                });
2019
2020                cx.on_mouse_event({
2021                    let active_tooltip = active_tooltip.clone();
2022                    let tooltip_id = self.tooltip_id;
2023                    move |_: &ScrollWheelEvent, _, cx| {
2024                        let tooltip_is_hovered =
2025                            tooltip_id.map_or(false, |tooltip_id| tooltip_id.is_hovered(cx));
2026                        if (!tooltip_is_hoverable || !tooltip_is_hovered)
2027                            && active_tooltip.borrow_mut().take().is_some()
2028                        {
2029                            cx.refresh();
2030                        }
2031                    }
2032                })
2033            }
2034
2035            let active_state = element_state
2036                .clicked_state
2037                .get_or_insert_with(Default::default)
2038                .clone();
2039            if active_state.borrow().is_clicked() {
2040                cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
2041                    if phase == DispatchPhase::Capture {
2042                        *active_state.borrow_mut() = ElementClickedState::default();
2043                        cx.refresh();
2044                    }
2045                });
2046            } else {
2047                let active_group_hitbox = self
2048                    .group_active_style
2049                    .as_ref()
2050                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
2051                let hitbox = hitbox.clone();
2052                cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
2053                    if phase == DispatchPhase::Bubble && !cx.default_prevented() {
2054                        let group_hovered = active_group_hitbox
2055                            .map_or(false, |group_hitbox_id| group_hitbox_id.is_hovered(cx));
2056                        let element_hovered = hitbox.is_hovered(cx);
2057                        if group_hovered || element_hovered {
2058                            *active_state.borrow_mut() = ElementClickedState {
2059                                group: group_hovered,
2060                                element: element_hovered,
2061                            };
2062                            cx.refresh();
2063                        }
2064                    }
2065                });
2066            }
2067        }
2068    }
2069
2070    fn paint_keyboard_listeners(&mut self, cx: &mut WindowContext) {
2071        let key_down_listeners = mem::take(&mut self.key_down_listeners);
2072        let key_up_listeners = mem::take(&mut self.key_up_listeners);
2073        let modifiers_changed_listeners = mem::take(&mut self.modifiers_changed_listeners);
2074        let action_listeners = mem::take(&mut self.action_listeners);
2075        if let Some(context) = self.key_context.clone() {
2076            cx.set_key_context(context);
2077        }
2078
2079        for listener in key_down_listeners {
2080            cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
2081                listener(event, phase, cx);
2082            })
2083        }
2084
2085        for listener in key_up_listeners {
2086            cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
2087                listener(event, phase, cx);
2088            })
2089        }
2090
2091        for listener in modifiers_changed_listeners {
2092            cx.on_modifiers_changed(move |event: &ModifiersChangedEvent, cx| {
2093                listener(event, cx);
2094            })
2095        }
2096
2097        for (action_type, listener) in action_listeners {
2098            cx.on_action(action_type, listener)
2099        }
2100    }
2101
2102    fn paint_hover_group_handler(&self, cx: &mut WindowContext) {
2103        let group_hitbox = self
2104            .group_hover_style
2105            .as_ref()
2106            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
2107
2108        if let Some(group_hitbox) = group_hitbox {
2109            let was_hovered = group_hitbox.is_hovered(cx);
2110            cx.on_mouse_event(move |_: &MouseMoveEvent, phase, cx| {
2111                let hovered = group_hitbox.is_hovered(cx);
2112                if phase == DispatchPhase::Capture && hovered != was_hovered {
2113                    cx.refresh();
2114                }
2115            });
2116        }
2117    }
2118
2119    fn paint_scroll_listener(&self, hitbox: &Hitbox, style: &Style, cx: &mut WindowContext) {
2120        if let Some(scroll_offset) = self.scroll_offset.clone() {
2121            let overflow = style.overflow;
2122            let allow_concurrent_scroll = style.allow_concurrent_scroll;
2123            let line_height = cx.line_height();
2124            let hitbox = hitbox.clone();
2125            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
2126                if phase == DispatchPhase::Bubble && hitbox.is_hovered(cx) {
2127                    let mut scroll_offset = scroll_offset.borrow_mut();
2128                    let old_scroll_offset = *scroll_offset;
2129                    let delta = event.delta.pixel_delta(line_height);
2130
2131                    let mut delta_x = Pixels::ZERO;
2132                    if overflow.x == Overflow::Scroll {
2133                        if !delta.x.is_zero() {
2134                            delta_x = delta.x;
2135                        } else if overflow.y != Overflow::Scroll {
2136                            delta_x = delta.y;
2137                        }
2138                    }
2139                    let mut delta_y = Pixels::ZERO;
2140                    if overflow.y == Overflow::Scroll {
2141                        if !delta.y.is_zero() {
2142                            delta_y = delta.y;
2143                        } else if overflow.x != Overflow::Scroll {
2144                            delta_y = delta.x;
2145                        }
2146                    }
2147                    if !allow_concurrent_scroll && !delta_x.is_zero() && !delta_y.is_zero() {
2148                        if delta_x.abs() > delta_y.abs() {
2149                            delta_y = Pixels::ZERO;
2150                        } else {
2151                            delta_x = Pixels::ZERO;
2152                        }
2153                    }
2154                    scroll_offset.y += delta_y;
2155                    scroll_offset.x += delta_x;
2156                    cx.stop_propagation();
2157                    if *scroll_offset != old_scroll_offset {
2158                        cx.refresh();
2159                    }
2160                }
2161            });
2162        }
2163    }
2164
2165    /// Compute the visual style for this element, based on the current bounds and the element's state.
2166    pub fn compute_style(
2167        &self,
2168        global_id: Option<&GlobalElementId>,
2169        hitbox: Option<&Hitbox>,
2170        cx: &mut WindowContext,
2171    ) -> Style {
2172        cx.with_optional_element_state(global_id, |element_state, cx| {
2173            let mut element_state =
2174                element_state.map(|element_state| element_state.unwrap_or_default());
2175            let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
2176            (style, element_state)
2177        })
2178    }
2179
2180    /// Called from internal methods that have already called with_element_state.
2181    fn compute_style_internal(
2182        &self,
2183        hitbox: Option<&Hitbox>,
2184        element_state: Option<&mut InteractiveElementState>,
2185        cx: &mut WindowContext,
2186    ) -> Style {
2187        let mut style = Style::default();
2188        style.refine(&self.base_style);
2189
2190        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
2191            if let Some(in_focus_style) = self.in_focus_style.as_ref() {
2192                if focus_handle.within_focused(cx) {
2193                    style.refine(in_focus_style);
2194                }
2195            }
2196
2197            if let Some(focus_style) = self.focus_style.as_ref() {
2198                if focus_handle.is_focused(cx) {
2199                    style.refine(focus_style);
2200                }
2201            }
2202        }
2203
2204        if let Some(hitbox) = hitbox {
2205            if !cx.has_active_drag() {
2206                if let Some(group_hover) = self.group_hover_style.as_ref() {
2207                    if let Some(group_hitbox_id) =
2208                        GroupHitboxes::get(&group_hover.group, cx.deref_mut())
2209                    {
2210                        if group_hitbox_id.is_hovered(cx) {
2211                            style.refine(&group_hover.style);
2212                        }
2213                    }
2214                }
2215
2216                if let Some(hover_style) = self.hover_style.as_ref() {
2217                    if hitbox.is_hovered(cx) {
2218                        style.refine(hover_style);
2219                    }
2220                }
2221            }
2222
2223            if let Some(drag) = cx.active_drag.take() {
2224                let mut can_drop = true;
2225                if let Some(can_drop_predicate) = &self.can_drop_predicate {
2226                    can_drop = can_drop_predicate(drag.value.as_ref(), cx);
2227                }
2228
2229                if can_drop {
2230                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
2231                        if let Some(group_hitbox_id) =
2232                            GroupHitboxes::get(&group_drag_style.group, cx.deref_mut())
2233                        {
2234                            if *state_type == drag.value.as_ref().type_id()
2235                                && group_hitbox_id.is_hovered(cx)
2236                            {
2237                                style.refine(&group_drag_style.style);
2238                            }
2239                        }
2240                    }
2241
2242                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
2243                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(cx) {
2244                            style.refine(&build_drag_over_style(drag.value.as_ref(), cx));
2245                        }
2246                    }
2247                }
2248
2249                cx.active_drag = Some(drag);
2250            }
2251        }
2252
2253        if let Some(element_state) = element_state {
2254            let clicked_state = element_state
2255                .clicked_state
2256                .get_or_insert_with(Default::default)
2257                .borrow();
2258            if clicked_state.group {
2259                if let Some(group) = self.group_active_style.as_ref() {
2260                    style.refine(&group.style)
2261                }
2262            }
2263
2264            if let Some(active_style) = self.active_style.as_ref() {
2265                if clicked_state.element {
2266                    style.refine(active_style)
2267                }
2268            }
2269        }
2270
2271        style
2272    }
2273}
2274
2275/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
2276/// and scroll offsets.
2277#[derive(Default)]
2278pub struct InteractiveElementState {
2279    pub(crate) focus_handle: Option<FocusHandle>,
2280    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
2281    pub(crate) hover_state: Option<Rc<RefCell<bool>>>,
2282    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
2283    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
2284    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
2285}
2286
2287/// The current active tooltip
2288pub struct ActiveTooltip {
2289    pub(crate) tooltip: Option<AnyTooltip>,
2290    pub(crate) _task: Option<Task<()>>,
2291}
2292
2293/// Whether or not the element or a group that contains it is clicked by the mouse.
2294#[derive(Copy, Clone, Default, Eq, PartialEq)]
2295pub struct ElementClickedState {
2296    /// True if this element's group has been clicked, false otherwise
2297    pub group: bool,
2298
2299    /// True if this element has been clicked, false otherwise
2300    pub element: bool,
2301}
2302
2303impl ElementClickedState {
2304    fn is_clicked(&self) -> bool {
2305        self.group || self.element
2306    }
2307}
2308
2309#[derive(Default)]
2310pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
2311
2312impl Global for GroupHitboxes {}
2313
2314impl GroupHitboxes {
2315    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<HitboxId> {
2316        cx.default_global::<Self>()
2317            .0
2318            .get(name)
2319            .and_then(|bounds_stack| bounds_stack.last())
2320            .cloned()
2321    }
2322
2323    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut AppContext) {
2324        cx.default_global::<Self>()
2325            .0
2326            .entry(name)
2327            .or_default()
2328            .push(hitbox_id);
2329    }
2330
2331    pub fn pop(name: &SharedString, cx: &mut AppContext) {
2332        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
2333    }
2334}
2335
2336/// A wrapper around an element that can be focused.
2337pub struct Focusable<E> {
2338    /// The element that is focusable
2339    pub element: E,
2340}
2341
2342impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
2343
2344impl<E> InteractiveElement for Focusable<E>
2345where
2346    E: InteractiveElement,
2347{
2348    fn interactivity(&mut self) -> &mut Interactivity {
2349        self.element.interactivity()
2350    }
2351}
2352
2353impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
2354
2355impl<E> Styled for Focusable<E>
2356where
2357    E: Styled,
2358{
2359    fn style(&mut self) -> &mut StyleRefinement {
2360        self.element.style()
2361    }
2362}
2363
2364impl Focusable<Div> {
2365    /// Add a listener to be called when the children of this `Div` are prepainted.
2366    /// This allows you to store the [`Bounds`] of the children for later use.
2367    pub fn on_children_prepainted(
2368        mut self,
2369        listener: impl Fn(Vec<Bounds<Pixels>>, &mut WindowContext) + 'static,
2370    ) -> Self {
2371        self.element = self.element.on_children_prepainted(listener);
2372        self
2373    }
2374}
2375
2376impl<E> Element for Focusable<E>
2377where
2378    E: Element,
2379{
2380    type RequestLayoutState = E::RequestLayoutState;
2381    type PrepaintState = E::PrepaintState;
2382
2383    fn id(&self) -> Option<ElementId> {
2384        self.element.id()
2385    }
2386
2387    fn request_layout(
2388        &mut self,
2389        id: Option<&GlobalElementId>,
2390        cx: &mut WindowContext,
2391    ) -> (LayoutId, Self::RequestLayoutState) {
2392        self.element.request_layout(id, cx)
2393    }
2394
2395    fn prepaint(
2396        &mut self,
2397        id: Option<&GlobalElementId>,
2398        bounds: Bounds<Pixels>,
2399        state: &mut Self::RequestLayoutState,
2400        cx: &mut WindowContext,
2401    ) -> E::PrepaintState {
2402        self.element.prepaint(id, bounds, state, cx)
2403    }
2404
2405    fn paint(
2406        &mut self,
2407        id: Option<&GlobalElementId>,
2408        bounds: Bounds<Pixels>,
2409        request_layout: &mut Self::RequestLayoutState,
2410        prepaint: &mut Self::PrepaintState,
2411        cx: &mut WindowContext,
2412    ) {
2413        self.element.paint(id, bounds, request_layout, prepaint, cx)
2414    }
2415}
2416
2417impl<E> IntoElement for Focusable<E>
2418where
2419    E: IntoElement,
2420{
2421    type Element = E::Element;
2422
2423    fn into_element(self) -> Self::Element {
2424        self.element.into_element()
2425    }
2426}
2427
2428impl<E> ParentElement for Focusable<E>
2429where
2430    E: ParentElement,
2431{
2432    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
2433        self.element.extend(elements)
2434    }
2435}
2436
2437/// A wrapper around an element that can store state, produced after assigning an ElementId.
2438pub struct Stateful<E> {
2439    pub(crate) element: E,
2440}
2441
2442impl<E> Styled for Stateful<E>
2443where
2444    E: Styled,
2445{
2446    fn style(&mut self) -> &mut StyleRefinement {
2447        self.element.style()
2448    }
2449}
2450
2451impl<E> StatefulInteractiveElement for Stateful<E>
2452where
2453    E: Element,
2454    Self: InteractiveElement,
2455{
2456}
2457
2458impl<E> InteractiveElement for Stateful<E>
2459where
2460    E: InteractiveElement,
2461{
2462    fn interactivity(&mut self) -> &mut Interactivity {
2463        self.element.interactivity()
2464    }
2465}
2466
2467impl<E: FocusableElement> FocusableElement for Stateful<E> {}
2468
2469impl<E> Element for Stateful<E>
2470where
2471    E: Element,
2472{
2473    type RequestLayoutState = E::RequestLayoutState;
2474    type PrepaintState = E::PrepaintState;
2475
2476    fn id(&self) -> Option<ElementId> {
2477        self.element.id()
2478    }
2479
2480    fn request_layout(
2481        &mut self,
2482        id: Option<&GlobalElementId>,
2483        cx: &mut WindowContext,
2484    ) -> (LayoutId, Self::RequestLayoutState) {
2485        self.element.request_layout(id, cx)
2486    }
2487
2488    fn prepaint(
2489        &mut self,
2490        id: Option<&GlobalElementId>,
2491        bounds: Bounds<Pixels>,
2492        state: &mut Self::RequestLayoutState,
2493        cx: &mut WindowContext,
2494    ) -> E::PrepaintState {
2495        self.element.prepaint(id, bounds, state, cx)
2496    }
2497
2498    fn paint(
2499        &mut self,
2500        id: Option<&GlobalElementId>,
2501        bounds: Bounds<Pixels>,
2502        request_layout: &mut Self::RequestLayoutState,
2503        prepaint: &mut Self::PrepaintState,
2504        cx: &mut WindowContext,
2505    ) {
2506        self.element.paint(id, bounds, request_layout, prepaint, cx);
2507    }
2508}
2509
2510impl<E> IntoElement for Stateful<E>
2511where
2512    E: Element,
2513{
2514    type Element = Self;
2515
2516    fn into_element(self) -> Self::Element {
2517        self
2518    }
2519}
2520
2521impl<E> ParentElement for Stateful<E>
2522where
2523    E: ParentElement,
2524{
2525    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
2526        self.element.extend(elements)
2527    }
2528}
2529
2530/// Represents an element that can be scrolled *to* in its parent element.
2531///
2532/// Contrary to [ScrollHandle::scroll_to_item], an anchored element does not have to be an immediate child of the parent.
2533#[derive(Clone)]
2534pub struct ScrollAnchor {
2535    handle: ScrollHandle,
2536    last_origin: Rc<RefCell<Point<Pixels>>>,
2537}
2538
2539impl ScrollAnchor {
2540    /// Creates a [ScrollAnchor] associated with a given [ScrollHandle].
2541    pub fn for_handle(handle: ScrollHandle) -> Self {
2542        Self {
2543            handle,
2544            last_origin: Default::default(),
2545        }
2546    }
2547    /// Request scroll to this item on the next frame.
2548    pub fn scroll_to(&self, cx: &mut WindowContext) {
2549        let this = self.clone();
2550
2551        cx.on_next_frame(move |_| {
2552            let viewport_bounds = this.handle.bounds();
2553            let self_bounds = *this.last_origin.borrow();
2554            this.handle.set_offset(viewport_bounds.origin - self_bounds);
2555        });
2556    }
2557}
2558#[derive(Default, Debug)]
2559struct ScrollHandleState {
2560    offset: Rc<RefCell<Point<Pixels>>>,
2561    bounds: Bounds<Pixels>,
2562    child_bounds: Vec<Bounds<Pixels>>,
2563    requested_scroll_top: Option<(usize, Pixels)>,
2564    overflow: Point<Overflow>,
2565}
2566
2567/// A handle to the scrollable aspects of an element.
2568/// Used for accessing scroll state, like the current scroll offset,
2569/// and for mutating the scroll state, like scrolling to a specific child.
2570#[derive(Clone, Debug)]
2571pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
2572
2573impl Default for ScrollHandle {
2574    fn default() -> Self {
2575        Self::new()
2576    }
2577}
2578
2579impl ScrollHandle {
2580    /// Construct a new scroll handle.
2581    pub fn new() -> Self {
2582        Self(Rc::default())
2583    }
2584
2585    /// Get the current scroll offset.
2586    pub fn offset(&self) -> Point<Pixels> {
2587        *self.0.borrow().offset.borrow()
2588    }
2589
2590    /// Get the top child that's scrolled into view.
2591    pub fn top_item(&self) -> usize {
2592        let state = self.0.borrow();
2593        let top = state.bounds.top() - state.offset.borrow().y;
2594
2595        match state.child_bounds.binary_search_by(|bounds| {
2596            if top < bounds.top() {
2597                Ordering::Greater
2598            } else if top > bounds.bottom() {
2599                Ordering::Less
2600            } else {
2601                Ordering::Equal
2602            }
2603        }) {
2604            Ok(ix) => ix,
2605            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
2606        }
2607    }
2608
2609    /// Return the bounds into which this child is painted
2610    pub fn bounds(&self) -> Bounds<Pixels> {
2611        self.0.borrow().bounds
2612    }
2613
2614    /// Set the bounds into which this child is painted
2615    pub(super) fn set_bounds(&self, bounds: Bounds<Pixels>) {
2616        self.0.borrow_mut().bounds = bounds;
2617    }
2618
2619    /// Get the bounds for a specific child.
2620    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
2621        self.0.borrow().child_bounds.get(ix).cloned()
2622    }
2623
2624    /// scroll_to_item scrolls the minimal amount to ensure that the child is
2625    /// fully visible
2626    pub fn scroll_to_item(&self, ix: usize) {
2627        let state = self.0.borrow();
2628
2629        let Some(bounds) = state.child_bounds.get(ix) else {
2630            return;
2631        };
2632
2633        let mut scroll_offset = state.offset.borrow_mut();
2634
2635        if state.overflow.y == Overflow::Scroll {
2636            if bounds.top() + scroll_offset.y < state.bounds.top() {
2637                scroll_offset.y = state.bounds.top() - bounds.top();
2638            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
2639                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
2640            }
2641        }
2642
2643        if state.overflow.x == Overflow::Scroll {
2644            if bounds.left() + scroll_offset.x < state.bounds.left() {
2645                scroll_offset.x = state.bounds.left() - bounds.left();
2646            } else if bounds.right() + scroll_offset.x > state.bounds.right() {
2647                scroll_offset.x = state.bounds.right() - bounds.right();
2648            }
2649        }
2650    }
2651
2652    /// Set the offset explicitly. The offset is the distance from the top left of the
2653    /// parent container to the top left of the first child.
2654    /// As you scroll further down the offset becomes more negative.
2655    pub fn set_offset(&self, mut position: Point<Pixels>) {
2656        let state = self.0.borrow();
2657        *state.offset.borrow_mut() = position;
2658    }
2659
2660    /// Get the logical scroll top, based on a child index and a pixel offset.
2661    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
2662        let ix = self.top_item();
2663        let state = self.0.borrow();
2664
2665        if let Some(child_bounds) = state.child_bounds.get(ix) {
2666            (
2667                ix,
2668                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
2669            )
2670        } else {
2671            (ix, px(0.))
2672        }
2673    }
2674
2675    /// Set the logical scroll top, based on a child index and a pixel offset.
2676    pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
2677        self.0.borrow_mut().requested_scroll_top = Some((ix, px));
2678    }
2679
2680    /// Get the count of children for scrollable item.
2681    pub fn children_count(&self) -> usize {
2682        self.0.borrow().child_bounds.len()
2683    }
2684}