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
73#[macro_export]
88macro_rules! gen_id {
89 ($idx:expr) => {
90 $idx.child($crate::DataID::Named(concat!(file!(), ":", line!())))
91 };
92 ($idx:expr, $i:expr) => {
93 $idx.child($crate::DataID::Int($i as i64))
94 };
95}
96
97use std::any::TypeId;
98#[derive(thiserror::Error, Debug)]
99pub enum Error {
100 #[error("Not an error, this component simply has no layout state.")]
101 Stateless,
102 #[error("Enum object didn't match tag {0}! Expected {1:?} but got {2:?}")]
103 MismatchedEnumTag(u64, TypeId, TypeId),
104 #[error("Invalid enum tag: {0}")]
105 InvalidEnumTag(u64),
106 #[error("Event handler didn't handle this method.")]
107 UnhandledEvent,
108 #[error("Frame aborted due to pending Texture Atlas resize.")]
109 ResizeTextureAtlas(u32, crate::render::atlas::AtlasKind),
110 #[error("Internal texture atlas reservation failure.")]
111 AtlasReservationFailure,
112 #[error("Internal texture atlas cache lookup failure.")]
113 AtlasCacheFailure,
114 #[error("Internal glyph render failure.")]
115 GlyphRenderFailure,
116 #[error("Internal glyph cache lookup failure.")]
117 GlyphCacheFailure,
118 #[error("An assumption about internal state was incorrect.")]
119 InternalFailure,
120 #[error("A filesystem error occurred: {0}")]
121 FileError(std::io::Error),
122 #[error("An error happened when loading a resource: {0:?}")]
123 ResourceError(Box<dyn std::fmt::Debug + Send + Sync>),
124 #[error(
125 "The resource was in an unrecognized format. Are you sure you enabled the right feature flags?"
126 )]
127 UnknownResourceFormat,
128 #[error("An index was out of range: {0}")]
129 OutOfRange(usize),
130 #[error("Type mismatch occured when attempting a downcast that should never fail!")]
131 RuntimeTypeMismatch,
132}
133
134impl From<std::io::Error> for Error {
135 fn from(value: std::io::Error) -> Self {
136 Self::FileError(value)
137 }
138}
139
140pub const UNSIZED_AXIS: f32 = f32::MAX;
144
145pub const BASE_DPI: RelDim = RelDim::new(96.0, 96.0);
148
149const MINUS_BOTTOMRIGHT: f32x4 = f32x4::new([1.0, 1.0, -1.0, -1.0]);
150
151#[macro_export]
180macro_rules! children {
181 () => { [] };
182 ($prop:path, $($param:expr),+ $(,)?) => { $crate::im::Vector::from_iter([$(Some(Box::new($param) as Box<$crate::component::ChildOf<dyn $prop>>)),+]) };
183}
184
185#[macro_export]
186macro_rules! handlers {
187 () => { [] };
188 ($app:path, $($param:ident),+ $(,)?) => { Vec::from_iter([$((stringify!($param).to_string(), Box::new($param) as $crate::AppEvent<$app>)),+]) };
189}
190
191#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
192pub struct Logical {}
194#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
195pub struct Relative {}
197#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
198pub struct Pixel {}
200#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
201pub struct Resolved {}
203
204pub type AbsPoint = Point2D<f32, Logical>;
206pub type PxPoint = Point2D<f32, Pixel>;
208pub type RelPoint = Point2D<f32, Relative>;
210pub type ResPoint = Point2D<f32, Resolved>;
212
213pub type AbsVector = Vector2D<f32, Logical>;
215pub type PxVector = Vector2D<f32, Pixel>;
217pub type RelVector = Vector2D<f32, Relative>;
219pub type ResVector = Vector2D<f32, Resolved>;
221
222pub type AbsDim = Size2D<f32, Logical>;
224pub type PxDim = Size2D<f32, Pixel>;
226pub type RelDim = Size2D<f32, Relative>;
228pub type ResDim = Size2D<f32, Resolved>;
230
231trait UnResolve<U> {
233 fn unresolve(self, dpi: RelDim) -> U;
234}
235
236impl UnResolve<AbsVector> for PxVector {
237 fn unresolve(self, dpi: RelDim) -> AbsVector {
238 AbsVector::new(self.x / dpi.width, self.y / dpi.height)
239 }
240}
241
242impl UnResolve<AbsPoint> for PxPoint {
243 fn unresolve(self, dpi: RelDim) -> AbsPoint {
244 AbsPoint::new(self.x / dpi.width, self.y / dpi.height)
245 }
246}
247
248trait Convert<U> {
251 fn to(self) -> U;
252}
253
254impl Convert<Size2D<u32, Pixel>> for winit::dpi::PhysicalSize<u32> {
255 fn to(self) -> Size2D<u32, Pixel> {
256 Size2D::<u32, Pixel>::new(self.width, self.height)
257 }
258}
259
260impl Convert<Size2D<u32, Logical>> for winit::dpi::LogicalSize<u32> {
261 fn to(self) -> Size2D<u32, Logical> {
262 Size2D::<u32, Logical>::new(self.width, self.height)
263 }
264}
265
266impl Convert<Point2D<f32, Pixel>> for winit::dpi::PhysicalPosition<f32> {
267 fn to(self) -> Point2D<f32, Pixel> {
268 Point2D::<f32, Pixel>::new(self.x, self.y)
269 }
270}
271
272impl Convert<Point2D<f64, Pixel>> for winit::dpi::PhysicalPosition<f64> {
273 fn to(self) -> Point2D<f64, Pixel> {
274 Point2D::<f64, Pixel>::new(self.x, self.y)
275 }
276}
277
278#[derive(Copy, Clone, Debug, Default, PartialEq)]
281pub struct Rect<U> {
282 pub v: f32x4,
283 #[doc(hidden)]
284 pub _unit: PhantomData<U>,
285}
286
287pub type AbsRect = Rect<Logical>;
289pub type PxRect = Rect<Pixel>;
291pub type RelRect = Rect<Relative>;
293pub type ResRect = Rect<Resolved>;
295
296unsafe impl<U: Copy + 'static> NoUninit for Rect<U> {}
297
298pub const ZERO_RECT: AbsRect = AbsRect::zero();
299
300impl<U> Rect<U> {
301 #[inline]
302 pub const fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
303 Self {
304 v: f32x4::new([left, top, right, bottom]),
305 _unit: PhantomData,
306 }
307 }
308
309 pub const fn splat(x: f32) -> Self {
310 Self {
311 v: f32x4::new([x, x, x, x]), _unit: PhantomData,
313 }
314 }
315
316 #[inline]
317 pub const fn corners(topleft: Point2D<f32, U>, bottomright: Point2D<f32, U>) -> Self {
318 Self {
319 v: f32x4::new([topleft.x, topleft.y, bottomright.x, bottomright.y]),
320 _unit: PhantomData,
321 }
322 }
323
324 #[inline]
325 pub fn contains(&self, p: Point2D<f32, U>) -> bool {
326 f32x4::new([p.x, p.y, p.x, p.y]).cmp_ge(self.v).move_mask() == 0b0011
329
330 }
335
336 #[inline]
337 pub fn collides(&self, rhs: &Self) -> bool {
338 let r = rhs.v.as_array_ref();
339 f32x4::new([r[2], r[3], -r[0], -r[1]])
340 .cmp_gt(self.v * MINUS_BOTTOMRIGHT)
341 .all()
342
343 }
348
349 #[inline]
350 pub fn intersect(&self, rhs: Self) -> Self {
351 let rect =
352 (self.v * MINUS_BOTTOMRIGHT).fast_max(rhs.v * MINUS_BOTTOMRIGHT) * MINUS_BOTTOMRIGHT;
353
354 let a = rect.to_array();
356 Self {
357 v: rect.fast_max(f32x4::new([a[0], a[1], a[0], a[1]])),
358 _unit: PhantomData,
359 }
360
361 }
370
371 #[inline]
372 pub fn extend(&self, rhs: Self) -> Self {
373 Self {
378 v: (self.v * MINUS_BOTTOMRIGHT).fast_min(rhs.v * MINUS_BOTTOMRIGHT) * MINUS_BOTTOMRIGHT,
379 _unit: PhantomData,
380 }
381 }
382
383 #[inline]
384 pub fn topleft(&self) -> Point2D<f32, U> {
385 let ltrb = self.v.as_array_ref();
386 Point2D::new(ltrb[0], ltrb[1])
387 }
388
389 #[inline]
390 pub fn set_topleft(&mut self, v: Point2D<f32, U>) {
391 let ltrb = self.v.as_array_mut();
392 ltrb[0] = v.x;
393 ltrb[1] = v.y;
394 }
395
396 #[inline]
397 pub fn bottomright(&self) -> Point2D<f32, U> {
398 let ltrb = self.v.as_array_ref();
399 Point2D::new(ltrb[2], ltrb[3])
400 }
401
402 #[inline]
403 pub fn set_bottomright(&mut self, v: Point2D<f32, U>) {
404 let ltrb = self.v.as_array_mut();
405 ltrb[2] = v.x;
406 ltrb[3] = v.y;
407 }
408
409 #[inline]
410 pub fn dim(&self) -> Size2D<f32, U> {
411 let ltrb = self.v.as_array_ref();
412 Size2D::new(ltrb[2] - ltrb[0], ltrb[3] - ltrb[1])
413 }
414
415 #[inline]
416 pub const fn zero() -> Self {
417 Self {
418 v: f32x4::ZERO,
419 _unit: PhantomData,
420 }
421 }
422
423 #[inline]
424 pub const fn unit() -> Self {
425 Self {
426 v: f32x4::new([0.0, 0.0, 1.0, 1.0]),
427 _unit: PhantomData,
428 }
429 }
430
431 #[inline]
433 pub fn to_untyped(self) -> PxRect {
434 self.cast_unit()
435 }
436
437 #[inline]
439 pub fn cast_unit<V>(self) -> Rect<V> {
440 Rect::<V> {
441 v: self.v,
442 _unit: PhantomData,
443 }
444 }
445}
446
447impl<U> Display for Rect<U> {
448 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
449 let ltrb = self.v.as_array_ref();
450 write!(
451 f,
452 "Rect[({},{});({},{})]",
453 ltrb[0], ltrb[1], ltrb[2], ltrb[3]
454 )
455 }
456}
457
458impl<U> From<[f32; 4]> for Rect<U> {
459 #[inline]
460 fn from(value: [f32; 4]) -> Self {
461 Self {
462 v: f32x4::new(value),
463 _unit: PhantomData,
464 }
465 }
466}
467
468#[inline]
469const fn splat_point<U>(v: Point2D<f32, U>) -> f32x4 {
470 f32x4::new([v.x, v.y, v.x, v.y])
471}
472
473#[inline]
474const fn splat_size<U>(v: Size2D<f32, U>) -> f32x4 {
475 f32x4::new([v.width, v.height, v.width, v.height])
476}
477
478impl<U> Add<Point2D<f32, U>> for Rect<U> {
479 type Output = Self;
480
481 #[inline]
482 fn add(self, rhs: Point2D<f32, U>) -> Self::Output {
483 Self {
484 v: self.v + splat_point(rhs),
485 _unit: PhantomData,
486 }
487 }
488}
489
490impl<U> AddAssign<Point2D<f32, U>> for Rect<U> {
491 #[inline]
492 fn add_assign(&mut self, rhs: Point2D<f32, U>) {
493 self.v += splat_point(rhs)
494 }
495}
496
497impl<U> Add<Vector2D<f32, U>> for Rect<U> {
498 type Output = Self;
499
500 #[inline]
501 fn add(self, rhs: Vector2D<f32, U>) -> Self::Output {
502 Self {
503 v: self.v + splat_point(rhs.to_point()),
504 _unit: PhantomData,
505 }
506 }
507}
508
509impl<U> AddAssign<Vector2D<f32, U>> for Rect<U> {
510 #[inline]
511 fn add_assign(&mut self, rhs: Vector2D<f32, U>) {
512 self.v += splat_point(rhs.to_point())
513 }
514}
515
516impl<U> Sub<Point2D<f32, U>> for Rect<U> {
517 type Output = Self;
518
519 #[inline]
520 fn sub(self, rhs: Point2D<f32, U>) -> Self::Output {
521 Self {
522 v: self.v - splat_point(rhs),
523 _unit: PhantomData,
524 }
525 }
526}
527
528impl<U> SubAssign<Point2D<f32, U>> for Rect<U> {
529 #[inline]
530 fn sub_assign(&mut self, rhs: Point2D<f32, U>) {
531 self.v -= splat_point(rhs)
532 }
533}
534
535impl<U> Neg for Rect<U> {
536 type Output = Rect<U>;
537
538 fn neg(self) -> Self::Output {
539 Self::Output {
540 v: -self.v,
541 _unit: PhantomData,
542 }
543 }
544}
545
546impl<U> From<Size2D<f32, U>> for Rect<U> {
547 fn from(value: Size2D<f32, U>) -> Self {
548 Self {
549 v: f32x4::new([0.0, 0.0, value.width, value.height]),
550 _unit: PhantomData,
551 }
552 }
553}
554
555#[derive(Copy, Clone, Debug, Default, PartialEq)]
558pub struct Perimeter<U> {
559 pub v: f32x4,
560 #[doc(hidden)]
561 pub _unit: PhantomData<U>,
562}
563
564impl<U> Perimeter<U> {
565 #[inline]
566 pub fn topleft(&self) -> Size2D<f32, U> {
567 let ltrb = self.v.as_array_ref();
568 Size2D::<f32, U> {
569 width: ltrb[0],
570 height: ltrb[1],
571 _unit: PhantomData,
572 }
573 }
574
575 #[inline]
576 pub fn bottomright(&self) -> Size2D<f32, U> {
577 let ltrb = self.v.as_array_ref();
578 Size2D::<f32, U> {
579 width: ltrb[2],
580 height: ltrb[3],
581 _unit: PhantomData,
582 }
583 }
584
585 #[inline]
587 pub fn to_untyped(self) -> Perimeter<euclid::UnknownUnit> {
588 self.cast_unit()
589 }
590
591 #[inline]
593 pub fn cast_unit<V>(self) -> Perimeter<V> {
594 Perimeter::<V> {
595 v: self.v,
596 _unit: PhantomData,
597 }
598 }
599}
600
601pub type PxPerimeter = Perimeter<Pixel>;
602
603impl<U> Add<Perimeter<U>> for Rect<U> {
604 type Output = Self;
605
606 #[inline]
607 fn add(self, rhs: Perimeter<U>) -> Self::Output {
608 Self {
609 v: self.v + (rhs.v * MINUS_BOTTOMRIGHT),
610 _unit: PhantomData,
611 }
612 }
613}
614
615impl<U> AddAssign<Perimeter<U>> for AbsRect {
616 #[inline]
617 fn add_assign(&mut self, rhs: Perimeter<U>) {
618 self.v += rhs.v * MINUS_BOTTOMRIGHT
619 }
620}
621
622#[derive(Copy, Clone, Debug, Default, PartialEq)]
623pub struct DAbsRect {
625 dp: AbsRect,
626 px: PxRect,
627}
628
629pub const ZERO_DABSRECT: DAbsRect = DAbsRect {
630 dp: AbsRect::zero(),
631 px: PxRect::zero(),
632};
633
634impl DAbsRect {
635 fn resolve(&self, dpi: RelDim) -> PxRect {
636 PxRect {
637 v: self.px.v + (self.dp.v * splat_size(dpi)),
638 _unit: PhantomData,
639 }
640 }
641
642 fn as_perimeter(&self, dpi: RelDim) -> PxPerimeter {
643 PxPerimeter {
644 v: self.resolve(dpi).v,
645 _unit: PhantomData,
646 }
647 }
648}
649
650impl From<AbsRect> for DAbsRect {
651 fn from(value: AbsRect) -> Self {
652 DAbsRect {
653 dp: value,
654 px: PxRect::zero(),
655 }
656 }
657}
658
659impl From<PxRect> for DAbsRect {
660 fn from(value: PxRect) -> Self {
661 DAbsRect {
662 dp: AbsRect::zero(),
663 px: value,
664 }
665 }
666}
667
668impl Neg for DAbsRect {
669 type Output = DAbsRect;
670
671 fn neg(self) -> Self::Output {
672 Self::Output {
673 dp: -self.dp,
674 px: -self.px,
675 }
676 }
677}
678
679#[derive(Copy, Clone, Debug, Default, PartialEq)]
680pub struct DAbsPoint {
702 pub dp: AbsPoint,
703 pub px: PxPoint,
704}
705
706impl DAbsPoint {
707 pub const fn zero() -> Self {
708 Self {
709 dp: AbsPoint::new(0.0, 0.0),
710 px: PxPoint::new(0.0, 0.0),
711 }
712 }
713
714 pub const fn unit() -> Self {
715 Self {
716 dp: AbsPoint::new(1.0, 1.0),
717 px: PxPoint::new(1.0, 1.0),
718 }
719 }
720
721 fn resolve(&self, dpi: RelDim) -> ResPoint {
722 ResPoint {
723 x: self.px.x + (self.dp.x * dpi.width),
724 y: self.px.y + (self.dp.y * dpi.height),
725 _unit: PhantomData,
726 }
727 }
729}
730
731impl From<AbsPoint> for DAbsPoint {
732 fn from(value: AbsPoint) -> Self {
733 DAbsPoint {
734 dp: value,
735 px: PxPoint::zero(),
736 }
737 }
738}
739
740impl From<PxPoint> for DAbsPoint {
741 fn from(value: PxPoint) -> Self {
742 DAbsPoint {
743 dp: AbsPoint::zero(),
744 px: value,
745 }
746 }
747}
748
749impl Add<DAbsPoint> for DAbsPoint {
750 type Output = DAbsPoint;
751
752 fn add(self, rhs: DAbsPoint) -> Self::Output {
753 Self::Output {
754 dp: self.dp + rhs.dp.to_vector(),
755 px: self.px + rhs.px.to_vector(),
756 }
757 }
758}
759
760impl AddAssign<DAbsPoint> for DAbsPoint {
761 fn add_assign(&mut self, rhs: DAbsPoint) {
762 self.dp += rhs.dp.to_vector();
763 self.px += rhs.px.to_vector();
764 }
765}
766
767impl Neg for DAbsPoint {
768 type Output = DAbsPoint;
769
770 fn neg(self) -> Self::Output {
771 Self::Output {
772 dp: -self.dp,
773 px: -self.px,
774 }
775 }
776}
777
778#[inline]
779pub fn build_aabb<U>(a: Point2D<f32, U>, b: Point2D<f32, U>) -> Rect<U> {
780 Rect::<U>::corners(a.min(b), a.max(b))
781}
782
783#[derive(Copy, Clone, Debug, Default, PartialEq)]
784pub struct UPoint(f32x4);
786
787pub const ZERO_UPOINT: UPoint = UPoint(f32x4::ZERO);
788
789impl UPoint {
790 #[inline]
791 pub const fn new(abs: ResPoint, rel: RelPoint) -> Self {
792 Self(f32x4::new([abs.x, abs.y, rel.x, rel.y]))
793 }
794 #[inline]
795 pub fn abs(&self) -> ResPoint {
796 let ltrb = self.0.as_array_ref();
797 ResPoint {
798 x: ltrb[0],
799 y: ltrb[1],
800 _unit: PhantomData,
801 }
802 }
803 #[inline]
804 pub fn rel(&self) -> RelPoint {
805 let ltrb = self.0.as_array_ref();
806 RelPoint {
807 x: ltrb[2],
808 y: ltrb[3],
809 _unit: PhantomData,
810 }
811 }
812}
813
814impl Add for UPoint {
815 type Output = Self;
816
817 #[inline]
818 fn add(self, rhs: Self) -> Self {
819 Self(self.0 + rhs.0)
820 }
821}
822
823impl Sub for UPoint {
824 type Output = Self;
825
826 #[inline]
827 fn sub(self, rhs: Self) -> Self {
828 Self(self.0 - rhs.0)
829 }
830}
831
832impl Mul<PxDim> for UPoint {
833 type Output = PxPoint;
834
835 #[inline]
836 fn mul(self, rhs: PxDim) -> Self::Output {
837 let rel = self.rel();
838 self.abs()
839 .add_size(&Size2D::<f32, Resolved>::new(
840 rel.x * rhs.width,
841 rel.y * rhs.height,
842 ))
843 .cast_unit()
844 }
845}
846
847impl Neg for UPoint {
848 type Output = UPoint;
849
850 fn neg(self) -> Self::Output {
851 UPoint(-self.0)
852 }
853}
854
855#[derive(Copy, Clone, Debug, Default, PartialEq)]
876pub struct DPoint {
877 pub dp: AbsPoint,
878 pub px: PxPoint,
879 pub rel: RelPoint,
880}
881
882pub const ZERO_DPOINT: DPoint = DPoint {
883 px: PxPoint {
884 x: 0.0,
885 y: 0.0,
886 _unit: PhantomData,
887 },
888 dp: AbsPoint {
889 x: 0.0,
890 y: 0.0,
891 _unit: PhantomData,
892 },
893 rel: RelPoint {
894 x: 0.0,
895 y: 0.0,
896 _unit: PhantomData,
897 },
898};
899
900impl DPoint {
901 const fn resolve(&self, dpi: RelDim) -> UPoint {
902 UPoint(f32x4::new([
903 self.px.x + (self.dp.x * dpi.width),
904 self.px.y + (self.dp.y * dpi.height),
905 self.rel.x,
906 self.rel.y,
907 ]))
908 }
909}
910
911impl From<AbsPoint> for DPoint {
912 fn from(value: AbsPoint) -> Self {
913 Self {
914 dp: value,
915 px: PxPoint::zero(),
916 rel: RelPoint::zero(),
917 }
918 }
919}
920
921impl From<PxPoint> for DPoint {
922 fn from(value: PxPoint) -> Self {
923 Self {
924 dp: AbsPoint::zero(),
925 px: value,
926 rel: RelPoint::zero(),
927 }
928 }
929}
930
931impl From<RelPoint> for DPoint {
932 fn from(value: RelPoint) -> Self {
933 Self {
934 dp: AbsPoint::zero(),
935 px: PxPoint::zero(),
936 rel: value,
937 }
938 }
939}
940
941impl Add<DPoint> for DPoint {
942 type Output = Self;
943
944 #[inline]
945 fn add(self, rhs: DPoint) -> Self::Output {
946 Self::Output {
947 dp: self.dp + rhs.dp.to_vector(),
948 px: self.px + rhs.px.to_vector(),
949 rel: self.rel + rhs.rel.to_vector(),
950 }
951 }
952}
953
954impl Sub<DPoint> for DPoint {
955 type Output = Self;
956
957 #[inline]
958 fn sub(self, rhs: DPoint) -> Self::Output {
959 self + (-rhs)
960 }
961}
962
963impl Neg for DPoint {
964 type Output = DPoint;
965
966 fn neg(self) -> Self::Output {
967 Self::Output {
968 dp: -self.dp,
969 px: -self.px,
970 rel: -self.rel,
971 }
972 }
973}
974
975#[derive(Copy, Clone, Debug, Default, PartialEq)]
976pub struct URect {
978 pub abs: ResRect,
979 pub rel: RelRect,
980}
981
982impl URect {
983 #[inline]
984 pub fn topleft(&self) -> UPoint {
985 let abs = self.abs.v.as_array_ref();
986 let rel = self.rel.v.as_array_ref();
987 UPoint(f32x4::new([abs[0], abs[1], rel[0], rel[1]]))
988 }
989
990 #[inline]
991 pub fn bottomright(&self) -> UPoint {
992 let abs = self.abs.v.as_array_ref();
993 let rel = self.rel.v.as_array_ref();
994 UPoint(f32x4::new([abs[2], abs[3], rel[2], rel[3]]))
995 }
996
997 #[inline]
998 pub fn resolve(&self, rect: PxRect) -> PxRect {
999 let ltrb = rect.v.as_array_ref();
1000 let topleft = f32x4::new([ltrb[0], ltrb[1], ltrb[0], ltrb[1]]);
1001 let bottomright = f32x4::new([ltrb[2], ltrb[3], ltrb[2], ltrb[3]]);
1002
1003 PxRect {
1004 v: topleft + self.abs.v + self.rel.v * (bottomright - topleft),
1005 _unit: PhantomData,
1006 }
1007 }
1008
1009 #[inline]
1010 pub fn to_perimeter(&self, rect: PxRect) -> PxPerimeter {
1011 PxPerimeter {
1012 v: self.resolve(rect).v,
1013 _unit: PhantomData,
1014 }
1015 }
1016}
1017
1018pub const ZERO_URECT: URect = URect {
1019 abs: ResRect::zero(),
1020 rel: RelRect::zero(),
1021};
1022
1023pub const FILL_URECT: URect = URect {
1024 abs: ResRect::zero(),
1025 rel: RelRect::unit(),
1026};
1027
1028pub const AUTO_URECT: URect = URect {
1029 abs: ResRect::zero(),
1030 rel: RelRect::new(0.0, 0.0, UNSIZED_AXIS, UNSIZED_AXIS),
1031};
1032
1033impl Mul<PxRect> for URect {
1034 type Output = PxRect;
1035
1036 #[inline]
1037 fn mul(self, rhs: PxRect) -> Self::Output {
1038 self.resolve(rhs)
1039 }
1040}
1041
1042impl Mul<PxDim> for URect {
1043 type Output = PxRect;
1044
1045 #[inline]
1046 fn mul(self, rhs: PxDim) -> Self::Output {
1047 Self::Output {
1048 v: self.abs.v + self.rel.v * splat_size(rhs),
1049 _unit: PhantomData,
1050 }
1051 }
1052}
1053
1054impl Neg for URect {
1055 type Output = URect;
1056
1057 fn neg(self) -> Self::Output {
1058 URect {
1059 abs: -self.abs,
1060 rel: -self.rel,
1061 }
1062 }
1063}
1064
1065#[derive(Copy, Clone, Debug, Default, PartialEq)]
1090pub struct DRect {
1091 pub px: PxRect,
1092 pub dp: AbsRect,
1093 pub rel: RelRect,
1094}
1095
1096impl DRect {
1097 fn resolve(&self, dpi: RelDim) -> URect {
1098 URect {
1099 abs: ResRect {
1100 v: self.px.v + (self.dp.v * splat_size(dpi)),
1101 _unit: PhantomData,
1102 },
1103 rel: self.rel,
1104 }
1105 }
1106
1107 pub fn topleft(&self) -> DPoint {
1110 DPoint {
1111 dp: self.dp.topleft(),
1112 px: self.px.topleft(),
1113 rel: self.rel.topleft(),
1114 }
1115 }
1116
1117 pub fn bottomright(&self) -> DPoint {
1122 DPoint {
1123 dp: self.dp.bottomright(),
1124 px: self.px.bottomright(),
1125 rel: self.rel.bottomright(),
1126 }
1127 }
1128
1129 pub fn size(&self) -> DPoint {
1131 self.bottomright() - self.topleft()
1132 }
1133
1134 pub const fn zero() -> Self {
1136 Self {
1137 px: PxRect::zero(),
1138 dp: AbsRect::zero(),
1139 rel: RelRect::zero(),
1140 }
1141 }
1142
1143 pub const fn fill() -> Self {
1146 DRect {
1147 px: PxRect::zero(),
1148 dp: AbsRect::zero(),
1149 rel: RelRect::unit(),
1150 }
1151 }
1152
1153 pub const fn auto() -> Self {
1157 DRect {
1158 px: PxRect::zero(),
1159 dp: AbsRect::zero(),
1160 rel: RelRect::new(0.0, 0.0, UNSIZED_AXIS, UNSIZED_AXIS),
1161 }
1162 }
1163}
1164
1165pub const ZERO_DRECT: DRect = DRect::zero();
1166pub const FILL_DRECT: DRect = DRect::fill();
1167pub const AUTO_DRECT: DRect = DRect::auto();
1168
1169impl Add<DRect> for DRect {
1170 type Output = Self;
1171
1172 #[inline]
1173 fn add(self, rhs: DRect) -> Self::Output {
1174 Self::Output {
1175 dp: AbsRect {
1176 v: self.dp.v + rhs.dp.v,
1177 _unit: PhantomData,
1178 },
1179 px: PxRect {
1180 v: self.px.v + rhs.px.v,
1181 _unit: PhantomData,
1182 },
1183 rel: RelRect {
1184 v: self.rel.v + rhs.rel.v,
1185 _unit: PhantomData,
1186 },
1187 }
1188 }
1189}
1190
1191impl Sub<DRect> for DRect {
1192 type Output = Self;
1193
1194 #[inline]
1195 fn sub(self, rhs: DRect) -> Self::Output {
1196 self + (-rhs)
1197 }
1198}
1199
1200impl Neg for DRect {
1201 type Output = DRect;
1202
1203 fn neg(self) -> Self::Output {
1204 Self::Output {
1205 dp: -self.dp,
1206 px: -self.px,
1207 rel: -self.rel,
1208 }
1209 }
1210}
1211
1212impl From<AbsRect> for DRect {
1213 fn from(value: AbsRect) -> Self {
1214 Self {
1215 px: PxRect::zero(),
1216 dp: value,
1217 rel: RelRect::zero(),
1218 }
1219 }
1220}
1221
1222impl From<PxRect> for DRect {
1223 fn from(value: PxRect) -> Self {
1224 Self {
1225 px: value,
1226 dp: AbsRect::zero(),
1227 rel: RelRect::zero(),
1228 }
1229 }
1230}
1231
1232impl From<RelRect> for DRect {
1233 fn from(value: RelRect) -> Self {
1234 Self {
1235 px: PxRect::zero(),
1236 dp: AbsRect::zero(),
1237 rel: value,
1238 }
1239 }
1240}
1241
1242impl<T, U: Into<DRect>> Add<U> for Rect<T>
1243where
1244 Self: Into<DRect>,
1245{
1246 type Output = DRect;
1247
1248 fn add(self, rhs: U) -> Self::Output {
1249 self.into() + rhs.into()
1250 }
1251}
1252
1253#[derive(Copy, Clone, Debug, PartialEq)]
1279pub struct Limits<U> {
1280 pub v: f32x4,
1281 #[doc(hidden)]
1282 pub _unit: PhantomData<U>,
1283}
1284
1285pub type PxLimits = Limits<Pixel>;
1286pub type AbsLimits = Limits<Logical>;
1287pub type RelLimits = Limits<Relative>;
1288pub type ResLimits = Limits<Resolved>;
1289
1290pub const DEFAULT_LIMITS: f32x4 = f32x4::new([
1296 f32::NEG_INFINITY,
1297 f32::NEG_INFINITY,
1298 f32::INFINITY,
1299 f32::INFINITY,
1300]);
1301
1302pub const DEFAULT_ABSLIMITS: AbsLimits = AbsLimits {
1305 v: DEFAULT_LIMITS,
1306 _unit: PhantomData,
1307};
1308
1309pub const DEFAULT_RLIMITS: RelLimits = RelLimits {
1312 v: DEFAULT_LIMITS,
1313 _unit: PhantomData,
1314};
1315
1316impl<U> Limits<U> {
1317 #[inline]
1318 const fn from_bound(bound: std::ops::Bound<&f32>, inf: f32) -> f32 {
1319 match bound {
1320 std::ops::Bound::Included(v) | std::ops::Bound::Excluded(v) => *v,
1321 std::ops::Bound::Unbounded => inf,
1322 }
1323 }
1324 pub fn new(x: impl std::ops::RangeBounds<f32>, y: impl std::ops::RangeBounds<f32>) -> Self {
1325 Self {
1326 v: f32x4::new([
1327 Self::from_bound(x.start_bound(), f32::NEG_INFINITY),
1328 Self::from_bound(y.start_bound(), f32::NEG_INFINITY),
1329 Self::from_bound(x.end_bound(), f32::INFINITY),
1330 Self::from_bound(y.end_bound(), f32::INFINITY),
1331 ]),
1332 _unit: PhantomData,
1333 }
1334 }
1335
1336 #[inline]
1337 pub fn min(&self) -> Size2D<f32, U> {
1338 let minmax = self.v.as_array_ref();
1339 Size2D::new(minmax[0], minmax[1])
1340 }
1341 #[inline]
1342 pub fn max(&self) -> Size2D<f32, U> {
1343 let minmax = self.v.as_array_ref();
1344 Size2D::new(minmax[2], minmax[3])
1345 }
1346
1347 #[inline]
1348 pub fn set_min(&mut self, bound: Size2D<f32, U>) {
1349 let minmax = self.v.as_array_mut();
1350 minmax[0] = bound.width;
1351 minmax[1] = bound.height;
1352 }
1353
1354 #[inline]
1355 pub fn set_max(&mut self, bound: Size2D<f32, U>) {
1356 let minmax = self.v.as_array_mut();
1357 minmax[2] = bound.width;
1358 minmax[3] = bound.height;
1359 }
1360
1361 #[inline]
1363 pub fn to_untyped(self) -> Limits<euclid::UnknownUnit> {
1364 self.cast_unit()
1365 }
1366
1367 #[inline]
1369 pub fn cast_unit<V>(self) -> Limits<V> {
1370 Limits::<V> {
1371 v: self.v,
1372 _unit: PhantomData,
1373 }
1374 }
1375}
1376
1377impl<U> Default for Limits<U> {
1378 #[inline]
1379 fn default() -> Self {
1380 Self {
1381 v: DEFAULT_LIMITS,
1382 _unit: PhantomData,
1383 }
1384 }
1385}
1386
1387impl<U> Add<Limits<U>> for Limits<U> {
1388 type Output = Self;
1389
1390 #[inline]
1391 fn add(self, rhs: Limits<U>) -> Self::Output {
1392 let minmax = self.v.as_array_ref();
1393 let r = rhs.v.as_array_ref();
1394
1395 Self {
1396 v: f32x4::new([
1397 minmax[0].max(r[0]),
1398 minmax[1].max(r[1]),
1399 minmax[2].min(r[2]),
1400 minmax[3].min(r[3]),
1401 ]),
1402 _unit: PhantomData,
1403 }
1404 }
1405}
1406
1407#[derive(Copy, Clone, Debug, Default)]
1408pub struct DLimits {
1409 dp: AbsLimits,
1410 px: PxLimits,
1411}
1412
1413pub const DEFAULT_DLIMITS: DLimits = DLimits {
1414 dp: AbsLimits {
1415 v: DEFAULT_LIMITS,
1416 _unit: PhantomData,
1417 },
1418 px: PxLimits {
1419 v: DEFAULT_LIMITS,
1420 _unit: PhantomData,
1421 },
1422};
1423
1424impl DLimits {
1425 pub fn resolve(&self, dpi: RelDim) -> PxLimits {
1426 self.px.cast_unit()
1427 + PxLimits {
1428 v: self.dp.v * splat_size(dpi),
1429 _unit: PhantomData,
1430 }
1431 }
1432}
1433
1434impl From<AbsLimits> for DLimits {
1435 fn from(value: AbsLimits) -> Self {
1436 DLimits {
1437 dp: value,
1438 px: Default::default(),
1439 }
1440 }
1441}
1442
1443impl From<PxLimits> for DLimits {
1444 fn from(value: PxLimits) -> Self {
1445 DLimits {
1446 dp: Default::default(),
1447 px: value,
1448 }
1449 }
1450}
1451
1452impl Mul<PxDim> for RelLimits {
1453 type Output = PxLimits;
1454
1455 #[inline]
1456 fn mul(self, rhs: PxDim) -> Self::Output {
1457 let (unsized_x, unsized_y) = crate::layout::check_unsized_dim(rhs);
1458 let minmax = self.v.as_array_ref();
1459 Self::Output {
1460 v: f32x4::new([
1461 if unsized_x {
1462 minmax[0]
1463 } else {
1464 minmax[0] * rhs.width
1465 },
1466 if unsized_y {
1467 minmax[1]
1468 } else {
1469 minmax[1] * rhs.height
1470 },
1471 if unsized_x {
1472 minmax[2]
1473 } else {
1474 minmax[2] * rhs.width
1475 },
1476 if unsized_y {
1477 minmax[3]
1478 } else {
1479 minmax[3] * rhs.height
1480 },
1481 ]),
1482 _unit: PhantomData,
1483 }
1484 }
1485}
1486
1487#[derive(Debug, Copy, Clone, PartialEq, Default)]
1488pub struct UValue {
1489 pub abs: f32,
1490 pub rel: f32,
1491}
1492
1493impl UValue {
1494 pub const fn resolve(&self, outer_dim: f32) -> f32 {
1495 if self.rel == UNSIZED_AXIS {
1496 UNSIZED_AXIS
1497 } else {
1498 self.abs + (self.rel * outer_dim)
1499 }
1500 }
1501 pub const fn is_unsized(&self) -> bool {
1502 self.rel == UNSIZED_AXIS
1503 }
1504}
1505
1506impl From<f32> for UValue {
1507 fn from(value: f32) -> Self {
1508 Self {
1509 abs: value,
1510 rel: 0.0,
1511 }
1512 }
1513}
1514
1515#[derive(Debug, Copy, Clone, PartialEq, Default)]
1516pub struct DValue {
1517 pub dp: f32,
1518 pub px: f32,
1519 pub rel: f32,
1520}
1521
1522impl DValue {
1523 pub const fn resolve(&self, dpi: f32) -> UValue {
1524 UValue {
1525 abs: self.px + (self.dp * dpi),
1526 rel: self.rel,
1527 }
1528 }
1529 pub const fn is_unsized(&self) -> bool {
1530 self.rel == UNSIZED_AXIS
1531 }
1532}
1533
1534impl From<f32> for DValue {
1535 fn from(value: f32) -> Self {
1536 Self {
1537 dp: value,
1538 px: 0.0,
1539 rel: 0.0,
1540 }
1541 }
1542}
1543
1544#[derive(
1552 Debug, Copy, Clone, PartialEq, Eq, Default, derive_more::TryFrom, derive_more::Display,
1553)]
1554#[try_from(repr)]
1555#[repr(u8)]
1556pub enum RowDirection {
1557 #[default]
1558 LeftToRight = 0,
1559 RightToLeft = 1,
1560 BottomToTop = 2,
1561 TopToBottom = 3,
1562}
1563
1564#[derive(Default)]
1568pub struct CrossReferenceDomain {
1569 mappings: RwLock<im::HashMap<Arc<SourceID>, PxRect>>,
1570}
1571
1572impl CrossReferenceDomain {
1573 pub fn write_area(&self, target: Arc<SourceID>, area: PxRect) {
1574 self.mappings.write().insert(target, area);
1575 }
1576
1577 pub fn get_area(&self, target: &Arc<SourceID>) -> Option<PxRect> {
1578 self.mappings.read().get(target).copied()
1579 }
1580
1581 pub fn remove_self(&self, target: &Arc<SourceID>) {
1582 self.mappings.write().remove(target);
1584 }
1585}
1586
1587pub trait DynHashEq: DynClone + std::fmt::Debug {
1589 fn dyn_hash(&self, state: &mut dyn Hasher);
1590 fn dyn_eq(&self, other: &dyn Any) -> bool;
1591}
1592
1593dyn_clone::clone_trait_object!(DynHashEq);
1594
1595impl<H: Hash + PartialEq + std::cmp::Eq + Clone + std::fmt::Debug + Any> DynHashEq for H {
1596 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
1597 self.hash(&mut state);
1598 }
1599 fn dyn_eq(&self, other: &dyn Any) -> bool {
1600 if let Some(o) = other.downcast_ref::<H>() {
1601 self == o
1602 } else {
1603 false
1604 }
1605 }
1606}
1607
1608#[derive(Clone, Default, Debug)]
1614pub enum DataID {
1615 Named(&'static str),
1616 Owned(String),
1617 Int(i64),
1618 Other(Box<dyn DynHashEq + Sync + Send>),
1619 #[default]
1620 None, }
1622
1623impl Hash for DataID {
1624 fn hash<H: Hasher>(&self, state: &mut H) {
1625 match self {
1626 DataID::Named(s) => s.hash(state),
1627 DataID::Owned(s) => s.hash(state),
1628 DataID::Int(i) => i.hash(state),
1629 DataID::Other(hash_comparable) => hash_comparable.dyn_hash(state),
1630 DataID::None => {
1631 panic!("Invalid ID! Did you forget to initialize a component node's ID field?")
1632 }
1633 }
1634 }
1635}
1636
1637impl std::cmp::Eq for DataID {}
1638impl PartialEq for DataID {
1639 fn eq(&self, other: &Self) -> bool {
1640 match self {
1641 DataID::Named(s) => {
1642 if let DataID::Named(name) = other {
1643 name == s
1644 } else {
1645 false
1646 }
1647 }
1648 DataID::Owned(s) => {
1649 if let DataID::Owned(name) = other {
1650 name == s
1651 } else {
1652 false
1653 }
1654 }
1655 DataID::Int(i) => {
1656 if let DataID::Int(integer) = other {
1657 integer == i
1658 } else {
1659 false
1660 }
1661 }
1662 DataID::Other(hash_comparable) => {
1663 if let DataID::Other(h) = other {
1664 hash_comparable.dyn_eq(h)
1665 } else {
1666 false
1667 }
1668 }
1669 DataID::None => panic!("Invalid ID!"),
1670 }
1671 }
1672}
1673
1674#[derive(Clone, Default, Debug)]
1680pub struct SourceID {
1681 parent: Option<std::sync::Arc<SourceID>>,
1682 id: DataID,
1683}
1684
1685impl SourceID {
1686 pub fn child(self: &Arc<Self>, id: DataID) -> Arc<Self> {
1688 Self {
1689 parent: self.clone().into(),
1690 id,
1691 }
1692 .into()
1693 }
1694
1695 pub fn duplicate(self: &Arc<Self>) -> Arc<Self> {
1700 self.child(DataID::Int(Arc::strong_count(self) as i64))
1701 }
1702
1703 #[allow(dead_code)] #[cfg(debug_assertions)]
1705 #[allow(clippy::mutable_key_type)]
1706 pub(crate) fn parents(self: &Arc<Self>) -> std::collections::HashSet<&Arc<Self>> {
1707 let mut set = std::collections::HashSet::new();
1708
1709 let mut cur = self.parent.as_ref();
1710 while let Some(id) = cur {
1711 if set.contains(id) {
1712 panic!("Loop detected in IDs! {:?} already existed!", id.id);
1713 }
1714 set.insert(id);
1715 cur = id.parent.as_ref();
1716 }
1717 set
1718 }
1719}
1720impl std::cmp::Eq for SourceID {}
1721impl PartialEq for SourceID {
1722 fn eq(&self, other: &Self) -> bool {
1723 if let Some(parent) = self.parent.as_ref() {
1724 if let Some(pother) = other.parent.as_ref() {
1725 parent == pother && self.id == other.id
1726 } else {
1727 false
1728 }
1729 } else {
1730 other.parent.is_none() && self.id == other.id
1731 }
1732 }
1733}
1734impl Hash for SourceID {
1735 fn hash<H: Hasher>(&self, state: &mut H) {
1736 if let Some(parent) = self.parent.as_ref() {
1737 parent.id.hash(state);
1738 }
1739 self.id.hash(state);
1740 }
1741}
1742impl Display for SourceID {
1743 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1744 if let Some(parent) = self.parent.as_ref() {
1745 parent.fmt(f)?;
1746 }
1747
1748 match (&self.id, self.parent.is_some()) {
1749 (DataID::Named(_), true) | (DataID::Owned(_), true) => f.write_str(" -> "),
1750 (DataID::Other(_), true) => f.write_str(" "),
1751 _ => Ok(()),
1752 }?;
1753
1754 match &self.id {
1755 DataID::Named(s) => f.write_str(s),
1756 DataID::Owned(s) => f.write_str(s),
1757 DataID::Int(i) => write!(f, "[{i}]"),
1758 DataID::Other(dyn_hash_eq) => {
1759 let mut h = std::hash::DefaultHasher::new();
1760 dyn_hash_eq.dyn_hash(&mut h);
1761 write!(f, "{{{}}}", h.finish())
1762 }
1763 DataID::None => Ok(()),
1764 }
1765 }
1766}
1767
1768pub struct ScopeIterID<'a, T> {
1769 base: ScopeID<'a>,
1770 it: T,
1771}
1772
1773impl<'a, T: Iterator> ScopeIterID<'a, T> {
1774 fn new(parent: &'a mut ScopeID<'_>, it: T) -> Self {
1775 Self {
1776 base: parent.scope(),
1777 it,
1778 }
1779 }
1780}
1781
1782impl<T> Iterator for ScopeIterID<'_, T>
1783where
1784 T: Iterator,
1785{
1786 type Item = (T::Item, Arc<SourceID>);
1787
1788 #[inline]
1789 fn next(&mut self) -> Option<Self::Item> {
1790 let x = self.it.next()?;
1791 let id = self.base.create();
1792 Some((x, id))
1793 }
1794
1795 #[inline]
1796 fn size_hint(&self) -> (usize, Option<usize>) {
1797 self.it.size_hint()
1798 }
1799
1800 #[inline]
1801 fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
1802 while let Some(x) = Iterator::next(self) {
1803 if n == 0 {
1804 return Some(x);
1805 }
1806 n -= 1;
1807 }
1808 None
1809 }
1810
1811 #[inline]
1812 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
1813 where
1814 F: FnMut(Acc, Self::Item) -> Acc,
1815 {
1816 let mut accum = init;
1817 while let Some(x) = Iterator::next(&mut self) {
1818 accum = f(accum, x);
1819 }
1820 accum
1821 }
1822}
1823
1824pub struct ScopeID<'a> {
1858 _parent: PhantomData<&'a mut ()>,
1860 base: Arc<SourceID>,
1861 count: i64,
1862}
1863
1864impl<'a> ScopeID<'a> {
1865 pub fn id(&mut self) -> &Arc<SourceID> {
1868 &self.base
1869 }
1870
1871 pub fn create(&mut self) -> Arc<SourceID> {
1893 let node = self.base.child(crate::DataID::Int(self.count));
1894 self.count += 1;
1895 node
1896 }
1897
1898 pub fn scope(&mut self) -> ScopeID<'_> {
1900 ScopeID {
1901 base: self.create(),
1902 _parent: PhantomData,
1903 count: 0,
1904 }
1905 }
1906
1907 pub fn child(&mut self, id: DataID) -> Arc<SourceID> {
1911 self.base.child(id)
1912 }
1913
1914 pub fn iter<U: IntoIterator>(&mut self, other: U) -> ScopeIterID<'_, U::IntoIter> {
1938 ScopeIterID::new(self, other.into_iter())
1939 }
1940
1941 pub fn cond<R>(
1974 &mut self,
1975 condition: bool,
1976 tvalue: impl FnOnce(ScopeID<'_>) -> R,
1977 fvalue: impl FnOnce(ScopeID<'_>) -> R,
1978 ) -> R {
1979 let (id_true, id_false) = (self.create(), self.create());
1980
1981 if condition {
1982 tvalue(ScopeID {
1983 base: id_true,
1984 _parent: PhantomData,
1985 count: 0,
1986 })
1987 } else {
1988 fvalue(ScopeID {
1989 base: id_false,
1990 _parent: PhantomData,
1991 count: 0,
1992 })
1993 }
1994 }
1995
1996 fn root() -> ScopeID<'a> {
1998 ScopeID {
1999 _parent: PhantomData,
2000 base: Arc::new(APP_SOURCE_ID),
2001 count: 0,
2002 }
2003 }
2004}
2005
2006pub enum InputResult<T> {
2009 Consume(T),
2010 Forward(T),
2011 Error(eyre::ErrReport),
2012}
2013
2014impl<T, E: std::error::Error + Send + Sync + 'static> From<Result<T, E>> for InputResult<T> {
2015 fn from(value: Result<T, E>) -> Self {
2016 match value {
2017 Ok(v) => InputResult::Consume(v),
2018 Err(e) => InputResult::Error(e.into()),
2019 }
2020 }
2021}
2022
2023impl<T> InputResult<T> {
2024 fn map<U>(self, f: impl FnOnce(T) -> U) -> InputResult<U> {
2026 match self {
2027 InputResult::Consume(v) => InputResult::Consume(f(v)),
2028 InputResult::Forward(v) => InputResult::Forward(f(v)),
2029 InputResult::Error(error) => InputResult::Error(error),
2030 }
2031 }
2032
2033 fn is_accept(&self) -> bool {
2034 matches!(*self, InputResult::Consume(_))
2035 }
2036 fn is_reject(&self) -> bool {
2037 matches!(*self, InputResult::Forward(_))
2038 }
2039 fn is_err(&self) -> bool {
2040 matches!(*self, InputResult::Error(_))
2041 }
2042}
2043
2044#[derive(Clone)]
2045pub struct Slot(pub Arc<SourceID>, pub u64);
2046
2047pub type AppEvent<State> = Box<dyn FnMut(DispatchPair, AccessCell<State>) -> InputResult<()>>;
2049
2050pub trait WrapEventEx<State: 'static + PartialEq, Input: Dispatchable + 'static> {
2095 fn wrap(self) -> impl FnMut(DispatchPair, AccessCell<State>) -> InputResult<()>;
2097}
2098
2099impl<AppData: 'static + PartialEq, Input: Dispatchable + 'static, T> WrapEventEx<AppData, Input>
2100 for T
2101where
2102 T: FnMut(Input, AccessCell<AppData>) -> InputResult<()>,
2103{
2104 fn wrap(mut self) -> impl FnMut(DispatchPair, AccessCell<AppData>) -> InputResult<()> {
2105 move |pair, state| (self)(Input::restore(pair).unwrap(), state)
2106 }
2107}
2108
2109pub type DispatchPair = (u64, Box<dyn Any>);
2111
2112pub trait Dispatchable
2113where
2114 Self: Sized,
2115{
2116 const SIZE: usize;
2117 fn extract(self) -> DispatchPair;
2118 fn restore(pair: DispatchPair) -> Result<Self, Error>;
2119}
2120
2121impl Dispatchable for Infallible {
2122 const SIZE: usize = 0;
2123
2124 fn extract(self) -> DispatchPair {
2125 (0, Box::new(self))
2126 }
2127
2128 fn restore(_: DispatchPair) -> Result<Self, Error> {
2129 Err(Error::Stateless)
2130 }
2131}
2132
2133pub trait StateMachineChild {
2169 #[allow(unused_variables)]
2170 fn init(
2171 &self,
2172 driver: &std::sync::Weak<Driver>,
2173 ) -> Result<Box<dyn StateMachineWrapper>, crate::Error> {
2174 Err(crate::Error::Stateless)
2175 }
2176 fn apply_children(
2177 &self,
2178 _: &mut dyn FnMut(&dyn StateMachineChild) -> eyre::Result<()>,
2179 ) -> eyre::Result<()> {
2180 Ok(())
2182 }
2183 fn id(&self) -> Arc<SourceID>;
2184}
2185
2186pub struct AccessCell<'a, 'b, T> {
2254 value: &'a mut T,
2255 changed: &'b mut bool,
2256}
2257
2258impl<'a, 'b, T> std::borrow::BorrowMut<T> for AccessCell<'a, 'b, T> {
2259 #[inline]
2260 fn borrow_mut(&mut self) -> &mut T {
2261 *self.changed = true;
2265 self.value
2266 }
2267}
2268
2269impl<'a, 'b, T> std::borrow::Borrow<T> for AccessCell<'a, 'b, T> {
2270 #[inline]
2271 fn borrow(&self) -> &T {
2272 self.value
2273 }
2274}
2275
2276impl<'a, 'b, T> std::ops::Deref for AccessCell<'a, 'b, T> {
2277 type Target = T;
2278
2279 #[inline]
2280 fn deref(&self) -> &T {
2281 self.value
2282 }
2283}
2284
2285impl<'a, 'b, T> std::ops::DerefMut for AccessCell<'a, 'b, T> {
2286 fn deref_mut(&mut self) -> &mut Self::Target {
2287 *self.changed = true;
2288 self.value
2289 }
2290}
2291
2292#[test]
2293fn test_access_cell() {
2294 struct FooBar {
2295 i: i32,
2296 }
2297
2298 fn change(change: bool, mut v: AccessCell<FooBar>) {
2299 if change {
2300 v.i = 4;
2301 }
2302 }
2303 let mut foobar = FooBar { i: 1 };
2304 let mut tracker = false;
2305
2306 let accessor = AccessCell {
2307 value: &mut foobar,
2308 changed: &mut tracker,
2309 };
2310 change(false, accessor);
2311 assert_eq!(foobar.i, 1);
2312 assert_eq!(tracker, false);
2313
2314 let accessor = AccessCell {
2315 value: &mut foobar,
2316 changed: &mut tracker,
2317 };
2318 change(true, accessor);
2319 assert_eq!(foobar.i, 4);
2320 assert_eq!(tracker, true);
2321}
2322
2323#[derive(Default)]
2391pub struct StateManager {
2392 states: HashMap<Arc<SourceID>, Box<dyn StateMachineWrapper>>,
2393 pointers: HashMap<*const c_void, Arc<SourceID>>,
2394 changed: bool,
2395}
2396
2397impl StateManager {
2398 pub fn register_pointer<T>(&mut self, p: *const T, id: Arc<SourceID>) -> Option<Arc<SourceID>> {
2399 let ptr = p as *const c_void;
2400 self.pointers.insert(ptr, id)
2401 }
2402
2403 pub fn invalidate_pointer<T>(&mut self, p: *const T) -> Option<Arc<SourceID>> {
2404 let ptr = p as *const c_void;
2405 self.pointers.remove(&ptr)
2406 }
2407
2408 pub fn mutate_pointer<T>(&mut self, p: *const T) {
2409 let ptr = p as *const c_void;
2410 let id = self
2411 .pointers
2412 .get(&ptr)
2413 .expect("Tried to mutate pointer that wasn't registered!")
2414 .clone();
2415
2416 self.mutate_id(&id);
2417 }
2418
2419 fn mutate_id(&mut self, id: &Arc<SourceID>) {
2420 if let Some(state) = self.states.get_mut(id) {
2421 state.set_changed(true);
2422 self.propagate_change(id);
2423 }
2424 }
2425
2426 #[allow(dead_code)]
2427 fn init_default<State: 'static + component::StateMachineWrapper + Default>(
2428 &mut self,
2429 id: Arc<SourceID>,
2430 ) -> eyre::Result<&mut State> {
2431 if !self.states.contains_key(&id) {
2432 self.states.insert(id.clone(), Box::new(State::default()));
2433 }
2434 let v = &mut *self
2435 .states
2436 .get_mut(&id)
2437 .ok_or_eyre("Failed to insert state!")?
2438 .as_mut() as &mut dyn Any;
2439 v.downcast_mut().ok_or(Error::RuntimeTypeMismatch.into())
2440 }
2441 fn init(&mut self, id: Arc<SourceID>, state: Box<dyn StateMachineWrapper>) {
2442 if !self.states.contains_key(&id) {
2443 self.states.insert(id.clone(), state);
2444 }
2445 }
2446
2447 pub fn get<'a, State: 'static + component::StateMachineWrapper>(
2450 &'a self,
2451 id: &SourceID,
2452 ) -> eyre::Result<&'a State> {
2453 let v = self
2454 .states
2455 .get(id)
2456 .ok_or_eyre("State does not exist")?
2457 .as_ref() as &dyn Any;
2458 v.downcast_ref().ok_or(Error::RuntimeTypeMismatch.into())
2459 }
2460
2461 pub fn get_mut<'a, State: 'static + component::StateMachineWrapper>(
2464 &'a mut self,
2465 id: &SourceID,
2466 ) -> eyre::Result<&'a mut State> {
2467 let v = &mut *self
2468 .states
2469 .get_mut(id)
2470 .ok_or_eyre("State does not exist")?
2471 .as_mut() as &mut dyn Any;
2472 v.downcast_mut().ok_or(Error::RuntimeTypeMismatch.into())
2473 }
2474
2475 #[allow(clippy::borrowed_box)]
2476 fn get_trait<'a>(&'a self, id: &SourceID) -> eyre::Result<&'a Box<dyn StateMachineWrapper>> {
2477 self.states.get(id).ok_or_eyre("State does not exist")
2478 }
2479
2480 fn propagate_change(&mut self, mut id: &Arc<SourceID>) {
2481 while let Some(parent) = id.parent.as_ref() {
2482 if let Some(state) = self.states.get_mut(parent) {
2483 if state.changed() {
2484 return;
2486 }
2487 state.set_changed(true);
2488 }
2489 id = parent;
2490 }
2491 }
2492
2493 fn process(
2494 &mut self,
2495 event: DispatchPair,
2496 slot: &Slot,
2497 dpi: RelDim,
2498 area: PxRect,
2499 extent: PxRect,
2500 driver: &std::sync::Weak<crate::Driver>,
2501 ) -> eyre::Result<bool> {
2502 type IterTuple = (Box<dyn Any>, u64, Option<Slot>);
2503
2504 let mut handled = false;
2506 let iter: SmallVec<[IterTuple; 2]> = {
2507 let state = self.states.get_mut(&slot.0).ok_or_eyre("Invalid slot")?;
2508 let v = match state.process(event, slot.1, dpi, area, extent, driver) {
2509 InputResult::Consume(v) => {
2510 handled |= v.is_empty();
2511 v
2512 }
2513 InputResult::Forward(v) => v,
2514 InputResult::Error(error) => return Err(error),
2515 };
2516 if state.changed() {
2517 self.changed = true;
2518 self.propagate_change(&slot.0);
2519 }
2520
2521 let state = self.states.get(&slot.0).ok_or(Error::InternalFailure)?;
2522
2523 v.into_iter()
2524 .map(|(i, e)| (e, i, state.output_slot(i.ilog2() as usize).unwrap().clone()))
2525 }
2526 .collect();
2527
2528 for (e, index, slot) in iter {
2529 if let Some(s) = slot.as_ref() {
2530 handled |= self.process((index, e), s, dpi, area, extent, driver)?;
2531 }
2532 }
2533
2534 Ok(handled)
2535 }
2536
2537 fn init_child(
2538 &mut self,
2539 target: &dyn StateMachineChild,
2540 driver: &std::sync::Weak<Driver>,
2541 ) -> eyre::Result<()> {
2542 if !self.states.contains_key(&target.id()) {
2543 match target.init(driver) {
2544 Ok(v) => self.init(target.id().clone(), v),
2545 Err(Error::Stateless) => (),
2546 Err(e) => return Err(e.into()),
2547 };
2548 }
2549
2550 target.apply_children(&mut |child| self.init_child(child, driver))
2551 }
2552}
2553
2554#[allow(clippy::declare_interior_mutable_const)]
2557pub const APP_SOURCE_ID: SourceID = SourceID {
2558 parent: None,
2559 id: DataID::Named("__fg_AppData_ID__"),
2560};
2561
2562type OutlineReturn = im::HashMap<Arc<SourceID>, Option<Window>>;
2563pub type EventPair<AppData> = (u64, AppEvent<AppData>);
2564
2565pub struct App<AppData, O: FnPersist2<AppData, ScopeID<'static>, OutlineReturn>> {
2572 pub instance: wgpu::Instance,
2573 pub driver: std::sync::Weak<graphics::Driver>,
2574 pub state: StateManager,
2575 store: Option<O::Store>,
2576 outline: O,
2577 _parents: BTreeMap<DataID, DataID>,
2578 root: component::Root, driver_init: Option<Box<dyn FnOnce(std::sync::Weak<Driver>) + 'static>>,
2580 _phantom: PhantomData<AppData>,
2581 handle_sync: mpsc::Receiver<EventPair<AppData>>,
2582}
2583
2584pub struct AppDataMachine<AppData> {
2585 pub state: AppData,
2586 handlers: HashMap<usize, AppEvent<AppData>>,
2587 changed: bool,
2588}
2589
2590impl<AppData: 'static + PartialEq> StateMachineWrapper for AppDataMachine<AppData> {
2591 fn output_slot(&self, _: usize) -> eyre::Result<&Option<Slot>> {
2592 Ok(&None)
2593 }
2594
2595 fn input_mask(&self) -> u64 {
2596 0
2597 }
2598
2599 fn changed(&self) -> bool {
2600 self.changed
2601 }
2602
2603 fn set_changed(&mut self, changed: bool) {
2604 self.changed = changed;
2605 }
2606
2607 fn process(
2608 &mut self,
2609 input: DispatchPair,
2610 index: u64,
2611 _: RelDim,
2612 _: PxRect,
2613 _: PxRect,
2614 _: &std::sync::Weak<crate::Driver>,
2615 ) -> InputResult<SmallVec<[DispatchPair; 1]>> {
2616 if let Some(f) = self.handlers.get_mut(&(index as usize)) {
2617 let cell = AccessCell {
2618 value: &mut self.state,
2619 changed: &mut self.changed,
2620 };
2621 f(input, cell).map(|_| SmallVec::new())
2622 } else {
2623 InputResult::Error(Error::InternalFailure.into())
2624 }
2625 }
2626}
2627#[cfg(target_os = "windows")]
2628use winit::platform::windows::EventLoopBuilderExtWindows;
2629
2630#[cfg(target_os = "linux")]
2632use winit::platform::x11::EventLoopBuilderExtX11;
2633
2634impl<AppData: Clone + PartialEq + 'static, O: FnPersist2<AppData, ScopeID<'static>, OutlineReturn>>
2635 App<AppData, O>
2636{
2637 #[allow(clippy::type_complexity)]
2681 pub fn new<T: 'static>(
2682 app_state: AppData,
2683 inputs: Vec<AppEvent<AppData>>,
2684 outline: O,
2685 driver_init: impl FnOnce(std::sync::Weak<Driver>) + 'static,
2686 ) -> eyre::Result<(
2687 Self,
2688 EventLoop<T>,
2689 mpsc::Sender<EventPair<AppData>>,
2690 AtomicU64,
2691 )> {
2692 #[cfg(test)]
2693 let any_thread = true;
2694 #[cfg(not(test))]
2695 let any_thread = false;
2696
2697 Self::new_any_thread(app_state, inputs, outline, any_thread, driver_init)
2698 }
2699
2700 #[allow(clippy::type_complexity)]
2703 pub fn new_any_thread<T: 'static>(
2704 app_state: AppData,
2705 inputs: Vec<AppEvent<AppData>>,
2706 outline: O,
2707 any_thread: bool,
2708 driver_init: impl FnOnce(std::sync::Weak<Driver>) + 'static,
2709 ) -> eyre::Result<(
2710 Self,
2711 EventLoop<T>,
2712 mpsc::Sender<EventPair<AppData>>,
2713 AtomicU64,
2714 )> {
2715 let count = AtomicU64::new(inputs.len() as u64);
2716 let mut manager: StateManager = Default::default();
2717 manager.init(
2718 Arc::new(APP_SOURCE_ID),
2719 Box::new(AppDataMachine {
2720 handlers: HashMap::from_iter(inputs.into_iter().enumerate()),
2721 state: app_state,
2722 changed: true,
2723 }),
2724 );
2725
2726 #[cfg(target_os = "windows")]
2727 let event_loop = EventLoop::with_user_event()
2728 .with_any_thread(any_thread)
2729 .with_dpi_aware(true)
2730 .build()?;
2731 #[cfg(not(target_os = "windows"))]
2732 let event_loop = EventLoop::with_user_event()
2733 .with_any_thread(any_thread)
2734 .build()
2735 .map_err(|e| {
2736 if e.to_string()
2737 .eq_ignore_ascii_case("Could not find wayland compositor")
2738 {
2739 eyre::eyre!(
2740 "Wayland initialization failed! winit cannot automatically fall back to X11 (). Try running the program with `WAYLAND_DISPLAY=\"\"`"
2741 )
2742 } else {
2743 e.into()
2744 }
2745 })?;
2746
2747 #[cfg(debug_assertions)]
2748 let desc = InstanceDescriptor {
2749 flags: InstanceFlags::debugging(),
2750 ..Default::default()
2751 };
2752 #[cfg(not(debug_assertions))]
2753 let desc = InstanceDescriptor {
2754 flags: InstanceFlags::DISCARD_HAL_LABELS,
2755 ..Default::default()
2756 };
2757
2758 let (sender, recv) = mpsc::channel();
2759 Ok((
2760 Self {
2761 instance: wgpu::Instance::new(&desc),
2762 driver: std::sync::Weak::<graphics::Driver>::new(),
2763 store: None,
2764 outline,
2765 state: manager,
2766 _parents: Default::default(),
2767 root: component::Root::new(),
2768 driver_init: Some(Box::new(driver_init)),
2769 _phantom: PhantomData,
2770 handle_sync: recv,
2771 },
2772 event_loop,
2773 sender,
2774 count,
2775 ))
2776 }
2777
2778 #[allow(clippy::borrow_interior_mutable_const)]
2779 fn update_outline(&mut self, event_loop: &ActiveEventLoop, store: O::Store) {
2780 let app_state: &mut AppDataMachine<AppData> = self.state.get_mut(&APP_SOURCE_ID).unwrap();
2781
2782 for (idx, handler) in self.handle_sync.try_iter() {
2783 app_state.handlers.insert(idx as usize, handler);
2784 }
2785
2786 let (store, windows) = self
2787 .outline
2788 .call(store, app_state.state.clone(), ScopeID::root());
2789 debug_assert!(
2790 APP_SOURCE_ID.parent.is_none(),
2791 "Something set the APP_SOURCE parent! This should never happen!"
2792 );
2793
2794 self.store.replace(store);
2795 self.root.children = windows;
2796 #[cfg(debug_assertions)]
2797 self.root.validate_ids().unwrap();
2798
2799 let (root, manager, graphics, instance, driver_init) = (
2800 &mut self.root,
2801 &mut self.state,
2802 &mut self.driver,
2803 &mut self.instance,
2804 &mut self.driver_init,
2805 );
2806
2807 root.layout_all(manager, graphics, driver_init, instance, event_loop)
2808 .unwrap();
2809
2810 root.stage_all(manager).unwrap();
2811 }
2812}
2813
2814impl<
2815 AppData: Clone + PartialEq + 'static,
2816 T: 'static,
2817 O: FnPersist2<AppData, ScopeID<'static>, OutlineReturn>,
2818> winit::application::ApplicationHandler<T> for App<AppData, O>
2819{
2820 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
2821 let store = self.store.take();
2823 self.update_outline(event_loop, store.unwrap_or_else(|| O::init(&self.outline)));
2824 }
2825 fn window_event(
2826 &mut self,
2827 event_loop: &ActiveEventLoop,
2828 window_id: WindowId,
2829 event: WindowEvent,
2830 ) {
2831 let mut delete = None;
2832 if let Some(root) = self.root.states.get_mut(&window_id) {
2833 let Some(rtree) = root.staging.as_ref().map(|x| x.get_rtree()) else {
2834 panic!("Got root state without valid staging!");
2835 };
2836
2837 if let Some(window) = self.root.children.get(&root.id) {
2838 let window = window.as_ref().unwrap();
2839 let mut resized = false;
2840 let _ = match event {
2841 WindowEvent::CloseRequested => {
2842 let v = Window::on_window_event(
2843 window.id(),
2844 rtree,
2845 event,
2846 &mut self.state,
2847 self.driver.clone(),
2848 );
2849 if v.is_accept() {
2850 delete = Some(window.id());
2851 }
2852 v
2853 }
2854 WindowEvent::RedrawRequested => {
2855 if let Ok(state) = self.state.get_mut::<WindowStateMachine>(&window.id())
2856 && let Some(driver) = self.driver.upgrade()
2857 {
2858 if let Some(staging) = root.staging.as_ref() {
2859 let inner = &mut state.state;
2860 let surface_dim = inner.surface_dim().to_f32();
2861
2862 loop {
2863 let mut viewer = CompositorView {
2865 index: 0,
2866 window: &mut inner.compositor,
2867 layer0: &mut driver.layer_composite[0].write(),
2868 layer1: &mut driver.layer_composite[1].write(),
2869 clipstack: &mut inner.clipstack,
2870 offset: PxVector::zero(),
2871 surface_dim,
2872 pass: 0,
2873 slice: 0,
2874 };
2875
2876 inner.layers.clear();
2878 viewer.clipstack.clear();
2879 if let Err(e) = staging.render(
2880 PxPoint::zero(),
2881 &driver,
2882 &mut viewer,
2883 &mut inner.layers,
2884 ) {
2885 match e {
2886 Error::ResizeTextureAtlas(layers, kind) => {
2887 match kind {
2889 AtlasKind::Primary => driver.atlas.write(),
2890 AtlasKind::Layer0 => {
2891 driver.layer_atlas[0].write()
2892 }
2893 AtlasKind::Layer1 => {
2894 driver.layer_atlas[1].write()
2895 }
2896 }
2897 .resize(&driver.device, &driver.queue, layers);
2898 viewer.window.cleanup();
2899 viewer.layer0.cleanup();
2900 viewer.layer1.cleanup();
2901 continue; }
2903 e => panic!("Fatal draw error: {e}"),
2904 }
2905 }
2906 break;
2907 }
2908 }
2909
2910 let mut encoder = driver.device.create_command_encoder(
2911 &wgpu::CommandEncoderDescriptor {
2912 label: Some("Root Encoder"),
2913 },
2914 );
2915
2916 driver.atlas.write().process_mipmaps(&driver, &mut encoder);
2917 driver.atlas.read().draw(&driver, &mut encoder);
2918
2919 let max_depth = driver.layer_composite[0]
2920 .read()
2921 .segments
2922 .len()
2923 .max(driver.layer_composite[1].read().segments.len());
2924
2925 for i in 0..2 {
2926 let surface_dim = driver.layer_atlas[i].read().texture.size();
2927 driver.layer_composite[i].write().prepare(
2928 &driver,
2929 &mut encoder,
2930 Size2D::<u32, Pixel>::new(
2931 surface_dim.width,
2932 surface_dim.height,
2933 )
2934 .to_f32(),
2935 );
2936 }
2937
2938 for i in (1..max_depth).rev() {
2940 let idx: usize = (i + 1) % 2;
2942 let mut compositor = driver.layer_composite[idx].write();
2943 let atlas = driver.layer_atlas[idx].read();
2944
2945 for slice in 0..atlas.texture.depth_or_array_layers() {
2947 let name = format!(
2948 "Layer {idx} (depth {i}) Atlas (slice {slice}) Pass"
2949 );
2950 let mut pass =
2951 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
2952 label: Some(&name),
2953 color_attachments: &[Some(
2954 wgpu::RenderPassColorAttachment {
2955 view: &atlas.targets[slice as usize],
2956 resolve_target: None,
2957 depth_slice: None,
2958 ops: wgpu::Operations {
2959 load: if true {
2960 wgpu::LoadOp::Clear(
2961 wgpu::Color::TRANSPARENT,
2962 )
2963 } else {
2964 wgpu::LoadOp::Load
2965 },
2966 store: wgpu::StoreOp::Store,
2967 },
2968 },
2969 )],
2970 depth_stencil_attachment: None,
2971 timestamp_writes: None,
2972 occlusion_query_set: None,
2973 });
2974
2975 pass.set_viewport(
2976 0.0,
2977 0.0,
2978 atlas.texture.width() as f32,
2979 atlas.texture.height() as f32,
2980 0.0,
2981 1.0,
2982 );
2983
2984 compositor.draw(&driver, &mut pass, i as u8, slice as u8);
2985 }
2986 }
2987
2988 state.state.draw(encoder);
2989 driver.layer_composite[0].write().cleanup();
2990 driver.layer_composite[1].write().cleanup();
2991 }
2992
2993 InputResult::Consume(())
2994 }
2995 WindowEvent::Resized(_) => {
2996 resized = true;
2997 Window::on_window_event(
2998 window.id(),
2999 rtree,
3000 event,
3001 &mut self.state,
3002 self.driver.clone(),
3003 )
3004 }
3005 _ => Window::on_window_event(
3006 window.id(),
3007 rtree,
3008 event,
3009 &mut self.state,
3010 self.driver.clone(),
3011 ),
3012 };
3013
3014 if self.state.changed || resized {
3015 self.state.changed = false;
3016 let store = self.store.take().unwrap();
3017 self.update_outline(event_loop, store);
3018 }
3019 }
3020 }
3021
3022 if let Some(id) = delete {
3023 self.root.children.remove(&id);
3024 }
3025
3026 if self.root.children.is_empty() {
3027 event_loop.exit();
3028 }
3029 }
3030
3031 fn device_event(
3032 &mut self,
3033 event_loop: &ActiveEventLoop,
3034 device_id: winit::event::DeviceId,
3035 event: winit::event::DeviceEvent,
3036 ) {
3037 let _ = (event_loop, device_id, event);
3038 }
3039
3040 fn user_event(&mut self, event_loop: &ActiveEventLoop, _: T) {
3041 event_loop.exit();
3042 }
3043
3044 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
3045 let _ = event_loop;
3046 }
3047}
3048
3049#[cfg(test)]
3050struct TestApp {}
3051
3052#[cfg(test)]
3053impl crate::persist::FnPersistStore for TestApp {
3054 type Store = (u8, OutlineReturn);
3055}
3056
3057#[cfg(test)]
3058impl FnPersist2<u8, ScopeID<'static>, OutlineReturn> for TestApp {
3059 fn init(&self) -> Self::Store {
3060 (0, im::HashMap::new())
3061 }
3062
3063 fn call(
3064 &mut self,
3065 store: Self::Store,
3066 _: u8,
3067 mut id: ScopeID<'static>,
3068 ) -> (Self::Store, OutlineReturn) {
3069 use crate::color::sRGB;
3070 use crate::component::shape::Shape;
3071
3072 let rect = Shape::<DRect, { component::shape::ShapeKind::RoundRect as u8 }>::new(
3073 gen_id!(id),
3074 crate::FILL_DRECT.into(),
3075 0.0,
3076 0.0,
3077 f32x4::splat(0.0),
3078 sRGB::new(1.0, 0.0, 0.0, 1.0),
3079 sRGB::transparent(),
3080 DAbsPoint::zero(),
3081 );
3082 let window = Window::new(
3083 gen_id!(id),
3084 winit::window::Window::default_attributes()
3085 .with_title("test_blank")
3086 .with_resizable(true),
3087 Box::new(rect),
3088 );
3089
3090 let mut windows = im::HashMap::new();
3091 windows.insert(window.id().clone(), Some(window));
3092
3093 (store, windows)
3094 }
3095}
3096
3097#[test]
3098fn test_basic() {
3099 let (mut app, event_loop, _, _) =
3100 App::<u8, TestApp>::new::<()>(0u8, vec![], TestApp {}, |_| ()).unwrap();
3101
3102 let proxy = event_loop.create_proxy();
3103 proxy.send_event(()).unwrap();
3104 event_loop.run_app(&mut app).unwrap();
3105}
3106
3107#[test]
3108fn test_absrect_contain() {
3109 let target = AbsRect::new(0.0, 0.0, 2.0, 2.0);
3110
3111 for x in 0..=2 {
3112 for y in 0..=2 {
3113 if x == 2 || y == 2 {
3114 assert!(!target.contains(AbsPoint::new(x as f32, y as f32)));
3115 } else {
3116 assert!(
3117 target.contains(AbsPoint::new(x as f32, y as f32)),
3118 "{x} {y} not inside {target}"
3119 );
3120 }
3121 }
3122 }
3123
3124 assert!(target.contains(AbsPoint::new(1.999, 1.999)));
3125
3126 for y in -1..=3 {
3127 assert!(!target.contains(AbsPoint::new(-1.0, y as f32)));
3128 assert!(!target.contains(AbsPoint::new(3.0, y as f32)));
3129 assert!(!target.contains(AbsPoint::new(3000000.0, y as f32)));
3130 }
3131
3132 for x in -1..=3 {
3133 assert!(!target.contains(AbsPoint::new(x as f32, -1.0)));
3134 assert!(!target.contains(AbsPoint::new(x as f32, 3.0)));
3135 assert!(!target.contains(AbsPoint::new(x as f32, -3000000.0)));
3136 }
3137}
3138
3139#[test]
3140fn test_absrect_collide() {
3141 let target = AbsRect::new(0.0, 0.0, 4.0, 4.0);
3142
3143 for l in 0..=3 {
3144 for t in 0..=3 {
3145 for r in 1..=4 {
3146 for b in 1..=4 {
3147 let rhs = AbsRect::new(l as f32, t as f32, r as f32, b as f32);
3148 assert!(
3149 target.collides(&rhs),
3150 "{target} not detected as touching {rhs}"
3151 );
3152 }
3153 }
3154 }
3155 }
3156
3157 for l in -2..=3 {
3158 for t in -2..=3 {
3159 for r in 1..=4 {
3160 for b in 1..=4 {
3161 assert!(target.collides(&AbsRect::new(l as f32, t as f32, r as f32, b as f32)));
3162 }
3163 }
3164 }
3165 }
3166
3167 for l in 1..=3 {
3168 for t in 1..=3 {
3169 for r in 3..=6 {
3170 if r > t {
3171 for b in 3..=6 {
3172 if b > t {
3173 let rhs = AbsRect::new(l as f32, t as f32, r as f32, b as f32);
3174 assert!(
3175 target.collides(&rhs),
3176 "{target} not detected as touching {rhs}"
3177 );
3178 }
3179 }
3180 }
3181 }
3182 }
3183 }
3184
3185 assert!(!target.collides(&AbsRect::new(1.0, 4.0, 5.0, 5.0)));
3186
3187 assert!(!target.collides(&AbsRect::new(4.0, 4.0, 5.0, 5.0)));
3189 assert!(!target.collides(&AbsRect::new(4.0, 0.0, 5.0, 4.0)));
3190 assert!(!target.collides(&AbsRect::new(0.0, 4.0, 4.0, 5.0)));
3191
3192 assert!(!target.collides(&AbsRect::new(-1.0, -1.0, 0.0, 0.0)));
3193 assert!(!target.collides(&AbsRect::new(-1.0, 0.0, 0.0, 4.0)));
3194 assert!(!target.collides(&AbsRect::new(0.0, -1.0, 4.0, 0.0)));
3195}
3196
3197#[test]
3198fn test_absrect_intersect() {
3199 let target = AbsRect::new(0.0, 0.0, 4.0, 4.0);
3200
3201 assert!(target.intersect(AbsRect::new(2.0, 2.0, 6.0, 6.0)) == AbsRect::new(2.0, 2.0, 4.0, 4.0));
3202 assert!(
3203 target.intersect(AbsRect::new(-2.0, -2.0, 2.0, 2.0)) == AbsRect::new(0.0, 0.0, 2.0, 2.0)
3204 );
3205
3206 assert!(
3207 target.intersect(AbsRect::new(-2.0, -2.0, -1.0, -1.0)) == AbsRect::new(0.0, 0.0, 0.0, 0.0)
3208 );
3209
3210 assert!(target.intersect(AbsRect::new(6.0, 6.0, 8.0, 8.0)) == AbsRect::new(6.0, 6.0, 6.0, 6.0));
3211}
3212
3213#[test]
3214fn test_absrect_extend() {
3215 let target = AbsRect::new(0.0, 0.0, 4.0, 4.0);
3216
3217 assert!(target.extend(AbsRect::new(2.0, 2.0, 6.0, 6.0)) == AbsRect::new(0.0, 0.0, 6.0, 6.0));
3218 assert!(
3219 target.extend(AbsRect::new(-2.0, -2.0, 2.0, 2.0)) == AbsRect::new(-2.0, -2.0, 4.0, 4.0)
3220 );
3221}
3222
3223#[test]
3224fn test_limits_add() {
3225 let limits = AbsLimits::new(.., 10.0..200.0);
3226 assert_eq!(
3227 limits.min(),
3228 Size2D::<f32, Logical>::new(f32::NEG_INFINITY, 10.0)
3229 );
3230 assert_eq!(
3231 limits.max(),
3232 Size2D::<f32, Logical>::new(f32::INFINITY, 200.0)
3233 );
3234
3235 let rlimits = RelLimits::new(..1.0, ..);
3236 assert_eq!(
3237 rlimits.min(),
3238 Size2D::<f32, Relative>::new(f32::NEG_INFINITY, f32::NEG_INFINITY)
3239 );
3240 assert_eq!(
3241 rlimits.max(),
3242 Size2D::<f32, Relative>::new(1.0, f32::INFINITY)
3243 );
3244
3245 let merged = AbsLimits::new(0.0.., 5.0..100.0) + limits;
3246 assert_eq!(merged.min(), Size2D::<f32, Logical>::new(0.0, 10.0));
3247 assert_eq!(
3248 merged.max(),
3249 Size2D::<f32, Logical>::new(f32::INFINITY, 100.0)
3250 );
3251}