window.rs

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