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