1use crate::{
2 AnyBox, AnyElement, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, Element,
3 ElementId, EntityHandle, EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext,
4 VisualContext, WeakHandle, WindowContext,
5};
6use anyhow::{Context, Result};
7use parking_lot::Mutex;
8use std::{
9 any::Any,
10 marker::PhantomData,
11 sync::{Arc, Weak},
12};
13
14pub struct View<V> {
15 pub(crate) state: Handle<V>,
16 render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
17}
18
19impl<V: 'static> View<V> {
20 pub fn for_handle<E>(
21 state: Handle<V>,
22 render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
23 ) -> View<V>
24 where
25 E: Component<V>,
26 {
27 View {
28 state,
29 render: Arc::new(Mutex::new(
30 move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
31 )),
32 }
33 }
34
35 pub fn into_any(self) -> AnyView {
36 AnyView(Arc::new(self))
37 }
38
39 pub fn downgrade(&self) -> WeakView<V> {
40 WeakView {
41 state: self.state.downgrade(),
42 render: Arc::downgrade(&self.render),
43 }
44 }
45
46 pub fn update<C, R>(
47 &self,
48 cx: &mut C,
49 f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
50 ) -> C::Result<R>
51 where
52 C: VisualContext,
53 {
54 cx.update_view(self, f)
55 }
56
57 pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
58 cx.entities.read(&self.state)
59 }
60}
61
62impl<V> Clone for View<V> {
63 fn clone(&self) -> Self {
64 Self {
65 state: self.state.clone(),
66 render: self.render.clone(),
67 }
68 }
69}
70
71impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V> {
72 fn render(self) -> AnyElement<ParentViewState> {
73 AnyElement::new(EraseViewState {
74 view: self,
75 parent_view_state_type: PhantomData,
76 })
77 }
78}
79
80impl<V: 'static> Element<()> for View<V> {
81 type ElementState = AnyElement<V>;
82
83 fn id(&self) -> Option<ElementId> {
84 Some(ElementId::View(self.state.entity_id))
85 }
86
87 fn initialize(
88 &mut self,
89 _: &mut (),
90 _: Option<Self::ElementState>,
91 cx: &mut ViewContext<()>,
92 ) -> Self::ElementState {
93 self.update(cx, |state, cx| {
94 let mut any_element = (self.render.lock())(state, cx);
95 any_element.initialize(state, cx);
96 any_element
97 })
98 }
99
100 fn layout(
101 &mut self,
102 _: &mut (),
103 element: &mut Self::ElementState,
104 cx: &mut ViewContext<()>,
105 ) -> LayoutId {
106 self.update(cx, |state, cx| element.layout(state, cx))
107 }
108
109 fn paint(
110 &mut self,
111 _: Bounds<Pixels>,
112 _: &mut (),
113 element: &mut Self::ElementState,
114 cx: &mut ViewContext<()>,
115 ) {
116 self.update(cx, |state, cx| element.paint(state, cx))
117 }
118}
119
120impl<T: 'static> EntityHandle<T> for View<T> {
121 type Weak = WeakView<T>;
122
123 fn entity_id(&self) -> EntityId {
124 self.state.entity_id
125 }
126
127 fn downgrade(&self) -> Self::Weak {
128 self.downgrade()
129 }
130
131 fn upgrade_from(weak: &Self::Weak) -> Option<Self>
132 where
133 Self: Sized,
134 {
135 weak.upgrade()
136 }
137}
138
139pub struct WeakView<V> {
140 pub(crate) state: WeakHandle<V>,
141 render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
142}
143
144impl<V: 'static> WeakView<V> {
145 pub fn upgrade(&self) -> Option<View<V>> {
146 let state = self.state.upgrade()?;
147 let render = self.render.upgrade()?;
148 Some(View { state, render })
149 }
150
151 pub fn update<C, R>(
152 &self,
153 cx: &mut C,
154 f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
155 ) -> Result<R>
156 where
157 C: VisualContext,
158 Result<C::Result<R>>: Flatten<R>,
159 {
160 let view = self.upgrade().context("error upgrading view")?;
161 Ok(view.update(cx, f)).flatten()
162 }
163}
164
165impl<V> Clone for WeakView<V> {
166 fn clone(&self) -> Self {
167 Self {
168 state: self.state.clone(),
169 render: self.render.clone(),
170 }
171 }
172}
173
174struct EraseViewState<V, ParentV> {
175 view: View<V>,
176 parent_view_state_type: PhantomData<ParentV>,
177}
178
179unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
180
181impl<V: 'static, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
182 fn render(self) -> AnyElement<ParentV> {
183 AnyElement::new(self)
184 }
185}
186
187impl<V: 'static, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
188 type ElementState = AnyBox;
189
190 fn id(&self) -> Option<ElementId> {
191 Element::id(&self.view)
192 }
193
194 fn initialize(
195 &mut self,
196 _: &mut ParentV,
197 _: Option<Self::ElementState>,
198 cx: &mut ViewContext<ParentV>,
199 ) -> Self::ElementState {
200 ViewObject::initialize(&mut self.view, cx)
201 }
202
203 fn layout(
204 &mut self,
205 _: &mut ParentV,
206 element: &mut Self::ElementState,
207 cx: &mut ViewContext<ParentV>,
208 ) -> LayoutId {
209 ViewObject::layout(&mut self.view, element, cx)
210 }
211
212 fn paint(
213 &mut self,
214 bounds: Bounds<Pixels>,
215 _: &mut ParentV,
216 element: &mut Self::ElementState,
217 cx: &mut ViewContext<ParentV>,
218 ) {
219 ViewObject::paint(&mut self.view, bounds, element, cx)
220 }
221}
222
223trait ViewObject: Send + Sync {
224 fn entity_id(&self) -> EntityId;
225 fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
226 fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
227 fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
228 fn as_any(&self) -> &dyn Any;
229}
230
231impl<V: 'static> ViewObject for View<V> {
232 fn entity_id(&self) -> EntityId {
233 self.state.entity_id
234 }
235
236 fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
237 cx.with_element_id(self.state.entity_id, |_global_id, cx| {
238 self.update(cx, |state, cx| {
239 let mut any_element = Box::new((self.render.lock())(state, cx));
240 any_element.initialize(state, cx);
241 any_element as AnyBox
242 })
243 })
244 }
245
246 fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
247 cx.with_element_id(self.state.entity_id, |_global_id, cx| {
248 self.update(cx, |state, cx| {
249 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
250 element.layout(state, cx)
251 })
252 })
253 }
254
255 fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
256 cx.with_element_id(self.state.entity_id, |_global_id, cx| {
257 self.update(cx, |state, cx| {
258 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
259 element.paint(state, cx);
260 });
261 });
262 }
263
264 fn as_any(&self) -> &dyn Any {
265 self
266 }
267}
268
269#[derive(Clone)]
270pub struct AnyView(Arc<dyn ViewObject>);
271
272impl AnyView {
273 pub fn downcast<V: 'static>(&self) -> Option<View<V>> {
274 self.0.as_any().downcast_ref().cloned()
275 }
276
277 pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
278 let mut rendered_element = self.0.initialize(cx);
279 let layout_id = self.0.layout(&mut rendered_element, cx);
280 cx.window
281 .layout_engine
282 .compute_layout(layout_id, available_space);
283 let bounds = cx.window.layout_engine.layout_bounds(layout_id);
284 self.0.paint(bounds, &mut rendered_element, cx);
285 }
286}
287
288impl<ParentV: 'static> Component<ParentV> for AnyView {
289 fn render(self) -> AnyElement<ParentV> {
290 AnyElement::new(EraseAnyViewState {
291 view: self,
292 parent_view_state_type: PhantomData,
293 })
294 }
295}
296
297impl Element<()> for AnyView {
298 type ElementState = AnyBox;
299
300 fn id(&self) -> Option<crate::ElementId> {
301 Some(ElementId::View(self.0.entity_id()))
302 }
303
304 fn initialize(
305 &mut self,
306 _: &mut (),
307 _: Option<Self::ElementState>,
308 cx: &mut ViewContext<()>,
309 ) -> Self::ElementState {
310 self.0.initialize(cx)
311 }
312
313 fn layout(
314 &mut self,
315 _: &mut (),
316 element: &mut Self::ElementState,
317 cx: &mut ViewContext<()>,
318 ) -> LayoutId {
319 self.0.layout(element, cx)
320 }
321
322 fn paint(
323 &mut self,
324 bounds: Bounds<Pixels>,
325 _: &mut (),
326 element: &mut AnyBox,
327 cx: &mut ViewContext<()>,
328 ) {
329 self.0.paint(bounds, element, cx)
330 }
331}
332
333struct EraseAnyViewState<ParentViewState> {
334 view: AnyView,
335 parent_view_state_type: PhantomData<ParentViewState>,
336}
337
338unsafe impl<ParentV> Send for EraseAnyViewState<ParentV> {}
339
340impl<ParentV: 'static> Component<ParentV> for EraseAnyViewState<ParentV> {
341 fn render(self) -> AnyElement<ParentV> {
342 AnyElement::new(self)
343 }
344}
345
346impl<ParentV: 'static> Element<ParentV> for EraseAnyViewState<ParentV> {
347 type ElementState = AnyBox;
348
349 fn id(&self) -> Option<ElementId> {
350 Element::id(&self.view)
351 }
352
353 fn initialize(
354 &mut self,
355 _: &mut ParentV,
356 _: Option<Self::ElementState>,
357 cx: &mut ViewContext<ParentV>,
358 ) -> Self::ElementState {
359 self.view.0.initialize(cx)
360 }
361
362 fn layout(
363 &mut self,
364 _: &mut ParentV,
365 element: &mut Self::ElementState,
366 cx: &mut ViewContext<ParentV>,
367 ) -> LayoutId {
368 self.view.0.layout(element, cx)
369 }
370
371 fn paint(
372 &mut self,
373 bounds: Bounds<Pixels>,
374 _: &mut ParentV,
375 element: &mut Self::ElementState,
376 cx: &mut ViewContext<ParentV>,
377 ) {
378 self.view.0.paint(bounds, element, cx)
379 }
380}