1extern crate alloc;
16
17pub mod color;
18pub mod component;
19mod editor;
20pub mod event;
21pub mod graphics;
22pub mod input;
23pub mod layout;
24#[cfg(feature = "lua")]
25pub mod lua;
26pub mod persist;
27mod propbag;
28pub mod render;
29pub mod resource;
30mod rtree;
31mod shaders;
32pub mod text;
33pub mod util;
34
35use crate::component::window::Window;
36use crate::graphics::Driver;
37use crate::render::atlas::AtlasKind;
38use crate::render::compositor::CompositorView;
39use bytemuck::NoUninit;
40use component::window::WindowStateMachine;
41use component::{Component, StateMachineWrapper};
42use core::f32;
43use dyn_clone::DynClone;
44use eyre::OptionExt;
45pub use guillotiere::euclid;
46use guillotiere::euclid::{Point2D, Size2D, Vector2D};
47use parking_lot::RwLock;
48use persist::FnPersist2;
49use smallvec::SmallVec;
50use std::any::Any;
51use std::cmp::PartialEq;
52use std::collections::{BTreeMap, HashMap};
53use std::convert::Infallible;
54use std::ffi::c_void;
55use std::fmt::Display;
56use std::hash::{Hash, Hasher};
57use std::marker::PhantomData;
58use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
59use std::sync::atomic::AtomicU64;
60use std::sync::{Arc, mpsc};
61use wgpu::{InstanceDescriptor, InstanceFlags};
62use wide::{CmpGe, CmpGt, f32x4};
63use winit::event::WindowEvent;
64use winit::event_loop::{ActiveEventLoop, EventLoop};
65use winit::window::WindowId;
66pub use {cosmic_text, eyre, im, notify, wgpu, wide, winit};
67
68type Mat4x4 = euclid::default::Transform3D<f32>;
69
70#[cfg(feature = "lua")]
71pub use mlua;
72
73const MAX_ALLOCA: usize = 1 << 20;
74
75#[macro_export]
90macro_rules! gen_id {
91 ($idx:expr) => {
92 $idx.child($crate::DataID::Named(concat!(file!(), ":", line!())))
93 };
94 ($idx:expr, $i:expr) => {
95 $idx.child($crate::DataID::Int($i as i64))
96 };
97}
98
99use std::any::TypeId;
100#[derive(thiserror::Error, Debug)]
101pub enum Error {
102 #[error("Not an error, this component simply has no layout state.")]
103 Stateless,
104 #[error("Enum object didn't match tag {0}! Expected {1:?} but got {2:?}")]
105 MismatchedEnumTag(u64, TypeId, TypeId),
106 #[error("Invalid enum tag: {0}")]
107 InvalidEnumTag(u64),
108 #[error("Event handler didn't handle this method.")]
109 UnhandledEvent,
110 #[error("Frame aborted due to pending Texture Atlas resize.")]
111 ResizeTextureAtlas(u32, crate::render::atlas::AtlasKind),
112 #[error("Internal texture atlas reservation failure.")]
113 AtlasReservationFailure,
114 #[error("Internal texture atlas cache lookup failure.")]
115 AtlasCacheFailure,
116 #[error("Internal glyph render failure.")]
117 GlyphRenderFailure,
118 #[error("Internal glyph cache lookup failure.")]
119 GlyphCacheFailure,
120 #[error("An assumption about internal state was incorrect.")]
121 InternalFailure,
122 #[error("A filesystem error occurred: {0}")]
123 FileError(std::io::Error),
124 #[error("An error happened when loading a resource: {0:?}")]
125 ResourceError(Box<dyn std::fmt::Debug + Send + Sync>),
126 #[error(
127 "The resource was in an unrecognized format. Are you sure you enabled the right feature flags?"
128 )]
129 UnknownResourceFormat,
130 #[error("An index was out of range: {0}")]
131 OutOfRange(usize),
132 #[error("Type mismatch occurred when attempting a downcast that should never fail!")]
133 RuntimeTypeMismatch,
134}
135
136impl From<std::io::Error> for Error {
137 fn from(value: std::io::Error) -> Self {
138 Self::FileError(value)
139 }
140}
141
142pub const UNSIZED_AXIS: f32 = f32::MAX;
147
148pub const BASE_DPI: RelDim = RelDim::new(96.0, 96.0);
152
153const MINUS_BOTTOMRIGHT: f32x4 = f32x4::new([1.0, 1.0, -1.0, -1.0]);
154
155#[macro_export]
185macro_rules! children {
186 () => { [] };
187 ($prop:path, $($param:expr),+ $(,)?) => { $crate::im::Vector::from_iter([$(Some(Box::new($param) as Box<$crate::component::ChildOf<dyn $prop>>)),+]) };
188}
189
190#[macro_export]
191macro_rules! handlers {
192 () => { [] };
193 ($app:path, $($param:ident),+ $(,)?) => { Vec::from_iter([$((stringify!($param).to_string(), Box::new($param) as $crate::AppEvent<$app>)),+]) };
194}
195
196#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
197pub struct Logical {}
199#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
200pub struct Relative {}
202#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
203pub struct Pixel {}
205#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
206pub struct Resolved {}
209
210pub type AbsPoint = Point2D<f32, Logical>;
212pub type PxPoint = Point2D<f32, Pixel>;
214pub type RelPoint = Point2D<f32, Relative>;
216pub type ResPoint = Point2D<f32, Resolved>;
219
220pub type AbsVector = Vector2D<f32, Logical>;
222pub type PxVector = Vector2D<f32, Pixel>;
224pub type RelVector = Vector2D<f32, Relative>;
226pub type ResVector = Vector2D<f32, Resolved>;
229
230pub type AbsDim = Size2D<f32, Logical>;
232pub type PxDim = Size2D<f32, Pixel>;
234pub type RelDim = Size2D<f32, Relative>;
236pub type ResDim = Size2D<f32, Resolved>;
239
240trait UnResolve<U> {
243 fn unresolve(self, dpi: RelDim) -> U;
244}
245
246impl UnResolve<AbsVector> for PxVector {
247 fn unresolve(self, dpi: RelDim) -> AbsVector {
248 AbsVector::new(self.x / dpi.width, self.y / dpi.height)
249 }
250}
251
252impl UnResolve<AbsPoint> for PxPoint {
253 fn unresolve(self, dpi: RelDim) -> AbsPoint {
254 AbsPoint::new(self.x / dpi.width, self.y / dpi.height)
255 }
256}
257
258trait Convert<U> {
261 fn to(self) -> U;
262}
263
264impl Convert<Size2D<u32, Pixel>> for winit::dpi::PhysicalSize<u32> {
265 fn to(self) -> Size2D<u32, Pixel> {
266 Size2D::<u32, Pixel>::new(self.width, self.height)
267 }
268}
269
270impl Convert<Size2D<u32, Logical>> for winit::dpi::LogicalSize<u32> {
271 fn to(self) -> Size2D<u32, Logical> {
272 Size2D::<u32, Logical>::new(self.width, self.height)
273 }
274}
275
276impl Convert<Point2D<f32, Pixel>> for winit::dpi::PhysicalPosition<f32> {
277 fn to(self) -> Point2D<f32, Pixel> {
278 Point2D::<f32, Pixel>::new(self.x, self.y)
279 }
280}
281
282impl Convert<Point2D<f64, Pixel>> for winit::dpi::PhysicalPosition<f64> {
283 fn to(self) -> Point2D<f64, Pixel> {
284 Point2D::<f64, Pixel>::new(self.x, self.y)
285 }
286}
287
288#[derive(Copy, Clone, Debug, Default, PartialEq)]
292pub struct Rect<U> {
293 pub v: f32x4,
294 #[doc(hidden)]
295 pub _unit: PhantomData<U>,
296}
297
298trait Canonicalize {
303 type Bits;
304
305 fn canonical_bits(self) -> Self::Bits;
306}
307
308impl Canonicalize for f32 {
309 type Bits = u32;
310
311 fn canonical_bits(self) -> Self::Bits {
312 debug_assert!(!self.is_nan()); (self + 0.0).to_bits()
314 }
315}
316
317impl Canonicalize for f64 {
318 type Bits = u64;
319
320 fn canonical_bits(self) -> Self::Bits {
321 debug_assert!(!self.is_nan()); (self + 0.0).to_bits()
323 }
324}
325
326pub type AbsRect = Rect<Logical>;
328pub type PxRect = Rect<Pixel>;
330pub type RelRect = Rect<Relative>;
332pub type ResRect = Rect<Resolved>;
335
336unsafe impl<U: Copy + 'static> NoUninit for Rect<U> {}
337
338pub const ZERO_RECT: AbsRect = AbsRect::zero();
339
340impl<U> Rect<U> {
341 #[inline]
342 pub const fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
343 Self {
344 v: f32x4::new([left, top, right, bottom]),
345 _unit: PhantomData,
346 }
347 }
348
349 pub const fn splat(x: f32) -> Self {
350 Self {
351 v: f32x4::new([x, x, x, x]), _unit: PhantomData,
353 }
354 }
355
356 #[inline]
357 pub const fn corners(topleft: Point2D<f32, U>, bottomright: Point2D<f32, U>) -> Self {
358 Self {
359 v: f32x4::new([topleft.x, topleft.y, bottomright.x, bottomright.y]),
360 _unit: PhantomData,
361 }
362 }
363
364 #[inline]
365 pub fn contains(&self, p: Point2D<f32, U>) -> bool {
366 f32x4::new([p.x, p.y, p.x, p.y]).cmp_ge(self.v).move_mask() == 0b0011
370
371 }
376
377 #[inline]
378 pub fn collides(&self, rhs: &Self) -> bool {
379 let r = rhs.v.as_array_ref();
380 f32x4::new([r[2], r[3], -r[0], -r[1]])
381 .cmp_gt(self.v * MINUS_BOTTOMRIGHT)
382 .all()
383
384 }
389
390 #[inline]
391 pub fn intersect(&self, rhs: Self) -> Self {
392 let rect =
393 (self.v * MINUS_BOTTOMRIGHT).fast_max(rhs.v * MINUS_BOTTOMRIGHT) * MINUS_BOTTOMRIGHT;
394
395 let a = rect.to_array();
398 Self {
399 v: rect.fast_max(f32x4::new([a[0], a[1], a[0], a[1]])),
400 _unit: PhantomData,
401 }
402
403 }
412
413 #[inline]
414 pub fn extend(&self, rhs: Self) -> Self {
415 Self {
420 v: (self.v * MINUS_BOTTOMRIGHT).fast_min(rhs.v * MINUS_BOTTOMRIGHT) * MINUS_BOTTOMRIGHT,
421 _unit: PhantomData,
422 }
423 }
424
425 #[inline]
426 pub fn left(&self) -> f32 {
427 self.v.as_array_ref()[0]
428 }
429
430 #[inline]
431 pub fn top(&self) -> f32 {
432 self.v.as_array_ref()[1]
433 }
434
435 #[inline]
436 pub fn right(&self) -> f32 {
437 self.v.as_array_ref()[2]
438 }
439
440 #[inline]
441 pub fn bottom(&self) -> f32 {
442 self.v.as_array_ref()[3]
443 }
444
445 #[inline]
446 pub fn topleft(&self) -> Point2D<f32, U> {
447 let ltrb = self.v.as_array_ref();
448 Point2D::new(ltrb[0], ltrb[1])
449 }
450
451 #[inline]
452 pub fn set_topleft(&mut self, v: Point2D<f32, U>) {
453 let ltrb = self.v.as_array_mut();
454 ltrb[0] = v.x;
455 ltrb[1] = v.y;
456 }
457
458 #[inline]
459 pub fn bottomright(&self) -> Point2D<f32, U> {
460 let ltrb = self.v.as_array_ref();
461 Point2D::new(ltrb[2], ltrb[3])
462 }
463
464 #[inline]
465 pub fn set_bottomright(&mut self, v: Point2D<f32, U>) {
466 let ltrb = self.v.as_array_mut();
467 ltrb[2] = v.x;
468 ltrb[3] = v.y;
469 }
470
471 #[inline]
472 pub fn dim(&self) -> Size2D<f32, U> {
473 let ltrb = self.v.as_array_ref();
474 Size2D::new(ltrb[2] - ltrb[0], ltrb[3] - ltrb[1])
475 }
476
477 #[inline]
478 pub const fn zero() -> Self {
479 Self {
480 v: f32x4::ZERO,
481 _unit: PhantomData,
482 }
483 }
484
485 #[inline]
486 pub const fn unit() -> Self {
487 Self {
488 v: f32x4::new([0.0, 0.0, 1.0, 1.0]),
489 _unit: PhantomData,
490 }
491 }
492
493 #[inline]
495 pub fn to_untyped(self) -> PxRect {
496 self.cast_unit()
497 }
498
499 #[inline]
501 pub fn cast_unit<V>(self) -> Rect<V> {
502 Rect::<V> {
503 v: self.v,
504 _unit: PhantomData,
505 }
506 }
507}
508
509impl<U> Display for Rect<U> {
510 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511 let ltrb = self.v.as_array_ref();
512 write!(
513 f,
514 "Rect[({},{});({},{})]",
515 ltrb[0], ltrb[1], ltrb[2], ltrb[3]
516 )
517 }
518}
519
520impl<U> From<[f32; 4]> for Rect<U> {
521 #[inline]
522 fn from(value: [f32; 4]) -> Self {
523 Self {
524 v: f32x4::new(value),
525 _unit: PhantomData,
526 }
527 }
528}
529
530#[inline]
531const fn splat_point<U>(v: Point2D<f32, U>) -> f32x4 {
532 f32x4::new([v.x, v.y, v.x, v.y])
533}
534
535#[inline]
536const fn splat_size<U>(v: Size2D<f32, U>) -> f32x4 {
537 f32x4::new([v.width, v.height, v.width, v.height])
538}
539
540impl<U> Add<Point2D<f32, U>> for Rect<U> {
541 type Output = Self;
542
543 #[inline]
544 fn add(self, rhs: Point2D<f32, U>) -> Self::Output {
545 Self {
546 v: self.v + splat_point(rhs),
547 _unit: PhantomData,
548 }
549 }
550}
551
552impl<U> AddAssign<Point2D<f32, U>> for Rect<U> {
553 #[inline]
554 fn add_assign(&mut self, rhs: Point2D<f32, U>) {
555 self.v += splat_point(rhs)
556 }
557}
558
559impl<U> Add<Vector2D<f32, U>> for Rect<U> {
560 type Output = Self;
561
562 #[inline]
563 fn add(self, rhs: Vector2D<f32, U>) -> Self::Output {
564 Self {
565 v: self.v + splat_point(rhs.to_point()),
566 _unit: PhantomData,
567 }
568 }
569}
570
571impl<U> AddAssign<Vector2D<f32, U>> for Rect<U> {
572 #[inline]
573 fn add_assign(&mut self, rhs: Vector2D<f32, U>) {
574 self.v += splat_point(rhs.to_point())
575 }
576}
577
578impl<U> Sub<Point2D<f32, U>> for Rect<U> {
579 type Output = Self;
580
581 #[inline]
582 fn sub(self, rhs: Point2D<f32, U>) -> Self::Output {
583 Self {
584 v: self.v - splat_point(rhs),
585 _unit: PhantomData,
586 }
587 }
588}
589
590impl<U> SubAssign<Point2D<f32, U>> for Rect<U> {
591 #[inline]
592 fn sub_assign(&mut self, rhs: Point2D<f32, U>) {
593 self.v -= splat_point(rhs)
594 }
595}
596
597impl<U> Neg for Rect<U> {
598 type Output = Rect<U>;
599
600 fn neg(self) -> Self::Output {
601 Self::Output {
602 v: -self.v,
603 _unit: PhantomData,
604 }
605 }
606}
607
608impl<U> From<Size2D<f32, U>> for Rect<U> {
609 fn from(value: Size2D<f32, U>) -> Self {
610 Self {
611 v: f32x4::new([0.0, 0.0, value.width, value.height]),
612 _unit: PhantomData,
613 }
614 }
615}
616
617#[derive(Copy, Clone, Debug, Default, PartialEq)]
621pub struct Perimeter<U> {
622 pub v: f32x4,
623 #[doc(hidden)]
624 pub _unit: PhantomData<U>,
625}
626
627impl<U> Perimeter<U> {
628 #[inline]
629 pub fn topleft(&self) -> Size2D<f32, U> {
630 let ltrb = self.v.as_array_ref();
631 Size2D::<f32, U> {
632 width: ltrb[0],
633 height: ltrb[1],
634 _unit: PhantomData,
635 }
636 }
637
638 #[inline]
639 pub fn bottomright(&self) -> Size2D<f32, U> {
640 let ltrb = self.v.as_array_ref();
641 Size2D::<f32, U> {
642 width: ltrb[2],
643 height: ltrb[3],
644 _unit: PhantomData,
645 }
646 }
647
648 #[inline]
650 pub fn to_untyped(self) -> Perimeter<euclid::UnknownUnit> {
651 self.cast_unit()
652 }
653
654 #[inline]
656 pub fn cast_unit<V>(self) -> Perimeter<V> {
657 Perimeter::<V> {
658 v: self.v,
659 _unit: PhantomData,
660 }
661 }
662}
663
664pub type PxPerimeter = Perimeter<Pixel>;
665
666impl<U> Add<Perimeter<U>> for Rect<U> {
667 type Output = Self;
668
669 #[inline]
670 fn add(self, rhs: Perimeter<U>) -> Self::Output {
671 Self {
672 v: self.v + (rhs.v * MINUS_BOTTOMRIGHT),
673 _unit: PhantomData,
674 }
675 }
676}
677
678impl<U> AddAssign<Perimeter<U>> for AbsRect {
679 #[inline]
680 fn add_assign(&mut self, rhs: Perimeter<U>) {
681 self.v += rhs.v * MINUS_BOTTOMRIGHT
682 }
683}
684
685#[derive(Copy, Clone, Debug, Default, PartialEq)]
686pub struct DAbsRect {
689 dp: AbsRect,
690 px: PxRect,
691}
692
693pub const ZERO_DABSRECT: DAbsRect = DAbsRect {
694 dp: AbsRect::zero(),
695 px: PxRect::zero(),
696};
697
698impl DAbsRect {
699 fn resolve(&self, dpi: RelDim) -> PxRect {
700 PxRect {
701 v: self.px.v + (self.dp.v * splat_size(dpi)),
702 _unit: PhantomData,
703 }
704 }
705
706 fn as_perimeter(&self, dpi: RelDim) -> PxPerimeter {
707 PxPerimeter {
708 v: self.resolve(dpi).v,
709 _unit: PhantomData,
710 }
711 }
712}
713
714impl From<AbsRect> for DAbsRect {
715 fn from(value: AbsRect) -> Self {
716 DAbsRect {
717 dp: value,
718 px: PxRect::zero(),
719 }
720 }
721}
722
723impl From<PxRect> for DAbsRect {
724 fn from(value: PxRect) -> Self {
725 DAbsRect {
726 dp: AbsRect::zero(),
727 px: value,
728 }
729 }
730}
731
732impl Neg for DAbsRect {
733 type Output = DAbsRect;
734
735 fn neg(self) -> Self::Output {
736 Self::Output {
737 dp: -self.dp,
738 px: -self.px,
739 }
740 }
741}
742
743#[derive(Copy, Clone, Debug, Default, PartialEq)]
744pub struct DAbsPoint {
767 pub dp: AbsPoint,
768 pub px: PxPoint,
769}
770
771impl DAbsPoint {
772 pub const fn zero() -> Self {
773 Self {
774 dp: AbsPoint::new(0.0, 0.0),
775 px: PxPoint::new(0.0, 0.0),
776 }
777 }
778
779 pub const fn unit() -> Self {
780 Self {
781 dp: AbsPoint::new(1.0, 1.0),
782 px: PxPoint::new(1.0, 1.0),
783 }
784 }
785
786 fn resolve(&self, dpi: RelDim) -> ResPoint {
787 ResPoint {
788 x: self.px.x + (self.dp.x * dpi.width),
789 y: self.px.y + (self.dp.y * dpi.height),
790 _unit: PhantomData,
791 }
792 }
794}
795
796impl From<AbsPoint> for DAbsPoint {
797 fn from(value: AbsPoint) -> Self {
798 DAbsPoint {
799 dp: value,
800 px: PxPoint::zero(),
801 }
802 }
803}
804
805impl From<PxPoint> for DAbsPoint {
806 fn from(value: PxPoint) -> Self {
807 DAbsPoint {
808 dp: AbsPoint::zero(),
809 px: value,
810 }
811 }
812}
813
814impl Add<DAbsPoint> for DAbsPoint {
815 type Output = DAbsPoint;
816
817 fn add(self, rhs: DAbsPoint) -> Self::Output {
818 Self::Output {
819 dp: self.dp + rhs.dp.to_vector(),
820 px: self.px + rhs.px.to_vector(),
821 }
822 }
823}
824
825impl AddAssign<DAbsPoint> for DAbsPoint {
826 fn add_assign(&mut self, rhs: DAbsPoint) {
827 self.dp += rhs.dp.to_vector();
828 self.px += rhs.px.to_vector();
829 }
830}
831
832impl Neg for DAbsPoint {
833 type Output = DAbsPoint;
834
835 fn neg(self) -> Self::Output {
836 Self::Output {
837 dp: -self.dp,
838 px: -self.px,
839 }
840 }
841}
842
843#[inline]
844pub fn build_aabb<U>(a: Point2D<f32, U>, b: Point2D<f32, U>) -> Rect<U> {
845 Rect::<U>::corners(a.min(b), a.max(b))
846}
847
848#[derive(Copy, Clone, Debug, Default, PartialEq)]
849pub struct UPoint(f32x4);
851
852pub const ZERO_UPOINT: UPoint = UPoint(f32x4::ZERO);
853
854impl UPoint {
855 #[inline]
856 pub const fn new(abs: ResPoint, rel: RelPoint) -> Self {
857 Self(f32x4::new([abs.x, abs.y, rel.x, rel.y]))
858 }
859 #[inline]
860 pub fn abs(&self) -> ResPoint {
861 let ltrb = self.0.as_array_ref();
862 ResPoint {
863 x: ltrb[0],
864 y: ltrb[1],
865 _unit: PhantomData,
866 }
867 }
868 #[inline]
869 pub fn rel(&self) -> RelPoint {
870 let ltrb = self.0.as_array_ref();
871 RelPoint {
872 x: ltrb[2],
873 y: ltrb[3],
874 _unit: PhantomData,
875 }
876 }
877}
878
879impl Add for UPoint {
880 type Output = Self;
881
882 #[inline]
883 fn add(self, rhs: Self) -> Self {
884 Self(self.0 + rhs.0)
885 }
886}
887
888impl Sub for UPoint {
889 type Output = Self;
890
891 #[inline]
892 fn sub(self, rhs: Self) -> Self {
893 Self(self.0 - rhs.0)
894 }
895}
896
897impl Mul<PxDim> for UPoint {
898 type Output = PxPoint;
899
900 #[inline]
901 fn mul(self, rhs: PxDim) -> Self::Output {
902 let rel = self.rel();
903 self.abs()
904 .add_size(&Size2D::<f32, Resolved>::new(
905 rel.x * rhs.width,
906 rel.y * rhs.height,
907 ))
908 .cast_unit()
909 }
910}
911
912impl Neg for UPoint {
913 type Output = UPoint;
914
915 fn neg(self) -> Self::Output {
916 UPoint(-self.0)
917 }
918}
919
920#[derive(Copy, Clone, Debug, Default, PartialEq)]
942pub struct DPoint {
943 pub dp: AbsPoint,
944 pub px: PxPoint,
945 pub rel: RelPoint,
946}
947
948pub const ZERO_DPOINT: DPoint = DPoint {
949 px: PxPoint {
950 x: 0.0,
951 y: 0.0,
952 _unit: PhantomData,
953 },
954 dp: AbsPoint {
955 x: 0.0,
956 y: 0.0,
957 _unit: PhantomData,
958 },
959 rel: RelPoint {
960 x: 0.0,
961 y: 0.0,
962 _unit: PhantomData,
963 },
964};
965
966impl DPoint {
967 const fn resolve(&self, dpi: RelDim) -> UPoint {
968 UPoint(f32x4::new([
969 self.px.x + (self.dp.x * dpi.width),
970 self.px.y + (self.dp.y * dpi.height),
971 self.rel.x,
972 self.rel.y,
973 ]))
974 }
975}
976
977impl From<AbsPoint> for DPoint {
978 fn from(value: AbsPoint) -> Self {
979 Self {
980 dp: value,
981 px: PxPoint::zero(),
982 rel: RelPoint::zero(),
983 }
984 }
985}
986
987impl From<PxPoint> for DPoint {
988 fn from(value: PxPoint) -> Self {
989 Self {
990 dp: AbsPoint::zero(),
991 px: value,
992 rel: RelPoint::zero(),
993 }
994 }
995}
996
997impl From<RelPoint> for DPoint {
998 fn from(value: RelPoint) -> Self {
999 Self {
1000 dp: AbsPoint::zero(),
1001 px: PxPoint::zero(),
1002 rel: value,
1003 }
1004 }
1005}
1006
1007impl Add<DPoint> for DPoint {
1008 type Output = Self;
1009
1010 #[inline]
1011 fn add(self, rhs: DPoint) -> Self::Output {
1012 Self::Output {
1013 dp: self.dp + rhs.dp.to_vector(),
1014 px: self.px + rhs.px.to_vector(),
1015 rel: self.rel + rhs.rel.to_vector(),
1016 }
1017 }
1018}
1019
1020impl Sub<DPoint> for DPoint {
1021 type Output = Self;
1022
1023 #[inline]
1024 fn sub(self, rhs: DPoint) -> Self::Output {
1025 self + (-rhs)
1026 }
1027}
1028
1029impl Neg for DPoint {
1030 type Output = DPoint;
1031
1032 fn neg(self) -> Self::Output {
1033 Self::Output {
1034 dp: -self.dp,
1035 px: -self.px,
1036 rel: -self.rel,
1037 }
1038 }
1039}
1040
1041#[derive(Copy, Clone, Debug, Default, PartialEq)]
1042pub struct URect {
1044 pub abs: ResRect,
1045 pub rel: RelRect,
1046}
1047
1048impl URect {
1049 #[inline]
1050 pub fn topleft(&self) -> UPoint {
1051 let abs = self.abs.v.as_array_ref();
1052 let rel = self.rel.v.as_array_ref();
1053 UPoint(f32x4::new([abs[0], abs[1], rel[0], rel[1]]))
1054 }
1055
1056 #[inline]
1057 pub fn bottomright(&self) -> UPoint {
1058 let abs = self.abs.v.as_array_ref();
1059 let rel = self.rel.v.as_array_ref();
1060 UPoint(f32x4::new([abs[2], abs[3], rel[2], rel[3]]))
1061 }
1062
1063 #[inline]
1064 pub fn resolve(&self, rect: PxRect) -> PxRect {
1065 let ltrb = rect.v.as_array_ref();
1066 let topleft = f32x4::new([ltrb[0], ltrb[1], ltrb[0], ltrb[1]]);
1067 let bottomright = f32x4::new([ltrb[2], ltrb[3], ltrb[2], ltrb[3]]);
1068
1069 PxRect {
1070 v: topleft + self.abs.v + self.rel.v * (bottomright - topleft),
1071 _unit: PhantomData,
1072 }
1073 }
1074
1075 #[inline]
1076 pub fn to_perimeter(&self, rect: PxRect) -> PxPerimeter {
1077 PxPerimeter {
1078 v: self.resolve(rect).v,
1079 _unit: PhantomData,
1080 }
1081 }
1082}
1083
1084pub const ZERO_URECT: URect = URect {
1085 abs: ResRect::zero(),
1086 rel: RelRect::zero(),
1087};
1088
1089pub const FILL_URECT: URect = URect {
1090 abs: ResRect::zero(),
1091 rel: RelRect::unit(),
1092};
1093
1094pub const AUTO_URECT: URect = URect {
1095 abs: ResRect::zero(),
1096 rel: RelRect::new(0.0, 0.0, UNSIZED_AXIS, UNSIZED_AXIS),
1097};
1098
1099impl Mul<PxRect> for URect {
1100 type Output = PxRect;
1101
1102 #[inline]
1103 fn mul(self, rhs: PxRect) -> Self::Output {
1104 self.resolve(rhs)
1105 }
1106}
1107
1108impl Mul<PxDim> for URect {
1109 type Output = PxRect;
1110
1111 #[inline]
1112 fn mul(self, rhs: PxDim) -> Self::Output {
1113 Self::Output {
1114 v: self.abs.v + self.rel.v * splat_size(rhs),
1115 _unit: PhantomData,
1116 }
1117 }
1118}
1119
1120impl Neg for URect {
1121 type Output = URect;
1122
1123 fn neg(self) -> Self::Output {
1124 URect {
1125 abs: -self.abs,
1126 rel: -self.rel,
1127 }
1128 }
1129}
1130
1131#[derive(Copy, Clone, Debug, Default, PartialEq)]
1157pub struct DRect {
1158 pub px: PxRect,
1159 pub dp: AbsRect,
1160 pub rel: RelRect,
1161}
1162
1163impl DRect {
1164 fn resolve(&self, dpi: RelDim) -> URect {
1165 URect {
1166 abs: ResRect {
1167 v: self.px.v + (self.dp.v * splat_size(dpi)),
1168 _unit: PhantomData,
1169 },
1170 rel: self.rel,
1171 }
1172 }
1173
1174 pub fn topleft(&self) -> DPoint {
1177 DPoint {
1178 dp: self.dp.topleft(),
1179 px: self.px.topleft(),
1180 rel: self.rel.topleft(),
1181 }
1182 }
1183
1184 pub fn bottomright(&self) -> DPoint {
1189 DPoint {
1190 dp: self.dp.bottomright(),
1191 px: self.px.bottomright(),
1192 rel: self.rel.bottomright(),
1193 }
1194 }
1195
1196 pub fn size(&self) -> DPoint {
1198 self.bottomright() - self.topleft()
1199 }
1200
1201 pub const fn zero() -> Self {
1203 Self {
1204 px: PxRect::zero(),
1205 dp: AbsRect::zero(),
1206 rel: RelRect::zero(),
1207 }
1208 }
1209
1210 pub const fn fill() -> Self {
1214 DRect {
1215 px: PxRect::zero(),
1216 dp: AbsRect::zero(),
1217 rel: RelRect::unit(),
1218 }
1219 }
1220
1221 pub const fn auto() -> Self {
1225 DRect {
1226 px: PxRect::zero(),
1227 dp: AbsRect::zero(),
1228 rel: RelRect::new(0.0, 0.0, UNSIZED_AXIS, UNSIZED_AXIS),
1229 }
1230 }
1231}
1232
1233pub const ZERO_DRECT: DRect = DRect::zero();
1234pub const FILL_DRECT: DRect = DRect::fill();
1235pub const AUTO_DRECT: DRect = DRect::auto();
1236
1237impl Add<DRect> for DRect {
1238 type Output = Self;
1239
1240 #[inline]
1241 fn add(self, rhs: DRect) -> Self::Output {
1242 Self::Output {
1243 dp: AbsRect {
1244 v: self.dp.v + rhs.dp.v,
1245 _unit: PhantomData,
1246 },
1247 px: PxRect {
1248 v: self.px.v + rhs.px.v,
1249 _unit: PhantomData,
1250 },
1251 rel: RelRect {
1252 v: self.rel.v + rhs.rel.v,
1253 _unit: PhantomData,
1254 },
1255 }
1256 }
1257}
1258
1259impl Sub<DRect> for DRect {
1260 type Output = Self;
1261
1262 #[inline]
1263 fn sub(self, rhs: DRect) -> Self::Output {
1264 self + (-rhs)
1265 }
1266}
1267
1268impl Neg for DRect {
1269 type Output = DRect;
1270
1271 fn neg(self) -> Self::Output {
1272 Self::Output {
1273 dp: -self.dp,
1274 px: -self.px,
1275 rel: -self.rel,
1276 }
1277 }
1278}
1279
1280impl From<AbsRect> for DRect {
1281 fn from(value: AbsRect) -> Self {
1282 Self {
1283 px: PxRect::zero(),
1284 dp: value,
1285 rel: RelRect::zero(),
1286 }
1287 }
1288}
1289
1290impl From<PxRect> for DRect {
1291 fn from(value: PxRect) -> Self {
1292 Self {
1293 px: value,
1294 dp: AbsRect::zero(),
1295 rel: RelRect::zero(),
1296 }
1297 }
1298}
1299
1300impl From<RelRect> for DRect {
1301 fn from(value: RelRect) -> Self {
1302 Self {
1303 px: PxRect::zero(),
1304 dp: AbsRect::zero(),
1305 rel: value,
1306 }
1307 }
1308}
1309
1310impl<T, U: Into<DRect>> Add<U> for Rect<T>
1311where
1312 Self: Into<DRect>,
1313{
1314 type Output = DRect;
1315
1316 fn add(self, rhs: U) -> Self::Output {
1317 self.into() + rhs.into()
1318 }
1319}
1320
1321#[derive(Copy, Clone, Debug, PartialEq)]
1349pub struct Limits<U> {
1350 v: f32x4,
1351 #[doc(hidden)]
1352 pub _unit: PhantomData<U>,
1353}
1354
1355pub type PxLimits = Limits<Pixel>;
1356pub type AbsLimits = Limits<Logical>;
1357pub type RelLimits = Limits<Relative>;
1358pub type ResLimits = Limits<Resolved>;
1359
1360pub const DEFAULT_LIMITS: f32x4 = f32x4::new([
1368 f32::NEG_INFINITY,
1369 f32::NEG_INFINITY,
1370 f32::INFINITY,
1371 f32::INFINITY,
1372]);
1373
1374pub const DEFAULT_ABSLIMITS: AbsLimits = AbsLimits {
1377 v: DEFAULT_LIMITS,
1378 _unit: PhantomData,
1379};
1380
1381pub const DEFAULT_RLIMITS: RelLimits = RelLimits {
1384 v: DEFAULT_LIMITS,
1385 _unit: PhantomData,
1386};
1387
1388impl<U> Limits<U> {
1389 #[inline]
1390 const fn from_bound(bound: std::ops::Bound<&f32>, inf: f32) -> f32 {
1391 match bound {
1392 std::ops::Bound::Included(v) | std::ops::Bound::Excluded(v) => *v,
1393 std::ops::Bound::Unbounded => inf,
1394 }
1395 }
1396 pub fn new(x: impl std::ops::RangeBounds<f32>, y: impl std::ops::RangeBounds<f32>) -> Self {
1397 Self {
1398 v: f32x4::new([
1399 Self::from_bound(x.start_bound(), f32::NEG_INFINITY),
1400 Self::from_bound(y.start_bound(), f32::NEG_INFINITY),
1401 Self::from_bound(x.end_bound(), f32::INFINITY),
1402 Self::from_bound(y.end_bound(), f32::INFINITY),
1403 ]),
1404 _unit: PhantomData,
1405 }
1406 }
1407
1408 #[inline]
1409 pub fn min(&self) -> Size2D<f32, U> {
1410 let minmax = self.v.as_array_ref();
1411 Size2D::new(minmax[0], minmax[1])
1412 }
1413 #[inline]
1414 pub fn max(&self) -> Size2D<f32, U> {
1415 let minmax = self.v.as_array_ref();
1416 Size2D::new(minmax[2], minmax[3])
1417 }
1418
1419 #[inline]
1420 pub fn set_min(&mut self, bound: Size2D<f32, U>) {
1421 let minmax = self.v.as_array_mut();
1422 minmax[0] = bound.width;
1423 minmax[1] = bound.height;
1424 }
1425
1426 #[inline]
1427 pub fn set_max(&mut self, bound: Size2D<f32, U>) {
1428 let minmax = self.v.as_array_mut();
1429 minmax[2] = bound.width;
1430 minmax[3] = bound.height;
1431 }
1432
1433 #[inline]
1435 pub fn to_untyped(self) -> Limits<euclid::UnknownUnit> {
1436 self.cast_unit()
1437 }
1438
1439 #[inline]
1441 pub fn cast_unit<V>(self) -> Limits<V> {
1442 Limits::<V> {
1443 v: self.v,
1444 _unit: PhantomData,
1445 }
1446 }
1447}
1448
1449impl<U> Default for Limits<U> {
1450 #[inline]
1451 fn default() -> Self {
1452 Self {
1453 v: DEFAULT_LIMITS,
1454 _unit: PhantomData,
1455 }
1456 }
1457}
1458
1459impl<U> Add<Limits<U>> for Limits<U> {
1460 type Output = Self;
1461
1462 #[inline]
1463 fn add(self, rhs: Limits<U>) -> Self::Output {
1464 let minmax = self.v.as_array_ref();
1465 let r = rhs.v.as_array_ref();
1466
1467 Self {
1468 v: f32x4::new([
1469 minmax[0].max(r[0]),
1470 minmax[1].max(r[1]),
1471 minmax[2].min(r[2]),
1472 minmax[3].min(r[3]),
1473 ]),
1474 _unit: PhantomData,
1475 }
1476 }
1477}
1478
1479#[derive(Copy, Clone, Debug, Default)]
1480pub struct DLimits {
1481 dp: AbsLimits,
1482 px: PxLimits,
1483}
1484
1485pub const DEFAULT_DLIMITS: DLimits = DLimits {
1486 dp: AbsLimits {
1487 v: DEFAULT_LIMITS,
1488 _unit: PhantomData,
1489 },
1490 px: PxLimits {
1491 v: DEFAULT_LIMITS,
1492 _unit: PhantomData,
1493 },
1494};
1495
1496impl DLimits {
1497 pub fn resolve(&self, dpi: RelDim) -> PxLimits {
1498 self.px.cast_unit()
1499 + PxLimits {
1500 v: self.dp.v * splat_size(dpi),
1501 _unit: PhantomData,
1502 }
1503 }
1504}
1505
1506impl From<AbsLimits> for DLimits {
1507 fn from(value: AbsLimits) -> Self {
1508 DLimits {
1509 dp: value,
1510 px: Default::default(),
1511 }
1512 }
1513}
1514
1515impl From<PxLimits> for DLimits {
1516 fn from(value: PxLimits) -> Self {
1517 DLimits {
1518 dp: Default::default(),
1519 px: value,
1520 }
1521 }
1522}
1523
1524impl Mul<PxDim> for RelLimits {
1525 type Output = PxLimits;
1526
1527 #[inline]
1528 fn mul(self, rhs: PxDim) -> Self::Output {
1529 let (unsized_x, unsized_y) = crate::layout::check_unsized_dim(rhs);
1530 let minmax = self.v.as_array_ref();
1531 let v = f32x4::new([
1532 if unsized_x {
1533 minmax[0]
1534 } else {
1535 minmax[0] * rhs.width
1536 },
1537 if unsized_y {
1538 minmax[1]
1539 } else {
1540 minmax[1] * rhs.height
1541 },
1542 if unsized_x {
1543 minmax[2]
1544 } else {
1545 minmax[2] * rhs.width
1546 },
1547 if unsized_y {
1548 minmax[3]
1549 } else {
1550 minmax[3] * rhs.height
1551 },
1552 ]);
1553
1554 Self::Output {
1555 v: self.v.is_finite().blend(v, self.v),
1556 _unit: PhantomData,
1557 }
1558 }
1559}
1560
1561#[derive(Debug, Copy, Clone, PartialEq, Default)]
1562pub struct UValue {
1563 pub abs: f32,
1564 pub rel: f32,
1565}
1566
1567impl UValue {
1568 pub const fn resolve(&self, outer_dim: f32) -> f32 {
1569 if self.rel == UNSIZED_AXIS {
1570 UNSIZED_AXIS
1571 } else {
1572 self.abs + (self.rel * outer_dim)
1573 }
1574 }
1575 pub const fn is_unsized(&self) -> bool {
1576 self.rel == UNSIZED_AXIS
1577 }
1578}
1579
1580impl From<f32> for UValue {
1581 fn from(value: f32) -> Self {
1582 Self {
1583 abs: value,
1584 rel: 0.0,
1585 }
1586 }
1587}
1588
1589#[derive(Debug, Copy, Clone, PartialEq, Default)]
1590pub struct DValue {
1591 pub dp: f32,
1592 pub px: f32,
1593 pub rel: f32,
1594}
1595
1596impl DValue {
1597 pub const fn resolve(&self, dpi: f32) -> UValue {
1598 UValue {
1599 abs: self.px + (self.dp * dpi),
1600 rel: self.rel,
1601 }
1602 }
1603 pub const fn is_unsized(&self) -> bool {
1604 self.rel == UNSIZED_AXIS
1605 }
1606}
1607
1608impl From<f32> for DValue {
1609 fn from(value: f32) -> Self {
1610 Self {
1611 dp: value,
1612 px: 0.0,
1613 rel: 0.0,
1614 }
1615 }
1616}
1617
1618#[derive(
1627 Debug, Copy, Clone, PartialEq, Eq, Default, derive_more::TryFrom, derive_more::Display,
1628)]
1629#[try_from(repr)]
1630#[repr(u8)]
1631pub enum RowDirection {
1632 #[default]
1633 LeftToRight = 0,
1634 RightToLeft = 1,
1635 BottomToTop = 2,
1636 TopToBottom = 3,
1637}
1638
1639#[derive(Default)]
1644pub struct CrossReferenceDomain {
1645 mappings: RwLock<im::HashMap<Arc<SourceID>, PxRect>>,
1646}
1647
1648impl CrossReferenceDomain {
1649 pub fn write_area(&self, target: Arc<SourceID>, area: PxRect) {
1650 self.mappings.write().insert(target, area);
1651 }
1652
1653 pub fn get_area(&self, target: &Arc<SourceID>) -> Option<PxRect> {
1654 self.mappings.read().get(target).copied()
1655 }
1656
1657 pub fn remove_self(&self, target: &Arc<SourceID>) {
1658 self.mappings.write().remove(target);
1661 }
1662}
1663
1664pub trait DynHashEq: DynClone + std::fmt::Debug {
1666 fn dyn_hash(&self, state: &mut dyn Hasher);
1667 fn dyn_eq(&self, other: &dyn Any) -> bool;
1668}
1669
1670dyn_clone::clone_trait_object!(DynHashEq);
1671
1672impl<H: Hash + PartialEq + std::cmp::Eq + Clone + std::fmt::Debug + Any> DynHashEq for H {
1673 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
1674 self.hash(&mut state);
1675 }
1676 fn dyn_eq(&self, other: &dyn Any) -> bool {
1677 if let Some(o) = other.downcast_ref::<H>() {
1678 self == o
1679 } else {
1680 false
1681 }
1682 }
1683}
1684
1685#[derive(Clone, Default, Debug)]
1691pub enum DataID {
1692 Named(&'static str),
1693 Owned(String),
1694 Int(i64),
1695 Other(Box<dyn DynHashEq + Sync + Send>),
1696 #[default]
1697 None, }
1699
1700impl Hash for DataID {
1701 fn hash<H: Hasher>(&self, state: &mut H) {
1702 match self {
1703 DataID::Named(s) => s.hash(state),
1704 DataID::Owned(s) => s.hash(state),
1705 DataID::Int(i) => i.hash(state),
1706 DataID::Other(hash_comparable) => hash_comparable.dyn_hash(state),
1707 DataID::None => {
1708 panic!("Invalid ID! Did you forget to initialize a component node's ID field?")
1709 }
1710 }
1711 }
1712}
1713
1714impl std::cmp::Eq for DataID {}
1715impl PartialEq for DataID {
1716 fn eq(&self, other: &Self) -> bool {
1717 match self {
1718 DataID::Named(s) => {
1719 if let DataID::Named(name) = other {
1720 name == s
1721 } else {
1722 false
1723 }
1724 }
1725 DataID::Owned(s) => {
1726 if let DataID::Owned(name) = other {
1727 name == s
1728 } else {
1729 false
1730 }
1731 }
1732 DataID::Int(i) => {
1733 if let DataID::Int(integer) = other {
1734 integer == i
1735 } else {
1736 false
1737 }
1738 }
1739 DataID::Other(hash_comparable) => {
1740 if let DataID::Other(h) = other {
1741 hash_comparable.dyn_eq(h)
1742 } else {
1743 false
1744 }
1745 }
1746 DataID::None => panic!("Invalid ID!"),
1747 }
1748 }
1749}
1750
1751#[derive(Clone, Default, Debug)]
1758pub struct SourceID {
1759 parent: Option<std::sync::Arc<SourceID>>,
1760 id: DataID,
1761}
1762
1763impl SourceID {
1764 pub fn child(self: &Arc<Self>, id: DataID) -> Arc<Self> {
1767 Self {
1768 parent: self.clone().into(),
1769 id,
1770 }
1771 .into()
1772 }
1773
1774 pub fn duplicate(self: &Arc<Self>) -> Arc<Self> {
1780 self.child(DataID::Int(Arc::strong_count(self) as i64))
1781 }
1782
1783 #[allow(dead_code)] #[cfg(debug_assertions)]
1785 #[allow(clippy::mutable_key_type)]
1786 pub(crate) fn parents(self: &Arc<Self>) -> std::collections::HashSet<&Arc<Self>> {
1787 let mut set = std::collections::HashSet::new();
1788
1789 let mut cur = self.parent.as_ref();
1790 while let Some(id) = cur {
1791 if set.contains(id) {
1792 panic!("Loop detected in IDs! {:?} already existed!", id.id);
1793 }
1794 set.insert(id);
1795 cur = id.parent.as_ref();
1796 }
1797 set
1798 }
1799}
1800impl std::cmp::Eq for SourceID {}
1801impl PartialEq for SourceID {
1802 fn eq(&self, other: &Self) -> bool {
1803 if let Some(parent) = self.parent.as_ref() {
1804 if let Some(pother) = other.parent.as_ref() {
1805 parent == pother && self.id == other.id
1806 } else {
1807 false
1808 }
1809 } else {
1810 other.parent.is_none() && self.id == other.id
1811 }
1812 }
1813}
1814impl Hash for SourceID {
1815 fn hash<H: Hasher>(&self, state: &mut H) {
1816 if let Some(parent) = self.parent.as_ref() {
1817 parent.id.hash(state);
1818 }
1819 self.id.hash(state);
1820 }
1821}
1822impl Display for SourceID {
1823 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1824 if let Some(parent) = self.parent.as_ref() {
1825 parent.fmt(f)?;
1826 }
1827
1828 match (&self.id, self.parent.is_some()) {
1829 (DataID::Named(_), true) | (DataID::Owned(_), true) => f.write_str(" -> "),
1830 (DataID::Other(_), true) => f.write_str(" "),
1831 _ => Ok(()),
1832 }?;
1833
1834 match &self.id {
1835 DataID::Named(s) => f.write_str(s),
1836 DataID::Owned(s) => f.write_str(s),
1837 DataID::Int(i) => write!(f, "[{i}]"),
1838 DataID::Other(dyn_hash_eq) => {
1839 let mut h = std::hash::DefaultHasher::new();
1840 dyn_hash_eq.dyn_hash(&mut h);
1841 write!(f, "{{{}}}", h.finish())
1842 }
1843 DataID::None => Ok(()),
1844 }
1845 }
1846}
1847
1848pub struct ScopeIterID<'a, T> {
1849 base: ScopeID<'a>,
1850 it: T,
1851}
1852
1853impl<'a, T: Iterator> ScopeIterID<'a, T> {
1854 fn new(parent: &'a mut ScopeID<'_>, it: T) -> Self {
1855 Self {
1856 base: parent.scope(),
1857 it,
1858 }
1859 }
1860}
1861
1862impl<T> Iterator for ScopeIterID<'_, T>
1863where
1864 T: Iterator,
1865{
1866 type Item = (T::Item, Arc<SourceID>);
1867
1868 #[inline]
1869 fn next(&mut self) -> Option<Self::Item> {
1870 let x = self.it.next()?;
1871 let id = self.base.create();
1872 Some((x, id))
1873 }
1874
1875 #[inline]
1876 fn size_hint(&self) -> (usize, Option<usize>) {
1877 self.it.size_hint()
1878 }
1879
1880 #[inline]
1881 fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
1882 while let Some(x) = Iterator::next(self) {
1883 if n == 0 {
1884 return Some(x);
1885 }
1886 n -= 1;
1887 }
1888 None
1889 }
1890
1891 #[inline]
1892 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
1893 where
1894 F: FnMut(Acc, Self::Item) -> Acc,
1895 {
1896 let mut accum = init;
1897 while let Some(x) = Iterator::next(&mut self) {
1898 accum = f(accum, x);
1899 }
1900 accum
1901 }
1902}
1903
1904pub struct ScopeID<'a> {
1938 _parent: PhantomData<&'a mut ()>,
1941 base: Arc<SourceID>,
1942 count: i64,
1943}
1944
1945impl<'a> ScopeID<'a> {
1946 pub fn id(&mut self) -> &Arc<SourceID> {
1949 &self.base
1950 }
1951
1952 pub fn create(&mut self) -> Arc<SourceID> {
1974 let node = self.base.child(crate::DataID::Int(self.count));
1975 self.count += 1;
1976 node
1977 }
1978
1979 pub fn scope(&mut self) -> ScopeID<'_> {
1982 ScopeID {
1983 base: self.create(),
1984 _parent: PhantomData,
1985 count: 0,
1986 }
1987 }
1988
1989 pub fn child(&mut self, id: DataID) -> Arc<SourceID> {
1994 self.base.child(id)
1995 }
1996
1997 pub fn iter<U: IntoIterator>(&mut self, other: U) -> ScopeIterID<'_, U::IntoIter> {
2021 ScopeIterID::new(self, other.into_iter())
2022 }
2023
2024 pub fn cond<R>(
2057 &mut self,
2058 condition: bool,
2059 tvalue: impl FnOnce(ScopeID<'_>) -> R,
2060 fvalue: impl FnOnce(ScopeID<'_>) -> R,
2061 ) -> R {
2062 let (id_true, id_false) = (self.create(), self.create());
2063
2064 if condition {
2065 tvalue(ScopeID {
2066 base: id_true,
2067 _parent: PhantomData,
2068 count: 0,
2069 })
2070 } else {
2071 fvalue(ScopeID {
2072 base: id_false,
2073 _parent: PhantomData,
2074 count: 0,
2075 })
2076 }
2077 }
2078
2079 fn root() -> ScopeID<'a> {
2082 ScopeID {
2083 _parent: PhantomData,
2084 base: Arc::new(APP_SOURCE_ID),
2085 count: 0,
2086 }
2087 }
2088}
2089
2090pub enum InputResult<T> {
2095 Consume(T),
2096 Forward(T),
2097 Error(eyre::ErrReport),
2098}
2099
2100impl<T, E: std::error::Error + Send + Sync + 'static> From<Result<T, E>> for InputResult<T> {
2101 fn from(value: Result<T, E>) -> Self {
2102 match value {
2103 Ok(v) => InputResult::Consume(v),
2104 Err(e) => InputResult::Error(e.into()),
2105 }
2106 }
2107}
2108
2109impl<T> InputResult<T> {
2110 fn map<U>(self, f: impl FnOnce(T) -> U) -> InputResult<U> {
2113 match self {
2114 InputResult::Consume(v) => InputResult::Consume(f(v)),
2115 InputResult::Forward(v) => InputResult::Forward(f(v)),
2116 InputResult::Error(error) => InputResult::Error(error),
2117 }
2118 }
2119
2120 fn is_accept(&self) -> bool {
2121 matches!(*self, InputResult::Consume(_))
2122 }
2123 fn is_reject(&self) -> bool {
2124 matches!(*self, InputResult::Forward(_))
2125 }
2126 fn is_err(&self) -> bool {
2127 matches!(*self, InputResult::Error(_))
2128 }
2129}
2130
2131#[derive(Clone)]
2132pub struct Slot(pub Arc<SourceID>, pub u64);
2133
2134pub type AppEvent<State> = Box<dyn FnMut(DispatchPair, AccessCell<State>) -> InputResult<()>>;
2137
2138pub trait WrapEventEx<State, Input: Dispatchable> {
2184 fn wrap(self) -> impl FnMut(DispatchPair, AccessCell<State>) -> InputResult<()>;
2187}
2188
2189impl<AppData, Input: Dispatchable, T> WrapEventEx<AppData, Input> for T
2190where
2191 T: FnMut(Input, AccessCell<AppData>) -> InputResult<()>,
2192{
2193 fn wrap(mut self) -> impl FnMut(DispatchPair, AccessCell<AppData>) -> InputResult<()> {
2194 move |pair, state| (self)(Input::restore(pair).unwrap(), state)
2195 }
2196}
2197
2198pub type DispatchPair = (u64, Box<dyn Any>);
2200
2201pub trait Dispatchable
2202where
2203 Self: Sized,
2204{
2205 const SIZE: usize;
2206 fn extract(self) -> DispatchPair;
2207 fn restore(pair: DispatchPair) -> Result<Self, Error>;
2208}
2209
2210impl Dispatchable for Infallible {
2211 const SIZE: usize = 0;
2212
2213 fn extract(self) -> DispatchPair {
2214 (0, Box::new(self))
2215 }
2216
2217 fn restore(_: DispatchPair) -> Result<Self, Error> {
2218 Err(Error::Stateless)
2219 }
2220}
2221
2222pub trait StateMachineChild {
2259 #[allow(unused_variables)]
2260 fn init(
2261 &self,
2262 driver: &std::sync::Weak<Driver>,
2263 ) -> Result<Box<dyn StateMachineWrapper>, crate::Error> {
2264 Err(crate::Error::Stateless)
2265 }
2266 fn apply_children(
2267 &self,
2268 _: &mut dyn FnMut(&dyn StateMachineChild) -> eyre::Result<()>,
2269 ) -> eyre::Result<()> {
2270 Ok(())
2272 }
2273 fn id(&self) -> Arc<SourceID>;
2274}
2275
2276pub struct AccessCell<'a, 'b, T> {
2346 value: &'a mut T,
2347 changed: &'b mut bool,
2348}
2349
2350impl<'a, 'b, T> std::borrow::BorrowMut<T> for AccessCell<'a, 'b, T> {
2351 #[inline]
2352 fn borrow_mut(&mut self) -> &mut T {
2353 *self.changed = true;
2358 self.value
2359 }
2360}
2361
2362impl<'a, 'b, T> std::borrow::Borrow<T> for AccessCell<'a, 'b, T> {
2363 #[inline]
2364 fn borrow(&self) -> &T {
2365 self.value
2366 }
2367}
2368
2369impl<'a, 'b, T> std::ops::Deref for AccessCell<'a, 'b, T> {
2370 type Target = T;
2371
2372 #[inline]
2373 fn deref(&self) -> &T {
2374 self.value
2375 }
2376}
2377
2378impl<'a, 'b, T> std::ops::DerefMut for AccessCell<'a, 'b, T> {
2379 fn deref_mut(&mut self) -> &mut Self::Target {
2380 *self.changed = true;
2381 self.value
2382 }
2383}
2384
2385#[test]
2386fn test_access_cell() {
2387 struct FooBar {
2388 i: i32,
2389 }
2390
2391 fn change(change: bool, mut v: AccessCell<FooBar>) {
2392 if change {
2393 v.i = 4;
2394 }
2395 }
2396 let mut foobar = FooBar { i: 1 };
2397 let mut tracker = false;
2398
2399 let accessor = AccessCell {
2400 value: &mut foobar,
2401 changed: &mut tracker,
2402 };
2403 change(false, accessor);
2404 assert_eq!(foobar.i, 1);
2405 assert_eq!(tracker, false);
2406
2407 let accessor = AccessCell {
2408 value: &mut foobar,
2409 changed: &mut tracker,
2410 };
2411 change(true, accessor);
2412 assert_eq!(foobar.i, 4);
2413 assert_eq!(tracker, true);
2414}
2415
2416#[derive(Default)]
2487pub struct StateManager {
2488 states: HashMap<Arc<SourceID>, Box<dyn StateMachineWrapper>>,
2489 pointers: HashMap<*const c_void, Arc<SourceID>>,
2490 changed: bool,
2491}
2492
2493impl StateManager {
2494 pub fn register_pointer<T>(&mut self, p: *const T, id: Arc<SourceID>) -> Option<Arc<SourceID>> {
2495 let ptr = p as *const c_void;
2496 self.pointers.insert(ptr, id)
2497 }
2498
2499 pub fn invalidate_pointer<T>(&mut self, p: *const T) -> Option<Arc<SourceID>> {
2500 let ptr = p as *const c_void;
2501 self.pointers.remove(&ptr)
2502 }
2503
2504 pub fn mutate_pointer<T>(&mut self, p: *const T) {
2505 let ptr = p as *const c_void;
2506 let id = self
2507 .pointers
2508 .get(&ptr)
2509 .expect("Tried to mutate pointer that wasn't registered!")
2510 .clone();
2511
2512 self.mutate_id(&id);
2513 }
2514
2515 pub fn mutate_id(&mut self, id: &Arc<SourceID>) {
2516 if let Some(state) = self.states.get_mut(id) {
2517 state.set_changed(true);
2518 self.propagate_change(id);
2519 }
2520 }
2521
2522 #[allow(dead_code)]
2523 fn init_default<State: component::StateMachineWrapper + Default>(
2524 &mut self,
2525 id: Arc<SourceID>,
2526 ) -> eyre::Result<&mut State> {
2527 if !self.states.contains_key(&id) {
2528 self.states.insert(id.clone(), Box::new(State::default()));
2529 }
2530 let v = &mut *self
2531 .states
2532 .get_mut(&id)
2533 .ok_or_eyre("Failed to insert state!")?
2534 .as_mut() as &mut dyn Any;
2535 v.downcast_mut().ok_or(Error::RuntimeTypeMismatch.into())
2536 }
2537 fn init(&mut self, id: Arc<SourceID>, state: Box<dyn StateMachineWrapper>) {
2538 if !self.states.contains_key(&id) {
2539 self.states.insert(id.clone(), state);
2540 }
2541 }
2542
2543 pub fn get<'a, State: component::StateMachineWrapper>(
2546 &'a self,
2547 id: &SourceID,
2548 ) -> eyre::Result<&'a State> {
2549 let v = self
2550 .states
2551 .get(id)
2552 .ok_or_eyre("State does not exist")?
2553 .as_ref() as &dyn Any;
2554 v.downcast_ref().ok_or(Error::RuntimeTypeMismatch.into())
2555 }
2556
2557 pub fn get_mut<'a, State: component::StateMachineWrapper>(
2561 &'a mut self,
2562 id: &SourceID,
2563 ) -> eyre::Result<&'a mut State> {
2564 let v = &mut *self
2565 .states
2566 .get_mut(id)
2567 .ok_or_eyre("State does not exist")?
2568 .as_mut() as &mut dyn Any;
2569 v.downcast_mut().ok_or(Error::RuntimeTypeMismatch.into())
2570 }
2571
2572 #[allow(clippy::borrowed_box)]
2573 fn get_trait<'a>(&'a self, id: &SourceID) -> eyre::Result<&'a Box<dyn StateMachineWrapper>> {
2574 self.states.get(id).ok_or_eyre("State does not exist")
2575 }
2576
2577 fn propagate_change(&mut self, mut id: &Arc<SourceID>) {
2578 self.changed = true;
2579 while let Some(parent) = id.parent.as_ref() {
2580 if let Some(state) = self.states.get_mut(parent) {
2581 if state.changed() {
2582 return;
2585 }
2586 state.set_changed(true);
2587 }
2588 id = parent;
2589 }
2590 }
2591
2592 fn process(
2593 &mut self,
2594 event: DispatchPair,
2595 slot: &Slot,
2596 dpi: RelDim,
2597 area: PxRect,
2598 extent: PxRect,
2599 driver: &std::sync::Weak<crate::Driver>,
2600 ) -> eyre::Result<bool> {
2601 type IterTuple = (Box<dyn Any>, u64, Option<Slot>);
2602
2603 let mut handled = false;
2606 let iter: SmallVec<[IterTuple; 2]> = {
2607 let state = self.states.get_mut(&slot.0).ok_or_eyre("Invalid slot")?;
2608 let v = match state.process(event, slot.1, dpi, area, extent, driver) {
2609 InputResult::Consume(v) => {
2610 handled = true;
2611 v
2612 }
2613 InputResult::Forward(v) => v,
2614 InputResult::Error(error) => return Err(error),
2615 };
2616 if state.changed() {
2617 self.propagate_change(&slot.0);
2618 }
2619
2620 let state = self.states.get(&slot.0).ok_or(Error::InternalFailure)?;
2621
2622 v.into_iter()
2623 .map(|(i, e)| (e, i, state.output_slot(i.ilog2() as usize).unwrap().clone()))
2624 }
2625 .collect();
2626
2627 for (e, index, slot) in iter {
2628 if let Some(s) = slot.as_ref() {
2629 handled |= self.process((index, e), s, dpi, area, extent, driver)?;
2630 }
2631 }
2632
2633 Ok(handled)
2634 }
2635
2636 fn init_child(
2637 &mut self,
2638 target: &dyn StateMachineChild,
2639 driver: &std::sync::Weak<Driver>,
2640 ) -> eyre::Result<()> {
2641 if !self.states.contains_key(&target.id()) {
2642 match target.init(driver) {
2643 Ok(v) => self.init(target.id().clone(), v),
2644 Err(Error::Stateless) => (),
2645 Err(e) => return Err(e.into()),
2646 };
2647 }
2648
2649 target.apply_children(&mut |child| self.init_child(child, driver))
2650 }
2651}
2652
2653#[allow(clippy::declare_interior_mutable_const)]
2657pub const APP_SOURCE_ID: SourceID = SourceID {
2658 parent: None,
2659 id: DataID::Named("__fg_AppData_ID__"),
2660};
2661
2662type OutlineReturn = im::HashMap<Arc<SourceID>, Option<Window>>;
2663pub type EventPair<AppData> = (u64, AppEvent<AppData>);
2664
2665pub struct App<AppData, O: for<'a> FnPersist2<&'a AppData, ScopeID<'static>, OutlineReturn>, T> {
2674 pub instance: wgpu::Instance,
2675 pub driver: std::sync::Weak<graphics::Driver>,
2676 pub state: StateManager,
2677 store: Option<O::Store>,
2678 outline: O,
2679 _parents: BTreeMap<DataID, DataID>,
2680 root: component::Root, driver_init: Option<Box<dyn FnOnce(std::sync::Weak<Driver>)>>,
2682 handle_sync: mpsc::Receiver<EventPair<AppData>>,
2683 #[allow(clippy::type_complexity)]
2684 user_events: Option<Box<dyn FnMut(&mut Self, &ActiveEventLoop, T)>>,
2685}
2686
2687pub struct AppDataMachine<AppData> {
2688 pub state: AppData,
2689 handlers: HashMap<usize, AppEvent<AppData>>,
2690 changed: bool,
2691}
2692
2693impl<AppData: 'static> StateMachineWrapper for AppDataMachine<AppData> {
2694 fn output_slot(&self, _: usize) -> eyre::Result<&Option<Slot>> {
2695 Ok(&None)
2696 }
2697
2698 fn input_mask(&self) -> u64 {
2699 0
2700 }
2701
2702 fn changed(&self) -> bool {
2703 self.changed
2704 }
2705
2706 fn set_changed(&mut self, changed: bool) {
2707 self.changed = changed;
2708 }
2709
2710 fn process(
2711 &mut self,
2712 input: DispatchPair,
2713 index: u64,
2714 _: RelDim,
2715 _: PxRect,
2716 _: PxRect,
2717 _: &std::sync::Weak<crate::Driver>,
2718 ) -> InputResult<SmallVec<[DispatchPair; 1]>> {
2719 if let Some(f) = self.handlers.get_mut(&(index as usize)) {
2720 let cell = AccessCell {
2721 value: &mut self.state,
2722 changed: &mut self.changed,
2723 };
2724 f(input, cell).map(|_| SmallVec::new())
2725 } else {
2726 InputResult::Error(Error::InternalFailure.into())
2727 }
2728 }
2729}
2730#[cfg(target_os = "windows")]
2731use winit::platform::windows::EventLoopBuilderExtWindows;
2732
2733#[cfg(target_os = "linux")]
2736use winit::platform::x11::EventLoopBuilderExtX11;
2737
2738impl<AppData: 'static, O: for<'a> FnPersist2<&'a AppData, ScopeID<'static>, OutlineReturn>, T>
2739 App<AppData, O, T>
2740{
2741 #[allow(clippy::type_complexity)]
2791 pub fn new(
2792 appstate: AppData,
2793 inputs: Vec<AppEvent<AppData>>,
2794 outline: O,
2795 user_event: Option<Box<dyn FnMut(&mut Self, &ActiveEventLoop, T)>>,
2796 driver_init: Option<Box<dyn FnOnce(std::sync::Weak<Driver>)>>,
2797 ) -> eyre::Result<(
2798 Self,
2799 EventLoop<T>,
2800 mpsc::Sender<EventPair<AppData>>,
2801 AtomicU64,
2802 )> {
2803 #[cfg(test)]
2804 let any_thread = true;
2805 #[cfg(not(test))]
2806 let any_thread = false;
2807
2808 Self::new_any_thread(
2809 appstate,
2810 inputs,
2811 outline,
2812 any_thread,
2813 user_event,
2814 driver_init,
2815 )
2816 }
2817
2818 #[allow(clippy::type_complexity)]
2822 pub fn new_any_thread(
2823 appstate: AppData,
2824 inputs: Vec<AppEvent<AppData>>,
2825 outline: O,
2826 any_thread: bool,
2827 user_event: Option<Box<dyn FnMut(&mut Self, &ActiveEventLoop, T)>>,
2828 driver_init: Option<Box<dyn FnOnce(std::sync::Weak<Driver>)>>,
2829 ) -> eyre::Result<(
2830 Self,
2831 EventLoop<T>,
2832 mpsc::Sender<EventPair<AppData>>,
2833 AtomicU64,
2834 )> {
2835 let count = AtomicU64::new(inputs.len() as u64);
2836 let mut manager: StateManager = Default::default();
2837 manager.init(
2838 Arc::new(APP_SOURCE_ID),
2839 Box::new(AppDataMachine {
2840 handlers: HashMap::from_iter(inputs.into_iter().enumerate()),
2841 state: appstate,
2842 changed: true,
2843 }),
2844 );
2845
2846 #[cfg(target_os = "windows")]
2847 let event_loop = EventLoop::with_user_event()
2848 .with_any_thread(any_thread)
2849 .with_dpi_aware(true)
2850 .build()?;
2851 #[cfg(not(target_os = "windows"))]
2852 let event_loop = EventLoop::with_user_event()
2853 .with_any_thread(any_thread)
2854 .build()
2855 .map_err(|e| {
2856 if e.to_string()
2857 .eq_ignore_ascii_case("Could not find wayland compositor")
2858 {
2859 eyre::eyre!(
2860 "Wayland initialization failed! winit cannot automatically fall back to X11 (). Try running the program with `WAYLAND_DISPLAY=\"\"`"
2861 )
2862 } else {
2863 e.into()
2864 }
2865 })?;
2866
2867 #[cfg(debug_assertions)]
2868 let desc = InstanceDescriptor {
2869 flags: InstanceFlags::debugging(),
2870 ..Default::default()
2871 };
2872 #[cfg(not(debug_assertions))]
2873 let desc = InstanceDescriptor {
2874 flags: InstanceFlags::DISCARD_HAL_LABELS,
2875 ..Default::default()
2876 };
2877
2878 let (sender, recv) = mpsc::channel();
2879 Ok((
2880 Self {
2881 instance: wgpu::Instance::new(&desc),
2882 driver: std::sync::Weak::<graphics::Driver>::new(),
2883 store: None,
2884 outline,
2885 state: manager,
2886 _parents: Default::default(),
2887 root: component::Root::new(),
2888 driver_init,
2889 handle_sync: recv,
2890 user_events: user_event,
2891 },
2892 event_loop,
2893 sender,
2894 count,
2895 ))
2896 }
2897
2898 pub fn with_appstate<R>(&mut self, f: impl FnOnce(AccessCell<AppData>) -> R) -> R {
2902 let app_state: &mut AppDataMachine<AppData> = self.state.get_mut(&APP_SOURCE_ID).unwrap();
2903 let cell = AccessCell {
2904 value: &mut app_state.state,
2905 changed: &mut app_state.changed,
2906 };
2907
2908 let r = f(cell);
2909 if app_state.changed {
2910 for (id, _) in &self.root.children {
2911 let Ok(state) = self.state.get::<WindowStateMachine>(id) else {
2912 continue;
2913 };
2914 state.state.window.request_redraw();
2915 }
2916 }
2917 r
2918 }
2919
2920 #[allow(clippy::borrow_interior_mutable_const)]
2921 fn update_outline(&mut self, event_loop: &ActiveEventLoop, store: O::Store) {
2922 let app_state: &mut AppDataMachine<AppData> = self.state.get_mut(&APP_SOURCE_ID).unwrap();
2923
2924 for (idx, handler) in self.handle_sync.try_iter() {
2925 app_state.handlers.insert(idx as usize, handler);
2926 }
2927
2928 let (store, windows) = self.outline.call(store, &app_state.state, ScopeID::root());
2929 debug_assert!(
2930 APP_SOURCE_ID.parent.is_none(),
2931 "Something set the APP_SOURCE parent! This should never happen!"
2932 );
2933
2934 self.store.replace(store);
2935 self.root.children = windows;
2936 #[cfg(debug_assertions)]
2937 self.root.validate_ids().unwrap();
2938
2939 let (root, manager, graphics, instance, driver_init) = (
2940 &mut self.root,
2941 &mut self.state,
2942 &mut self.driver,
2943 &mut self.instance,
2944 &mut self.driver_init,
2945 );
2946
2947 root.layout_all(manager, graphics, driver_init, instance, event_loop)
2948 .unwrap();
2949
2950 root.stage_all(manager).unwrap();
2951 }
2952}
2953
2954impl<
2955 AppData: 'static,
2956 T: 'static,
2957 O: for<'a> FnPersist2<&'a AppData, ScopeID<'static>, OutlineReturn>,
2958> winit::application::ApplicationHandler<T> for App<AppData, O, T>
2959{
2960 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
2961 let store = self.store.take();
2964 self.update_outline(event_loop, store.unwrap_or_else(|| O::init(&self.outline)));
2965 }
2966 fn window_event(
2967 &mut self,
2968 event_loop: &ActiveEventLoop,
2969 window_id: WindowId,
2970 event: WindowEvent,
2971 ) {
2972 let mut delete = None;
2973 if let Some(root) = self.root.states.get_mut(&window_id) {
2974 let Some(rtree) = root.staging.as_ref().map(|x| x.get_rtree()) else {
2975 panic!("Got root state without valid staging!");
2976 };
2977
2978 if let Some(window) = self.root.children.get(&root.id) {
2979 let window = window.as_ref().unwrap();
2980 let mut resized = false;
2981 let _ = match event {
2982 WindowEvent::CloseRequested => {
2983 let v = Window::on_window_event(
2984 window.id(),
2985 rtree,
2986 event,
2987 &mut self.state,
2988 self.driver.clone(),
2989 );
2990 if v.is_accept() {
2991 delete = Some(window.id());
2992 }
2993 v
2994 }
2995 WindowEvent::RedrawRequested => {
2996 if let Ok(state) = self.state.get_mut::<WindowStateMachine>(&window.id())
2997 && let Some(driver) = self.driver.upgrade()
2998 {
2999 if let Some(staging) = root.staging.as_ref() {
3000 let inner = &mut state.state;
3001 let surface_dim = inner.surface_dim().to_f32();
3002
3003 loop {
3004 let mut viewer = CompositorView {
3006 index: 0,
3007 window: &mut inner.compositor,
3008 layer0: &mut driver.layer_composite[0].write(),
3009 layer1: &mut driver.layer_composite[1].write(),
3010 clipstack: &mut inner.clipstack,
3011 offset: PxVector::zero(),
3012 surface_dim,
3013 pass: 0,
3014 slice: 0,
3015 };
3016
3017 inner.layers.clear();
3019 viewer.clipstack.clear();
3020 if let Err(e) = staging.render(
3021 PxPoint::zero(),
3022 &driver,
3023 &mut viewer,
3024 &mut inner.layers,
3025 ) {
3026 match e {
3027 Error::ResizeTextureAtlas(layers, kind) => {
3028 match kind {
3032 AtlasKind::Primary => driver.atlas.write(),
3033 AtlasKind::Layer0 => {
3034 driver.layer_atlas[0].write()
3035 }
3036 AtlasKind::Layer1 => {
3037 driver.layer_atlas[1].write()
3038 }
3039 }
3040 .resize(&driver.device, &driver.queue, layers);
3041 viewer.window.cleanup();
3042 viewer.layer0.cleanup();
3043 viewer.layer1.cleanup();
3044 continue; }
3046 e => panic!("Fatal draw error: {e}"),
3047 }
3048 }
3049 break;
3050 }
3051 }
3052
3053 let mut encoder = driver.device.create_command_encoder(
3054 &wgpu::CommandEncoderDescriptor {
3055 label: Some("Root Encoder"),
3056 },
3057 );
3058
3059 driver.atlas.write().process_mipmaps(&driver, &mut encoder);
3060 driver.atlas.read().draw(&driver, &mut encoder);
3061
3062 let max_depth = driver.layer_composite[0]
3063 .read()
3064 .segments
3065 .len()
3066 .max(driver.layer_composite[1].read().segments.len());
3067
3068 for i in 0..2 {
3069 let surface_dim = driver.layer_atlas[i].read().texture.size();
3070 driver.layer_composite[i].write().prepare(
3071 &driver,
3072 &mut encoder,
3073 Size2D::<u32, Pixel>::new(
3074 surface_dim.width,
3075 surface_dim.height,
3076 )
3077 .to_f32(),
3078 );
3079 }
3080
3081 for i in (1..max_depth).rev() {
3084 let idx: usize = (i + 1) % 2;
3087 let mut compositor = driver.layer_composite[idx].write();
3088 let atlas = driver.layer_atlas[idx].read();
3089
3090 for slice in 0..atlas.texture.depth_or_array_layers() {
3092 let name = format!(
3093 "Layer {idx} (depth {i}) Atlas (slice {slice}) Pass"
3094 );
3095 let mut pass =
3096 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
3097 label: Some(&name),
3098 color_attachments: &[Some(
3099 wgpu::RenderPassColorAttachment {
3100 view: &atlas.targets[slice as usize],
3101 resolve_target: None,
3102 depth_slice: None,
3103 ops: wgpu::Operations {
3104 load: if true {
3105 wgpu::LoadOp::Clear(
3106 wgpu::Color::TRANSPARENT,
3107 )
3108 } else {
3109 wgpu::LoadOp::Load
3110 },
3111 store: wgpu::StoreOp::Store,
3112 },
3113 },
3114 )],
3115 depth_stencil_attachment: None,
3116 timestamp_writes: None,
3117 occlusion_query_set: None,
3118 });
3119
3120 pass.set_viewport(
3121 0.0,
3122 0.0,
3123 atlas.texture.width() as f32,
3124 atlas.texture.height() as f32,
3125 0.0,
3126 1.0,
3127 );
3128
3129 compositor.draw(&driver, &mut pass, i as u8, slice as u8);
3130 }
3131 }
3132
3133 state.state.draw(encoder);
3134 driver.layer_composite[0].write().cleanup();
3135 driver.layer_composite[1].write().cleanup();
3136 }
3137
3138 InputResult::Consume(())
3139 }
3140 WindowEvent::Resized(_) => {
3141 resized = true;
3142 Window::on_window_event(
3143 window.id(),
3144 rtree,
3145 event,
3146 &mut self.state,
3147 self.driver.clone(),
3148 )
3149 }
3150 _ => Window::on_window_event(
3151 window.id(),
3152 rtree,
3153 event,
3154 &mut self.state,
3155 self.driver.clone(),
3156 ),
3157 };
3158
3159 if self.state.changed || resized {
3160 self.state.changed = false;
3161 let store = self.store.take().unwrap();
3162 self.update_outline(event_loop, store);
3163 }
3164 }
3165 }
3166
3167 if let Some(id) = delete {
3168 self.root.children.remove(&id);
3169 }
3170
3171 if self.root.children.is_empty() {
3172 event_loop.exit();
3173 }
3174 }
3175
3176 fn device_event(
3177 &mut self,
3178 event_loop: &ActiveEventLoop,
3179 device_id: winit::event::DeviceId,
3180 event: winit::event::DeviceEvent,
3181 ) {
3182 let _ = (event_loop, device_id, event);
3183 }
3184
3185 fn user_event(&mut self, event_loop: &ActiveEventLoop, evt: T) {
3186 if let Some(mut f) = self.user_events.take() {
3187 (f)(self, event_loop, evt);
3188 self.user_events.replace(f);
3189 }
3190 }
3191
3192 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
3193 let _ = event_loop;
3194 }
3195}
3196
3197#[cfg(test)]
3198struct TestApp {}
3199
3200#[cfg(test)]
3201impl crate::persist::FnPersistStore for TestApp {
3202 type Store = (u8, OutlineReturn);
3203}
3204
3205#[cfg(test)]
3206impl FnPersist2<&u8, ScopeID<'static>, OutlineReturn> for TestApp {
3207 fn init(&self) -> Self::Store {
3208 (0, im::HashMap::new())
3209 }
3210
3211 fn call(
3212 &mut self,
3213 store: Self::Store,
3214 _: &u8,
3215 mut id: ScopeID<'static>,
3216 ) -> (Self::Store, OutlineReturn) {
3217 use crate::color::sRGB;
3218 use crate::component::shape::Shape;
3219
3220 let rect = Shape::<DRect, { component::shape::ShapeKind::RoundRect as u8 }>::new(
3221 gen_id!(id),
3222 crate::FILL_DRECT.into(),
3223 0.0,
3224 0.0,
3225 f32x4::splat(0.0),
3226 sRGB::new(1.0, 0.0, 0.0, 1.0),
3227 sRGB::transparent(),
3228 DAbsPoint::zero(),
3229 );
3230 let window = Window::new(
3231 gen_id!(id),
3232 winit::window::Window::default_attributes()
3233 .with_title("test_blank")
3234 .with_resizable(true),
3235 Box::new(rect),
3236 );
3237
3238 let mut windows = im::HashMap::new();
3239 windows.insert(window.id().clone(), Some(window));
3240
3241 (store, windows)
3242 }
3243}
3244
3245#[test]
3246fn test_basic() {
3247 let (mut app, event_loop, _, _) = App::<u8, TestApp, ()>::new(
3248 0u8,
3249 vec![],
3250 TestApp {},
3251 Some(Box::new(|_, evt: &ActiveEventLoop, _| evt.exit())),
3252 None,
3253 )
3254 .unwrap();
3255
3256 let proxy = event_loop.create_proxy();
3257 proxy.send_event(()).unwrap();
3258 event_loop.run_app(&mut app).unwrap();
3259}
3260
3261#[test]
3262fn test_absrect_contain() {
3263 let target = AbsRect::new(0.0, 0.0, 2.0, 2.0);
3264
3265 for x in 0..=2 {
3266 for y in 0..=2 {
3267 if x == 2 || y == 2 {
3268 assert!(!target.contains(AbsPoint::new(x as f32, y as f32)));
3269 } else {
3270 assert!(
3271 target.contains(AbsPoint::new(x as f32, y as f32)),
3272 "{x} {y} not inside {target}"
3273 );
3274 }
3275 }
3276 }
3277
3278 assert!(target.contains(AbsPoint::new(1.999, 1.999)));
3279
3280 for y in -1..=3 {
3281 assert!(!target.contains(AbsPoint::new(-1.0, y as f32)));
3282 assert!(!target.contains(AbsPoint::new(3.0, y as f32)));
3283 assert!(!target.contains(AbsPoint::new(3000000.0, y as f32)));
3284 }
3285
3286 for x in -1..=3 {
3287 assert!(!target.contains(AbsPoint::new(x as f32, -1.0)));
3288 assert!(!target.contains(AbsPoint::new(x as f32, 3.0)));
3289 assert!(!target.contains(AbsPoint::new(x as f32, -3000000.0)));
3290 }
3291}
3292
3293#[test]
3294fn test_absrect_collide() {
3295 let target = AbsRect::new(0.0, 0.0, 4.0, 4.0);
3296
3297 for l in 0..=3 {
3298 for t in 0..=3 {
3299 for r in 1..=4 {
3300 for b in 1..=4 {
3301 let rhs = AbsRect::new(l as f32, t as f32, r as f32, b as f32);
3302 assert!(
3303 target.collides(&rhs),
3304 "{target} not detected as touching {rhs}"
3305 );
3306 }
3307 }
3308 }
3309 }
3310
3311 for l in -2..=3 {
3312 for t in -2..=3 {
3313 for r in 1..=4 {
3314 for b in 1..=4 {
3315 assert!(target.collides(&AbsRect::new(l as f32, t as f32, r as f32, b as f32)));
3316 }
3317 }
3318 }
3319 }
3320
3321 for l in 1..=3 {
3322 for t in 1..=3 {
3323 for r in 3..=6 {
3324 if r > t {
3325 for b in 3..=6 {
3326 if b > t {
3327 let rhs = AbsRect::new(l as f32, t as f32, r as f32, b as f32);
3328 assert!(
3329 target.collides(&rhs),
3330 "{target} not detected as touching {rhs}"
3331 );
3332 }
3333 }
3334 }
3335 }
3336 }
3337 }
3338
3339 assert!(!target.collides(&AbsRect::new(1.0, 4.0, 5.0, 5.0)));
3340
3341 assert!(!target.collides(&AbsRect::new(4.0, 4.0, 5.0, 5.0)));
3344 assert!(!target.collides(&AbsRect::new(4.0, 0.0, 5.0, 4.0)));
3345 assert!(!target.collides(&AbsRect::new(0.0, 4.0, 4.0, 5.0)));
3346
3347 assert!(!target.collides(&AbsRect::new(-1.0, -1.0, 0.0, 0.0)));
3348 assert!(!target.collides(&AbsRect::new(-1.0, 0.0, 0.0, 4.0)));
3349 assert!(!target.collides(&AbsRect::new(0.0, -1.0, 4.0, 0.0)));
3350}
3351
3352#[test]
3353fn test_absrect_intersect() {
3354 let target = AbsRect::new(0.0, 0.0, 4.0, 4.0);
3355
3356 assert!(target.intersect(AbsRect::new(2.0, 2.0, 6.0, 6.0)) == AbsRect::new(2.0, 2.0, 4.0, 4.0));
3357 assert!(
3358 target.intersect(AbsRect::new(-2.0, -2.0, 2.0, 2.0)) == AbsRect::new(0.0, 0.0, 2.0, 2.0)
3359 );
3360
3361 assert!(
3362 target.intersect(AbsRect::new(-2.0, -2.0, -1.0, -1.0)) == AbsRect::new(0.0, 0.0, 0.0, 0.0)
3363 );
3364
3365 assert!(target.intersect(AbsRect::new(6.0, 6.0, 8.0, 8.0)) == AbsRect::new(6.0, 6.0, 6.0, 6.0));
3366}
3367
3368#[test]
3369fn test_absrect_extend() {
3370 let target = AbsRect::new(0.0, 0.0, 4.0, 4.0);
3371
3372 assert!(target.extend(AbsRect::new(2.0, 2.0, 6.0, 6.0)) == AbsRect::new(0.0, 0.0, 6.0, 6.0));
3373 assert!(
3374 target.extend(AbsRect::new(-2.0, -2.0, 2.0, 2.0)) == AbsRect::new(-2.0, -2.0, 4.0, 4.0)
3375 );
3376}
3377
3378#[test]
3379fn test_limits_add() {
3380 let limits = AbsLimits::new(.., 10.0..200.0);
3381 assert_eq!(
3382 limits.min(),
3383 Size2D::<f32, Logical>::new(f32::NEG_INFINITY, 10.0)
3384 );
3385 assert_eq!(
3386 limits.max(),
3387 Size2D::<f32, Logical>::new(f32::INFINITY, 200.0)
3388 );
3389
3390 let rlimits = RelLimits::new(..1.0, ..);
3391 assert_eq!(
3392 rlimits.min(),
3393 Size2D::<f32, Relative>::new(f32::NEG_INFINITY, f32::NEG_INFINITY)
3394 );
3395 assert_eq!(
3396 rlimits.max(),
3397 Size2D::<f32, Relative>::new(1.0, f32::INFINITY)
3398 );
3399
3400 let merged = AbsLimits::new(0.0.., 5.0..100.0) + limits;
3401 assert_eq!(merged.min(), Size2D::<f32, Logical>::new(0.0, 10.0));
3402 assert_eq!(
3403 merged.max(),
3404 Size2D::<f32, Logical>::new(f32::INFINITY, 100.0)
3405 );
3406}