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