1use crate::{
2 AvailableSpace, MainThreadOnly, Platform, PlatformWindow, Point, Size, Style, TextStyle,
3 TextStyleRefinement, WindowOptions,
4};
5
6use super::{
7 px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference,
8 TaffyLayoutEngine,
9};
10use anyhow::Result;
11use derive_more::{Deref, DerefMut};
12use refineable::Refineable;
13use std::{
14 any::{Any, TypeId},
15 marker::PhantomData,
16 sync::Arc,
17};
18
19pub struct AnyWindow {}
20
21pub struct Window {
22 handle: AnyWindowHandle,
23 platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
24 rem_size: Pixels,
25 layout_engine: TaffyLayoutEngine,
26 text_style_stack: Vec<TextStyleRefinement>,
27 pub(crate) root_view: Option<Box<dyn Any + Send>>,
28 mouse_position: Point<Pixels>,
29}
30
31impl Window {
32 pub fn new(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Window {
33 let platform_window = Arc::new(platform.open_window(handle, options));
34 let mouse_position = platform_window.mouse_position();
35 Window {
36 handle,
37 platform_window: MainThreadOnly::new(platform_window, platform.dispatcher()),
38 rem_size: px(16.),
39 layout_engine: TaffyLayoutEngine::new(),
40 text_style_stack: Vec::new(),
41 root_view: None,
42 mouse_position,
43 }
44 }
45}
46
47#[derive(Deref, DerefMut)]
48pub struct WindowContext<'a, 'b> {
49 #[deref]
50 #[deref_mut]
51 app: Reference<'a, AppContext>,
52 window: Reference<'b, Window>,
53}
54
55impl<'a, 'w> WindowContext<'a, 'w> {
56 pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
57 Self {
58 app: Reference::Mutable(app),
59 window: Reference::Mutable(window),
60 }
61 }
62
63 pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self {
64 Self {
65 app: Reference::Immutable(app),
66 window: Reference::Immutable(window),
67 }
68 }
69
70 pub fn request_layout(
71 &mut self,
72 style: Style,
73 children: impl IntoIterator<Item = LayoutId>,
74 ) -> Result<LayoutId> {
75 self.app.layout_id_buffer.clear();
76 self.app.layout_id_buffer.extend(children.into_iter());
77 let rem_size = self.rem_size();
78
79 self.window
80 .layout_engine
81 .request_layout(style, rem_size, &self.app.layout_id_buffer)
82 }
83
84 pub fn request_measured_layout<
85 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync + 'static,
86 >(
87 &mut self,
88 style: Style,
89 rem_size: Pixels,
90 measure: F,
91 ) -> Result<LayoutId> {
92 self.window
93 .layout_engine
94 .request_measured_layout(style, rem_size, measure)
95 }
96
97 pub fn layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
98 Ok(self
99 .window
100 .layout_engine
101 .layout(layout_id)
102 .map(Into::into)?)
103 }
104
105 pub fn rem_size(&self) -> Pixels {
106 self.window.rem_size
107 }
108
109 pub fn push_text_style(&mut self, text_style: TextStyleRefinement) {
110 self.window.text_style_stack.push(text_style);
111 }
112
113 pub fn pop_text_style(&mut self) {
114 self.window.text_style_stack.pop();
115 }
116
117 pub fn text_style(&self) -> TextStyle {
118 let mut style = TextStyle::default();
119 for refinement in &self.window.text_style_stack {
120 style.refine(refinement);
121 }
122 style
123 }
124
125 pub fn mouse_position(&self) -> Point<Pixels> {
126 self.window.mouse_position
127 }
128
129 fn update_window<R>(
130 &mut self,
131 window_id: WindowId,
132 update: impl FnOnce(&mut WindowContext) -> R,
133 ) -> Result<R> {
134 if window_id == self.window.handle.id {
135 Ok(update(self))
136 } else {
137 self.app.update_window(window_id, update)
138 }
139 }
140}
141
142impl Context for WindowContext<'_, '_> {
143 type EntityContext<'a, 'w, T: Send + 'static> = ViewContext<'a, 'w, T>;
144
145 fn entity<T: Send + 'static>(
146 &mut self,
147 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
148 ) -> Handle<T> {
149 let id = self.entities.insert(None);
150 let entity = Box::new(build_entity(&mut ViewContext::mutable(
151 &mut *self.app,
152 &mut self.window,
153 id,
154 )));
155 self.entities.get_mut(id).unwrap().replace(entity);
156
157 Handle {
158 id,
159 entity_type: PhantomData,
160 }
161 }
162
163 fn update_entity<T: Send + 'static, R>(
164 &mut self,
165 handle: &Handle<T>,
166 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
167 ) -> R {
168 let mut entity = self
169 .app
170 .entities
171 .get_mut(handle.id)
172 .unwrap()
173 .take()
174 .unwrap()
175 .downcast::<T>()
176 .unwrap();
177
178 let result = update(
179 &mut *entity,
180 &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
181 );
182
183 self.app
184 .entities
185 .get_mut(handle.id)
186 .unwrap()
187 .replace(entity);
188
189 result
190 }
191}
192
193#[derive(Deref, DerefMut)]
194pub struct ViewContext<'a, 'w, T> {
195 #[deref]
196 #[deref_mut]
197 window_cx: WindowContext<'a, 'w>,
198 entity_type: PhantomData<T>,
199 entity_id: EntityId,
200}
201
202impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> {
203 // fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
204
205 // self.window_cx.update_entity(handle, update)
206
207 // let mut entity = self.window_cx.app.entities.remove(&self.entity_id).unwrap();
208 // let result = update(entity.downcast_mut::<T>().unwrap(), self);
209 // self.window_cx
210 // .app
211 // .entities
212 // .insert(self.entity_id, Box::new(entity));
213 // result
214 // }
215
216 fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
217 Self {
218 window_cx: WindowContext::mutable(app, window),
219 entity_id,
220 entity_type: PhantomData,
221 }
222 }
223
224 fn immutable(app: &'a AppContext, window: &'w Window, entity_id: EntityId) -> Self {
225 Self {
226 window_cx: WindowContext::immutable(app, window),
227 entity_id,
228 entity_type: PhantomData,
229 }
230 }
231
232 pub fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
233 let unit_entity_id = self.unit_entity_id;
234 let mut cx = ViewContext::mutable(
235 &mut *self.window_cx.app,
236 &mut *self.window_cx.window,
237 unit_entity_id,
238 );
239 f(&mut cx)
240 }
241}
242
243impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
244 type EntityContext<'b, 'c, U: Send + 'static> = ViewContext<'b, 'c, U>;
245
246 fn entity<T2: Send + 'static>(
247 &mut self,
248 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
249 ) -> Handle<T2> {
250 self.window_cx.entity(build_entity)
251 }
252
253 fn update_entity<U: Send + 'static, R>(
254 &mut self,
255 handle: &Handle<U>,
256 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
257 ) -> R {
258 self.window_cx.update_entity(handle, update)
259 }
260}
261
262// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
263slotmap::new_key_type! { pub struct WindowId; }
264
265#[derive(PartialEq, Eq)]
266pub struct WindowHandle<S> {
267 id: WindowId,
268 state_type: PhantomData<S>,
269}
270
271impl<S> Copy for WindowHandle<S> {}
272
273impl<S> Clone for WindowHandle<S> {
274 fn clone(&self) -> Self {
275 WindowHandle {
276 id: self.id,
277 state_type: PhantomData,
278 }
279 }
280}
281
282impl<S> WindowHandle<S> {
283 pub fn new(id: WindowId) -> Self {
284 WindowHandle {
285 id,
286 state_type: PhantomData,
287 }
288 }
289}
290
291impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
292 fn into(self) -> AnyWindowHandle {
293 AnyWindowHandle {
294 id: self.id,
295 state_type: TypeId::of::<S>(),
296 }
297 }
298}
299
300#[derive(Copy, Clone, PartialEq, Eq)]
301pub struct AnyWindowHandle {
302 id: WindowId,
303 state_type: TypeId,
304}
305
306#[derive(Clone)]
307pub struct Layout {
308 pub order: u32,
309 pub bounds: Bounds<Pixels>,
310}