1use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
2use derive_more::{Deref, DerefMut};
3pub(crate) use smallvec::SmallVec;
4
5pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
6 type ViewState: 'static + Send + Sync;
7 type ElementState: 'static + Send + Sync;
8
9 fn id(&self) -> Option<ElementId>;
10
11 fn layout(
12 &mut self,
13 state: &mut Self::ViewState,
14 element_state: Option<Self::ElementState>,
15 cx: &mut ViewContext<Self::ViewState>,
16 ) -> (LayoutId, Self::ElementState);
17
18 fn paint(
19 &mut self,
20 bounds: Bounds<Pixels>,
21 state: &mut Self::ViewState,
22 element_state: &mut Self::ElementState,
23 cx: &mut ViewContext<Self::ViewState>,
24 );
25}
26
27#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
28pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
29
30pub trait ElementIdentity: 'static + Send + Sync {
31 fn id(&self) -> Option<ElementId>;
32}
33
34pub struct IdentifiedElement(pub(crate) ElementId);
35pub struct AnonymousElement;
36
37impl ElementIdentity for IdentifiedElement {
38 fn id(&self) -> Option<ElementId> {
39 Some(self.0.clone())
40 }
41}
42
43impl ElementIdentity for AnonymousElement {
44 fn id(&self) -> Option<ElementId> {
45 None
46 }
47}
48
49pub trait ParentElement: Element {
50 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
51
52 fn child(mut self, child: impl IntoAnyElement<Self::ViewState>) -> Self
53 where
54 Self: Sized,
55 {
56 self.children_mut().push(child.into_any());
57 self
58 }
59
60 fn children(
61 mut self,
62 iter: impl IntoIterator<Item = impl IntoAnyElement<Self::ViewState>>,
63 ) -> Self
64 where
65 Self: Sized,
66 {
67 self.children_mut()
68 .extend(iter.into_iter().map(|item| item.into_any()));
69 self
70 }
71}
72
73trait ElementObject<S>: 'static + Send + Sync {
74 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
75 fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
76}
77
78struct RenderedElement<E: Element> {
79 element: E,
80 phase: ElementRenderPhase<E::ElementState>,
81}
82
83#[derive(Default)]
84enum ElementRenderPhase<S> {
85 #[default]
86 Rendered,
87 LayoutRequested {
88 layout_id: LayoutId,
89 frame_state: Option<S>,
90 },
91 Painted {
92 bounds: Bounds<Pixels>,
93 frame_state: Option<S>,
94 },
95}
96
97/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
98/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
99/// improved usability.
100impl<E: Element> RenderedElement<E> {
101 fn new(element: E) -> Self {
102 RenderedElement {
103 element,
104 phase: ElementRenderPhase::Rendered,
105 }
106 }
107
108 fn paint_with_element_state(
109 &mut self,
110 bounds: Bounds<Pixels>,
111 view_state: &mut E::ViewState,
112 frame_state: &mut Option<E::ElementState>,
113 cx: &mut ViewContext<E::ViewState>,
114 ) {
115 if let Some(id) = self.element.id() {
116 cx.with_element_state(id, |element_state, cx| {
117 let mut element_state = element_state.unwrap();
118 self.element
119 .paint(bounds, view_state, &mut element_state, cx);
120 ((), element_state)
121 });
122 } else {
123 self.element
124 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
125 }
126 }
127}
128
129impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
130where
131 E: Element<ElementState = S>,
132 S: 'static + Send + Sync,
133{
134 fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
135 let (layout_id, frame_state) = if let Some(id) = self.element.id() {
136 let layout_id = cx.with_element_state(id, |element_state, cx| {
137 self.element.layout(state, element_state, cx)
138 });
139 (layout_id, None)
140 } else {
141 let (layout_id, frame_state) = self.element.layout(state, None, cx);
142 (layout_id, Some(frame_state))
143 };
144
145 self.phase = ElementRenderPhase::LayoutRequested {
146 layout_id,
147 frame_state,
148 };
149
150 layout_id
151 }
152
153 fn paint(
154 &mut self,
155 view_state: &mut E::ViewState,
156 offset: Option<Point<Pixels>>,
157 cx: &mut ViewContext<E::ViewState>,
158 ) {
159 self.phase = match std::mem::take(&mut self.phase) {
160 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
161
162 ElementRenderPhase::LayoutRequested {
163 layout_id,
164 mut frame_state,
165 } => {
166 let mut bounds = cx.layout_bounds(layout_id);
167 offset.map(|offset| bounds.origin += offset);
168 self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
169 ElementRenderPhase::Painted {
170 bounds,
171 frame_state,
172 }
173 }
174
175 ElementRenderPhase::Painted {
176 bounds,
177 mut frame_state,
178 } => {
179 self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
180 ElementRenderPhase::Painted {
181 bounds,
182 frame_state,
183 }
184 }
185 };
186 }
187}
188
189pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
190
191impl<S: 'static + Send + Sync> AnyElement<S> {
192 pub fn new<E: Element<ViewState = S>>(element: E) -> Self {
193 AnyElement(Box::new(RenderedElement::new(element)))
194 }
195}
196
197impl<S: 'static + Send + Sync> AnyElement<S> {
198 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
199 self.0.layout(state, cx)
200 }
201
202 pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
203 self.0.paint(state, offset, cx)
204 }
205}
206
207pub trait IntoAnyElement<S> {
208 fn into_any(self) -> AnyElement<S>;
209}
210
211impl<S> IntoAnyElement<S> for AnyElement<S> {
212 fn into_any(self) -> AnyElement<S> {
213 self
214 }
215}