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