1use crate::{Bounds, Identified, LayoutId, Pixels, Point, Result, ViewContext};
2use derive_more::{Deref, DerefMut};
3pub(crate) use smallvec::SmallVec;
4use util::arc_cow::ArcCow;
5
6pub trait Element: 'static {
7 type State;
8 type FrameState;
9
10 fn element_id(&self) -> Option<ElementId> {
11 None
12 }
13
14 fn layout(
15 &mut self,
16 state: &mut Self::State,
17 cx: &mut ViewContext<Self::State>,
18 ) -> Result<(LayoutId, Self::FrameState)>;
19
20 fn paint(
21 &mut self,
22 bounds: Bounds<Pixels>,
23 state: &mut Self::State,
24 frame_state: &mut Self::FrameState,
25 cx: &mut ViewContext<Self::State>,
26 ) -> Result<()>;
27
28 fn id(self, id: ElementId) -> Identified<Self>
29 where
30 Self: Sized,
31 {
32 Identified { element: self, id }
33 }
34}
35
36pub trait StatefulElement: Element {
37 fn element_id(&self) -> ElementId {
38 Element::element_id(self).unwrap()
39 }
40}
41
42#[derive(Clone, Debug, Eq, PartialEq, Hash)]
43pub struct ElementId(ArcCow<'static, [u8]>);
44
45#[derive(Deref, DerefMut, Default, Clone, Debug)]
46pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
47
48pub trait ParentElement {
49 type State;
50
51 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]>;
52
53 fn child(mut self, child: impl IntoAnyElement<Self::State>) -> Self
54 where
55 Self: Sized,
56 {
57 self.children_mut().push(child.into_any());
58 self
59 }
60
61 fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<Self::State>>) -> Self
62 where
63 Self: Sized,
64 {
65 self.children_mut()
66 .extend(iter.into_iter().map(|item| item.into_any()));
67 self
68 }
69
70 // HACK: This is a temporary hack to get children working for the purposes
71 // of building UI on top of the current version of gpui2.
72 //
73 // We'll (hopefully) be moving away from this in the future.
74 fn children_any<I>(mut self, children: I) -> Self
75 where
76 I: IntoIterator<Item = AnyElement<Self::State>>,
77 Self: Sized,
78 {
79 self.children_mut().extend(children.into_iter());
80 self
81 }
82
83 // HACK: This is a temporary hack to get children working for the purposes
84 // of building UI on top of the current version of gpui2.
85 //
86 // We'll (hopefully) be moving away from this in the future.
87 fn child_any(mut self, children: AnyElement<Self::State>) -> Self
88 where
89 Self: Sized,
90 {
91 self.children_mut().push(children);
92 self
93 }
94}
95
96trait ElementObject<S> {
97 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
98 fn paint(
99 &mut self,
100 state: &mut S,
101 offset: Option<Point<Pixels>>,
102 cx: &mut ViewContext<S>,
103 ) -> Result<()>;
104}
105
106struct RenderedElement<E: Element> {
107 element: E,
108 phase: ElementRenderPhase<E::FrameState>,
109}
110
111#[derive(Default)]
112enum ElementRenderPhase<S> {
113 #[default]
114 Rendered,
115 LayoutRequested {
116 layout_id: LayoutId,
117 frame_state: S,
118 },
119 Painted {
120 bounds: Bounds<Pixels>,
121 frame_state: S,
122 },
123}
124
125/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
126/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
127/// improved usability.
128impl<E: Element> RenderedElement<E> {
129 fn new(element: E) -> Self {
130 RenderedElement {
131 element,
132 phase: ElementRenderPhase::Rendered,
133 }
134 }
135}
136
137impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
138 fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
139 let (layout_id, frame_state) = self.element.layout(state, cx)?;
140 self.phase = ElementRenderPhase::LayoutRequested {
141 layout_id,
142 frame_state,
143 };
144 Ok(layout_id)
145 }
146
147 fn paint(
148 &mut self,
149 state: &mut E::State,
150 offset: Option<Point<Pixels>>,
151 cx: &mut ViewContext<E::State>,
152 ) -> Result<()> {
153 self.phase = match std::mem::take(&mut self.phase) {
154 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
155
156 ElementRenderPhase::LayoutRequested {
157 layout_id,
158 mut frame_state,
159 } => {
160 let mut bounds = cx.layout_bounds(layout_id)?.clone();
161 offset.map(|offset| bounds.origin += offset);
162 self.element.paint(bounds, state, &mut frame_state, cx)?;
163 ElementRenderPhase::Painted {
164 bounds,
165 frame_state,
166 }
167 }
168
169 ElementRenderPhase::Painted {
170 bounds,
171 mut frame_state,
172 } => {
173 self.element
174 .paint(bounds.clone(), state, &mut frame_state, cx)?;
175 ElementRenderPhase::Painted {
176 bounds,
177 frame_state,
178 }
179 }
180 };
181
182 Ok(())
183 }
184}
185
186pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
187
188impl<S> AnyElement<S> {
189 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
190 self.0.layout(state, cx)
191 }
192
193 pub fn paint(
194 &mut self,
195 state: &mut S,
196 offset: Option<Point<Pixels>>,
197 cx: &mut ViewContext<S>,
198 ) -> Result<()> {
199 self.0.paint(state, offset, cx)
200 }
201}
202
203pub trait IntoAnyElement<S> {
204 fn into_any(self) -> AnyElement<S>;
205}
206
207impl<E: Element> IntoAnyElement<E::State> for E {
208 fn into_any(self) -> AnyElement<E::State> {
209 AnyElement(Box::new(RenderedElement::new(self)))
210 }
211}
212
213impl<S> IntoAnyElement<S> for AnyElement<S> {
214 fn into_any(self) -> AnyElement<S> {
215 self
216 }
217}