1use crate::Empty;
2use crate::{
3 seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, Bounds, ContentMask, Element,
4 ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, GlobalElementId, IntoElement,
5 LayoutId, Model, PaintIndex, Pixels, PrepaintStateIndex, Render, Style, StyleRefinement,
6 TextStyle, ViewContext, VisualContext, WeakModel, WindowContext,
7};
8use anyhow::{Context, Result};
9use refineable::Refineable;
10use std::mem;
11use std::{
12 any::{type_name, TypeId},
13 fmt,
14 hash::{Hash, Hasher},
15 ops::Range,
16};
17
18/// A view is a piece of state that can be presented on screen by implementing the [Render] trait.
19/// Views implement [Element] and can composed with other views, and every window is created with a root view.
20pub struct View<V> {
21 /// A view is just a [Model] whose type implements `Render`, and the model is accessible via this field.
22 pub model: Model<V>,
23}
24
25impl<V> Sealed for View<V> {}
26
27struct AnyViewState {
28 prepaint_range: Range<PrepaintStateIndex>,
29 paint_range: Range<PaintIndex>,
30 cache_key: ViewCacheKey,
31}
32
33#[derive(Default)]
34struct ViewCacheKey {
35 bounds: Bounds<Pixels>,
36 content_mask: ContentMask<Pixels>,
37 text_style: TextStyle,
38}
39
40impl<V: 'static> Entity<V> for View<V> {
41 type Weak = WeakView<V>;
42
43 fn entity_id(&self) -> EntityId {
44 self.model.entity_id
45 }
46
47 fn downgrade(&self) -> Self::Weak {
48 WeakView {
49 model: self.model.downgrade(),
50 }
51 }
52
53 fn upgrade_from(weak: &Self::Weak) -> Option<Self>
54 where
55 Self: Sized,
56 {
57 let model = weak.model.upgrade()?;
58 Some(View { model })
59 }
60}
61
62impl<V: 'static> View<V> {
63 /// Convert this strong view reference into a weak view reference.
64 pub fn downgrade(&self) -> WeakView<V> {
65 Entity::downgrade(self)
66 }
67
68 /// Updates the view's state with the given function, which is passed a mutable reference and a context.
69 pub fn update<C, R>(
70 &self,
71 cx: &mut C,
72 f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
73 ) -> C::Result<R>
74 where
75 C: VisualContext,
76 {
77 cx.update_view(self, f)
78 }
79
80 /// Obtain a read-only reference to this view's state.
81 pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
82 self.model.read(cx)
83 }
84
85 /// Gets a [FocusHandle] for this view when its state implements [FocusableView].
86 pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
87 where
88 V: FocusableView,
89 {
90 self.read(cx).focus_handle(cx)
91 }
92}
93
94impl<V: Render> Element for View<V> {
95 type RequestLayoutState = AnyElement;
96 type PrepaintState = ();
97
98 fn id(&self) -> Option<ElementId> {
99 Some(ElementId::View(self.entity_id()))
100 }
101
102 fn request_layout(
103 &mut self,
104 _id: Option<&GlobalElementId>,
105 cx: &mut WindowContext,
106 ) -> (LayoutId, Self::RequestLayoutState) {
107 let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
108 let layout_id = element.request_layout(cx);
109 (layout_id, element)
110 }
111
112 fn prepaint(
113 &mut self,
114 _id: Option<&GlobalElementId>,
115 _: Bounds<Pixels>,
116 element: &mut Self::RequestLayoutState,
117 cx: &mut WindowContext,
118 ) {
119 cx.set_view_id(self.entity_id());
120 element.prepaint(cx);
121 }
122
123 fn paint(
124 &mut self,
125 _id: Option<&GlobalElementId>,
126 _: Bounds<Pixels>,
127 element: &mut Self::RequestLayoutState,
128 _: &mut Self::PrepaintState,
129 cx: &mut WindowContext,
130 ) {
131 element.paint(cx);
132 }
133}
134
135impl<V> Clone for View<V> {
136 fn clone(&self) -> Self {
137 Self {
138 model: self.model.clone(),
139 }
140 }
141}
142
143impl<T> std::fmt::Debug for View<T> {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 f.debug_struct(&format!("View<{}>", type_name::<T>()))
146 .field("entity_id", &self.model.entity_id)
147 .finish_non_exhaustive()
148 }
149}
150
151impl<V> Hash for View<V> {
152 fn hash<H: Hasher>(&self, state: &mut H) {
153 self.model.hash(state);
154 }
155}
156
157impl<V> PartialEq for View<V> {
158 fn eq(&self, other: &Self) -> bool {
159 self.model == other.model
160 }
161}
162
163impl<V> Eq for View<V> {}
164
165/// A weak variant of [View] which does not prevent the view from being released.
166pub struct WeakView<V> {
167 pub(crate) model: WeakModel<V>,
168}
169
170impl<V: 'static> WeakView<V> {
171 /// Gets the entity id associated with this handle.
172 pub fn entity_id(&self) -> EntityId {
173 self.model.entity_id
174 }
175
176 /// Obtain a strong handle for the view if it hasn't been released.
177 pub fn upgrade(&self) -> Option<View<V>> {
178 Entity::upgrade_from(self)
179 }
180
181 /// Updates this view's state if it hasn't been released.
182 /// Returns an error if this view has been released.
183 pub fn update<C, R>(
184 &self,
185 cx: &mut C,
186 f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
187 ) -> Result<R>
188 where
189 C: VisualContext,
190 Result<C::Result<R>>: Flatten<R>,
191 {
192 let view = self.upgrade().context("error upgrading view")?;
193 Ok(view.update(cx, f)).flatten()
194 }
195
196 /// Assert that the view referenced by this handle has been released.
197 #[cfg(any(test, feature = "test-support"))]
198 pub fn assert_released(&self) {
199 self.model.assert_released()
200 }
201}
202
203impl<V> Clone for WeakView<V> {
204 fn clone(&self) -> Self {
205 Self {
206 model: self.model.clone(),
207 }
208 }
209}
210
211impl<V> Hash for WeakView<V> {
212 fn hash<H: Hasher>(&self, state: &mut H) {
213 self.model.hash(state);
214 }
215}
216
217impl<V> PartialEq for WeakView<V> {
218 fn eq(&self, other: &Self) -> bool {
219 self.model == other.model
220 }
221}
222
223impl<V> Eq for WeakView<V> {}
224
225/// A dynamically-typed handle to a view, which can be downcast to a [View] for a specific type.
226#[derive(Clone, Debug)]
227pub struct AnyView {
228 model: AnyModel,
229 render: fn(&AnyView, &mut WindowContext) -> AnyElement,
230 cached_style: Option<StyleRefinement>,
231}
232
233impl AnyView {
234 /// Indicate that this view should be cached when using it as an element.
235 /// When using this method, the view's previous layout and paint will be recycled from the previous frame if [ViewContext::notify] has not been called since it was rendered.
236 /// The one exception is when [WindowContext::refresh] is called, in which case caching is ignored.
237 pub fn cached(mut self, style: StyleRefinement) -> Self {
238 self.cached_style = Some(style);
239 self
240 }
241
242 /// Convert this to a weak handle.
243 pub fn downgrade(&self) -> AnyWeakView {
244 AnyWeakView {
245 model: self.model.downgrade(),
246 render: self.render,
247 }
248 }
249
250 /// Convert this to a [View] of a specific type.
251 /// If this handle does not contain a view of the specified type, returns itself in an `Err` variant.
252 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
253 match self.model.downcast() {
254 Ok(model) => Ok(View { model }),
255 Err(model) => Err(Self {
256 model,
257 render: self.render,
258 cached_style: self.cached_style,
259 }),
260 }
261 }
262
263 /// Gets the [TypeId] of the underlying view.
264 pub fn entity_type(&self) -> TypeId {
265 self.model.entity_type
266 }
267
268 /// Gets the entity id of this handle.
269 pub fn entity_id(&self) -> EntityId {
270 self.model.entity_id()
271 }
272}
273
274impl<V: Render> From<View<V>> for AnyView {
275 fn from(value: View<V>) -> Self {
276 AnyView {
277 model: value.model.into_any(),
278 render: any_view::render::<V>,
279 cached_style: None,
280 }
281 }
282}
283
284impl PartialEq for AnyView {
285 fn eq(&self, other: &Self) -> bool {
286 self.model == other.model
287 }
288}
289
290impl Eq for AnyView {}
291
292impl Element for AnyView {
293 type RequestLayoutState = Option<AnyElement>;
294 type PrepaintState = Option<AnyElement>;
295
296 fn id(&self) -> Option<ElementId> {
297 Some(ElementId::View(self.entity_id()))
298 }
299
300 fn request_layout(
301 &mut self,
302 _id: Option<&GlobalElementId>,
303 cx: &mut WindowContext,
304 ) -> (LayoutId, Self::RequestLayoutState) {
305 if let Some(style) = self.cached_style.as_ref() {
306 let mut root_style = Style::default();
307 root_style.refine(style);
308 let layout_id = cx.request_layout(root_style, None);
309 (layout_id, None)
310 } else {
311 let mut element = (self.render)(self, cx);
312 let layout_id = element.request_layout(cx);
313 (layout_id, Some(element))
314 }
315 }
316
317 fn prepaint(
318 &mut self,
319 global_id: Option<&GlobalElementId>,
320 bounds: Bounds<Pixels>,
321 element: &mut Self::RequestLayoutState,
322 cx: &mut WindowContext,
323 ) -> Option<AnyElement> {
324 cx.set_view_id(self.entity_id());
325 if self.cached_style.is_some() {
326 cx.with_element_state::<AnyViewState, _>(global_id.unwrap(), |element_state, cx| {
327 let content_mask = cx.content_mask();
328 let text_style = cx.text_style();
329
330 if let Some(mut element_state) = element_state {
331 if element_state.cache_key.bounds == bounds
332 && element_state.cache_key.content_mask == content_mask
333 && element_state.cache_key.text_style == text_style
334 && !cx.window.dirty_views.contains(&self.entity_id())
335 && !cx.window.refreshing
336 {
337 let prepaint_start = cx.prepaint_index();
338 cx.reuse_prepaint(element_state.prepaint_range.clone());
339 let prepaint_end = cx.prepaint_index();
340 element_state.prepaint_range = prepaint_start..prepaint_end;
341 return (None, element_state);
342 }
343 }
344
345 let refreshing = mem::replace(&mut cx.window.refreshing, true);
346 let prepaint_start = cx.prepaint_index();
347 let mut element = (self.render)(self, cx);
348 element.layout_as_root(bounds.size.into(), cx);
349 element.prepaint_at(bounds.origin, cx);
350 let prepaint_end = cx.prepaint_index();
351 cx.window.refreshing = refreshing;
352
353 (
354 Some(element),
355 AnyViewState {
356 prepaint_range: prepaint_start..prepaint_end,
357 paint_range: PaintIndex::default()..PaintIndex::default(),
358 cache_key: ViewCacheKey {
359 bounds,
360 content_mask,
361 text_style,
362 },
363 },
364 )
365 })
366 } else {
367 let mut element = element.take().unwrap();
368 element.prepaint(cx);
369 Some(element)
370 }
371 }
372
373 fn paint(
374 &mut self,
375 global_id: Option<&GlobalElementId>,
376 _bounds: Bounds<Pixels>,
377 _: &mut Self::RequestLayoutState,
378 element: &mut Self::PrepaintState,
379 cx: &mut WindowContext,
380 ) {
381 if self.cached_style.is_some() {
382 cx.with_element_state::<AnyViewState, _>(global_id.unwrap(), |element_state, cx| {
383 let mut element_state = element_state.unwrap();
384
385 let paint_start = cx.paint_index();
386
387 if let Some(element) = element {
388 let refreshing = mem::replace(&mut cx.window.refreshing, true);
389 element.paint(cx);
390 cx.window.refreshing = refreshing;
391 } else {
392 cx.reuse_paint(element_state.paint_range.clone());
393 }
394
395 let paint_end = cx.paint_index();
396 element_state.paint_range = paint_start..paint_end;
397
398 ((), element_state)
399 })
400 } else {
401 element.as_mut().unwrap().paint(cx);
402 }
403 }
404}
405
406impl<V: 'static + Render> IntoElement for View<V> {
407 type Element = View<V>;
408
409 fn into_element(self) -> Self::Element {
410 self
411 }
412}
413
414impl IntoElement for AnyView {
415 type Element = Self;
416
417 fn into_element(self) -> Self::Element {
418 self
419 }
420}
421
422/// A weak, dynamically-typed view handle that does not prevent the view from being released.
423pub struct AnyWeakView {
424 model: AnyWeakModel,
425 render: fn(&AnyView, &mut WindowContext) -> AnyElement,
426}
427
428impl AnyWeakView {
429 /// Convert to a strongly-typed handle if the referenced view has not yet been released.
430 pub fn upgrade(&self) -> Option<AnyView> {
431 let model = self.model.upgrade()?;
432 Some(AnyView {
433 model,
434 render: self.render,
435 cached_style: None,
436 })
437 }
438}
439
440impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
441 fn from(view: WeakView<V>) -> Self {
442 Self {
443 model: view.model.into(),
444 render: any_view::render::<V>,
445 }
446 }
447}
448
449impl PartialEq for AnyWeakView {
450 fn eq(&self, other: &Self) -> bool {
451 self.model == other.model
452 }
453}
454
455impl std::fmt::Debug for AnyWeakView {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 f.debug_struct("AnyWeakView")
458 .field("entity_id", &self.model.entity_id)
459 .finish_non_exhaustive()
460 }
461}
462
463mod any_view {
464 use crate::{AnyElement, AnyView, IntoElement, Render, WindowContext};
465
466 pub(crate) fn render<V: 'static + Render>(
467 view: &AnyView,
468 cx: &mut WindowContext,
469 ) -> AnyElement {
470 let view = view.clone().downcast::<V>().unwrap();
471 view.update(cx, |view, cx| view.render(cx).into_any_element())
472 }
473}
474
475/// A view that renders nothing
476pub struct EmptyView;
477
478impl Render for EmptyView {
479 fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
480 Empty
481 }
482}