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