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