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