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