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