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(¶ms)?;
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(¶ms.clone().into(), &mut || {
240 self.text_system().rasterize_glyph(¶ms)
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}