1use crate::{
2 seal::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::{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
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 request_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_element());
90 let layout_id = element.request_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<T> std::fmt::Debug for View<T> {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 f.debug_struct(&format!("View<{}>", type_name::<T>()))
110 .field("entity_id", &self.model.entity_id)
111 .finish_non_exhaustive()
112 }
113}
114
115impl<V> Hash for View<V> {
116 fn hash<H: Hasher>(&self, state: &mut H) {
117 self.model.hash(state);
118 }
119}
120
121impl<V> PartialEq for View<V> {
122 fn eq(&self, other: &Self) -> bool {
123 self.model == other.model
124 }
125}
126
127impl<V> Eq for View<V> {}
128
129pub struct WeakView<V> {
130 pub(crate) model: WeakModel<V>,
131}
132
133impl<V: 'static> WeakView<V> {
134 pub fn entity_id(&self) -> EntityId {
135 self.model.entity_id
136 }
137
138 pub fn upgrade(&self) -> Option<View<V>> {
139 Entity::upgrade_from(self)
140 }
141
142 pub fn update<C, R>(
143 &self,
144 cx: &mut C,
145 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
146 ) -> Result<R>
147 where
148 C: VisualContext,
149 Result<C::Result<R>>: Flatten<R>,
150 {
151 let view = self.upgrade().context("error upgrading view")?;
152 Ok(view.update(cx, f)).flatten()
153 }
154
155 #[cfg(any(test, feature = "test-support"))]
156 pub fn assert_dropped(&self) {
157 self.model.assert_dropped()
158 }
159}
160
161impl<V> Clone for WeakView<V> {
162 fn clone(&self) -> Self {
163 Self {
164 model: self.model.clone(),
165 }
166 }
167}
168
169impl<V> Hash for WeakView<V> {
170 fn hash<H: Hasher>(&self, state: &mut H) {
171 self.model.hash(state);
172 }
173}
174
175impl<V> PartialEq for WeakView<V> {
176 fn eq(&self, other: &Self) -> bool {
177 self.model == other.model
178 }
179}
180
181impl<V> Eq for WeakView<V> {}
182
183#[derive(Clone, Debug)]
184pub struct AnyView {
185 model: AnyModel,
186 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
187 paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
188}
189
190impl AnyView {
191 pub fn downgrade(&self) -> AnyWeakView {
192 AnyWeakView {
193 model: self.model.downgrade(),
194 layout: self.layout,
195 paint: self.paint,
196 }
197 }
198
199 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
200 match self.model.downcast() {
201 Ok(model) => Ok(View { model }),
202 Err(model) => Err(Self {
203 model,
204 layout: self.layout,
205 paint: self.paint,
206 }),
207 }
208 }
209
210 pub fn entity_type(&self) -> TypeId {
211 self.model.entity_type
212 }
213
214 pub fn entity_id(&self) -> EntityId {
215 self.model.entity_id()
216 }
217
218 pub(crate) fn draw(
219 &self,
220 origin: Point<Pixels>,
221 available_space: Size<AvailableSpace>,
222 cx: &mut WindowContext,
223 ) {
224 cx.with_absolute_element_offset(origin, |cx| {
225 let (layout_id, mut rendered_element) = (self.layout)(self, cx);
226 cx.compute_layout(layout_id, available_space);
227 (self.paint)(self, &mut rendered_element, cx);
228 })
229 }
230}
231
232impl<V: Render> From<View<V>> for AnyView {
233 fn from(value: View<V>) -> Self {
234 AnyView {
235 model: value.model.into_any(),
236 layout: any_view::layout::<V>,
237 paint: any_view::paint,
238 }
239 }
240}
241
242impl Element for AnyView {
243 type State = Option<AnyElement>;
244
245 fn request_layout(
246 &mut self,
247 _state: Option<Self::State>,
248 cx: &mut WindowContext,
249 ) -> (LayoutId, Self::State) {
250 let (layout_id, state) = (self.layout)(self, cx);
251 (layout_id, Some(state))
252 }
253
254 fn paint(&mut self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
255 debug_assert!(
256 state.is_some(),
257 "state is None. Did you include an AnyView twice in the tree?"
258 );
259 (self.paint)(self, state.as_mut().unwrap(), cx)
260 }
261}
262
263impl<V: 'static + Render> IntoElement for View<V> {
264 type Element = View<V>;
265
266 fn element_id(&self) -> Option<ElementId> {
267 Some(ElementId::from_entity_id(self.model.entity_id))
268 }
269
270 fn into_element(self) -> Self::Element {
271 self
272 }
273}
274
275impl IntoElement for AnyView {
276 type Element = Self;
277
278 fn element_id(&self) -> Option<ElementId> {
279 Some(ElementId::from_entity_id(self.model.entity_id))
280 }
281
282 fn into_element(self) -> Self::Element {
283 self
284 }
285}
286
287pub struct AnyWeakView {
288 model: AnyWeakModel,
289 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
290 paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
291}
292
293impl AnyWeakView {
294 pub fn upgrade(&self) -> Option<AnyView> {
295 let model = self.model.upgrade()?;
296 Some(AnyView {
297 model,
298 layout: self.layout,
299 paint: self.paint,
300 })
301 }
302}
303
304impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
305 fn from(view: WeakView<V>) -> Self {
306 Self {
307 model: view.model.into(),
308 layout: any_view::layout::<V>,
309 paint: any_view::paint,
310 }
311 }
312}
313
314impl PartialEq for AnyWeakView {
315 fn eq(&self, other: &Self) -> bool {
316 self.model == other.model
317 }
318}
319
320impl std::fmt::Debug for AnyWeakView {
321 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322 f.debug_struct("AnyWeakView")
323 .field("entity_id", &self.model.entity_id)
324 .finish_non_exhaustive()
325 }
326}
327
328mod any_view {
329 use crate::{AnyElement, AnyView, IntoElement, LayoutId, Render, WindowContext};
330
331 pub(crate) fn layout<V: 'static + Render>(
332 view: &AnyView,
333 cx: &mut WindowContext,
334 ) -> (LayoutId, AnyElement) {
335 let view = view.clone().downcast::<V>().unwrap();
336 let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element());
337 let layout_id = element.request_layout(cx);
338 (layout_id, element)
339 }
340
341 pub(crate) fn paint(_view: &AnyView, element: &mut AnyElement, cx: &mut WindowContext) {
342 element.paint(cx);
343 }
344}