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