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