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