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