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