1use crate::{
2 AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
3};
4use derive_more::{Deref, DerefMut};
5pub(crate) use smallvec::SmallVec;
6use std::{any::Any, mem};
7
8pub trait Element<V: 'static> {
9 type ElementState: 'static;
10
11 fn id(&self) -> Option<ElementId>;
12
13 /// Called to initialize this element for the current frame. If this
14 /// element had state in a previous frame, it will be passed in for the 3rd argument.
15 fn initialize(
16 &mut self,
17 view_state: &mut V,
18 element_state: Option<Self::ElementState>,
19 cx: &mut ViewContext<V>,
20 ) -> Self::ElementState;
21
22 fn layout(
23 &mut self,
24 view_state: &mut V,
25 element_state: &mut Self::ElementState,
26 cx: &mut ViewContext<V>,
27 ) -> LayoutId;
28
29 fn paint(
30 &mut self,
31 bounds: Bounds<Pixels>,
32 view_state: &mut V,
33 element_state: &mut Self::ElementState,
34 cx: &mut ViewContext<V>,
35 );
36}
37
38#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
39pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
40
41pub trait ParentElement<V: 'static> {
42 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
43
44 fn child(mut self, child: impl Component<V>) -> Self
45 where
46 Self: Sized,
47 {
48 self.children_mut().push(child.render());
49 self
50 }
51
52 fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
53 where
54 Self: Sized,
55 {
56 self.children_mut()
57 .extend(iter.into_iter().map(|item| item.render()));
58 self
59 }
60}
61
62trait ElementObject<V> {
63 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
64 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
65 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
66}
67
68struct RenderedElement<V: 'static, E: Element<V>> {
69 element: E,
70 phase: ElementRenderPhase<E::ElementState>,
71}
72
73#[derive(Default)]
74enum ElementRenderPhase<V> {
75 #[default]
76 Start,
77 Initialized {
78 frame_state: Option<V>,
79 },
80 LayoutRequested {
81 layout_id: LayoutId,
82 frame_state: Option<V>,
83 },
84 Painted,
85}
86
87/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
88/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
89/// improved usability.
90impl<V, E: Element<V>> RenderedElement<V, E> {
91 fn new(element: E) -> Self {
92 RenderedElement {
93 element,
94 phase: ElementRenderPhase::Start,
95 }
96 }
97}
98
99impl<V, E> ElementObject<V> for RenderedElement<V, E>
100where
101 E: Element<V>,
102 E::ElementState: 'static,
103{
104 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
105 let frame_state = if let Some(id) = self.element.id() {
106 cx.with_element_state(id, |element_state, cx| {
107 let element_state = self.element.initialize(view_state, element_state, cx);
108 ((), element_state)
109 });
110 None
111 } else {
112 let frame_state = self.element.initialize(view_state, None, cx);
113 Some(frame_state)
114 };
115
116 self.phase = ElementRenderPhase::Initialized { frame_state };
117 }
118
119 fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
120 let layout_id;
121 let mut frame_state;
122 match mem::take(&mut self.phase) {
123 ElementRenderPhase::Initialized {
124 frame_state: initial_frame_state,
125 } => {
126 frame_state = initial_frame_state;
127 if let Some(id) = self.element.id() {
128 layout_id = cx.with_element_state(id, |element_state, cx| {
129 let mut element_state = element_state.unwrap();
130 let layout_id = self.element.layout(state, &mut element_state, cx);
131 (layout_id, element_state)
132 });
133 } else {
134 layout_id = self
135 .element
136 .layout(state, frame_state.as_mut().unwrap(), cx);
137 }
138 }
139 ElementRenderPhase::Start => panic!("must call initialize before layout"),
140 ElementRenderPhase::LayoutRequested { .. } | ElementRenderPhase::Painted => {
141 panic!("element rendered twice")
142 }
143 };
144
145 self.phase = ElementRenderPhase::LayoutRequested {
146 layout_id,
147 frame_state,
148 };
149 layout_id
150 }
151
152 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
153 self.phase = match mem::take(&mut self.phase) {
154 ElementRenderPhase::LayoutRequested {
155 layout_id,
156 mut frame_state,
157 } => {
158 let bounds = cx.layout_bounds(layout_id);
159 if let Some(id) = self.element.id() {
160 cx.with_element_state(id, |element_state, cx| {
161 let mut element_state = element_state.unwrap();
162 self.element
163 .paint(bounds, view_state, &mut element_state, cx);
164 ((), element_state)
165 });
166 } else {
167 self.element
168 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
169 }
170 ElementRenderPhase::Painted
171 }
172
173 _ => panic!("must call layout before paint"),
174 };
175 }
176}
177
178pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
179
180impl<V> AnyElement<V> {
181 pub fn new<E>(element: E) -> Self
182 where
183 V: 'static,
184 E: 'static + Element<V>,
185 E::ElementState: Any,
186 {
187 AnyElement(Box::new(RenderedElement::new(element)))
188 }
189
190 pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
191 self.0.initialize(view_state, cx);
192 }
193
194 pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
195 self.0.layout(view_state, cx)
196 }
197
198 pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
199 self.0.paint(view_state, cx)
200 }
201
202 /// Initializes this element and performs layout within the given available space to determine its size.
203 pub fn measure(
204 &mut self,
205 available_space: Size<AvailableSpace>,
206 view_state: &mut V,
207 cx: &mut ViewContext<V>,
208 ) -> Size<Pixels> {
209 self.initialize(view_state, cx);
210 let layout_id = self.layout(view_state, cx);
211 cx.compute_layout(layout_id, available_space);
212 cx.layout_bounds(layout_id).size
213 }
214
215 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
216 pub fn draw(
217 &mut self,
218 origin: Point<Pixels>,
219 available_space: Size<AvailableSpace>,
220 view_state: &mut V,
221 cx: &mut ViewContext<V>,
222 ) {
223 self.initialize(view_state, cx);
224 let layout_id = self.layout(view_state, cx);
225 cx.compute_layout(layout_id, available_space);
226 cx.with_element_offset(Some(origin), |cx| self.paint(view_state, cx))
227 }
228}
229
230pub trait Component<V> {
231 fn render(self) -> AnyElement<V>;
232
233 fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
234 where
235 Self: Sized,
236 U: Component<V>,
237 {
238 f(self)
239 }
240
241 fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
242 where
243 Self: Sized,
244 {
245 self.map(|this| if condition { then(this) } else { this })
246 }
247
248 fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
249 where
250 Self: Sized,
251 {
252 self.map(|this| {
253 if let Some(value) = option {
254 then(this, value)
255 } else {
256 this
257 }
258 })
259 }
260}
261
262impl<V> Component<V> for AnyElement<V> {
263 fn render(self) -> AnyElement<V> {
264 self
265 }
266}
267
268impl<V, E, F> Element<V> for Option<F>
269where
270 V: 'static,
271 E: 'static + Component<V>,
272 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
273{
274 type ElementState = AnyElement<V>;
275
276 fn id(&self) -> Option<ElementId> {
277 None
278 }
279
280 fn initialize(
281 &mut self,
282 view_state: &mut V,
283 _rendered_element: Option<Self::ElementState>,
284 cx: &mut ViewContext<V>,
285 ) -> Self::ElementState {
286 let render = self.take().unwrap();
287 let mut rendered_element = (render)(view_state, cx).render();
288 rendered_element.initialize(view_state, cx);
289 rendered_element
290 }
291
292 fn layout(
293 &mut self,
294 view_state: &mut V,
295 rendered_element: &mut Self::ElementState,
296 cx: &mut ViewContext<V>,
297 ) -> LayoutId {
298 rendered_element.layout(view_state, cx)
299 }
300
301 fn paint(
302 &mut self,
303 _bounds: Bounds<Pixels>,
304 view_state: &mut V,
305 rendered_element: &mut Self::ElementState,
306 cx: &mut ViewContext<V>,
307 ) {
308 rendered_element.paint(view_state, cx)
309 }
310}
311
312impl<V, E, F> Component<V> for Option<F>
313where
314 V: 'static,
315 E: 'static + Component<V>,
316 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
317{
318 fn render(self) -> AnyElement<V> {
319 AnyElement::new(self)
320 }
321}
322
323impl<V, E, F> Component<V> for F
324where
325 V: 'static,
326 E: 'static + Component<V>,
327 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
328{
329 fn render(self) -> AnyElement<V> {
330 AnyElement::new(Some(self))
331 }
332}