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