window.rs

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