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 {
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 // HACK: This is a temporary hack to get children working for the purposes
87 // of building UI on top of the current version of gpui2.
88 //
89 // We'll (hopefully) be moving away from this in the future.
90 fn children_any<I>(mut self, children: I) -> Self
91 where
92 I: IntoIterator<Item = AnyElement<Self::State>>,
93 Self: Sized,
94 {
95 self.children_mut().extend(children.into_iter());
96 self
97 }
98
99 // HACK: This is a temporary hack to get children working for the purposes
100 // of building UI on top of the current version of gpui2.
101 //
102 // We'll (hopefully) be moving away from this in the future.
103 fn child_any(mut self, children: AnyElement<Self::State>) -> Self
104 where
105 Self: Sized,
106 {
107 self.children_mut().push(children);
108 self
109 }
110}
111
112trait ElementObject<S>: 'static + Send + Sync {
113 fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
114 fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
115}
116
117struct RenderedElement<E: Element> {
118 element: E,
119 phase: ElementRenderPhase<E::ElementState>,
120}
121
122#[derive(Default)]
123enum ElementRenderPhase<S> {
124 #[default]
125 Rendered,
126 LayoutRequested {
127 layout_id: LayoutId,
128 frame_state: Option<S>,
129 },
130 Painted {
131 bounds: Bounds<Pixels>,
132 frame_state: Option<S>,
133 },
134}
135
136/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
137/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
138/// improved usability.
139impl<E: Element> RenderedElement<E> {
140 fn new(element: E) -> Self {
141 RenderedElement {
142 element,
143 phase: ElementRenderPhase::Rendered,
144 }
145 }
146
147 fn paint_with_element_state(
148 &mut self,
149 bounds: Bounds<Pixels>,
150 view_state: &mut E::ViewState,
151 frame_state: &mut Option<E::ElementState>,
152 cx: &mut ViewContext<E::ViewState>,
153 ) {
154 if let Some(id) = self.element.element_id() {
155 cx.with_element_state(id, |element_state, cx| {
156 let mut element_state = element_state.unwrap();
157 self.element
158 .paint(bounds, view_state, &mut element_state, cx);
159 ((), element_state)
160 });
161 } else {
162 self.element
163 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
164 }
165 }
166}
167
168impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
169where
170 E: Element<ElementState = S>,
171 S: 'static + Send + Sync,
172{
173 fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
174 let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
175 let layout_id = cx.with_element_state(id, |element_state, cx| {
176 self.element.layout(state, element_state, cx)
177 });
178 (layout_id, None)
179 } else {
180 let (layout_id, frame_state) = self.element.layout(state, None, cx);
181 (layout_id, Some(frame_state))
182 };
183
184 self.phase = ElementRenderPhase::LayoutRequested {
185 layout_id,
186 frame_state,
187 };
188
189 layout_id
190 }
191
192 fn paint(
193 &mut self,
194 view_state: &mut E::ViewState,
195 offset: Option<Point<Pixels>>,
196 cx: &mut ViewContext<E::ViewState>,
197 ) {
198 self.phase = match std::mem::take(&mut self.phase) {
199 ElementRenderPhase::Rendered => panic!("must call layout before paint"),
200
201 ElementRenderPhase::LayoutRequested {
202 layout_id,
203 mut frame_state,
204 } => {
205 let mut bounds = cx.layout_bounds(layout_id);
206 offset.map(|offset| bounds.origin += offset);
207 self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
208 ElementRenderPhase::Painted {
209 bounds,
210 frame_state,
211 }
212 }
213
214 ElementRenderPhase::Painted {
215 bounds,
216 mut frame_state,
217 } => {
218 self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
219 ElementRenderPhase::Painted {
220 bounds,
221 frame_state,
222 }
223 }
224 };
225 }
226}
227
228pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
229
230impl<S: 'static + Send + Sync> AnyElement<S> {
231 pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
232 self.0.layout(state, cx)
233 }
234
235 pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
236 self.0.paint(state, offset, cx)
237 }
238}
239
240pub trait IntoAnyElement<S> {
241 fn into_any(self) -> AnyElement<S>;
242}
243
244impl<E: Element> IntoAnyElement<E::ViewState> for E {
245 fn into_any(self) -> AnyElement<E::ViewState> {
246 AnyElement(Box::new(RenderedElement::new(self)))
247 }
248}
249
250impl<S> IntoAnyElement<S> for AnyElement<S> {
251 fn into_any(self) -> AnyElement<S> {
252 self
253 }
254}