1use crate::{
2 private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
3 BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, FocusHandle,
4 FocusableView, LayoutId, Model, Pixels, Point, Size, ViewContext, VisualContext, WeakModel,
5 WindowContext,
6};
7use anyhow::{Context, Result};
8use std::{
9 any::{Any, TypeId},
10 hash::{Hash, Hasher},
11};
12
13pub trait Render: 'static + Sized {
14 type Element: Element<Self> + 'static;
15
16 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
17}
18
19pub struct View<V> {
20 pub(crate) model: Model<V>,
21}
22
23impl<V> Sealed for View<V> {}
24
25impl<V: 'static> Entity<V> for View<V> {
26 type Weak = WeakView<V>;
27
28 fn entity_id(&self) -> EntityId {
29 self.model.entity_id
30 }
31
32 fn downgrade(&self) -> Self::Weak {
33 WeakView {
34 model: self.model.downgrade(),
35 }
36 }
37
38 fn upgrade_from(weak: &Self::Weak) -> Option<Self>
39 where
40 Self: Sized,
41 {
42 let model = weak.model.upgrade()?;
43 Some(View { model })
44 }
45}
46
47impl<V: 'static> View<V> {
48 /// Convert this strong view reference into a weak view reference.
49 pub fn downgrade(&self) -> WeakView<V> {
50 Entity::downgrade(self)
51 }
52
53 pub fn update<C, R>(
54 &self,
55 cx: &mut C,
56 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
57 ) -> C::Result<R>
58 where
59 C: VisualContext,
60 {
61 cx.update_view(self, f)
62 }
63
64 pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
65 self.model.read(cx)
66 }
67
68 pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
69 where
70 C: 'static + Component<V>,
71 {
72 RenderViewWith {
73 view: self.clone(),
74 component: Some(component),
75 }
76 }
77
78 pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
79 where
80 V: FocusableView,
81 {
82 self.read(cx).focus_handle(cx)
83 }
84}
85
86impl<V> Clone for View<V> {
87 fn clone(&self) -> Self {
88 Self {
89 model: self.model.clone(),
90 }
91 }
92}
93
94impl<V> Hash for View<V> {
95 fn hash<H: Hasher>(&self, state: &mut H) {
96 self.model.hash(state);
97 }
98}
99
100impl<V> PartialEq for View<V> {
101 fn eq(&self, other: &Self) -> bool {
102 self.model == other.model
103 }
104}
105
106impl<V> Eq for View<V> {}
107
108impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
109 fn render(self) -> AnyElement<ParentViewState> {
110 AnyElement::new(AnyView::from(self))
111 }
112}
113
114pub struct WeakView<V> {
115 pub(crate) model: WeakModel<V>,
116}
117
118impl<V: 'static> WeakView<V> {
119 pub fn entity_id(&self) -> EntityId {
120 self.model.entity_id
121 }
122
123 pub fn upgrade(&self) -> Option<View<V>> {
124 Entity::upgrade_from(self)
125 }
126
127 pub fn update<C, R>(
128 &self,
129 cx: &mut C,
130 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
131 ) -> Result<R>
132 where
133 C: VisualContext,
134 Result<C::Result<R>>: Flatten<R>,
135 {
136 let view = self.upgrade().context("error upgrading view")?;
137 Ok(view.update(cx, f)).flatten()
138 }
139}
140
141impl<V> Clone for WeakView<V> {
142 fn clone(&self) -> Self {
143 Self {
144 model: self.model.clone(),
145 }
146 }
147}
148
149impl<V> Hash for WeakView<V> {
150 fn hash<H: Hasher>(&self, state: &mut H) {
151 self.model.hash(state);
152 }
153}
154
155impl<V> PartialEq for WeakView<V> {
156 fn eq(&self, other: &Self) -> bool {
157 self.model == other.model
158 }
159}
160
161impl<V> Eq for WeakView<V> {}
162
163#[derive(Clone, Debug)]
164pub struct AnyView {
165 model: AnyModel,
166 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
167 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
168}
169
170impl AnyView {
171 pub fn downgrade(&self) -> AnyWeakView {
172 AnyWeakView {
173 model: self.model.downgrade(),
174 layout: self.layout,
175 paint: self.paint,
176 }
177 }
178
179 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
180 match self.model.downcast() {
181 Ok(model) => Ok(View { model }),
182 Err(model) => Err(Self {
183 model,
184 layout: self.layout,
185 paint: self.paint,
186 }),
187 }
188 }
189
190 pub fn entity_type(&self) -> TypeId {
191 self.model.entity_type
192 }
193
194 pub fn entity_id(&self) -> EntityId {
195 self.model.entity_id()
196 }
197
198 pub(crate) fn draw(
199 &self,
200 origin: Point<Pixels>,
201 available_space: Size<AvailableSpace>,
202 cx: &mut WindowContext,
203 ) {
204 cx.with_absolute_element_offset(origin, |cx| {
205 let (layout_id, mut rendered_element) = (self.layout)(self, cx);
206 cx.window
207 .layout_engine
208 .compute_layout(layout_id, available_space);
209 (self.paint)(self, &mut rendered_element, cx);
210 })
211 }
212}
213
214impl<V: 'static> Component<V> for AnyView {
215 fn render(self) -> AnyElement<V> {
216 AnyElement::new(self)
217 }
218}
219
220impl<V: Render> From<View<V>> for AnyView {
221 fn from(value: View<V>) -> Self {
222 AnyView {
223 model: value.model.into_any(),
224 layout: any_view::layout::<V>,
225 paint: any_view::paint::<V>,
226 }
227 }
228}
229
230impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
231 type ElementState = Box<dyn Any>;
232
233 fn element_id(&self) -> Option<ElementId> {
234 Some(self.model.entity_id.into())
235 }
236
237 fn layout(
238 &mut self,
239 _view_state: &mut ParentViewState,
240 _element_state: Option<Self::ElementState>,
241 cx: &mut ViewContext<ParentViewState>,
242 ) -> (LayoutId, Self::ElementState) {
243 (self.layout)(self, cx)
244 }
245
246 fn paint(
247 &mut self,
248 _bounds: Bounds<Pixels>,
249 _view_state: &mut ParentViewState,
250 rendered_element: &mut Self::ElementState,
251 cx: &mut ViewContext<ParentViewState>,
252 ) {
253 (self.paint)(self, rendered_element, cx)
254 }
255}
256
257pub struct AnyWeakView {
258 model: AnyWeakModel,
259 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
260 paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
261}
262
263impl AnyWeakView {
264 pub fn upgrade(&self) -> Option<AnyView> {
265 let model = self.model.upgrade()?;
266 Some(AnyView {
267 model,
268 layout: self.layout,
269 paint: self.paint,
270 })
271 }
272}
273
274impl<V: Render> From<WeakView<V>> for AnyWeakView {
275 fn from(view: WeakView<V>) -> Self {
276 Self {
277 model: view.model.into(),
278 layout: any_view::layout::<V>,
279 paint: any_view::paint::<V>,
280 }
281 }
282}
283
284// impl<T, E> Render for T
285// where
286// T: 'static + FnMut(&mut WindowContext) -> E,
287// E: 'static + Send + Element<T>,
288// {
289// type Element = E;
290
291// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
292// (self)(cx)
293// }
294// }
295
296pub struct RenderViewWith<C, V> {
297 view: View<V>,
298 component: Option<C>,
299}
300
301impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<C, ViewState>
302where
303 C: 'static + Component<ViewState>,
304 ParentViewState: 'static,
305 ViewState: 'static,
306{
307 fn render(self) -> AnyElement<ParentViewState> {
308 AnyElement::new(self)
309 }
310}
311
312impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderViewWith<C, ViewState>
313where
314 C: 'static + Component<ViewState>,
315 ParentViewState: 'static,
316 ViewState: 'static,
317{
318 type ElementState = AnyElement<ViewState>;
319
320 fn element_id(&self) -> Option<ElementId> {
321 Some(self.view.entity_id().into())
322 }
323
324 fn layout(
325 &mut self,
326 _: &mut ParentViewState,
327 _: Option<Self::ElementState>,
328 cx: &mut ViewContext<ParentViewState>,
329 ) -> (LayoutId, Self::ElementState) {
330 self.view.update(cx, |view, cx| {
331 let mut element = self.component.take().unwrap().render();
332 let layout_id = element.layout(view, cx);
333 (layout_id, element)
334 })
335 }
336
337 fn paint(
338 &mut self,
339 _: Bounds<Pixels>,
340 _: &mut ParentViewState,
341 element: &mut Self::ElementState,
342 cx: &mut ViewContext<ParentViewState>,
343 ) {
344 self.view.update(cx, |view, cx| element.paint(view, cx))
345 }
346}
347
348mod any_view {
349 use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
350 use std::any::Any;
351
352 pub(crate) fn layout<V: Render>(
353 view: &AnyView,
354 cx: &mut WindowContext,
355 ) -> (LayoutId, Box<dyn Any>) {
356 cx.with_element_id(Some(view.model.entity_id), |cx| {
357 let view = view.clone().downcast::<V>().unwrap();
358 view.update(cx, |view, cx| {
359 let mut element = AnyElement::new(view.render(cx));
360 let layout_id = element.layout(view, cx);
361 (layout_id, Box::new(element) as Box<dyn Any>)
362 })
363 })
364 }
365
366 pub(crate) fn paint<V: Render>(
367 view: &AnyView,
368 element: &mut Box<dyn Any>,
369 cx: &mut WindowContext,
370 ) {
371 cx.with_element_id(Some(view.model.entity_id), |cx| {
372 let view = view.clone().downcast::<V>().unwrap();
373 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
374 view.update(cx, |view, cx| element.paint(view, cx))
375 })
376 }
377}