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 // HACK: This is a temporary hack to get children working for the purposes
48 // of building UI on top of the current version of gpui2.
49 //
50 // We'll (hopefully) be moving away from this in the future.
51 fn children_any<I>(mut self, children: I) -> Self
52 where
53 I: IntoIterator<Item = AnyElement<Self::State>>,
54 Self: Sized,
55 {
56 self.children_mut().extend(children.into_iter());
57 self
58 }
59
60 // HACK: This is a temporary hack to get children working for the purposes
61 // of building UI on top of the current version of gpui2.
62 //
63 // We'll (hopefully) be moving away from this in the future.
64 fn child_any(mut self, children: AnyElement<Self::State>) -> Self
65 where
66 Self: Sized,
67 {
68 self.children_mut().push(children);
69 self
70 }
71}
72
73trait ElementObject<S> {
74 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
75 fn paint(
76 &mut self,
77 state: &mut S,
78 offset: Option<Point<Pixels>>,
79 cx: &mut ViewContext<S>,
80 ) -> Result<()>;
81}
82
83struct RenderedElement<E: Element> {
84 element: E,
85 phase: ElementRenderPhase<E::FrameState>,
86}
87
88#[derive(Default)]
89enum ElementRenderPhase<S> {
90 #[default]
91 Rendered,
92 LayoutRequested {
93 layout_id: LayoutId,
94 frame_state: S,
95 },
96 Painted {
97 bounds: Bounds<Pixels>,
98 frame_state: S,
99 },
100}
101
102/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
103/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
104/// improved usability.
105impl<E: Element> RenderedElement<E> {
106 fn new(element: E) -> Self {
107 RenderedElement {
108 element,
109 phase: ElementRenderPhase::Rendered,
110 }
111 }
112}
113
114impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
115 fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
116 let (layout_id, frame_state) = self.element.layout(state, cx)?;
117 self.phase = ElementRenderPhase::LayoutRequested {
118 layout_id,
119 frame_state,
120 };
121 Ok(layout_id)
122 }
123
124 fn paint(
125 &mut self,
126 state: &mut E::State,
127 offset: Option<Point<Pixels>>,
128 cx: &mut ViewContext<E::State>,
129 ) -> Result<()> {
130 self.phase = match std::mem::take(&mut self.phase) {
131 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
132
133 ElementRenderPhase::LayoutRequested {
134 layout_id,
135 mut frame_state,
136 } => {
137 let mut bounds = cx.layout_bounds(layout_id)?.clone();
138 offset.map(|offset| bounds.origin += offset);
139 self.element.paint(bounds, state, &mut frame_state, cx)?;
140 ElementRenderPhase::Painted {
141 bounds,
142 frame_state,
143 }
144 }
145
146 ElementRenderPhase::Painted {
147 bounds,
148 mut frame_state,
149 } => {
150 self.element
151 .paint(bounds.clone(), state, &mut frame_state, cx)?;
152 ElementRenderPhase::Painted {
153 bounds,
154 frame_state,
155 }
156 }
157 };
158
159 Ok(())
160 }
161}
162
163pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
164
165impl<S> AnyElement<S> {
166 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
167 self.0.layout(state, cx)
168 }
169
170 pub fn paint(
171 &mut self,
172 state: &mut S,
173 offset: Option<Point<Pixels>>,
174 cx: &mut ViewContext<S>,
175 ) -> Result<()> {
176 self.0.paint(state, offset, cx)
177 }
178}
179
180pub trait IntoAnyElement<S> {
181 fn into_any(self) -> AnyElement<S>;
182}
183
184impl<E: Element> IntoAnyElement<E::State> for E {
185 fn into_any(self) -> AnyElement<E::State> {
186 AnyElement(Box::new(RenderedElement::new(self)))
187 }
188}
189
190impl<S> IntoAnyElement<S> for AnyElement<S> {
191 fn into_any(self) -> AnyElement<S> {
192 self
193 }
194}