window.rs

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