window.rs

  1use crate::{
  2    px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect,
  3    Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread,
  4    MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, Reference,
  5    RenderGlyphParams, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle,
  6    WindowOptions, SUBPIXEL_VARIANTS,
  7};
  8use anyhow::Result;
  9use futures::Future;
 10use smallvec::SmallVec;
 11use std::{any::TypeId, marker::PhantomData, mem, sync::Arc};
 12use util::ResultExt;
 13
 14pub struct AnyWindow {}
 15
 16pub struct Window {
 17    handle: AnyWindowHandle,
 18    platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
 19    glyph_atlas: Arc<dyn PlatformAtlas>,
 20    rem_size: Pixels,
 21    content_size: Size<Pixels>,
 22    layout_engine: TaffyLayoutEngine,
 23    pub(crate) root_view: Option<AnyView<()>>,
 24    mouse_position: Point<Pixels>,
 25    current_layer_id: LayerId,
 26    content_mask_stack: Vec<ContentMask>,
 27    pub(crate) scene: Scene,
 28    pub(crate) dirty: bool,
 29}
 30
 31impl Window {
 32    pub fn new(
 33        handle: AnyWindowHandle,
 34        options: WindowOptions,
 35        cx: &mut MainThread<AppContext>,
 36    ) -> Self {
 37        let platform_window = cx.platform().open_window(handle, options);
 38        let glyph_atlas = platform_window.glyph_atlas();
 39        let mouse_position = platform_window.mouse_position();
 40        let content_size = platform_window.content_size();
 41        let scale_factor = platform_window.scale_factor();
 42        platform_window.on_resize(Box::new({
 43            let handle = handle;
 44            let cx = cx.to_async();
 45            move |content_size, scale_factor| {
 46                cx.update_window(handle, |cx| {
 47                    cx.window.scene = Scene::new(scale_factor);
 48                    cx.window.content_size = content_size;
 49                    cx.window.dirty = true;
 50                })
 51                .log_err();
 52            }
 53        }));
 54
 55        let platform_window =
 56            MainThreadOnly::new(Arc::new(platform_window), cx.platform().dispatcher());
 57
 58        Window {
 59            handle,
 60            platform_window,
 61            glyph_atlas,
 62            rem_size: px(16.),
 63            content_size,
 64            layout_engine: TaffyLayoutEngine::new(),
 65            root_view: None,
 66            mouse_position,
 67            current_layer_id: SmallVec::new(),
 68            content_mask_stack: Vec::new(),
 69            scene: Scene::new(scale_factor),
 70            dirty: true,
 71        }
 72    }
 73}
 74
 75#[derive(Clone, Debug)]
 76pub struct ContentMask {
 77    pub bounds: Bounds<Pixels>,
 78    pub corner_radii: Corners<Pixels>,
 79}
 80
 81impl ContentMask {
 82    pub fn scale(&self, factor: f32) -> ScaledContentMask {
 83        ScaledContentMask {
 84            bounds: self.bounds.scale(factor),
 85            corner_radii: self.corner_radii.scale(factor),
 86        }
 87    }
 88}
 89
 90#[derive(Clone, Debug, PartialEq, Eq)]
 91#[repr(C)]
 92pub struct ScaledContentMask {
 93    bounds: Bounds<ScaledPixels>,
 94    corner_radii: Corners<ScaledPixels>,
 95}
 96
 97pub struct WindowContext<'a, 'w> {
 98    app: Reference<'a, AppContext>,
 99    window: Reference<'w, Window>,
100}
101
102impl<'a, 'w> WindowContext<'a, 'w> {
103    pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
104        Self {
105            app: Reference::Mutable(app),
106            window: Reference::Mutable(window),
107        }
108    }
109
110    pub fn notify(&mut self) {
111        self.window.dirty = true;
112    }
113
114    pub fn request_layout(
115        &mut self,
116        style: Style,
117        children: impl IntoIterator<Item = LayoutId>,
118    ) -> Result<LayoutId> {
119        self.app.layout_id_buffer.clear();
120        self.app.layout_id_buffer.extend(children.into_iter());
121        let rem_size = self.rem_size();
122
123        self.window
124            .layout_engine
125            .request_layout(style, rem_size, &self.app.layout_id_buffer)
126    }
127
128    pub fn request_measured_layout<
129        F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync + 'static,
130    >(
131        &mut self,
132        style: Style,
133        rem_size: Pixels,
134        measure: F,
135    ) -> Result<LayoutId> {
136        self.window
137            .layout_engine
138            .request_measured_layout(style, rem_size, measure)
139    }
140
141    pub fn layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
142        Ok(self
143            .window
144            .layout_engine
145            .layout(layout_id)
146            .map(Into::into)?)
147    }
148
149    pub fn scale_factor(&self) -> f32 {
150        self.window.scene.scale_factor
151    }
152
153    pub fn rem_size(&self) -> Pixels {
154        self.window.rem_size
155    }
156
157    pub fn mouse_position(&self) -> Point<Pixels> {
158        self.window.mouse_position
159    }
160
161    pub fn scene(&mut self) -> &mut Scene {
162        &mut self.window.scene
163    }
164
165    pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
166        self.window.current_layer_id.push(order);
167        let result = f(self);
168        self.window.current_layer_id.pop();
169        result
170    }
171
172    pub fn clip<F, R>(
173        &mut self,
174        bounds: Bounds<Pixels>,
175        corner_radii: Corners<Pixels>,
176        f: impl FnOnce(&mut Self) -> R,
177    ) -> R {
178        let clip_mask = ContentMask {
179            bounds,
180            corner_radii,
181        };
182
183        self.window.content_mask_stack.push(clip_mask);
184        let result = f(self);
185        self.window.content_mask_stack.pop();
186        result
187    }
188
189    pub fn current_layer_id(&self) -> LayerId {
190        self.window.current_layer_id.clone()
191    }
192
193    pub fn run_on_main<R>(
194        &self,
195        f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
196    ) -> impl Future<Output = Result<R>>
197    where
198        R: Send + 'static,
199    {
200        let id = self.window.handle.id;
201        self.app.run_on_main(move |cx| {
202            cx.update_window(id, |cx| {
203                f(unsafe {
204                    mem::transmute::<&mut WindowContext, &mut MainThread<WindowContext>>(cx)
205                })
206            })
207        })
208    }
209
210    pub fn paint_glyph(
211        &mut self,
212        origin: Point<Pixels>,
213        order: u32,
214        font_id: FontId,
215        glyph_id: GlyphId,
216        font_size: Pixels,
217        color: Hsla,
218    ) -> Result<()> {
219        let scale_factor = self.scale_factor();
220        let glyph_origin = origin.scale(scale_factor);
221        let subpixel_variant = Point {
222            x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
223            y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
224        };
225        let params = RenderGlyphParams {
226            font_id,
227            glyph_id,
228            font_size,
229            subpixel_variant,
230            scale_factor,
231        };
232
233        let raster_bounds = self.text_system().raster_bounds(&params)?;
234        if !raster_bounds.is_zero() {
235            let layer_id = self.current_layer_id();
236            let tile = self
237                .window
238                .glyph_atlas
239                .get_or_insert_with(&params.clone().into(), &mut || {
240                    self.text_system().rasterize_glyph(&params)
241                })?;
242            let bounds = Bounds {
243                origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
244                size: tile.bounds.size.map(Into::into),
245            };
246            let content_mask = self.content_mask().scale(scale_factor);
247
248            self.window.scene.insert(
249                layer_id,
250                MonochromeSprite {
251                    order,
252                    bounds,
253                    content_mask,
254                    color,
255                    tile,
256                },
257            );
258        }
259        Ok(())
260    }
261
262    pub(crate) fn draw(&mut self) -> Result<()> {
263        let unit_entity = self.unit_entity.clone();
264        self.update_entity(&unit_entity, |_, cx| {
265            let mut root_view = cx.window.root_view.take().unwrap();
266            let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
267            let available_space = cx.window.content_size.map(Into::into);
268
269            cx.window
270                .layout_engine
271                .compute_layout(root_layout_id, available_space)?;
272            let layout = cx.window.layout_engine.layout(root_layout_id)?;
273
274            root_view.paint(layout, &mut (), &mut frame_state, cx)?;
275            cx.window.root_view = Some(root_view);
276            let scene = cx.window.scene.take();
277
278            let _ = cx.run_on_main(|cx| {
279                cx.window
280                    .platform_window
281                    .borrow_on_main_thread()
282                    .draw(scene);
283            });
284
285            cx.window.dirty = false;
286            Ok(())
287        })
288    }
289}
290
291impl Context for WindowContext<'_, '_> {
292    type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
293    type Result<T> = T;
294
295    fn entity<T: Send + Sync + 'static>(
296        &mut self,
297        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
298    ) -> Handle<T> {
299        let slot = self.app.entities.reserve();
300        let entity = build_entity(&mut ViewContext::mutable(
301            &mut *self.app,
302            &mut self.window,
303            slot.id,
304        ));
305        self.entities.redeem(slot, entity)
306    }
307
308    fn update_entity<T: Send + Sync + 'static, R>(
309        &mut self,
310        handle: &Handle<T>,
311        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
312    ) -> R {
313        let mut entity = self.entities.lease(handle);
314        let result = update(
315            &mut *entity,
316            &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
317        );
318        self.entities.end_lease(entity);
319        result
320    }
321}
322
323impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> {
324    type Target = AppContext;
325
326    fn deref(&self) -> &Self::Target {
327        &self.app
328    }
329}
330
331impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
332    fn deref_mut(&mut self) -> &mut Self::Target {
333        &mut self.app
334    }
335}
336
337impl BorrowAppContext for WindowContext<'_, '_> {
338    fn app_mut(&mut self) -> &mut AppContext {
339        &mut *self.app
340    }
341}
342
343pub trait BorrowWindow: BorrowAppContext {
344    fn window(&self) -> &Window;
345    fn window_mut(&mut self) -> &mut Window;
346
347    fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
348        self.window_mut().content_mask_stack.push(mask);
349        let result = f(self);
350        self.window_mut().content_mask_stack.pop();
351        result
352    }
353
354    fn content_mask(&self) -> ContentMask {
355        self.window()
356            .content_mask_stack
357            .last()
358            .cloned()
359            .unwrap_or_else(|| ContentMask {
360                bounds: Bounds {
361                    origin: Point::default(),
362                    size: self.window().content_size,
363                },
364                corner_radii: Default::default(),
365            })
366    }
367
368    fn rem_size(&self) -> Pixels {
369        self.window().rem_size
370    }
371}
372
373impl BorrowWindow for WindowContext<'_, '_> {
374    fn window(&self) -> &Window {
375        &*self.window
376    }
377
378    fn window_mut(&mut self) -> &mut Window {
379        &mut *self.window
380    }
381}
382
383pub struct ViewContext<'a, 'w, S> {
384    window_cx: WindowContext<'a, 'w>,
385    entity_type: PhantomData<S>,
386    entity_id: EntityId,
387}
388
389impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
390    fn app_mut(&mut self) -> &mut AppContext {
391        &mut *self.window_cx.app
392    }
393
394    fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
395    where
396        F: FnOnce(&mut Self) -> R,
397    {
398        self.window_cx.app.push_text_style(style);
399        let result = f(self);
400        self.window_cx.app.pop_text_style();
401        result
402    }
403
404    fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
405    where
406        F: FnOnce(&mut Self) -> R,
407    {
408        self.window_cx.app.push_state(state);
409        let result = f(self);
410        self.window_cx.app.pop_state::<T>();
411        result
412    }
413}
414
415impl<S> BorrowWindow for ViewContext<'_, '_, S> {
416    fn window(&self) -> &Window {
417        &self.window_cx.window
418    }
419
420    fn window_mut(&mut self) -> &mut Window {
421        &mut *self.window_cx.window
422    }
423}
424
425impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
426    fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
427        Self {
428            window_cx: WindowContext::mutable(app, window),
429            entity_id,
430            entity_type: PhantomData,
431        }
432    }
433
434    pub fn handle(&self) -> WeakHandle<S> {
435        self.entities.weak_handle(self.entity_id)
436    }
437
438    pub fn observe<E: Send + Sync + 'static>(
439        &mut self,
440        handle: &Handle<E>,
441        on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
442    ) {
443        let this = self.handle();
444        let handle = handle.downgrade();
445        let window_handle = self.window.handle;
446        self.app
447            .observers
448            .entry(handle.id)
449            .or_default()
450            .push(Arc::new(move |cx| {
451                cx.update_window(window_handle.id, |cx| {
452                    if let Some(handle) = handle.upgrade(cx) {
453                        this.update(cx, |this, cx| on_notify(this, handle, cx))
454                            .is_ok()
455                    } else {
456                        false
457                    }
458                })
459                .unwrap_or(false)
460            }));
461    }
462
463    pub fn notify(&mut self) {
464        self.window_cx.notify();
465        self.window_cx
466            .app
467            .pending_effects
468            .push_back(Effect::Notify(self.entity_id));
469    }
470
471    pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
472        let entity_id = self.unit_entity.id;
473        let mut cx = ViewContext::mutable(
474            &mut *self.window_cx.app,
475            &mut *self.window_cx.window,
476            entity_id,
477        );
478        f(&mut cx)
479    }
480}
481
482impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
483    type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
484    type Result<U> = U;
485
486    fn entity<T2: Send + Sync + 'static>(
487        &mut self,
488        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
489    ) -> Handle<T2> {
490        self.window_cx.entity(build_entity)
491    }
492
493    fn update_entity<U: Send + Sync + 'static, R>(
494        &mut self,
495        handle: &Handle<U>,
496        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
497    ) -> R {
498        self.window_cx.update_entity(handle, update)
499    }
500}
501
502impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> {
503    type Target = WindowContext<'a, 'w>;
504
505    fn deref(&self) -> &Self::Target {
506        &self.window_cx
507    }
508}
509
510impl<'a, 'w, S: 'static> std::ops::DerefMut for ViewContext<'a, 'w, S> {
511    fn deref_mut(&mut self) -> &mut Self::Target {
512        &mut self.window_cx
513    }
514}
515
516// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
517slotmap::new_key_type! { pub struct WindowId; }
518
519#[derive(PartialEq, Eq)]
520pub struct WindowHandle<S> {
521    id: WindowId,
522    state_type: PhantomData<S>,
523}
524
525impl<S> Copy for WindowHandle<S> {}
526
527impl<S> Clone for WindowHandle<S> {
528    fn clone(&self) -> Self {
529        WindowHandle {
530            id: self.id,
531            state_type: PhantomData,
532        }
533    }
534}
535
536impl<S> WindowHandle<S> {
537    pub fn new(id: WindowId) -> Self {
538        WindowHandle {
539            id,
540            state_type: PhantomData,
541        }
542    }
543}
544
545impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
546    fn into(self) -> AnyWindowHandle {
547        AnyWindowHandle {
548            id: self.id,
549            state_type: TypeId::of::<S>(),
550        }
551    }
552}
553
554#[derive(Copy, Clone, PartialEq, Eq)]
555pub struct AnyWindowHandle {
556    pub(crate) id: WindowId,
557    state_type: TypeId,
558}
559
560#[derive(Clone)]
561pub struct Layout {
562    pub order: u32,
563    pub bounds: Bounds<Pixels>,
564}