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 element_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 ParentComponent<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 element_id(&self) -> Option<ElementId>;
64 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
65 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
66 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
67 fn measure(
68 &mut self,
69 available_space: Size<AvailableSpace>,
70 view_state: &mut V,
71 cx: &mut ViewContext<V>,
72 ) -> Size<Pixels>;
73 fn draw(
74 &mut self,
75 origin: Point<Pixels>,
76 available_space: Size<AvailableSpace>,
77 view_state: &mut V,
78 cx: &mut ViewContext<V>,
79 );
80}
81
82struct RenderedElement<V: 'static, E: Element<V>> {
83 element: E,
84 phase: ElementRenderPhase<E::ElementState>,
85}
86
87#[derive(Default)]
88enum ElementRenderPhase<V> {
89 #[default]
90 Start,
91 Initialized {
92 frame_state: Option<V>,
93 },
94 LayoutRequested {
95 layout_id: LayoutId,
96 frame_state: Option<V>,
97 },
98 LayoutComputed {
99 layout_id: LayoutId,
100 available_space: Size<AvailableSpace>,
101 frame_state: Option<V>,
102 },
103 Painted,
104}
105
106/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
107/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
108/// improved usability.
109impl<V, E: Element<V>> RenderedElement<V, E> {
110 fn new(element: E) -> Self {
111 RenderedElement {
112 element,
113 phase: ElementRenderPhase::Start,
114 }
115 }
116}
117
118impl<V, E> ElementObject<V> for RenderedElement<V, E>
119where
120 E: Element<V>,
121 E::ElementState: 'static,
122{
123 fn element_id(&self) -> Option<ElementId> {
124 self.element.element_id()
125 }
126
127 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
128 let frame_state = if let Some(id) = self.element.element_id() {
129 cx.with_element_state(id, |element_state, cx| {
130 let element_state = self.element.initialize(view_state, element_state, cx);
131 ((), element_state)
132 });
133 None
134 } else {
135 let frame_state = self.element.initialize(view_state, None, cx);
136 Some(frame_state)
137 };
138
139 self.phase = ElementRenderPhase::Initialized { frame_state };
140 }
141
142 fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
143 let layout_id;
144 let mut frame_state;
145 match mem::take(&mut self.phase) {
146 ElementRenderPhase::Initialized {
147 frame_state: initial_frame_state,
148 } => {
149 frame_state = initial_frame_state;
150 if let Some(id) = self.element.element_id() {
151 layout_id = cx.with_element_state(id, |element_state, cx| {
152 let mut element_state = element_state.unwrap();
153 let layout_id = self.element.layout(state, &mut element_state, cx);
154 (layout_id, element_state)
155 });
156 } else {
157 layout_id = self
158 .element
159 .layout(state, frame_state.as_mut().unwrap(), cx);
160 }
161 }
162 ElementRenderPhase::Start => panic!("must call initialize before layout"),
163 ElementRenderPhase::LayoutRequested { .. }
164 | ElementRenderPhase::LayoutComputed { .. }
165 | ElementRenderPhase::Painted => {
166 panic!("element rendered twice")
167 }
168 };
169
170 self.phase = ElementRenderPhase::LayoutRequested {
171 layout_id,
172 frame_state,
173 };
174 layout_id
175 }
176
177 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
178 self.phase = match mem::take(&mut self.phase) {
179 ElementRenderPhase::LayoutRequested {
180 layout_id,
181 mut frame_state,
182 }
183 | ElementRenderPhase::LayoutComputed {
184 layout_id,
185 mut frame_state,
186 ..
187 } => {
188 let bounds = cx.layout_bounds(layout_id);
189 if let Some(id) = self.element.element_id() {
190 cx.with_element_state(id, |element_state, cx| {
191 let mut element_state = element_state.unwrap();
192 self.element
193 .paint(bounds, view_state, &mut element_state, cx);
194 ((), element_state)
195 });
196 } else {
197 self.element
198 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
199 }
200 ElementRenderPhase::Painted
201 }
202
203 _ => panic!("must call layout before paint"),
204 };
205 }
206
207 fn measure(
208 &mut self,
209 available_space: Size<AvailableSpace>,
210 view_state: &mut V,
211 cx: &mut ViewContext<V>,
212 ) -> Size<Pixels> {
213 if matches!(&self.phase, ElementRenderPhase::Start) {
214 self.initialize(view_state, cx);
215 }
216
217 if matches!(&self.phase, ElementRenderPhase::Initialized { .. }) {
218 self.layout(view_state, cx);
219 }
220
221 let layout_id = match &mut self.phase {
222 ElementRenderPhase::LayoutRequested {
223 layout_id,
224 frame_state,
225 } => {
226 cx.compute_layout(*layout_id, available_space);
227 let layout_id = *layout_id;
228 self.phase = ElementRenderPhase::LayoutComputed {
229 layout_id,
230 available_space,
231 frame_state: frame_state.take(),
232 };
233 layout_id
234 }
235 ElementRenderPhase::LayoutComputed {
236 layout_id,
237 available_space: prev_available_space,
238 ..
239 } => {
240 if available_space != *prev_available_space {
241 cx.compute_layout(*layout_id, available_space);
242 *prev_available_space = available_space;
243 }
244 *layout_id
245 }
246 _ => panic!("cannot measure after painting"),
247 };
248
249 cx.layout_bounds(layout_id).size
250 }
251
252 fn draw(
253 &mut self,
254 mut origin: Point<Pixels>,
255 available_space: Size<AvailableSpace>,
256 view_state: &mut V,
257 cx: &mut ViewContext<V>,
258 ) {
259 self.measure(available_space, view_state, cx);
260 // Ignore the element offset when drawing this element, as the origin is already specified
261 // in absolute terms.
262 origin -= cx.element_offset();
263 cx.with_element_offset(origin, |cx| self.paint(view_state, cx))
264 }
265}
266
267pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
268
269impl<V> AnyElement<V> {
270 pub fn new<E>(element: E) -> Self
271 where
272 V: 'static,
273 E: 'static + Element<V>,
274 E::ElementState: Any,
275 {
276 AnyElement(Box::new(RenderedElement::new(element)))
277 }
278
279 pub fn element_id(&self) -> Option<ElementId> {
280 self.0.element_id()
281 }
282
283 pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
284 self.0.initialize(view_state, cx);
285 }
286
287 pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
288 self.0.layout(view_state, cx)
289 }
290
291 pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
292 self.0.paint(view_state, cx)
293 }
294
295 /// Initializes this element and performs layout within the given available space to determine its size.
296 pub fn measure(
297 &mut self,
298 available_space: Size<AvailableSpace>,
299 view_state: &mut V,
300 cx: &mut ViewContext<V>,
301 ) -> Size<Pixels> {
302 self.0.measure(available_space, view_state, cx)
303 }
304
305 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
306 pub fn draw(
307 &mut self,
308 origin: Point<Pixels>,
309 available_space: Size<AvailableSpace>,
310 view_state: &mut V,
311 cx: &mut ViewContext<V>,
312 ) {
313 self.0.draw(origin, available_space, view_state, cx)
314 }
315}
316
317pub trait Component<V> {
318 fn render(self) -> AnyElement<V>;
319
320 fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
321 where
322 Self: Sized,
323 U: Component<V>,
324 {
325 f(self)
326 }
327
328 fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
329 where
330 Self: Sized,
331 {
332 self.map(|this| if condition { then(this) } else { this })
333 }
334
335 fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
336 where
337 Self: Sized,
338 {
339 self.map(|this| {
340 if let Some(value) = option {
341 then(this, value)
342 } else {
343 this
344 }
345 })
346 }
347}
348
349impl<V> Component<V> for AnyElement<V> {
350 fn render(self) -> AnyElement<V> {
351 self
352 }
353}
354
355impl<V, E, F> Element<V> for Option<F>
356where
357 V: 'static,
358 E: 'static + Component<V>,
359 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
360{
361 type ElementState = AnyElement<V>;
362
363 fn element_id(&self) -> Option<ElementId> {
364 None
365 }
366
367 fn initialize(
368 &mut self,
369 view_state: &mut V,
370 _rendered_element: Option<Self::ElementState>,
371 cx: &mut ViewContext<V>,
372 ) -> Self::ElementState {
373 let render = self.take().unwrap();
374 let mut rendered_element = (render)(view_state, cx).render();
375 rendered_element.initialize(view_state, cx);
376 rendered_element
377 }
378
379 fn layout(
380 &mut self,
381 view_state: &mut V,
382 rendered_element: &mut Self::ElementState,
383 cx: &mut ViewContext<V>,
384 ) -> LayoutId {
385 rendered_element.layout(view_state, cx)
386 }
387
388 fn paint(
389 &mut self,
390 _bounds: Bounds<Pixels>,
391 view_state: &mut V,
392 rendered_element: &mut Self::ElementState,
393 cx: &mut ViewContext<V>,
394 ) {
395 rendered_element.paint(view_state, cx)
396 }
397}
398
399impl<V, E, F> Component<V> for Option<F>
400where
401 V: 'static,
402 E: 'static + Component<V>,
403 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
404{
405 fn render(self) -> AnyElement<V> {
406 AnyElement::new(self)
407 }
408}
409
410impl<V, E, F> Component<V> for F
411where
412 V: 'static,
413 E: 'static + Component<V>,
414 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
415{
416 fn render(self) -> AnyElement<V> {
417 AnyElement::new(Some(self))
418 }
419}