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}