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