1use crate::Bounds;
2
3use super::{LayoutId, Pixels, Point, Result, ViewContext};
4pub(crate) use smallvec::SmallVec;
5
6pub trait Element: 'static {
7 type State;
8 type FrameState;
9
10 fn layout(
11 &mut self,
12 state: &mut Self::State,
13 cx: &mut ViewContext<Self::State>,
14 ) -> Result<(LayoutId, Self::FrameState)>;
15
16 fn paint(
17 &mut self,
18 bounds: Bounds<Pixels>,
19 state: &mut Self::State,
20 frame_state: &mut Self::FrameState,
21 cx: &mut ViewContext<Self::State>,
22 ) -> Result<()>;
23}
24
25pub trait ParentElement<S> {
26 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]>;
27
28 fn child(mut self, child: impl IntoAnyElement<S>) -> Self
29 where
30 Self: Sized,
31 {
32 self.children_mut().push(child.into_any());
33 self
34 }
35
36 fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<S>>) -> Self
37 where
38 Self: Sized,
39 {
40 self.children_mut()
41 .extend(iter.into_iter().map(|item| item.into_any()));
42 self
43 }
44}
45
46trait ElementObject<S> {
47 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
48 fn paint(
49 &mut self,
50 state: &mut S,
51 offset: Option<Point<Pixels>>,
52 cx: &mut ViewContext<S>,
53 ) -> Result<()>;
54}
55
56struct RenderedElement<E: Element> {
57 element: E,
58 phase: ElementRenderPhase<E::FrameState>,
59}
60
61#[derive(Default)]
62enum ElementRenderPhase<S> {
63 #[default]
64 Rendered,
65 LayoutRequested {
66 layout_id: LayoutId,
67 frame_state: S,
68 },
69 Painted {
70 bounds: Bounds<Pixels>,
71 frame_state: S,
72 },
73}
74
75/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
76/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
77/// improved usability.
78impl<E: Element> RenderedElement<E> {
79 fn new(element: E) -> Self {
80 RenderedElement {
81 element,
82 phase: ElementRenderPhase::Rendered,
83 }
84 }
85}
86
87impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
88 fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
89 let (layout_id, frame_state) = self.element.layout(state, cx)?;
90 self.phase = ElementRenderPhase::LayoutRequested {
91 layout_id,
92 frame_state,
93 };
94 Ok(layout_id)
95 }
96
97 fn paint(
98 &mut self,
99 state: &mut E::State,
100 offset: Option<Point<Pixels>>,
101 cx: &mut ViewContext<E::State>,
102 ) -> Result<()> {
103 self.phase = match std::mem::take(&mut self.phase) {
104 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
105
106 ElementRenderPhase::LayoutRequested {
107 layout_id,
108 mut frame_state,
109 } => {
110 let mut bounds = cx.layout_bounds(layout_id)?.clone();
111 offset.map(|offset| bounds.origin += offset);
112 self.element.paint(bounds, state, &mut frame_state, cx)?;
113 ElementRenderPhase::Painted {
114 bounds,
115 frame_state,
116 }
117 }
118
119 ElementRenderPhase::Painted {
120 bounds,
121 mut frame_state,
122 } => {
123 self.element
124 .paint(bounds.clone(), state, &mut frame_state, cx)?;
125 ElementRenderPhase::Painted {
126 bounds,
127 frame_state,
128 }
129 }
130 };
131
132 Ok(())
133 }
134}
135
136pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
137
138impl<S> AnyElement<S> {
139 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
140 self.0.layout(state, cx)
141 }
142
143 pub fn paint(
144 &mut self,
145 state: &mut S,
146 offset: Option<Point<Pixels>>,
147 cx: &mut ViewContext<S>,
148 ) -> Result<()> {
149 self.0.paint(state, offset, cx)
150 }
151}
152
153pub trait IntoAnyElement<S> {
154 fn into_any(self) -> AnyElement<S>;
155}
156
157impl<E: Element> IntoAnyElement<E::State> for E {
158 fn into_any(self) -> AnyElement<E::State> {
159 AnyElement(Box::new(RenderedElement::new(self)))
160 }
161}
162
163impl<S> IntoAnyElement<S> for AnyElement<S> {
164 fn into_any(self) -> AnyElement<S> {
165 self
166 }
167}