1use crate::{
2 private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
3 BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId,
4 Model, Pixels, Point, 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 pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
68 where
69 C: 'static + Component<V>,
70 {
71 RenderViewWith {
72 view: self.clone(),
73 component: Some(component),
74 }
75 }
76}
77
78impl<V> Clone for View<V> {
79 fn clone(&self) -> Self {
80 Self {
81 model: self.model.clone(),
82 }
83 }
84}
85
86impl<V> Hash for View<V> {
87 fn hash<H: Hasher>(&self, state: &mut H) {
88 self.model.hash(state);
89 }
90}
91
92impl<V> PartialEq for View<V> {
93 fn eq(&self, other: &Self) -> bool {
94 self.model == other.model
95 }
96}
97
98impl<V> Eq for View<V> {}
99
100impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
101 fn render(self) -> AnyElement<ParentViewState> {
102 AnyElement::new(AnyView::from(self))
103 }
104}
105
106pub struct WeakView<V> {
107 pub(crate) model: WeakModel<V>,
108}
109
110impl<V: 'static> WeakView<V> {
111 pub fn entity_id(&self) -> EntityId {
112 self.model.entity_id
113 }
114
115 pub fn upgrade(&self) -> Option<View<V>> {
116 Entity::upgrade_from(self)
117 }
118
119 pub fn update<C, R>(
120 &self,
121 cx: &mut C,
122 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
123 ) -> Result<R>
124 where
125 C: VisualContext,
126 Result<C::Result<R>>: Flatten<R>,
127 {
128 let view = self.upgrade().context("error upgrading view")?;
129 Ok(view.update(cx, f)).flatten()
130 }
131}
132
133impl<V> Clone for WeakView<V> {
134 fn clone(&self) -> Self {
135 Self {
136 model: self.model.clone(),
137 }
138 }
139}
140
141impl<V> Hash for WeakView<V> {
142 fn hash<H: Hasher>(&self, state: &mut H) {
143 self.model.hash(state);
144 }
145}
146
147impl<V> PartialEq for WeakView<V> {
148 fn eq(&self, other: &Self) -> bool {
149 self.model == other.model
150 }
151}
152
153impl<V> Eq for WeakView<V> {}
154
155#[derive(Clone, Debug)]
156pub struct AnyView {
157 model: AnyModel,
158 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
159 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
160}
161
162impl AnyView {
163 pub fn downgrade(&self) -> AnyWeakView {
164 AnyWeakView {
165 model: self.model.downgrade(),
166 layout: self.layout,
167 paint: self.paint,
168 }
169 }
170
171 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
172 match self.model.downcast() {
173 Ok(model) => Ok(View { model }),
174 Err(model) => Err(Self {
175 model,
176 layout: self.layout,
177 paint: self.paint,
178 }),
179 }
180 }
181
182 pub fn entity_type(&self) -> TypeId {
183 self.model.entity_type
184 }
185
186 pub(crate) fn draw(
187 &self,
188 origin: Point<Pixels>,
189 available_space: Size<AvailableSpace>,
190 cx: &mut WindowContext,
191 ) {
192 cx.with_absolute_element_offset(origin, |cx| {
193 let (layout_id, mut rendered_element) = (self.layout)(self, cx);
194 cx.window
195 .layout_engine
196 .compute_layout(layout_id, available_space);
197 (self.paint)(self, &mut rendered_element, cx);
198 })
199 }
200}
201
202impl<V: 'static> Component<V> for AnyView {
203 fn render(self) -> AnyElement<V> {
204 AnyElement::new(self)
205 }
206}
207
208impl<V: Render> From<View<V>> for AnyView {
209 fn from(value: View<V>) -> Self {
210 AnyView {
211 model: value.model.into_any(),
212 layout: any_view::layout::<V>,
213 paint: any_view::paint::<V>,
214 }
215 }
216}
217
218impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
219 type ElementState = Box<dyn Any>;
220
221 fn element_id(&self) -> Option<ElementId> {
222 Some(self.model.entity_id.into())
223 }
224
225 fn layout(
226 &mut self,
227 _view_state: &mut ParentViewState,
228 _element_state: Option<Self::ElementState>,
229 cx: &mut ViewContext<ParentViewState>,
230 ) -> (LayoutId, Self::ElementState) {
231 (self.layout)(self, cx)
232 }
233
234 fn paint(
235 &mut self,
236 _bounds: Bounds<Pixels>,
237 _view_state: &mut ParentViewState,
238 rendered_element: &mut Self::ElementState,
239 cx: &mut ViewContext<ParentViewState>,
240 ) {
241 (self.paint)(self, rendered_element, cx)
242 }
243}
244
245pub struct AnyWeakView {
246 model: AnyWeakModel,
247 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
248 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
249}
250
251impl AnyWeakView {
252 pub fn upgrade(&self) -> Option<AnyView> {
253 let model = self.model.upgrade()?;
254 Some(AnyView {
255 model,
256 layout: self.layout,
257 paint: self.paint,
258 })
259 }
260}
261
262impl<V: Render> From<WeakView<V>> for AnyWeakView {
263 fn from(view: WeakView<V>) -> Self {
264 Self {
265 model: view.model.into(),
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 RenderViewWith<C, V> {
285 view: View<V>,
286 component: Option<C>,
287}
288
289impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<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 RenderViewWith<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 layout(
313 &mut self,
314 _: &mut ParentViewState,
315 _: Option<Self::ElementState>,
316 cx: &mut ViewContext<ParentViewState>,
317 ) -> (LayoutId, Self::ElementState) {
318 self.view.update(cx, |view, cx| {
319 let mut element = self.component.take().unwrap().render();
320 let layout_id = element.layout(view, cx);
321 (layout_id, element)
322 })
323 }
324
325 fn paint(
326 &mut self,
327 _: Bounds<Pixels>,
328 _: &mut ParentViewState,
329 element: &mut Self::ElementState,
330 cx: &mut ViewContext<ParentViewState>,
331 ) {
332 self.view.update(cx, |view, cx| element.paint(view, cx))
333 }
334}
335
336mod any_view {
337 use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
338 use std::any::Any;
339
340 pub(crate) fn layout<V: Render>(
341 view: &AnyView,
342 cx: &mut WindowContext,
343 ) -> (LayoutId, Box<dyn Any>) {
344 cx.with_element_id(Some(view.model.entity_id), |cx| {
345 let view = view.clone().downcast::<V>().unwrap();
346 view.update(cx, |view, cx| {
347 let mut element = AnyElement::new(view.render(cx));
348 let layout_id = element.layout(view, cx);
349 (layout_id, Box::new(element) as Box<dyn Any>)
350 })
351 })
352 }
353
354 pub(crate) fn paint<V: Render>(
355 view: &AnyView,
356 element: &mut Box<dyn Any>,
357 cx: &mut WindowContext,
358 ) {
359 cx.with_element_id(Some(view.model.entity_id), |cx| {
360 let view = view.clone().downcast::<V>().unwrap();
361 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
362 view.update(cx, |view, cx| element.paint(view, cx))
363 })
364 }
365}