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