1use crate::{
2 private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
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::{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 pub(crate) fn draw_dispatch_stack(&self, cx: &mut WindowContext) {
189 (self.initialize)(self, cx);
190 }
191}
192
193impl<V: 'static> Component<V> for AnyView {
194 fn render(self) -> AnyElement<V> {
195 AnyElement::new(self)
196 }
197}
198
199impl<V: Render> From<View<V>> for AnyView {
200 fn from(value: View<V>) -> Self {
201 AnyView {
202 model: value.model.into_any(),
203 initialize: any_view::initialize::<V>,
204 layout: any_view::layout::<V>,
205 paint: any_view::paint::<V>,
206 }
207 }
208}
209
210impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
211 type ElementState = Box<dyn Any>;
212
213 fn id(&self) -> Option<ElementId> {
214 Some(self.model.entity_id.into())
215 }
216
217 fn initialize(
218 &mut self,
219 _view_state: &mut ParentViewState,
220 _element_state: Option<Self::ElementState>,
221 cx: &mut ViewContext<ParentViewState>,
222 ) -> Self::ElementState {
223 (self.initialize)(self, cx)
224 }
225
226 fn layout(
227 &mut self,
228 _view_state: &mut ParentViewState,
229 rendered_element: &mut Self::ElementState,
230 cx: &mut ViewContext<ParentViewState>,
231 ) -> LayoutId {
232 (self.layout)(self, rendered_element, cx)
233 }
234
235 fn paint(
236 &mut self,
237 _bounds: Bounds<Pixels>,
238 _view_state: &mut ParentViewState,
239 rendered_element: &mut Self::ElementState,
240 cx: &mut ViewContext<ParentViewState>,
241 ) {
242 (self.paint)(self, rendered_element, cx)
243 }
244}
245
246pub struct AnyWeakView {
247 model: AnyWeakModel,
248 initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
249 layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
250 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
251}
252
253impl AnyWeakView {
254 pub fn upgrade(&self) -> Option<AnyView> {
255 let model = self.model.upgrade()?;
256 Some(AnyView {
257 model,
258 initialize: self.initialize,
259 layout: self.layout,
260 paint: self.paint,
261 })
262 }
263}
264
265impl<V: Render> From<WeakView<V>> for AnyWeakView {
266 fn from(view: WeakView<V>) -> Self {
267 Self {
268 model: view.model.into(),
269 initialize: any_view::initialize::<V>,
270 layout: any_view::layout::<V>,
271 paint: any_view::paint::<V>,
272 }
273 }
274}
275
276impl<T, E> Render for T
277where
278 T: 'static + FnMut(&mut WindowContext) -> E,
279 E: 'static + Send + Element<T>,
280{
281 type Element = E;
282
283 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
284 (self)(cx)
285 }
286}
287
288mod any_view {
289 use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
290 use std::any::Any;
291
292 pub(crate) fn initialize<V: Render>(view: &AnyView, cx: &mut WindowContext) -> Box<dyn Any> {
293 cx.with_element_id(view.model.entity_id, |_, cx| {
294 let view = view.clone().downcast::<V>().unwrap();
295 let element = view.update(cx, |view, cx| {
296 let mut element = AnyElement::new(view.render(cx));
297 element.initialize(view, cx);
298 element
299 });
300 Box::new(element)
301 })
302 }
303
304 pub(crate) fn layout<V: Render>(
305 view: &AnyView,
306 element: &mut Box<dyn Any>,
307 cx: &mut WindowContext,
308 ) -> LayoutId {
309 cx.with_element_id(view.model.entity_id, |_, cx| {
310 let view = view.clone().downcast::<V>().unwrap();
311 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
312 view.update(cx, |view, cx| element.layout(view, cx))
313 })
314 }
315
316 pub(crate) fn paint<V: Render>(
317 view: &AnyView,
318 element: &mut Box<dyn Any>,
319 cx: &mut WindowContext,
320 ) {
321 cx.with_element_id(view.model.entity_id, |_, cx| {
322 let view = view.clone().downcast::<V>().unwrap();
323 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
324 view.update(cx, |view, cx| element.paint(view, cx))
325 })
326 }
327}