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