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