element.rs

  1//! Elements are the workhorses of GPUI. They are responsible for laying out and painting all of
  2//! the contents of a window. Elements form a tree and are laid out according to the web layout
  3//! standards as implemented by [taffy](https://github.com/DioxusLabs/taffy). Most of the time,
  4//! you won't need to interact with this module or these APIs directly. Elements provide their
  5//! own APIs and GPUI, or other element implementation, uses the APIs in this module to convert
  6//! that element tree into the pixels you see on the screen.
  7//!
  8//! # Element Basics
  9//!
 10//! Elements are constructed by calling [`Render::render()`] on the root view of the window, which
 11//! which recursively constructs the element tree from the current state of the application,.
 12//! These elements are then laid out by Taffy, and painted to the screen according to their own
 13//! implementation of [`Element::paint()`]. Before the start of the next frame, the entire element
 14//! tree and any callbacks they have registered with GPUI are dropped and the process repeats.
 15//!
 16//! But some state is too simple and voluminous to store in every view that needs it, e.g.
 17//! whether a hover has been started or not. For this, GPUI provides the [`Element::State`], associated type.
 18//! If an element returns an [`ElementId`] from [`IntoElement::element_id()`], and that element id
 19//! appears in the same place relative to other views and ElementIds in the frame, then the previous
 20//! frame's state will be passed to the element's layout and paint methods.
 21//!
 22//! # Implementing your own elements
 23//!
 24//! Elements are intended to be the low level, imperative API to GPUI. They are responsible for upholding,
 25//! or breaking, GPUI's features as they deem necessary. As an example, most GPUI elements are expected
 26//! to stay in the bounds that their parent element gives them. But with [`WindowContext::break_content_mask`],
 27//! you can ignore this restriction and paint anywhere inside of the window's bounds. This is useful for overlays
 28//! and popups and anything else that shows up 'on top' of other elements.
 29//! With great power, comes great responsibility.
 30//!
 31//! However, most of the time, you won't need to implement your own elements. GPUI provides a number of
 32//! elements that should cover most common use cases out of the box and it's recommended that you use those
 33//! to construct `components`, using the [`RenderOnce`] trait and the `#[derive(IntoElement)]` macro. Only implement
 34//! elements when you need to take manual control of the layout and painting process, such as when using
 35//! your own custom layout algorithm or rendering a code editor.
 36
 37use crate::{
 38    util::FluentBuilder, AppContext, ArenaBox, AvailableSpace, BorrowWindow, Bounds, ContentMask,
 39    ElementId, ElementStateBox, EntityId, IsZero, LayoutId, Pixels, Point, Size, ViewContext,
 40    Window, WindowContext, ELEMENT_ARENA,
 41};
 42use derive_more::{Deref, DerefMut};
 43pub(crate) use smallvec::SmallVec;
 44use std::{
 45    any::Any,
 46    borrow::{Borrow, BorrowMut},
 47    fmt::Debug,
 48    mem,
 49    ops::DerefMut,
 50};
 51use util::post_inc;
 52
 53/// This context is used for assisting in the implementation of the element trait
 54#[derive(Deref, DerefMut)]
 55pub struct ElementContext<'a> {
 56    pub(crate) cx: WindowContext<'a>,
 57}
 58
 59impl<'a> WindowContext<'a> {
 60    pub(crate) fn into_element_cx(self) -> ElementContext<'a> {
 61        ElementContext { cx: self }
 62    }
 63}
 64
 65impl<'a> Borrow<AppContext> for ElementContext<'a> {
 66    fn borrow(&self) -> &AppContext {
 67        self.cx.borrow()
 68    }
 69}
 70
 71impl<'a> BorrowMut<AppContext> for ElementContext<'a> {
 72    fn borrow_mut(&mut self) -> &mut AppContext {
 73        self.cx.borrow_mut()
 74    }
 75}
 76
 77impl<'a> Borrow<Window> for ElementContext<'a> {
 78    fn borrow(&self) -> &Window {
 79        self.cx.borrow()
 80    }
 81}
 82
 83impl<'a> BorrowMut<Window> for ElementContext<'a> {
 84    fn borrow_mut(&mut self) -> &mut Window {
 85        self.cx.borrow_mut()
 86    }
 87}
 88
 89/// Implemented by types that participate in laying out and painting the contents of a window.
 90/// Elements form a tree and are laid out according to web-based layout rules, as implemented by Taffy.
 91/// You can create custom elements by implementing this trait, see the module-level documentation
 92/// for more details.
 93pub trait Element: 'static + IntoElement {
 94    /// The type of state to store for this element between frames. See the module-level documentation
 95    /// for details.
 96    type State: 'static;
 97
 98    /// Before an element can be painted, we need to know where it's going to be and how big it is.
 99    /// Use this method to request a layout from Taffy and initialize the element's state.
100    fn request_layout(
101        &mut self,
102        state: Option<Self::State>,
103        cx: &mut ElementContext,
104    ) -> (LayoutId, Self::State);
105
106    /// Once layout has been completed, this method will be called to paint the element to the screen.
107    /// The state argument is the same state that was returned from [`Element::request_layout()`].
108    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext);
109
110    /// Convert this element into a dynamically-typed [`AnyElement`].
111    fn into_any(self) -> AnyElement {
112        AnyElement::new(self)
113    }
114}
115
116/// Implemented by any type that can be converted into an element.
117pub trait IntoElement: Sized {
118    /// The specific type of element into which the implementing type is converted.
119    /// Useful for converting other types into elements automatically, like Strings
120    type Element: Element;
121
122    /// The [`ElementId`] of self once converted into an [`Element`].
123    /// If present, the resulting element's state will be carried across frames.
124    fn element_id(&self) -> Option<ElementId>;
125
126    /// Convert self into a type that implements [`Element`].
127    fn into_element(self) -> Self::Element;
128
129    /// Convert self into a dynamically-typed [`AnyElement`].
130    fn into_any_element(self) -> AnyElement {
131        self.into_element().into_any()
132    }
133
134    /// Convert into an element, then draw in the current window at the given origin.
135    /// The available space argument is provided to the layout engine to determine the size of the
136    // root element.  Once the element is drawn, its associated element state is yielded to the
137    // given callback.
138    fn draw_and_update_state<T, R>(
139        self,
140        origin: Point<Pixels>,
141        available_space: Size<T>,
142        cx: &mut ElementContext,
143        f: impl FnOnce(&mut <Self::Element as Element>::State, &mut ElementContext) -> R,
144    ) -> R
145    where
146        T: Clone + Default + Debug + Into<AvailableSpace>,
147    {
148        let element = self.into_element();
149        let element_id = element.element_id();
150        let element = DrawableElement {
151            element: Some(element),
152            phase: ElementDrawPhase::Start,
153        };
154
155        let frame_state =
156            DrawableElement::draw(element, origin, available_space.map(Into::into), cx);
157
158        if let Some(mut frame_state) = frame_state {
159            f(&mut frame_state, cx)
160        } else {
161            cx.with_element_state(element_id.unwrap(), |element_state, cx| {
162                let mut element_state = element_state.unwrap();
163                let result = f(&mut element_state, cx);
164                (result, element_state)
165            })
166        }
167    }
168}
169
170impl<T: IntoElement> FluentBuilder for T {}
171
172/// An object that can be drawn to the screen. This is the trait that distinguishes `Views` from
173/// models. Views are drawn to the screen and care about the current window's state, models are not and do not.
174pub trait Render: 'static + Sized {
175    /// Render this view into an element tree.
176    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement;
177}
178
179impl Render for () {
180    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
181        ()
182    }
183}
184
185/// You can derive [`IntoElement`] on any type that implements this trait.
186/// It is used to construct reusable `components` out of plain data. Think of
187/// components as a recipe for a certain pattern of elements. RenderOnce allows
188/// you to invoke this pattern, without breaking the fluent builder pattern of
189/// the element APIs.
190pub trait RenderOnce: 'static {
191    /// Render this component into an element tree. Note that this method
192    /// takes ownership of self, as compared to [`Render::render()`] method
193    /// which takes a mutable reference.
194    fn render(self, cx: &mut WindowContext) -> impl IntoElement;
195}
196
197/// This is a helper trait to provide a uniform interface for constructing elements that
198/// can accept any number of any kind of child elements
199pub trait ParentElement {
200    /// Extend this element's children with the given child elements.
201    fn extend(&mut self, elements: impl Iterator<Item = AnyElement>);
202
203    /// Add a single child element to this element.
204    fn child(mut self, child: impl IntoElement) -> Self
205    where
206        Self: Sized,
207    {
208        self.extend(std::iter::once(child.into_element().into_any()));
209        self
210    }
211
212    /// Add multiple child elements to this element.
213    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
214    where
215        Self: Sized,
216    {
217        self.extend(children.into_iter().map(|child| child.into_any_element()));
218        self
219    }
220}
221
222/// An element for rendering components. An implementation detail of the [`IntoElement`] derive macro
223/// for [`RenderOnce`]
224#[doc(hidden)]
225pub struct Component<C: RenderOnce>(Option<C>);
226
227impl<C: RenderOnce> Component<C> {
228    /// Create a new component from the given RenderOnce type.
229    pub fn new(component: C) -> Self {
230        Component(Some(component))
231    }
232}
233
234impl<C: RenderOnce> Element for Component<C> {
235    type State = AnyElement;
236
237    fn request_layout(
238        &mut self,
239        _: Option<Self::State>,
240        cx: &mut ElementContext,
241    ) -> (LayoutId, Self::State) {
242        let mut element = self
243            .0
244            .take()
245            .unwrap()
246            .render(cx.deref_mut())
247            .into_any_element();
248        let layout_id = element.request_layout(cx);
249        (layout_id, element)
250    }
251
252    fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) {
253        element.paint(cx)
254    }
255}
256
257impl<C: RenderOnce> IntoElement for Component<C> {
258    type Element = Self;
259
260    fn element_id(&self) -> Option<ElementId> {
261        None
262    }
263
264    fn into_element(self) -> Self::Element {
265        self
266    }
267}
268
269/// A globally unique identifier for an element, used to track state across frames.
270#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
271pub(crate) struct GlobalElementId(SmallVec<[ElementId; 32]>);
272
273trait ElementObject {
274    fn element_id(&self) -> Option<ElementId>;
275
276    fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
277
278    fn paint(&mut self, cx: &mut ElementContext);
279
280    fn measure(
281        &mut self,
282        available_space: Size<AvailableSpace>,
283        cx: &mut ElementContext,
284    ) -> Size<Pixels>;
285
286    fn draw(
287        &mut self,
288        origin: Point<Pixels>,
289        available_space: Size<AvailableSpace>,
290        cx: &mut ElementContext,
291    );
292}
293
294/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
295pub(crate) struct DrawableElement<E: Element> {
296    element: Option<E>,
297    phase: ElementDrawPhase<E::State>,
298}
299
300#[derive(Default)]
301enum ElementDrawPhase<S> {
302    #[default]
303    Start,
304    LayoutRequested {
305        layout_id: LayoutId,
306        frame_state: Option<S>,
307    },
308    LayoutComputed {
309        layout_id: LayoutId,
310        available_space: Size<AvailableSpace>,
311        frame_state: Option<S>,
312    },
313}
314
315/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
316impl<E: Element> DrawableElement<E> {
317    fn new(element: E) -> Self {
318        DrawableElement {
319            element: Some(element),
320            phase: ElementDrawPhase::Start,
321        }
322    }
323
324    fn element_id(&self) -> Option<ElementId> {
325        self.element.as_ref()?.element_id()
326    }
327
328    fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
329        let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
330        {
331            let layout_id = cx.with_element_state(id, |element_state, cx| {
332                self.element
333                    .as_mut()
334                    .unwrap()
335                    .request_layout(element_state, cx)
336            });
337            (layout_id, None)
338        } else {
339            let (layout_id, frame_state) = self.element.as_mut().unwrap().request_layout(None, cx);
340            (layout_id, Some(frame_state))
341        };
342
343        self.phase = ElementDrawPhase::LayoutRequested {
344            layout_id,
345            frame_state,
346        };
347        layout_id
348    }
349
350    fn paint(mut self, cx: &mut ElementContext) -> Option<E::State> {
351        match self.phase {
352            ElementDrawPhase::LayoutRequested {
353                layout_id,
354                frame_state,
355            }
356            | ElementDrawPhase::LayoutComputed {
357                layout_id,
358                frame_state,
359                ..
360            } => {
361                let bounds = cx.layout_bounds(layout_id);
362
363                if let Some(mut frame_state) = frame_state {
364                    self.element
365                        .take()
366                        .unwrap()
367                        .paint(bounds, &mut frame_state, cx);
368                    Some(frame_state)
369                } else {
370                    let element_id = self
371                        .element
372                        .as_ref()
373                        .unwrap()
374                        .element_id()
375                        .expect("if we don't have frame state, we should have element state");
376                    cx.with_element_state(element_id, |element_state, cx| {
377                        let mut element_state = element_state.unwrap();
378                        self.element
379                            .take()
380                            .unwrap()
381                            .paint(bounds, &mut element_state, cx);
382                        ((), element_state)
383                    });
384                    None
385                }
386            }
387
388            _ => panic!("must call layout before paint"),
389        }
390    }
391
392    fn measure(
393        &mut self,
394        available_space: Size<AvailableSpace>,
395        cx: &mut ElementContext,
396    ) -> Size<Pixels> {
397        if matches!(&self.phase, ElementDrawPhase::Start) {
398            self.request_layout(cx);
399        }
400
401        let layout_id = match &mut self.phase {
402            ElementDrawPhase::LayoutRequested {
403                layout_id,
404                frame_state,
405            } => {
406                cx.compute_layout(*layout_id, available_space);
407                let layout_id = *layout_id;
408                self.phase = ElementDrawPhase::LayoutComputed {
409                    layout_id,
410                    available_space,
411                    frame_state: frame_state.take(),
412                };
413                layout_id
414            }
415            ElementDrawPhase::LayoutComputed {
416                layout_id,
417                available_space: prev_available_space,
418                ..
419            } => {
420                if available_space != *prev_available_space {
421                    cx.compute_layout(*layout_id, available_space);
422                    *prev_available_space = available_space;
423                }
424                *layout_id
425            }
426            _ => panic!("cannot measure after painting"),
427        };
428
429        cx.layout_bounds(layout_id).size
430    }
431
432    fn draw(
433        mut self,
434        origin: Point<Pixels>,
435        available_space: Size<AvailableSpace>,
436        cx: &mut ElementContext,
437    ) -> Option<E::State> {
438        self.measure(available_space, cx);
439        cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
440    }
441}
442
443impl<E> ElementObject for Option<DrawableElement<E>>
444where
445    E: Element,
446    E::State: 'static,
447{
448    fn element_id(&self) -> Option<ElementId> {
449        self.as_ref().unwrap().element_id()
450    }
451
452    fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
453        DrawableElement::request_layout(self.as_mut().unwrap(), cx)
454    }
455
456    fn paint(&mut self, cx: &mut ElementContext) {
457        DrawableElement::paint(self.take().unwrap(), cx);
458    }
459
460    fn measure(
461        &mut self,
462        available_space: Size<AvailableSpace>,
463        cx: &mut ElementContext,
464    ) -> Size<Pixels> {
465        DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
466    }
467
468    fn draw(
469        &mut self,
470        origin: Point<Pixels>,
471        available_space: Size<AvailableSpace>,
472        cx: &mut ElementContext,
473    ) {
474        DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
475    }
476}
477
478/// A dynamically typed element that can be used to store any element type.
479pub struct AnyElement(ArenaBox<dyn ElementObject>);
480
481impl AnyElement {
482    pub(crate) fn new<E>(element: E) -> Self
483    where
484        E: 'static + Element,
485        E::State: Any,
486    {
487        let element = ELEMENT_ARENA
488            .with_borrow_mut(|arena| arena.alloc(|| Some(DrawableElement::new(element))))
489            .map(|element| element as &mut dyn ElementObject);
490        AnyElement(element)
491    }
492
493    /// Request the layout ID of the element stored in this `AnyElement`.
494    /// Used for laying out child elements in a parent element.
495    pub fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
496        self.0.request_layout(cx)
497    }
498
499    /// Paints the element stored in this `AnyElement`.
500    pub fn paint(&mut self, cx: &mut ElementContext) {
501        self.0.paint(cx)
502    }
503
504    /// Initializes this element and performs layout within the given available space to determine its size.
505    pub fn measure(
506        &mut self,
507        available_space: Size<AvailableSpace>,
508        cx: &mut ElementContext,
509    ) -> Size<Pixels> {
510        self.0.measure(available_space, cx)
511    }
512
513    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
514    pub fn draw(
515        &mut self,
516        origin: Point<Pixels>,
517        available_space: Size<AvailableSpace>,
518        cx: &mut ElementContext,
519    ) {
520        self.0.draw(origin, available_space, cx)
521    }
522
523    /// Returns the element ID of the element stored in this `AnyElement`, if any.
524    pub fn inner_id(&self) -> Option<ElementId> {
525        self.0.element_id()
526    }
527}
528
529impl Element for AnyElement {
530    type State = ();
531
532    fn request_layout(
533        &mut self,
534        _: Option<Self::State>,
535        cx: &mut ElementContext,
536    ) -> (LayoutId, Self::State) {
537        let layout_id = self.request_layout(cx);
538        (layout_id, ())
539    }
540
541    fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut ElementContext) {
542        self.paint(cx)
543    }
544}
545
546impl IntoElement for AnyElement {
547    type Element = Self;
548
549    fn element_id(&self) -> Option<ElementId> {
550        None
551    }
552
553    fn into_element(self) -> Self::Element {
554        self
555    }
556
557    fn into_any_element(self) -> AnyElement {
558        self
559    }
560}
561
562/// The empty element, which renders nothing.
563pub type Empty = ();
564
565impl IntoElement for () {
566    type Element = Self;
567
568    fn element_id(&self) -> Option<ElementId> {
569        None
570    }
571
572    fn into_element(self) -> Self::Element {
573        self
574    }
575}
576
577impl Element for () {
578    type State = ();
579
580    fn request_layout(
581        &mut self,
582        _state: Option<Self::State>,
583        cx: &mut ElementContext,
584    ) -> (LayoutId, Self::State) {
585        (cx.request_layout(&crate::Style::default(), None), ())
586    }
587
588    fn paint(
589        &mut self,
590        _bounds: Bounds<Pixels>,
591        _state: &mut Self::State,
592        _cx: &mut ElementContext,
593    ) {
594    }
595}
596
597impl<'a> ElementContext<'a> {
598    /// Pushes the given element id onto the global stack and invokes the given closure
599    /// with a `GlobalElementId`, which disambiguates the given id in the context of its ancestor
600    /// ids. Because elements are discarded and recreated on each frame, the `GlobalElementId` is
601    /// used to associate state with identified elements across separate frames.
602    fn with_element_id<R>(
603        &mut self,
604        id: Option<impl Into<ElementId>>,
605        f: impl FnOnce(&mut Self) -> R,
606    ) -> R {
607        if let Some(id) = id.map(Into::into) {
608            let window = self.window_mut();
609            window.element_id_stack.push(id);
610            let result = f(self);
611            let window: &mut Window = self.borrow_mut();
612            window.element_id_stack.pop();
613            result
614        } else {
615            f(self)
616        }
617    }
618
619    /// Invoke the given function with the given content mask after intersecting it
620    /// with the current mask.
621    fn with_content_mask<R>(
622        &mut self,
623        mask: Option<ContentMask<Pixels>>,
624        f: impl FnOnce(&mut Self) -> R,
625    ) -> R {
626        if let Some(mask) = mask {
627            let mask = mask.intersect(&self.content_mask());
628            self.window_mut().next_frame.content_mask_stack.push(mask);
629            let result = f(self);
630            self.window_mut().next_frame.content_mask_stack.pop();
631            result
632        } else {
633            f(self)
634        }
635    }
636
637    /// Invoke the given function with the content mask reset to that
638    /// of the window.
639    fn break_content_mask<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
640        let mask = ContentMask {
641            bounds: Bounds {
642                origin: Point::default(),
643                size: self.window().viewport_size,
644            },
645        };
646        let new_stacking_order_id =
647            post_inc(&mut self.window_mut().next_frame.next_stacking_order_id);
648        let new_root_z_index = post_inc(&mut self.window_mut().next_frame.next_root_z_index);
649        let old_stacking_order = mem::take(&mut self.window_mut().next_frame.z_index_stack);
650        self.window_mut().next_frame.z_index_stack.id = new_stacking_order_id;
651        self.window_mut()
652            .next_frame
653            .z_index_stack
654            .push(new_root_z_index);
655        self.window_mut().next_frame.content_mask_stack.push(mask);
656        let result = f(self);
657        self.window_mut().next_frame.content_mask_stack.pop();
658        self.window_mut().next_frame.z_index_stack = old_stacking_order;
659        result
660    }
661
662    /// Called during painting to invoke the given closure in a new stacking context. The given
663    /// z-index is interpreted relative to the previous call to `stack`.
664    fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
665        let new_stacking_order_id =
666            post_inc(&mut self.window_mut().next_frame.next_stacking_order_id);
667        let old_stacking_order_id = mem::replace(
668            &mut self.window_mut().next_frame.z_index_stack.id,
669            new_stacking_order_id,
670        );
671        self.window_mut().next_frame.z_index_stack.id = new_stacking_order_id;
672        self.window_mut().next_frame.z_index_stack.push(z_index);
673        let result = f(self);
674        self.window_mut().next_frame.z_index_stack.id = old_stacking_order_id;
675        self.window_mut().next_frame.z_index_stack.pop();
676        result
677    }
678
679    /// Updates the global element offset relative to the current offset. This is used to implement
680    /// scrolling.
681    fn with_element_offset<R>(
682        &mut self,
683        offset: Point<Pixels>,
684        f: impl FnOnce(&mut Self) -> R,
685    ) -> R {
686        if offset.is_zero() {
687            return f(self);
688        };
689
690        let abs_offset = self.element_offset() + offset;
691        self.with_absolute_element_offset(abs_offset, f)
692    }
693
694    /// Updates the global element offset based on the given offset. This is used to implement
695    /// drag handles and other manual painting of elements.
696    fn with_absolute_element_offset<R>(
697        &mut self,
698        offset: Point<Pixels>,
699        f: impl FnOnce(&mut Self) -> R,
700    ) -> R {
701        self.window_mut()
702            .next_frame
703            .element_offset_stack
704            .push(offset);
705        let result = f(self);
706        self.window_mut().next_frame.element_offset_stack.pop();
707        result
708    }
709
710    /// Obtain the current element offset.
711    fn element_offset(&self) -> Point<Pixels> {
712        self.window()
713            .next_frame
714            .element_offset_stack
715            .last()
716            .copied()
717            .unwrap_or_default()
718    }
719
720    /// Obtain the current content mask.
721    fn content_mask(&self) -> ContentMask<Pixels> {
722        self.window()
723            .next_frame
724            .content_mask_stack
725            .last()
726            .cloned()
727            .unwrap_or_else(|| ContentMask {
728                bounds: Bounds {
729                    origin: Point::default(),
730                    size: self.window().viewport_size,
731                },
732            })
733    }
734
735    /// The size of an em for the base font of the application. Adjusting this value allows the
736    /// UI to scale, just like zooming a web page.
737    fn rem_size(&self) -> Pixels {
738        self.window().rem_size
739    }
740
741    fn parent_view_id(&self) -> EntityId {
742        *self
743            .window
744            .next_frame
745            .view_stack
746            .last()
747            .expect("a view should always be on the stack while drawing")
748    }
749
750    /// Updates or initializes state for an element with the given id that lives across multiple
751    /// frames. If an element with this ID existed in the rendered frame, its state will be passed
752    /// to the given closure. The state returned by the closure will be stored so it can be referenced
753    /// when drawing the next frame.
754    pub(crate) fn with_element_state<S, R>(
755        &mut self,
756        id: ElementId,
757        f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
758    ) -> R
759    where
760        S: 'static,
761    {
762        self.with_element_id(Some(id), |cx| {
763            let global_id = cx.window().element_id_stack.clone();
764
765            if let Some(any) = cx
766                .window_mut()
767                .next_frame
768                .element_states
769                .remove(&global_id)
770                .or_else(|| {
771                    cx.window_mut()
772                        .rendered_frame
773                        .element_states
774                        .remove(&global_id)
775                })
776            {
777                let ElementStateBox {
778                    inner,
779                    parent_view_id,
780                    #[cfg(debug_assertions)]
781                    type_name
782                } = any;
783                // Using the extra inner option to avoid needing to reallocate a new box.
784                let mut state_box = inner
785                    .downcast::<Option<S>>()
786                    .map_err(|_| {
787                        #[cfg(debug_assertions)]
788                        {
789                            anyhow::anyhow!(
790                                "invalid element state type for id, requested_type {:?}, actual type: {:?}",
791                                std::any::type_name::<S>(),
792                                type_name
793                            )
794                        }
795
796                        #[cfg(not(debug_assertions))]
797                        {
798                            anyhow::anyhow!(
799                                "invalid element state type for id, requested_type {:?}",
800                                std::any::type_name::<S>(),
801                            )
802                        }
803                    })
804                    .unwrap();
805
806                // Actual: Option<AnyElement> <- View
807                // Requested: () <- AnyElement
808                let state = state_box
809                    .take()
810                    .expect("element state is already on the stack");
811                let (result, state) = f(Some(state), cx);
812                state_box.replace(state);
813                cx.window_mut()
814                    .next_frame
815                    .element_states
816                    .insert(global_id, ElementStateBox {
817                        inner: state_box,
818                        parent_view_id,
819                        #[cfg(debug_assertions)]
820                        type_name
821                    });
822                result
823            } else {
824                let (result, state) = f(None, cx);
825                let parent_view_id = cx.parent_view_id();
826                cx.window_mut()
827                    .next_frame
828                    .element_states
829                    .insert(global_id,
830                        ElementStateBox {
831                            inner: Box::new(Some(state)),
832                            parent_view_id,
833                            #[cfg(debug_assertions)]
834                            type_name: std::any::type_name::<S>()
835                        }
836
837                    );
838                result
839            }
840        })
841    }
842}