gpui/elements/
div.rs

1//! Div is the central, reusable element that most GPUI trees will be built from.
2//! It functions as a container for other elements, and provides a number of
3//! useful features for laying out and styling its children as well as binding
4//! mouse events and action handlers. It is meant to be similar to the HTML `<div>`
5//! element, but for GPUI.
6//!
7//! # Build your own div
8//!
9//! GPUI does not directly provide APIs for stateful, multi step events like `click`
10//! and `drag`. We want GPUI users to be able to build their own abstractions for
11//! their own needs. However, as a UI framework, we're also obliged to provide some
12//! building blocks to make the process of building your own elements easier.
13//! For this we have the [`Interactivity`] and the [`StyleRefinement`] structs, as well
14//! as several associated traits. Together, these provide the full suite of Dom-like events
15//! and Tailwind-like styling that you can use to build your own custom elements. Div is
16//! constructed by combining these two systems into an all-in-one element.
17
18use crate::{
19    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.
586    /// The imperative API equivalent to [`InteractiveElement::block_mouse_except_scroll`].
587    ///
588    /// See [`Hitbox::is_hovered`] for details.
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::capture_action`].
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.
1010    /// The fluent API equivalent to [`Interactivity::block_mouse_except_scroll`].
1011    ///
1012    /// See [`Hitbox::is_hovered`] for details.
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}