1use crate::{
2 image_cache::RenderImageParams, px, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
3 BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect, Element, EntityId,
4 FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayerId, LayoutId, MainThread,
5 MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
6 PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene,
7 SharedString, Size, Style, TaffyLayoutEngine, Task, WeakHandle, WindowOptions,
8 SUBPIXEL_VARIANTS,
9};
10use anyhow::Result;
11use smallvec::SmallVec;
12use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc};
13use util::ResultExt;
14
15pub struct AnyWindow {}
16
17pub struct Window {
18 handle: AnyWindowHandle,
19 platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
20 pub(crate) display_id: DisplayId, // todo!("make private again?")
21 sprite_atlas: Arc<dyn PlatformAtlas>,
22 rem_size: Pixels,
23 content_size: Size<Pixels>,
24 layout_engine: TaffyLayoutEngine,
25 pub(crate) root_view: Option<AnyView<()>>,
26 mouse_position: Point<Pixels>,
27 current_layer_id: LayerId,
28 content_mask_stack: Vec<ContentMask>,
29 pub(crate) scene: Scene,
30 pub(crate) dirty: bool,
31}
32
33impl Window {
34 pub fn new(
35 handle: AnyWindowHandle,
36 options: WindowOptions,
37 cx: &mut MainThread<AppContext>,
38 ) -> Self {
39 let platform_window = cx.platform().open_window(handle, options);
40 let display_id = platform_window.display().id();
41 let sprite_atlas = platform_window.sprite_atlas();
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.display_id = cx
53 .window
54 .platform_window
55 .borrow_on_main_thread()
56 .display()
57 .id();
58 cx.window.dirty = true;
59 })
60 .log_err();
61 }
62 }));
63
64 let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone());
65
66 Window {
67 handle,
68 platform_window,
69 display_id,
70 sprite_atlas,
71 rem_size: px(16.),
72 content_size,
73 layout_engine: TaffyLayoutEngine::new(),
74 root_view: None,
75 mouse_position,
76 current_layer_id: SmallVec::new(),
77 content_mask_stack: Vec::new(),
78 scene: Scene::new(scale_factor),
79 dirty: true,
80 }
81 }
82}
83
84#[derive(Clone, Debug)]
85pub struct ContentMask {
86 pub bounds: Bounds<Pixels>,
87}
88
89impl ContentMask {
90 pub fn scale(&self, factor: f32) -> ScaledContentMask {
91 ScaledContentMask {
92 bounds: self.bounds.scale(factor),
93 }
94 }
95
96 pub fn intersect(&self, other: &Self) -> Self {
97 let bounds = self.bounds.intersect(&other.bounds);
98 ContentMask { bounds }
99 }
100}
101
102#[derive(Clone, Debug, PartialEq, Eq)]
103#[repr(C)]
104pub struct ScaledContentMask {
105 bounds: Bounds<ScaledPixels>,
106}
107
108pub struct WindowContext<'a, 'w> {
109 app: Reference<'a, AppContext>,
110 window: Reference<'w, Window>,
111}
112
113impl<'a, 'w> WindowContext<'a, 'w> {
114 pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
115 Self {
116 app: Reference::Mutable(app),
117 window: Reference::Mutable(window),
118 }
119 }
120
121 pub fn notify(&mut self) {
122 self.window.dirty = true;
123 }
124
125 pub fn run_on_main<R>(
126 &mut self,
127 f: impl FnOnce(&mut MainThread<WindowContext<'_, '_>>) -> R + Send + 'static,
128 ) -> Task<Result<R>>
129 where
130 R: Send + 'static,
131 {
132 if self.executor.is_main_thread() {
133 Task::ready(Ok(f(unsafe {
134 mem::transmute::<&mut Self, &mut MainThread<Self>>(self)
135 })))
136 } else {
137 let id = self.window.handle.id;
138 self.app.run_on_main(move |cx| cx.update_window(id, f))
139 }
140 }
141
142 pub fn to_async(&self) -> AsyncWindowContext {
143 AsyncWindowContext::new(self.app.to_async(), self.window.handle)
144 }
145
146 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
147 let cx = self.to_async();
148 let display_id = self.window.display_id;
149 self.display_linker.on_next_frame(display_id, move |_, _| {
150 cx.update(f).ok();
151 });
152 }
153
154 pub fn spawn<Fut, R>(
155 &mut self,
156 f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut + Send + 'static,
157 ) -> Task<R>
158 where
159 R: Send + 'static,
160 Fut: Future<Output = R> + Send + 'static,
161 {
162 let window = self.window.handle;
163 self.app.spawn(move |app| {
164 let cx = AsyncWindowContext::new(app, window);
165 let future = f(window, cx);
166 async move { future.await }
167 })
168 }
169
170 pub fn request_layout(
171 &mut self,
172 style: Style,
173 children: impl IntoIterator<Item = LayoutId>,
174 ) -> Result<LayoutId> {
175 self.app.layout_id_buffer.clear();
176 self.app.layout_id_buffer.extend(children.into_iter());
177 let rem_size = self.rem_size();
178
179 self.window
180 .layout_engine
181 .request_layout(style, rem_size, &self.app.layout_id_buffer)
182 }
183
184 pub fn request_measured_layout<
185 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync + 'static,
186 >(
187 &mut self,
188 style: Style,
189 rem_size: Pixels,
190 measure: F,
191 ) -> Result<LayoutId> {
192 self.window
193 .layout_engine
194 .request_measured_layout(style, rem_size, measure)
195 }
196
197 pub fn layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
198 Ok(self
199 .window
200 .layout_engine
201 .layout(layout_id)
202 .map(Into::into)?)
203 }
204
205 pub fn scale_factor(&self) -> f32 {
206 self.window.scene.scale_factor
207 }
208
209 pub fn rem_size(&self) -> Pixels {
210 self.window.rem_size
211 }
212
213 pub fn mouse_position(&self) -> Point<Pixels> {
214 self.window.mouse_position
215 }
216
217 pub fn scene(&mut self) -> &mut Scene {
218 &mut self.window.scene
219 }
220
221 pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
222 self.window.current_layer_id.push(order);
223 let result = f(self);
224 self.window.current_layer_id.pop();
225 result
226 }
227
228 pub fn current_layer_id(&self) -> LayerId {
229 self.window.current_layer_id.clone()
230 }
231
232 pub fn paint_glyph(
233 &mut self,
234 origin: Point<Pixels>,
235 order: u32,
236 font_id: FontId,
237 glyph_id: GlyphId,
238 font_size: Pixels,
239 color: Hsla,
240 ) -> Result<()> {
241 let scale_factor = self.scale_factor();
242 let glyph_origin = origin.scale(scale_factor);
243 let subpixel_variant = Point {
244 x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
245 y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
246 };
247 let params = RenderGlyphParams {
248 font_id,
249 glyph_id,
250 font_size,
251 subpixel_variant,
252 scale_factor,
253 is_emoji: false,
254 };
255
256 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
257 if !raster_bounds.is_zero() {
258 let layer_id = self.current_layer_id();
259 let tile =
260 self.window
261 .sprite_atlas
262 .get_or_insert_with(¶ms.clone().into(), &mut || {
263 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
264 Ok((size, Cow::Owned(bytes)))
265 })?;
266 let bounds = Bounds {
267 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
268 size: tile.bounds.size.map(Into::into),
269 };
270 let content_mask = self.content_mask().scale(scale_factor);
271
272 self.window.scene.insert(
273 layer_id,
274 MonochromeSprite {
275 order,
276 bounds,
277 content_mask,
278 color,
279 tile,
280 },
281 );
282 }
283 Ok(())
284 }
285
286 pub fn paint_emoji(
287 &mut self,
288 origin: Point<Pixels>,
289 order: u32,
290 font_id: FontId,
291 glyph_id: GlyphId,
292 font_size: Pixels,
293 ) -> Result<()> {
294 let scale_factor = self.scale_factor();
295 let glyph_origin = origin.scale(scale_factor);
296 let params = RenderGlyphParams {
297 font_id,
298 glyph_id,
299 font_size,
300 // We don't render emojis with subpixel variants.
301 subpixel_variant: Default::default(),
302 scale_factor,
303 is_emoji: true,
304 };
305
306 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
307 if !raster_bounds.is_zero() {
308 let layer_id = self.current_layer_id();
309 let tile =
310 self.window
311 .sprite_atlas
312 .get_or_insert_with(¶ms.clone().into(), &mut || {
313 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
314 Ok((size, Cow::Owned(bytes)))
315 })?;
316 let bounds = Bounds {
317 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
318 size: tile.bounds.size.map(Into::into),
319 };
320 let content_mask = self.content_mask().scale(scale_factor);
321
322 self.window.scene.insert(
323 layer_id,
324 PolychromeSprite {
325 order,
326 bounds,
327 corner_radii: Default::default(),
328 content_mask,
329 tile,
330 grayscale: false,
331 },
332 );
333 }
334 Ok(())
335 }
336
337 pub fn paint_svg(
338 &mut self,
339 bounds: Bounds<Pixels>,
340 order: u32,
341 path: SharedString,
342 color: Hsla,
343 ) -> Result<()> {
344 let scale_factor = self.scale_factor();
345 let bounds = bounds.scale(scale_factor);
346 // Render the SVG at twice the size to get a higher quality result.
347 let params = RenderSvgParams {
348 path,
349 size: bounds
350 .size
351 .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
352 };
353
354 let layer_id = self.current_layer_id();
355 let tile =
356 self.window
357 .sprite_atlas
358 .get_or_insert_with(¶ms.clone().into(), &mut || {
359 let bytes = self.svg_renderer.render(¶ms)?;
360 Ok((params.size, Cow::Owned(bytes)))
361 })?;
362 let content_mask = self.content_mask().scale(scale_factor);
363
364 self.window.scene.insert(
365 layer_id,
366 MonochromeSprite {
367 order,
368 bounds,
369 content_mask,
370 color,
371 tile,
372 },
373 );
374
375 Ok(())
376 }
377
378 pub fn paint_image(
379 &mut self,
380 bounds: Bounds<Pixels>,
381 corner_radii: Corners<Pixels>,
382 order: u32,
383 data: Arc<ImageData>,
384 grayscale: bool,
385 ) -> Result<()> {
386 let scale_factor = self.scale_factor();
387 let bounds = bounds.scale(scale_factor);
388 let params = RenderImageParams { image_id: data.id };
389
390 let layer_id = self.current_layer_id();
391 let tile = self
392 .window
393 .sprite_atlas
394 .get_or_insert_with(¶ms.clone().into(), &mut || {
395 Ok((data.size(), Cow::Borrowed(data.as_bytes())))
396 })?;
397 let content_mask = self.content_mask().scale(scale_factor);
398 let corner_radii = corner_radii.scale(scale_factor);
399
400 self.window.scene.insert(
401 layer_id,
402 PolychromeSprite {
403 order,
404 bounds,
405 content_mask,
406 corner_radii,
407 tile,
408 grayscale,
409 },
410 );
411
412 Ok(())
413 }
414
415 pub(crate) fn draw(&mut self) -> Result<()> {
416 let unit_entity = self.unit_entity.clone();
417 self.update_entity(&unit_entity, |view, cx| {
418 let mut root_view = cx.window.root_view.take().unwrap();
419 let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
420 let available_space = cx.window.content_size.map(Into::into);
421
422 cx.window
423 .layout_engine
424 .compute_layout(root_layout_id, available_space)?;
425 let layout = cx.window.layout_engine.layout(root_layout_id)?;
426
427 root_view.paint(layout, &mut (), &mut frame_state, cx)?;
428 cx.window.root_view = Some(root_view);
429 let scene = cx.window.scene.take();
430
431 cx.run_on_main(view, |_, cx| {
432 cx.window
433 .platform_window
434 .borrow_on_main_thread()
435 .draw(scene);
436 cx.window.dirty = false;
437 })
438 .detach();
439
440 Ok(())
441 })
442 }
443}
444
445impl Context for WindowContext<'_, '_> {
446 type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
447 type Result<T> = T;
448
449 fn entity<T: Send + Sync + 'static>(
450 &mut self,
451 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
452 ) -> Handle<T> {
453 let slot = self.app.entities.reserve();
454 let entity = build_entity(&mut ViewContext::mutable(
455 &mut *self.app,
456 &mut self.window,
457 slot.id,
458 ));
459 self.entities.insert(slot, entity)
460 }
461
462 fn update_entity<T: Send + Sync + 'static, R>(
463 &mut self,
464 handle: &Handle<T>,
465 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
466 ) -> R {
467 let mut entity = self.entities.lease(handle);
468 let result = update(
469 &mut *entity,
470 &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
471 );
472 self.entities.end_lease(entity);
473 result
474 }
475}
476
477impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> {
478 type Target = AppContext;
479
480 fn deref(&self) -> &Self::Target {
481 &self.app
482 }
483}
484
485impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
486 fn deref_mut(&mut self) -> &mut Self::Target {
487 &mut self.app
488 }
489}
490
491impl BorrowAppContext for WindowContext<'_, '_> {
492 fn app_mut(&mut self) -> &mut AppContext {
493 &mut *self.app
494 }
495}
496
497pub trait BorrowWindow: BorrowAppContext {
498 fn window(&self) -> &Window;
499 fn window_mut(&mut self) -> &mut Window;
500
501 fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
502 let mask = mask.intersect(&self.content_mask());
503 self.window_mut().content_mask_stack.push(mask);
504 let result = f(self);
505 self.window_mut().content_mask_stack.pop();
506 result
507 }
508
509 fn content_mask(&self) -> ContentMask {
510 self.window()
511 .content_mask_stack
512 .last()
513 .cloned()
514 .unwrap_or_else(|| ContentMask {
515 bounds: Bounds {
516 origin: Point::default(),
517 size: self.window().content_size,
518 },
519 })
520 }
521
522 fn rem_size(&self) -> Pixels {
523 self.window().rem_size
524 }
525}
526
527impl BorrowWindow for WindowContext<'_, '_> {
528 fn window(&self) -> &Window {
529 &*self.window
530 }
531
532 fn window_mut(&mut self) -> &mut Window {
533 &mut *self.window
534 }
535}
536
537pub struct ViewContext<'a, 'w, S> {
538 window_cx: WindowContext<'a, 'w>,
539 entity_type: PhantomData<S>,
540 entity_id: EntityId,
541}
542
543impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
544 fn app_mut(&mut self) -> &mut AppContext {
545 &mut *self.window_cx.app
546 }
547
548 fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
549 where
550 F: FnOnce(&mut Self) -> R,
551 {
552 self.window_cx.app.push_text_style(style);
553 let result = f(self);
554 self.window_cx.app.pop_text_style();
555 result
556 }
557
558 fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
559 where
560 F: FnOnce(&mut Self) -> R,
561 {
562 self.window_cx.app.push_state(state);
563 let result = f(self);
564 self.window_cx.app.pop_state::<T>();
565 result
566 }
567}
568
569impl<S> BorrowWindow for ViewContext<'_, '_, S> {
570 fn window(&self) -> &Window {
571 &self.window_cx.window
572 }
573
574 fn window_mut(&mut self) -> &mut Window {
575 &mut *self.window_cx.window
576 }
577}
578
579impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
580 fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
581 Self {
582 window_cx: WindowContext::mutable(app, window),
583 entity_id,
584 entity_type: PhantomData,
585 }
586 }
587
588 pub fn handle(&self) -> WeakHandle<S> {
589 self.entities.weak_handle(self.entity_id)
590 }
591
592 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
593 let mut cx = self.to_async();
594 let entity = self.handle();
595 let display_id = self.window.display_id;
596 self.display_linker.on_next_frame(display_id, move |_, _| {
597 entity.update(&mut cx, f).ok();
598 });
599 }
600
601 pub fn observe<E: Send + Sync + 'static>(
602 &mut self,
603 handle: &Handle<E>,
604 on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
605 ) {
606 let this = self.handle();
607 let handle = handle.downgrade();
608 let window_handle = self.window.handle;
609 self.app
610 .observers
611 .entry(handle.id)
612 .or_default()
613 .push(Arc::new(move |cx| {
614 cx.update_window(window_handle.id, |cx| {
615 if let Some(handle) = handle.upgrade(cx) {
616 this.update(cx, |this, cx| on_notify(this, handle, cx))
617 .is_ok()
618 } else {
619 false
620 }
621 })
622 .unwrap_or(false)
623 }));
624 }
625
626 pub fn notify(&mut self) {
627 self.window_cx.notify();
628 self.window_cx
629 .app
630 .pending_effects
631 .push_back(Effect::Notify(self.entity_id));
632 }
633
634 pub fn run_on_main<R>(
635 &mut self,
636 view: &mut S,
637 f: impl FnOnce(&mut S, &mut MainThread<ViewContext<'_, '_, S>>) -> R + Send + 'static,
638 ) -> Task<Result<R>>
639 where
640 R: Send + 'static,
641 {
642 if self.executor.is_main_thread() {
643 let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
644 Task::ready(Ok(f(view, cx)))
645 } else {
646 let handle = self.handle().upgrade(self).unwrap();
647 self.window_cx.run_on_main(move |cx| handle.update(cx, f))
648 }
649 }
650
651 pub fn spawn<Fut, R>(
652 &mut self,
653 f: impl FnOnce(WeakHandle<S>, AsyncWindowContext) -> Fut + Send + 'static,
654 ) -> Task<R>
655 where
656 R: Send + 'static,
657 Fut: Future<Output = R> + Send + 'static,
658 {
659 let handle = self.handle();
660 self.window_cx.spawn(move |_, cx| {
661 let result = f(handle, cx);
662 async move { result.await }
663 })
664 }
665
666 pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
667 let entity_id = self.unit_entity.id;
668 let mut cx = ViewContext::mutable(
669 &mut *self.window_cx.app,
670 &mut *self.window_cx.window,
671 entity_id,
672 );
673 f(&mut cx)
674 }
675}
676
677impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
678 type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
679 type Result<U> = U;
680
681 fn entity<T2: Send + Sync + 'static>(
682 &mut self,
683 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
684 ) -> Handle<T2> {
685 self.window_cx.entity(build_entity)
686 }
687
688 fn update_entity<U: Send + Sync + 'static, R>(
689 &mut self,
690 handle: &Handle<U>,
691 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
692 ) -> R {
693 self.window_cx.update_entity(handle, update)
694 }
695}
696
697impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> {
698 type Target = WindowContext<'a, 'w>;
699
700 fn deref(&self) -> &Self::Target {
701 &self.window_cx
702 }
703}
704
705impl<'a, 'w, S: 'static> std::ops::DerefMut for ViewContext<'a, 'w, S> {
706 fn deref_mut(&mut self) -> &mut Self::Target {
707 &mut self.window_cx
708 }
709}
710
711// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
712slotmap::new_key_type! { pub struct WindowId; }
713
714#[derive(PartialEq, Eq)]
715pub struct WindowHandle<S> {
716 id: WindowId,
717 state_type: PhantomData<S>,
718}
719
720impl<S> Copy for WindowHandle<S> {}
721
722impl<S> Clone for WindowHandle<S> {
723 fn clone(&self) -> Self {
724 WindowHandle {
725 id: self.id,
726 state_type: PhantomData,
727 }
728 }
729}
730
731impl<S> WindowHandle<S> {
732 pub fn new(id: WindowId) -> Self {
733 WindowHandle {
734 id,
735 state_type: PhantomData,
736 }
737 }
738}
739
740impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
741 fn into(self) -> AnyWindowHandle {
742 AnyWindowHandle {
743 id: self.id,
744 state_type: TypeId::of::<S>(),
745 }
746 }
747}
748
749#[derive(Copy, Clone, PartialEq, Eq)]
750pub struct AnyWindowHandle {
751 pub(crate) id: WindowId,
752 state_type: TypeId,
753}
754
755#[derive(Clone)]
756pub struct Layout {
757 pub order: u32,
758 pub bounds: Bounds<Pixels>,
759}