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, fmt::Debug};
7
8pub trait Element<V: 'static>: 'static + Sized {
9 type State: 'static;
10
11 fn element_id(&self) -> Option<ElementId>;
12
13 fn layout(
14 &mut self,
15 view_state: &mut V,
16 element_state: Option<Self::State>,
17 cx: &mut ViewContext<V>,
18 ) -> (LayoutId, Self::State);
19
20 fn paint(
21 self,
22 bounds: Bounds<Pixels>,
23 view_state: &mut V,
24 element_state: &mut Self::State,
25 cx: &mut ViewContext<V>,
26 );
27
28 fn into_any(self) -> AnyElement<V> {
29 AnyElement::new(self)
30 }
31
32 fn draw<T, R>(
33 self,
34 origin: Point<Pixels>,
35 available_space: Size<T>,
36 view_state: &mut V,
37 cx: &mut ViewContext<V>,
38 f: impl FnOnce(&mut Self::State, &mut ViewContext<V>) -> R,
39 ) -> R
40 where
41 T: Clone + Default + Debug + Into<AvailableSpace>,
42 {
43 let element_id = self.element_id();
44 let element = DrawableElement {
45 element: Some(self),
46 phase: ElementDrawPhase::Start,
47 };
48 let frame_state = element.draw(origin, available_space.map(Into::into), view_state, cx);
49
50 if let Some(mut frame_state) = frame_state {
51 f(&mut frame_state, cx)
52 } else {
53 cx.with_element_state(element_id.unwrap(), |element_state, cx| {
54 let mut element_state = element_state.unwrap();
55 let result = f(&mut element_state, cx);
56 (result, element_state)
57 })
58 }
59 }
60}
61
62#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
63pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
64
65pub trait ParentComponent<V: 'static> {
66 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
67
68 fn child(mut self, child: impl Element<V>) -> Self
69 where
70 Self: Sized,
71 {
72 self.children_mut().push(child.into_any());
73 self
74 }
75
76 fn children(mut self, children: impl IntoIterator<Item = impl Element<V>>) -> Self
77 where
78 Self: Sized,
79 {
80 self.children_mut()
81 .extend(children.into_iter().map(Element::into_any));
82 self
83 }
84}
85
86trait ElementObject<V> {
87 fn element_id(&self) -> Option<ElementId>;
88 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
89 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
90 fn measure(
91 &mut self,
92 available_space: Size<AvailableSpace>,
93 view_state: &mut V,
94 cx: &mut ViewContext<V>,
95 ) -> Size<Pixels>;
96 fn draw(
97 &mut self,
98 origin: Point<Pixels>,
99 available_space: Size<AvailableSpace>,
100 view_state: &mut V,
101 cx: &mut ViewContext<V>,
102 );
103}
104
105pub struct DrawableElement<V: 'static, E: Element<V>> {
106 element: Option<E>,
107 phase: ElementDrawPhase<E::State>,
108}
109
110#[derive(Default)]
111enum ElementDrawPhase<V> {
112 #[default]
113 Start,
114 LayoutRequested {
115 layout_id: LayoutId,
116 frame_state: Option<V>,
117 },
118 LayoutComputed {
119 layout_id: LayoutId,
120 available_space: Size<AvailableSpace>,
121 frame_state: Option<V>,
122 },
123}
124
125/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
126/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
127/// improved usability.
128impl<V, E: Element<V>> DrawableElement<V, E> {
129 fn new(element: E) -> Self {
130 DrawableElement {
131 element: Some(element),
132 phase: ElementDrawPhase::Start,
133 }
134 }
135
136 fn element_id(&self) -> Option<ElementId> {
137 self.element.as_ref()?.element_id()
138 }
139
140 fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
141 let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
142 {
143 let layout_id = cx.with_element_state(id, |element_state, cx| {
144 self.element
145 .as_mut()
146 .unwrap()
147 .layout(state, element_state, cx)
148 });
149 (layout_id, None)
150 } else {
151 let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(state, None, cx);
152 (layout_id, Some(frame_state))
153 };
154
155 self.phase = ElementDrawPhase::LayoutRequested {
156 layout_id,
157 frame_state,
158 };
159 layout_id
160 }
161
162 fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> Option<E::State> {
163 match self.phase {
164 ElementDrawPhase::LayoutRequested {
165 layout_id,
166 frame_state,
167 }
168 | ElementDrawPhase::LayoutComputed {
169 layout_id,
170 frame_state,
171 ..
172 } => {
173 let bounds = cx.layout_bounds(layout_id);
174
175 if let Some(mut frame_state) = frame_state {
176 self.element
177 .take()
178 .unwrap()
179 .paint(bounds, view_state, &mut frame_state, cx);
180 Some(frame_state)
181 } else {
182 let element_id = self
183 .element
184 .as_ref()
185 .unwrap()
186 .element_id()
187 .expect("if we don't have frame state, we should have element state");
188 cx.with_element_state(element_id, |element_state, cx| {
189 let mut element_state = element_state.unwrap();
190 self.element.take().unwrap().paint(
191 bounds,
192 view_state,
193 &mut element_state,
194 cx,
195 );
196 ((), element_state)
197 });
198 None
199 }
200 }
201
202 _ => panic!("must call layout before paint"),
203 }
204 }
205
206 fn measure(
207 &mut self,
208 available_space: Size<AvailableSpace>,
209 view_state: &mut V,
210 cx: &mut ViewContext<V>,
211 ) -> Size<Pixels> {
212 if matches!(&self.phase, ElementDrawPhase::Start) {
213 self.layout(view_state, cx);
214 }
215
216 let layout_id = match &mut self.phase {
217 ElementDrawPhase::LayoutRequested {
218 layout_id,
219 frame_state,
220 } => {
221 cx.compute_layout(*layout_id, available_space);
222 let layout_id = *layout_id;
223 self.phase = ElementDrawPhase::LayoutComputed {
224 layout_id,
225 available_space,
226 frame_state: frame_state.take(),
227 };
228 layout_id
229 }
230 ElementDrawPhase::LayoutComputed {
231 layout_id,
232 available_space: prev_available_space,
233 ..
234 } => {
235 if available_space != *prev_available_space {
236 cx.compute_layout(*layout_id, available_space);
237 *prev_available_space = available_space;
238 }
239 *layout_id
240 }
241 _ => panic!("cannot measure after painting"),
242 };
243
244 cx.layout_bounds(layout_id).size
245 }
246
247 fn draw(
248 mut self,
249 origin: Point<Pixels>,
250 available_space: Size<AvailableSpace>,
251 view_state: &mut V,
252 cx: &mut ViewContext<V>,
253 ) -> Option<E::State> {
254 self.measure(available_space, view_state, cx);
255 cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
256 }
257}
258
259impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>>
260where
261 E: Element<V>,
262 E::State: 'static,
263{
264 fn element_id(&self) -> Option<ElementId> {
265 self.as_ref().unwrap().element_id()
266 }
267
268 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
269 DrawableElement::layout(self.as_mut().unwrap(), view_state, cx)
270 }
271
272 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
273 DrawableElement::paint(self.take().unwrap(), view_state, cx);
274 }
275
276 fn measure(
277 &mut self,
278 available_space: Size<AvailableSpace>,
279 view_state: &mut V,
280 cx: &mut ViewContext<V>,
281 ) -> Size<Pixels> {
282 DrawableElement::measure(self.as_mut().unwrap(), available_space, view_state, cx)
283 }
284
285 fn draw(
286 &mut self,
287 origin: Point<Pixels>,
288 available_space: Size<AvailableSpace>,
289 view_state: &mut V,
290 cx: &mut ViewContext<V>,
291 ) {
292 DrawableElement::draw(
293 self.take().unwrap(),
294 origin,
295 available_space,
296 view_state,
297 cx,
298 );
299 }
300}
301
302pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
303
304impl<V> AnyElement<V> {
305 pub fn new<E>(element: E) -> Self
306 where
307 V: 'static,
308 E: 'static + Element<V>,
309 E::State: Any,
310 {
311 AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject<V>>)
312 }
313
314 pub fn element_id(&self) -> Option<ElementId> {
315 self.0.element_id()
316 }
317
318 pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
319 self.0.layout(view_state, cx)
320 }
321
322 pub fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
323 self.0.paint(view_state, cx)
324 }
325
326 /// Initializes this element and performs layout within the given available space to determine its size.
327 pub fn measure(
328 &mut self,
329 available_space: Size<AvailableSpace>,
330 view_state: &mut V,
331 cx: &mut ViewContext<V>,
332 ) -> Size<Pixels> {
333 self.0.measure(available_space, view_state, cx)
334 }
335
336 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
337 pub fn draw(
338 mut self,
339 origin: Point<Pixels>,
340 available_space: Size<AvailableSpace>,
341 view_state: &mut V,
342 cx: &mut ViewContext<V>,
343 ) {
344 self.0.draw(origin, available_space, view_state, cx)
345 }
346}
347
348impl<V: 'static> Element<V> for AnyElement<V> {
349 type State = ();
350
351 fn element_id(&self) -> Option<ElementId> {
352 AnyElement::element_id(self)
353 }
354
355 fn layout(
356 &mut self,
357 view_state: &mut V,
358 _: Option<Self::State>,
359 cx: &mut ViewContext<V>,
360 ) -> (LayoutId, Self::State) {
361 let layout_id = self.layout(view_state, cx);
362 (layout_id, ())
363 }
364
365 fn paint(
366 self,
367 _bounds: Bounds<Pixels>,
368 view_state: &mut V,
369 _: &mut Self::State,
370 cx: &mut ViewContext<V>,
371 ) {
372 self.paint(view_state, cx);
373 }
374}
375
376pub trait Component<V> {
377 fn render(self) -> AnyElement<V>;
378
379 fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
380 where
381 Self: Sized,
382 U: Component<V>,
383 {
384 f(self)
385 }
386
387 fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
388 where
389 Self: Sized,
390 {
391 self.map(|this| if condition { then(this) } else { this })
392 }
393
394 fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
395 where
396 Self: Sized,
397 {
398 self.map(|this| {
399 if let Some(value) = option {
400 then(this, value)
401 } else {
402 this
403 }
404 })
405 }
406}
407
408impl<V> Component<V> for AnyElement<V> {
409 fn render(self) -> AnyElement<V> {
410 self
411 }
412}
413
414impl<V, E, F> Element<V> for Option<F>
415where
416 V: 'static,
417 E: 'static + Component<V>,
418 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
419{
420 type State = Option<AnyElement<V>>;
421
422 fn element_id(&self) -> Option<ElementId> {
423 None
424 }
425
426 fn layout(
427 &mut self,
428 view_state: &mut V,
429 _: Option<Self::State>,
430 cx: &mut ViewContext<V>,
431 ) -> (LayoutId, Self::State) {
432 let render = self.take().unwrap();
433 let mut rendered_element = (render)(view_state, cx).render();
434 let layout_id = rendered_element.layout(view_state, cx);
435 (layout_id, Some(rendered_element))
436 }
437
438 fn paint(
439 self,
440 _bounds: Bounds<Pixels>,
441 view_state: &mut V,
442 rendered_element: &mut Self::State,
443 cx: &mut ViewContext<V>,
444 ) {
445 rendered_element.take().unwrap().paint(view_state, cx);
446 }
447}
448
449impl<V, E, F> Component<V> for Option<F>
450where
451 V: 'static,
452 E: 'static + Component<V>,
453 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
454{
455 fn render(self) -> AnyElement<V> {
456 AnyElement::new(self)
457 }
458}
459
460impl<V, E, F> Component<V> for F
461where
462 V: 'static,
463 E: 'static + Component<V>,
464 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
465{
466 fn render(self) -> AnyElement<V> {
467 AnyElement::new(Some(self))
468 }
469}
470
471// impl<V, E, F> Element<V> for F
472// where
473// V: 'static,
474// E: 'static + Component<V>,
475// F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
476// {
477// type State = Option<AnyElement<V>>;
478
479// fn element_id(&self) -> Option<ElementId> {
480// None
481// }
482
483// fn layout(
484// &mut self,
485// view_state: &mut V,
486// element_state: Option<Self::State>,
487// cx: &mut ViewContext<V>,
488// ) -> (LayoutId, Self::State) {
489
490// self(view_state)
491
492// }
493
494// fn paint(
495// self,
496// bounds: Bounds<Pixels>,
497// view_state: &mut V,
498// element_state: &mut Self::State,
499// cx: &mut ViewContext<V>,
500// ) {
501// todo!()
502// }
503// }