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::{Any, TypeId},
9 hash::{Hash, Hasher},
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 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> Hash for View<V> {
77 fn hash<H: Hasher>(&self, state: &mut H) {
78 self.model.hash(state);
79 }
80}
81
82impl<V> PartialEq for View<V> {
83 fn eq(&self, other: &Self) -> bool {
84 self.model == other.model
85 }
86}
87
88impl<V> Eq for View<V> {}
89
90impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
91 fn render(self) -> AnyElement<ParentViewState> {
92 AnyElement::new(AnyView::from(self))
93 }
94}
95
96pub struct WeakView<V> {
97 pub(crate) model: WeakModel<V>,
98}
99
100impl<V: 'static> WeakView<V> {
101 pub fn entity_id(&self) -> EntityId {
102 self.model.entity_id
103 }
104
105 pub fn upgrade(&self) -> Option<View<V>> {
106 Entity::upgrade_from(self)
107 }
108
109 pub fn update<C, R>(
110 &self,
111 cx: &mut C,
112 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
113 ) -> Result<R>
114 where
115 C: VisualContext,
116 Result<C::Result<R>>: Flatten<R>,
117 {
118 let view = self.upgrade().context("error upgrading view")?;
119 Ok(view.update(cx, f)).flatten()
120 }
121}
122
123impl<V> Clone for WeakView<V> {
124 fn clone(&self) -> Self {
125 Self {
126 model: self.model.clone(),
127 }
128 }
129}
130
131impl<V> Hash for WeakView<V> {
132 fn hash<H: Hasher>(&self, state: &mut H) {
133 self.model.hash(state);
134 }
135}
136
137impl<V> PartialEq for WeakView<V> {
138 fn eq(&self, other: &Self) -> bool {
139 self.model == other.model
140 }
141}
142
143impl<V> Eq for WeakView<V> {}
144
145#[derive(Clone, Debug)]
146pub struct AnyView {
147 model: AnyModel,
148 initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
149 layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
150 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
151}
152
153impl AnyView {
154 pub fn downgrade(&self) -> AnyWeakView {
155 AnyWeakView {
156 model: self.model.downgrade(),
157 initialize: self.initialize,
158 layout: self.layout,
159 paint: self.paint,
160 }
161 }
162
163 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
164 match self.model.downcast() {
165 Ok(model) => Ok(View { model }),
166 Err(model) => Err(Self {
167 model,
168 initialize: self.initialize,
169 layout: self.layout,
170 paint: self.paint,
171 }),
172 }
173 }
174
175 pub fn entity_type(&self) -> TypeId {
176 self.model.entity_type
177 }
178
179 pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
180 let mut rendered_element = (self.initialize)(self, cx);
181 let layout_id = (self.layout)(self, &mut rendered_element, cx);
182 cx.window
183 .layout_engine
184 .compute_layout(layout_id, available_space);
185 (self.paint)(self, &mut rendered_element, cx);
186 }
187}
188
189impl<V: 'static> Component<V> for AnyView {
190 fn render(self) -> AnyElement<V> {
191 AnyElement::new(self)
192 }
193}
194
195impl<V: Render> From<View<V>> for AnyView {
196 fn from(value: View<V>) -> Self {
197 AnyView {
198 model: value.model.into_any(),
199 initialize: |view, cx| {
200 cx.with_element_id(view.model.entity_id, |_, cx| {
201 let view = view.clone().downcast::<V>().unwrap();
202 let element = view.update(cx, |view, cx| {
203 let mut element = AnyElement::new(view.render(cx));
204 element.initialize(view, cx);
205 element
206 });
207 Box::new(element)
208 })
209 },
210 layout: |view, element, cx| {
211 cx.with_element_id(view.model.entity_id, |_, cx| {
212 let view = view.clone().downcast::<V>().unwrap();
213 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
214 view.update(cx, |view, cx| element.layout(view, cx))
215 })
216 },
217 paint: |view, element, cx| {
218 cx.with_element_id(view.model.entity_id, |_, cx| {
219 let view = view.clone().downcast::<V>().unwrap();
220 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
221 view.update(cx, |view, cx| element.paint(view, cx))
222 })
223 },
224 }
225 }
226}
227
228impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
229 type ElementState = Box<dyn Any>;
230
231 fn id(&self) -> Option<ElementId> {
232 Some(self.model.entity_id.into())
233 }
234
235 fn initialize(
236 &mut self,
237 _view_state: &mut ParentViewState,
238 _element_state: Option<Self::ElementState>,
239 cx: &mut ViewContext<ParentViewState>,
240 ) -> Self::ElementState {
241 (self.initialize)(self, cx)
242 }
243
244 fn layout(
245 &mut self,
246 _view_state: &mut ParentViewState,
247 rendered_element: &mut Self::ElementState,
248 cx: &mut ViewContext<ParentViewState>,
249 ) -> LayoutId {
250 (self.layout)(self, rendered_element, cx)
251 }
252
253 fn paint(
254 &mut self,
255 _bounds: Bounds<Pixels>,
256 _view_state: &mut ParentViewState,
257 rendered_element: &mut Self::ElementState,
258 cx: &mut ViewContext<ParentViewState>,
259 ) {
260 (self.paint)(self, rendered_element, cx)
261 }
262}
263
264pub struct AnyWeakView {
265 model: AnyWeakModel,
266 initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
267 layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
268 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
269}
270
271impl AnyWeakView {
272 pub fn upgrade(&self) -> Option<AnyView> {
273 let model = self.model.upgrade()?;
274 Some(AnyView {
275 model,
276 initialize: self.initialize,
277 layout: self.layout,
278 paint: self.paint,
279 })
280 }
281}
282
283impl<T, E> Render for T
284where
285 T: 'static + FnMut(&mut WindowContext) -> E,
286 E: 'static + Send + Element<T>,
287{
288 type Element = E;
289
290 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
291 (self)(cx)
292 }
293}