Skip to main content

gpui/
element.rs

1//! Elements lay out and paint everything in a window. They form a tree, and their layout follows
2//! the web layout rules implemented by [taffy](https://github.com/DioxusLabs/taffy). Most of the
3//! time you won't use this module directly. The elements behind [`div`](crate::div) and friends have their
4//! own APIs, and GPUI uses the traits in this module to turn the element tree into pixels.
5//!
6//! # Element basics
7//!
8//! GPUI builds the element tree by calling [`Render::render`] on the root view of a window. It
9//! then lays the tree out with Taffy and paints it, one [`Element`] at a time. When the frame is
10//! done, the tree and the callbacks it registered are dropped, and the next frame builds a new one.
11//! [The frame](crate::_documentation::concepts::the_frame) describes this sequence in full.
12//!
13//! Elements hold no state between frames, because they are rebuilt every frame. State that
14//! must survive a frame lives in an entity, or in element state keyed by a [`GlobalElementId`].
15//! An element can also pass small pieces of state from one of its phases to the next through its
16//! associated types. [`Element`] explains the three phases.
17//!
18//! # Implementing your own elements
19//!
20//! Elements are the low-level, imperative API of GPUI. Most elements stay inside the bounds their
21//! parent gives them, which keeps GPUI's layout guarantees. [`deferred`](crate::deferred) lets an
22//! element paint outside those bounds, which overlays and popups need. Use that power with care.
23//!
24//! Most of the time you don't need a custom element. Build components from the built-in elements
25//! instead, with [`RenderOnce`] and `#[derive(IntoElement)]`. Write an [`Element`] only when you
26//! need your own layout or painting, such as a custom layout algorithm or a code editor. The
27//! [`custom_element`](crate::_documentation::examples::custom_element) example is a complete one.
28
29#[cfg(any(feature = "inspector", debug_assertions))]
30use crate::InspectorElementPath;
31use crate::{
32    A11ySubtreeBuilder, App, ArenaBox, AvailableSpace, Bounds, Context, DispatchNodeId, ElementId,
33    FocusHandle, InspectorElementId, LayoutId, Pixels, Point, Size, Style, Window,
34    util::FluentBuilder, window::with_element_arena,
35};
36use std::{
37    any::Any,
38    fmt::{self, Debug, Display},
39    mem, panic,
40    sync::Arc,
41};
42
43/// A part of a window's element tree that lays itself out and paints itself.
44///
45/// GPUI draws each element in three phases. Each phase runs once per frame, in this order:
46///
47/// 1. [`request_layout`](Element::request_layout) asks Taffy for a [`LayoutId`] that describes the
48///    element's size and position rules. It returns the element's
49///    [`RequestLayoutState`](Element::RequestLayoutState). The element has no bounds yet.
50/// 2. [`prepaint`](Element::prepaint) receives the element's final [`Bounds`] and returns its
51///    [`PrepaintState`](Element::PrepaintState). Insert hitboxes and compute anything that `paint`
52///    needs here.
53/// 3. [`paint`](Element::paint) receives the bounds and both states, and draws. Add primitives to
54///    the scene and register event listeners here.
55///
56/// The two associated state types carry data from one phase to the next:
57///
58/// * `RequestLayoutState` is produced by `request_layout`, and `prepaint` and `paint` each get a
59///   `&mut` to it. Use it for what layout produced, such as the ids of child layouts or a measured
60///   text shape.
61/// * `PrepaintState` is produced by `prepaint`, and `paint` gets a `&mut` to it. Use it for what
62///   needs the final bounds, such as a [`Hitbox`](crate::Hitbox) or the position of a cursor.
63///
64/// Use `()` for a state type when the element has nothing to pass on.
65///
66/// A parent calls its children's phases from inside its own. A child's `request_layout` therefore
67/// runs during its parent's, and its `prepaint` and `paint` run while the parent's do. Call
68/// [`Window::insert_hitbox`] from `prepaint`, and [`Window::on_mouse_event`] or
69/// [`Window::paint_quad`] from `paint`. Window methods check the phase they run in with debug
70/// assertions, so calling one in the wrong phase fails in debug builds.
71///
72/// [`Element::id`] returns the element's identity, if it has one. An element with an id receives a
73/// [`GlobalElementId`] in all three phases, so it can read and write state that survives from frame
74/// to frame. An element without one receives `None`. See
75/// [element identity](crate::_documentation::concepts::elements#identity-and-element-state).
76///
77/// # Example
78///
79/// This element draws nothing. It records the phases it runs in, and the example checks their
80/// order:
81///
82/// ```
83/// use std::{cell::RefCell, rc::Rc};
84///
85/// use gpui::{
86///     App, Bounds, Context, Element, ElementId, GlobalElementId, InspectorElementId,
87///     IntoElement, LayoutId, Pixels, Render, Style, TestApp, Window, div, prelude::*,
88/// };
89///
90/// #[derive(Clone, Default)]
91/// struct Log(Rc<RefCell<Vec<&'static str>>>);
92///
93/// struct Probe {
94///     log: Log,
95/// }
96///
97/// impl IntoElement for Probe {
98///     type Element = Self;
99///
100///     fn into_element(self) -> Self::Element {
101///         self
102///     }
103/// }
104///
105/// impl Element for Probe {
106///     type RequestLayoutState = ();
107///     type PrepaintState = Bounds<Pixels>;
108///
109///     fn id(&self) -> Option<ElementId> {
110///         None
111///     }
112///
113///     fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
114///         None
115///     }
116///
117///     fn request_layout(
118///         &mut self,
119///         _id: Option<&GlobalElementId>,
120///         _inspector_id: Option<&InspectorElementId>,
121///         window: &mut Window,
122///         cx: &mut App,
123///     ) -> (LayoutId, Self::RequestLayoutState) {
124///         self.log.0.borrow_mut().push("request_layout");
125///         (window.request_layout(Style::default(), [], cx), ())
126///     }
127///
128///     fn prepaint(
129///         &mut self,
130///         _id: Option<&GlobalElementId>,
131///         _inspector_id: Option<&InspectorElementId>,
132///         bounds: Bounds<Pixels>,
133///         _request_layout: &mut Self::RequestLayoutState,
134///         _window: &mut Window,
135///         _cx: &mut App,
136///     ) -> Self::PrepaintState {
137///         self.log.0.borrow_mut().push("prepaint");
138///         bounds
139///     }
140///
141///     fn paint(
142///         &mut self,
143///         _id: Option<&GlobalElementId>,
144///         _inspector_id: Option<&InspectorElementId>,
145///         _bounds: Bounds<Pixels>,
146///         _request_layout: &mut Self::RequestLayoutState,
147///         _prepaint: &mut Self::PrepaintState,
148///         _window: &mut Window,
149///         _cx: &mut App,
150///     ) {
151///         self.log.0.borrow_mut().push("paint");
152///     }
153/// }
154///
155/// struct ProbeView {
156///     log: Log,
157/// }
158///
159/// impl Render for ProbeView {
160///     fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
161///         div().size_full().child(Probe { log: self.log.clone() })
162///     }
163/// }
164///
165/// let log = Log::default();
166/// let mut app = TestApp::new();
167/// let mut window = app.open_window({
168///     let log = log.clone();
169///     move |_window, _cx| ProbeView { log }
170/// });
171///
172/// log.0.borrow_mut().clear();
173/// // Notify the view so the next draw renders it again instead of reusing its output.
174/// window.update(|_, _, cx| cx.notify());
175/// window.draw();
176/// assert_eq!(*log.0.borrow(), ["request_layout", "prepaint", "paint"]);
177/// ```
178///
179/// For a complete element, see
180/// [`custom_element`](crate::_documentation::examples::custom_element). It is a slider that inserts
181/// a hitbox in `prepaint` and handles dragging in `paint`.
182pub trait Element: 'static + IntoElement {
183    /// The state that [`Element::request_layout`] returns for the later phases.
184    ///
185    /// `prepaint` and `paint` each receive a `&mut` reference to it. Use `()` if the element needs
186    /// no such state.
187    type RequestLayoutState: 'static;
188
189    /// The state that [`Element::prepaint`] returns for [`Element::paint`].
190    ///
191    /// `paint` receives a `&mut` reference to it. Use `()` if the element needs no such state.
192    type PrepaintState: 'static;
193
194    /// Returns the element's identity, or `None` if it has none.
195    ///
196    /// Return an id from any element whose state must survive from one frame to the next, such as
197    /// a hover, a drag or a scroll offset. GPUI finds that state again by the id's path from the
198    /// window root. The id must be stable on every frame; two elements with the same id path share
199    /// state and accessibility identity. The path includes every ancestor that has an id.
200    fn id(&self) -> Option<ElementId>;
201
202    /// Returns where this element was created, for the inspector and debug output.
203    ///
204    /// GPUI uses this only in debug builds and with the `inspector` feature. Return `None` when the
205    /// location doesn't matter. To capture it, mark the constructor `#[track_caller]` and store
206    /// [`std::panic::Location::caller`].
207    fn source_location(&self) -> Option<&'static panic::Location<'static>>;
208
209    /// Requests a layout node from Taffy, and returns it with the state the later phases need.
210    ///
211    /// Describe the element's size and position rules here: build a [`Style`] and pass it to
212    /// [`Window::request_layout`], along with the layout ids of any children. Lay out the children
213    /// you draw here too, by calling their `request_layout` before this element's own. The element
214    /// has no bounds in this phase.
215    fn request_layout(
216        &mut self,
217        id: Option<&GlobalElementId>,
218        inspector_id: Option<&InspectorElementId>,
219        window: &mut Window,
220        cx: &mut App,
221    ) -> (LayoutId, Self::RequestLayoutState);
222
223    /// Runs once the element's bounds are known, and returns the state that `paint` needs.
224    ///
225    /// `bounds` is the element's final rectangle in window coordinates, in logical pixels. Insert
226    /// hitboxes with [`Window::insert_hitbox`] here, so that the next mouse event can be tested
227    /// against them. Compute anything `paint` needs too. Calls that draw, such as
228    /// [`Window::paint_quad`], belong in `paint`.
229    fn prepaint(
230        &mut self,
231        id: Option<&GlobalElementId>,
232        inspector_id: Option<&InspectorElementId>,
233        bounds: Bounds<Pixels>,
234        request_layout: &mut Self::RequestLayoutState,
235        window: &mut Window,
236        cx: &mut App,
237    ) -> Self::PrepaintState;
238
239    /// Draws the element. Runs after `prepaint`, once per frame.
240    ///
241    /// `bounds` is the rectangle that `prepaint` received. Add primitives with the painting methods
242    /// on [`Window`], such as [`Window::paint_quad`], and register event listeners with
243    /// [`Window::on_mouse_event`] and related methods. Listeners stay registered until the next
244    /// frame replaces them, so an event is always delivered against the frame the user saw.
245    fn paint(
246        &mut self,
247        id: Option<&GlobalElementId>,
248        inspector_id: Option<&InspectorElementId>,
249        bounds: Bounds<Pixels>,
250        request_layout: &mut Self::RequestLayoutState,
251        prepaint: &mut Self::PrepaintState,
252        window: &mut Window,
253        cx: &mut App,
254    );
255
256    /// Returns the accessible role for this element, if any.
257    /// Elements that return `None` have no accessibility node unless
258    /// [`Element::is_a11y_hidden`] returns `true`.
259    ///
260    /// Note: inclusion in accessibility tree requires non-`None` [`id`][Element::id].
261    ///
262    /// See the [accessibility guide](crate::_documentation::guides::accessibility) for an overview.
263    fn a11y_role(&self) -> Option<accesskit::Role> {
264        None
265    }
266
267    /// Whether assistive technology should ignore this element and its
268    /// descendants.
269    ///
270    /// GPUI gives a hidden element without a role an internal container node.
271    /// AccessKit uses that node to omit the subtree.
272    fn is_a11y_hidden(&self) -> bool {
273        false
274    }
275
276    /// Write accessibility properties to the given node.
277    /// GPUI calls this only when [`Element::a11y_role`] returns `Some` or
278    /// [`Element::is_a11y_hidden`] returns `true`.
279    ///
280    /// See the [accessibility guide](crate::_documentation::guides::accessibility) for an overview.
281    fn write_a11y_info(&self, _node: &mut accesskit::Node) {}
282
283    /// Add synthetic child nodes to an [`Element`]. The element must have an
284    /// [`.id()`][Element::id]. It must also have a
285    /// [`.role()`][Element::a11y_role] or return `true` from
286    /// [`Element::is_a11y_hidden`].
287    ///
288    /// Some elements may want to inject accessibility nodes that do not
289    /// correspond to any GPUI element. For example, a custom text field element
290    /// may want to inject synthetic child nodes for the text content.
291    ///
292    /// See [Expose elements that GPUI doesn't draw](crate::_documentation::guides::accessibility#expose-elements-that-gpui-doesnt-draw-as-nodes) in
293    /// the accessibility guide for more detail.
294    fn a11y_synthetic_children(
295        &mut self,
296        _prepaint: &mut Self::PrepaintState,
297        _builder: &mut A11ySubtreeBuilder,
298    ) {
299    }
300
301    /// Convert this element into a dynamically-typed [`AnyElement`].
302    fn into_any(self) -> AnyElement {
303        AnyElement::new(self)
304    }
305}
306
307/// A type that can be converted into an [`Element`], so it can be a child of another element.
308///
309/// [`ParentElement::child`] takes any `IntoElement`. Strings, [`Entity`](crate::Entity) views and every element
310/// implement it. Derive it with `#[derive(IntoElement)]` on a [`RenderOnce`] component to make the
311/// component usable wherever an element is.
312///
313/// # Example
314///
315/// ```
316/// use gpui::{IntoElement, div, prelude::*};
317///
318/// let row = div().child("Name").child(String::from("Ada"));
319/// let _element = row.into_element();
320/// ```
321pub trait IntoElement: Sized {
322    /// The element type that this type converts into.
323    ///
324    /// Strings convert into text elements. A [`RenderOnce`] component that derives `IntoElement`
325    /// converts into the element that renders it.
326    type Element: Element;
327
328    /// Converts `self` into an [`Element`].
329    ///
330    /// GPUI calls this when it needs the element. You rarely call it yourself, but it is the method
331    /// to implement.
332    fn into_element(self) -> Self::Element;
333
334    /// Converts `self` into an [`AnyElement`], with its concrete type erased.
335    ///
336    /// Use this when two branches return different element types, or a list holds mixed types.
337    fn into_any_element(self) -> AnyElement {
338        self.into_element().into_any()
339    }
340}
341
342impl<T: IntoElement> FluentBuilder for T {}
343
344/// A view: an entity that GPUI draws in a window.
345///
346/// Implement `Render` for the state of a view. GPUI can then draw an [`Entity`](crate::Entity) of that type as an
347/// element, and [`Context::notify`] redraws it. Use a view when a part of the interface has state
348/// that must survive from frame to frame. For stateless pieces, use [`RenderOnce`].
349///
350/// GPUI calls `render` each time it draws the window and reaches this view. The view keeps its
351/// state in `self`, not in the elements it returns. Those elements are consumed by the frame and
352/// dropped, and the next call builds new ones. So `render` should only read state and build
353/// elements from it. GPUI skips the call while nothing the view read has changed; see
354/// [retained view rendering](crate::_documentation::concepts::retained_rendering).
355///
356/// # Example
357///
358/// ```
359/// use std::{cell::Cell, rc::Rc};
360///
361/// use gpui::{Context, IntoElement, Render, TestApp, Window, div, prelude::*};
362///
363/// struct Greeting {
364///     name: String,
365///     renders: Rc<Cell<usize>>,
366/// }
367///
368/// impl Render for Greeting {
369///     fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
370///         self.renders.set(self.renders.get() + 1);
371///         div().child(format!("Hello, {}", self.name))
372///     }
373/// }
374///
375/// let renders = Rc::new(Cell::new(0));
376/// let mut app = TestApp::new();
377/// let mut window = app.open_window({
378///     let renders = renders.clone();
379///     move |_window, _cx| Greeting {
380///         name: "Ada".into(),
381///         renders,
382///     }
383/// });
384///
385/// renders.set(0);
386/// // Notify the view so the next draw renders it again instead of reusing its output.
387/// window.update(|_, _, cx| cx.notify());
388/// window.draw();
389/// assert_eq!(renders.get(), 1);
390/// ```
391pub trait Render: 'static + Sized {
392    /// Builds the view's element tree from its current state.
393    ///
394    /// `window` is the window being drawn, and `cx` gives access to this view through
395    /// [`Context<Self>`](Context). Return the elements the view shows. Don't change state in this
396    /// method, because GPUI may call it many times, or skip it, for one change.
397    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement;
398}
399
400impl Render for Empty {
401    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
402        Empty
403    }
404}
405
406/// A component: a value that describes a pattern of elements and renders it once.
407///
408/// Use `RenderOnce` for reusable pieces of interface that keep no state of their own. Build the
409/// component from plain data, and derive [`IntoElement`] on it so it can be a child of an element.
410/// The component's `render` takes `self` by value, and the component is consumed when it is drawn.
411/// A component can't call [`Context::notify`], because it has no entity. To report events, store a
412/// callback in the component and let the parent view decide what the callback does. Use [`Render`]
413/// for a piece of interface that holds state.
414///
415/// Elements that need state across frames need ids. Pass the id in from the parent, and use it
416/// with [`InteractiveElement::id`](crate::InteractiveElement::id). GPUI scopes a component's elements under the component's type
417/// name, so two instances of the same component side by side would otherwise share their state.
418///
419/// # Example
420///
421/// ```
422/// use std::{cell::Cell, rc::Rc};
423///
424/// use gpui::{App, Context, IntoElement, Render, RenderOnce, TestApp, Window, div, prelude::*};
425///
426/// #[derive(IntoElement)]
427/// struct Badge {
428///     renders: Rc<Cell<usize>>,
429/// }
430///
431/// impl RenderOnce for Badge {
432///     fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
433///         self.renders.set(self.renders.get() + 1);
434///         div().child("3")
435///     }
436/// }
437///
438/// struct Inbox {
439///     renders: Rc<Cell<usize>>,
440/// }
441///
442/// impl Render for Inbox {
443///     fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
444///         div().child(Badge {
445///             renders: self.renders.clone(),
446///         })
447///     }
448/// }
449///
450/// let renders = Rc::new(Cell::new(0));
451/// let mut app = TestApp::new();
452/// let mut window = app.open_window({
453///     let renders = renders.clone();
454///     move |_window, _cx| Inbox { renders }
455/// });
456///
457/// renders.set(0);
458/// // Notify the view so the next draw renders it again instead of reusing its output.
459/// window.update(|_, _, cx| cx.notify());
460/// window.draw();
461/// assert_eq!(renders.get(), 1);
462/// ```
463pub trait RenderOnce: 'static {
464    /// Builds the component's element tree. Takes `self` by value, so the component is used up.
465    ///
466    /// GPUI calls this once for each time the component appears in a frame. Return the elements
467    /// the component shows.
468    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement;
469}
470
471/// A parent element whose children all have one concrete type.
472///
473/// Use it when a container's children carry a shared type, such as rows with their own data.
474/// Most containers use [`ParentElement`], which accepts any [`IntoElement`].
475pub trait ParentElementTyped {
476    /// The type of child that this element accepts.
477    type Child;
478
479    /// Adds the given children to the end of this element's children.
480    fn extend(&mut self, elements: impl IntoIterator<Item = Self::Child>);
481
482    /// Adds one child to this element, and returns the element for chaining.
483    fn child(mut self, child: Self::Child) -> Self
484    where
485        Self: Sized,
486    {
487        self.extend(std::iter::once(child));
488        self
489    }
490
491    /// Adds several children to this element, in iteration order, and returns the element.
492    fn children(mut self, children: impl IntoIterator<Item = Self::Child>) -> Self
493    where
494        Self: Sized,
495    {
496        self.extend(children);
497        self
498    }
499}
500
501/// An element that can hold any number of children of any type.
502///
503/// This is the trait behind `.child()` and `.children()` on containers such as [`div`](crate::div). Each
504/// child is anything that implements [`IntoElement`], so strings, views and other elements can be
505/// mixed in one container.
506pub trait ParentElement {
507    /// Adds the given children to the end of this element's children.
508    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>);
509
510    /// Adds one child to this element, and returns the element for chaining.
511    fn child(mut self, child: impl IntoElement) -> Self
512    where
513        Self: Sized,
514    {
515        self.extend(std::iter::once(child.into_any_element()));
516        self
517    }
518
519    /// Adds several children to this element, in iteration order, and returns the element.
520    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
521    where
522        Self: Sized,
523    {
524        self.extend(children.into_iter().map(|child| child.into_any_element()));
525        self
526    }
527}
528
529/// A globally unique identifier for an element, used to track state across frames.
530///
531/// The hash of the id path is computed once, when the id is built. Every
532/// element with an id is looked up in the element-state maps of two frames
533/// and recorded as accessed on every frame it is drawn, and each of those
534/// hashes the whole path — every ancestor's id, string names byte by byte —
535/// so on a deep tree the hashing alone was a visible share of a frame.
536#[derive(Clone, Debug)]
537pub struct GlobalElementId {
538    ids: Arc<[ElementId]>,
539    hash: u64,
540}
541
542/// The hash of an empty id path; every path hash is folded from it with
543/// [`extend_path_hash`], one id at a time, so the window can keep the hash
544/// of each prefix of its id stack and never re-hash a path.
545pub(crate) const EMPTY_PATH_HASH: u64 = 0;
546
547/// The hash of the path `prefix` + `id`, given the hash of `prefix`.
548pub(crate) fn extend_path_hash(prefix: u64, id: &ElementId) -> u64 {
549    use std::hash::{Hash, Hasher};
550    let mut hasher = collections::FxHasher::with_seed(prefix as usize);
551    id.hash(&mut hasher);
552    hasher.finish()
553}
554
555impl GlobalElementId {
556    pub(crate) fn new(ids: &[ElementId]) -> Self {
557        let hash = ids.iter().fold(EMPTY_PATH_HASH, extend_path_hash);
558        Self::with_hash(ids, hash)
559    }
560
561    /// `ids` with its hash already known, as the window's id stack keeps it.
562    pub(crate) fn with_hash(ids: &[ElementId], hash: u64) -> Self {
563        debug_assert_eq!(hash, ids.iter().fold(EMPTY_PATH_HASH, extend_path_hash));
564        Self {
565            ids: Arc::from(ids),
566            hash,
567        }
568    }
569
570    pub(crate) fn accesskit_node_id(&self) -> accesskit::NodeId {
571        accesskit::NodeId(self.hash)
572    }
573}
574
575impl Default for GlobalElementId {
576    fn default() -> Self {
577        Self::new(&[])
578    }
579}
580
581impl std::ops::Deref for GlobalElementId {
582    type Target = [ElementId];
583
584    fn deref(&self) -> &Self::Target {
585        &self.ids
586    }
587}
588
589impl PartialEq for GlobalElementId {
590    fn eq(&self, other: &Self) -> bool {
591        self.hash == other.hash && (Arc::ptr_eq(&self.ids, &other.ids) || self.ids == other.ids)
592    }
593}
594
595impl Eq for GlobalElementId {}
596
597impl std::hash::Hash for GlobalElementId {
598    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
599        state.write_u64(self.hash);
600    }
601}
602impl Display for GlobalElementId {
603    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
604        for (i, element_id) in self.ids.iter().enumerate() {
605            if i > 0 {
606                write!(f, ".")?;
607            }
608            write!(f, "{}", element_id)?;
609        }
610        Ok(())
611    }
612}
613
614trait ElementObject {
615    fn inner_element(&mut self) -> &mut dyn Any;
616
617    fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId;
618
619    fn prepaint(&mut self, window: &mut Window, cx: &mut App);
620
621    fn paint(&mut self, window: &mut Window, cx: &mut App);
622
623    fn layout_as_root(
624        &mut self,
625        available_space: Size<AvailableSpace>,
626        window: &mut Window,
627        cx: &mut App,
628    ) -> Size<Pixels>;
629}
630
631/// An [`Element`] together with the state GPUI keeps while drawing it in one frame.
632///
633/// GPUI creates a `Drawable` for each element in the tree, and an [`AnyElement`] holds one.
634/// Its phase state moves through the frame's phases in order. You don't construct it yourself.
635/// Use `element` to reach the wrapped element.
636pub struct Drawable<E: Element> {
637    /// The wrapped element.
638    pub element: E,
639    phase: ElementDrawPhase<E::RequestLayoutState, E::PrepaintState>,
640}
641
642#[derive(Default)]
643enum ElementDrawPhase<RequestLayoutState, PrepaintState> {
644    #[default]
645    Start,
646    RequestLayout {
647        layout_id: LayoutId,
648        global_id: Option<GlobalElementId>,
649        inspector_id: Option<InspectorElementId>,
650        request_layout: RequestLayoutState,
651    },
652    LayoutComputed {
653        layout_id: LayoutId,
654        global_id: Option<GlobalElementId>,
655        inspector_id: Option<InspectorElementId>,
656        available_space: Size<AvailableSpace>,
657        request_layout: RequestLayoutState,
658    },
659    Prepaint {
660        node_id: DispatchNodeId,
661        global_id: Option<GlobalElementId>,
662        inspector_id: Option<InspectorElementId>,
663        bounds: Bounds<Pixels>,
664        request_layout: RequestLayoutState,
665        prepaint: PrepaintState,
666        inline_fragments: Option<Arc<[Bounds<Pixels>]>>,
667    },
668    Painted,
669}
670
671impl<E: Element> Drawable<E> {
672    pub(crate) fn new(element: E) -> Self {
673        Drawable {
674            element,
675            phase: ElementDrawPhase::Start,
676        }
677    }
678
679    fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId {
680        match mem::take(&mut self.phase) {
681            ElementDrawPhase::Start => {
682                let global_id = self
683                    .element
684                    .id()
685                    .map(|element_id| prepare_element_id(element_id, window));
686
687                let inspector_id;
688                #[cfg(any(feature = "inspector", debug_assertions))]
689                {
690                    inspector_id = if window.inspector_enabled() {
691                        self.element
692                            .source_location()
693                            .map(|source| prepare_inspector_id(source, window))
694                    } else {
695                        None
696                    };
697                }
698                #[cfg(not(any(feature = "inspector", debug_assertions)))]
699                {
700                    inspector_id = None;
701                }
702
703                #[cfg(all(
704                    feature = "hot-patching",
705                    debug_assertions,
706                    not(target_family = "wasm")
707                ))]
708                let (layout_id, request_layout) = subsecond::HotFn::current(E::request_layout)
709                    .call((
710                        &mut self.element,
711                        global_id.as_ref(),
712                        inspector_id.as_ref(),
713                        window,
714                        cx,
715                    ));
716                #[cfg(not(all(
717                    feature = "hot-patching",
718                    debug_assertions,
719                    not(target_family = "wasm")
720                )))]
721                let (layout_id, request_layout) = self.element.request_layout(
722                    global_id.as_ref(),
723                    inspector_id.as_ref(),
724                    window,
725                    cx,
726                );
727
728                if global_id.is_some() {
729                    window.element_id_stack.pop();
730                }
731
732                self.phase = ElementDrawPhase::RequestLayout {
733                    layout_id,
734                    global_id,
735                    inspector_id,
736                    request_layout,
737                };
738                layout_id
739            }
740            _ => panic!("must call request_layout only once"),
741        }
742    }
743
744    pub(crate) fn prepaint(&mut self, window: &mut Window, cx: &mut App) {
745        match mem::take(&mut self.phase) {
746            ElementDrawPhase::RequestLayout {
747                layout_id,
748                global_id,
749                inspector_id,
750                mut request_layout,
751            }
752            | ElementDrawPhase::LayoutComputed {
753                layout_id,
754                global_id,
755                inspector_id,
756                mut request_layout,
757                ..
758            } => {
759                if let Some(element_id) = self.element.id() {
760                    window.element_id_stack.push(element_id);
761                    debug_assert_eq!(&**global_id.as_ref().unwrap(), &*window.element_id_stack);
762                }
763
764                let bounds = window.layout_bounds(layout_id);
765                let mut pushed_a11y_node = false;
766                if window.a11y.is_active() {
767                    if let Some(global_id) = global_id.as_ref() {
768                        let hidden = self.element.is_a11y_hidden();
769                        let role = self.element.a11y_role();
770                        if role.is_some() || hidden {
771                            let role = role.unwrap_or(accesskit::Role::GenericContainer);
772                            let node_id = global_id.accesskit_node_id();
773                            let mut node = accesskit::Node::new(role);
774                            let scale = window.scale_factor();
775                            node.set_bounds(accesskit::Rect {
776                                x0: (bounds.origin.x.0 * scale) as f64,
777                                y0: (bounds.origin.y.0 * scale) as f64,
778                                x1: ((bounds.origin.x.0 + bounds.size.width.0) * scale) as f64,
779                                y1: ((bounds.origin.y.0 + bounds.size.height.0) * scale) as f64,
780                            });
781                            self.element.write_a11y_info(&mut node);
782                            if hidden {
783                                node.set_hidden();
784                            }
785                            window.a11y.node_bounds.insert(node_id, bounds);
786                            pushed_a11y_node = window.a11y.nodes.push(node_id, node);
787                            #[cfg(debug_assertions)]
788                            if pushed_a11y_node {
789                                let view = window
790                                    .a11y
791                                    .view_type_names
792                                    .get(&window.current_view())
793                                    .copied();
794                                let source_location = self.element.source_location();
795                                window.a11y.nodes.record_node_info(
796                                    node_id,
797                                    crate::window::a11y::debug::NodeDebugInfo {
798                                        synthetic: false,
799                                        view,
800                                        element_id: global_id.last().map(|id| format!("{id:?}")),
801                                        source_location,
802                                    },
803                                );
804                            }
805                        }
806                    }
807                }
808
809                let node_id = window.next_frame.dispatch_tree.push_node();
810
811                let inline_fragments = window.inline_fragments(layout_id);
812                let previous_fragments = std::mem::replace(
813                    &mut window.current_inline_fragments,
814                    inline_fragments.clone(),
815                );
816
817                let mut prepaint = window.with_layout_direction_context(layout_id, |window| {
818                    #[cfg(all(
819                        feature = "hot-patching",
820                        debug_assertions,
821                        not(target_family = "wasm")
822                    ))]
823                    {
824                        subsecond::HotFn::current(E::prepaint).call((
825                            &mut self.element,
826                            global_id.as_ref(),
827                            inspector_id.as_ref(),
828                            bounds,
829                            &mut request_layout,
830                            window,
831                            cx,
832                        ))
833                    }
834
835                    #[cfg(not(all(
836                        feature = "hot-patching",
837                        debug_assertions,
838                        not(target_family = "wasm")
839                    )))]
840                    {
841                        self.element.prepaint(
842                            global_id.as_ref(),
843                            inspector_id.as_ref(),
844                            bounds,
845                            &mut request_layout,
846                            window,
847                            cx,
848                        )
849                    }
850                });
851
852                window.current_inline_fragments = previous_fragments;
853                window.next_frame.dispatch_tree.pop_node();
854
855                if pushed_a11y_node {
856                    if let Some(global_id) = global_id.as_ref() {
857                        #[cfg(debug_assertions)]
858                        let creator = crate::window::a11y::debug::NodeCreator {
859                            view: window
860                                .a11y
861                                .view_type_names
862                                .get(&window.current_view())
863                                .copied(),
864                            element_id: global_id.last().map(|id| format!("{id:?}")),
865                            source_location: self.element.source_location(),
866                        };
867                        let mut builder = A11ySubtreeBuilder::new(
868                            global_id.accesskit_node_id(),
869                            &mut window.a11y.nodes,
870                        );
871                        #[cfg(debug_assertions)]
872                        {
873                            builder = builder.with_creator(creator);
874                        }
875                        self.element
876                            .a11y_synthetic_children(&mut prepaint, &mut builder);
877                    }
878                    window.a11y.nodes.pop();
879                }
880
881                if global_id.is_some() {
882                    window.element_id_stack.pop();
883                }
884
885                self.phase = ElementDrawPhase::Prepaint {
886                    node_id,
887                    global_id,
888                    inspector_id,
889                    bounds,
890                    request_layout,
891                    prepaint,
892                    inline_fragments,
893                };
894            }
895            _ => panic!("must call request_layout before prepaint"),
896        }
897    }
898
899    pub(crate) fn paint(
900        &mut self,
901        window: &mut Window,
902        cx: &mut App,
903    ) -> (E::RequestLayoutState, E::PrepaintState) {
904        match mem::take(&mut self.phase) {
905            ElementDrawPhase::Prepaint {
906                node_id,
907                global_id,
908                inspector_id,
909                bounds,
910                mut request_layout,
911                mut prepaint,
912                inline_fragments,
913                ..
914            } => {
915                if let Some(element_id) = self.element.id() {
916                    window.element_id_stack.push(element_id);
917                    debug_assert_eq!(&**global_id.as_ref().unwrap(), &*window.element_id_stack);
918                }
919
920                window.next_frame.dispatch_tree.set_active_node(node_id);
921
922                let previous_fragments =
923                    std::mem::replace(&mut window.current_inline_fragments, inline_fragments);
924
925                #[cfg(all(
926                    feature = "hot-patching",
927                    debug_assertions,
928                    not(target_family = "wasm")
929                ))]
930                subsecond::HotFn::current(E::paint).call((
931                    &mut self.element,
932                    global_id.as_ref(),
933                    inspector_id.as_ref(),
934                    bounds,
935                    &mut request_layout,
936                    &mut prepaint,
937                    window,
938                    cx,
939                ));
940                #[cfg(not(all(
941                    feature = "hot-patching",
942                    debug_assertions,
943                    not(target_family = "wasm")
944                )))]
945                self.element.paint(
946                    global_id.as_ref(),
947                    inspector_id.as_ref(),
948                    bounds,
949                    &mut request_layout,
950                    &mut prepaint,
951                    window,
952                    cx,
953                );
954
955                if global_id.is_some() {
956                    window.element_id_stack.pop();
957                }
958
959                window.current_inline_fragments = previous_fragments;
960
961                self.phase = ElementDrawPhase::Painted;
962                (request_layout, prepaint)
963            }
964            _ => panic!("must call prepaint before paint"),
965        }
966    }
967
968    fn compute_layout_as_root(
969        &mut self,
970        available_space: Size<AvailableSpace>,
971        window: &mut Window,
972        cx: &mut App,
973    ) -> (LayoutId, Size<Pixels>) {
974        if matches!(&self.phase, ElementDrawPhase::Start) {
975            self.request_layout(window, cx);
976        }
977
978        let layout_id = match mem::take(&mut self.phase) {
979            ElementDrawPhase::RequestLayout {
980                layout_id,
981                global_id,
982                inspector_id,
983                request_layout,
984            } => {
985                window.compute_layout(layout_id, available_space, cx);
986                self.phase = ElementDrawPhase::LayoutComputed {
987                    layout_id,
988                    global_id,
989                    inspector_id,
990                    available_space,
991                    request_layout,
992                };
993                layout_id
994            }
995            ElementDrawPhase::LayoutComputed {
996                layout_id,
997                global_id,
998                inspector_id,
999                available_space: prev_available_space,
1000                request_layout,
1001            } => {
1002                if available_space != prev_available_space {
1003                    window.compute_layout(layout_id, available_space, cx);
1004                }
1005                self.phase = ElementDrawPhase::LayoutComputed {
1006                    layout_id,
1007                    global_id,
1008                    inspector_id,
1009                    available_space,
1010                    request_layout,
1011                };
1012                layout_id
1013            }
1014            _ => panic!("cannot measure after painting"),
1015        };
1016
1017        (layout_id, window.layout_bounds(layout_id).size)
1018    }
1019
1020    pub(crate) fn layout_as_root(
1021        &mut self,
1022        available_space: Size<AvailableSpace>,
1023        window: &mut Window,
1024        cx: &mut App,
1025    ) -> Size<Pixels> {
1026        self.compute_layout_as_root(available_space, window, cx).1
1027    }
1028}
1029
1030impl<E> ElementObject for Drawable<E>
1031where
1032    E: Element,
1033    E::RequestLayoutState: 'static,
1034{
1035    fn inner_element(&mut self) -> &mut dyn Any {
1036        &mut self.element
1037    }
1038
1039    #[inline]
1040    fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId {
1041        Drawable::request_layout(self, window, cx)
1042    }
1043
1044    #[inline]
1045    fn prepaint(&mut self, window: &mut Window, cx: &mut App) {
1046        Drawable::prepaint(self, window, cx);
1047    }
1048
1049    #[inline]
1050    fn paint(&mut self, window: &mut Window, cx: &mut App) {
1051        Drawable::paint(self, window, cx);
1052    }
1053
1054    #[inline]
1055    fn layout_as_root(
1056        &mut self,
1057        available_space: Size<AvailableSpace>,
1058        window: &mut Window,
1059        cx: &mut App,
1060    ) -> Size<Pixels> {
1061        Drawable::layout_as_root(self, available_space, window, cx)
1062    }
1063}
1064
1065/// An element with its concrete type erased, so that elements of different types can share one
1066/// type.
1067///
1068/// Use it when a function must return one type but its branches build different elements, or when
1069/// a list holds elements of mixed types. Create one with [`IntoElement::into_any_element`] or
1070/// [`Element::into_any`]. Its methods run the same phases as the element it wraps.
1071///
1072/// # Example
1073///
1074/// ```
1075/// use gpui::{AnyElement, Div, IntoElement, div, prelude::*};
1076///
1077/// fn label(wide: bool) -> AnyElement {
1078///     if wide {
1079///         div().w_full().child("Wide").into_any_element()
1080///     } else {
1081///         "Narrow".into_any_element()
1082///     }
1083/// }
1084///
1085/// let mut wide = label(true);
1086/// assert!(wide.downcast_mut::<Div>().is_some());
1087///
1088/// let mut narrow = label(false);
1089/// assert!(narrow.downcast_mut::<Div>().is_none());
1090/// ```
1091pub struct AnyElement(ArenaBox<dyn ElementObject>);
1092
1093impl AnyElement {
1094    pub(crate) fn new<E>(element: E) -> Self
1095    where
1096        E: 'static + Element,
1097        E::RequestLayoutState: Any,
1098    {
1099        let element = with_element_arena(|arena| arena.alloc(|| Drawable::new(element)))
1100            .map(|element| element as &mut dyn ElementObject);
1101        AnyElement(element)
1102    }
1103
1104    /// Returns a mutable reference to the wrapped element if it has type `T`, or `None` otherwise.
1105    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
1106        self.0.inner_element().downcast_mut::<T>()
1107    }
1108
1109    /// Runs the request-layout phase on the wrapped element, and returns its layout id.
1110    ///
1111    /// Call this from a parent's `request_layout`, before the parent's own layout is requested.
1112    pub fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId {
1113        self.0.request_layout(window, cx)
1114    }
1115
1116    /// Runs the prepaint phase on the wrapped element, with the bounds that layout gave it.
1117    ///
1118    /// Returns the [`FocusHandle`] of a focused element in this subtree, if one became focused
1119    /// during this call. Otherwise returns `None`.
1120    pub fn prepaint(&mut self, window: &mut Window, cx: &mut App) -> Option<FocusHandle> {
1121        let focus_assigned = window.next_frame.focus.is_some();
1122
1123        self.0.prepaint(window, cx);
1124
1125        if !focus_assigned && let Some(focus_id) = window.next_frame.focus {
1126            return FocusHandle::for_id(focus_id, &cx.focus_handles);
1127        }
1128
1129        None
1130    }
1131
1132    /// Runs the paint phase on the wrapped element. Call it after [`AnyElement::prepaint`].
1133    pub fn paint(&mut self, window: &mut Window, cx: &mut App) {
1134        self.0.paint(window, cx);
1135    }
1136
1137    /// Lays out this element as the root of its own layout, within `available_space`, and returns
1138    /// its size.
1139    ///
1140    /// The element is not placed in the window by this call. Use it to measure an element before
1141    /// placing it with [`AnyElement::prepaint_at`]. If the layout hasn't been requested yet, this
1142    /// method requests it first.
1143    pub fn layout_as_root(
1144        &mut self,
1145        available_space: Size<AvailableSpace>,
1146        window: &mut Window,
1147        cx: &mut App,
1148    ) -> Size<Pixels> {
1149        self.0.layout_as_root(available_space, window, cx)
1150    }
1151
1152    /// Runs the prepaint phase with `origin` as the element's origin, in window coordinates.
1153    ///
1154    /// Call [`AnyElement::layout_as_root`] first, or use [`AnyElement::prepaint_as_root`], which
1155    /// does both. Returns the focus handle of a focused element in the subtree that became focused
1156    /// during this call, if any.
1157    pub fn prepaint_at(
1158        &mut self,
1159        origin: Point<Pixels>,
1160        window: &mut Window,
1161        cx: &mut App,
1162    ) -> Option<FocusHandle> {
1163        window.with_absolute_element_offset(origin, |window| self.prepaint(window, cx))
1164    }
1165
1166    /// Lays out this element as a root within `available_space`, then prepaints it at `origin`.
1167    ///
1168    /// Use it for an element that sits outside its parent's layout, such as a popover placed at a
1169    /// window position. Returns the focus handle of a focused element in the subtree that became
1170    /// focused during this call, if any.
1171    pub fn prepaint_as_root(
1172        &mut self,
1173        origin: Point<Pixels>,
1174        available_space: Size<AvailableSpace>,
1175        window: &mut Window,
1176        cx: &mut App,
1177    ) -> Option<FocusHandle> {
1178        self.layout_as_root(available_space, window, cx);
1179        window.with_absolute_element_offset(origin, |window| self.prepaint(window, cx))
1180    }
1181}
1182
1183impl Element for AnyElement {
1184    type RequestLayoutState = ();
1185    type PrepaintState = ();
1186
1187    fn id(&self) -> Option<ElementId> {
1188        None
1189    }
1190
1191    fn source_location(&self) -> Option<&'static panic::Location<'static>> {
1192        None
1193    }
1194
1195    fn request_layout(
1196        &mut self,
1197        _: Option<&GlobalElementId>,
1198        _inspector_id: Option<&InspectorElementId>,
1199        window: &mut Window,
1200        cx: &mut App,
1201    ) -> (LayoutId, Self::RequestLayoutState) {
1202        let layout_id = self.request_layout(window, cx);
1203        (layout_id, ())
1204    }
1205
1206    fn prepaint(
1207        &mut self,
1208        _: Option<&GlobalElementId>,
1209        _inspector_id: Option<&InspectorElementId>,
1210        _: Bounds<Pixels>,
1211        _: &mut Self::RequestLayoutState,
1212        window: &mut Window,
1213        cx: &mut App,
1214    ) {
1215        self.prepaint(window, cx);
1216    }
1217
1218    fn paint(
1219        &mut self,
1220        _: Option<&GlobalElementId>,
1221        _inspector_id: Option<&InspectorElementId>,
1222        _: Bounds<Pixels>,
1223        _: &mut Self::RequestLayoutState,
1224        _: &mut Self::PrepaintState,
1225        window: &mut Window,
1226        cx: &mut App,
1227    ) {
1228        self.paint(window, cx);
1229    }
1230}
1231
1232impl IntoElement for AnyElement {
1233    type Element = Self;
1234
1235    fn into_element(self) -> Self::Element {
1236        self
1237    }
1238
1239    fn into_any_element(self) -> AnyElement {
1240        self
1241    }
1242}
1243
1244/// An element that draws nothing and takes up no space.
1245///
1246/// Return it where a view or component must produce an element but has nothing to show. Its
1247/// layout has `display: none`, so it doesn't affect its siblings.
1248pub struct Empty;
1249
1250impl IntoElement for Empty {
1251    type Element = Self;
1252
1253    fn into_element(self) -> Self::Element {
1254        self
1255    }
1256}
1257
1258impl Element for Empty {
1259    type RequestLayoutState = ();
1260    type PrepaintState = ();
1261
1262    fn id(&self) -> Option<ElementId> {
1263        None
1264    }
1265
1266    fn source_location(&self) -> Option<&'static panic::Location<'static>> {
1267        None
1268    }
1269
1270    fn request_layout(
1271        &mut self,
1272        _id: Option<&GlobalElementId>,
1273        _inspector_id: Option<&InspectorElementId>,
1274        window: &mut Window,
1275        cx: &mut App,
1276    ) -> (LayoutId, Self::RequestLayoutState) {
1277        (
1278            window.request_layout(
1279                Style {
1280                    display: crate::Display::None,
1281                    ..Default::default()
1282                },
1283                None,
1284                cx,
1285            ),
1286            (),
1287        )
1288    }
1289
1290    fn prepaint(
1291        &mut self,
1292        _id: Option<&GlobalElementId>,
1293        _inspector_id: Option<&InspectorElementId>,
1294        _bounds: Bounds<Pixels>,
1295        _state: &mut Self::RequestLayoutState,
1296        _window: &mut Window,
1297        _cx: &mut App,
1298    ) {
1299    }
1300
1301    fn paint(
1302        &mut self,
1303        _id: Option<&GlobalElementId>,
1304        _inspector_id: Option<&InspectorElementId>,
1305        _bounds: Bounds<Pixels>,
1306        _request_layout: &mut Self::RequestLayoutState,
1307        _prepaint: &mut Self::PrepaintState,
1308        _window: &mut Window,
1309        _cx: &mut App,
1310    ) {
1311    }
1312}
1313
1314#[inline(never)]
1315fn prepare_element_id(element_id: ElementId, window: &mut Window) -> GlobalElementId {
1316    window.element_id_stack.push(element_id);
1317    window.element_id_stack.global_id()
1318}
1319
1320#[cfg(any(feature = "inspector", debug_assertions))]
1321#[inline(never)]
1322fn prepare_inspector_id(
1323    source: &'static panic::Location<'static>,
1324    window: &mut Window,
1325) -> InspectorElementId {
1326    let path = InspectorElementPath {
1327        global_id: window.element_id_stack.global_id(),
1328        source_location: source,
1329    };
1330    window.build_inspector_element_id(path)
1331}
1332
1333#[cfg(test)]
1334mod global_element_id_tests {
1335    use super::*;
1336    use std::hash::{Hash, Hasher};
1337
1338    fn path(depth: usize, leaf: u64) -> Vec<ElementId> {
1339        let mut ids: Vec<ElementId> = (0..depth as u64)
1340            .map(|level| ElementId::NamedInteger("some-container-element".into(), level))
1341            .collect();
1342        ids.push(ElementId::NamedInteger("leaf".into(), leaf));
1343        ids
1344    }
1345
1346    fn fx_hash(value: &impl Hash) -> u64 {
1347        let mut hasher = collections::FxHasher::default();
1348        value.hash(&mut hasher);
1349        hasher.finish()
1350    }
1351
1352    #[test]
1353    fn equal_paths_are_equal_and_hash_alike() {
1354        let a = GlobalElementId::new(&path(8, 1));
1355        let b = GlobalElementId::new(&path(8, 1));
1356        let c = GlobalElementId::new(&path(8, 2));
1357        let shallower = GlobalElementId::new(&path(7, 1));
1358        assert_eq!(a, b);
1359        assert_eq!(fx_hash(&a), fx_hash(&b));
1360        assert_eq!(a.accesskit_node_id(), b.accesskit_node_id());
1361        assert_ne!(a, c);
1362        assert_ne!(a, shallower);
1363        assert_ne!(fx_hash(&a), fx_hash(&c));
1364        assert_eq!(&*a, path(8, 1).as_slice());
1365        assert_eq!(a.to_string(), b.to_string());
1366        assert_eq!(GlobalElementId::default(), GlobalElementId::new(&[]));
1367    }
1368
1369    /// A window of `items` columns of `depth` nested stateful divs — the
1370    /// shape of a list of cards — drawn from scratch on every frame.
1371    struct DeepStatefulTree {
1372        items: usize,
1373        depth: usize,
1374    }
1375
1376    impl crate::Render for DeepStatefulTree {
1377        fn render(&mut self, _: &mut Window, _: &mut crate::Context<Self>) -> impl IntoElement {
1378            use crate::{InteractiveElement as _, ParentElement as _, Styled as _, div, px};
1379            let depth = self.depth;
1380            div()
1381                .flex()
1382                .flex_wrap()
1383                .size_full()
1384                .children((0..self.items).map(move |item| {
1385                    let mut element = div().id(("leaf", item as u64)).size(px(2.));
1386                    for level in (0..depth).rev() {
1387                        element = div()
1388                            .id(("some-container-element", level as u64))
1389                            .child(element);
1390                    }
1391                    element.id(("item", item as u64)).size(px(4.))
1392                }))
1393        }
1394    }
1395
1396    /// Frame cost of a tree of stateful elements: every one of them builds a
1397    /// `GlobalElementId` and looks its state up in two frames' maps.
1398    ///
1399    /// `cargo test -p gpui --release --lib global_element_id_tests::frame_cost -- --ignored --nocapture`
1400    #[crate::test]
1401    #[ignore = "prints timings; run by hand"]
1402    fn frame_cost(cx: &mut crate::TestAppContext) {
1403        use crate::AppContext as _;
1404        for (items, depth) in [(500, 4), (500, 12), (2000, 12)] {
1405            let window = cx.add_window(move |_, _| DeepStatefulTree { items, depth });
1406            let window = crate::AnyWindowHandle::from(window);
1407            let mut frame = |cx: &mut crate::TestAppContext| {
1408                cx.update_window(window, |_, window, cx| {
1409                    window.refresh();
1410                    let started = std::time::Instant::now();
1411                    window.draw(cx).clear(cx);
1412                    started.elapsed()
1413                })
1414                .unwrap()
1415            };
1416            for _ in 0..5 {
1417                frame(cx);
1418            }
1419            let mut samples: Vec<_> = (0..40).map(|_| frame(cx)).collect();
1420            samples.sort();
1421            let median = samples[samples.len() / 2];
1422            let stateful = items * (depth + 2);
1423            eprintln!(
1424                "{items} items x {depth} deep ({stateful} stateful elements): median frame {:.2} ms, {:.0} ns per stateful element",
1425                median.as_secs_f64() * 1e3,
1426                median.as_nanos() as f64 / stateful as f64,
1427            );
1428        }
1429    }
1430
1431    /// `cargo test -p gpui --release --lib global_element_id_tests::hash_cost -- --ignored --nocapture`
1432    #[test]
1433    #[ignore = "prints timings; run by hand"]
1434    fn hash_cost() {
1435        let ids = path(11, 7);
1436        let id = GlobalElementId::new(&ids);
1437        let n = 1_000_000u64;
1438        let mut acc = 0u64;
1439        let started = std::time::Instant::now();
1440        for _ in 0..n {
1441            acc ^= fx_hash(&std::hint::black_box(ids.as_slice()));
1442        }
1443        let walk = started.elapsed();
1444        let started = std::time::Instant::now();
1445        for _ in 0..n {
1446            acc ^= fx_hash(std::hint::black_box(&id));
1447        }
1448        let cached = started.elapsed();
1449        let started = std::time::Instant::now();
1450        for _ in 0..n {
1451            acc ^= GlobalElementId::new(std::hint::black_box(&ids)).hash;
1452        }
1453        let build = started.elapsed();
1454        eprintln!(
1455            "12-deep path: hash by walking ids {:.1} ns, cached {:.1} ns, build (clone + hash once) {:.1} ns [{acc}]",
1456            walk.as_nanos() as f64 / n as f64,
1457            cached.as_nanos() as f64 / n as f64,
1458            build.as_nanos() as f64 / n as f64,
1459        );
1460    }
1461}