1use crate::{
2 ArenaBox, AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size,
3 ViewContext, WindowContext, ELEMENT_ARENA,
4};
5use derive_more::{Deref, DerefMut};
6pub(crate) use smallvec::SmallVec;
7use std::{any::Any, fmt::Debug};
8
9pub trait Render: 'static + Sized {
10 fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element;
11}
12
13pub trait IntoElement: Sized {
14 type Element: Element + 'static;
15
16 fn element_id(&self) -> Option<ElementId>;
17
18 fn into_element(self) -> Self::Element;
19
20 fn into_any_element(self) -> AnyElement {
21 self.into_element().into_any()
22 }
23
24 fn draw_and_update_state<T, R>(
25 self,
26 origin: Point<Pixels>,
27 available_space: Size<T>,
28 cx: &mut WindowContext,
29 f: impl FnOnce(&mut <Self::Element as Element>::State, &mut WindowContext) -> R,
30 ) -> R
31 where
32 T: Clone + Default + Debug + Into<AvailableSpace>,
33 {
34 let element = self.into_element();
35 let element_id = element.element_id();
36 let element = DrawableElement {
37 element: Some(element),
38 phase: ElementDrawPhase::Start,
39 };
40
41 let frame_state =
42 DrawableElement::draw(element, origin, available_space.map(Into::into), cx);
43
44 if let Some(mut frame_state) = frame_state {
45 f(&mut frame_state, cx)
46 } else {
47 cx.with_element_state(element_id.unwrap(), |element_state, cx| {
48 let mut element_state = element_state.unwrap();
49 let result = f(&mut element_state, cx);
50 (result, element_state)
51 })
52 }
53 }
54
55 fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
56 where
57 Self: Sized,
58 U: IntoElement,
59 {
60 f(self)
61 }
62
63 fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
64 where
65 Self: Sized,
66 {
67 self.map(|this| if condition { then(this) } else { this })
68 }
69
70 fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
71 where
72 Self: Sized,
73 {
74 self.map(|this| {
75 if let Some(value) = option {
76 then(this, value)
77 } else {
78 this
79 }
80 })
81 }
82}
83
84pub trait Element: 'static + IntoElement {
85 type State: 'static;
86
87 fn layout(
88 &mut self,
89 state: Option<Self::State>,
90 cx: &mut WindowContext,
91 ) -> (LayoutId, Self::State);
92
93 fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
94
95 fn into_any(self) -> AnyElement {
96 AnyElement::new(self)
97 }
98}
99
100pub trait RenderOnce: 'static {
101 type Rendered: IntoElement;
102
103 fn render(self, cx: &mut WindowContext) -> Self::Rendered;
104}
105
106pub struct Component<C> {
107 component: Option<C>,
108}
109
110pub struct CompositeElementState<C: RenderOnce> {
111 rendered_element: Option<<C::Rendered as IntoElement>::Element>,
112 rendered_element_state: Option<<<C::Rendered as IntoElement>::Element as Element>::State>,
113}
114
115impl<C> Component<C> {
116 pub fn new(component: C) -> Self {
117 Component {
118 component: Some(component),
119 }
120 }
121}
122
123impl<C: RenderOnce> Element for Component<C> {
124 type State = CompositeElementState<C>;
125
126 fn layout(
127 &mut self,
128 state: Option<Self::State>,
129 cx: &mut WindowContext,
130 ) -> (LayoutId, Self::State) {
131 let mut element = self.component.take().unwrap().render(cx).into_element();
132 if let Some(element_id) = element.element_id() {
133 let layout_id =
134 cx.with_element_state(element_id, |state, cx| element.layout(state, cx));
135 let state = CompositeElementState {
136 rendered_element: Some(element),
137 rendered_element_state: None,
138 };
139 (layout_id, state)
140 } else {
141 let (layout_id, state) =
142 element.layout(state.and_then(|s| s.rendered_element_state), cx);
143 let state = CompositeElementState {
144 rendered_element: Some(element),
145 rendered_element_state: Some(state),
146 };
147 (layout_id, state)
148 }
149 }
150
151 fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
152 let mut element = state.rendered_element.take().unwrap();
153 if let Some(element_id) = element.element_id() {
154 cx.with_element_state(element_id, |element_state, cx| {
155 let mut element_state = element_state.unwrap();
156 element.paint(bounds, &mut element_state, cx);
157 ((), element_state)
158 });
159 } else {
160 element.paint(
161 bounds,
162 state.rendered_element_state.as_mut().unwrap(),
163 cx,
164 );
165 }
166 }
167}
168
169impl<C: RenderOnce> IntoElement for Component<C> {
170 type Element = Self;
171
172 fn element_id(&self) -> Option<ElementId> {
173 None
174 }
175
176 fn into_element(self) -> Self::Element {
177 self
178 }
179}
180
181#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
182pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
183
184pub trait ParentElement {
185 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
186
187 fn child(mut self, child: impl IntoElement) -> Self
188 where
189 Self: Sized,
190 {
191 self.children_mut().push(child.into_element().into_any());
192 self
193 }
194
195 fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
196 where
197 Self: Sized,
198 {
199 self.children_mut()
200 .extend(children.into_iter().map(|child| child.into_any_element()));
201 self
202 }
203}
204
205trait ElementObject {
206 fn element_id(&self) -> Option<ElementId>;
207
208 fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
209
210 fn paint(&mut self, cx: &mut WindowContext);
211
212 fn measure(
213 &mut self,
214 available_space: Size<AvailableSpace>,
215 cx: &mut WindowContext,
216 ) -> Size<Pixels>;
217
218 fn draw(
219 &mut self,
220 origin: Point<Pixels>,
221 available_space: Size<AvailableSpace>,
222 cx: &mut WindowContext,
223 );
224}
225
226pub struct DrawableElement<E: Element> {
227 element: Option<E>,
228 phase: ElementDrawPhase<E::State>,
229}
230
231#[derive(Default)]
232enum ElementDrawPhase<S> {
233 #[default]
234 Start,
235 LayoutRequested {
236 layout_id: LayoutId,
237 frame_state: Option<S>,
238 },
239 LayoutComputed {
240 layout_id: LayoutId,
241 available_space: Size<AvailableSpace>,
242 frame_state: Option<S>,
243 },
244}
245
246/// A wrapper around an implementer of [Element] that allows it to be drawn in a window.
247impl<E: Element> DrawableElement<E> {
248 fn new(element: E) -> Self {
249 DrawableElement {
250 element: Some(element),
251 phase: ElementDrawPhase::Start,
252 }
253 }
254
255 fn element_id(&self) -> Option<ElementId> {
256 self.element.as_ref()?.element_id()
257 }
258
259 fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
260 let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
261 {
262 let layout_id = cx.with_element_state(id, |element_state, cx| {
263 self.element.as_mut().unwrap().layout(element_state, cx)
264 });
265 (layout_id, None)
266 } else {
267 let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(None, cx);
268 (layout_id, Some(frame_state))
269 };
270
271 self.phase = ElementDrawPhase::LayoutRequested {
272 layout_id,
273 frame_state,
274 };
275 layout_id
276 }
277
278 fn paint(mut self, cx: &mut WindowContext) -> Option<E::State> {
279 match self.phase {
280 ElementDrawPhase::LayoutRequested {
281 layout_id,
282 frame_state,
283 }
284 | ElementDrawPhase::LayoutComputed {
285 layout_id,
286 frame_state,
287 ..
288 } => {
289 let bounds = cx.layout_bounds(layout_id);
290
291 if let Some(mut frame_state) = frame_state {
292 self.element
293 .take()
294 .unwrap()
295 .paint(bounds, &mut frame_state, cx);
296 Some(frame_state)
297 } else {
298 let element_id = self
299 .element
300 .as_ref()
301 .unwrap()
302 .element_id()
303 .expect("if we don't have frame state, we should have element state");
304 cx.with_element_state(element_id, |element_state, cx| {
305 let mut element_state = element_state.unwrap();
306 self.element
307 .take()
308 .unwrap()
309 .paint(bounds, &mut element_state, cx);
310 ((), element_state)
311 });
312 None
313 }
314 }
315
316 _ => panic!("must call layout before paint"),
317 }
318 }
319
320 fn measure(
321 &mut self,
322 available_space: Size<AvailableSpace>,
323 cx: &mut WindowContext,
324 ) -> Size<Pixels> {
325 if matches!(&self.phase, ElementDrawPhase::Start) {
326 self.layout(cx);
327 }
328
329 let layout_id = match &mut self.phase {
330 ElementDrawPhase::LayoutRequested {
331 layout_id,
332 frame_state,
333 } => {
334 cx.compute_layout(*layout_id, available_space);
335 let layout_id = *layout_id;
336 self.phase = ElementDrawPhase::LayoutComputed {
337 layout_id,
338 available_space,
339 frame_state: frame_state.take(),
340 };
341 layout_id
342 }
343 ElementDrawPhase::LayoutComputed {
344 layout_id,
345 available_space: prev_available_space,
346 ..
347 } => {
348 if available_space != *prev_available_space {
349 cx.compute_layout(*layout_id, available_space);
350 *prev_available_space = available_space;
351 }
352 *layout_id
353 }
354 _ => panic!("cannot measure after painting"),
355 };
356
357 cx.layout_bounds(layout_id).size
358 }
359
360 fn draw(
361 mut self,
362 origin: Point<Pixels>,
363 available_space: Size<AvailableSpace>,
364 cx: &mut WindowContext,
365 ) -> Option<E::State> {
366 self.measure(available_space, cx);
367 cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
368 }
369}
370
371impl<E> ElementObject for Option<DrawableElement<E>>
372where
373 E: Element,
374 E::State: 'static,
375{
376 fn element_id(&self) -> Option<ElementId> {
377 self.as_ref().unwrap().element_id()
378 }
379
380 fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
381 DrawableElement::layout(self.as_mut().unwrap(), cx)
382 }
383
384 fn paint(&mut self, cx: &mut WindowContext) {
385 DrawableElement::paint(self.take().unwrap(), cx);
386 }
387
388 fn measure(
389 &mut self,
390 available_space: Size<AvailableSpace>,
391 cx: &mut WindowContext,
392 ) -> Size<Pixels> {
393 DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
394 }
395
396 fn draw(
397 &mut self,
398 origin: Point<Pixels>,
399 available_space: Size<AvailableSpace>,
400 cx: &mut WindowContext,
401 ) {
402 DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
403 }
404}
405
406pub struct AnyElement(ArenaBox<dyn ElementObject>);
407
408impl AnyElement {
409 pub fn new<E>(element: E) -> Self
410 where
411 E: 'static + Element,
412 E::State: Any,
413 {
414 let element = ELEMENT_ARENA
415 .with_borrow_mut(|arena| arena.alloc(|| Some(DrawableElement::new(element))))
416 .map(|element| element as &mut dyn ElementObject);
417 AnyElement(element)
418 }
419
420 pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
421 self.0.layout(cx)
422 }
423
424 pub fn paint(&mut self, cx: &mut WindowContext) {
425 self.0.paint(cx)
426 }
427
428 /// Initializes this element and performs layout within the given available space to determine its size.
429 pub fn measure(
430 &mut self,
431 available_space: Size<AvailableSpace>,
432 cx: &mut WindowContext,
433 ) -> Size<Pixels> {
434 self.0.measure(available_space, cx)
435 }
436
437 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
438 pub fn draw(
439 &mut self,
440 origin: Point<Pixels>,
441 available_space: Size<AvailableSpace>,
442 cx: &mut WindowContext,
443 ) {
444 self.0.draw(origin, available_space, cx)
445 }
446
447 pub fn inner_id(&self) -> Option<ElementId> {
448 self.0.element_id()
449 }
450}
451
452impl Element for AnyElement {
453 type State = ();
454
455 fn layout(
456 &mut self,
457 _: Option<Self::State>,
458 cx: &mut WindowContext,
459 ) -> (LayoutId, Self::State) {
460 let layout_id = self.layout(cx);
461 (layout_id, ())
462 }
463
464 fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
465 self.paint(cx)
466 }
467}
468
469impl IntoElement for AnyElement {
470 type Element = Self;
471
472 fn element_id(&self) -> Option<ElementId> {
473 None
474 }
475
476 fn into_element(self) -> Self::Element {
477 self
478 }
479
480 fn into_any_element(self) -> AnyElement {
481 self
482 }
483}
484
485/// The empty element, which renders nothing.
486pub type Empty = ();
487
488impl IntoElement for () {
489 type Element = Self;
490
491 fn element_id(&self) -> Option<ElementId> {
492 None
493 }
494
495 fn into_element(self) -> Self::Element {
496 self
497 }
498}
499
500impl Element for () {
501 type State = ();
502
503 fn layout(
504 &mut self,
505 _state: Option<Self::State>,
506 cx: &mut WindowContext,
507 ) -> (LayoutId, Self::State) {
508 (cx.request_layout(&crate::Style::default(), None), ())
509 }
510
511 fn paint(
512 &mut self,
513 _bounds: Bounds<Pixels>,
514 _state: &mut Self::State,
515 _cx: &mut WindowContext,
516 ) {
517 }
518}