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