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_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(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(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
154 let 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(Box<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 AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject>)
417 }
418
419 pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
420 self.0.layout(cx)
421 }
422
423 pub fn paint(mut self, cx: &mut WindowContext) {
424 self.0.paint(cx)
425 }
426
427 /// Initializes this element and performs layout within the given available space to determine its size.
428 pub fn measure(
429 &mut self,
430 available_space: Size<AvailableSpace>,
431 cx: &mut WindowContext,
432 ) -> Size<Pixels> {
433 self.0.measure(available_space, cx)
434 }
435
436 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
437 pub fn draw(
438 mut self,
439 origin: Point<Pixels>,
440 available_space: Size<AvailableSpace>,
441 cx: &mut WindowContext,
442 ) {
443 self.0.draw(origin, available_space, cx)
444 }
445
446 /// Converts this `AnyElement` into a trait object that can be stored and manipulated.
447 pub fn into_any(self) -> AnyElement {
448 AnyElement::new(self)
449 }
450
451 pub fn inner_id(&self) -> Option<ElementId> {
452 self.0.element_id()
453 }
454}
455
456impl Element for AnyElement {
457 type State = ();
458
459 fn layout(
460 &mut self,
461 _: Option<Self::State>,
462 cx: &mut WindowContext,
463 ) -> (LayoutId, Self::State) {
464 let layout_id = self.layout(cx);
465 (layout_id, ())
466 }
467
468 fn paint(self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
469 self.paint(cx);
470 }
471}
472
473impl IntoElement for AnyElement {
474 type Element = Self;
475
476 fn element_id(&self) -> Option<ElementId> {
477 None
478 }
479
480 fn into_element(self) -> Self::Element {
481 self
482 }
483}
484
485// impl<V, E, F> Element for Option<F>
486// where
487// V: 'static,
488// E: Element,
489// F: FnOnce(&mut V, &mut WindowContext<'_, V>) -> E + 'static,
490// {
491// type State = Option<AnyElement>;
492
493// fn element_id(&self) -> Option<ElementId> {
494// None
495// }
496
497// fn layout(
498// &mut self,
499// _: Option<Self::State>,
500// cx: &mut WindowContext,
501// ) -> (LayoutId, Self::State) {
502// let render = self.take().unwrap();
503// let mut element = (render)(view_state, cx).into_any();
504// let layout_id = element.layout(view_state, cx);
505// (layout_id, Some(element))
506// }
507
508// fn paint(
509// self,
510// _bounds: Bounds<Pixels>,
511// rendered_element: &mut Self::State,
512// cx: &mut WindowContext,
513// ) {
514// rendered_element.take().unwrap().paint(view_state, cx);
515// }
516// }
517
518// impl<V, E, F> RenderOnce for Option<F>
519// where
520// V: 'static,
521// E: Element,
522// F: FnOnce(&mut V, &mut WindowContext) -> E + 'static,
523// {
524// type Element = Self;
525
526// fn render(self) -> Self::Element {
527// self
528// }
529// }