1use crate::{
2 BorrowWindow, Bounds, ElementId, FocusHandle, InputHandlerView, LayoutId, Pixels, ViewContext,
3 WindowInputHandler,
4};
5use derive_more::{Deref, DerefMut};
6pub(crate) use smallvec::SmallVec;
7use std::{any::Any, mem};
8
9pub trait Element<V: 'static> {
10 type ElementState: 'static;
11
12 fn id(&self) -> Option<ElementId>;
13
14 /// Called to initialize this element for the current frame. If this
15 /// element had state in a previous frame, it will be passed in for the 3rd argument.
16 fn initialize(
17 &mut self,
18 view_state: &mut V,
19 element_state: Option<Self::ElementState>,
20 cx: &mut ViewContext<V>,
21 ) -> Self::ElementState;
22
23 fn layout(
24 &mut self,
25 view_state: &mut V,
26 element_state: &mut Self::ElementState,
27 cx: &mut ViewContext<V>,
28 ) -> LayoutId;
29
30 fn paint(
31 &mut self,
32 bounds: Bounds<Pixels>,
33 view_state: &mut V,
34 element_state: &mut Self::ElementState,
35 cx: &mut ViewContext<V>,
36 );
37
38 fn handle_text_input<'a>(
39 &self,
40 _view_state: &'a mut V,
41 _cx: &mut ViewContext<V>,
42 ) -> Option<(Box<dyn InputHandlerView>, &'a FocusHandle)> {
43 None
44 }
45}
46
47#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
48pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
49
50pub trait ParentElement<V: 'static> {
51 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
52
53 fn child(mut self, child: impl Component<V>) -> Self
54 where
55 Self: Sized,
56 {
57 self.children_mut().push(child.render());
58 self
59 }
60
61 fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
62 where
63 Self: Sized,
64 {
65 self.children_mut()
66 .extend(iter.into_iter().map(|item| item.render()));
67 self
68 }
69}
70
71trait ElementObject<V> {
72 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
73 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
74 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
75}
76
77struct RenderedElement<V: 'static, E: Element<V>> {
78 element: E,
79 phase: ElementRenderPhase<E::ElementState>,
80}
81
82#[derive(Default)]
83enum ElementRenderPhase<V> {
84 #[default]
85 Start,
86 Initialized {
87 frame_state: Option<V>,
88 },
89 LayoutRequested {
90 layout_id: LayoutId,
91 frame_state: Option<V>,
92 },
93 Painted,
94}
95
96/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
97/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
98/// improved usability.
99impl<V, E: Element<V>> RenderedElement<V, E> {
100 fn new(element: E) -> Self {
101 RenderedElement {
102 element,
103 phase: ElementRenderPhase::Start,
104 }
105 }
106}
107
108impl<V, E> ElementObject<V> for RenderedElement<V, E>
109where
110 E: Element<V>,
111 E::ElementState: 'static,
112{
113 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
114 let frame_state = if let Some(id) = self.element.id() {
115 cx.with_element_state(id, |element_state, cx| {
116 let element_state = self.element.initialize(view_state, element_state, cx);
117 ((), element_state)
118 });
119 None
120 } else {
121 let frame_state = self.element.initialize(view_state, None, cx);
122 Some(frame_state)
123 };
124
125 self.phase = ElementRenderPhase::Initialized { frame_state };
126 }
127
128 fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
129 let layout_id;
130 let mut frame_state;
131 match mem::take(&mut self.phase) {
132 ElementRenderPhase::Initialized {
133 frame_state: initial_frame_state,
134 } => {
135 frame_state = initial_frame_state;
136 if let Some(id) = self.element.id() {
137 layout_id = cx.with_element_state(id, |element_state, cx| {
138 let mut element_state = element_state.unwrap();
139 let layout_id = self.element.layout(state, &mut element_state, cx);
140 (layout_id, element_state)
141 });
142 } else {
143 layout_id = self
144 .element
145 .layout(state, frame_state.as_mut().unwrap(), cx);
146 }
147 }
148 ElementRenderPhase::Start => panic!("must call initialize before layout"),
149 ElementRenderPhase::LayoutRequested { .. } | ElementRenderPhase::Painted => {
150 panic!("element rendered twice")
151 }
152 };
153
154 self.phase = ElementRenderPhase::LayoutRequested {
155 layout_id,
156 frame_state,
157 };
158 layout_id
159 }
160
161 fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
162 self.phase = match mem::take(&mut self.phase) {
163 ElementRenderPhase::LayoutRequested {
164 layout_id,
165 mut frame_state,
166 } => {
167 let bounds = cx.layout_bounds(layout_id);
168 if let Some((input_handler, focus_handle)) =
169 self.element.handle_text_input(view_state, cx)
170 {
171 if focus_handle.is_focused(cx) {
172 cx.window.requested_input_handler = Some(Box::new(WindowInputHandler {
173 cx: cx.app.this.clone(),
174 window: cx.window_handle(),
175 input_handler,
176 element_bounds: bounds,
177 }));
178 }
179 }
180 if let Some(id) = self.element.id() {
181 cx.with_element_state(id, |element_state, cx| {
182 let mut element_state = element_state.unwrap();
183 self.element
184 .paint(bounds, view_state, &mut element_state, cx);
185 ((), element_state)
186 });
187 } else {
188 self.element
189 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
190 }
191 ElementRenderPhase::Painted
192 }
193
194 _ => panic!("must call layout before paint"),
195 };
196 }
197}
198
199pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
200
201impl<V> AnyElement<V> {
202 pub fn new<E>(element: E) -> Self
203 where
204 V: 'static,
205 E: 'static + Element<V>,
206 E::ElementState: Any,
207 {
208 AnyElement(Box::new(RenderedElement::new(element)))
209 }
210
211 pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
212 self.0.initialize(view_state, cx);
213 }
214
215 pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
216 self.0.layout(view_state, cx)
217 }
218
219 pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
220 self.0.paint(view_state, cx)
221 }
222}
223
224pub trait Component<V> {
225 fn render(self) -> AnyElement<V>;
226
227 fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
228 where
229 Self: Sized,
230 U: Component<V>,
231 {
232 f(self)
233 }
234
235 fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
236 where
237 Self: Sized,
238 {
239 self.map(|this| if condition { then(this) } else { this })
240 }
241
242 fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
243 where
244 Self: Sized,
245 {
246 self.map(|this| {
247 if let Some(value) = option {
248 then(this, value)
249 } else {
250 this
251 }
252 })
253 }
254}
255
256impl<V> Component<V> for AnyElement<V> {
257 fn render(self) -> AnyElement<V> {
258 self
259 }
260}
261
262impl<V, E, F> Element<V> for Option<F>
263where
264 V: 'static,
265 E: 'static + Component<V>,
266 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
267{
268 type ElementState = AnyElement<V>;
269
270 fn id(&self) -> Option<ElementId> {
271 None
272 }
273
274 fn initialize(
275 &mut self,
276 view_state: &mut V,
277 _rendered_element: Option<Self::ElementState>,
278 cx: &mut ViewContext<V>,
279 ) -> Self::ElementState {
280 let render = self.take().unwrap();
281 let mut rendered_element = (render)(view_state, cx).render();
282 rendered_element.initialize(view_state, cx);
283 rendered_element
284 }
285
286 fn layout(
287 &mut self,
288 view_state: &mut V,
289 rendered_element: &mut Self::ElementState,
290 cx: &mut ViewContext<V>,
291 ) -> LayoutId {
292 rendered_element.layout(view_state, cx)
293 }
294
295 fn paint(
296 &mut self,
297 _bounds: Bounds<Pixels>,
298 view_state: &mut V,
299 rendered_element: &mut Self::ElementState,
300 cx: &mut ViewContext<V>,
301 ) {
302 rendered_element.paint(view_state, cx)
303 }
304}
305
306impl<V, E, F> Component<V> for Option<F>
307where
308 V: 'static,
309 E: 'static + Component<V>,
310 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
311{
312 fn render(self) -> AnyElement<V> {
313 AnyElement::new(self)
314 }
315}
316
317impl<V, E, F> Component<V> for F
318where
319 V: 'static,
320 E: 'static + Component<V>,
321 F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
322{
323 fn render(self) -> AnyElement<V> {
324 AnyElement::new(Some(self))
325 }
326}