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