1use crate::cast::*;
20use crate::dir::Directional;
21use std::cmp::{Ordering, PartialOrd};
22
23mod transform;
24mod vector;
25pub use transform::{Affine, Linear};
26pub use vector::{DVec2, Quad, Vec2, Vec3};
27
28macro_rules! impl_common {
29 ($T:ty) => {
30 impl $T {
31 pub const ZERO: Self = Self(0, 0);
33
34 pub const MIN: Self = Self(i32::MIN, i32::MIN);
36
37 pub const MAX: Self = Self(i32::MAX, i32::MAX);
39
40 #[inline]
42 #[must_use = "method does not modify self but returns a new value"]
43 pub fn min(self, other: Self) -> Self {
44 Self(self.0.min(other.0), self.1.min(other.1))
45 }
46
47 #[inline]
49 #[must_use = "method does not modify self but returns a new value"]
50 pub fn max(self, other: Self) -> Self {
51 Self(self.0.max(other.0), self.1.max(other.1))
52 }
53
54 #[inline]
56 #[must_use = "method does not modify self but returns a new value"]
57 pub fn clamp(self, min: Self, max: Self) -> Self {
58 debug_assert!(min <= max);
59 self.min(max).max(min)
60 }
61
62 #[inline]
64 #[must_use = "method does not modify self but returns a new value"]
65 pub fn transpose(self) -> Self {
66 Self(self.1, self.0)
67 }
68
69 #[inline]
71 #[must_use = "method does not modify self but returns a new value"]
72 pub fn cwise_mul(self, rhs: Self) -> Self {
73 Self(self.0 * rhs.0, self.1 * rhs.1)
74 }
75
76 #[inline]
78 #[must_use = "method does not modify self but returns a new value"]
79 pub fn cwise_div(self, rhs: Self) -> Self {
80 Self(self.0 / rhs.0, self.1 / rhs.1)
81 }
82
83 #[inline]
85 pub fn distance_l1(self) -> i32 {
86 self.0.abs() + self.1.abs()
87 }
88
89 #[inline]
91 pub fn distance_l_inf(self) -> i32 {
92 self.0.abs().max(self.1.abs())
93 }
94
95 #[inline]
100 pub fn extract<D: Directional>(self, dir: D) -> i32 {
101 match dir.is_vertical() {
102 false => self.0,
103 true => self.1,
104 }
105 }
106
107 #[inline]
111 pub fn set_component<D: Directional>(&mut self, dir: D, value: i32) {
112 match dir.is_vertical() {
113 false => self.0 = value,
114 true => self.1 = value,
115 }
116 }
117 }
118
119 impl PartialOrd for $T {
120 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
121 if self == rhs {
122 Some(Ordering::Equal)
123 } else if self.0 < rhs.0 && self.1 < rhs.1 {
124 Some(Ordering::Less)
125 } else if self.0 > rhs.0 && self.1 > rhs.1 {
126 Some(Ordering::Greater)
127 } else {
128 None
129 }
130 }
131
132 #[inline]
133 fn lt(&self, rhs: &Self) -> bool {
134 self.0 < rhs.0 && self.1 < rhs.1
135 }
136
137 #[inline]
138 fn le(&self, rhs: &Self) -> bool {
139 self.0 <= rhs.0 && self.1 <= rhs.1
140 }
141
142 #[inline]
143 fn ge(&self, rhs: &Self) -> bool {
144 self.0 >= rhs.0 && self.1 >= rhs.1
145 }
146
147 #[inline]
148 fn gt(&self, rhs: &Self) -> bool {
149 self.0 > rhs.0 && self.1 > rhs.1
150 }
151 }
152
153 impl From<(i32, i32)> for $T {
154 #[inline]
155 fn from(v: (i32, i32)) -> Self {
156 Self(v.0, v.1)
157 }
158 }
159 impl Conv<(i32, i32)> for $T {
160 #[inline]
161 fn conv(v: (i32, i32)) -> Self {
162 Self(v.0, v.1)
163 }
164 #[inline]
165 fn try_conv(v: (i32, i32)) -> Result<Self> {
166 Ok(Self::conv(v))
167 }
168 }
169 };
170}
171
172#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
182#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
183pub struct Coord(pub i32, pub i32);
184
185impl_common!(Coord);
186
187impl Coord {
188 #[inline]
190 pub fn new(x: i32, y: i32) -> Self {
191 Self(x, y)
192 }
193
194 #[inline]
196 pub const fn splat(n: i32) -> Self {
197 Self(n, n)
198 }
199}
200
201impl std::ops::Sub for Coord {
202 type Output = Offset;
203
204 #[inline]
205 fn sub(self, other: Self) -> Offset {
206 Offset(self.0 - other.0, self.1 - other.1)
207 }
208}
209
210impl std::ops::Add<Offset> for Coord {
211 type Output = Self;
212
213 #[inline]
214 fn add(self, other: Offset) -> Self {
215 Coord(self.0 + other.0, self.1 + other.1)
216 }
217}
218impl std::ops::AddAssign<Offset> for Coord {
219 #[inline]
220 fn add_assign(&mut self, rhs: Offset) {
221 self.0 += rhs.0;
222 self.1 += rhs.1;
223 }
224}
225impl std::ops::Sub<Offset> for Coord {
226 type Output = Self;
227
228 #[inline]
229 fn sub(self, other: Offset) -> Self {
230 Coord(self.0 - other.0, self.1 - other.1)
231 }
232}
233impl std::ops::SubAssign<Offset> for Coord {
234 #[inline]
235 fn sub_assign(&mut self, rhs: Offset) {
236 self.0 -= rhs.0;
237 self.1 -= rhs.1;
238 }
239}
240
241impl std::ops::Add<Size> for Coord {
242 type Output = Self;
243
244 #[inline]
245 fn add(self, other: Size) -> Self {
246 Coord(self.0 + other.0, self.1 + other.1)
247 }
248}
249impl std::ops::AddAssign<Size> for Coord {
250 #[inline]
251 fn add_assign(&mut self, rhs: Size) {
252 self.0 += rhs.0;
253 self.1 += rhs.1;
254 }
255}
256impl std::ops::Sub<Size> for Coord {
257 type Output = Self;
258
259 #[inline]
260 fn sub(self, other: Size) -> Self {
261 Coord(self.0 - other.0, self.1 - other.1)
262 }
263}
264impl std::ops::SubAssign<Size> for Coord {
265 #[inline]
266 fn sub_assign(&mut self, rhs: Size) {
267 self.0 -= rhs.0;
268 self.1 -= rhs.1;
269 }
270}
271
272impl Conv<Coord> for kas_text::Vec2 {
273 #[inline]
274 fn try_conv(pos: Coord) -> Result<Self> {
275 Ok(Vec2::try_conv(pos)?.into())
276 }
277}
278
279#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
297#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
298pub struct Size(pub i32, pub i32);
299
300impl_common!(Size);
301
302impl Size {
303 #[inline]
307 pub fn new(w: i32, h: i32) -> Self {
308 debug_assert!(w >= 0 && h >= 0, "Size::new({w}, {h}): negative value");
309 Self(w, h)
310 }
311
312 #[inline]
316 pub fn splat(n: i32) -> Self {
317 debug_assert!(n >= 0, "Size::splat({n}): negative value");
318 Self(n, n)
319 }
320
321 pub fn aspect_scale_to(self, target: Size) -> Option<Size> {
325 if self.0 == 0 || self.1 == 0 {
326 return None;
327 }
328
329 let h = i32::conv((i64::conv(self.1) * i64::conv(target.0)) / i64::conv(self.0));
330 if h <= target.1 {
331 Some(Size(target.0, h))
332 } else {
333 let w = i32::conv((i64::conv(self.0) * i64::conv(target.1)) / i64::conv(self.1));
334 Some(Size(w, target.1))
335 }
336 }
337}
338
339impl std::ops::Add for Size {
340 type Output = Self;
341
342 #[inline]
343 fn add(self, other: Self) -> Self {
344 Size(self.0 + other.0, self.1 + other.1)
345 }
346}
347impl std::ops::AddAssign for Size {
348 #[inline]
349 fn add_assign(&mut self, rhs: Self) {
350 self.0 += rhs.0;
351 self.1 += rhs.1;
352 }
353}
354
355impl std::ops::Sub for Size {
359 type Output = Self;
360
361 #[inline]
362 fn sub(self, rhs: Self) -> Self {
363 Size(self.0 - rhs.0, self.1 - rhs.1).max(Size::ZERO)
365 }
366}
367impl std::ops::SubAssign for Size {
371 #[inline]
372 fn sub_assign(&mut self, rhs: Self) {
373 *self = *self - rhs;
374 }
375}
376
377impl std::ops::Mul<i32> for Size {
381 type Output = Self;
382
383 #[inline]
384 fn mul(self, x: i32) -> Self {
385 debug_assert!(x >= 0);
386 Size(self.0 * x, self.1 * x)
387 }
388}
389impl std::ops::Div<i32> for Size {
393 type Output = Self;
394
395 #[inline]
396 fn div(self, x: i32) -> Self {
397 debug_assert!(x >= 0);
398 Size(self.0 / x, self.1 / x)
399 }
400}
401
402impl Conv<Offset> for Coord {
406 #[inline]
407 fn try_conv(v: Offset) -> Result<Self> {
408 debug_assert!(v.0 >= 0 && v.1 >= 0, "Coord::conv({v:?}): negative value");
409 Ok(Self(v.0, v.1))
410 }
411}
412
413impl Conv<Offset> for Size {
417 #[inline]
418 fn try_conv(v: Offset) -> Result<Self> {
419 debug_assert!(v.0 >= 0 && v.1 >= 0, "Size::conv({v:?}): negative value");
420 Ok(Self(v.0, v.1))
421 }
422}
423
424impl Conv<Size> for (u16, u16) {
426 #[inline]
427 fn try_conv(size: Size) -> Result<Self> {
428 Ok((size.0.try_cast()?, size.1.try_cast()?))
429 }
430}
431impl Conv<(u16, u16)> for Size {
432 #[inline]
433 fn try_conv(v: (u16, u16)) -> Result<Self> {
434 Ok(Self(i32::try_conv(v.0)?, i32::try_conv(v.1)?))
435 }
436}
437
438impl Conv<(u32, u32)> for Size {
439 #[inline]
440 fn try_conv(v: (u32, u32)) -> Result<Self> {
441 Ok(Self(i32::try_conv(v.0)?, i32::try_conv(v.1)?))
442 }
443}
444
445impl Conv<Size> for (u32, u32) {
446 #[inline]
447 fn try_conv(size: Size) -> Result<Self> {
448 Ok((u32::try_conv(size.0)?, u32::try_conv(size.1)?))
449 }
450}
451
452impl Conv<Size> for kas_text::Vec2 {
453 #[inline]
454 fn try_conv(size: Size) -> Result<Self> {
455 Ok(Vec2::try_conv(size)?.into())
456 }
457}
458
459#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
472#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
473pub struct Offset(pub i32, pub i32);
474
475impl_common!(Offset);
476
477impl Offset {
478 #[inline]
480 pub fn new(x: i32, y: i32) -> Self {
481 Self(x, y)
482 }
483
484 #[inline]
486 pub const fn splat(n: i32) -> Self {
487 Self(n, n)
488 }
489}
490
491impl std::ops::Neg for Offset {
492 type Output = Self;
493
494 #[inline]
495 fn neg(self) -> Self {
496 Offset(-self.0, -self.1)
497 }
498}
499
500impl std::ops::Add for Offset {
501 type Output = Self;
502
503 #[inline]
504 fn add(self, other: Self) -> Self {
505 Offset(self.0 + other.0, self.1 + other.1)
506 }
507}
508impl std::ops::AddAssign for Offset {
509 #[inline]
510 fn add_assign(&mut self, rhs: Self) {
511 self.0 += rhs.0;
512 self.1 += rhs.1;
513 }
514}
515
516impl std::ops::Sub for Offset {
517 type Output = Self;
518
519 #[inline]
520 fn sub(self, other: Self) -> Self {
521 Offset(self.0 - other.0, self.1 - other.1)
522 }
523}
524impl std::ops::SubAssign for Offset {
525 #[inline]
526 fn sub_assign(&mut self, rhs: Self) {
527 self.0 -= rhs.0;
528 self.1 -= rhs.1;
529 }
530}
531
532impl std::ops::Mul<i32> for Offset {
533 type Output = Self;
534
535 #[inline]
536 fn mul(self, x: i32) -> Self {
537 Offset(self.0 * x, self.1 * x)
538 }
539}
540impl std::ops::Div<i32> for Offset {
541 type Output = Self;
542
543 #[inline]
544 fn div(self, x: i32) -> Self {
545 Offset(self.0 / x, self.1 / x)
546 }
547}
548
549impl Conv<Coord> for Offset {
550 #[inline]
551 fn try_conv(v: Coord) -> Result<Self> {
552 Ok(Self(v.0, v.1))
553 }
554}
555
556impl Conv<Size> for Offset {
557 #[inline]
558 fn try_conv(v: Size) -> Result<Self> {
559 Ok(Self(v.0, v.1))
560 }
561}
562
563impl Conv<Offset> for kas_text::Vec2 {
564 #[inline]
565 fn try_conv(v: Offset) -> Result<Self> {
566 Ok(Vec2::try_conv(v)?.into())
567 }
568}
569
570#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
575#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
576pub struct Rect {
577 pub pos: Coord,
578 pub size: Size,
579}
580
581impl Rect {
582 pub const ZERO: Self = Self::new(Coord::ZERO, Size::ZERO);
584
585 #[inline]
587 pub const fn new(pos: Coord, size: Size) -> Self {
588 Rect { pos, size }
589 }
590
591 #[inline]
595 pub fn from_coords(pos: Coord, pos2: Coord) -> Self {
596 let size = (pos2 - pos).cast();
597 Rect { pos, size }
598 }
599
600 #[inline]
602 pub fn pos2(&self) -> Coord {
603 self.pos + self.size
604 }
605
606 #[inline]
608 pub fn contains<P: PartialOrd<Coord>>(&self, p: P) -> bool {
609 p >= self.pos && p < self.pos2()
610 }
611
612 #[inline]
614 pub fn intersection(&self, rhs: &Rect) -> Option<Rect> {
615 let (l1, l2) = (self.pos, self.pos2());
616 let (r1, r2) = (rhs.pos, rhs.pos2());
617 let pos = l1.max(r1);
618 let pos2 = l2.min(r2);
619 if pos <= pos2 {
620 Some(Rect::new(pos, (pos2 - pos).cast()))
621 } else {
622 None
623 }
624 }
625
626 #[inline]
628 #[must_use = "method does not modify self but returns a new value"]
629 pub fn shrink(&self, n: i32) -> Rect {
630 let pos = self.pos + Offset::splat(n);
631 let size = self.size - Size::splat(n + n);
632 Rect { pos, size }
633 }
634
635 #[inline]
639 #[must_use = "method does not modify self but returns a new value"]
640 pub fn expand(&self, n: i32) -> Rect {
641 debug_assert!(n >= 0);
642 let pos = self.pos - Offset::splat(n);
643 let size = self.size + Size::splat(n + n);
644 Rect { pos, size }
645 }
646}
647
648impl std::ops::Add<Offset> for Rect {
649 type Output = Self;
650
651 #[inline]
652 fn add(self, offset: Offset) -> Self {
653 Rect::new(self.pos + offset, self.size)
654 }
655}
656impl std::ops::AddAssign<Offset> for Rect {
657 #[inline]
658 fn add_assign(&mut self, offset: Offset) {
659 self.pos += offset;
660 }
661}
662
663impl std::ops::Sub<Offset> for Rect {
664 type Output = Self;
665
666 #[inline]
667 fn sub(self, offset: Offset) -> Self {
668 Rect::new(self.pos - offset, self.size)
669 }
670}
671impl std::ops::SubAssign<Offset> for Rect {
672 #[inline]
673 fn sub_assign(&mut self, offset: Offset) {
674 self.pos -= offset;
675 }
676}
677
678#[cfg(feature = "accesskit")]
679mod accesskit_impls {
680 use super::{Coord, Offset, Rect};
681 use crate::cast::{Cast, CastApprox, Conv, ConvApprox, Result};
682
683 impl ConvApprox<accesskit::Point> for Coord {
684 fn try_conv_approx(p: accesskit::Point) -> Result<Self> {
685 Ok(Coord(p.x.try_cast_approx()?, p.y.try_cast_approx()?))
686 }
687 }
688
689 impl Conv<Rect> for accesskit::Rect {
690 fn try_conv(rect: Rect) -> Result<Self> {
691 let p = rect.pos;
692 let p2 = rect.pos2();
693 Ok(accesskit::Rect {
694 x0: p.0.try_cast()?,
695 y0: p.1.try_cast()?,
696 x1: p2.0.try_cast()?,
697 y1: p2.1.try_cast()?,
698 })
699 }
700 }
701
702 impl ConvApprox<accesskit::Rect> for Rect {
703 fn try_conv_approx(rect: accesskit::Rect) -> Result<Self> {
704 let pos = Coord(rect.x0.try_cast_approx()?, rect.y0.try_cast_approx()?);
705 let p2 = Coord(rect.x1.try_cast_approx()?, rect.y1.try_cast_approx()?);
706 let size = (p2 - pos).cast();
707 Ok(Rect { pos, size })
708 }
709 }
710
711 impl ConvApprox<accesskit::Point> for Offset {
712 fn try_conv_approx(point: accesskit::Point) -> Result<Self> {
713 Ok(Offset(
714 point.x.try_cast_approx()?,
715 point.y.try_cast_approx()?,
716 ))
717 }
718 }
719}
720
721mod winit_impls {
722 use super::{Coord, Size};
723 use crate::cast::{Cast, CastApprox, Conv, ConvApprox, Result};
724 use winit::dpi::{PhysicalPosition, PhysicalSize};
725
726 impl<X: CastApprox<i32>> ConvApprox<PhysicalPosition<X>> for Coord {
727 #[inline]
728 fn try_conv_approx(pos: PhysicalPosition<X>) -> Result<Self> {
729 Ok(Coord(pos.x.try_cast_approx()?, pos.y.try_cast_approx()?))
730 }
731 }
732
733 impl<X: Cast<i32>> Conv<PhysicalSize<X>> for Size {
734 #[inline]
735 fn try_conv(size: PhysicalSize<X>) -> Result<Self> {
736 Ok(Size(size.width.cast(), size.height.cast()))
737 }
738 }
739
740 impl Coord {
741 #[inline]
747 pub fn as_physical(self) -> winit::dpi::Position {
748 winit::dpi::Position::Physical(PhysicalPosition::new(self.0, self.1))
749 }
750 }
751
752 impl Size {
753 #[inline]
759 pub fn as_physical(self) -> winit::dpi::Size {
760 let (w, h): (u32, u32) = self.cast();
761 winit::dpi::Size::Physical(PhysicalSize::new(w, h))
762 }
763 }
764}