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