1use parking_lot::Mutex;
2
3use crate::{
4 AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle,
5 LayoutId, Pixels, ViewContext, WindowContext,
6};
7use std::{marker::PhantomData, sync::Arc};
8
9pub struct View<V> {
10 state: Handle<V>,
11 render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
12}
13
14impl<V: 'static> View<V> {
15 pub fn into_any(self) -> AnyView {
16 AnyView(Arc::new(self))
17 }
18}
19
20impl<V> Clone for View<V> {
21 fn clone(&self) -> Self {
22 Self {
23 state: self.state.clone(),
24 render: self.render.clone(),
25 }
26 }
27}
28
29pub fn view<V, E>(
30 state: Handle<V>,
31 render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
32) -> View<V>
33where
34 E: Component<V>,
35{
36 View {
37 state,
38 render: Arc::new(Mutex::new(
39 move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
40 )),
41 }
42}
43
44impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V> {
45 fn render(self) -> AnyElement<ParentViewState> {
46 AnyElement::new(EraseViewState {
47 view: self,
48 parent_view_state_type: PhantomData,
49 })
50 }
51}
52
53impl<V: 'static> Element<()> for View<V> {
54 type ElementState = AnyElement<V>;
55
56 fn id(&self) -> Option<crate::ElementId> {
57 Some(ElementId::View(self.state.entity_id))
58 }
59
60 fn initialize(
61 &mut self,
62 _: &mut (),
63 _: Option<Self::ElementState>,
64 cx: &mut ViewContext<()>,
65 ) -> Self::ElementState {
66 self.state.update(cx, |state, cx| {
67 let mut any_element = (self.render.lock())(state, cx);
68 any_element.initialize(state, cx);
69 any_element
70 })
71 }
72
73 fn layout(
74 &mut self,
75 _: &mut (),
76 element: &mut Self::ElementState,
77 cx: &mut ViewContext<()>,
78 ) -> LayoutId {
79 self.state.update(cx, |state, cx| element.layout(state, cx))
80 }
81
82 fn paint(
83 &mut self,
84 _: Bounds<Pixels>,
85 _: &mut (),
86 element: &mut Self::ElementState,
87 cx: &mut ViewContext<()>,
88 ) {
89 self.state.update(cx, |state, cx| element.paint(state, cx))
90 }
91}
92
93struct EraseViewState<V, ParentV> {
94 view: View<V>,
95 parent_view_state_type: PhantomData<ParentV>,
96}
97
98unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
99
100impl<V: 'static, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
101 fn render(self) -> AnyElement<ParentV> {
102 AnyElement::new(self)
103 }
104}
105
106impl<V: 'static, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
107 type ElementState = AnyBox;
108
109 fn id(&self) -> Option<crate::ElementId> {
110 Element::id(&self.view)
111 }
112
113 fn initialize(
114 &mut self,
115 _: &mut ParentV,
116 _: Option<Self::ElementState>,
117 cx: &mut ViewContext<ParentV>,
118 ) -> Self::ElementState {
119 ViewObject::initialize(&mut self.view, cx)
120 }
121
122 fn layout(
123 &mut self,
124 _: &mut ParentV,
125 element: &mut Self::ElementState,
126 cx: &mut ViewContext<ParentV>,
127 ) -> LayoutId {
128 ViewObject::layout(&mut self.view, element, cx)
129 }
130
131 fn paint(
132 &mut self,
133 bounds: Bounds<Pixels>,
134 _: &mut ParentV,
135 element: &mut Self::ElementState,
136 cx: &mut ViewContext<ParentV>,
137 ) {
138 ViewObject::paint(&mut self.view, bounds, element, cx)
139 }
140}
141
142trait ViewObject: Send + Sync {
143 fn entity_id(&self) -> EntityId;
144 fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
145 fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
146 fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
147}
148
149impl<V: 'static> ViewObject for View<V> {
150 fn entity_id(&self) -> EntityId {
151 self.state.entity_id
152 }
153
154 fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
155 cx.with_element_id(self.entity_id(), |_global_id, cx| {
156 self.state.update(cx, |state, cx| {
157 let mut any_element = Box::new((self.render.lock())(state, cx));
158 any_element.initialize(state, cx);
159 any_element as AnyBox
160 })
161 })
162 }
163
164 fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
165 cx.with_element_id(self.entity_id(), |_global_id, cx| {
166 self.state.update(cx, |state, cx| {
167 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
168 element.layout(state, cx)
169 })
170 })
171 }
172
173 fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
174 cx.with_element_id(self.entity_id(), |_global_id, cx| {
175 self.state.update(cx, |state, cx| {
176 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
177 element.paint(state, cx);
178 });
179 });
180 }
181}
182
183#[derive(Clone)]
184pub struct AnyView(Arc<dyn ViewObject>);
185
186impl<ParentV: 'static> Component<ParentV> for AnyView {
187 fn render(self) -> AnyElement<ParentV> {
188 AnyElement::new(EraseAnyViewState {
189 view: self,
190 parent_view_state_type: PhantomData,
191 })
192 }
193}
194
195impl Element<()> for AnyView {
196 type ElementState = AnyBox;
197
198 fn id(&self) -> Option<crate::ElementId> {
199 Some(ElementId::View(self.0.entity_id()))
200 }
201
202 fn initialize(
203 &mut self,
204 _: &mut (),
205 _: Option<Self::ElementState>,
206 cx: &mut ViewContext<()>,
207 ) -> Self::ElementState {
208 self.0.initialize(cx)
209 }
210
211 fn layout(
212 &mut self,
213 _: &mut (),
214 element: &mut Self::ElementState,
215 cx: &mut ViewContext<()>,
216 ) -> LayoutId {
217 self.0.layout(element, cx)
218 }
219
220 fn paint(
221 &mut self,
222 bounds: Bounds<Pixels>,
223 _: &mut (),
224 element: &mut AnyBox,
225 cx: &mut ViewContext<()>,
226 ) {
227 self.0.paint(bounds, element, cx)
228 }
229}
230
231struct EraseAnyViewState<ParentViewState> {
232 view: AnyView,
233 parent_view_state_type: PhantomData<ParentViewState>,
234}
235
236unsafe impl<ParentV> Send for EraseAnyViewState<ParentV> {}
237
238impl<ParentV: 'static> Component<ParentV> for EraseAnyViewState<ParentV> {
239 fn render(self) -> AnyElement<ParentV> {
240 AnyElement::new(self)
241 }
242}
243
244impl<ParentV: 'static> Element<ParentV> for EraseAnyViewState<ParentV> {
245 type ElementState = AnyBox;
246
247 fn id(&self) -> Option<crate::ElementId> {
248 Element::id(&self.view)
249 }
250
251 fn initialize(
252 &mut self,
253 _: &mut ParentV,
254 _: Option<Self::ElementState>,
255 cx: &mut ViewContext<ParentV>,
256 ) -> Self::ElementState {
257 self.view.0.initialize(cx)
258 }
259
260 fn layout(
261 &mut self,
262 _: &mut ParentV,
263 element: &mut Self::ElementState,
264 cx: &mut ViewContext<ParentV>,
265 ) -> LayoutId {
266 self.view.0.layout(element, cx)
267 }
268
269 fn paint(
270 &mut self,
271 bounds: Bounds<Pixels>,
272 _: &mut ParentV,
273 element: &mut Self::ElementState,
274 cx: &mut ViewContext<ParentV>,
275 ) {
276 self.view.0.paint(bounds, element, cx)
277 }
278}