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: any_view::initialize::<V>,
200 layout: any_view::layout::<V>,
201 paint: any_view::paint::<V>,
202 }
203 }
204}
205
206impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
207 type ElementState = Box<dyn Any>;
208
209 fn element_id(&self) -> Option<ElementId> {
210 Some(self.model.entity_id.into())
211 }
212
213 fn initialize(
214 &mut self,
215 _view_state: &mut ParentViewState,
216 _element_state: Option<Self::ElementState>,
217 cx: &mut ViewContext<ParentViewState>,
218 ) -> Self::ElementState {
219 (self.initialize)(self, cx)
220 }
221
222 fn layout(
223 &mut self,
224 _view_state: &mut ParentViewState,
225 rendered_element: &mut Self::ElementState,
226 cx: &mut ViewContext<ParentViewState>,
227 ) -> LayoutId {
228 (self.layout)(self, rendered_element, cx)
229 }
230
231 fn paint(
232 &mut self,
233 _bounds: Bounds<Pixels>,
234 _view_state: &mut ParentViewState,
235 rendered_element: &mut Self::ElementState,
236 cx: &mut ViewContext<ParentViewState>,
237 ) {
238 (self.paint)(self, rendered_element, cx)
239 }
240}
241
242pub struct AnyWeakView {
243 model: AnyWeakModel,
244 initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
245 layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
246 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
247}
248
249impl AnyWeakView {
250 pub fn upgrade(&self) -> Option<AnyView> {
251 let model = self.model.upgrade()?;
252 Some(AnyView {
253 model,
254 initialize: self.initialize,
255 layout: self.layout,
256 paint: self.paint,
257 })
258 }
259}
260
261impl<V: Render> From<WeakView<V>> for AnyWeakView {
262 fn from(view: WeakView<V>) -> Self {
263 Self {
264 model: view.model.into(),
265 initialize: any_view::initialize::<V>,
266 layout: any_view::layout::<V>,
267 paint: any_view::paint::<V>,
268 }
269 }
270}
271
272impl<T, E> Render for T
273where
274 T: 'static + FnMut(&mut WindowContext) -> E,
275 E: 'static + Send + Element<T>,
276{
277 type Element = E;
278
279 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
280 (self)(cx)
281 }
282}
283
284pub struct RenderView<C, V> {
285 view: View<V>,
286 component: Option<C>,
287}
288
289impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderView<C, ViewState>
290where
291 C: 'static + Component<ViewState>,
292 ParentViewState: 'static,
293 ViewState: 'static,
294{
295 fn render(self) -> AnyElement<ParentViewState> {
296 AnyElement::new(self)
297 }
298}
299
300impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderView<C, ViewState>
301where
302 C: 'static + Component<ViewState>,
303 ParentViewState: 'static,
304 ViewState: 'static,
305{
306 type ElementState = AnyElement<ViewState>;
307
308 fn element_id(&self) -> Option<ElementId> {
309 Some(self.view.entity_id().into())
310 }
311
312 fn initialize(
313 &mut self,
314 _: &mut ParentViewState,
315 _: Option<Self::ElementState>,
316 cx: &mut ViewContext<ParentViewState>,
317 ) -> Self::ElementState {
318 cx.with_element_id(Some(self.view.entity_id()), |cx| {
319 self.view.update(cx, |view, cx| {
320 let mut element = self.component.take().unwrap().render();
321 element.initialize(view, cx);
322 element
323 })
324 })
325 }
326
327 fn layout(
328 &mut self,
329 _: &mut ParentViewState,
330 element: &mut Self::ElementState,
331 cx: &mut ViewContext<ParentViewState>,
332 ) -> LayoutId {
333 cx.with_element_id(Some(self.view.entity_id()), |cx| {
334 self.view.update(cx, |view, cx| element.layout(view, cx))
335 })
336 }
337
338 fn paint(
339 &mut self,
340 _: Bounds<Pixels>,
341 _: &mut ParentViewState,
342 element: &mut Self::ElementState,
343 cx: &mut ViewContext<ParentViewState>,
344 ) {
345 cx.with_element_id(Some(self.view.entity_id()), |cx| {
346 self.view.update(cx, |view, cx| element.paint(view, cx))
347 })
348 }
349}
350
351pub fn render_view<C, V>(view: &View<V>, component: C) -> RenderView<C, V>
352where
353 C: 'static + Component<V>,
354 V: 'static,
355{
356 RenderView {
357 view: view.clone(),
358 component: Some(component),
359 }
360}
361
362mod any_view {
363 use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
364 use std::any::Any;
365
366 pub(crate) fn initialize<V: Render>(view: &AnyView, cx: &mut WindowContext) -> Box<dyn Any> {
367 cx.with_element_id(Some(view.model.entity_id), |cx| {
368 let view = view.clone().downcast::<V>().unwrap();
369 let element = view.update(cx, |view, cx| {
370 let mut element = AnyElement::new(view.render(cx));
371 element.initialize(view, cx);
372 element
373 });
374 Box::new(element)
375 })
376 }
377
378 pub(crate) fn layout<V: Render>(
379 view: &AnyView,
380 element: &mut Box<dyn Any>,
381 cx: &mut WindowContext,
382 ) -> LayoutId {
383 cx.with_element_id(Some(view.model.entity_id), |cx| {
384 let view = view.clone().downcast::<V>().unwrap();
385 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
386 view.update(cx, |view, cx| element.layout(view, cx))
387 })
388 }
389
390 pub(crate) fn paint<V: Render>(
391 view: &AnyView,
392 element: &mut Box<dyn Any>,
393 cx: &mut WindowContext,
394 ) {
395 cx.with_element_id(Some(view.model.entity_id), |cx| {
396 let view = view.clone().downcast::<V>().unwrap();
397 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
398 view.update(cx, |view, cx| element.paint(view, cx))
399 })
400 }
401}