window.rs

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