window.rs

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