1use crate::{
2 AnyElement, AnyEntity, AnyWeakEntity, App, Bounds, ContentMask, Context, Element, ElementId,
3 Entity, EntityId, GlobalElementId, IntoElement, LayoutId, PaintIndex, Pixels,
4 PrepaintStateIndex, Render, Style, StyleRefinement, TextStyle, WeakEntity,
5};
6use crate::{Empty, Window};
7use anyhow::Result;
8use collections::FxHashSet;
9use refineable::Refineable;
10use std::mem;
11use std::rc::Rc;
12use std::{any::TypeId, fmt, ops::Range};
13
14struct AnyViewState {
15 prepaint_range: Range<PrepaintStateIndex>,
16 paint_range: Range<PaintIndex>,
17 cache_key: ViewCacheKey,
18 accessed_entities: FxHashSet<EntityId>,
19}
20
21#[derive(Default)]
22struct ViewCacheKey {
23 bounds: Bounds<Pixels>,
24 content_mask: ContentMask<Pixels>,
25 text_style: TextStyle,
26}
27
28impl<V: Render> Element for Entity<V> {
29 type RequestLayoutState = AnyElement;
30 type PrepaintState = ();
31
32 fn id(&self) -> Option<ElementId> {
33 Some(ElementId::View(self.entity_id()))
34 }
35
36 fn request_layout(
37 &mut self,
38 _id: Option<&GlobalElementId>,
39 window: &mut Window,
40 cx: &mut App,
41 ) -> (LayoutId, Self::RequestLayoutState) {
42 let mut element = self.update(cx, |view, cx| view.render(window, cx).into_any_element());
43 let layout_id = window.with_rendered_view(self.entity_id(), |window| {
44 element.request_layout(window, cx)
45 });
46 (layout_id, element)
47 }
48
49 fn prepaint(
50 &mut self,
51 _id: Option<&GlobalElementId>,
52 _: Bounds<Pixels>,
53 element: &mut Self::RequestLayoutState,
54 window: &mut Window,
55 cx: &mut App,
56 ) {
57 window.set_view_id(self.entity_id());
58 window.with_rendered_view(self.entity_id(), |window| element.prepaint(window, cx));
59 }
60
61 fn paint(
62 &mut self,
63 _id: Option<&GlobalElementId>,
64 _: Bounds<Pixels>,
65 element: &mut Self::RequestLayoutState,
66 _: &mut Self::PrepaintState,
67 window: &mut Window,
68 cx: &mut App,
69 ) {
70 window.with_rendered_view(self.entity_id(), |window| element.paint(window, cx));
71 }
72}
73
74/// A dynamically-typed handle to a view, which can be downcast to a [Entity] for a specific type.
75#[derive(Clone, Debug)]
76pub struct AnyView {
77 entity: AnyEntity,
78 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
79 cached_style: Option<Rc<StyleRefinement>>,
80}
81
82impl<V: Render> From<Entity<V>> for AnyView {
83 fn from(value: Entity<V>) -> Self {
84 AnyView {
85 entity: value.into_any(),
86 render: any_view::render::<V>,
87 cached_style: None,
88 }
89 }
90}
91
92impl AnyView {
93 /// Indicate that this view should be cached when using it as an element.
94 /// When using this method, the view's previous layout and paint will be recycled from the previous frame if [Context::notify] has not been called since it was rendered.
95 /// The one exception is when [Window::refresh] is called, in which case caching is ignored.
96 pub fn cached(mut self, style: StyleRefinement) -> Self {
97 self.cached_style = Some(style.into());
98 self
99 }
100
101 /// Convert this to a weak handle.
102 pub fn downgrade(&self) -> AnyWeakView {
103 AnyWeakView {
104 entity: self.entity.downgrade(),
105 render: self.render,
106 }
107 }
108
109 /// Convert this to a [Entity] of a specific type.
110 /// If this handle does not contain a view of the specified type, returns itself in an `Err` variant.
111 pub fn downcast<T: 'static>(self) -> Result<Entity<T>, Self> {
112 match self.entity.downcast() {
113 Ok(entity) => Ok(entity),
114 Err(entity) => Err(Self {
115 entity,
116 render: self.render,
117 cached_style: self.cached_style,
118 }),
119 }
120 }
121
122 /// Gets the [TypeId] of the underlying view.
123 pub fn entity_type(&self) -> TypeId {
124 self.entity.entity_type
125 }
126
127 /// Gets the entity id of this handle.
128 pub fn entity_id(&self) -> EntityId {
129 self.entity.entity_id()
130 }
131}
132
133impl PartialEq for AnyView {
134 fn eq(&self, other: &Self) -> bool {
135 self.entity == other.entity
136 }
137}
138
139impl Eq for AnyView {}
140
141impl Element for AnyView {
142 type RequestLayoutState = Option<AnyElement>;
143 type PrepaintState = Option<AnyElement>;
144
145 fn id(&self) -> Option<ElementId> {
146 Some(ElementId::View(self.entity_id()))
147 }
148
149 fn request_layout(
150 &mut self,
151 _id: Option<&GlobalElementId>,
152 window: &mut Window,
153 cx: &mut App,
154 ) -> (LayoutId, Self::RequestLayoutState) {
155 window.with_rendered_view(self.entity_id(), |window| {
156 if let Some(style) = self.cached_style.as_ref() {
157 let mut root_style = Style::default();
158 root_style.refine(style);
159 let layout_id = window.request_layout(root_style, None, cx);
160 (layout_id, None)
161 } else {
162 let mut element = (self.render)(self, window, cx);
163 let layout_id = element.request_layout(window, cx);
164 (layout_id, Some(element))
165 }
166 })
167 }
168
169 fn prepaint(
170 &mut self,
171 global_id: Option<&GlobalElementId>,
172 bounds: Bounds<Pixels>,
173 element: &mut Self::RequestLayoutState,
174 window: &mut Window,
175 cx: &mut App,
176 ) -> Option<AnyElement> {
177 window.set_view_id(self.entity_id());
178 window.with_rendered_view(self.entity_id(), |window| {
179 if self.cached_style.is_some() {
180 window.with_element_state::<AnyViewState, _>(
181 global_id.unwrap(),
182 |element_state, window| {
183 let content_mask = window.content_mask();
184 let text_style = window.text_style();
185
186 if let Some(mut element_state) = element_state {
187 if element_state.cache_key.bounds == bounds
188 && element_state.cache_key.content_mask == content_mask
189 && element_state.cache_key.text_style == text_style
190 && !window.dirty_views.contains(&self.entity_id())
191 && !window.refreshing
192 {
193 let prepaint_start = window.prepaint_index();
194 window.reuse_prepaint(element_state.prepaint_range.clone());
195 cx.entities
196 .extend_accessed(&element_state.accessed_entities);
197 let prepaint_end = window.prepaint_index();
198 element_state.prepaint_range = prepaint_start..prepaint_end;
199
200 return (None, element_state);
201 }
202 }
203
204 let refreshing = mem::replace(&mut window.refreshing, true);
205 let prepaint_start = window.prepaint_index();
206 let (mut element, accessed_entities) = cx.detect_accessed_entities(|cx| {
207 let mut element = (self.render)(self, window, cx);
208 element.layout_as_root(bounds.size.into(), window, cx);
209 element.prepaint_at(bounds.origin, window, cx);
210 element
211 });
212
213 let prepaint_end = window.prepaint_index();
214 window.refreshing = refreshing;
215
216 (
217 Some(element),
218 AnyViewState {
219 accessed_entities,
220 prepaint_range: prepaint_start..prepaint_end,
221 paint_range: PaintIndex::default()..PaintIndex::default(),
222 cache_key: ViewCacheKey {
223 bounds,
224 content_mask,
225 text_style,
226 },
227 },
228 )
229 },
230 )
231 } else {
232 let mut element = element.take().unwrap();
233 element.prepaint(window, cx);
234
235 Some(element)
236 }
237 })
238 }
239
240 fn paint(
241 &mut self,
242 global_id: Option<&GlobalElementId>,
243 _bounds: Bounds<Pixels>,
244 _: &mut Self::RequestLayoutState,
245 element: &mut Self::PrepaintState,
246 window: &mut Window,
247 cx: &mut App,
248 ) {
249 window.with_rendered_view(self.entity_id(), |window| {
250 if self.cached_style.is_some() {
251 window.with_element_state::<AnyViewState, _>(
252 global_id.unwrap(),
253 |element_state, window| {
254 let mut element_state = element_state.unwrap();
255
256 let paint_start = window.paint_index();
257
258 if let Some(element) = element {
259 let refreshing = mem::replace(&mut window.refreshing, true);
260 element.paint(window, cx);
261 window.refreshing = refreshing;
262 } else {
263 window.reuse_paint(element_state.paint_range.clone());
264 }
265
266 let paint_end = window.paint_index();
267 element_state.paint_range = paint_start..paint_end;
268
269 ((), element_state)
270 },
271 )
272 } else {
273 element.as_mut().unwrap().paint(window, cx);
274 }
275 });
276 }
277}
278
279impl<V: 'static + Render> IntoElement for Entity<V> {
280 type Element = Entity<V>;
281
282 fn into_element(self) -> Self::Element {
283 self
284 }
285}
286
287impl IntoElement for AnyView {
288 type Element = Self;
289
290 fn into_element(self) -> Self::Element {
291 self
292 }
293}
294
295/// A weak, dynamically-typed view handle that does not prevent the view from being released.
296pub struct AnyWeakView {
297 entity: AnyWeakEntity,
298 render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
299}
300
301impl AnyWeakView {
302 /// Convert to a strongly-typed handle if the referenced view has not yet been released.
303 pub fn upgrade(&self) -> Option<AnyView> {
304 let entity = self.entity.upgrade()?;
305 Some(AnyView {
306 entity,
307 render: self.render,
308 cached_style: None,
309 })
310 }
311}
312
313impl<V: 'static + Render> From<WeakEntity<V>> for AnyWeakView {
314 fn from(view: WeakEntity<V>) -> Self {
315 AnyWeakView {
316 entity: view.into(),
317 render: any_view::render::<V>,
318 }
319 }
320}
321
322impl PartialEq for AnyWeakView {
323 fn eq(&self, other: &Self) -> bool {
324 self.entity == other.entity
325 }
326}
327
328impl std::fmt::Debug for AnyWeakView {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 f.debug_struct("AnyWeakView")
331 .field("entity_id", &self.entity.entity_id)
332 .finish_non_exhaustive()
333 }
334}
335
336mod any_view {
337 use crate::{AnyElement, AnyView, App, IntoElement, Render, Window};
338
339 pub(crate) fn render<V: 'static + Render>(
340 view: &AnyView,
341 window: &mut Window,
342 cx: &mut App,
343 ) -> AnyElement {
344 let view = view.clone().downcast::<V>().unwrap();
345 view.update(cx, |view, cx| view.render(window, cx).into_any_element())
346 }
347}
348
349/// A view that renders nothing
350pub struct EmptyView;
351
352impl Render for EmptyView {
353 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
354 Empty
355 }
356}