1use crate::{
2 AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
3};
4use derive_more::{Deref, DerefMut};
5pub(crate) use smallvec::SmallVec;
6use std::{any::Any, mem};
7
8pub trait Element<V: 'static> {
9 type ElementState: 'static;
10
11 fn element_id(&self) -> Option<ElementId>;
12
13 /// Called to initialize this element for the current frame. If this
14 /// element had state in a previous frame, it will be passed in for the 3rd argument.
15 fn initialize(
16 &mut self,
17 view_state: &mut V,
18 element_state: Option<Self::ElementState>,
19 cx: &mut ViewContext<V>,
20 ) -> Self::ElementState;
21
22 fn layout(
23 &mut self,
24 view_state: &mut V,
25 element_state: &mut Self::ElementState,
26 cx: &mut ViewContext<V>,
27 ) -> LayoutId;
28
29 fn paint(
30 &mut self,
31 bounds: Bounds<Pixels>,
32 view_state: &mut V,
33 element_state: &mut Self::ElementState,
34 cx: &mut ViewContext<V>,
35 );
36}
37
38#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
39pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
40
41pub trait ParentComponent<V: 'static> {
42 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
43
44 fn child(mut self, child: impl Component<V>) -> Self
45 where
46 Self: Sized,
47 {
48 self.children_mut().push(child.render());
49 self
50 }
51
52 fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
53 where
54 Self: Sized,
55 {
56 self.children_mut()
57 .extend(iter.into_iter().map(|item| item.render()));
58 self
59 }
60}
61
62trait ElementObject<V> {
63 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
64 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
65 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
66 fn measure(
67 &mut self,
68 available_space: Size<AvailableSpace>,
69 view_state: &mut V,
70 cx: &mut ViewContext<V>,
71 ) -> Size<Pixels>;
72 fn draw(
73 &mut self,
74 origin: Point<Pixels>,
75 available_space: Size<AvailableSpace>,
76 view_state: &mut V,
77 cx: &mut ViewContext<V>,
78 );
79}
80
81struct RenderedElement<V: 'static, E: Element<V>> {
82 element: E,
83 phase: ElementRenderPhase<E::ElementState>,
84}
85
86#[derive(Default)]
87enum ElementRenderPhase<V> {
88 #[default]
89 Start,
90 Initialized {
91 frame_state: Option<V>,
92 },
93 LayoutRequested {
94 layout_id: LayoutId,
95 frame_state: Option<V>,
96 },
97 LayoutComputed {
98 layout_id: LayoutId,
99 available_space: Size<AvailableSpace>,
100 frame_state: Option<V>,
101 },
102 Painted,
103}
104
105/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
106/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
107/// improved usability.
108impl<V, E: Element<V>> RenderedElement<V, E> {
109 fn new(element: E) -> Self {
110 RenderedElement {
111 element,
112 phase: ElementRenderPhase::Start,
113 }
114 }
115}
116
117impl<V, E> ElementObject<V> for RenderedElement<V, E>
118where
119 E: Element<V>,
120 E::ElementState: 'static,
121{
122 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
123 let frame_state = if let Some(id) = self.element.element_id() {
124 cx.with_element_state(id, |element_state, cx| {
125 let element_state = self.element.initialize(view_state, element_state, cx);
126 ((), element_state)
127 });
128 None
129 } else {
130 let frame_state = self.element.initialize(view_state, None, cx);
131 Some(frame_state)
132 };
133
134 self.phase = ElementRenderPhase::Initialized { frame_state };
135 }
136
137 fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
138 let layout_id;
139 let mut frame_state;
140 match mem::take(&mut self.phase) {
141 ElementRenderPhase::Initialized {
142 frame_state: initial_frame_state,
143 } => {
144 frame_state = initial_frame_state;
145 if let Some(id) = self.element.element_id() {
146 layout_id = cx.with_element_state(id, |element_state, cx| {
147 let mut element_state = element_state.unwrap();
148 let layout_id = self.element.layout(state, &mut element_state, cx);
149 (layout_id, element_state)
150 });
151 } else {
152 layout_id = self
153 .element
154 .layout(state, frame_state.as_mut().unwrap(), cx);
155 }
156 }
157 ElementRenderPhase::Start => panic!("must call initialize before layout"),
158 ElementRenderPhase::LayoutRequested { .. }
159 | ElementRenderPhase::LayoutComputed { .. }
160 | ElementRenderPhase::Painted => {
161 panic!("element rendered twice")
162 }
163 };
164
165 self.phase = ElementRenderPhase::LayoutRequested {
166 layout_id,
167 frame_state,
168 };
169 layout_id
170 }
171
172 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
173 self.phase = match mem::take(&mut self.phase) {
174 ElementRenderPhase::LayoutRequested {
175 layout_id,
176 mut frame_state,
177 }
178 | ElementRenderPhase::LayoutComputed {
179 layout_id,
180 mut frame_state,
181 ..
182 } => {
183 let bounds = cx.layout_bounds(layout_id);
184 if let Some(id) = self.element.element_id() {
185 cx.with_element_state(id, |element_state, cx| {
186 let mut element_state = element_state.unwrap();
187 self.element
188 .paint(bounds, view_state, &mut element_state, cx);
189 ((), element_state)
190 });
191 } else {
192 self.element
193 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
194 }
195 ElementRenderPhase::Painted
196 }
197
198 _ => panic!("must call layout before paint"),
199 };
200 }
201
202 fn measure(
203 &mut self,
204 available_space: Size<AvailableSpace>,
205 view_state: &mut V,
206 cx: &mut ViewContext<V>,
207 ) -> Size<Pixels> {
208 if matches!(&self.phase, ElementRenderPhase::Start) {
209 self.initialize(view_state, cx);
210 }
211
212 if matches!(&self.phase, ElementRenderPhase::Initialized { .. }) {
213 self.layout(view_state, cx);
214 }
215
216 let layout_id = match &mut self.phase {
217 ElementRenderPhase::LayoutRequested {
218 layout_id,
219 frame_state,
220 } => {
221 cx.compute_layout(*layout_id, available_space);
222 let layout_id = *layout_id;
223 self.phase = ElementRenderPhase::LayoutComputed {
224 layout_id,
225 available_space,
226 frame_state: frame_state.take(),
227 };
228 layout_id
229 }
230 ElementRenderPhase::LayoutComputed {
231 layout_id,
232 available_space: prev_available_space,
233 ..
234 } => {
235 if available_space != *prev_available_space {
236 cx.compute_layout(*layout_id, available_space);
237 *prev_available_space = available_space;
238 }
239 *layout_id
240 }
241 _ => panic!("cannot measure after painting"),
242 };
243
244 cx.layout_bounds(layout_id).size
245 }
246
247 fn draw(
248 &mut self,
249 mut origin: Point<Pixels>,
250 available_space: Size<AvailableSpace>,
251 view_state: &mut V,
252 cx: &mut ViewContext<V>,
253 ) {
254 self.measure(available_space, view_state, cx);
255 // Ignore the element offset when drawing this element, as the origin is already specified
256 // in absolute terms.
257 origin -= cx.element_offset();
258 cx.with_element_offset(origin, |cx| self.paint(view_state, cx))
259 }
260}
261
262pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
263
264impl<V> AnyElement<V> {
265 pub fn new<E>(element: E) -> Self
266 where
267 V: 'static,
268 E: 'static + Element<V>,
269 E::ElementState: Any,
270 {
271 AnyElement(Box::new(RenderedElement::new(element)))
272 }
273
274 pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
275 self.0.initialize(view_state, cx);
276 }
277
278 pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
279 self.0.layout(view_state, cx)
280 }
281
282 pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
283 self.0.paint(view_state, cx)
284 }
285
286 /// Initializes this element and performs layout within the given available space to determine its size.
287 pub fn measure(
288 &mut self,
289 available_space: Size<AvailableSpace>,
290 view_state: &mut V,
291 cx: &mut ViewContext<V>,
292 ) -> Size<Pixels> {
293 self.0.measure(available_space, view_state, cx)
294 }
295
296 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
297 pub fn draw(
298 &mut self,
299 origin: Point<Pixels>,
300 available_space: Size<AvailableSpace>,
301 view_state: &mut V,
302 cx: &mut ViewContext<V>,
303 ) {
304 self.0.draw(origin, available_space, view_state, cx)
305 }
306}
307
308pub trait Component<V> {
309 fn render(self) -> AnyElement<V>;
310
311 fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
312 where
313 Self: Sized,
314 U: Component<V>,
315 {
316 f(self)
317 }
318
319 fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
320 where
321 Self: Sized,
322 {
323 self.map(|this| if condition { then(this) } else { this })
324 }
325
326 fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
327 where
328 Self: Sized,
329 {
330 self.map(|this| {
331 if let Some(value) = option {
332 then(this, value)
333 } else {
334 this
335 }
336 })
337 }
338}
339
340impl<V> Component<V> for AnyElement<V> {
341 fn render(self) -> AnyElement<V> {
342 self
343 }
344}
345
346impl<V, E, F> Element<V> for Option<F>
347where
348 V: 'static,
349 E: 'static + Component<V>,
350 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
351{
352 type ElementState = AnyElement<V>;
353
354 fn element_id(&self) -> Option<ElementId> {
355 None
356 }
357
358 fn initialize(
359 &mut self,
360 view_state: &mut V,
361 _rendered_element: Option<Self::ElementState>,
362 cx: &mut ViewContext<V>,
363 ) -> Self::ElementState {
364 let render = self.take().unwrap();
365 let mut rendered_element = (render)(view_state, cx).render();
366 rendered_element.initialize(view_state, cx);
367 rendered_element
368 }
369
370 fn layout(
371 &mut self,
372 view_state: &mut V,
373 rendered_element: &mut Self::ElementState,
374 cx: &mut ViewContext<V>,
375 ) -> LayoutId {
376 rendered_element.layout(view_state, cx)
377 }
378
379 fn paint(
380 &mut self,
381 _bounds: Bounds<Pixels>,
382 view_state: &mut V,
383 rendered_element: &mut Self::ElementState,
384 cx: &mut ViewContext<V>,
385 ) {
386 rendered_element.paint(view_state, cx)
387 }
388}
389
390impl<V, E, F> Component<V> for Option<F>
391where
392 V: 'static,
393 E: 'static + Component<V>,
394 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
395{
396 fn render(self) -> AnyElement<V> {
397 AnyElement::new(self)
398 }
399}
400
401impl<V, E, F> Component<V> for F
402where
403 V: 'static,
404 E: 'static + Component<V>,
405 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
406{
407 fn render(self) -> AnyElement<V> {
408 AnyElement::new(Some(self))
409 }
410}