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