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