Skip to main content

open_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::PinchEvent;
19use crate::{
20    Action, AnyDrag, AnyElement, AnyTooltip, AnyView, App, Bounds, ClickEvent, DispatchPhase,
21    Display, Element, ElementId, Entity, EntityId, FocusHandle, Global, GlobalElementId, Hitbox,
22    HitboxBehavior, HitboxId, InspectorElementId, IntoElement, IsZero, KeyContext, KeyDownEvent,
23    KeyUpEvent, KeyboardButton, KeyboardClickEvent, LayoutId, ModifiersChangedEvent, MouseButton,
24    MouseClickEvent, MouseDownEvent, MouseMoveEvent, MousePressureEvent, MouseUpEvent, Overflow,
25    ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
26    StyleRefinement, Styled, Task, TooltipId, Visibility, Window, WindowControlArea, point, px,
27    size,
28};
29use open_gpui_collections::HashMap;
30use open_gpui_core_util::ResultExt;
31use open_gpui_refineable::Refineable;
32use smallvec::SmallVec;
33use stacksafe::{StackSafe, stacksafe};
34use std::{
35    any::{Any, TypeId},
36    cell::RefCell,
37    cmp::Ordering,
38    fmt::Debug,
39    marker::PhantomData,
40    mem,
41    rc::Rc,
42    sync::Arc,
43    time::Duration,
44};
45
46use super::ImageCacheProvider;
47
48const DRAG_THRESHOLD: f64 = 2.;
49const DEFAULT_TOOLTIP_SHOW_DELAY: Duration = Duration::from_millis(500);
50const HOVERABLE_TOOLTIP_HIDE_DELAY: Duration = Duration::from_millis(500);
51
52/// The styling information for a given group.
53pub struct GroupStyle {
54    /// The identifier for this group.
55    pub group: SharedString,
56
57    /// The specific style refinement that this group would apply
58    /// to its children.
59    pub style: Box<StyleRefinement>,
60}
61
62/// An event for when a drag is moving over this element, with the given state type.
63pub struct DragMoveEvent<T> {
64    /// The mouse move event that triggered this drag move event.
65    pub event: MouseMoveEvent,
66
67    /// The bounds of this element.
68    pub bounds: Bounds<Pixels>,
69    drag: PhantomData<T>,
70    dragged_item: Arc<dyn Any>,
71}
72
73impl<T: 'static> DragMoveEvent<T> {
74    /// Returns the drag state for this event.
75    pub fn drag<'b>(&self, cx: &'b App) -> &'b T {
76        cx.active_drag
77            .as_ref()
78            .and_then(|drag| drag.value.downcast_ref::<T>())
79            .expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
80    }
81
82    /// An item that is about to be dropped.
83    pub fn dragged_item(&self) -> &dyn Any {
84        self.dragged_item.as_ref()
85    }
86}
87
88impl Interactivity {
89    /// Create an `Interactivity`, capturing the caller location in debug mode.
90    #[cfg(any(feature = "inspector", debug_assertions))]
91    #[track_caller]
92    pub fn new() -> Interactivity {
93        Interactivity {
94            source_location: Some(core::panic::Location::caller()),
95            ..Default::default()
96        }
97    }
98
99    /// Create an `Interactivity`, capturing the caller location in debug mode.
100    #[cfg(not(any(feature = "inspector", debug_assertions)))]
101    pub fn new() -> Interactivity {
102        Interactivity::default()
103    }
104
105    /// Gets the source location of construction. Returns `None` when not in debug mode.
106    pub fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
107        #[cfg(any(feature = "inspector", debug_assertions))]
108        {
109            self.source_location
110        }
111
112        #[cfg(not(any(feature = "inspector", debug_assertions)))]
113        {
114            None
115        }
116    }
117
118    /// Bind the given callback to the mouse down event for the given mouse button, during the bubble phase.
119    /// The imperative API equivalent of [`InteractiveElement::on_mouse_down`].
120    ///
121    /// See [`Context::listener`](crate::Context::listener) to get access to the view state from this callback.
122    pub fn on_mouse_down(
123        &mut self,
124        button: MouseButton,
125        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
126    ) {
127        self.mouse_down_listeners
128            .push(Box::new(move |event, phase, hitbox, window, cx| {
129                if phase == DispatchPhase::Bubble
130                    && event.button == button
131                    && hitbox.is_hovered(window)
132                {
133                    (listener)(event, window, cx)
134                }
135            }));
136    }
137
138    /// Bind the given callback to the mouse down event for any button, during the capture phase.
139    /// The imperative API equivalent of [`InteractiveElement::capture_any_mouse_down`].
140    ///
141    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
142    pub fn capture_any_mouse_down(
143        &mut self,
144        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
145    ) {
146        self.mouse_down_listeners
147            .push(Box::new(move |event, phase, hitbox, window, cx| {
148                if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
149                    (listener)(event, window, cx)
150                }
151            }));
152    }
153
154    /// Bind the given callback to the mouse down event for any button, during the bubble phase.
155    /// The imperative API equivalent to [`InteractiveElement::on_any_mouse_down`].
156    ///
157    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
158    pub fn on_any_mouse_down(
159        &mut self,
160        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
161    ) {
162        self.mouse_down_listeners
163            .push(Box::new(move |event, phase, hitbox, window, cx| {
164                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
165                    (listener)(event, window, cx)
166                }
167            }));
168    }
169
170    /// Bind the given callback to the mouse pressure event, during the bubble phase
171    /// the imperative API equivalent to [`InteractiveElement::on_mouse_pressure`].
172    ///
173    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
174    pub fn on_mouse_pressure(
175        &mut self,
176        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
177    ) {
178        self.mouse_pressure_listeners
179            .push(Box::new(move |event, phase, hitbox, window, cx| {
180                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
181                    (listener)(event, window, cx)
182                }
183            }));
184    }
185
186    /// Bind the given callback to the mouse pressure event, during the capture phase
187    /// the imperative API equivalent to [`InteractiveElement::on_mouse_pressure`].
188    ///
189    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
190    pub fn capture_mouse_pressure(
191        &mut self,
192        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
193    ) {
194        self.mouse_pressure_listeners
195            .push(Box::new(move |event, phase, hitbox, window, cx| {
196                if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
197                    (listener)(event, window, cx)
198                }
199            }));
200    }
201
202    /// Bind the given callback to the mouse up event for the given button, during the bubble phase.
203    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up`].
204    ///
205    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
206    pub fn on_mouse_up(
207        &mut self,
208        button: MouseButton,
209        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
210    ) {
211        self.mouse_up_listeners
212            .push(Box::new(move |event, phase, hitbox, window, cx| {
213                if phase == DispatchPhase::Bubble
214                    && event.button == button
215                    && hitbox.is_hovered(window)
216                {
217                    (listener)(event, window, cx)
218                }
219            }));
220    }
221
222    /// Bind the given callback to the mouse up event for any button, during the capture phase.
223    /// The imperative API equivalent to [`InteractiveElement::capture_any_mouse_up`].
224    ///
225    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
226    pub fn capture_any_mouse_up(
227        &mut self,
228        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
229    ) {
230        self.mouse_up_listeners
231            .push(Box::new(move |event, phase, hitbox, window, cx| {
232                if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
233                    (listener)(event, window, cx)
234                }
235            }));
236    }
237
238    /// Bind the given callback to the mouse up event for any button, during the bubble phase.
239    /// The imperative API equivalent to [`Interactivity::on_any_mouse_up`].
240    ///
241    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
242    pub fn on_any_mouse_up(
243        &mut self,
244        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
245    ) {
246        self.mouse_up_listeners
247            .push(Box::new(move |event, phase, hitbox, window, cx| {
248                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
249                    (listener)(event, window, cx)
250                }
251            }));
252    }
253
254    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
255    /// when the mouse is outside of the bounds of this element.
256    /// The imperative API equivalent to [`InteractiveElement::on_mouse_down_out`].
257    ///
258    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
259    pub fn on_mouse_down_out(
260        &mut self,
261        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
262    ) {
263        self.mouse_down_listeners
264            .push(Box::new(move |event, phase, hitbox, window, cx| {
265                if phase == DispatchPhase::Capture && !hitbox.contains(&window.mouse_position()) {
266                    (listener)(event, window, cx)
267                }
268            }));
269    }
270
271    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
272    /// when the mouse is outside of the bounds of this element.
273    /// The imperative API equivalent to [`InteractiveElement::on_mouse_up_out`].
274    ///
275    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
276    pub fn on_mouse_up_out(
277        &mut self,
278        button: MouseButton,
279        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
280    ) {
281        self.mouse_up_listeners
282            .push(Box::new(move |event, phase, hitbox, window, cx| {
283                if phase == DispatchPhase::Capture
284                    && event.button == button
285                    && !hitbox.is_hovered(window)
286                {
287                    (listener)(event, window, cx);
288                }
289            }));
290    }
291
292    /// Bind the given callback to the mouse move event, during the bubble phase.
293    /// The imperative API equivalent to [`InteractiveElement::on_mouse_move`].
294    ///
295    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
296    pub fn on_mouse_move(
297        &mut self,
298        listener: impl Fn(&MouseMoveEvent, &mut Window, &mut App) + 'static,
299    ) {
300        self.mouse_move_listeners
301            .push(Box::new(move |event, phase, hitbox, window, cx| {
302                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
303                    (listener)(event, window, cx);
304                }
305            }));
306    }
307
308    /// Bind the given callback to the mouse drag event of the given type. Note that this
309    /// will be called for all move events, inside or outside of this element, as long as the
310    /// drag was started with this element under the mouse. Useful for implementing draggable
311    /// UIs that don't conform to a drag and drop style interaction, like resizing.
312    /// The imperative API equivalent to [`InteractiveElement::on_drag_move`].
313    ///
314    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
315    pub fn on_drag_move<T>(
316        &mut self,
317        listener: impl Fn(&DragMoveEvent<T>, &mut Window, &mut App) + 'static,
318    ) where
319        T: 'static,
320    {
321        self.mouse_move_listeners
322            .push(Box::new(move |event, phase, hitbox, window, cx| {
323                if phase == DispatchPhase::Capture
324                    && let Some(drag) = &cx.active_drag
325                    && drag.value.as_ref().type_id() == TypeId::of::<T>()
326                {
327                    (listener)(
328                        &DragMoveEvent {
329                            event: event.clone(),
330                            bounds: hitbox.bounds,
331                            drag: PhantomData,
332                            dragged_item: Arc::clone(&drag.value),
333                        },
334                        window,
335                        cx,
336                    );
337                }
338            }));
339    }
340
341    /// Bind the given callback to scroll wheel events during the bubble phase.
342    /// The imperative API equivalent to [`InteractiveElement::on_scroll_wheel`].
343    ///
344    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
345    pub fn on_scroll_wheel(
346        &mut self,
347        listener: impl Fn(&ScrollWheelEvent, &mut Window, &mut App) + 'static,
348    ) {
349        self.scroll_wheel_listeners
350            .push(Box::new(move |event, phase, hitbox, window, cx| {
351                if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
352                    (listener)(event, window, cx);
353                }
354            }));
355    }
356
357    /// Bind the given callback to pinch gesture events during the bubble phase.
358    ///
359    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
360    pub fn on_pinch(&mut self, listener: impl Fn(&PinchEvent, &mut Window, &mut App) + 'static) {
361        self.pinch_listeners
362            .push(Box::new(move |event, phase, hitbox, window, cx| {
363                if phase == DispatchPhase::Bubble && hitbox.is_hovered(window) {
364                    (listener)(event, window, cx);
365                }
366            }));
367    }
368
369    /// Bind the given callback to pinch gesture events during the capture phase.
370    ///
371    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
372    pub fn capture_pinch(
373        &mut self,
374        listener: impl Fn(&PinchEvent, &mut Window, &mut App) + 'static,
375    ) {
376        self.pinch_listeners
377            .push(Box::new(move |event, phase, _hitbox, window, cx| {
378                if phase == DispatchPhase::Capture {
379                    (listener)(event, window, cx);
380                } else {
381                    cx.propagate();
382                }
383            }));
384    }
385
386    /// Bind the given callback to an action dispatch during the capture phase.
387    /// The imperative API equivalent to [`InteractiveElement::capture_action`].
388    ///
389    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
390    pub fn capture_action<A: Action>(
391        &mut self,
392        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
393    ) {
394        self.action_listeners.push((
395            TypeId::of::<A>(),
396            Box::new(move |action, phase, window, cx| {
397                let action = action.downcast_ref().unwrap();
398                if phase == DispatchPhase::Capture {
399                    (listener)(action, window, cx)
400                } else {
401                    cx.propagate();
402                }
403            }),
404        ));
405    }
406
407    /// Bind the given callback to an action dispatch during the bubble phase.
408    /// The imperative API equivalent to [`InteractiveElement::on_action`].
409    ///
410    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
411    #[track_caller]
412    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Window, &mut App) + 'static) {
413        self.action_listeners.push((
414            TypeId::of::<A>(),
415            Box::new(move |action, phase, window, cx| {
416                let action = action.downcast_ref().unwrap();
417                if phase == DispatchPhase::Bubble {
418                    (listener)(action, window, cx)
419                }
420            }),
421        ));
422    }
423
424    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
425    /// instead of a type parameter. Useful for component libraries that want to expose
426    /// action bindings to their users.
427    /// The imperative API equivalent to [`InteractiveElement::on_boxed_action`].
428    ///
429    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
430    pub fn on_boxed_action(
431        &mut self,
432        action: &dyn Action,
433        listener: impl Fn(&dyn Action, &mut Window, &mut App) + 'static,
434    ) {
435        let action = action.boxed_clone();
436        self.action_listeners.push((
437            (*action).type_id(),
438            Box::new(move |_, phase, window, cx| {
439                if phase == DispatchPhase::Bubble {
440                    (listener)(&*action, window, cx)
441                }
442            }),
443        ));
444    }
445
446    /// Bind the given callback to key down events during the bubble phase.
447    /// The imperative API equivalent to [`InteractiveElement::on_key_down`].
448    ///
449    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
450    pub fn on_key_down(
451        &mut self,
452        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
453    ) {
454        self.key_down_listeners
455            .push(Box::new(move |event, phase, window, cx| {
456                if phase == DispatchPhase::Bubble {
457                    (listener)(event, window, cx)
458                }
459            }));
460    }
461
462    /// Bind the given callback to key down events during the capture phase.
463    /// The imperative API equivalent to [`InteractiveElement::capture_key_down`].
464    ///
465    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
466    pub fn capture_key_down(
467        &mut self,
468        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
469    ) {
470        self.key_down_listeners
471            .push(Box::new(move |event, phase, window, cx| {
472                if phase == DispatchPhase::Capture {
473                    listener(event, window, cx)
474                }
475            }));
476    }
477
478    /// Bind the given callback to key up events during the bubble phase.
479    /// The imperative API equivalent to [`InteractiveElement::on_key_up`].
480    ///
481    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
482    pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static) {
483        self.key_up_listeners
484            .push(Box::new(move |event, phase, window, cx| {
485                if phase == DispatchPhase::Bubble {
486                    listener(event, window, cx)
487                }
488            }));
489    }
490
491    /// Bind the given callback to key up events during the capture phase.
492    /// The imperative API equivalent to [`InteractiveElement::on_key_up`].
493    ///
494    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
495    pub fn capture_key_up(
496        &mut self,
497        listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static,
498    ) {
499        self.key_up_listeners
500            .push(Box::new(move |event, phase, window, cx| {
501                if phase == DispatchPhase::Capture {
502                    listener(event, window, cx)
503                }
504            }));
505    }
506
507    /// Bind the given callback to modifiers changing events.
508    /// The imperative API equivalent to [`InteractiveElement::on_modifiers_changed`].
509    ///
510    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
511    pub fn on_modifiers_changed(
512        &mut self,
513        listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
514    ) {
515        self.modifiers_changed_listeners
516            .push(Box::new(move |event, window, cx| {
517                listener(event, window, cx)
518            }));
519    }
520
521    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element.
522    /// The imperative API equivalent to [`InteractiveElement::on_drop`].
523    ///
524    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
525    pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut Window, &mut App) + 'static) {
526        self.drop_listeners.push((
527            TypeId::of::<T>(),
528            Box::new(move |dragged_value, window, cx| {
529                listener(dragged_value.downcast_ref().unwrap(), window, cx);
530            }),
531        ));
532    }
533
534    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element.
535    /// The imperative API equivalent to [`InteractiveElement::can_drop`].
536    pub fn can_drop(
537        &mut self,
538        predicate: impl Fn(&dyn Any, &mut Window, &mut App) -> bool + 'static,
539    ) {
540        self.can_drop_predicate = Some(Box::new(predicate));
541    }
542
543    /// Bind the given callback to click events of this element.
544    /// The imperative API equivalent to [`StatefulInteractiveElement::on_click`].
545    ///
546    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
547    pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static)
548    where
549        Self: Sized,
550    {
551        self.click_listeners.push(Rc::new(move |event, window, cx| {
552            listener(event, window, cx)
553        }));
554    }
555
556    /// Bind the given callback to non-primary click events of this element.
557    /// The imperative API equivalent to [`StatefulInteractiveElement::on_aux_click`].
558    ///
559    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
560    pub fn on_aux_click(&mut self, listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static)
561    where
562        Self: Sized,
563    {
564        self.aux_click_listeners
565            .push(Rc::new(move |event, window, cx| {
566                listener(event, window, cx)
567            }));
568    }
569
570    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
571    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
572    /// the [`Self::on_drag_move`] API.
573    /// The imperative API equivalent to [`StatefulInteractiveElement::on_drag`].
574    ///
575    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
576    pub fn on_drag<T, W>(
577        &mut self,
578        value: T,
579        constructor: impl Fn(&T, Point<Pixels>, Bounds<Pixels>, &mut Window, &mut App) -> Entity<W>
580        + 'static,
581    ) where
582        Self: Sized,
583        T: 'static,
584        W: 'static + Render,
585    {
586        debug_assert!(
587            self.drag_listener.is_none(),
588            "calling on_drag more than once on the same element is not supported"
589        );
590        self.drag_listener = Some((
591            Arc::new(value),
592            Box::new(move |value, offset, bounds, window, cx| {
593                constructor(value.downcast_ref().unwrap(), offset, bounds, window, cx).into()
594            }),
595        ));
596    }
597
598    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
599    /// passed to the callback is true when the hover starts and false when it ends.
600    /// The imperative API equivalent to [`StatefulInteractiveElement::on_hover`].
601    ///
602    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
603    pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut Window, &mut App) + 'static)
604    where
605        Self: Sized,
606    {
607        debug_assert!(
608            self.hover_listener.is_none(),
609            "calling on_hover more than once on the same element is not supported"
610        );
611        self.hover_listener = Some(Box::new(listener));
612    }
613
614    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
615    /// The imperative API equivalent to [`StatefulInteractiveElement::tooltip`].
616    pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static)
617    where
618        Self: Sized,
619    {
620        debug_assert!(
621            self.tooltip_builder.is_none(),
622            "calling tooltip more than once on the same element is not supported"
623        );
624        self.tooltip_builder = Some(TooltipBuilder {
625            build: Rc::new(build_tooltip),
626            hoverable: false,
627        });
628    }
629
630    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
631    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
632    /// the tooltip. The imperative API equivalent to [`StatefulInteractiveElement::hoverable_tooltip`].
633    pub fn hoverable_tooltip(
634        &mut self,
635        build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
636    ) where
637        Self: Sized,
638    {
639        debug_assert!(
640            self.tooltip_builder.is_none(),
641            "calling tooltip more than once on the same element is not supported"
642        );
643        self.tooltip_builder = Some(TooltipBuilder {
644            build: Rc::new(build_tooltip),
645            hoverable: true,
646        });
647    }
648
649    /// Set the delay before this element's tooltip is shown.
650    /// The imperative API equivalent to [`StatefulInteractiveElement::tooltip_show_delay`].
651    pub fn tooltip_show_delay(&mut self, delay: Duration) {
652        self.tooltip_show_delay = Some(delay);
653    }
654
655    /// Block the mouse from all interactions with elements behind this element's hitbox. Typically
656    /// `block_mouse_except_scroll` should be preferred.
657    ///
658    /// The imperative API equivalent to [`InteractiveElement::occlude`]
659    pub fn occlude_mouse(&mut self) {
660        self.hitbox_behavior = HitboxBehavior::BlockMouse;
661    }
662
663    /// Set the bounds of this element as a window control area for the platform window.
664    /// The imperative API equivalent to [`InteractiveElement::window_control_area`]
665    pub fn window_control_area(&mut self, area: WindowControlArea) {
666        self.window_control = Some(area);
667    }
668
669    /// Block non-scroll mouse interactions with elements behind this element's hitbox.
670    /// The imperative API equivalent to [`InteractiveElement::block_mouse_except_scroll`].
671    ///
672    /// See [`Hitbox::is_hovered`] for details.
673    pub fn block_mouse_except_scroll(&mut self) {
674        self.hitbox_behavior = HitboxBehavior::BlockMouseExceptScroll;
675    }
676
677    fn has_pinch_listeners(&self) -> bool {
678        !self.pinch_listeners.is_empty()
679    }
680}
681
682/// A trait for elements that want to use the standard GPUI event handlers that don't
683/// require any state.
684pub trait InteractiveElement: Sized {
685    /// Retrieve the interactivity state associated with this element
686    fn interactivity(&mut self) -> &mut Interactivity;
687
688    /// Assign this element to a group of elements that can be styled together
689    fn group(mut self, group: impl Into<SharedString>) -> Self {
690        self.interactivity().group = Some(group.into());
691        self
692    }
693
694    /// Assign this element an ID, so that it can be used with interactivity
695    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
696        self.interactivity().element_id = Some(id.into());
697
698        Stateful { element: self }
699    }
700
701    /// Track the focus state of the given focus handle on this element.
702    /// If the focus handle is focused by the application, this element will
703    /// apply its focused styles.
704    fn track_focus(mut self, focus_handle: &FocusHandle) -> Self {
705        self.interactivity().focusable = true;
706        self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
707        self
708    }
709
710    /// Set whether this element is a tab stop.
711    ///
712    /// When false, the element remains in tab-index order but cannot be reached via keyboard navigation.
713    /// Useful for container elements: focus the container, then call `window.focus_next(cx)` to focus
714    /// the first tab stop inside it while having the container element itself be unreachable via the keyboard.
715    /// Should only be used with `tab_index`.
716    fn tab_stop(mut self, tab_stop: bool) -> Self {
717        self.interactivity().tab_stop = tab_stop;
718        self
719    }
720
721    /// Set index of the tab stop order, and set this node as a tab stop.
722    /// This will default the element to being a tab stop. See [`Self::tab_stop`] for more information.
723    /// This should only be used in conjunction with `tab_group`
724    /// in order to not interfere with the tab index of other elements.
725    fn tab_index(mut self, index: isize) -> Self {
726        self.interactivity().focusable = true;
727        self.interactivity().tab_index = Some(index);
728        self.interactivity().tab_stop = true;
729        self
730    }
731
732    /// Designate this div as a "tab group". Tab groups have their own location in the tab-index order,
733    /// but for children of the tab group, the tab index is reset to 0. This can be useful for swapping
734    /// the order of tab stops within the group, without having to renumber all the tab stops in the whole
735    /// application.
736    fn tab_group(mut self) -> Self {
737        self.interactivity().tab_group = true;
738        if self.interactivity().tab_index.is_none() {
739            self.interactivity().tab_index = Some(0);
740        }
741        self
742    }
743
744    /// Set the keymap context for this element. This will be used to determine
745    /// which action to dispatch from the keymap.
746    fn key_context<C, E>(mut self, key_context: C) -> Self
747    where
748        C: TryInto<KeyContext, Error = E>,
749        E: std::fmt::Display,
750    {
751        if let Some(key_context) = key_context.try_into().log_err() {
752            self.interactivity().key_context = Some(key_context);
753        }
754        self
755    }
756
757    /// Apply the given style to this element when the mouse hovers over it
758    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
759        debug_assert!(
760            self.interactivity().hover_style.is_none(),
761            "hover style already set"
762        );
763        self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
764        self
765    }
766
767    /// Apply the given style to this element when the mouse hovers over a group member
768    fn group_hover(
769        mut self,
770        group_name: impl Into<SharedString>,
771        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
772    ) -> Self {
773        self.interactivity().group_hover_style = Some(GroupStyle {
774            group: group_name.into(),
775            style: Box::new(f(StyleRefinement::default())),
776        });
777        self
778    }
779
780    /// Bind the given callback to the mouse down event for the given mouse button.
781    /// The fluent API equivalent to [`Interactivity::on_mouse_down`].
782    ///
783    /// See [`Context::listener`](crate::Context::listener) to get access to the view state from this callback.
784    fn on_mouse_down(
785        mut self,
786        button: MouseButton,
787        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
788    ) -> Self {
789        self.interactivity().on_mouse_down(button, listener);
790        self
791    }
792
793    #[cfg(any(test, feature = "test-support"))]
794    /// Set a key that can be used to look up this element's bounds
795    /// in the [`crate::VisualTestContext::debug_bounds`] map
796    /// This is a noop in release builds
797    fn debug_selector(mut self, f: impl FnOnce() -> String) -> Self {
798        self.interactivity().debug_selector = Some(f());
799        self
800    }
801
802    #[cfg(not(any(test, feature = "test-support")))]
803    /// Set a key that can be used to look up this element's bounds
804    /// in the [`crate::VisualTestContext::debug_bounds`] map
805    /// This is a noop in release builds
806    #[inline]
807    fn debug_selector(self, _: impl FnOnce() -> String) -> Self {
808        self
809    }
810
811    /// Bind the given callback to the mouse down event for any button, during the capture phase.
812    /// The fluent API equivalent to [`Interactivity::capture_any_mouse_down`].
813    ///
814    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
815    fn capture_any_mouse_down(
816        mut self,
817        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
818    ) -> Self {
819        self.interactivity().capture_any_mouse_down(listener);
820        self
821    }
822
823    /// Bind the given callback to the mouse down event for any button, during the capture phase.
824    /// The fluent API equivalent to [`Interactivity::on_any_mouse_down`].
825    ///
826    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
827    fn on_any_mouse_down(
828        mut self,
829        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
830    ) -> Self {
831        self.interactivity().on_any_mouse_down(listener);
832        self
833    }
834
835    /// Bind the given callback to the mouse up event for the given button, during the bubble phase.
836    /// The fluent API equivalent to [`Interactivity::on_mouse_up`].
837    ///
838    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
839    fn on_mouse_up(
840        mut self,
841        button: MouseButton,
842        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
843    ) -> Self {
844        self.interactivity().on_mouse_up(button, listener);
845        self
846    }
847
848    /// Bind the given callback to the mouse up event for any button, during the capture phase.
849    /// The fluent API equivalent to [`Interactivity::capture_any_mouse_up`].
850    ///
851    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
852    fn capture_any_mouse_up(
853        mut self,
854        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
855    ) -> Self {
856        self.interactivity().capture_any_mouse_up(listener);
857        self
858    }
859
860    /// Bind the given callback to the mouse pressure event, during the bubble phase
861    /// the fluent API equivalent to [`Interactivity::on_mouse_pressure`]
862    ///
863    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
864    fn on_mouse_pressure(
865        mut self,
866        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
867    ) -> Self {
868        self.interactivity().on_mouse_pressure(listener);
869        self
870    }
871
872    /// Bind the given callback to the mouse pressure event, during the capture phase
873    /// the fluent API equivalent to [`Interactivity::on_mouse_pressure`]
874    ///
875    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
876    fn capture_mouse_pressure(
877        mut self,
878        listener: impl Fn(&MousePressureEvent, &mut Window, &mut App) + 'static,
879    ) -> Self {
880        self.interactivity().capture_mouse_pressure(listener);
881        self
882    }
883
884    /// Bind the given callback to the mouse down event, on any button, during the capture phase,
885    /// when the mouse is outside of the bounds of this element.
886    /// The fluent API equivalent to [`Interactivity::on_mouse_down_out`].
887    ///
888    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
889    fn on_mouse_down_out(
890        mut self,
891        listener: impl Fn(&MouseDownEvent, &mut Window, &mut App) + 'static,
892    ) -> Self {
893        self.interactivity().on_mouse_down_out(listener);
894        self
895    }
896
897    /// Bind the given callback to the mouse up event, for the given button, during the capture phase,
898    /// when the mouse is outside of the bounds of this element.
899    /// The fluent API equivalent to [`Interactivity::on_mouse_up_out`].
900    ///
901    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
902    fn on_mouse_up_out(
903        mut self,
904        button: MouseButton,
905        listener: impl Fn(&MouseUpEvent, &mut Window, &mut App) + 'static,
906    ) -> Self {
907        self.interactivity().on_mouse_up_out(button, listener);
908        self
909    }
910
911    /// Bind the given callback to the mouse move event, during the bubble phase.
912    /// The fluent API equivalent to [`Interactivity::on_mouse_move`].
913    ///
914    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
915    fn on_mouse_move(
916        mut self,
917        listener: impl Fn(&MouseMoveEvent, &mut Window, &mut App) + 'static,
918    ) -> Self {
919        self.interactivity().on_mouse_move(listener);
920        self
921    }
922
923    /// Bind the given callback to the mouse drag event of the given type. Note that this
924    /// will be called for all move events, inside or outside of this element, as long as the
925    /// drag was started with this element under the mouse. Useful for implementing draggable
926    /// UIs that don't conform to a drag and drop style interaction, like resizing.
927    /// The fluent API equivalent to [`Interactivity::on_drag_move`].
928    ///
929    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
930    fn on_drag_move<T: 'static>(
931        mut self,
932        listener: impl Fn(&DragMoveEvent<T>, &mut Window, &mut App) + 'static,
933    ) -> Self {
934        self.interactivity().on_drag_move(listener);
935        self
936    }
937
938    /// Bind the given callback to scroll wheel events during the bubble phase.
939    /// The fluent API equivalent to [`Interactivity::on_scroll_wheel`].
940    ///
941    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
942    fn on_scroll_wheel(
943        mut self,
944        listener: impl Fn(&ScrollWheelEvent, &mut Window, &mut App) + 'static,
945    ) -> Self {
946        self.interactivity().on_scroll_wheel(listener);
947        self
948    }
949
950    /// Bind the given callback to pinch gesture events during the bubble phase.
951    /// The fluent API equivalent to [`Interactivity::on_pinch`].
952    ///
953    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
954    fn on_pinch(mut self, listener: impl Fn(&PinchEvent, &mut Window, &mut App) + 'static) -> Self {
955        self.interactivity().on_pinch(listener);
956        self
957    }
958
959    /// Bind the given callback to pinch gesture events during the capture phase.
960    /// The fluent API equivalent to [`Interactivity::capture_pinch`].
961    ///
962    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
963    fn capture_pinch(
964        mut self,
965        listener: impl Fn(&PinchEvent, &mut Window, &mut App) + 'static,
966    ) -> Self {
967        self.interactivity().capture_pinch(listener);
968        self
969    }
970    /// Capture the given action, before normal action dispatch can fire.
971    /// The fluent API equivalent to [`Interactivity::capture_action`].
972    ///
973    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
974    fn capture_action<A: Action>(
975        mut self,
976        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
977    ) -> Self {
978        self.interactivity().capture_action(listener);
979        self
980    }
981
982    /// Bind the given callback to an action dispatch during the bubble phase.
983    /// The fluent API equivalent to [`Interactivity::on_action`].
984    ///
985    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
986    #[track_caller]
987    fn on_action<A: Action>(
988        mut self,
989        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
990    ) -> Self {
991        self.interactivity().on_action(listener);
992        self
993    }
994
995    /// Bind the given callback to an action dispatch, based on a dynamic action parameter
996    /// instead of a type parameter. Useful for component libraries that want to expose
997    /// action bindings to their users.
998    /// The fluent API equivalent to [`Interactivity::on_boxed_action`].
999    ///
1000    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1001    fn on_boxed_action(
1002        mut self,
1003        action: &dyn Action,
1004        listener: impl Fn(&dyn Action, &mut Window, &mut App) + 'static,
1005    ) -> Self {
1006        self.interactivity().on_boxed_action(action, listener);
1007        self
1008    }
1009
1010    /// Bind the given callback to key down events during the bubble phase.
1011    /// The fluent API equivalent to [`Interactivity::on_key_down`].
1012    ///
1013    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1014    fn on_key_down(
1015        mut self,
1016        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
1017    ) -> Self {
1018        self.interactivity().on_key_down(listener);
1019        self
1020    }
1021
1022    /// Bind the given callback to key down events during the capture phase.
1023    /// The fluent API equivalent to [`Interactivity::capture_key_down`].
1024    ///
1025    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1026    fn capture_key_down(
1027        mut self,
1028        listener: impl Fn(&KeyDownEvent, &mut Window, &mut App) + 'static,
1029    ) -> Self {
1030        self.interactivity().capture_key_down(listener);
1031        self
1032    }
1033
1034    /// Bind the given callback to key up events during the bubble phase.
1035    /// The fluent API equivalent to [`Interactivity::on_key_up`].
1036    ///
1037    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1038    fn on_key_up(
1039        mut self,
1040        listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static,
1041    ) -> Self {
1042        self.interactivity().on_key_up(listener);
1043        self
1044    }
1045
1046    /// Bind the given callback to key up events during the capture phase.
1047    /// The fluent API equivalent to [`Interactivity::capture_key_up`].
1048    ///
1049    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1050    fn capture_key_up(
1051        mut self,
1052        listener: impl Fn(&KeyUpEvent, &mut Window, &mut App) + 'static,
1053    ) -> Self {
1054        self.interactivity().capture_key_up(listener);
1055        self
1056    }
1057
1058    /// Bind the given callback to modifiers changing events.
1059    /// The fluent API equivalent to [`Interactivity::on_modifiers_changed`].
1060    ///
1061    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1062    fn on_modifiers_changed(
1063        mut self,
1064        listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
1065    ) -> Self {
1066        self.interactivity().on_modifiers_changed(listener);
1067        self
1068    }
1069
1070    /// Apply the given style when the given data type is dragged over this element
1071    fn drag_over<S: 'static>(
1072        mut self,
1073        f: impl 'static + Fn(StyleRefinement, &S, &mut Window, &mut App) -> StyleRefinement,
1074    ) -> Self {
1075        self.interactivity().drag_over_styles.push((
1076            TypeId::of::<S>(),
1077            Box::new(move |currently_dragged: &dyn Any, window, cx| {
1078                f(
1079                    StyleRefinement::default(),
1080                    currently_dragged.downcast_ref::<S>().unwrap(),
1081                    window,
1082                    cx,
1083                )
1084            }),
1085        ));
1086        self
1087    }
1088
1089    /// Apply the given style when the given data type is dragged over this element's group
1090    fn group_drag_over<S: 'static>(
1091        mut self,
1092        group_name: impl Into<SharedString>,
1093        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
1094    ) -> Self {
1095        self.interactivity().group_drag_over_styles.push((
1096            TypeId::of::<S>(),
1097            GroupStyle {
1098                group: group_name.into(),
1099                style: Box::new(f(StyleRefinement::default())),
1100            },
1101        ));
1102        self
1103    }
1104
1105    /// Bind the given callback to drop events of the given type, whether or not the drag started on this element.
1106    /// The fluent API equivalent to [`Interactivity::on_drop`].
1107    ///
1108    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1109    fn on_drop<T: 'static>(
1110        mut self,
1111        listener: impl Fn(&T, &mut Window, &mut App) + 'static,
1112    ) -> Self {
1113        self.interactivity().on_drop(listener);
1114        self
1115    }
1116
1117    /// Use the given predicate to determine whether or not a drop event should be dispatched to this element.
1118    /// The fluent API equivalent to [`Interactivity::can_drop`].
1119    fn can_drop(
1120        mut self,
1121        predicate: impl Fn(&dyn Any, &mut Window, &mut App) -> bool + 'static,
1122    ) -> Self {
1123        self.interactivity().can_drop(predicate);
1124        self
1125    }
1126
1127    /// Block the mouse from all interactions with elements behind this element's hitbox. Typically
1128    /// `block_mouse_except_scroll` should be preferred.
1129    /// The fluent API equivalent to [`Interactivity::occlude_mouse`].
1130    fn occlude(mut self) -> Self {
1131        self.interactivity().occlude_mouse();
1132        self
1133    }
1134
1135    /// Set the bounds of this element as a window control area for the platform window.
1136    /// The fluent API equivalent to [`Interactivity::window_control_area`].
1137    fn window_control_area(mut self, area: WindowControlArea) -> Self {
1138        self.interactivity().window_control_area(area);
1139        self
1140    }
1141
1142    /// Block non-scroll mouse interactions with elements behind this element's hitbox.
1143    /// The fluent API equivalent to [`Interactivity::block_mouse_except_scroll`].
1144    ///
1145    /// See [`Hitbox::is_hovered`] for details.
1146    fn block_mouse_except_scroll(mut self) -> Self {
1147        self.interactivity().block_mouse_except_scroll();
1148        self
1149    }
1150
1151    /// Set the given styles to be applied when this element, specifically, is focused.
1152    /// Requires that the element is focusable. Elements can be made focusable using [`InteractiveElement::track_focus`].
1153    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1154    where
1155        Self: Sized,
1156    {
1157        self.interactivity().focus_style = Some(Box::new(f(StyleRefinement::default())));
1158        self
1159    }
1160
1161    /// Set the given styles to be applied when this element is inside another element that is focused.
1162    /// Requires that the element is focusable. Elements can be made focusable using [`InteractiveElement::track_focus`].
1163    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1164    where
1165        Self: Sized,
1166    {
1167        self.interactivity().in_focus_style = Some(Box::new(f(StyleRefinement::default())));
1168        self
1169    }
1170
1171    /// Set the given styles to be applied when this element is focused via keyboard navigation.
1172    /// This is similar to CSS's `:focus-visible` pseudo-class - it only applies when the element
1173    /// is focused AND the user is navigating via keyboard (not mouse clicks).
1174    /// Requires that the element is focusable. Elements can be made focusable using [`InteractiveElement::track_focus`].
1175    fn focus_visible(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1176    where
1177        Self: Sized,
1178    {
1179        self.interactivity().focus_visible_style = Some(Box::new(f(StyleRefinement::default())));
1180        self
1181    }
1182}
1183
1184/// A trait for elements that want to use the standard GPUI interactivity features
1185/// that require state.
1186pub trait StatefulInteractiveElement: InteractiveElement {
1187    /// Set the accessible role for this element.
1188    ///
1189    /// See the [accessibility guide](crate::_accessibility) for an overview.
1190    fn role(mut self, role: accesskit::Role) -> Self {
1191        debug_assert!(
1192            role != accesskit::Role::GenericContainer,
1193            "GenericContainer is filtered out of the a11y tree and has no effect"
1194        );
1195        self.interactivity().override_role = Some(role);
1196        self
1197    }
1198
1199    /// Set the accessible label for this element.
1200    fn aria_label(mut self, label: impl Into<SharedString>) -> Self {
1201        self.interactivity().aria_label = Some(label.into());
1202        self
1203    }
1204
1205    /// Set the nodes this element controls.
1206    fn aria_controls(mut self, controls: impl IntoIterator<Item = accesskit::NodeId>) -> Self {
1207        self.interactivity().aria_controls = Some(controls.into_iter().collect());
1208        self
1209    }
1210
1211    /// Set the nodes that label this element.
1212    fn aria_labelled_by(
1213        mut self,
1214        labelled_by: impl IntoIterator<Item = accesskit::NodeId>,
1215    ) -> Self {
1216        self.interactivity().aria_labelled_by = Some(labelled_by.into_iter().collect());
1217        self
1218    }
1219
1220    /// Set the selected state for this element.
1221    fn aria_selected(mut self, selected: bool) -> Self {
1222        self.interactivity().aria_selected = Some(selected);
1223        self
1224    }
1225
1226    /// Set the required state for this element.
1227    fn aria_required(mut self, required: bool) -> Self {
1228        self.interactivity().aria_required = Some(required);
1229        self
1230    }
1231
1232    /// Set the disabled state for this element.
1233    fn aria_disabled(mut self, disabled: bool) -> Self {
1234        self.interactivity().aria_disabled = Some(disabled);
1235        self
1236    }
1237
1238    /// Set the expanded state for this element.
1239    fn aria_expanded(mut self, expanded: bool) -> Self {
1240        self.interactivity().aria_expanded = Some(expanded);
1241        self
1242    }
1243
1244    /// Set the toggled state for this element.
1245    fn aria_toggled(mut self, toggled: accesskit::Toggled) -> Self {
1246        self.interactivity().aria_toggled = Some(toggled);
1247        self
1248    }
1249
1250    /// Set the numeric value for this element.
1251    fn aria_numeric_value(mut self, value: f64) -> Self {
1252        self.interactivity().aria_numeric_value = Some(value);
1253        self
1254    }
1255
1256    /// Set the minimum numeric value for this element.
1257    fn aria_min_numeric_value(mut self, value: f64) -> Self {
1258        self.interactivity().aria_min_numeric_value = Some(value);
1259        self
1260    }
1261
1262    /// Set the maximum numeric value for this element.
1263    fn aria_max_numeric_value(mut self, value: f64) -> Self {
1264        self.interactivity().aria_max_numeric_value = Some(value);
1265        self
1266    }
1267
1268    /// Set the orientation of this element.
1269    fn aria_orientation(mut self, orientation: accesskit::Orientation) -> Self {
1270        self.interactivity().aria_orientation = Some(orientation);
1271        self
1272    }
1273
1274    /// Set the heading level of this element.
1275    fn aria_level(mut self, level: usize) -> Self {
1276        self.interactivity().aria_level = Some(level);
1277        self
1278    }
1279
1280    /// Set the position in set of this element.
1281    fn aria_position_in_set(mut self, position: usize) -> Self {
1282        self.interactivity().aria_position_in_set = Some(position);
1283        self
1284    }
1285
1286    /// Set the size of set for this element.
1287    fn aria_size_of_set(mut self, size: usize) -> Self {
1288        self.interactivity().aria_size_of_set = Some(size);
1289        self
1290    }
1291
1292    /// Set the row index for this element.
1293    fn aria_row_index(mut self, index: usize) -> Self {
1294        self.interactivity().aria_row_index = Some(index);
1295        self
1296    }
1297
1298    /// Set the column index for this element.
1299    fn aria_column_index(mut self, index: usize) -> Self {
1300        self.interactivity().aria_column_index = Some(index);
1301        self
1302    }
1303
1304    /// Set the row count for this element.
1305    fn aria_row_count(mut self, count: usize) -> Self {
1306        self.interactivity().aria_row_count = Some(count);
1307        self
1308    }
1309
1310    /// Set the column count for this element.
1311    fn aria_column_count(mut self, count: usize) -> Self {
1312        self.interactivity().aria_column_count = Some(count);
1313        self
1314    }
1315
1316    /// Register a handler for an accessibility action on this element.
1317    /// The handler is called when a screen reader requests the given action.
1318    ///
1319    /// See the [accessibility guide](crate::_accessibility) for an overview.
1320    fn on_a11y_action(
1321        mut self,
1322        action: accesskit::Action,
1323        listener: impl FnMut(Option<&accesskit::ActionData>, &mut crate::Window, &mut crate::App)
1324        + 'static,
1325    ) -> Self {
1326        self.interactivity()
1327            .a11y_action_listeners
1328            .push((action, Box::new(listener)));
1329        self
1330    }
1331
1332    /// Set this element to focusable.
1333    fn focusable(mut self) -> Self {
1334        self.interactivity().focusable = true;
1335        self
1336    }
1337
1338    /// Set the overflow x and y to scroll.
1339    fn overflow_scroll(mut self) -> Self {
1340        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
1341        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
1342        self
1343    }
1344
1345    /// Set the overflow x to scroll.
1346    fn overflow_x_scroll(mut self) -> Self {
1347        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
1348        self
1349    }
1350
1351    /// Set the overflow y to scroll.
1352    fn overflow_y_scroll(mut self) -> Self {
1353        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
1354        self
1355    }
1356
1357    /// Track the scroll state of this element with the given handle.
1358    fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
1359        self.interactivity().tracked_scroll_handle = Some(scroll_handle.clone());
1360        self
1361    }
1362
1363    /// Track the scroll state of this element with the given handle.
1364    fn anchor_scroll(mut self, scroll_anchor: Option<ScrollAnchor>) -> Self {
1365        self.interactivity().scroll_anchor = scroll_anchor;
1366        self
1367    }
1368
1369    /// Set the given styles to be applied when this element is active.
1370    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
1371    where
1372        Self: Sized,
1373    {
1374        self.interactivity().active_style = Some(Box::new(f(StyleRefinement::default())));
1375        self
1376    }
1377
1378    /// Set the given styles to be applied when this element's group is active.
1379    fn group_active(
1380        mut self,
1381        group_name: impl Into<SharedString>,
1382        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
1383    ) -> Self
1384    where
1385        Self: Sized,
1386    {
1387        self.interactivity().group_active_style = Some(GroupStyle {
1388            group: group_name.into(),
1389            style: Box::new(f(StyleRefinement::default())),
1390        });
1391        self
1392    }
1393
1394    /// Bind the given callback to click events of this element.
1395    /// The fluent API equivalent to [`Interactivity::on_click`].
1396    ///
1397    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1398    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self
1399    where
1400        Self: Sized,
1401    {
1402        self.interactivity().on_click(listener);
1403        self
1404    }
1405
1406    /// Bind the given callback to non-primary click events of this element.
1407    /// The fluent API equivalent to [`Interactivity::on_aux_click`].
1408    ///
1409    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1410    fn on_aux_click(
1411        mut self,
1412        listener: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
1413    ) -> Self
1414    where
1415        Self: Sized,
1416    {
1417        self.interactivity().on_aux_click(listener);
1418        self
1419    }
1420
1421    /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
1422    /// drag and drop operation. This API should also be used as the equivalent of 'on drag start' with
1423    /// the [`InteractiveElement::on_drag_move`] API.
1424    /// The callback also has access to the offset of triggering click from the origin of parent element
1425    /// and the source element bounds.
1426    /// The fluent API equivalent to [`Interactivity::on_drag`].
1427    ///
1428    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1429    fn on_drag<T, W>(
1430        mut self,
1431        value: T,
1432        constructor: impl Fn(&T, Point<Pixels>, Bounds<Pixels>, &mut Window, &mut App) -> Entity<W>
1433        + 'static,
1434    ) -> Self
1435    where
1436        Self: Sized,
1437        T: 'static,
1438        W: 'static + Render,
1439    {
1440        self.interactivity().on_drag(value, constructor);
1441        self
1442    }
1443
1444    /// Bind the given callback on the hover start and end events of this element. Note that the boolean
1445    /// passed to the callback is true when the hover starts and false when it ends.
1446    /// The fluent API equivalent to [`Interactivity::on_hover`].
1447    ///
1448    /// See [`Context::listener`](crate::Context::listener) to get access to a view's state from this callback.
1449    fn on_hover(mut self, listener: impl Fn(&bool, &mut Window, &mut App) + 'static) -> Self
1450    where
1451        Self: Sized,
1452    {
1453        self.interactivity().on_hover(listener);
1454        self
1455    }
1456
1457    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1458    /// The fluent API equivalent to [`Interactivity::tooltip`].
1459    fn tooltip(mut self, build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self
1460    where
1461        Self: Sized,
1462    {
1463        self.interactivity().tooltip(build_tooltip);
1464        self
1465    }
1466
1467    /// Use the given callback to construct a new tooltip view when the mouse hovers over this element.
1468    /// The tooltip itself is also hoverable and won't disappear when the user moves the mouse into
1469    /// the tooltip. The fluent API equivalent to [`Interactivity::hoverable_tooltip`].
1470    fn hoverable_tooltip(
1471        mut self,
1472        build_tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
1473    ) -> Self
1474    where
1475        Self: Sized,
1476    {
1477        self.interactivity().hoverable_tooltip(build_tooltip);
1478        self
1479    }
1480
1481    /// Set the delay before this element's tooltip is shown.
1482    /// The fluent API equivalent to [`Interactivity::tooltip_show_delay`].
1483    fn tooltip_show_delay(mut self, delay: Duration) -> Self
1484    where
1485        Self: Sized,
1486    {
1487        self.interactivity().tooltip_show_delay(delay);
1488        self
1489    }
1490}
1491
1492pub(crate) type MouseDownListener =
1493    Box<dyn Fn(&MouseDownEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1494pub(crate) type MouseUpListener =
1495    Box<dyn Fn(&MouseUpEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1496pub(crate) type MousePressureListener =
1497    Box<dyn Fn(&MousePressureEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1498pub(crate) type MouseMoveListener =
1499    Box<dyn Fn(&MouseMoveEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1500
1501pub(crate) type ScrollWheelListener =
1502    Box<dyn Fn(&ScrollWheelEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1503
1504pub(crate) type PinchListener =
1505    Box<dyn Fn(&PinchEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
1506
1507pub(crate) type ClickListener = Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>;
1508
1509pub(crate) type DragListener = Box<
1510    dyn Fn(&dyn Any, Point<Pixels>, Bounds<Pixels>, &mut Window, &mut App) -> AnyView + 'static,
1511>;
1512
1513type DropListener = Box<dyn Fn(&dyn Any, &mut Window, &mut App) + 'static>;
1514
1515type CanDropPredicate = Box<dyn Fn(&dyn Any, &mut Window, &mut App) -> bool + 'static>;
1516
1517pub(crate) struct TooltipBuilder {
1518    build: Rc<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>,
1519    hoverable: bool,
1520}
1521
1522pub(crate) type KeyDownListener =
1523    Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut Window, &mut App) + 'static>;
1524
1525pub(crate) type KeyUpListener =
1526    Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut Window, &mut App) + 'static>;
1527
1528pub(crate) type ModifiersChangedListener =
1529    Box<dyn Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static>;
1530
1531pub(crate) type ActionListener =
1532    Box<dyn Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
1533
1534/// Construct a new [`Div`] element
1535#[track_caller]
1536pub fn div() -> Div {
1537    Div {
1538        interactivity: Interactivity::new(),
1539        children: SmallVec::default(),
1540        prepaint_listener: None,
1541        image_cache: None,
1542        prepaint_order_fn: None,
1543    }
1544}
1545
1546/// A [`Div`] element, the all-in-one element for building complex UIs in GPUI
1547pub struct Div {
1548    interactivity: Interactivity,
1549    children: SmallVec<[StackSafe<AnyElement>; 2]>,
1550    prepaint_listener: Option<Box<dyn Fn(Vec<Bounds<Pixels>>, &mut Window, &mut App) + 'static>>,
1551    image_cache: Option<Box<dyn ImageCacheProvider>>,
1552    prepaint_order_fn: Option<Box<dyn Fn(&mut Window, &mut App) -> SmallVec<[usize; 8]>>>,
1553}
1554
1555impl Div {
1556    /// Add a listener to be called when the children of this `Div` are prepainted.
1557    /// This allows you to store the [`Bounds`] of the children for later use.
1558    pub fn on_children_prepainted(
1559        mut self,
1560        listener: impl Fn(Vec<Bounds<Pixels>>, &mut Window, &mut App) + 'static,
1561    ) -> Self {
1562        self.prepaint_listener = Some(Box::new(listener));
1563        self
1564    }
1565
1566    /// Add an image cache at the location of this div in the element tree.
1567    pub fn image_cache(mut self, cache: impl ImageCacheProvider) -> Self {
1568        self.image_cache = Some(Box::new(cache));
1569        self
1570    }
1571
1572    /// Specify a function that determines the order in which children are prepainted.
1573    ///
1574    /// The function is called at prepaint time and should return a vector of child indices
1575    /// in the desired prepaint order. Each index should appear exactly once.
1576    ///
1577    /// This is useful when the prepaint of one child affects state that another child reads.
1578    /// For example, in split editor views, the editor with an autoscroll request should
1579    /// be prepainted first so its scroll position update is visible to the other editor.
1580    pub fn with_dynamic_prepaint_order(
1581        mut self,
1582        order_fn: impl Fn(&mut Window, &mut App) -> SmallVec<[usize; 8]> + 'static,
1583    ) -> Self {
1584        self.prepaint_order_fn = Some(Box::new(order_fn));
1585        self
1586    }
1587}
1588
1589/// A frame state for a `Div` element, which contains layout IDs for its children.
1590///
1591/// This struct is used internally by the `Div` element to manage the layout state of its children
1592/// during the UI update cycle. It holds a small vector of `LayoutId` values, each corresponding to
1593/// a child element of the `Div`. These IDs are used to query the layout engine for the computed
1594/// bounds of the children after the layout phase is complete.
1595pub struct DivFrameState {
1596    child_layout_ids: SmallVec<[LayoutId; 2]>,
1597}
1598
1599/// Interactivity state displayed an manipulated in the inspector.
1600#[derive(Clone)]
1601pub struct DivInspectorState {
1602    /// The inspected element's base style. This is used for both inspecting and modifying the
1603    /// state. In the future it will make sense to separate the read and write, possibly tracking
1604    /// the modifications.
1605    #[cfg(any(feature = "inspector", debug_assertions))]
1606    pub base_style: Box<StyleRefinement>,
1607    /// Inspects the bounds of the element.
1608    pub bounds: Bounds<Pixels>,
1609    /// Size of the children of the element, or `bounds.size` if it has no children.
1610    pub content_size: Size<Pixels>,
1611}
1612
1613impl Styled for Div {
1614    fn style(&mut self) -> &mut StyleRefinement {
1615        &mut self.interactivity.base_style
1616    }
1617}
1618
1619impl InteractiveElement for Div {
1620    fn interactivity(&mut self) -> &mut Interactivity {
1621        &mut self.interactivity
1622    }
1623}
1624
1625impl ParentElement for Div {
1626    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
1627        self.children
1628            .extend(elements.into_iter().map(StackSafe::new))
1629    }
1630}
1631
1632impl Element for Div {
1633    type RequestLayoutState = DivFrameState;
1634    type PrepaintState = Option<Hitbox>;
1635
1636    fn id(&self) -> Option<ElementId> {
1637        self.interactivity.element_id.clone()
1638    }
1639
1640    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
1641        self.interactivity.source_location()
1642    }
1643
1644    fn a11y_role(&self) -> Option<accesskit::Role> {
1645        // Nodes with `GenericContainer` should never be reported to accesskit.
1646        // Equivalent to an HTML div with no role.
1647        self.interactivity
1648            .override_role
1649            .filter(|role| *role != accesskit::Role::GenericContainer)
1650    }
1651
1652    fn write_a11y_info(&self, node: &mut accesskit::Node) {
1653        self.interactivity.write_a11y_info(node);
1654    }
1655
1656    #[stacksafe]
1657    fn request_layout(
1658        &mut self,
1659        global_id: Option<&GlobalElementId>,
1660        inspector_id: Option<&InspectorElementId>,
1661        window: &mut Window,
1662        cx: &mut App,
1663    ) -> (LayoutId, Self::RequestLayoutState) {
1664        let mut child_layout_ids = SmallVec::new();
1665        let image_cache = self
1666            .image_cache
1667            .as_mut()
1668            .map(|provider| provider.provide(window, cx));
1669
1670        let layout_id = window.with_image_cache(image_cache, |window| {
1671            self.interactivity.request_layout(
1672                global_id,
1673                inspector_id,
1674                window,
1675                cx,
1676                |style, window, cx| {
1677                    window.with_text_style(style.text_style().cloned(), |window| {
1678                        child_layout_ids = self
1679                            .children
1680                            .iter_mut()
1681                            .map(|child| child.request_layout(window, cx))
1682                            .collect::<SmallVec<_>>();
1683                        window.request_layout(style, child_layout_ids.iter().copied(), cx)
1684                    })
1685                },
1686            )
1687        });
1688
1689        (layout_id, DivFrameState { child_layout_ids })
1690    }
1691
1692    #[stacksafe]
1693    fn prepaint(
1694        &mut self,
1695        global_id: Option<&GlobalElementId>,
1696        inspector_id: Option<&InspectorElementId>,
1697        bounds: Bounds<Pixels>,
1698        request_layout: &mut Self::RequestLayoutState,
1699        window: &mut Window,
1700        cx: &mut App,
1701    ) -> Option<Hitbox> {
1702        let image_cache = self
1703            .image_cache
1704            .as_mut()
1705            .map(|provider| provider.provide(window, cx));
1706
1707        let has_prepaint_listener = self.prepaint_listener.is_some();
1708        let mut children_bounds = Vec::with_capacity(if has_prepaint_listener {
1709            request_layout.child_layout_ids.len()
1710        } else {
1711            0
1712        });
1713
1714        let mut child_min = point(Pixels::MAX, Pixels::MAX);
1715        let mut child_max = Point::default();
1716        if let Some(handle) = self.interactivity.scroll_anchor.as_ref() {
1717            *handle.last_origin.borrow_mut() = bounds.origin - window.element_offset();
1718        }
1719        let content_size = if request_layout.child_layout_ids.is_empty() {
1720            bounds.size
1721        } else if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1722            let mut state = scroll_handle.0.borrow_mut();
1723            state.child_bounds = Vec::with_capacity(request_layout.child_layout_ids.len());
1724            for child_layout_id in &request_layout.child_layout_ids {
1725                let child_bounds = window.layout_bounds(*child_layout_id);
1726                child_min = child_min.min(&child_bounds.origin);
1727                child_max = child_max.max(&child_bounds.bottom_right());
1728                state.child_bounds.push(child_bounds);
1729            }
1730            (child_max - child_min).into()
1731        } else {
1732            for child_layout_id in &request_layout.child_layout_ids {
1733                let child_bounds = window.layout_bounds(*child_layout_id);
1734                child_min = child_min.min(&child_bounds.origin);
1735                child_max = child_max.max(&child_bounds.bottom_right());
1736
1737                if has_prepaint_listener {
1738                    children_bounds.push(child_bounds);
1739                }
1740            }
1741            (child_max - child_min).into()
1742        };
1743
1744        if let Some(scroll_handle) = self.interactivity.tracked_scroll_handle.as_ref() {
1745            scroll_handle.scroll_to_active_item();
1746        }
1747
1748        self.interactivity.prepaint(
1749            global_id,
1750            inspector_id,
1751            bounds,
1752            content_size,
1753            window,
1754            cx,
1755            |style, scroll_offset, hitbox, window, cx| {
1756                // skip children
1757                if style.display == Display::None {
1758                    return hitbox;
1759                }
1760
1761                window.with_image_cache(image_cache, |window| {
1762                    window.with_element_offset(scroll_offset, |window| {
1763                        if let Some(order_fn) = &self.prepaint_order_fn {
1764                            let order = order_fn(window, cx);
1765                            for idx in order {
1766                                if let Some(child) = self.children.get_mut(idx) {
1767                                    child.prepaint(window, cx);
1768                                }
1769                            }
1770                        } else {
1771                            for child in &mut self.children {
1772                                child.prepaint(window, cx);
1773                            }
1774                        }
1775                    });
1776
1777                    if let Some(listener) = self.prepaint_listener.as_ref() {
1778                        listener(children_bounds, window, cx);
1779                    }
1780                });
1781
1782                hitbox
1783            },
1784        )
1785    }
1786
1787    #[stacksafe]
1788    fn paint(
1789        &mut self,
1790        global_id: Option<&GlobalElementId>,
1791        inspector_id: Option<&InspectorElementId>,
1792        bounds: Bounds<Pixels>,
1793        _request_layout: &mut Self::RequestLayoutState,
1794        hitbox: &mut Option<Hitbox>,
1795        window: &mut Window,
1796        cx: &mut App,
1797    ) {
1798        let image_cache = self
1799            .image_cache
1800            .as_mut()
1801            .map(|provider| provider.provide(window, cx));
1802
1803        window.with_image_cache(image_cache, |window| {
1804            self.interactivity.paint(
1805                global_id,
1806                inspector_id,
1807                bounds,
1808                hitbox.as_ref(),
1809                window,
1810                cx,
1811                |style, window, cx| {
1812                    // skip children
1813                    if style.display == Display::None {
1814                        return;
1815                    }
1816
1817                    for child in &mut self.children {
1818                        child.paint(window, cx);
1819                    }
1820                },
1821            )
1822        });
1823    }
1824}
1825
1826impl IntoElement for Div {
1827    type Element = Self;
1828
1829    fn into_element(self) -> Self::Element {
1830        self
1831    }
1832}
1833
1834/// The interactivity struct. Powers all of the general-purpose
1835/// interactivity in the `Div` element.
1836#[derive(Default)]
1837pub struct Interactivity {
1838    /// The element ID of the element. In id is required to support a stateful subset of the interactivity such as on_click.
1839    pub element_id: Option<ElementId>,
1840    /// Whether the element was clicked. This will only be present after layout.
1841    pub active: Option<bool>,
1842    /// Whether the element was hovered. This will only be present after paint if an hitbox
1843    /// was created for the interactive element.
1844    pub hovered: Option<bool>,
1845    pub(crate) tooltip_id: Option<TooltipId>,
1846    pub(crate) content_size: Size<Pixels>,
1847    pub(crate) key_context: Option<KeyContext>,
1848    pub(crate) focusable: bool,
1849    pub(crate) tracked_focus_handle: Option<FocusHandle>,
1850    pub(crate) tracked_scroll_handle: Option<ScrollHandle>,
1851    pub(crate) scroll_anchor: Option<ScrollAnchor>,
1852    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
1853    pub(crate) group: Option<SharedString>,
1854    /// The base style of the element, before any modifications are applied
1855    /// by focus, active, etc.
1856    pub base_style: Box<StyleRefinement>,
1857    pub(crate) focus_style: Option<Box<StyleRefinement>>,
1858    pub(crate) in_focus_style: Option<Box<StyleRefinement>>,
1859    pub(crate) focus_visible_style: Option<Box<StyleRefinement>>,
1860    pub(crate) hover_style: Option<Box<StyleRefinement>>,
1861    pub(crate) group_hover_style: Option<GroupStyle>,
1862    pub(crate) active_style: Option<Box<StyleRefinement>>,
1863    pub(crate) group_active_style: Option<GroupStyle>,
1864    pub(crate) drag_over_styles: Vec<(
1865        TypeId,
1866        Box<dyn Fn(&dyn Any, &mut Window, &mut App) -> StyleRefinement>,
1867    )>,
1868    pub(crate) group_drag_over_styles: Vec<(TypeId, GroupStyle)>,
1869    pub(crate) mouse_down_listeners: Vec<MouseDownListener>,
1870    pub(crate) mouse_up_listeners: Vec<MouseUpListener>,
1871    pub(crate) mouse_pressure_listeners: Vec<MousePressureListener>,
1872    pub(crate) mouse_move_listeners: Vec<MouseMoveListener>,
1873    pub(crate) scroll_wheel_listeners: Vec<ScrollWheelListener>,
1874    pub(crate) pinch_listeners: Vec<PinchListener>,
1875    pub(crate) key_down_listeners: Vec<KeyDownListener>,
1876    pub(crate) key_up_listeners: Vec<KeyUpListener>,
1877    pub(crate) modifiers_changed_listeners: Vec<ModifiersChangedListener>,
1878    pub(crate) action_listeners: Vec<(TypeId, ActionListener)>,
1879    pub(crate) drop_listeners: Vec<(TypeId, DropListener)>,
1880    pub(crate) can_drop_predicate: Option<CanDropPredicate>,
1881    pub(crate) click_listeners: Vec<ClickListener>,
1882    pub(crate) aux_click_listeners: Vec<ClickListener>,
1883    pub(crate) drag_listener: Option<(Arc<dyn Any>, DragListener)>,
1884    pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut Window, &mut App)>>,
1885    pub(crate) tooltip_builder: Option<TooltipBuilder>,
1886    pub(crate) tooltip_show_delay: Option<Duration>,
1887    pub(crate) window_control: Option<WindowControlArea>,
1888    pub(crate) hitbox_behavior: HitboxBehavior,
1889    pub(crate) tab_index: Option<isize>,
1890    pub(crate) tab_group: bool,
1891    pub(crate) tab_stop: bool,
1892
1893    pub(crate) a11y_action_listeners:
1894        Vec<(accesskit::Action, crate::window::a11y::A11yActionListener)>,
1895    pub(crate) override_role: Option<accesskit::Role>,
1896    pub(crate) aria_label: Option<SharedString>,
1897    pub(crate) aria_controls: Option<Vec<accesskit::NodeId>>,
1898    pub(crate) aria_labelled_by: Option<Vec<accesskit::NodeId>>,
1899    pub(crate) aria_selected: Option<bool>,
1900    pub(crate) aria_required: Option<bool>,
1901    pub(crate) aria_disabled: Option<bool>,
1902    pub(crate) aria_expanded: Option<bool>,
1903    pub(crate) aria_toggled: Option<accesskit::Toggled>,
1904    pub(crate) aria_numeric_value: Option<f64>,
1905    pub(crate) aria_min_numeric_value: Option<f64>,
1906    pub(crate) aria_max_numeric_value: Option<f64>,
1907    pub(crate) aria_orientation: Option<accesskit::Orientation>,
1908    pub(crate) aria_level: Option<usize>,
1909    pub(crate) aria_position_in_set: Option<usize>,
1910    pub(crate) aria_size_of_set: Option<usize>,
1911    pub(crate) aria_row_index: Option<usize>,
1912    pub(crate) aria_column_index: Option<usize>,
1913    pub(crate) aria_row_count: Option<usize>,
1914    pub(crate) aria_column_count: Option<usize>,
1915
1916    #[cfg(any(feature = "inspector", debug_assertions))]
1917    pub(crate) source_location: Option<&'static core::panic::Location<'static>>,
1918
1919    #[cfg(any(test, feature = "test-support"))]
1920    pub(crate) debug_selector: Option<String>,
1921}
1922
1923impl Interactivity {
1924    /// Layout this element according to this interactivity state's configured styles
1925    pub fn request_layout(
1926        &mut self,
1927        global_id: Option<&GlobalElementId>,
1928        _inspector_id: Option<&InspectorElementId>,
1929        window: &mut Window,
1930        cx: &mut App,
1931        f: impl FnOnce(Style, &mut Window, &mut App) -> LayoutId,
1932    ) -> LayoutId {
1933        #[cfg(any(feature = "inspector", debug_assertions))]
1934        window.with_inspector_state(
1935            _inspector_id,
1936            cx,
1937            |inspector_state: &mut Option<DivInspectorState>, _window| {
1938                if let Some(inspector_state) = inspector_state {
1939                    self.base_style = inspector_state.base_style.clone();
1940                } else {
1941                    *inspector_state = Some(DivInspectorState {
1942                        base_style: self.base_style.clone(),
1943                        bounds: Default::default(),
1944                        content_size: Default::default(),
1945                    })
1946                }
1947            },
1948        );
1949
1950        window.with_optional_element_state::<InteractiveElementState, _>(
1951            global_id,
1952            |element_state, window| {
1953                let mut element_state =
1954                    element_state.map(|element_state| element_state.unwrap_or_default());
1955
1956                if let Some(element_state) = element_state.as_ref()
1957                    && cx.has_active_drag()
1958                {
1959                    if let Some(pending_mouse_down) = element_state.pending_mouse_down.as_ref() {
1960                        *pending_mouse_down.borrow_mut() = None;
1961                    }
1962                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
1963                        *clicked_state.borrow_mut() = ElementClickedState::default();
1964                    }
1965                }
1966
1967                // Ensure we store a focus handle in our element state if we're focusable.
1968                // If there's an explicit focus handle we're tracking, use that. Otherwise
1969                // create a new handle and store it in the element state, which lives for as
1970                // as frames contain an element with this id.
1971                if self.focusable
1972                    && self.tracked_focus_handle.is_none()
1973                    && let Some(element_state) = element_state.as_mut()
1974                {
1975                    let mut handle = element_state
1976                        .focus_handle
1977                        .get_or_insert_with(|| cx.focus_handle())
1978                        .clone()
1979                        .tab_stop(self.tab_stop);
1980
1981                    if let Some(index) = self.tab_index {
1982                        handle = handle.tab_index(index);
1983                    }
1984
1985                    self.tracked_focus_handle = Some(handle);
1986                }
1987
1988                if let Some(scroll_handle) = self.tracked_scroll_handle.as_ref() {
1989                    self.scroll_offset = Some(scroll_handle.0.borrow().offset.clone());
1990                } else if (self.base_style.overflow.x == Some(Overflow::Scroll)
1991                    || self.base_style.overflow.y == Some(Overflow::Scroll))
1992                    && let Some(element_state) = element_state.as_mut()
1993                {
1994                    self.scroll_offset = Some(
1995                        element_state
1996                            .scroll_offset
1997                            .get_or_insert_with(Rc::default)
1998                            .clone(),
1999                    );
2000                }
2001
2002                let style = self.compute_style_internal(None, element_state.as_mut(), window, cx);
2003                let layout_id = f(style, window, cx);
2004                (layout_id, element_state)
2005            },
2006        )
2007    }
2008
2009    /// Commit the bounds of this element according to this interactivity state's configured styles.
2010    pub fn prepaint<R>(
2011        &mut self,
2012        global_id: Option<&GlobalElementId>,
2013        _inspector_id: Option<&InspectorElementId>,
2014        bounds: Bounds<Pixels>,
2015        content_size: Size<Pixels>,
2016        window: &mut Window,
2017        cx: &mut App,
2018        f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut Window, &mut App) -> R,
2019    ) -> R {
2020        self.content_size = content_size;
2021
2022        #[cfg(any(feature = "inspector", debug_assertions))]
2023        window.with_inspector_state(
2024            _inspector_id,
2025            cx,
2026            |inspector_state: &mut Option<DivInspectorState>, _window| {
2027                if let Some(inspector_state) = inspector_state {
2028                    inspector_state.bounds = bounds;
2029                    inspector_state.content_size = content_size;
2030                }
2031            },
2032        );
2033
2034        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
2035            window.set_focus_handle(focus_handle, cx);
2036
2037            if window.a11y.is_active() {
2038                if let Some(global_id) = global_id {
2039                    let node_id = global_id.accesskit_node_id();
2040                    window.a11y.focus_ids.insert(node_id, focus_handle.id);
2041                    if focus_handle.is_focused(window) && window.a11y.nodes.has_node(node_id) {
2042                        window.a11y.nodes.set_focus(node_id);
2043                    }
2044                }
2045            }
2046        }
2047        window.with_optional_element_state::<InteractiveElementState, _>(
2048            global_id,
2049            |element_state, window| {
2050                let mut element_state =
2051                    element_state.map(|element_state| element_state.unwrap_or_default());
2052                let style = self.compute_style_internal(None, element_state.as_mut(), window, cx);
2053
2054                if let Some(element_state) = element_state.as_mut() {
2055                    if let Some(clicked_state) = element_state.clicked_state.as_ref() {
2056                        let clicked_state = clicked_state.borrow();
2057                        self.active = Some(clicked_state.element);
2058                    }
2059                    if self.hover_style.is_some() || self.group_hover_style.is_some() {
2060                        element_state
2061                            .hover_state
2062                            .get_or_insert_with(Default::default);
2063                    }
2064                    if let Some(active_tooltip) = element_state.active_tooltip.as_ref() {
2065                        if self.tooltip_builder.is_some() {
2066                            self.tooltip_id = set_tooltip_on_window(active_tooltip, window);
2067                        } else {
2068                            // If there is no longer a tooltip builder, remove the active tooltip.
2069                            element_state.active_tooltip.take();
2070                        }
2071                    }
2072                }
2073
2074                window.with_text_style(style.text_style().cloned(), |window| {
2075                    window.with_content_mask(
2076                        style.overflow_mask(bounds, window.rem_size()),
2077                        |window| {
2078                            let hitbox = if self.should_insert_hitbox(&style, window, cx) {
2079                                Some(window.insert_hitbox(bounds, self.hitbox_behavior))
2080                            } else {
2081                                None
2082                            };
2083
2084                            let scroll_offset =
2085                                self.clamp_scroll_position(bounds, &style, window, cx);
2086                            let result = f(&style, scroll_offset, hitbox, window, cx);
2087                            (result, element_state)
2088                        },
2089                    )
2090                })
2091            },
2092        )
2093    }
2094
2095    fn should_insert_hitbox(&self, style: &Style, window: &Window, cx: &App) -> bool {
2096        self.hitbox_behavior != HitboxBehavior::Normal
2097            || self.window_control.is_some()
2098            || style.mouse_cursor.is_some()
2099            || self.group.is_some()
2100            || self.scroll_offset.is_some()
2101            || self.tracked_focus_handle.is_some()
2102            || self.hover_style.is_some()
2103            || self.group_hover_style.is_some()
2104            || self.hover_listener.is_some()
2105            || !self.mouse_up_listeners.is_empty()
2106            || !self.mouse_pressure_listeners.is_empty()
2107            || !self.mouse_down_listeners.is_empty()
2108            || !self.mouse_move_listeners.is_empty()
2109            || !self.click_listeners.is_empty()
2110            || !self.aux_click_listeners.is_empty()
2111            || !self.scroll_wheel_listeners.is_empty()
2112            || self.has_pinch_listeners()
2113            || self.drag_listener.is_some()
2114            || !self.drop_listeners.is_empty()
2115            || self.tooltip_builder.is_some()
2116            || window.is_inspector_picking(cx)
2117    }
2118
2119    fn clamp_scroll_position(
2120        &self,
2121        bounds: Bounds<Pixels>,
2122        style: &Style,
2123        window: &mut Window,
2124        _cx: &mut App,
2125    ) -> Point<Pixels> {
2126        fn round_to_two_decimals(pixels: Pixels) -> Pixels {
2127            const ROUNDING_FACTOR: f32 = 100.0;
2128            (pixels * ROUNDING_FACTOR).round() / ROUNDING_FACTOR
2129        }
2130
2131        if let Some(scroll_offset) = self.scroll_offset.as_ref() {
2132            let mut scroll_to_bottom = false;
2133            let mut tracked_scroll_handle = self
2134                .tracked_scroll_handle
2135                .as_ref()
2136                .map(|handle| handle.0.borrow_mut());
2137            if let Some(mut scroll_handle_state) = tracked_scroll_handle.as_deref_mut() {
2138                scroll_handle_state.overflow = style.overflow;
2139                scroll_to_bottom = mem::take(&mut scroll_handle_state.scroll_to_bottom);
2140            }
2141
2142            let rem_size = window.rem_size();
2143            let padding = style.padding.to_pixels(bounds.size.into(), rem_size);
2144            let padding_size = size(padding.left + padding.right, padding.top + padding.bottom);
2145            // The floating point values produced by Taffy and ours often vary
2146            // slightly after ~5 decimal places. This can lead to cases where after
2147            // subtracting these, the container becomes scrollable for less than
2148            // 0.00000x pixels. As we generally don't benefit from a precision that
2149            // high for the maximum scroll, we round the scroll max to 2 decimal
2150            // places here.
2151            let padded_content_size = self.content_size + padding_size;
2152            let scroll_max = Point::from(padded_content_size - bounds.size)
2153                .map(round_to_two_decimals)
2154                .max(&Default::default());
2155            // Clamp scroll offset in case scroll max is smaller now (e.g., if children
2156            // were removed or the bounds became larger).
2157            let mut scroll_offset = scroll_offset.borrow_mut();
2158
2159            scroll_offset.x = scroll_offset.x.clamp(-scroll_max.x, px(0.));
2160            if scroll_to_bottom {
2161                scroll_offset.y = -scroll_max.y;
2162            } else {
2163                scroll_offset.y = scroll_offset.y.clamp(-scroll_max.y, px(0.));
2164            }
2165
2166            if let Some(mut scroll_handle_state) = tracked_scroll_handle {
2167                scroll_handle_state.max_offset = scroll_max;
2168                scroll_handle_state.bounds = bounds;
2169            }
2170
2171            *scroll_offset
2172        } else {
2173            Point::default()
2174        }
2175    }
2176
2177    /// Paint this element according to this interactivity state's configured styles
2178    /// and bind the element's mouse and keyboard events.
2179    ///
2180    /// content_size is the size of the content of the element, which may be larger than the
2181    /// element's bounds if the element is scrollable.
2182    ///
2183    /// the final computed style will be passed to the provided function, along
2184    /// with the current scroll offset
2185    pub fn paint(
2186        &mut self,
2187        global_id: Option<&GlobalElementId>,
2188        _inspector_id: Option<&InspectorElementId>,
2189        bounds: Bounds<Pixels>,
2190        hitbox: Option<&Hitbox>,
2191        window: &mut Window,
2192        cx: &mut App,
2193        f: impl FnOnce(&Style, &mut Window, &mut App),
2194    ) {
2195        self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(window));
2196        window.with_optional_element_state::<InteractiveElementState, _>(
2197            global_id,
2198            |element_state, window| {
2199                let mut element_state =
2200                    element_state.map(|element_state| element_state.unwrap_or_default());
2201
2202                let style = self.compute_style_internal(hitbox, element_state.as_mut(), window, cx);
2203
2204                #[cfg(any(feature = "test-support", test))]
2205                if let Some(debug_selector) = &self.debug_selector {
2206                    window
2207                        .next_frame
2208                        .debug_bounds
2209                        .insert(debug_selector.clone(), bounds);
2210                    if let Some(focus_handle) = &self.tracked_focus_handle {
2211                        window
2212                            .next_frame
2213                            .debug_focus_handles
2214                            .insert(debug_selector.clone(), focus_handle.id);
2215                    }
2216                }
2217
2218                self.paint_hover_group_handler(window, cx);
2219
2220                if style.visibility == Visibility::Hidden {
2221                    return ((), element_state);
2222                }
2223
2224                let mut tab_group = None;
2225                if self.tab_group {
2226                    tab_group = self.tab_index;
2227                }
2228                if let Some(focus_handle) = &self.tracked_focus_handle {
2229                    window.next_frame.tab_stops.insert(focus_handle);
2230                }
2231
2232                window.with_element_opacity(style.opacity, |window| {
2233                    style.paint(bounds, window, cx, |window: &mut Window, cx: &mut App| {
2234                        window.with_text_style(style.text_style().cloned(), |window| {
2235                            window.with_content_mask(
2236                                style.overflow_mask(bounds, window.rem_size()),
2237                                |window| {
2238                                    window.with_tab_group(tab_group, |window| {
2239                                        if let Some(hitbox) = hitbox {
2240                                            #[cfg(debug_assertions)]
2241                                            self.paint_debug_info(
2242                                                global_id, hitbox, &style, window, cx,
2243                                            );
2244
2245                                            if let Some(drag) = cx.active_drag.as_ref() {
2246                                                if let Some(mouse_cursor) = drag.cursor_style {
2247                                                    if window.is_mouse_in_window() {
2248                                                        window
2249                                                            .set_window_cursor_style(mouse_cursor);
2250                                                    }
2251                                                }
2252                                            } else {
2253                                                if let Some(mouse_cursor) = style.mouse_cursor {
2254                                                    window.set_cursor_style(mouse_cursor, hitbox);
2255                                                }
2256                                            }
2257
2258                                            if let Some(group) = self.group.clone() {
2259                                                GroupHitboxes::push(group, hitbox.id, cx);
2260                                            }
2261
2262                                            if let Some(area) = self.window_control {
2263                                                window.insert_window_control_hitbox(
2264                                                    area,
2265                                                    hitbox.clone(),
2266                                                );
2267                                            }
2268
2269                                            self.paint_mouse_listeners(
2270                                                hitbox,
2271                                                element_state.as_mut(),
2272                                                window,
2273                                                cx,
2274                                            );
2275                                            self.paint_scroll_listener(hitbox, &style, window, cx);
2276                                        }
2277
2278                                        self.paint_keyboard_listeners(window, cx);
2279
2280                                        if window.a11y.is_active() {
2281                                            if let Some(global_id) = global_id {
2282                                                if !self.a11y_action_listeners.is_empty() {
2283                                                    let node_id = global_id.accesskit_node_id();
2284                                                    for (action, listener) in
2285                                                        self.a11y_action_listeners.drain(..)
2286                                                    {
2287                                                        window.on_a11y_action(
2288                                                            node_id, action, listener,
2289                                                        );
2290                                                    }
2291                                                }
2292                                            }
2293                                        }
2294
2295                                        f(&style, window, cx);
2296
2297                                        if let Some(_hitbox) = hitbox {
2298                                            #[cfg(any(feature = "inspector", debug_assertions))]
2299                                            window.insert_inspector_hitbox(
2300                                                _hitbox.id,
2301                                                _inspector_id,
2302                                                cx,
2303                                            );
2304
2305                                            if let Some(group) = self.group.as_ref() {
2306                                                GroupHitboxes::pop(group, cx);
2307                                            }
2308                                        }
2309                                    })
2310                                },
2311                            );
2312                        });
2313                    });
2314                });
2315
2316                ((), element_state)
2317            },
2318        );
2319    }
2320
2321    #[cfg(debug_assertions)]
2322    fn paint_debug_info(
2323        &self,
2324        global_id: Option<&GlobalElementId>,
2325        hitbox: &Hitbox,
2326        style: &Style,
2327        window: &mut Window,
2328        cx: &mut App,
2329    ) {
2330        use crate::{BorderStyle, TextAlign};
2331
2332        if let Some(global_id) = global_id
2333            && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
2334            && hitbox.is_hovered(window)
2335        {
2336            const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
2337            let element_id = format!("{global_id:?}");
2338            let str_len = element_id.len();
2339
2340            let render_debug_text = |window: &mut Window| {
2341                if let Some(text) = window
2342                    .text_system()
2343                    .shape_text(
2344                        element_id.into(),
2345                        FONT_SIZE,
2346                        &[window.text_style().to_run(str_len)],
2347                        None,
2348                        None,
2349                    )
2350                    .ok()
2351                    .and_then(|mut text| text.pop())
2352                {
2353                    text.paint(hitbox.origin, FONT_SIZE, TextAlign::Left, None, window, cx)
2354                        .ok();
2355
2356                    let text_bounds = crate::Bounds {
2357                        origin: hitbox.origin,
2358                        size: text.size(FONT_SIZE),
2359                    };
2360                    if let Some(source_location) = self.source_location
2361                        && text_bounds.contains(&window.mouse_position())
2362                        && window.modifiers().secondary()
2363                    {
2364                        let secondary_held = window.modifiers().secondary();
2365                        window.on_key_event({
2366                            move |e: &crate::ModifiersChangedEvent, _phase, window, _cx| {
2367                                if e.modifiers.secondary() != secondary_held
2368                                    && text_bounds.contains(&window.mouse_position())
2369                                {
2370                                    window.refresh();
2371                                }
2372                            }
2373                        });
2374
2375                        let was_hovered = hitbox.is_hovered(window);
2376                        let current_view = window.current_view();
2377                        window.on_mouse_event({
2378                            let hitbox = hitbox.clone();
2379                            move |_: &MouseMoveEvent, phase, window, cx| {
2380                                if phase == DispatchPhase::Capture {
2381                                    let hovered = hitbox.is_hovered(window);
2382                                    if hovered != was_hovered {
2383                                        cx.notify(current_view)
2384                                    }
2385                                }
2386                            }
2387                        });
2388
2389                        window.on_mouse_event({
2390                            let hitbox = hitbox.clone();
2391                            move |e: &crate::MouseDownEvent, phase, window, cx| {
2392                                if text_bounds.contains(&e.position)
2393                                    && phase.capture()
2394                                    && hitbox.is_hovered(window)
2395                                {
2396                                    cx.stop_propagation();
2397                                    let Ok(dir) = std::env::current_dir() else {
2398                                        return;
2399                                    };
2400
2401                                    eprintln!(
2402                                        "This element was created at:\n{}:{}:{}",
2403                                        dir.join(source_location.file()).to_string_lossy(),
2404                                        source_location.line(),
2405                                        source_location.column()
2406                                    );
2407                                }
2408                            }
2409                        });
2410                        window.paint_quad(crate::outline(
2411                            crate::Bounds {
2412                                origin: hitbox.origin
2413                                    + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
2414                                size: crate::Size {
2415                                    width: text_bounds.size.width,
2416                                    height: crate::px(1.),
2417                                },
2418                            },
2419                            crate::red(),
2420                            BorderStyle::default(),
2421                        ))
2422                    }
2423                }
2424            };
2425
2426            window.with_text_style(
2427                Some(crate::TextStyleRefinement {
2428                    color: Some(crate::red()),
2429                    line_height: Some(FONT_SIZE.into()),
2430                    background_color: Some(crate::white()),
2431                    ..Default::default()
2432                }),
2433                render_debug_text,
2434            )
2435        }
2436    }
2437
2438    fn paint_mouse_listeners(
2439        &mut self,
2440        hitbox: &Hitbox,
2441        element_state: Option<&mut InteractiveElementState>,
2442        window: &mut Window,
2443        cx: &mut App,
2444    ) {
2445        let is_focused = self
2446            .tracked_focus_handle
2447            .as_ref()
2448            .map(|handle| handle.is_focused(window))
2449            .unwrap_or(false);
2450
2451        // If this element can be focused, register a mouse down listener
2452        // that will automatically transfer focus when hitting the element.
2453        // This behavior can be suppressed by using `cx.prevent_default()`.
2454        if let Some(focus_handle) = self.tracked_focus_handle.clone() {
2455            let hitbox = hitbox.clone();
2456            window.on_mouse_event(move |_: &MouseDownEvent, phase, window, cx| {
2457                if phase == DispatchPhase::Bubble
2458                    && hitbox.is_hovered(window)
2459                    && !window.default_prevented()
2460                {
2461                    window.focus(&focus_handle, cx);
2462                    // If there is a parent that is also focusable, prevent it
2463                    // from transferring focus because we already did so.
2464                    window.prevent_default();
2465                }
2466            });
2467        }
2468
2469        for listener in self.mouse_down_listeners.drain(..) {
2470            let hitbox = hitbox.clone();
2471            window.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {
2472                listener(event, phase, &hitbox, window, cx);
2473            })
2474        }
2475
2476        for listener in self.mouse_up_listeners.drain(..) {
2477            let hitbox = hitbox.clone();
2478            window.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {
2479                listener(event, phase, &hitbox, window, cx);
2480            })
2481        }
2482
2483        for listener in self.mouse_pressure_listeners.drain(..) {
2484            let hitbox = hitbox.clone();
2485            window.on_mouse_event(move |event: &MousePressureEvent, phase, window, cx| {
2486                listener(event, phase, &hitbox, window, cx);
2487            })
2488        }
2489
2490        for listener in self.mouse_move_listeners.drain(..) {
2491            let hitbox = hitbox.clone();
2492            window.on_mouse_event(move |event: &MouseMoveEvent, phase, window, cx| {
2493                listener(event, phase, &hitbox, window, cx);
2494            })
2495        }
2496
2497        for listener in self.scroll_wheel_listeners.drain(..) {
2498            let hitbox = hitbox.clone();
2499            window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {
2500                listener(event, phase, &hitbox, window, cx);
2501            })
2502        }
2503
2504        for listener in self.pinch_listeners.drain(..) {
2505            let hitbox = hitbox.clone();
2506            window.on_mouse_event(move |event: &PinchEvent, phase, window, cx| {
2507                listener(event, phase, &hitbox, window, cx);
2508            })
2509        }
2510
2511        if self.hover_style.is_some()
2512            || self.base_style.mouse_cursor.is_some()
2513            || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
2514        {
2515            let hitbox = hitbox.clone();
2516            let hover_state = self.hover_style.as_ref().and_then(|_| {
2517                element_state
2518                    .as_ref()
2519                    .and_then(|state| state.hover_state.as_ref())
2520                    .cloned()
2521            });
2522            let current_view = window.current_view();
2523
2524            window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2525                let hovered = hitbox.is_hovered(window);
2526                let was_hovered = hover_state
2527                    .as_ref()
2528                    .is_some_and(|state| state.borrow().element);
2529                if phase == DispatchPhase::Capture && hovered != was_hovered {
2530                    if let Some(hover_state) = &hover_state {
2531                        hover_state.borrow_mut().element = hovered;
2532                        cx.notify(current_view);
2533                    }
2534                }
2535            });
2536        }
2537
2538        if let Some(group_hover) = self.group_hover_style.as_ref() {
2539            if let Some(group_hitbox_id) = GroupHitboxes::get(&group_hover.group, cx) {
2540                let hover_state = element_state
2541                    .as_ref()
2542                    .and_then(|element| element.hover_state.as_ref())
2543                    .cloned();
2544                let current_view = window.current_view();
2545
2546                window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2547                    let group_hovered = group_hitbox_id.is_hovered(window);
2548                    let was_group_hovered = hover_state
2549                        .as_ref()
2550                        .is_some_and(|state| state.borrow().group);
2551                    if phase == DispatchPhase::Capture && group_hovered != was_group_hovered {
2552                        if let Some(hover_state) = &hover_state {
2553                            hover_state.borrow_mut().group = group_hovered;
2554                        }
2555                        cx.notify(current_view);
2556                    }
2557                });
2558            }
2559        }
2560
2561        let drag_cursor_style = self.base_style.as_ref().mouse_cursor;
2562
2563        let mut drag_listener = mem::take(&mut self.drag_listener);
2564        let drop_listeners = mem::take(&mut self.drop_listeners);
2565        let click_listeners = mem::take(&mut self.click_listeners);
2566        let aux_click_listeners = mem::take(&mut self.aux_click_listeners);
2567        let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
2568
2569        if !drop_listeners.is_empty() {
2570            let hitbox = hitbox.clone();
2571            window.on_mouse_event({
2572                move |_: &MouseUpEvent, phase, window, cx| {
2573                    if let Some(drag) = &cx.active_drag
2574                        && phase == DispatchPhase::Bubble
2575                        && hitbox.is_hovered(window)
2576                    {
2577                        let drag_state_type = drag.value.as_ref().type_id();
2578                        for (drop_state_type, listener) in &drop_listeners {
2579                            if *drop_state_type == drag_state_type {
2580                                let drag = cx
2581                                    .active_drag
2582                                    .take()
2583                                    .expect("checked for type drag state type above");
2584
2585                                let mut can_drop = true;
2586                                if let Some(predicate) = &can_drop_predicate {
2587                                    can_drop = predicate(drag.value.as_ref(), window, cx);
2588                                }
2589
2590                                if can_drop {
2591                                    listener(drag.value.as_ref(), window, cx);
2592                                    window.refresh();
2593                                    cx.stop_propagation();
2594                                }
2595                            }
2596                        }
2597                    }
2598                }
2599            });
2600        }
2601
2602        if let Some(element_state) = element_state {
2603            if !click_listeners.is_empty()
2604                || !aux_click_listeners.is_empty()
2605                || drag_listener.is_some()
2606            {
2607                let pending_mouse_down = element_state
2608                    .pending_mouse_down
2609                    .get_or_insert_with(Default::default)
2610                    .clone();
2611
2612                let clicked_state = element_state
2613                    .clicked_state
2614                    .get_or_insert_with(Default::default)
2615                    .clone();
2616
2617                window.on_mouse_event({
2618                    let pending_mouse_down = pending_mouse_down.clone();
2619                    let hitbox = hitbox.clone();
2620                    let has_aux_click_listeners = !aux_click_listeners.is_empty();
2621                    move |event: &MouseDownEvent, phase, window, _cx| {
2622                        if phase == DispatchPhase::Bubble
2623                            && (event.button == MouseButton::Left || has_aux_click_listeners)
2624                            && hitbox.is_hovered(window)
2625                        {
2626                            *pending_mouse_down.borrow_mut() = Some(event.clone());
2627                            window.refresh();
2628                        }
2629                    }
2630                });
2631
2632                window.on_mouse_event({
2633                    let pending_mouse_down = pending_mouse_down.clone();
2634                    let hitbox = hitbox.clone();
2635                    move |event: &MouseMoveEvent, phase, window, cx| {
2636                        if phase == DispatchPhase::Capture {
2637                            return;
2638                        }
2639
2640                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
2641                        if let Some(mouse_down) = pending_mouse_down.clone()
2642                            && !cx.has_active_drag()
2643                            && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD
2644                            && let Some((drag_value, drag_listener)) = drag_listener.take()
2645                            && mouse_down.button == MouseButton::Left
2646                        {
2647                            *clicked_state.borrow_mut() = ElementClickedState::default();
2648                            let cursor_offset = event.position - hitbox.origin;
2649                            let drag = (drag_listener)(
2650                                drag_value.as_ref(),
2651                                cursor_offset,
2652                                hitbox.bounds,
2653                                window,
2654                                cx,
2655                            );
2656                            cx.active_drag = Some(AnyDrag {
2657                                view: drag,
2658                                value: drag_value,
2659                                cursor_offset,
2660                                cursor_style: drag_cursor_style,
2661                            });
2662                            pending_mouse_down.take();
2663                            window.refresh();
2664                            cx.stop_propagation();
2665                        }
2666                    }
2667                });
2668
2669                if is_focused {
2670                    // Press enter, space to trigger click, when the element is focused.
2671                    window.on_key_event({
2672                        let click_listeners = click_listeners.clone();
2673                        let hitbox = hitbox.clone();
2674                        move |event: &KeyUpEvent, phase, window, cx| {
2675                            if phase.bubble() && !window.default_prevented() {
2676                                let stroke = &event.keystroke;
2677                                let keyboard_button = if stroke.key.eq("enter") {
2678                                    Some(KeyboardButton::Enter)
2679                                } else if stroke.key.eq("space") {
2680                                    Some(KeyboardButton::Space)
2681                                } else {
2682                                    None
2683                                };
2684
2685                                if let Some(button) = keyboard_button
2686                                    && !stroke.modifiers.modified()
2687                                {
2688                                    let click_event = ClickEvent::Keyboard(KeyboardClickEvent {
2689                                        button,
2690                                        bounds: hitbox.bounds,
2691                                    });
2692
2693                                    for listener in &click_listeners {
2694                                        listener(&click_event, window, cx);
2695                                    }
2696                                }
2697                            }
2698                        }
2699                    });
2700                }
2701
2702                window.on_mouse_event({
2703                    let mut captured_mouse_down = None;
2704                    let hitbox = hitbox.clone();
2705                    move |event: &MouseUpEvent, phase, window, cx| match phase {
2706                        // Clear the pending mouse down during the capture phase,
2707                        // so that it happens even if another event handler stops
2708                        // propagation.
2709                        DispatchPhase::Capture => {
2710                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
2711                            if pending_mouse_down.is_some() && hitbox.is_hovered(window) {
2712                                captured_mouse_down = pending_mouse_down.take();
2713                                window.refresh();
2714                            } else if pending_mouse_down.is_some() {
2715                                // Clear the pending mouse down event (without firing click handlers)
2716                                // if the hitbox is not being hovered.
2717                                // This avoids dragging elements that changed their position
2718                                // immediately after being clicked.
2719                                // See https://github.com/zed-industries/zed/issues/24600 for more details
2720                                pending_mouse_down.take();
2721                                window.refresh();
2722                            }
2723                        }
2724                        // Fire click handlers during the bubble phase.
2725                        DispatchPhase::Bubble => {
2726                            if let Some(mouse_down) = captured_mouse_down.take() {
2727                                let btn = mouse_down.button;
2728
2729                                let mouse_click = ClickEvent::Mouse(MouseClickEvent {
2730                                    down: mouse_down,
2731                                    up: event.clone(),
2732                                });
2733
2734                                match btn {
2735                                    MouseButton::Left => {
2736                                        for listener in &click_listeners {
2737                                            listener(&mouse_click, window, cx);
2738                                        }
2739                                    }
2740                                    _ => {
2741                                        for listener in &aux_click_listeners {
2742                                            listener(&mouse_click, window, cx);
2743                                        }
2744                                    }
2745                                }
2746                            }
2747                        }
2748                    }
2749                });
2750            }
2751
2752            if let Some(hover_listener) = self.hover_listener.take() {
2753                let hitbox = hitbox.clone();
2754                let was_hovered = element_state
2755                    .hover_listener_state
2756                    .get_or_insert_with(Default::default)
2757                    .clone();
2758                let has_mouse_down = element_state
2759                    .pending_mouse_down
2760                    .get_or_insert_with(Default::default)
2761                    .clone();
2762
2763                window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2764                    if phase != DispatchPhase::Bubble {
2765                        return;
2766                    }
2767                    let is_hovered = has_mouse_down.borrow().is_none()
2768                        && !cx.has_active_drag()
2769                        && hitbox.is_hovered(window);
2770                    let mut was_hovered = was_hovered.borrow_mut();
2771
2772                    if is_hovered != *was_hovered {
2773                        *was_hovered = is_hovered;
2774                        drop(was_hovered);
2775
2776                        hover_listener(&is_hovered, window, cx);
2777                    }
2778                });
2779            }
2780
2781            if let Some(tooltip_builder) = self.tooltip_builder.take() {
2782                let active_tooltip = element_state
2783                    .active_tooltip
2784                    .get_or_insert_with(Default::default)
2785                    .clone();
2786                let pending_mouse_down = element_state
2787                    .pending_mouse_down
2788                    .get_or_insert_with(Default::default)
2789                    .clone();
2790
2791                let tooltip_is_hoverable = tooltip_builder.hoverable;
2792                let build_tooltip = Rc::new(move |window: &mut Window, cx: &mut App| {
2793                    Some(((tooltip_builder.build)(window, cx), tooltip_is_hoverable))
2794                });
2795                // Use bounds instead of testing hitbox since this is called during prepaint.
2796                let check_is_hovered_during_prepaint = Rc::new({
2797                    let pending_mouse_down = pending_mouse_down.clone();
2798                    let source_bounds = hitbox.bounds;
2799                    move |window: &Window| {
2800                        !window.last_input_was_keyboard()
2801                            && pending_mouse_down.borrow().is_none()
2802                            && source_bounds.contains(&window.mouse_position())
2803                    }
2804                });
2805                let check_is_hovered = Rc::new({
2806                    let hitbox = hitbox.clone();
2807                    move |window: &Window| {
2808                        pending_mouse_down.borrow().is_none() && hitbox.is_hovered(window)
2809                    }
2810                });
2811                register_tooltip_mouse_handlers(
2812                    &active_tooltip,
2813                    self.tooltip_id,
2814                    build_tooltip,
2815                    check_is_hovered,
2816                    check_is_hovered_during_prepaint,
2817                    self.tooltip_show_delay,
2818                    window,
2819                );
2820            }
2821
2822            // We unconditionally bind both the mouse up and mouse down active state handlers
2823            // Because we might not get a chance to render a frame before the mouse up event arrives.
2824            let active_state = element_state
2825                .clicked_state
2826                .get_or_insert_with(Default::default)
2827                .clone();
2828
2829            {
2830                let active_state = active_state.clone();
2831                window.on_mouse_event(move |_: &MouseUpEvent, phase, window, _cx| {
2832                    if phase == DispatchPhase::Capture && active_state.borrow().is_clicked() {
2833                        *active_state.borrow_mut() = ElementClickedState::default();
2834                        window.refresh();
2835                    }
2836                });
2837            }
2838
2839            {
2840                let active_group_hitbox = self
2841                    .group_active_style
2842                    .as_ref()
2843                    .and_then(|group_active| GroupHitboxes::get(&group_active.group, cx));
2844                let hitbox = hitbox.clone();
2845                window.on_mouse_event(move |_: &MouseDownEvent, phase, window, _cx| {
2846                    if phase == DispatchPhase::Bubble && !window.default_prevented() {
2847                        let group_hovered = active_group_hitbox
2848                            .is_some_and(|group_hitbox_id| group_hitbox_id.is_hovered(window));
2849                        let element_hovered = hitbox.is_hovered(window);
2850                        if group_hovered || element_hovered {
2851                            *active_state.borrow_mut() = ElementClickedState {
2852                                group: group_hovered,
2853                                element: element_hovered,
2854                            };
2855                            window.refresh();
2856                        }
2857                    }
2858                });
2859            }
2860        }
2861    }
2862
2863    fn paint_keyboard_listeners(&mut self, window: &mut Window, _cx: &mut App) {
2864        let key_down_listeners = mem::take(&mut self.key_down_listeners);
2865        let key_up_listeners = mem::take(&mut self.key_up_listeners);
2866        let modifiers_changed_listeners = mem::take(&mut self.modifiers_changed_listeners);
2867        let action_listeners = mem::take(&mut self.action_listeners);
2868        if let Some(context) = self.key_context.clone() {
2869            window.set_key_context(context);
2870        }
2871
2872        for listener in key_down_listeners {
2873            window.on_key_event(move |event: &KeyDownEvent, phase, window, cx| {
2874                listener(event, phase, window, cx);
2875            })
2876        }
2877
2878        for listener in key_up_listeners {
2879            window.on_key_event(move |event: &KeyUpEvent, phase, window, cx| {
2880                listener(event, phase, window, cx);
2881            })
2882        }
2883
2884        for listener in modifiers_changed_listeners {
2885            window.on_modifiers_changed(move |event: &ModifiersChangedEvent, window, cx| {
2886                listener(event, window, cx);
2887            })
2888        }
2889
2890        for (action_type, listener) in action_listeners {
2891            window.on_action(action_type, listener)
2892        }
2893    }
2894
2895    fn paint_hover_group_handler(&self, window: &mut Window, cx: &mut App) {
2896        let group_hitbox = self
2897            .group_hover_style
2898            .as_ref()
2899            .and_then(|group_hover| GroupHitboxes::get(&group_hover.group, cx));
2900
2901        if let Some(group_hitbox) = group_hitbox {
2902            let was_hovered = group_hitbox.is_hovered(window);
2903            let current_view = window.current_view();
2904            window.on_mouse_event(move |_: &MouseMoveEvent, phase, window, cx| {
2905                let hovered = group_hitbox.is_hovered(window);
2906                if phase == DispatchPhase::Capture && hovered != was_hovered {
2907                    cx.notify(current_view);
2908                }
2909            });
2910        }
2911    }
2912
2913    fn paint_scroll_listener(
2914        &self,
2915        hitbox: &Hitbox,
2916        style: &Style,
2917        window: &mut Window,
2918        _cx: &mut App,
2919    ) {
2920        if let Some(scroll_offset) = self.scroll_offset.clone() {
2921            let overflow = style.overflow;
2922            let allow_concurrent_scroll = style.allow_concurrent_scroll;
2923            let restrict_scroll_to_axis = style.restrict_scroll_to_axis;
2924            let line_height = window.line_height();
2925            let hitbox = hitbox.clone();
2926            let current_view = window.current_view();
2927            window.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {
2928                if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
2929                    let mut scroll_offset = scroll_offset.borrow_mut();
2930                    let old_scroll_offset = *scroll_offset;
2931                    let delta = event.delta.pixel_delta(line_height);
2932
2933                    let mut delta_x = Pixels::ZERO;
2934                    if overflow.x == Overflow::Scroll {
2935                        if !delta.x.is_zero() {
2936                            delta_x = delta.x;
2937                        } else if !restrict_scroll_to_axis && overflow.y != Overflow::Scroll {
2938                            delta_x = delta.y;
2939                        }
2940                    }
2941                    let mut delta_y = Pixels::ZERO;
2942                    if overflow.y == Overflow::Scroll {
2943                        if !delta.y.is_zero() {
2944                            delta_y = delta.y;
2945                        } else if !restrict_scroll_to_axis && overflow.x != Overflow::Scroll {
2946                            delta_y = delta.x;
2947                        }
2948                    }
2949                    if !allow_concurrent_scroll && !delta_x.is_zero() && !delta_y.is_zero() {
2950                        if delta_x.abs() > delta_y.abs() {
2951                            delta_y = Pixels::ZERO;
2952                        } else {
2953                            delta_x = Pixels::ZERO;
2954                        }
2955                    }
2956                    scroll_offset.y += delta_y;
2957                    scroll_offset.x += delta_x;
2958                    if !delta_x.is_zero() || !delta_y.is_zero() {
2959                        // Consume the wheel whenever this scroll container handled it, even if
2960                        // it was already pinned at an edge. That keeps nested scrollables from
2961                        // leaking wheel input to their ancestors.
2962                        window.prevent_default();
2963                        cx.stop_propagation();
2964                        if *scroll_offset != old_scroll_offset {
2965                            cx.notify(current_view);
2966                        }
2967                    }
2968                }
2969            });
2970        }
2971    }
2972
2973    /// Compute the visual style for this element, based on the current bounds and the element's state.
2974    pub fn compute_style(
2975        &self,
2976        global_id: Option<&GlobalElementId>,
2977        hitbox: Option<&Hitbox>,
2978        window: &mut Window,
2979        cx: &mut App,
2980    ) -> Style {
2981        window.with_optional_element_state(global_id, |element_state, window| {
2982            let mut element_state =
2983                element_state.map(|element_state| element_state.unwrap_or_default());
2984            let style = self.compute_style_internal(hitbox, element_state.as_mut(), window, cx);
2985            (style, element_state)
2986        })
2987    }
2988
2989    /// Called from internal methods that have already called with_element_state.
2990    fn compute_style_internal(
2991        &self,
2992        hitbox: Option<&Hitbox>,
2993        element_state: Option<&mut InteractiveElementState>,
2994        window: &mut Window,
2995        cx: &mut App,
2996    ) -> Style {
2997        let mut style = Style::default();
2998        style.refine(&self.base_style);
2999
3000        if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
3001            if let Some(in_focus_style) = self.in_focus_style.as_ref()
3002                && focus_handle.within_focused(window, cx)
3003            {
3004                style.refine(in_focus_style);
3005            }
3006
3007            if let Some(focus_style) = self.focus_style.as_ref()
3008                && focus_handle.is_focused(window)
3009            {
3010                style.refine(focus_style);
3011            }
3012
3013            if let Some(focus_visible_style) = self.focus_visible_style.as_ref()
3014                && focus_handle.is_focused(window)
3015                && window.last_input_was_keyboard()
3016            {
3017                style.refine(focus_visible_style);
3018            }
3019        }
3020
3021        if !cx.has_active_drag() {
3022            if let Some(group_hover) = self.group_hover_style.as_ref() {
3023                let is_group_hovered =
3024                    if let Some(group_hitbox_id) = GroupHitboxes::get(&group_hover.group, cx) {
3025                        group_hitbox_id.is_hovered(window)
3026                    } else if let Some(element_state) = element_state.as_ref() {
3027                        element_state
3028                            .hover_state
3029                            .as_ref()
3030                            .map(|state| state.borrow().group)
3031                            .unwrap_or(false)
3032                    } else {
3033                        false
3034                    };
3035
3036                if is_group_hovered {
3037                    style.refine(&group_hover.style);
3038                }
3039            }
3040
3041            if let Some(hover_style) = self.hover_style.as_ref() {
3042                let is_hovered = if let Some(hitbox) = hitbox {
3043                    hitbox.is_hovered(window)
3044                } else if let Some(element_state) = element_state.as_ref() {
3045                    element_state
3046                        .hover_state
3047                        .as_ref()
3048                        .map(|state| state.borrow().element)
3049                        .unwrap_or(false)
3050                } else {
3051                    false
3052                };
3053
3054                if is_hovered {
3055                    style.refine(hover_style);
3056                }
3057            }
3058        }
3059
3060        if let Some(hitbox) = hitbox {
3061            if let Some(drag) = cx.active_drag.take() {
3062                let mut can_drop = true;
3063                if let Some(can_drop_predicate) = &self.can_drop_predicate {
3064                    can_drop = can_drop_predicate(drag.value.as_ref(), window, cx);
3065                }
3066
3067                if can_drop {
3068                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
3069                        if let Some(group_hitbox_id) =
3070                            GroupHitboxes::get(&group_drag_style.group, cx)
3071                            && *state_type == drag.value.as_ref().type_id()
3072                            && group_hitbox_id.is_hovered(window)
3073                        {
3074                            style.refine(&group_drag_style.style);
3075                        }
3076                    }
3077
3078                    for (state_type, build_drag_over_style) in &self.drag_over_styles {
3079                        if *state_type == drag.value.as_ref().type_id() && hitbox.is_hovered(window)
3080                        {
3081                            style.refine(&build_drag_over_style(drag.value.as_ref(), window, cx));
3082                        }
3083                    }
3084                }
3085
3086                style.mouse_cursor = if window.is_mouse_in_window() {
3087                    drag.cursor_style
3088                } else {
3089                    None
3090                };
3091                cx.active_drag = Some(drag);
3092            }
3093        }
3094
3095        if let Some(element_state) = element_state {
3096            let clicked_state = element_state
3097                .clicked_state
3098                .get_or_insert_with(Default::default)
3099                .borrow();
3100            if clicked_state.group
3101                && let Some(group) = self.group_active_style.as_ref()
3102            {
3103                style.refine(&group.style)
3104            }
3105
3106            if let Some(active_style) = self.active_style.as_ref()
3107                && clicked_state.element
3108            {
3109                style.refine(active_style)
3110            }
3111        }
3112
3113        style
3114    }
3115
3116    pub(crate) fn write_a11y_info(&self, node: &mut accesskit::Node) {
3117        if let Some(label) = &self.aria_label {
3118            node.set_label(label.to_string());
3119        }
3120        if let Some(controls) = &self.aria_controls {
3121            node.set_controls(controls.clone());
3122        }
3123        if let Some(labelled_by) = &self.aria_labelled_by {
3124            node.set_labelled_by(labelled_by.clone());
3125        }
3126        if let Some(selected) = self.aria_selected {
3127            node.set_selected(selected);
3128        }
3129        if let Some(required) = self.aria_required {
3130            if required {
3131                node.set_required();
3132            } else {
3133                node.clear_required();
3134            }
3135        }
3136        if let Some(disabled) = self.aria_disabled {
3137            if disabled {
3138                node.set_disabled();
3139            } else {
3140                node.clear_disabled();
3141            }
3142        }
3143        if let Some(expanded) = self.aria_expanded {
3144            node.set_expanded(expanded);
3145        }
3146        if let Some(toggled) = self.aria_toggled {
3147            node.set_toggled(toggled);
3148        }
3149        if let Some(value) = self.aria_numeric_value {
3150            node.set_numeric_value(value);
3151        }
3152        if let Some(value) = self.aria_min_numeric_value {
3153            node.set_min_numeric_value(value);
3154        }
3155        if let Some(value) = self.aria_max_numeric_value {
3156            node.set_max_numeric_value(value);
3157        }
3158        if let Some(orientation) = self.aria_orientation {
3159            node.set_orientation(orientation);
3160        }
3161        if let Some(level) = self.aria_level {
3162            node.set_level(level);
3163        }
3164        if let Some(position) = self.aria_position_in_set {
3165            node.set_position_in_set(position);
3166        }
3167        if let Some(size) = self.aria_size_of_set {
3168            node.set_size_of_set(size);
3169        }
3170        if let Some(index) = self.aria_row_index {
3171            node.set_row_index(index);
3172        }
3173        if let Some(index) = self.aria_column_index {
3174            node.set_column_index(index);
3175        }
3176        if let Some(count) = self.aria_row_count {
3177            node.set_row_count(count);
3178        }
3179        if let Some(count) = self.aria_column_count {
3180            node.set_column_count(count);
3181        }
3182        if !self.click_listeners.is_empty() {
3183            node.add_action(accesskit::Action::Click);
3184        }
3185        if self.tracked_focus_handle.is_some() || self.focusable {
3186            node.add_action(accesskit::Action::Focus);
3187        }
3188        for (action, _) in &self.a11y_action_listeners {
3189            node.add_action(*action);
3190        }
3191    }
3192}
3193
3194/// The per-frame state of an interactive element. Used for tracking stateful interactions like clicks
3195/// and scroll offsets.
3196#[derive(Default)]
3197pub struct InteractiveElementState {
3198    pub(crate) focus_handle: Option<FocusHandle>,
3199    pub(crate) clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
3200    pub(crate) hover_state: Option<Rc<RefCell<ElementHoverState>>>,
3201    pub(crate) hover_listener_state: Option<Rc<RefCell<bool>>>,
3202    pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
3203    pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
3204    pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
3205}
3206
3207/// Whether or not the element or a group that contains it is clicked by the mouse.
3208#[derive(Copy, Clone, Default, Eq, PartialEq)]
3209pub struct ElementClickedState {
3210    /// True if this element's group has been clicked, false otherwise
3211    pub group: bool,
3212
3213    /// True if this element has been clicked, false otherwise
3214    pub element: bool,
3215}
3216
3217impl ElementClickedState {
3218    fn is_clicked(&self) -> bool {
3219        self.group || self.element
3220    }
3221}
3222
3223/// Whether or not the element or a group that contains it is hovered.
3224#[derive(Copy, Clone, Default, Eq, PartialEq)]
3225pub struct ElementHoverState {
3226    /// True if this element's group is hovered, false otherwise
3227    pub group: bool,
3228
3229    /// True if this element is hovered, false otherwise
3230    pub element: bool,
3231}
3232
3233pub(crate) enum ActiveTooltip {
3234    /// Currently delaying before showing the tooltip.
3235    WaitingForShow { _task: Task<()> },
3236    /// Tooltip is visible, element was hovered or for hoverable tooltips, the tooltip was hovered.
3237    Visible {
3238        tooltip: AnyTooltip,
3239        is_hoverable: bool,
3240    },
3241    /// Tooltip is visible and hoverable, but the mouse is no longer hovering. Currently delaying
3242    /// before hiding it.
3243    WaitingForHide {
3244        tooltip: AnyTooltip,
3245        _task: Task<()>,
3246    },
3247}
3248
3249pub(crate) fn clear_active_tooltip(
3250    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3251    window: &mut Window,
3252) {
3253    match active_tooltip.borrow_mut().take() {
3254        None => {}
3255        Some(ActiveTooltip::WaitingForShow { .. }) => {}
3256        Some(ActiveTooltip::Visible { .. }) => window.refresh(),
3257        Some(ActiveTooltip::WaitingForHide { .. }) => window.refresh(),
3258    }
3259}
3260
3261pub(crate) fn clear_active_tooltip_if_not_hoverable(
3262    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3263    window: &mut Window,
3264) {
3265    let should_clear = match active_tooltip.borrow().as_ref() {
3266        None => false,
3267        Some(ActiveTooltip::WaitingForShow { .. }) => false,
3268        Some(ActiveTooltip::Visible { is_hoverable, .. }) => !is_hoverable,
3269        Some(ActiveTooltip::WaitingForHide { .. }) => false,
3270    };
3271    if should_clear {
3272        active_tooltip.borrow_mut().take();
3273        window.refresh();
3274    }
3275}
3276
3277pub(crate) fn set_tooltip_on_window(
3278    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3279    window: &mut Window,
3280) -> Option<TooltipId> {
3281    let tooltip = match active_tooltip.borrow().as_ref() {
3282        None => return None,
3283        Some(ActiveTooltip::WaitingForShow { .. }) => return None,
3284        Some(ActiveTooltip::Visible { tooltip, .. }) => tooltip.clone(),
3285        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => tooltip.clone(),
3286    };
3287    Some(window.set_tooltip(tooltip))
3288}
3289
3290pub(crate) fn register_tooltip_mouse_handlers(
3291    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3292    tooltip_id: Option<TooltipId>,
3293    build_tooltip: Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
3294    check_is_hovered: Rc<dyn Fn(&Window) -> bool>,
3295    check_is_hovered_during_prepaint: Rc<dyn Fn(&Window) -> bool>,
3296    show_delay: Option<Duration>,
3297    window: &mut Window,
3298) {
3299    let current_view = window.current_view();
3300    let show_delay = show_delay.unwrap_or(DEFAULT_TOOLTIP_SHOW_DELAY);
3301
3302    window.on_mouse_event({
3303        let active_tooltip = active_tooltip.clone();
3304        let build_tooltip = build_tooltip.clone();
3305        let check_is_hovered = check_is_hovered.clone();
3306        move |_: &MouseMoveEvent, phase, window, cx| {
3307            handle_tooltip_mouse_move(
3308                &active_tooltip,
3309                &build_tooltip,
3310                &check_is_hovered,
3311                &check_is_hovered_during_prepaint,
3312                tooltip_id,
3313                current_view,
3314                phase,
3315                show_delay,
3316                window,
3317                cx,
3318            )
3319        }
3320    });
3321
3322    window.on_mouse_event({
3323        let active_tooltip = active_tooltip.clone();
3324        move |_: &MouseDownEvent, _phase, window: &mut Window, _cx| {
3325            if !tooltip_id.is_some_and(|tooltip_id| tooltip_id.is_hovered(window)) {
3326                clear_active_tooltip_if_not_hoverable(&active_tooltip, window);
3327            }
3328        }
3329    });
3330
3331    window.on_mouse_event({
3332        let active_tooltip = active_tooltip.clone();
3333        move |_: &ScrollWheelEvent, _phase, window: &mut Window, _cx| {
3334            if !tooltip_id.is_some_and(|tooltip_id| tooltip_id.is_hovered(window)) {
3335                clear_active_tooltip_if_not_hoverable(&active_tooltip, window);
3336            }
3337        }
3338    });
3339}
3340
3341/// Handles displaying tooltips when an element is hovered.
3342///
3343/// The mouse hovering logic also relies on being called from window prepaint in order to handle the
3344/// case where the element the tooltip is on is not rendered - in that case its mouse listeners are
3345/// also not registered. During window prepaint, the hitbox information is not available, so
3346/// `check_is_hovered_during_prepaint` is used which bases the check off of the absolute bounds of
3347/// the element.
3348///
3349/// TODO: There's a minor bug due to the use of absolute bounds while checking during prepaint - it
3350/// does not know if the hitbox is occluded. In the case where a tooltip gets displayed and then
3351/// gets occluded after display, it will stick around until the mouse exits the hover bounds.
3352fn handle_tooltip_mouse_move(
3353    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3354    build_tooltip: &Rc<dyn Fn(&mut Window, &mut App) -> Option<(AnyView, bool)>>,
3355    check_is_hovered: &Rc<dyn Fn(&Window) -> bool>,
3356    check_is_hovered_during_prepaint: &Rc<dyn Fn(&Window) -> bool>,
3357    tooltip_id: Option<TooltipId>,
3358    current_view: EntityId,
3359    phase: DispatchPhase,
3360    show_delay: Duration,
3361    window: &mut Window,
3362    cx: &mut App,
3363) {
3364    // Separates logic for what mutation should occur from applying it, to avoid overlapping
3365    // RefCell borrows.
3366    enum Action {
3367        None,
3368        CancelShow,
3369        ScheduleShow,
3370        CheckVisible,
3371    }
3372
3373    let action = match active_tooltip.borrow().as_ref() {
3374        None => {
3375            let is_hovered = check_is_hovered(window);
3376            if is_hovered && phase.bubble() {
3377                Action::ScheduleShow
3378            } else {
3379                Action::None
3380            }
3381        }
3382        Some(ActiveTooltip::WaitingForShow { .. }) => {
3383            let is_hovered = check_is_hovered(window);
3384            if is_hovered {
3385                Action::None
3386            } else {
3387                Action::CancelShow
3388            }
3389        }
3390        Some(ActiveTooltip::Visible { is_hoverable, .. }) => {
3391            if phase.capture()
3392                && !check_is_hovered(window)
3393                && (!*is_hoverable
3394                    || !tooltip_id.is_some_and(|tooltip_id| tooltip_id.is_hovered(window)))
3395            {
3396                Action::CheckVisible
3397            } else {
3398                Action::None
3399            }
3400        }
3401        Some(ActiveTooltip::WaitingForHide { .. }) => {
3402            if phase.capture()
3403                && (check_is_hovered(window)
3404                    || tooltip_id.is_some_and(|tooltip_id| tooltip_id.is_hovered(window)))
3405            {
3406                Action::CheckVisible
3407            } else {
3408                Action::None
3409            }
3410        }
3411    };
3412
3413    match action {
3414        Action::None => {}
3415        Action::CancelShow => {
3416            // Cancel waiting to show tooltip when it is no longer hovered.
3417            active_tooltip.borrow_mut().take();
3418        }
3419        Action::ScheduleShow => {
3420            let delayed_show_task = window.spawn(cx, {
3421                let weak_active_tooltip = Rc::downgrade(active_tooltip);
3422                let build_tooltip = build_tooltip.clone();
3423                let check_is_hovered_during_prepaint = check_is_hovered_during_prepaint.clone();
3424                async move |cx| {
3425                    cx.background_executor().timer(show_delay).await;
3426                    let Some(active_tooltip) = weak_active_tooltip.upgrade() else {
3427                        return;
3428                    };
3429                    cx.update(|window, cx| {
3430                        let new_tooltip =
3431                            build_tooltip(window, cx).map(|(view, tooltip_is_hoverable)| {
3432                                let weak_active_tooltip = Rc::downgrade(&active_tooltip);
3433                                ActiveTooltip::Visible {
3434                                    tooltip: AnyTooltip {
3435                                        view,
3436                                        mouse_position: window.mouse_position(),
3437                                        check_visible_and_update: Rc::new(
3438                                            move |tooltip_bounds, window, cx| {
3439                                                let Some(active_tooltip) =
3440                                                    weak_active_tooltip.upgrade()
3441                                                else {
3442                                                    return false;
3443                                                };
3444                                                handle_tooltip_check_visible_and_update(
3445                                                    &active_tooltip,
3446                                                    tooltip_is_hoverable,
3447                                                    &check_is_hovered_during_prepaint,
3448                                                    tooltip_bounds,
3449                                                    window,
3450                                                    cx,
3451                                                )
3452                                            },
3453                                        ),
3454                                    },
3455                                    is_hoverable: tooltip_is_hoverable,
3456                                }
3457                            });
3458                        *active_tooltip.borrow_mut() = new_tooltip;
3459                        window.refresh();
3460                    })
3461                    .ok();
3462                }
3463            });
3464            active_tooltip
3465                .borrow_mut()
3466                .replace(ActiveTooltip::WaitingForShow {
3467                    _task: delayed_show_task,
3468                });
3469        }
3470        Action::CheckVisible => cx.notify(current_view),
3471    }
3472}
3473
3474/// Returns a callback which will be called by window prepaint to update tooltip visibility. The
3475/// purpose of doing this logic here instead of the mouse move handler is that the mouse move
3476/// handler won't get called when the element is not painted (e.g. via use of `visible_on_hover`).
3477fn handle_tooltip_check_visible_and_update(
3478    active_tooltip: &Rc<RefCell<Option<ActiveTooltip>>>,
3479    tooltip_is_hoverable: bool,
3480    check_is_hovered: &Rc<dyn Fn(&Window) -> bool>,
3481    tooltip_bounds: Bounds<Pixels>,
3482    window: &mut Window,
3483    cx: &mut App,
3484) -> bool {
3485    // Separates logic for what mutation should occur from applying it, to avoid overlapping RefCell
3486    // borrows.
3487    enum Action {
3488        None,
3489        Hide,
3490        ScheduleHide(AnyTooltip),
3491        CancelHide(AnyTooltip),
3492    }
3493
3494    let is_hovered = check_is_hovered(window)
3495        || (tooltip_is_hoverable && tooltip_bounds.contains(&window.mouse_position()));
3496    let action = match active_tooltip.borrow().as_ref() {
3497        Some(ActiveTooltip::Visible { tooltip, .. }) => {
3498            if is_hovered {
3499                Action::None
3500            } else {
3501                if tooltip_is_hoverable {
3502                    Action::ScheduleHide(tooltip.clone())
3503                } else {
3504                    Action::Hide
3505                }
3506            }
3507        }
3508        Some(ActiveTooltip::WaitingForHide { tooltip, .. }) => {
3509            if is_hovered {
3510                Action::CancelHide(tooltip.clone())
3511            } else {
3512                Action::None
3513            }
3514        }
3515        None | Some(ActiveTooltip::WaitingForShow { .. }) => Action::None,
3516    };
3517
3518    match action {
3519        Action::None => {}
3520        Action::Hide => clear_active_tooltip(active_tooltip, window),
3521        Action::ScheduleHide(tooltip) => {
3522            let delayed_hide_task = window.spawn(cx, {
3523                let weak_active_tooltip = Rc::downgrade(active_tooltip);
3524                async move |cx| {
3525                    cx.background_executor()
3526                        .timer(HOVERABLE_TOOLTIP_HIDE_DELAY)
3527                        .await;
3528                    let Some(active_tooltip) = weak_active_tooltip.upgrade() else {
3529                        return;
3530                    };
3531                    if active_tooltip.borrow_mut().take().is_some() {
3532                        cx.update(|window, _cx| window.refresh()).ok();
3533                    }
3534                }
3535            });
3536            active_tooltip
3537                .borrow_mut()
3538                .replace(ActiveTooltip::WaitingForHide {
3539                    tooltip,
3540                    _task: delayed_hide_task,
3541                });
3542        }
3543        Action::CancelHide(tooltip) => {
3544            // Cancel waiting to hide tooltip when it becomes hovered.
3545            active_tooltip.borrow_mut().replace(ActiveTooltip::Visible {
3546                tooltip,
3547                is_hoverable: true,
3548            });
3549        }
3550    }
3551
3552    active_tooltip.borrow().is_some()
3553}
3554
3555#[derive(Default)]
3556pub(crate) struct GroupHitboxes(HashMap<SharedString, SmallVec<[HitboxId; 1]>>);
3557
3558impl Global for GroupHitboxes {}
3559
3560impl GroupHitboxes {
3561    pub fn get(name: &SharedString, cx: &mut App) -> Option<HitboxId> {
3562        cx.default_global::<Self>()
3563            .0
3564            .get(name)
3565            .and_then(|bounds_stack| bounds_stack.last())
3566            .cloned()
3567    }
3568
3569    pub fn push(name: SharedString, hitbox_id: HitboxId, cx: &mut App) {
3570        cx.default_global::<Self>()
3571            .0
3572            .entry(name)
3573            .or_default()
3574            .push(hitbox_id);
3575    }
3576
3577    pub fn pop(name: &SharedString, cx: &mut App) {
3578        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
3579    }
3580}
3581
3582/// A wrapper around an element that can store state, produced after assigning an ElementId.
3583pub struct Stateful<E> {
3584    pub(crate) element: E,
3585}
3586
3587impl<E> Styled for Stateful<E>
3588where
3589    E: Styled,
3590{
3591    fn style(&mut self) -> &mut StyleRefinement {
3592        self.element.style()
3593    }
3594}
3595
3596impl<E> StatefulInteractiveElement for Stateful<E>
3597where
3598    E: Element,
3599    Self: InteractiveElement,
3600{
3601}
3602
3603impl<E> InteractiveElement for Stateful<E>
3604where
3605    E: InteractiveElement,
3606{
3607    fn interactivity(&mut self) -> &mut Interactivity {
3608        self.element.interactivity()
3609    }
3610}
3611
3612impl<E> Element for Stateful<E>
3613where
3614    E: Element,
3615{
3616    type RequestLayoutState = E::RequestLayoutState;
3617    type PrepaintState = E::PrepaintState;
3618
3619    fn id(&self) -> Option<ElementId> {
3620        self.element.id()
3621    }
3622
3623    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
3624        self.element.source_location()
3625    }
3626
3627    fn a11y_role(&self) -> Option<accesskit::Role> {
3628        self.element.a11y_role()
3629    }
3630
3631    fn write_a11y_info(&self, node: &mut accesskit::Node) {
3632        self.element.write_a11y_info(node);
3633    }
3634
3635    fn request_layout(
3636        &mut self,
3637        id: Option<&GlobalElementId>,
3638        inspector_id: Option<&InspectorElementId>,
3639        window: &mut Window,
3640        cx: &mut App,
3641    ) -> (LayoutId, Self::RequestLayoutState) {
3642        self.element.request_layout(id, inspector_id, window, cx)
3643    }
3644
3645    fn prepaint(
3646        &mut self,
3647        id: Option<&GlobalElementId>,
3648        inspector_id: Option<&InspectorElementId>,
3649        bounds: Bounds<Pixels>,
3650        state: &mut Self::RequestLayoutState,
3651        window: &mut Window,
3652        cx: &mut App,
3653    ) -> E::PrepaintState {
3654        self.element
3655            .prepaint(id, inspector_id, bounds, state, window, cx)
3656    }
3657
3658    fn paint(
3659        &mut self,
3660        id: Option<&GlobalElementId>,
3661        inspector_id: Option<&InspectorElementId>,
3662        bounds: Bounds<Pixels>,
3663        request_layout: &mut Self::RequestLayoutState,
3664        prepaint: &mut Self::PrepaintState,
3665        window: &mut Window,
3666        cx: &mut App,
3667    ) {
3668        self.element.paint(
3669            id,
3670            inspector_id,
3671            bounds,
3672            request_layout,
3673            prepaint,
3674            window,
3675            cx,
3676        );
3677    }
3678}
3679
3680impl<E> IntoElement for Stateful<E>
3681where
3682    E: Element,
3683{
3684    type Element = Self;
3685
3686    fn into_element(self) -> Self::Element {
3687        self
3688    }
3689}
3690
3691impl<E> ParentElement for Stateful<E>
3692where
3693    E: ParentElement,
3694{
3695    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
3696        self.element.extend(elements)
3697    }
3698}
3699
3700/// Represents an element that can be scrolled *to* in its parent element.
3701/// Contrary to [ScrollHandle::scroll_to_active_item], an anchored element does not have to be an immediate child of the parent.
3702#[derive(Clone, Debug)]
3703pub struct ScrollAnchor {
3704    handle: ScrollHandle,
3705    last_origin: Rc<RefCell<Point<Pixels>>>,
3706}
3707
3708impl ScrollAnchor {
3709    /// Creates a [ScrollAnchor] associated with a given [ScrollHandle].
3710    pub fn for_handle(handle: ScrollHandle) -> Self {
3711        Self {
3712            handle,
3713            last_origin: Default::default(),
3714        }
3715    }
3716    /// Request scroll to this item on the next frame.
3717    pub fn scroll_to(&self, window: &mut Window, _cx: &mut App) {
3718        let this = self.clone();
3719
3720        window.on_next_frame(move |_, _| {
3721            this.scroll_now();
3722        });
3723    }
3724
3725    /// Scroll to this item immediately using the current layout state.
3726    pub fn scroll_now(&self) {
3727        let viewport_bounds = self.handle.bounds();
3728        let self_bounds = *self.last_origin.borrow();
3729        self.handle.set_offset(viewport_bounds.origin - self_bounds);
3730    }
3731}
3732
3733#[derive(Default, Debug)]
3734struct ScrollHandleState {
3735    offset: Rc<RefCell<Point<Pixels>>>,
3736    bounds: Bounds<Pixels>,
3737    max_offset: Point<Pixels>,
3738    child_bounds: Vec<Bounds<Pixels>>,
3739    scroll_to_bottom: bool,
3740    overflow: Point<Overflow>,
3741    active_item: Option<ScrollActiveItem>,
3742}
3743
3744#[derive(Default, Debug, Clone, Copy)]
3745struct ScrollActiveItem {
3746    index: usize,
3747    strategy: ScrollStrategy,
3748}
3749
3750#[derive(Default, Debug, Clone, Copy)]
3751enum ScrollStrategy {
3752    #[default]
3753    FirstVisible,
3754    Top,
3755}
3756
3757/// A handle to the scrollable aspects of an element.
3758/// Used for accessing scroll state, like the current scroll offset,
3759/// and for mutating the scroll state, like scrolling to a specific child.
3760#[derive(Clone, Debug)]
3761pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
3762
3763impl Default for ScrollHandle {
3764    fn default() -> Self {
3765        Self::new()
3766    }
3767}
3768
3769impl ScrollHandle {
3770    /// Construct a new scroll handle.
3771    pub fn new() -> Self {
3772        Self(Rc::default())
3773    }
3774
3775    /// Get the current scroll offset.
3776    pub fn offset(&self) -> Point<Pixels> {
3777        *self.0.borrow().offset.borrow()
3778    }
3779
3780    /// Get the maximum scroll offset.
3781    pub fn max_offset(&self) -> Point<Pixels> {
3782        self.0.borrow().max_offset
3783    }
3784
3785    /// Get the top child that's scrolled into view.
3786    pub fn top_item(&self) -> usize {
3787        let state = self.0.borrow();
3788        let top = state.bounds.top() - state.offset.borrow().y;
3789
3790        match state.child_bounds.binary_search_by(|bounds| {
3791            if top < bounds.top() {
3792                Ordering::Greater
3793            } else if top > bounds.bottom() {
3794                Ordering::Less
3795            } else {
3796                Ordering::Equal
3797            }
3798        }) {
3799            Ok(ix) => ix,
3800            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
3801        }
3802    }
3803
3804    /// Get the bottom child that's scrolled into view.
3805    pub fn bottom_item(&self) -> usize {
3806        let state = self.0.borrow();
3807        let bottom = state.bounds.bottom() - state.offset.borrow().y;
3808
3809        match state.child_bounds.binary_search_by(|bounds| {
3810            if bottom < bounds.top() {
3811                Ordering::Greater
3812            } else if bottom > bounds.bottom() {
3813                Ordering::Less
3814            } else {
3815                Ordering::Equal
3816            }
3817        }) {
3818            Ok(ix) => ix,
3819            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
3820        }
3821    }
3822
3823    /// Return the bounds into which this child is painted
3824    pub fn bounds(&self) -> Bounds<Pixels> {
3825        self.0.borrow().bounds
3826    }
3827
3828    /// Get the bounds for a specific child.
3829    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
3830        self.0.borrow().child_bounds.get(ix).cloned()
3831    }
3832
3833    /// Update [ScrollHandleState]'s active item for scrolling to in prepaint
3834    pub fn scroll_to_item(&self, ix: usize) {
3835        let mut state = self.0.borrow_mut();
3836        state.active_item = Some(ScrollActiveItem {
3837            index: ix,
3838            strategy: ScrollStrategy::default(),
3839        });
3840    }
3841
3842    /// Update [ScrollHandleState]'s active item for scrolling to in prepaint
3843    /// This scrolls the minimal amount to ensure that the child is the first visible element
3844    pub fn scroll_to_top_of_item(&self, ix: usize) {
3845        let mut state = self.0.borrow_mut();
3846        state.active_item = Some(ScrollActiveItem {
3847            index: ix,
3848            strategy: ScrollStrategy::Top,
3849        });
3850    }
3851
3852    /// Scrolls the minimal amount to either ensure that the child is
3853    /// fully visible or the top element of the view depends on the
3854    /// scroll strategy
3855    fn scroll_to_active_item(&self) {
3856        let mut state = self.0.borrow_mut();
3857
3858        let Some(active_item) = state.active_item else {
3859            return;
3860        };
3861
3862        let active_item = match state.child_bounds.get(active_item.index) {
3863            Some(bounds) => {
3864                let mut scroll_offset = state.offset.borrow_mut();
3865
3866                match active_item.strategy {
3867                    ScrollStrategy::FirstVisible => {
3868                        if state.overflow.y == Overflow::Scroll {
3869                            let child_height = bounds.size.height;
3870                            let viewport_height = state.bounds.size.height;
3871                            if child_height > viewport_height {
3872                                scroll_offset.y = state.bounds.top() - bounds.top();
3873                            } else if bounds.top() + scroll_offset.y < state.bounds.top() {
3874                                scroll_offset.y = state.bounds.top() - bounds.top();
3875                            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
3876                                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
3877                            }
3878                        }
3879                    }
3880                    ScrollStrategy::Top => {
3881                        scroll_offset.y = state.bounds.top() - bounds.top();
3882                    }
3883                }
3884
3885                if state.overflow.x == Overflow::Scroll {
3886                    let child_width = bounds.size.width;
3887                    let viewport_width = state.bounds.size.width;
3888                    if child_width > viewport_width {
3889                        scroll_offset.x = state.bounds.left() - bounds.left();
3890                    } else if bounds.left() + scroll_offset.x < state.bounds.left() {
3891                        scroll_offset.x = state.bounds.left() - bounds.left();
3892                    } else if bounds.right() + scroll_offset.x > state.bounds.right() {
3893                        scroll_offset.x = state.bounds.right() - bounds.right();
3894                    }
3895                }
3896                None
3897            }
3898            None => Some(active_item),
3899        };
3900        state.active_item = active_item;
3901    }
3902
3903    /// Scrolls to the bottom.
3904    pub fn scroll_to_bottom(&self) {
3905        let mut state = self.0.borrow_mut();
3906        state.scroll_to_bottom = true;
3907    }
3908
3909    /// Set the offset explicitly. The offset is the distance from the top left of the
3910    /// parent container to the top left of the first child.
3911    /// As you scroll further down the offset becomes more negative.
3912    pub fn set_offset(&self, mut position: Point<Pixels>) {
3913        let state = self.0.borrow();
3914        *state.offset.borrow_mut() = position;
3915    }
3916
3917    /// Get the logical scroll top, based on a child index and a pixel offset.
3918    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
3919        let ix = self.top_item();
3920        let state = self.0.borrow();
3921
3922        if let Some(child_bounds) = state.child_bounds.get(ix) {
3923            (
3924                ix,
3925                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
3926            )
3927        } else {
3928            (ix, px(0.))
3929        }
3930    }
3931
3932    /// Get the logical scroll bottom, based on a child index and a pixel offset.
3933    pub fn logical_scroll_bottom(&self) -> (usize, Pixels) {
3934        let ix = self.bottom_item();
3935        let state = self.0.borrow();
3936
3937        if let Some(child_bounds) = state.child_bounds.get(ix) {
3938            (
3939                ix,
3940                child_bounds.bottom() + state.offset.borrow().y - state.bounds.bottom(),
3941            )
3942        } else {
3943            (ix, px(0.))
3944        }
3945    }
3946
3947    /// Get the count of children for scrollable item.
3948    pub fn children_count(&self) -> usize {
3949        self.0.borrow().child_bounds.len()
3950    }
3951}
3952
3953#[cfg(test)]
3954mod tests {
3955    use super::*;
3956    use crate::{
3957        AppContext as _, Context, InputEvent, MouseMoveEvent, TestAppContext,
3958        util::FluentBuilder as _,
3959    };
3960    use std::rc::Weak;
3961
3962    struct TestTooltipView;
3963
3964    impl Render for TestTooltipView {
3965        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
3966            div().w(px(20.)).h(px(20.)).child("tooltip")
3967        }
3968    }
3969
3970    type CapturedActiveTooltip = Rc<RefCell<Option<Weak<RefCell<Option<ActiveTooltip>>>>>>;
3971
3972    struct TooltipCaptureElement {
3973        child: AnyElement,
3974        captured_active_tooltip: CapturedActiveTooltip,
3975    }
3976
3977    impl IntoElement for TooltipCaptureElement {
3978        type Element = Self;
3979
3980        fn into_element(self) -> Self::Element {
3981            self
3982        }
3983    }
3984
3985    impl Element for TooltipCaptureElement {
3986        type RequestLayoutState = ();
3987        type PrepaintState = ();
3988
3989        fn id(&self) -> Option<ElementId> {
3990            None
3991        }
3992
3993        fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
3994            None
3995        }
3996
3997        fn request_layout(
3998            &mut self,
3999            _id: Option<&GlobalElementId>,
4000            _inspector_id: Option<&InspectorElementId>,
4001            window: &mut Window,
4002            cx: &mut App,
4003        ) -> (LayoutId, Self::RequestLayoutState) {
4004            (self.child.request_layout(window, cx), ())
4005        }
4006
4007        fn prepaint(
4008            &mut self,
4009            _id: Option<&GlobalElementId>,
4010            _inspector_id: Option<&InspectorElementId>,
4011            _bounds: Bounds<Pixels>,
4012            _request_layout: &mut Self::RequestLayoutState,
4013            window: &mut Window,
4014            cx: &mut App,
4015        ) -> Self::PrepaintState {
4016            self.child.prepaint(window, cx);
4017        }
4018
4019        fn paint(
4020            &mut self,
4021            _id: Option<&GlobalElementId>,
4022            _inspector_id: Option<&InspectorElementId>,
4023            _bounds: Bounds<Pixels>,
4024            _request_layout: &mut Self::RequestLayoutState,
4025            _prepaint: &mut Self::PrepaintState,
4026            window: &mut Window,
4027            cx: &mut App,
4028        ) {
4029            self.child.paint(window, cx);
4030            window.with_global_id("target".into(), |global_id, window| {
4031                window.with_element_state::<InteractiveElementState, _>(
4032                    global_id,
4033                    |state, _window| {
4034                        let state = state.unwrap();
4035                        *self.captured_active_tooltip.borrow_mut() =
4036                            state.active_tooltip.as_ref().map(Rc::downgrade);
4037                        ((), state)
4038                    },
4039                )
4040            });
4041        }
4042    }
4043
4044    struct TooltipOwner {
4045        captured_active_tooltip: CapturedActiveTooltip,
4046        show_delay_override: Option<Duration>,
4047    }
4048
4049    impl Render for TooltipOwner {
4050        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
4051            TooltipCaptureElement {
4052                child: div()
4053                    .size_full()
4054                    .child(
4055                        div()
4056                            .id("target")
4057                            .w(px(50.))
4058                            .h(px(50.))
4059                            .tooltip(|_, cx| cx.new(|_| TestTooltipView).into())
4060                            .when_some(self.show_delay_override, |this, delay| {
4061                                this.tooltip_show_delay(delay)
4062                            }),
4063                    )
4064                    .into_any_element(),
4065                captured_active_tooltip: self.captured_active_tooltip.clone(),
4066            }
4067        }
4068    }
4069
4070    #[test]
4071    fn scroll_handle_aligns_wide_children_to_left_edge() {
4072        let handle = ScrollHandle::new();
4073        {
4074            let mut state = handle.0.borrow_mut();
4075            state.bounds = Bounds::new(point(px(0.), px(0.)), size(px(80.), px(20.)));
4076            state.child_bounds = vec![Bounds::new(point(px(25.), px(0.)), size(px(200.), px(20.)))];
4077            state.overflow.x = Overflow::Scroll;
4078            state.active_item = Some(ScrollActiveItem {
4079                index: 0,
4080                strategy: ScrollStrategy::default(),
4081            });
4082        }
4083
4084        handle.scroll_to_active_item();
4085
4086        assert_eq!(handle.offset().x, px(-25.));
4087    }
4088
4089    #[test]
4090    fn scroll_handle_aligns_tall_children_to_top_edge() {
4091        let handle = ScrollHandle::new();
4092        {
4093            let mut state = handle.0.borrow_mut();
4094            state.bounds = Bounds::new(point(px(0.), px(0.)), size(px(20.), px(80.)));
4095            state.child_bounds = vec![Bounds::new(point(px(0.), px(25.)), size(px(20.), px(200.)))];
4096            state.overflow.y = Overflow::Scroll;
4097            state.active_item = Some(ScrollActiveItem {
4098                index: 0,
4099                strategy: ScrollStrategy::default(),
4100            });
4101        }
4102
4103        handle.scroll_to_active_item();
4104
4105        assert_eq!(handle.offset().y, px(-25.));
4106    }
4107
4108    fn setup_tooltip_owner_test(
4109        show_delay_override: Option<Duration>,
4110    ) -> (
4111        TestAppContext,
4112        crate::AnyWindowHandle,
4113        CapturedActiveTooltip,
4114    ) {
4115        let mut test_app = TestAppContext::single();
4116        let captured_active_tooltip: CapturedActiveTooltip = Rc::new(RefCell::new(None));
4117        let window = test_app.add_window({
4118            let captured_active_tooltip = captured_active_tooltip.clone();
4119            move |_, _| TooltipOwner {
4120                captured_active_tooltip,
4121                show_delay_override,
4122            }
4123        });
4124        let any_window = window.into();
4125
4126        test_app
4127            .update_window(any_window, |_, window, cx| {
4128                window.draw(cx).clear();
4129            })
4130            .unwrap();
4131
4132        test_app
4133            .update_window(any_window, |_, window, cx| {
4134                window.dispatch_event(
4135                    MouseMoveEvent {
4136                        position: point(px(10.), px(10.)),
4137                        modifiers: Default::default(),
4138                        pressed_button: None,
4139                    }
4140                    .to_platform_input(),
4141                    cx,
4142                );
4143            })
4144            .unwrap();
4145
4146        test_app
4147            .update_window(any_window, |_, window, cx| {
4148                window.draw(cx).clear();
4149            })
4150            .unwrap();
4151
4152        (test_app, any_window, captured_active_tooltip)
4153    }
4154
4155    #[test]
4156    fn tooltip_waiting_for_show_is_released_when_its_owner_disappears() {
4157        let (mut test_app, any_window, captured_active_tooltip) = setup_tooltip_owner_test(None);
4158
4159        let weak_active_tooltip = captured_active_tooltip.borrow().clone().unwrap();
4160        let active_tooltip = weak_active_tooltip.upgrade().unwrap();
4161        assert!(matches!(
4162            active_tooltip.borrow().as_ref(),
4163            Some(ActiveTooltip::WaitingForShow { .. })
4164        ));
4165
4166        test_app
4167            .update_window(any_window, |_, window, _| {
4168                window.remove_window();
4169            })
4170            .unwrap();
4171        test_app.run_until_parked();
4172        drop(active_tooltip);
4173
4174        assert!(weak_active_tooltip.upgrade().is_none());
4175    }
4176
4177    #[test]
4178    fn tooltip_respects_custom_show_delay() {
4179        let extra_delay = Duration::from_secs(1);
4180        let show_delay_override = DEFAULT_TOOLTIP_SHOW_DELAY + extra_delay;
4181        let (mut test_app, _any_window, captured_active_tooltip) =
4182            setup_tooltip_owner_test(Some(show_delay_override));
4183
4184        let weak_active_tooltip = captured_active_tooltip.borrow().clone().unwrap();
4185        let active_tooltip = weak_active_tooltip.upgrade().unwrap();
4186
4187        test_app
4188            .dispatcher
4189            .advance_clock(DEFAULT_TOOLTIP_SHOW_DELAY);
4190        test_app.run_until_parked();
4191
4192        assert!(matches!(
4193            active_tooltip.borrow().as_ref(),
4194            Some(ActiveTooltip::WaitingForShow { .. })
4195        ));
4196
4197        test_app.dispatcher.advance_clock(extra_delay);
4198        test_app.run_until_parked();
4199
4200        assert!(matches!(
4201            active_tooltip.borrow().as_ref(),
4202            Some(ActiveTooltip::Visible { .. })
4203        ));
4204    }
4205
4206    #[test]
4207    fn tooltip_is_released_when_its_owner_disappears() {
4208        let (mut test_app, any_window, captured_active_tooltip) = setup_tooltip_owner_test(None);
4209
4210        let weak_active_tooltip = captured_active_tooltip.borrow().clone().unwrap();
4211        let active_tooltip = weak_active_tooltip.upgrade().unwrap();
4212
4213        test_app
4214            .dispatcher
4215            .advance_clock(DEFAULT_TOOLTIP_SHOW_DELAY);
4216        test_app.run_until_parked();
4217
4218        assert!(matches!(
4219            active_tooltip.borrow().as_ref(),
4220            Some(ActiveTooltip::Visible { .. })
4221        ));
4222
4223        test_app
4224            .update_window(any_window, |_, window, _| {
4225                window.remove_window();
4226            })
4227            .unwrap();
4228        test_app.run_until_parked();
4229        drop(active_tooltip);
4230
4231        assert!(weak_active_tooltip.upgrade().is_none());
4232    }
4233
4234    #[test]
4235    fn tooltip_hides_after_mouse_leaves_origin() {
4236        let (mut test_app, any_window, captured_active_tooltip) = setup_tooltip_owner_test(None);
4237
4238        let weak_active_tooltip = captured_active_tooltip.borrow().clone().unwrap();
4239        let active_tooltip = weak_active_tooltip.upgrade().unwrap();
4240
4241        test_app
4242            .dispatcher
4243            .advance_clock(DEFAULT_TOOLTIP_SHOW_DELAY);
4244        test_app.run_until_parked();
4245
4246        assert!(matches!(
4247            active_tooltip.borrow().as_ref(),
4248            Some(ActiveTooltip::Visible { .. })
4249        ));
4250
4251        test_app
4252            .update_window(any_window, |_, window, cx| {
4253                window.dispatch_event(
4254                    MouseMoveEvent {
4255                        position: point(px(75.), px(75.)),
4256                        modifiers: Default::default(),
4257                        pressed_button: None,
4258                    }
4259                    .to_platform_input(),
4260                    cx,
4261                );
4262            })
4263            .unwrap();
4264
4265        assert!(active_tooltip.borrow().is_none());
4266    }
4267}