1use crate::{
2 private::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::TypeId,
10 hash::{Hash, Hasher},
11};
12
13pub struct View<V> {
14 pub model: Model<V>,
15}
16
17impl<V> Sealed for View<V> {}
18
19impl<V: 'static> Entity<V> for View<V> {
20 type Weak = WeakView<V>;
21
22 fn entity_id(&self) -> EntityId {
23 self.model.entity_id
24 }
25
26 fn downgrade(&self) -> Self::Weak {
27 WeakView {
28 model: self.model.downgrade(),
29 }
30 }
31
32 fn upgrade_from(weak: &Self::Weak) -> Option<Self>
33 where
34 Self: Sized,
35 {
36 let model = weak.model.upgrade()?;
37 Some(View { model })
38 }
39}
40
41impl<V: 'static> View<V> {
42 /// Convert this strong view reference into a weak view reference.
43 pub fn downgrade(&self) -> WeakView<V> {
44 Entity::downgrade(self)
45 }
46
47 pub fn update<C, R>(
48 &self,
49 cx: &mut C,
50 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
51 ) -> C::Result<R>
52 where
53 C: VisualContext,
54 {
55 cx.update_view(self, f)
56 }
57
58 pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
59 self.model.read(cx)
60 }
61
62 // pub fn render_with<E>(&self, component: E) -> RenderViewWith<E, V>
63 // where
64 // E: 'static + Element,
65 // {
66 // RenderViewWith {
67 // view: self.clone(),
68 // element: Some(component),
69 // }
70 // }
71
72 pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
73 where
74 V: FocusableView,
75 {
76 self.read(cx).focus_handle(cx)
77 }
78}
79
80impl<V: Render> Element for View<V> {
81 type State = Option<AnyElement>;
82
83 fn layout(
84 &mut self,
85 _state: Option<Self::State>,
86 cx: &mut WindowContext,
87 ) -> (LayoutId, Self::State) {
88 let mut element = self.update(cx, |view, cx| view.render(cx).into_any());
89 let layout_id = element.layout(cx);
90 (layout_id, Some(element))
91 }
92
93 fn paint(self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
94 element.take().unwrap().paint(cx);
95 }
96}
97
98impl<V> Clone for View<V> {
99 fn clone(&self) -> Self {
100 Self {
101 model: self.model.clone(),
102 }
103 }
104}
105
106impl<V> Hash for View<V> {
107 fn hash<H: Hasher>(&self, state: &mut H) {
108 self.model.hash(state);
109 }
110}
111
112impl<V> PartialEq for View<V> {
113 fn eq(&self, other: &Self) -> bool {
114 self.model == other.model
115 }
116}
117
118impl<V> Eq for View<V> {}
119
120pub struct WeakView<V> {
121 pub(crate) model: WeakModel<V>,
122}
123
124impl<V: 'static> WeakView<V> {
125 pub fn entity_id(&self) -> EntityId {
126 self.model.entity_id
127 }
128
129 pub fn upgrade(&self) -> Option<View<V>> {
130 Entity::upgrade_from(self)
131 }
132
133 pub fn update<C, R>(
134 &self,
135 cx: &mut C,
136 f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
137 ) -> Result<R>
138 where
139 C: VisualContext,
140 Result<C::Result<R>>: Flatten<R>,
141 {
142 let view = self.upgrade().context("error upgrading view")?;
143 Ok(view.update(cx, f)).flatten()
144 }
145}
146
147impl<V> Clone for WeakView<V> {
148 fn clone(&self) -> Self {
149 Self {
150 model: self.model.clone(),
151 }
152 }
153}
154
155impl<V> Hash for WeakView<V> {
156 fn hash<H: Hasher>(&self, state: &mut H) {
157 self.model.hash(state);
158 }
159}
160
161impl<V> PartialEq for WeakView<V> {
162 fn eq(&self, other: &Self) -> bool {
163 self.model == other.model
164 }
165}
166
167impl<V> Eq for WeakView<V> {}
168
169#[derive(Clone, Debug)]
170pub struct AnyView {
171 model: AnyModel,
172 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
173 paint: fn(&AnyView, AnyElement, &mut WindowContext),
174}
175
176impl AnyView {
177 pub fn downgrade(&self) -> AnyWeakView {
178 AnyWeakView {
179 model: self.model.downgrade(),
180 layout: self.layout,
181 paint: self.paint,
182 }
183 }
184
185 pub fn downcast<T: 'static>(self) -> Result<View<T>, Self> {
186 match self.model.downcast() {
187 Ok(model) => Ok(View { model }),
188 Err(model) => Err(Self {
189 model,
190 layout: self.layout,
191 paint: self.paint,
192 }),
193 }
194 }
195
196 pub fn entity_type(&self) -> TypeId {
197 self.model.entity_type
198 }
199
200 pub fn entity_id(&self) -> EntityId {
201 self.model.entity_id()
202 }
203
204 pub(crate) fn draw(
205 &self,
206 origin: Point<Pixels>,
207 available_space: Size<AvailableSpace>,
208 cx: &mut WindowContext,
209 ) {
210 cx.with_absolute_element_offset(origin, |cx| {
211 let (layout_id, rendered_element) = (self.layout)(self, cx);
212 cx.window
213 .layout_engine
214 .compute_layout(layout_id, available_space);
215 (self.paint)(self, rendered_element, cx);
216 })
217 }
218}
219
220impl<V: Render> From<View<V>> for AnyView {
221 fn from(value: View<V>) -> Self {
222 AnyView {
223 model: value.model.into_any(),
224 layout: any_view::layout::<V>,
225 paint: any_view::paint::<V>,
226 }
227 }
228}
229
230impl Element for AnyView {
231 type State = Option<AnyElement>;
232
233 fn layout(
234 &mut self,
235 _state: Option<Self::State>,
236 cx: &mut WindowContext,
237 ) -> (LayoutId, Self::State) {
238 let (layout_id, state) = (self.layout)(self, cx);
239 (layout_id, Some(state))
240 }
241
242 fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
243 (self.paint)(&self, state.take().unwrap(), cx)
244 }
245}
246
247impl<V: 'static + Render> IntoElement for View<V> {
248 type Element = View<V>;
249
250 fn element_id(&self) -> Option<ElementId> {
251 Some(ElementId::from_entity_id(self.model.entity_id))
252 }
253
254 fn into_element(self) -> Self::Element {
255 self
256 }
257}
258
259impl IntoElement for AnyView {
260 type Element = Self;
261
262 fn element_id(&self) -> Option<ElementId> {
263 Some(ElementId::from_entity_id(self.model.entity_id))
264 }
265
266 fn into_element(self) -> Self::Element {
267 self
268 }
269}
270
271pub struct AnyWeakView {
272 model: AnyWeakModel,
273 layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
274 paint: fn(&AnyView, AnyElement, &mut WindowContext),
275}
276
277impl AnyWeakView {
278 pub fn upgrade(&self) -> Option<AnyView> {
279 let model = self.model.upgrade()?;
280 Some(AnyView {
281 model,
282 layout: self.layout,
283 paint: self.paint,
284 })
285 }
286}
287
288impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
289 fn from(view: WeakView<V>) -> Self {
290 Self {
291 model: view.model.into(),
292 layout: any_view::layout::<V>,
293 paint: any_view::paint::<V>,
294 }
295 }
296}
297
298impl<T, E> Render for T
299where
300 T: 'static + FnMut(&mut WindowContext) -> E,
301 E: 'static + Send + Element,
302{
303 type Element = E;
304
305 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
306 (self)(cx)
307 }
308}
309
310mod any_view {
311 use crate::{AnyElement, AnyView, Element, LayoutId, Render, WindowContext};
312
313 pub(crate) fn layout<V: 'static + Render>(
314 view: &AnyView,
315 cx: &mut WindowContext,
316 ) -> (LayoutId, AnyElement) {
317 let view = view.clone().downcast::<V>().unwrap();
318 let mut element = view.update(cx, |view, cx| view.render(cx).into_any());
319 let layout_id = element.layout(cx);
320 (layout_id, element)
321 }
322
323 pub(crate) fn paint<V: 'static + Render>(
324 _view: &AnyView,
325 element: AnyElement,
326 cx: &mut WindowContext,
327 ) {
328 element.paint(cx);
329 }
330}