1use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, SharedString, ViewContext};
2use derive_more::{Deref, DerefMut};
3pub(crate) use smallvec::SmallVec;
4
5pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
6 type ViewState: 'static + Send + Sync;
7 type ElementState: 'static + Send + Sync;
8
9 fn id(&self) -> Option<ElementId>;
10
11 fn layout(
12 &mut self,
13 state: &mut Self::ViewState,
14 element_state: Option<Self::ElementState>,
15 cx: &mut ViewContext<Self::ViewState>,
16 ) -> (LayoutId, Self::ElementState);
17
18 fn paint(
19 &mut self,
20 bounds: Bounds<Pixels>,
21 state: &mut Self::ViewState,
22 element_state: &mut Self::ElementState,
23 cx: &mut ViewContext<Self::ViewState>,
24 );
25}
26
27pub trait IdentifiedElement: Element {
28 fn id(&self) -> ElementId {
29 Element::id(self).unwrap()
30 }
31}
32
33#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
34pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
35
36pub trait ParentElement: Element {
37 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
38 fn group_mut(&mut self) -> &mut Option<SharedString>;
39
40 fn child(mut self, child: impl IntoAnyElement<Self::ViewState>) -> Self
41 where
42 Self: Sized,
43 {
44 self.children_mut().push(child.into_any());
45 self
46 }
47
48 fn children(
49 mut self,
50 iter: impl IntoIterator<Item = impl IntoAnyElement<Self::ViewState>>,
51 ) -> Self
52 where
53 Self: Sized,
54 {
55 self.children_mut()
56 .extend(iter.into_iter().map(|item| item.into_any()));
57 self
58 }
59}
60
61trait ElementObject<S>: 'static + Send + Sync {
62 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
63 fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
64}
65
66struct RenderedElement<E: Element> {
67 element: E,
68 phase: ElementRenderPhase<E::ElementState>,
69}
70
71#[derive(Default)]
72enum ElementRenderPhase<S> {
73 #[default]
74 Rendered,
75 LayoutRequested {
76 layout_id: LayoutId,
77 frame_state: Option<S>,
78 },
79 Painted {
80 bounds: Bounds<Pixels>,
81 frame_state: Option<S>,
82 },
83}
84
85/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
86/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
87/// improved usability.
88impl<E: Element> RenderedElement<E> {
89 fn new(element: E) -> Self {
90 RenderedElement {
91 element,
92 phase: ElementRenderPhase::Rendered,
93 }
94 }
95
96 fn paint_with_element_state(
97 &mut self,
98 bounds: Bounds<Pixels>,
99 view_state: &mut E::ViewState,
100 frame_state: &mut Option<E::ElementState>,
101 cx: &mut ViewContext<E::ViewState>,
102 ) {
103 if let Some(id) = self.element.id() {
104 cx.with_element_state(id, |element_state, cx| {
105 let mut element_state = element_state.unwrap();
106 self.element
107 .paint(bounds, view_state, &mut element_state, cx);
108 ((), element_state)
109 });
110 } else {
111 self.element
112 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
113 }
114 }
115}
116
117impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
118where
119 E: Element<ElementState = S>,
120 S: 'static + Send + Sync,
121{
122 fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
123 let (layout_id, frame_state) = if let Some(id) = self.element.id() {
124 let layout_id = cx.with_element_state(id, |element_state, cx| {
125 self.element.layout(state, element_state, cx)
126 });
127 (layout_id, None)
128 } else {
129 let (layout_id, frame_state) = self.element.layout(state, None, cx);
130 (layout_id, Some(frame_state))
131 };
132
133 self.phase = ElementRenderPhase::LayoutRequested {
134 layout_id,
135 frame_state,
136 };
137
138 layout_id
139 }
140
141 fn paint(
142 &mut self,
143 view_state: &mut E::ViewState,
144 offset: Option<Point<Pixels>>,
145 cx: &mut ViewContext<E::ViewState>,
146 ) {
147 self.phase = match std::mem::take(&mut self.phase) {
148 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
149
150 ElementRenderPhase::LayoutRequested {
151 layout_id,
152 mut frame_state,
153 } => {
154 let mut bounds = cx.layout_bounds(layout_id);
155 offset.map(|offset| bounds.origin += offset);
156 self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
157 ElementRenderPhase::Painted {
158 bounds,
159 frame_state,
160 }
161 }
162
163 ElementRenderPhase::Painted {
164 bounds,
165 mut frame_state,
166 } => {
167 self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
168 ElementRenderPhase::Painted {
169 bounds,
170 frame_state,
171 }
172 }
173 };
174 }
175}
176
177pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
178
179impl<S: 'static + Send + Sync> AnyElement<S> {
180 pub fn new<E: Element<ViewState = S>>(element: E) -> Self {
181 AnyElement(Box::new(RenderedElement::new(element)))
182 }
183}
184
185impl<S: 'static + Send + Sync> AnyElement<S> {
186 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
187 self.0.layout(state, cx)
188 }
189
190 pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
191 self.0.paint(state, offset, cx)
192 }
193}
194
195pub trait IntoAnyElement<S> {
196 fn into_any(self) -> AnyElement<S>;
197}
198
199impl<S> IntoAnyElement<S> for AnyElement<S> {
200 fn into_any(self) -> AnyElement<S> {
201 self
202 }
203}