gioser

tawasuyu/mirada

Sovereign tiling Wayland compositor + window manager in Rust, on Llimphi.

Rust 50Markdown 30TOML 211282 Definitions

⎇ main vendor/smithay/src/utils/geometry.rs Rust · 2029 lines · 61.2 KB History Who touched what raw

chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0) a91da3fea · Sergio ·

1use std::fmt;
2use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
3
4#[cfg(feature = "wayland_frontend")]
5use wayland_server::protocol::wl_output::Transform as WlTransform;
6
7/// Type-level marker for the logical coordinate space
8#[derive(Debug)]
9pub struct Logical;
10
11/// Type-level marker for the client logical coordinate space
12#[derive(Debug)]
13#[cfg(feature = "wayland_frontend")]
14pub(crate) struct Client;
15
16/// Type-level marker for the physical coordinate space
17#[derive(Debug)]
18pub struct Physical;
19
20/// Type-level marker for the buffer coordinate space
21#[derive(Debug)]
22pub struct Buffer;
23
24/// Type-level marker for raw coordinate space, provided by input devices
25#[derive(Debug)]
26pub struct Raw;
27
28/// Trait for types serving as a coordinate for other geometry utils
29pub trait Coordinate:
30    Sized + Add<Self, Output = Self> + Sub<Self, Output = Self> + PartialOrd + Default + Copy + fmt::Debug
31{
32    /// A Coordinate that is 0
33    const ZERO: Self;
34    /// Downscale the coordinate
35    fn downscale(self, scale: Self) -> Self;
36    /// Upscale the coordinate
37    fn upscale(self, scale: Self) -> Self;
38    /// Convert the coordinate to a f64
39    fn to_f64(self) -> f64;
40    /// Convert to this coordinate from a f64
41    fn from_f64(v: f64) -> Self;
42    /// Compare and return the smaller one
43    fn min(self, other: Self) -> Self {
44        if self < other {
45            self
46        } else {
47            other
48        }
49    }
50    /// Compare and return the larger one
51    fn max(self, other: Self) -> Self {
52        if self > other {
53            self
54        } else {
55            other
56        }
57    }
58    /// Test if the coordinate is not negative
59    fn non_negative(self) -> bool;
60    /// Returns the absolute value of this coordinate
61    fn abs(self) -> Self;
62
63    /// Saturating integer addition. Computes self + other, saturating at the numeric bounds instead of overflowing.
64    fn saturating_add(self, other: Self) -> Self;
65    /// Saturating integer subtraction. Computes self - other, saturating at the numeric bounds instead of overflowing.
66    fn saturating_sub(self, other: Self) -> Self;
67    /// Saturating integer multiplication. Computes self * other, saturating at the numeric bounds instead of overflowing.
68    fn saturating_mul(self, other: Self) -> Self;
69}
70
71/// Implements Coordinate for an unsigned numerical type.
72macro_rules! unsigned_coordinate_impl {
73    ($ty:ty, $ ($tys:ty),* ) => {
74        unsigned_coordinate_impl!($ty);
75        $(
76            unsigned_coordinate_impl!($tys);
77        )*
78    };
79
80    ($ty:ty) => {
81        impl Coordinate for $ty {
82            const ZERO: $ty = 0;
83
84            #[inline]
85            fn downscale(self, scale: Self) -> Self {
86                self / scale
87            }
88
89            #[inline]
90            fn upscale(self, scale: Self) -> Self {
91                self.saturating_mul(scale)
92            }
93
94            #[inline]
95            fn to_f64(self) -> f64 {
96                self as f64
97            }
98
99            #[inline]
100            fn from_f64(v: f64) -> Self {
101                v as Self
102            }
103
104            #[inline]
105            fn non_negative(self) -> bool {
106                true
107            }
108
109            #[inline]
110            fn abs(self) -> Self {
111                self
112            }
113
114            #[inline]
115            fn saturating_add(self, other: Self) -> Self {
116                self.saturating_add(other)
117            }
118            #[inline]
119            fn saturating_sub(self, other: Self) -> Self {
120                self.saturating_sub(other)
121            }
122            #[inline]
123            fn saturating_mul(self, other: Self) -> Self {
124                self.saturating_mul(other)
125            }
126        }
127    };
128}
129
130unsigned_coordinate_impl! {
131    u8,
132    u16,
133    u32,
134    u64,
135    u128
136}
137
138/// Implements Coordinate for an signed numerical type.
139macro_rules! signed_coordinate_impl {
140    ($ty:ty, $ ($tys:ty),* ) => {
141        signed_coordinate_impl!($ty);
142        $(
143            signed_coordinate_impl!($tys);
144        )*
145    };
146
147    ($ty:ty) => {
148        impl Coordinate for $ty {
149            const ZERO: $ty = 0;
150
151            #[inline]
152            fn downscale(self, scale: Self) -> Self {
153                self / scale
154            }
155
156            #[inline]
157            fn upscale(self, scale: Self) -> Self {
158                self.saturating_mul(scale)
159            }
160
161            #[inline]
162            fn to_f64(self) -> f64 {
163                self as f64
164            }
165
166            #[inline]
167            fn from_f64(v: f64) -> Self {
168                v as Self
169            }
170
171            #[inline]
172            fn non_negative(self) -> bool {
173                self >= 0
174            }
175
176            #[inline]
177            fn abs(self) -> Self {
178                self.abs()
179            }
180
181            #[inline]
182            fn saturating_add(self, other: Self) -> Self {
183                self.saturating_add(other)
184            }
185            #[inline]
186            fn saturating_sub(self, other: Self) -> Self {
187                self.saturating_sub(other)
188            }
189            #[inline]
190            fn saturating_mul(self, other: Self) -> Self {
191                self.saturating_mul(other)
192            }
193        }
194    };
195}
196
197signed_coordinate_impl! {
198    i8,
199    i16,
200    i32,
201    i64,
202    i128
203}
204
205macro_rules! floating_point_coordinate_impl {
206    ($ty:ty, $ ($tys:ty),* ) => {
207        floating_point_coordinate_impl!($ty);
208        $(
209            floating_point_coordinate_impl!($tys);
210        )*
211    };
212
213    ($ty:ty) => {
214        impl Coordinate for $ty {
215            const ZERO: $ty = 0.0;
216
217            #[inline]
218            fn downscale(self, scale: Self) -> Self {
219                self / scale
220            }
221
222            #[inline]
223            fn upscale(self, scale: Self) -> Self {
224                self * scale
225            }
226
227            #[inline]
228            fn to_f64(self) -> f64 {
229                self as f64
230            }
231
232            #[inline]
233            fn from_f64(v: f64) -> Self {
234                v as Self
235            }
236
237            #[inline]
238            fn non_negative(self) -> bool {
239                self >= 0.0
240            }
241
242            #[inline]
243            fn abs(self) -> Self {
244                self.abs()
245            }
246
247            #[inline]
248            fn saturating_add(self, other: Self) -> Self {
249                self + other
250            }
251            #[inline]
252            fn saturating_sub(self, other: Self) -> Self {
253                self - other
254            }
255            #[inline]
256            fn saturating_mul(self, other: Self) -> Self {
257                self * other
258            }
259        }
260    };
261}
262
263floating_point_coordinate_impl! {
264    f32,
265    f64
266}
267
268/*
269 * Scale
270 */
271
272/// A two-dimensional scale that can be
273/// used to scale [`Point`]s, [`Size`]s and
274/// [`Rectangle`]s
275#[derive(Debug, Clone, Copy, PartialEq, Eq)]
276pub struct Scale<N: Coordinate> {
277    /// The scale on the x axis
278    pub x: N,
279    /// The scale on the y axis
280    pub y: N,
281}
282
283impl<N: Coordinate> Scale<N> {
284    /// Convert the underlying numerical type to f64 for floating point manipulations
285    #[inline]
286    pub fn to_f64(self) -> Scale<f64> {
287        Scale {
288            x: self.x.to_f64(),
289            y: self.y.to_f64(),
290        }
291    }
292}
293
294impl<N: Coordinate> From<N> for Scale<N> {
295    #[inline]
296    fn from(scale: N) -> Self {
297        Scale { x: scale, y: scale }
298    }
299}
300
301impl<N: Coordinate> From<(N, N)> for Scale<N> {
302    #[inline]
303    fn from((scale_x, scale_y): (N, N)) -> Self {
304        Scale {
305            x: scale_x,
306            y: scale_y,
307        }
308    }
309}
310
311impl<N, T> Mul<T> for Scale<N>
312where
313    N: Coordinate,
314    T: Into<Scale<N>>,
315{
316    type Output = Scale<N>;
317
318    #[inline]
319    fn mul(self, rhs: T) -> Self::Output {
320        let rhs = rhs.into();
321        Scale {
322            x: self.x.upscale(rhs.x),
323            y: self.y.upscale(rhs.y),
324        }
325    }
326}
327
328/*
329 * Point
330 */
331
332/// A point as defined by its x and y coordinates
333///
334/// Operations on points are saturating.
335#[repr(C)]
336pub struct Point<N, Kind> {
337    /// horizontal coordinate
338    pub x: N,
339    /// vertical coordinate
340    pub y: N,
341    _kind: std::marker::PhantomData<Kind>,
342}
343
344impl<N, Kind> Point<N, Kind> {
345    /// Create a new Point
346    pub const fn new(x: N, y: N) -> Point<N, Kind> {
347        Point {
348            x,
349            y,
350            _kind: std::marker::PhantomData,
351        }
352    }
353}
354
355impl<N: Coordinate, Kind> Point<N, Kind> {
356    /// Convert this [`Point`] to a [`Size`] with the same coordinates
357    ///
358    /// Checks that the coordinates are positive with a `debug_assert!()`.
359    #[inline]
360    pub fn to_size(self) -> Size<N, Kind> {
361        debug_assert!(
362            self.x.non_negative() && self.y.non_negative(),
363            "Attempting to create a `Size` of negative size: {:?}",
364            (self.x, self.y)
365        );
366        Size {
367            w: self.x,
368            h: self.y,
369            _kind: std::marker::PhantomData,
370        }
371    }
372
373    /// Convert this [`Point`] to a [`Size`] with the same coordinates
374    ///
375    /// Ensures that the coordinates are positive by taking their absolute value
376    #[inline]
377    pub fn to_size_abs(self) -> Size<N, Kind> {
378        Size {
379            w: self.x.abs(),
380            h: self.y.abs(),
381            _kind: std::marker::PhantomData,
382        }
383    }
384
385    /// Upscale this [`Point`] by a specified [`Scale`]
386    #[inline]
387    pub fn upscale(self, scale: impl Into<Scale<N>>) -> Point<N, Kind> {
388        let scale = scale.into();
389        Point {
390            x: self.x.upscale(scale.x),
391            y: self.y.upscale(scale.y),
392            _kind: std::marker::PhantomData,
393        }
394    }
395
396    /// Downscale this [`Point`] by a specified [`Scale`]
397    #[inline]
398    pub fn downscale(self, scale: impl Into<Scale<N>>) -> Point<N, Kind> {
399        let scale = scale.into();
400        Point {
401            x: self.x.downscale(scale.x),
402            y: self.y.downscale(scale.y),
403            _kind: std::marker::PhantomData,
404        }
405    }
406}
407
408impl<N: Coordinate, Kind> Point<N, Kind> {
409    /// Constrain this [`Point`] within a [`Rectangle`] with the same coordinates
410    ///
411    /// The [`Point`] returned is guaranteed to be not smaller than the [`Rectangle`]
412    /// location and not greater than the [`Rectangle`] location plus size.
413    #[inline]
414    pub fn constrain(self, rect: impl Into<Rectangle<N, Kind>>) -> Point<N, Kind> {
415        let rect = rect.into();
416
417        Point {
418            x: self.x.max(rect.loc.x).min(rect.loc.x + rect.size.w),
419            y: self.y.max(rect.loc.y).min(rect.loc.y + rect.size.h),
420            _kind: std::marker::PhantomData,
421        }
422    }
423}
424
425impl<N: Coordinate, Kind> Point<N, Kind> {
426    /// Convert the underlying numerical type to f64 for floating point manipulations
427    #[inline]
428    pub fn to_f64(self) -> Point<f64, Kind> {
429        Point {
430            x: self.x.to_f64(),
431            y: self.y.to_f64(),
432            _kind: std::marker::PhantomData,
433        }
434    }
435}
436
437impl<Kind> Point<f64, Kind> {
438    /// Convert to i32 for integer-space manipulations by rounding float values
439    #[inline]
440    pub fn to_i32_round<N: Coordinate>(self) -> Point<N, Kind> {
441        Point {
442            x: N::from_f64(self.x.round()),
443            y: N::from_f64(self.y.round()),
444            _kind: std::marker::PhantomData,
445        }
446    }
447
448    /// Convert to i32 for integer-space manipulations by flooring float values
449    #[inline]
450    pub fn to_i32_floor<N: Coordinate>(self) -> Point<N, Kind> {
451        Point {
452            x: N::from_f64(self.x.floor()),
453            y: N::from_f64(self.y.floor()),
454            _kind: std::marker::PhantomData,
455        }
456    }
457
458    /// Convert to i32 for integer-space manipulations by ceiling float values
459    #[inline]
460    pub fn to_i32_ceil<N: Coordinate>(self) -> Point<N, Kind> {
461        Point {
462            x: N::from_f64(self.x.ceil()),
463            y: N::from_f64(self.y.ceil()),
464            _kind: std::marker::PhantomData,
465        }
466    }
467}
468
469impl<N: fmt::Debug, S> fmt::Debug for Point<N, S> {
470    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471        f.write_fmt(format_args!("Point<{}>", std::any::type_name::<S>()))?;
472        f.debug_struct("")
473            .field("x", &self.x)
474            .field("y", &self.y)
475            .finish()
476    }
477}
478
479impl<N: Coordinate> Point<N, Logical> {
480    #[inline]
481    #[cfg(feature = "wayland_frontend")]
482    pub(crate) fn to_client(self, scale: impl Into<Scale<N>>) -> Point<N, Client> {
483        let scale: Scale<N> = scale.into();
484        Point {
485            x: self.x.upscale(scale.x),
486            y: self.y.upscale(scale.y),
487            _kind: std::marker::PhantomData,
488        }
489    }
490
491    #[inline]
492    #[cfg(feature = "wayland_frontend")]
493    pub(crate) fn to_client_precise_round<S: Coordinate, R: Coordinate>(
494        self,
495        scale: impl Into<Scale<S>>,
496    ) -> Point<R, Client> {
497        self.to_f64().to_client(scale.into().to_f64()).to_i32_round()
498    }
499
500    #[inline]
501    /// Convert this logical point to physical coordinate space according to given scale factor
502    pub fn to_physical(self, scale: impl Into<Scale<N>>) -> Point<N, Physical> {
503        let scale = scale.into();
504        Point {
505            x: self.x.upscale(scale.x),
506            y: self.y.upscale(scale.y),
507            _kind: std::marker::PhantomData,
508        }
509    }
510
511    /// Convert this logical point to physical coordinate space according to given scale factor
512    /// and round the result
513    #[inline]
514    pub fn to_physical_precise_round<S: Coordinate, R: Coordinate>(
515        self,
516        scale: impl Into<Scale<S>>,
517    ) -> Point<R, Physical> {
518        self.to_f64().to_physical(scale.into().to_f64()).to_i32_round()
519    }
520
521    /// Convert this logical point to physical coordinate space according to given scale factor
522    /// and ceil the result
523    #[inline]
524    pub fn to_physical_precise_ceil<S: Coordinate, R: Coordinate>(
525        &self,
526        scale: impl Into<Scale<S>>,
527    ) -> Point<R, Physical> {
528        self.to_f64().to_physical(scale.into().to_f64()).to_i32_ceil()
529    }
530
531    /// Convert this logical point to physical coordinate space according to given scale factor
532    /// and floor the result
533    #[inline]
534    pub fn to_physical_precise_floor<S: Coordinate, R: Coordinate>(
535        &self,
536        scale: impl Into<Scale<S>>,
537    ) -> Point<R, Physical> {
538        self.to_f64().to_physical(scale.into().to_f64()).to_i32_floor()
539    }
540
541    #[inline]
542    /// Convert this logical point to buffer coordinate space according to given scale factor
543    pub fn to_buffer(
544        self,
545        scale: impl Into<Scale<N>>,
546        transformation: Transform,
547        area: &Size<N, Logical>,
548    ) -> Point<N, Buffer> {
549        let point = transformation.transform_point_in(self, area);
550        let scale = scale.into();
551        Point {
552            x: point.x.upscale(scale.x),
553            y: point.y.upscale(scale.y),
554            _kind: std::marker::PhantomData,
555        }
556    }
557}
558
559#[cfg(feature = "wayland_frontend")]
560impl<N: Coordinate> Point<N, Client> {
561    #[inline]
562    pub(crate) fn to_logical(self, scale: impl Into<Scale<N>>) -> Point<N, Logical> {
563        let scale = scale.into();
564        Point {
565            x: self.x.downscale(scale.x),
566            y: self.y.downscale(scale.y),
567            _kind: std::marker::PhantomData,
568        }
569    }
570}
571
572impl<N: Coordinate> Point<N, Physical> {
573    #[inline]
574    /// Convert this physical point to logical coordinate space according to given scale factor
575    pub fn to_logical(self, scale: impl Into<Scale<N>>) -> Point<N, Logical> {
576        let scale = scale.into();
577        Point {
578            x: self.x.downscale(scale.x),
579            y: self.y.downscale(scale.y),
580            _kind: std::marker::PhantomData,
581        }
582    }
583}
584
585impl<N: Coordinate> Point<N, Buffer> {
586    #[inline]
587    /// Convert this physical point to logical coordinate space according to given scale factor
588    pub fn to_logical(
589        self,
590        scale: impl Into<Scale<N>>,
591        transform: Transform,
592        area: &Size<N, Buffer>,
593    ) -> Point<N, Logical> {
594        let point = transform.invert().transform_point_in(self, area);
595        let scale = scale.into();
596        Point {
597            x: point.x.downscale(scale.x),
598            y: point.y.downscale(scale.y),
599            _kind: std::marker::PhantomData,
600        }
601    }
602}
603
604impl<N, Kind> From<(N, N)> for Point<N, Kind> {
605    #[inline]
606    fn from((x, y): (N, N)) -> Point<N, Kind> {
607        Point::new(x, y)
608    }
609}
610
611impl<N, Kind> From<Point<N, Kind>> for (N, N) {
612    #[inline]
613    fn from(point: Point<N, Kind>) -> (N, N) {
614        (point.x, point.y)
615    }
616}
617
618impl<N: Coordinate, Kind> Add for Point<N, Kind> {
619    type Output = Point<N, Kind>;
620    #[inline]
621    fn add(self, other: Point<N, Kind>) -> Point<N, Kind> {
622        Point {
623            x: self.x.saturating_add(other.x),
624            y: self.y.saturating_add(other.y),
625            _kind: std::marker::PhantomData,
626        }
627    }
628}
629
630impl<N: Coordinate, Kind> AddAssign for Point<N, Kind> {
631    #[inline]
632    fn add_assign(&mut self, rhs: Self) {
633        self.x = self.x.saturating_add(rhs.x);
634        self.y = self.y.saturating_add(rhs.y);
635    }
636}
637
638impl<N: Coordinate, Kind> SubAssign for Point<N, Kind> {
639    #[inline]
640    fn sub_assign(&mut self, rhs: Self) {
641        self.x = self.x.saturating_sub(rhs.x);
642        self.y = self.y.saturating_sub(rhs.y);
643    }
644}
645
646impl<N: Coordinate, Kind> Sub for Point<N, Kind> {
647    type Output = Point<N, Kind>;
648    #[inline]
649    fn sub(self, other: Point<N, Kind>) -> Point<N, Kind> {
650        Point {
651            x: self.x.saturating_sub(other.x),
652            y: self.y.saturating_sub(other.y),
653            _kind: std::marker::PhantomData,
654        }
655    }
656}
657
658impl<N: Clone, Kind> Clone for Point<N, Kind> {
659    #[inline]
660    fn clone(&self) -> Self {
661        Point {
662            x: self.x.clone(),
663            y: self.y.clone(),
664            _kind: std::marker::PhantomData,
665        }
666    }
667}
668
669impl<N: Copy, Kind> Copy for Point<N, Kind> {}
670
671impl<N: PartialEq, Kind> PartialEq for Point<N, Kind> {
672    #[inline]
673    fn eq(&self, other: &Self) -> bool {
674        self.x == other.x && self.y == other.y
675    }
676}
677
678impl<N: Eq, Kind> Eq for Point<N, Kind> {}
679
680impl<N: Default, Kind> Default for Point<N, Kind> {
681    #[inline]
682    fn default() -> Self {
683        Point {
684            x: N::default(),
685            y: N::default(),
686            _kind: std::marker::PhantomData,
687        }
688    }
689}
690
691/*
692 * Size
693 */
694
695/// A size as defined by its width and height
696///
697/// Constructors of this type ensure that the values are always positive via
698/// `debug_assert!()`, however manually changing the values of the fields
699/// can break this invariant.
700///
701/// Operations on sizes are saturating.
702#[repr(C)]
703pub struct Size<N, Kind> {
704    /// horizontal coordinate
705    pub w: N,
706    /// vertical coordinate
707    pub h: N,
708    _kind: std::marker::PhantomData<Kind>,
709}
710
711impl<N: Coordinate, Kind> Size<N, Kind> {
712    /// Create a new Size
713    pub fn new(w: N, h: N) -> Size<N, Kind> {
714        debug_assert!(
715            w.non_negative() && h.non_negative(),
716            "Attempting to create a `Size` of negative size: {:?}",
717            (w, h)
718        );
719        Size {
720            w,
721            h,
722            _kind: std::marker::PhantomData,
723        }
724    }
725}
726
727impl<N: Coordinate, Kind> Size<N, Kind> {
728    /// Convert this [`Size`] to a [`Point`] with the same coordinates
729    #[inline]
730    pub fn to_point(self) -> Point<N, Kind> {
731        Point {
732            x: self.w,
733            y: self.h,
734            _kind: std::marker::PhantomData,
735        }
736    }
737}
738
739impl<N: Coordinate, Kind> Size<N, Kind> {
740    /// Restrict this [`Size`] to min and max [`Size`] with the same coordinates
741    pub fn clamp(self, min: impl Into<Size<N, Kind>>, max: impl Into<Size<N, Kind>>) -> Size<N, Kind> {
742        let min = min.into();
743        let max = max.into();
744
745        Size {
746            w: self.w.max(min.w).min(max.w),
747            h: self.h.max(min.h).min(max.h),
748            _kind: std::marker::PhantomData,
749        }
750    }
751}
752
753impl<N: Coordinate, Kind> Size<N, Kind> {
754    /// Convert the underlying numerical type to f64 for floating point manipulations
755    #[inline]
756    pub fn to_f64(self) -> Size<f64, Kind> {
757        Size {
758            w: self.w.to_f64(),
759            h: self.h.to_f64(),
760            _kind: std::marker::PhantomData,
761        }
762    }
763}
764
765impl<N: Coordinate, Kind> Size<N, Kind> {
766    /// Upscale this [`Size`] by a specified [`Scale`]
767    #[inline]
768    pub fn upscale(self, scale: impl Into<Scale<N>>) -> Size<N, Kind> {
769        let scale = scale.into();
770        Size {
771            w: self.w.upscale(scale.x),
772            h: self.h.upscale(scale.y),
773            _kind: std::marker::PhantomData,
774        }
775    }
776
777    /// Downscale this [`Size`] by a specified [`Scale`]
778    #[inline]
779    pub fn downscale(self, scale: impl Into<Scale<N>>) -> Size<N, Kind> {
780        let scale = scale.into();
781        Size {
782            w: self.w.downscale(scale.x),
783            h: self.h.downscale(scale.y),
784            _kind: std::marker::PhantomData,
785        }
786    }
787
788    /// Check if this [`Size`] is empty
789    ///
790    /// Returns true if either the width or the height is zero
791    #[inline]
792    pub fn is_empty(&self) -> bool {
793        self.w == N::default() || self.h == N::default()
794    }
795}
796
797impl<Kind> Size<f64, Kind> {
798    /// Convert to i32 for integer-space manipulations by rounding float values
799    #[inline]
800    pub fn to_i32_round<N: Coordinate>(self) -> Size<N, Kind> {
801        Size {
802            w: N::from_f64(self.w.round()),
803            h: N::from_f64(self.h.round()),
804            _kind: std::marker::PhantomData,
805        }
806    }
807
808    /// Convert to i32 for integer-space manipulations by flooring float values
809    #[inline]
810    pub fn to_i32_floor<N: Coordinate>(self) -> Size<N, Kind> {
811        Size {
812            w: N::from_f64(self.w.floor()),
813            h: N::from_f64(self.h.floor()),
814            _kind: std::marker::PhantomData,
815        }
816    }
817
818    /// Convert to i32 for integer-space manipulations by ceiling float values
819    #[inline]
820    pub fn to_i32_ceil<N: Coordinate>(self) -> Size<N, Kind> {
821        Size {
822            w: N::from_f64(self.w.ceil()),
823            h: N::from_f64(self.h.ceil()),
824            _kind: std::marker::PhantomData,
825        }
826    }
827}
828
829impl<N: fmt::Debug, S> fmt::Debug for Size<N, S> {
830    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831        f.write_fmt(format_args!("Size<{}>", std::any::type_name::<S>()))?;
832        f.debug_struct("")
833            .field("w", &self.w)
834            .field("h", &self.h)
835            .finish()
836    }
837}
838
839impl<N: Coordinate> Size<N, Logical> {
840    #[inline]
841    #[cfg(feature = "wayland_frontend")]
842    pub(crate) fn to_client(self, scale: impl Into<Scale<N>>) -> Size<N, Client> {
843        let scale = scale.into();
844        Size {
845            w: self.w.upscale(scale.x),
846            h: self.h.upscale(scale.y),
847            _kind: std::marker::PhantomData,
848        }
849    }
850
851    #[inline]
852    /// Convert this logical size to physical coordinate space according to given scale factor
853    pub fn to_physical(self, scale: impl Into<Scale<N>>) -> Size<N, Physical> {
854        let scale = scale.into();
855        Size {
856            w: self.w.upscale(scale.x),
857            h: self.h.upscale(scale.y),
858            _kind: std::marker::PhantomData,
859        }
860    }
861
862    /// Convert this logical size to physical coordinate space according to given scale factor
863    /// and round the result
864    #[inline]
865    pub fn to_physical_precise_round<S: Coordinate, R: Coordinate>(
866        self,
867        scale: impl Into<Scale<S>>,
868    ) -> Size<R, Physical> {
869        self.to_f64().to_physical(scale.into().to_f64()).to_i32_round()
870    }
871
872    /// Convert this logical size to physical coordinate space according to given scale factor
873    /// and ceil the result
874    #[inline]
875    pub fn to_physical_precise_ceil<S: Coordinate, R: Coordinate>(
876        &self,
877        scale: impl Into<Scale<S>>,
878    ) -> Size<R, Physical> {
879        self.to_f64().to_physical(scale.into().to_f64()).to_i32_ceil()
880    }
881
882    /// Convert this logical size to physical coordinate space according to given scale factor
883    /// and floor the result
884    #[inline]
885    pub fn to_physical_precise_floor<S: Coordinate, R: Coordinate>(
886        &self,
887        scale: impl Into<Scale<S>>,
888    ) -> Size<R, Physical> {
889        self.to_f64().to_physical(scale.into().to_f64()).to_i32_floor()
890    }
891
892    #[inline]
893    /// Convert this logical size to buffer coordinate space according to given scale factor
894    pub fn to_buffer(self, scale: impl Into<Scale<N>>, transformation: Transform) -> Size<N, Buffer> {
895        let scale = scale.into();
896        transformation.transform_size(Size {
897            w: self.w.upscale(scale.x),
898            h: self.h.upscale(scale.y),
899            _kind: std::marker::PhantomData,
900        })
901    }
902}
903
904#[cfg(feature = "wayland_frontend")]
905impl<N: Coordinate> Size<N, Client> {
906    #[inline]
907    pub(crate) fn to_logical(self, scale: impl Into<Scale<N>>) -> Size<N, Logical> {
908        let scale = scale.into();
909        Size {
910            w: self.w.downscale(scale.x),
911            h: self.h.downscale(scale.y),
912            _kind: std::marker::PhantomData,
913        }
914    }
915}
916
917impl<N: Coordinate> Size<N, Physical> {
918    #[inline]
919    /// Convert this physical point to logical coordinate space according to given scale factor
920    pub fn to_logical(self, scale: impl Into<Scale<N>>) -> Size<N, Logical> {
921        let scale = scale.into();
922        Size {
923            w: self.w.downscale(scale.x),
924            h: self.h.downscale(scale.y),
925            _kind: std::marker::PhantomData,
926        }
927    }
928}
929
930impl<N: Coordinate> Size<N, Buffer> {
931    #[inline]
932    /// Convert this physical point to logical coordinate space according to given scale factor
933    pub fn to_logical(self, scale: impl Into<Scale<N>>, transformation: Transform) -> Size<N, Logical> {
934        let scale = scale.into();
935        transformation.invert().transform_size(Size {
936            w: self.w.downscale(scale.x),
937            h: self.h.downscale(scale.y),
938            _kind: std::marker::PhantomData,
939        })
940    }
941}
942
943impl<N: Coordinate, Kind> From<(N, N)> for Size<N, Kind> {
944    #[inline]
945    fn from((w, h): (N, N)) -> Size<N, Kind> {
946        Size::new(w, h)
947    }
948}
949
950impl<N, Kind> From<Size<N, Kind>> for (N, N) {
951    #[inline]
952    fn from(point: Size<N, Kind>) -> (N, N) {
953        (point.w, point.h)
954    }
955}
956
957impl<N: Coordinate, Kind> Add for Size<N, Kind> {
958    type Output = Size<N, Kind>;
959    #[inline]
960    fn add(self, other: Size<N, Kind>) -> Size<N, Kind> {
961        Size {
962            w: self.w.saturating_add(other.w),
963            h: self.h.saturating_add(other.h),
964            _kind: std::marker::PhantomData,
965        }
966    }
967}
968
969impl<N: Coordinate, Kind> AddAssign for Size<N, Kind> {
970    #[inline]
971    fn add_assign(&mut self, rhs: Self) {
972        self.w = self.w.saturating_add(rhs.w);
973        self.h = self.h.saturating_add(rhs.h);
974    }
975}
976
977impl<N: Coordinate, Kind> Sub for Size<N, Kind> {
978    type Output = Size<N, Kind>;
979    #[inline]
980    fn sub(self, rhs: Self) -> Self::Output {
981        Size {
982            w: self.w.saturating_sub(rhs.w).max(N::ZERO),
983            h: self.h.saturating_sub(rhs.h).max(N::ZERO),
984            _kind: std::marker::PhantomData,
985        }
986    }
987}
988
989impl<N: Coordinate, Kind> SubAssign for Size<N, Kind> {
990    #[inline]
991    fn sub_assign(&mut self, rhs: Self) {
992        self.w = self.w.saturating_sub(rhs.w).max(N::ZERO);
993        self.h = self.h.saturating_sub(rhs.h).max(N::ZERO);
994    }
995}
996
997impl<N: Coordinate + Div<Output = N>, KindLhs, KindRhs> Div<Size<N, KindRhs>> for Size<N, KindLhs> {
998    type Output = Scale<N>;
999
1000    #[inline]
1001    fn div(self, rhs: Size<N, KindRhs>) -> Self::Output {
1002        Scale {
1003            x: self.w / rhs.w,
1004            y: self.h / rhs.h,
1005        }
1006    }
1007}
1008
1009impl<N: Coordinate + Div, Kind> Div<N> for Size<N, Kind> {
1010    type Output = Size<<N as Div>::Output, Kind>;
1011
1012    #[inline]
1013    fn div(self, rhs: N) -> Self::Output {
1014        Size {
1015            w: self.w / rhs,
1016            h: self.h / rhs,
1017            _kind: std::marker::PhantomData,
1018        }
1019    }
1020}
1021
1022impl<N: Coordinate + Mul, Kind> Mul<N> for Size<N, Kind> {
1023    type Output = Size<<N as Mul>::Output, Kind>;
1024
1025    #[inline]
1026    fn mul(self, rhs: N) -> Self::Output {
1027        Size {
1028            w: self.w * rhs,
1029            h: self.h * rhs,
1030            _kind: std::marker::PhantomData,
1031        }
1032    }
1033}
1034
1035impl<N: Clone, Kind> Clone for Size<N, Kind> {
1036    #[inline]
1037    fn clone(&self) -> Self {
1038        Size {
1039            w: self.w.clone(),
1040            h: self.h.clone(),
1041            _kind: std::marker::PhantomData,
1042        }
1043    }
1044}
1045
1046impl<N: Copy, Kind> Copy for Size<N, Kind> {}
1047
1048impl<N: PartialEq, Kind> PartialEq for Size<N, Kind> {
1049    #[inline]
1050    fn eq(&self, other: &Self) -> bool {
1051        self.w == other.w && self.h == other.h
1052    }
1053}
1054
1055impl<N: Eq, Kind> Eq for Size<N, Kind> {}
1056
1057impl<N: Default, Kind> Default for Size<N, Kind> {
1058    #[inline]
1059    fn default() -> Self {
1060        Size {
1061            w: N::default(),
1062            h: N::default(),
1063            _kind: std::marker::PhantomData,
1064        }
1065    }
1066}
1067
1068impl<N: Coordinate, Kind> Add<Size<N, Kind>> for Point<N, Kind> {
1069    type Output = Point<N, Kind>;
1070    #[inline]
1071    fn add(self, other: Size<N, Kind>) -> Point<N, Kind> {
1072        Point {
1073            x: self.x.saturating_add(other.w),
1074            y: self.y.saturating_add(other.h),
1075            _kind: std::marker::PhantomData,
1076        }
1077    }
1078}
1079
1080impl<N: Coordinate, Kind> Sub<Size<N, Kind>> for Point<N, Kind> {
1081    type Output = Point<N, Kind>;
1082    #[inline]
1083    fn sub(self, other: Size<N, Kind>) -> Point<N, Kind> {
1084        Point {
1085            x: self.x.saturating_sub(other.w),
1086            y: self.y.saturating_sub(other.h),
1087            _kind: std::marker::PhantomData,
1088        }
1089    }
1090}
1091
1092/// A rectangle defined by its top-left corner and dimensions
1093///
1094/// Operations on rectangles are saturating.
1095#[repr(C)]
1096pub struct Rectangle<N, Kind> {
1097    /// Location of the top-left corner of the rectangle
1098    pub loc: Point<N, Kind>,
1099    /// Size of the rectangle, as (width, height)
1100    pub size: Size<N, Kind>,
1101}
1102
1103impl<N: Coordinate, Kind> Rectangle<N, Kind> {
1104    /// Convert the underlying numerical type to another
1105    pub fn to_f64(self) -> Rectangle<f64, Kind> {
1106        Rectangle {
1107            loc: self.loc.to_f64(),
1108            size: self.size.to_f64(),
1109        }
1110    }
1111}
1112
1113impl<N: Coordinate, Kind> Rectangle<N, Kind> {
1114    /// Upscale this [`Rectangle`] by the supplied [`Scale`]
1115    pub fn upscale(self, scale: impl Into<Scale<N>>) -> Rectangle<N, Kind> {
1116        let scale = scale.into();
1117        Rectangle {
1118            loc: self.loc.upscale(scale),
1119            size: self.size.upscale(scale),
1120        }
1121    }
1122
1123    /// Downscale this [`Rectangle`] by the supplied [`Scale`]
1124    pub fn downscale(self, scale: impl Into<Scale<N>>) -> Rectangle<N, Kind> {
1125        let scale = scale.into();
1126        Rectangle {
1127            loc: self.loc.downscale(scale),
1128            size: self.size.downscale(scale),
1129        }
1130    }
1131
1132    /// Check if this [`Rectangle`] is empty
1133    ///
1134    /// Returns true if either the width or the height
1135    /// of the [`Size`] is zero
1136    pub fn is_empty(&self) -> bool {
1137        self.size.is_empty()
1138    }
1139}
1140
1141impl<Kind> Rectangle<f64, Kind> {
1142    /// Convert to i32 for integer-space manipulations by rounding float values
1143    #[inline]
1144    pub fn to_i32_round<N: Coordinate>(self) -> Rectangle<N, Kind> {
1145        Rectangle {
1146            loc: self.loc.to_i32_round(),
1147            size: self.size.to_i32_round(),
1148        }
1149    }
1150
1151    /// Convert to i32 by returning the largest integer-space rectangle fitting into the float-based rectangle
1152    #[inline]
1153    pub fn to_i32_down<N: Coordinate>(self) -> Rectangle<N, Kind> {
1154        Rectangle::from_extremities(self.loc.to_i32_ceil(), (self.loc + self.size).to_i32_floor())
1155    }
1156
1157    /// Convert to i32 by returning the smallest integet-space rectangle encapsulating the float-based rectangle
1158    #[inline]
1159    pub fn to_i32_up<N: Coordinate>(self) -> Rectangle<N, Kind> {
1160        Rectangle::from_extremities(self.loc.to_i32_floor(), (self.loc + self.size).to_i32_ceil())
1161    }
1162}
1163
1164impl<N: Coordinate, Kind> Rectangle<N, Kind> {
1165    /// Create a new [`Rectangle`] from the coordinates of its top-left corner and its dimensions
1166    #[deprecated(note = "use new or from_size")]
1167    #[inline]
1168    pub fn from_loc_and_size(loc: impl Into<Point<N, Kind>>, size: impl Into<Size<N, Kind>>) -> Self {
1169        Rectangle {
1170            loc: loc.into(),
1171            size: size.into(),
1172        }
1173    }
1174
1175    /// Create a new [`Rectangle`] from the coordinates of its top-left corner and its dimensions
1176    #[inline]
1177    pub fn new(loc: Point<N, Kind>, size: Size<N, Kind>) -> Self {
1178        Rectangle { loc, size }
1179    }
1180
1181    /// Create a new [`Rectangle`] from its dimensions, with location zero
1182    #[inline]
1183    pub fn from_size(size: Size<N, Kind>) -> Self {
1184        Rectangle {
1185            loc: (N::ZERO, N::ZERO).into(),
1186            size,
1187        }
1188    }
1189
1190    /// Create a new [`Rectangle`] with location and size zero
1191    #[inline]
1192    pub fn zero() -> Self {
1193        Rectangle {
1194            loc: (N::ZERO, N::ZERO).into(),
1195            size: (N::ZERO, N::ZERO).into(),
1196        }
1197    }
1198
1199    /// Create a new [`Rectangle`] from the coordinates of its top-left corner and its bottom-right corner
1200    #[inline]
1201    #[deprecated = "use Rectangle::from_extremities instead"]
1202    #[doc(hidden)]
1203    pub fn from_extemities(
1204        topleft: impl Into<Point<N, Kind>>,
1205        bottomright: impl Into<Point<N, Kind>>,
1206    ) -> Self {
1207        Rectangle::from_extremities(topleft, bottomright)
1208    }
1209
1210    /// Create a new [`Rectangle`] from the coordinates of its top-left corner and its bottom-right corner
1211    #[inline]
1212    pub fn from_extremities(
1213        topleft: impl Into<Point<N, Kind>>,
1214        bottomright: impl Into<Point<N, Kind>>,
1215    ) -> Self {
1216        let topleft = topleft.into();
1217        let bottomright = bottomright.into();
1218        Rectangle {
1219            loc: topleft,
1220            size: (bottomright - topleft).to_size(),
1221        }
1222    }
1223
1224    /// Checks whether given [`Point`] is inside the rectangle
1225    #[inline]
1226    pub fn contains<P: Into<Point<N, Kind>>>(self, point: P) -> bool {
1227        let p: Point<N, Kind> = point.into();
1228        (p.x >= self.loc.x)
1229            && (p.x < self.loc.x.saturating_add(self.size.w))
1230            && (p.y >= self.loc.y)
1231            && (p.y < self.loc.y.saturating_add(self.size.h))
1232    }
1233
1234    /// Checks whether given [`Rectangle`] is inside the rectangle
1235    ///
1236    /// A rectangle is considered inside another rectangle
1237    /// if its location is inside the other rectangle and it does not
1238    /// extend outside the other rectangle.
1239    /// This includes rectangles with the same location and size
1240    #[inline]
1241    pub fn contains_rect<R: Into<Rectangle<N, Kind>>>(self, rect: R) -> bool {
1242        let r: Rectangle<N, Kind> = rect.into();
1243        r.loc.x >= self.loc.x
1244            && r.loc.y >= self.loc.y
1245            && r.loc.x.saturating_add(r.size.w) <= self.loc.x.saturating_add(self.size.w)
1246            && r.loc.y.saturating_add(r.size.h) <= self.loc.y.saturating_add(self.size.h)
1247    }
1248
1249    /// Checks whether a given [`Rectangle`] overlaps with this one
1250    ///
1251    /// Note: This operation is exclusive, touching only rectangles will return `false`.
1252    /// For inclusive overlap test see [`overlaps_or_touches`](Rectangle::overlaps_or_touches)
1253    #[inline]
1254    pub fn overlaps(self, other: impl Into<Rectangle<N, Kind>>) -> bool {
1255        let other = other.into();
1256
1257        self.loc.x < other.loc.x.saturating_add(other.size.w)
1258            && other.loc.x < self.loc.x.saturating_add(self.size.w)
1259            && self.loc.y < other.loc.y.saturating_add(other.size.h)
1260            && other.loc.y < self.loc.y.saturating_add(self.size.h)
1261    }
1262
1263    /// Checks whether a given [`Rectangle`] overlaps with this one or touches it
1264    ///
1265    /// Note: This operation is inclusive, touching only rectangles will return `true`.
1266    /// For exclusive overlap test see [`overlaps`](Rectangle::overlaps)
1267    #[inline]
1268    pub fn overlaps_or_touches(self, other: impl Into<Rectangle<N, Kind>>) -> bool {
1269        let other = other.into();
1270
1271        self.loc.x <= other.loc.x.saturating_add(other.size.w)
1272            && other.loc.x <= self.loc.x.saturating_add(self.size.w)
1273            && self.loc.y <= other.loc.y.saturating_add(other.size.h)
1274            && other.loc.y <= self.loc.y.saturating_add(self.size.h)
1275    }
1276
1277    /// Clamp rectangle to min and max corners resulting in the overlapping area of two rectangles
1278    ///
1279    /// Returns `None` if the two rectangles don't overlap
1280    #[inline]
1281    pub fn intersection(self, other: impl Into<Rectangle<N, Kind>>) -> Option<Self> {
1282        let other = other.into();
1283        if !self.overlaps(other) {
1284            return None;
1285        }
1286        Some(Rectangle::from_extremities(
1287            (self.loc.x.max(other.loc.x), self.loc.y.max(other.loc.y)),
1288            (
1289                (self.loc.x.saturating_add(self.size.w)).min(other.loc.x.saturating_add(other.size.w)),
1290                (self.loc.y.saturating_add(self.size.h)).min(other.loc.y.saturating_add(other.size.h)),
1291            ),
1292        ))
1293    }
1294
1295    /// Compute the bounding box of a given set of points
1296    pub fn bounding_box(points: impl IntoIterator<Item = Point<N, Kind>>) -> Self {
1297        let ret = points.into_iter().fold(None, |acc, point| match acc {
1298            None => Some((point, point)),
1299            Some((min_point, max_point)) => Some((
1300                (point.x.min(min_point.x), point.y.min(min_point.y)).into(),
1301                (point.x.max(max_point.x), point.y.max(max_point.y)).into(),
1302            )),
1303        });
1304
1305        match ret {
1306            None => Rectangle::default(),
1307            Some((min_point, max_point)) => Rectangle::from_extremities(min_point, max_point),
1308        }
1309    }
1310
1311    /// Merge two [`Rectangle`] by producing the smallest rectangle that contains both
1312    #[inline]
1313    pub fn merge(self, other: Self) -> Self {
1314        Self::bounding_box([self.loc, self.loc + self.size, other.loc, other.loc + other.size])
1315    }
1316
1317    /// Subtract another [`Rectangle`] from this [`Rectangle`]
1318    ///
1319    /// If the rectangles to not overlap the original rectangle will
1320    /// be returned.
1321    /// If the other rectangle contains self no rectangle will be returned,
1322    /// otherwise up to 4 rectangles will be returned.
1323    pub fn subtract_rect(self, other: Self) -> Vec<Self> {
1324        self.subtract_rects([other])
1325    }
1326
1327    /// Subtract a set of [`Rectangle`]s from this [`Rectangle`]
1328    pub fn subtract_rects(self, others: impl IntoIterator<Item = Self>) -> Vec<Self> {
1329        let mut remaining = Vec::with_capacity(4);
1330        remaining.push(self);
1331        Self::subtract_rects_many_in_place(remaining, others)
1332    }
1333
1334    /// Subtract a set of [`Rectangle`]s from a set [`Rectangle`]s
1335    pub fn subtract_rects_many(
1336        rects: impl IntoIterator<Item = Self>,
1337        others: impl IntoIterator<Item = Self>,
1338    ) -> Vec<Self> {
1339        let remaining = rects.into_iter().collect::<Vec<_>>();
1340        Self::subtract_rects_many_in_place(remaining, others)
1341    }
1342
1343    /// Subtract a set of [`Rectangle`]s from a set [`Rectangle`]s in-place
1344    pub fn subtract_rects_many_in_place(
1345        mut rects: Vec<Self>,
1346        others: impl IntoIterator<Item = Self>,
1347    ) -> Vec<Self> {
1348        for other in others {
1349            let items = rects.len();
1350            let mut checked = 0usize;
1351            let mut index = 0usize;
1352
1353            // If there is nothing left we can stop,
1354            // we won't be able to subtract any further
1355            if items == 0 {
1356                return rects;
1357            }
1358
1359            while checked != items {
1360                checked += 1;
1361
1362                // If there is no overlap there is nothing to subtract
1363                let Some(intersection) = rects[index].intersection(other) else {
1364                    index += 1;
1365                    continue;
1366                };
1367
1368                // We now know that we have to subtract the other rect
1369                let item = rects.remove(index);
1370
1371                // If we are completely contained then nothing is left
1372                if other.contains_rect(item) {
1373                    continue;
1374                }
1375
1376                let top_rect = Rectangle::new(
1377                    item.loc,
1378                    (item.size.w, intersection.loc.y.saturating_sub(item.loc.y)).into(),
1379                );
1380                let left_rect: Rectangle<N, Kind> = Rectangle::new(
1381                    (item.loc.x, intersection.loc.y).into(),
1382                    (intersection.loc.x.saturating_sub(item.loc.x), intersection.size.h).into(),
1383                );
1384                let right_rect: Rectangle<N, Kind> = Rectangle::new(
1385                    (
1386                        intersection.loc.x.saturating_add(intersection.size.w),
1387                        intersection.loc.y,
1388                    )
1389                        .into(),
1390                    (
1391                        (item.loc.x.saturating_add(item.size.w))
1392                            .saturating_sub(intersection.loc.x.saturating_add(intersection.size.w)),
1393                        intersection.size.h,
1394                    )
1395                        .into(),
1396                );
1397                let bottom_rect: Rectangle<N, Kind> = Rectangle::new(
1398                    (item.loc.x, intersection.loc.y.saturating_add(intersection.size.h)).into(),
1399                    (
1400                        item.size.w,
1401                        (item.loc.y.saturating_add(item.size.h))
1402                            .saturating_sub(intersection.loc.y.saturating_add(intersection.size.h)),
1403                    )
1404                        .into(),
1405                );
1406
1407                if !top_rect.is_empty() {
1408                    rects.push(top_rect);
1409                }
1410
1411                if !left_rect.is_empty() {
1412                    rects.push(left_rect);
1413                }
1414
1415                if !right_rect.is_empty() {
1416                    rects.push(right_rect);
1417                }
1418
1419                if !bottom_rect.is_empty() {
1420                    rects.push(bottom_rect);
1421                }
1422            }
1423        }
1424
1425        rects
1426    }
1427}
1428
1429impl<N: Coordinate> Rectangle<N, Logical> {
1430    #[inline]
1431    #[cfg(feature = "xwayland")]
1432    pub(crate) fn to_client(self, scale: impl Into<Scale<N>>) -> Rectangle<N, Client> {
1433        let scale = scale.into();
1434        Rectangle {
1435            loc: self.loc.to_client(scale),
1436            size: self.size.to_client(scale),
1437        }
1438    }
1439
1440    #[inline]
1441    #[cfg(feature = "xwayland")]
1442    pub(crate) fn to_client_precise_round<S: Coordinate, R: Coordinate>(
1443        self,
1444        scale: impl Into<Scale<S>>,
1445    ) -> Rectangle<R, Client> {
1446        self.to_f64().to_client(scale.into().to_f64()).to_i32_round()
1447    }
1448
1449    /// Convert this logical rectangle to physical coordinate space according to given scale factor
1450    #[inline]
1451    pub fn to_physical(self, scale: impl Into<Scale<N>>) -> Rectangle<N, Physical> {
1452        let scale = scale.into();
1453        Rectangle {
1454            loc: self.loc.to_physical(scale),
1455            size: self.size.to_physical(scale),
1456        }
1457    }
1458
1459    /// Convert this logical rectangle to physical coordinate space according to given scale factor
1460    /// and round the result
1461    #[inline]
1462    pub fn to_physical_precise_round<S: Coordinate, R: Coordinate>(
1463        self,
1464        scale: impl Into<Scale<S>>,
1465    ) -> Rectangle<R, Physical> {
1466        self.to_f64().to_physical(scale.into().to_f64()).to_i32_round()
1467    }
1468
1469    /// Convert this logical rectangle to physical coordinate space according to given scale factor,
1470    /// returning the largest N-space rectangle fitting into the N-based rectangle
1471    ///
1472    /// This will ceil the location and floor the size after applying the scale
1473    #[inline]
1474    pub fn to_physical_precise_down<S: Coordinate, R: Coordinate>(
1475        &self,
1476        scale: impl Into<Scale<S>>,
1477    ) -> Rectangle<R, Physical> {
1478        self.to_f64().to_physical(scale.into().to_f64()).to_i32_down()
1479    }
1480
1481    /// Convert this logical rectangle to physical coordinate space according to given scale factor,
1482    /// returning the smallest N-space rectangle encapsulating the N-based rectangle
1483    ///
1484    /// This will floor the location and ceil the size after applying the scale
1485    #[inline]
1486    pub fn to_physical_precise_up<S: Coordinate, R: Coordinate>(
1487        &self,
1488        scale: impl Into<Scale<S>>,
1489    ) -> Rectangle<R, Physical> {
1490        self.to_f64().to_physical(scale.into().to_f64()).to_i32_up()
1491    }
1492
1493    /// Convert this logical rectangle to buffer coordinate space according to given scale factor
1494    #[inline]
1495    pub fn to_buffer(
1496        self,
1497        scale: impl Into<Scale<N>>,
1498        transformation: Transform,
1499        area: &Size<N, Logical>,
1500    ) -> Rectangle<N, Buffer> {
1501        let rect = transformation.transform_rect_in(self, area);
1502        let scale = scale.into();
1503        Rectangle {
1504            loc: Point {
1505                x: rect.loc.x.upscale(scale.x),
1506                y: rect.loc.y.upscale(scale.y),
1507                _kind: std::marker::PhantomData,
1508            },
1509            size: Size {
1510                w: rect.size.w.upscale(scale.x),
1511                h: rect.size.h.upscale(scale.y),
1512                _kind: std::marker::PhantomData,
1513            },
1514        }
1515    }
1516}
1517
1518#[cfg(feature = "wayland_frontend")]
1519impl<N: Coordinate> Rectangle<N, Client> {
1520    #[inline]
1521    pub(crate) fn to_logical(self, scale: impl Into<Scale<N>>) -> Rectangle<N, Logical> {
1522        let scale = scale.into();
1523        Rectangle {
1524            loc: self.loc.to_logical(scale),
1525            size: self.size.to_logical(scale),
1526        }
1527    }
1528}
1529
1530impl<N: Coordinate> Rectangle<N, Physical> {
1531    /// Convert this physical rectangle to logical coordinate space according to given scale factor
1532    #[inline]
1533    pub fn to_logical(self, scale: impl Into<Scale<N>>) -> Rectangle<N, Logical> {
1534        let scale = scale.into();
1535        Rectangle {
1536            loc: self.loc.to_logical(scale),
1537            size: self.size.to_logical(scale),
1538        }
1539    }
1540}
1541
1542impl<N: Coordinate> Rectangle<N, Buffer> {
1543    /// Convert this physical rectangle to logical coordinate space according to given scale factor
1544    #[inline]
1545    pub fn to_logical(
1546        self,
1547        scale: impl Into<Scale<N>>,
1548        transformation: Transform,
1549        area: &Size<N, Buffer>,
1550    ) -> Rectangle<N, Logical> {
1551        let rect = transformation.invert().transform_rect_in(self, area);
1552        let scale = scale.into();
1553        Rectangle {
1554            loc: Point {
1555                x: rect.loc.x.downscale(scale.x),
1556                y: rect.loc.y.downscale(scale.y),
1557                _kind: std::marker::PhantomData,
1558            },
1559            size: Size {
1560                w: rect.size.w.downscale(scale.x),
1561                h: rect.size.h.downscale(scale.y),
1562                _kind: std::marker::PhantomData,
1563            },
1564        }
1565    }
1566}
1567
1568impl<N: fmt::Debug, S> fmt::Debug for Rectangle<N, S> {
1569    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1570        f.write_fmt(format_args!("Rectangle<{}>", std::any::type_name::<S>()))?;
1571        f.debug_struct("")
1572            .field("x", &self.loc.x)
1573            .field("y", &self.loc.y)
1574            .field("width", &self.size.w)
1575            .field("height", &self.size.h)
1576            .finish()
1577    }
1578}
1579
1580impl<N: Clone, Kind> Clone for Rectangle<N, Kind> {
1581    #[inline]
1582    fn clone(&self) -> Self {
1583        Rectangle {
1584            loc: self.loc.clone(),
1585            size: self.size.clone(),
1586        }
1587    }
1588}
1589
1590impl<N: Copy, Kind> Copy for Rectangle<N, Kind> {}
1591
1592impl<N: PartialEq, Kind> PartialEq for Rectangle<N, Kind> {
1593    #[inline]
1594    fn eq(&self, other: &Self) -> bool {
1595        self.loc == other.loc && self.size == other.size
1596    }
1597}
1598
1599impl<N: Eq, Kind> Eq for Rectangle<N, Kind> {}
1600
1601impl<N: Default, Kind> Default for Rectangle<N, Kind> {
1602    #[inline]
1603    fn default() -> Self {
1604        Rectangle {
1605            loc: Default::default(),
1606            size: Default::default(),
1607        }
1608    }
1609}
1610
1611#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
1612/// Possible transformations to two-dimensional planes
1613#[derive(Default)]
1614pub enum Transform {
1615    /// Identity transformation (plane is unaltered when applied)
1616    #[default]
1617    Normal,
1618    /// Plane is rotated by 90 degrees
1619    _90,
1620    /// Plane is rotated by 180 degrees
1621    _180,
1622    /// Plane is rotated by 270 degrees
1623    _270,
1624    /// Plane is flipped vertically
1625    Flipped,
1626    /// Plane is flipped vertically and rotated by 90 degrees
1627    Flipped90,
1628    /// Plane is flipped vertically and rotated by 180 degrees
1629    Flipped180,
1630    /// Plane is flipped vertically and rotated by 270 degrees
1631    Flipped270,
1632}
1633
1634impl Transform {
1635    /// Inverts any 90-degree transformation into 270-degree transformations and vise versa.
1636    ///
1637    /// Flipping is preserved and 180/Normal transformation are uneffected.
1638    #[inline]
1639    pub fn invert(&self) -> Transform {
1640        match self {
1641            Transform::Normal => Transform::Normal,
1642            Transform::Flipped => Transform::Flipped,
1643            Transform::_90 => Transform::_270,
1644            Transform::_180 => Transform::_180,
1645            Transform::_270 => Transform::_90,
1646            Transform::Flipped90 => Transform::Flipped270,
1647            Transform::Flipped180 => Transform::Flipped180,
1648            Transform::Flipped270 => Transform::Flipped90,
1649        }
1650    }
1651
1652    /// Transforms a point inside an area of a given size by applying this transformation.
1653    pub fn transform_point_in<N: Coordinate, Kind>(
1654        &self,
1655        point: Point<N, Kind>,
1656        area: &Size<N, Kind>,
1657    ) -> Point<N, Kind> {
1658        match *self {
1659            Transform::Normal => point,
1660            Transform::_90 => (area.h - point.y, point.x).into(),
1661            Transform::_180 => (area.w - point.x, area.h - point.y).into(),
1662            Transform::_270 => (point.y, area.w - point.x).into(),
1663            Transform::Flipped => (area.w - point.x, point.y).into(),
1664            Transform::Flipped90 => (point.y, point.x).into(),
1665            Transform::Flipped180 => (point.x, area.h - point.y).into(),
1666            Transform::Flipped270 => (area.h - point.y, area.w - point.x).into(),
1667        }
1668    }
1669
1670    /// Transformed size after applying this transformation.
1671    pub fn transform_size<N: Coordinate, Kind>(&self, size: Size<N, Kind>) -> Size<N, Kind> {
1672        if *self == Transform::_90
1673            || *self == Transform::_270
1674            || *self == Transform::Flipped90
1675            || *self == Transform::Flipped270
1676        {
1677            (size.h, size.w).into()
1678        } else {
1679            size
1680        }
1681    }
1682
1683    /// Transforms a rectangle inside an area of a given size by applying this transformation.
1684    pub fn transform_rect_in<N: Coordinate, Kind>(
1685        &self,
1686        rect: Rectangle<N, Kind>,
1687        area: &Size<N, Kind>,
1688    ) -> Rectangle<N, Kind> {
1689        let size = self.transform_size(rect.size);
1690
1691        let loc = match *self {
1692            Transform::Normal => rect.loc,
1693            Transform::_90 => (area.h - rect.loc.y - rect.size.h, rect.loc.x).into(),
1694            Transform::_180 => (
1695                area.w - rect.loc.x - rect.size.w,
1696                area.h - rect.loc.y - rect.size.h,
1697            )
1698                .into(),
1699            Transform::_270 => (rect.loc.y, area.w - rect.loc.x - rect.size.w).into(),
1700            Transform::Flipped => (area.w - rect.loc.x - rect.size.w, rect.loc.y).into(),
1701            Transform::Flipped90 => (
1702                area.h - rect.loc.y - rect.size.h,
1703                area.w - rect.loc.x - rect.size.w,
1704            )
1705                .into(),
1706            Transform::Flipped180 => (rect.loc.x, area.h - rect.loc.y - rect.size.h).into(),
1707            Transform::Flipped270 => (rect.loc.y, rect.loc.x).into(),
1708        };
1709
1710        Rectangle::new(loc, size)
1711    }
1712
1713    /// Returns true if the transformation would flip contents
1714    pub fn flipped(&self) -> bool {
1715        !matches!(
1716            self,
1717            Transform::Normal | Transform::_90 | Transform::_180 | Transform::_270
1718        )
1719    }
1720
1721    /// Returns the angle (in degrees) of the transformation
1722    #[inline]
1723    pub fn degrees(&self) -> u32 {
1724        match self {
1725            Transform::Normal | Transform::Flipped => 0,
1726            Transform::_90 | Transform::Flipped90 => 90,
1727            Transform::_180 | Transform::Flipped180 => 180,
1728            Transform::_270 | Transform::Flipped270 => 270,
1729        }
1730    }
1731}
1732
1733impl std::ops::Add for Transform {
1734    type Output = Self;
1735
1736    #[inline]
1737    fn add(self, other: Self) -> Self {
1738        let flipped = matches!((self.flipped(), other.flipped()), (true, false) | (false, true));
1739        let degrees = (self.degrees() + other.degrees()) % 360;
1740        match (flipped, degrees) {
1741            (false, 0) => Transform::Normal,
1742            (false, 90) => Transform::_90,
1743            (false, 180) => Transform::_180,
1744            (false, 270) => Transform::_270,
1745            (true, 0) => Transform::Flipped,
1746            (true, 90) => Transform::Flipped90,
1747            (true, 180) => Transform::Flipped180,
1748            (true, 270) => Transform::Flipped270,
1749            _ => unreachable!(),
1750        }
1751    }
1752}
1753
1754#[cfg(feature = "wayland_frontend")]
1755impl From<Transform> for WlTransform {
1756    #[inline]
1757    fn from(transform: Transform) -> Self {
1758        match transform {
1759            Transform::Normal => WlTransform::Normal,
1760            Transform::_90 => WlTransform::_90,
1761            Transform::_180 => WlTransform::_180,
1762            Transform::_270 => WlTransform::_270,
1763            Transform::Flipped => WlTransform::Flipped,
1764            Transform::Flipped90 => WlTransform::Flipped90,
1765            Transform::Flipped180 => WlTransform::Flipped180,
1766            Transform::Flipped270 => WlTransform::Flipped270,
1767        }
1768    }
1769}
1770
1771#[cfg(test)]
1772mod tests {
1773    use super::{Logical, Rectangle, Size, Transform};
1774
1775    #[test]
1776    fn transform_rect_ident() {
1777        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1778        let size = Size::from((70, 90));
1779        let transform = Transform::Normal;
1780
1781        assert_eq!(rect, transform.transform_rect_in(rect, &size))
1782    }
1783
1784    #[test]
1785    fn transform_rect_90() {
1786        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1787        let size = Size::from((70, 90));
1788        let transform = Transform::_90;
1789
1790        assert_eq!(
1791            Rectangle::new((30, 10).into(), (40, 30).into()),
1792            transform.transform_rect_in(rect, &size)
1793        )
1794    }
1795
1796    #[test]
1797    fn transform_rect_180() {
1798        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1799        let size = Size::from((70, 90));
1800        let transform = Transform::_180;
1801
1802        assert_eq!(
1803            Rectangle::new((30, 30).into(), (30, 40).into()),
1804            transform.transform_rect_in(rect, &size)
1805        )
1806    }
1807
1808    #[test]
1809    fn transform_rect_270() {
1810        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1811        let size = Size::from((70, 90));
1812        let transform = Transform::_270;
1813
1814        assert_eq!(
1815            Rectangle::new((20, 30).into(), (40, 30).into()),
1816            transform.transform_rect_in(rect, &size)
1817        )
1818    }
1819
1820    #[test]
1821    fn transform_rect_f() {
1822        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1823        let size = Size::from((70, 90));
1824        let transform = Transform::Flipped;
1825
1826        assert_eq!(
1827            Rectangle::new((30, 20).into(), (30, 40).into()),
1828            transform.transform_rect_in(rect, &size)
1829        )
1830    }
1831
1832    #[test]
1833    fn transform_rect_f90() {
1834        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1835        let size = Size::from((70, 80));
1836        let transform = Transform::Flipped90;
1837
1838        assert_eq!(
1839            Rectangle::new((20, 30).into(), (40, 30).into()),
1840            transform.transform_rect_in(rect, &size)
1841        )
1842    }
1843
1844    #[test]
1845    fn transform_rect_f180() {
1846        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1847        let size = Size::from((70, 90));
1848        let transform = Transform::Flipped180;
1849
1850        assert_eq!(
1851            Rectangle::new((10, 30).into(), (30, 40).into()),
1852            transform.transform_rect_in(rect, &size)
1853        )
1854    }
1855
1856    #[test]
1857    fn transform_rect_f270() {
1858        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1859        let size = Size::from((70, 90));
1860        let transform = Transform::Flipped270;
1861
1862        assert_eq!(
1863            Rectangle::new((20, 10).into(), (40, 30).into()),
1864            transform.transform_rect_in(rect, &size)
1865        )
1866    }
1867
1868    #[test]
1869    fn rectangle_contains_rect_itself() {
1870        let rect = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1871        assert!(rect.contains_rect(rect));
1872    }
1873
1874    #[test]
1875    fn rectangle_contains_rect_outside() {
1876        let first = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1877        let second = Rectangle::<i32, Logical>::new((41, 61).into(), (30, 40).into());
1878        assert!(!first.contains_rect(second));
1879    }
1880
1881    #[test]
1882    fn rectangle_contains_rect_extends() {
1883        let first = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 40).into());
1884        let second = Rectangle::<i32, Logical>::new((10, 20).into(), (30, 45).into());
1885        assert!(!first.contains_rect(second));
1886    }
1887
1888    #[test]
1889    fn rectangle_subtract_full() {
1890        let outer = Rectangle::<i32, Logical>::from_size((100, 100).into());
1891        let inner = Rectangle::<i32, Logical>::new((-10, -10).into(), (1000, 1000).into());
1892
1893        let rects = outer.subtract_rect(inner);
1894        assert_eq!(rects, vec![])
1895    }
1896
1897    #[test]
1898    fn rectangle_subtract_center_hole() {
1899        let outer = Rectangle::<i32, Logical>::from_size((100, 100).into());
1900        let inner = Rectangle::<i32, Logical>::new((10, 10).into(), (80, 80).into());
1901
1902        let rects = outer.subtract_rect(inner);
1903        assert_eq!(
1904            rects,
1905            vec![
1906                // Top rect
1907                Rectangle::<i32, Logical>::from_size((100, 10).into()),
1908                // Left rect
1909                Rectangle::<i32, Logical>::new((0, 10).into(), (10, 80).into()),
1910                // Right rect
1911                Rectangle::<i32, Logical>::new((90, 10).into(), (10, 80).into()),
1912                // Bottom rect
1913                Rectangle::<i32, Logical>::new((0, 90).into(), (100, 10).into()),
1914            ]
1915        )
1916    }
1917
1918    #[test]
1919    fn rectangle_subtract_full_top() {
1920        let outer = Rectangle::<i32, Logical>::from_size((100, 100).into());
1921        let inner = Rectangle::<i32, Logical>::new((0, -20).into(), (100, 100).into());
1922
1923        let rects = outer.subtract_rect(inner);
1924        assert_eq!(
1925            rects,
1926            vec![
1927                // Bottom rect
1928                Rectangle::<i32, Logical>::new((0, 80).into(), (100, 20).into()),
1929            ]
1930        )
1931    }
1932
1933    #[test]
1934    fn rectangle_subtract_full_bottom() {
1935        let outer = Rectangle::<i32, Logical>::from_size((100, 100).into());
1936        let inner = Rectangle::<i32, Logical>::new((0, 20).into(), (100, 100).into());
1937
1938        let rects = outer.subtract_rect(inner);
1939        assert_eq!(
1940            rects,
1941            vec![
1942                // Top rect
1943                Rectangle::<i32, Logical>::from_size((100, 20).into()),
1944            ]
1945        )
1946    }
1947
1948    #[test]
1949    fn rectangle_subtract_full_left() {
1950        let outer = Rectangle::<i32, Logical>::from_size((100, 100).into());
1951        let inner = Rectangle::<i32, Logical>::new((-20, 0).into(), (100, 100).into());
1952
1953        let rects = outer.subtract_rect(inner);
1954        assert_eq!(
1955            rects,
1956            vec![
1957                // Right rect
1958                Rectangle::<i32, Logical>::new((80, 0).into(), (20, 100).into()),
1959            ]
1960        )
1961    }
1962
1963    #[test]
1964    fn rectangle_subtract_full_right() {
1965        let outer = Rectangle::<i32, Logical>::from_size((100, 100).into());
1966        let inner = Rectangle::<i32, Logical>::new((20, 0).into(), (100, 100).into());
1967
1968        let rects = outer.subtract_rect(inner);
1969        assert_eq!(
1970            rects,
1971            vec![
1972                // Left rect
1973                Rectangle::<i32, Logical>::from_size((20, 100).into()),
1974            ]
1975        )
1976    }
1977
1978    #[test]
1979    fn rectangle_overlaps_or_touches_top() {
1980        let top = Rectangle::<i32, Logical>::new((0, -24).into(), (800, 24).into());
1981        let main = Rectangle::<i32, Logical>::from_size((800, 600).into());
1982        assert!(main.overlaps_or_touches(top));
1983    }
1984
1985    #[test]
1986    fn rectangle_overlaps_or_touches_left() {
1987        let left = Rectangle::<i32, Logical>::new((-4, -24).into(), (4, 624).into());
1988        let main = Rectangle::<i32, Logical>::from_size((800, 600).into());
1989        assert!(main.overlaps_or_touches(left));
1990    }
1991
1992    #[test]
1993    fn rectangle_overlaps_or_touches_right() {
1994        let right = Rectangle::<i32, Logical>::new((800, -24).into(), (4, 624).into());
1995        let main = Rectangle::<i32, Logical>::from_size((800, 600).into());
1996        assert!(main.overlaps_or_touches(right));
1997    }
1998
1999    #[test]
2000    fn rectangle_no_overlap_top() {
2001        let top = Rectangle::<i32, Logical>::new((0, -24).into(), (800, 24).into());
2002        let main = Rectangle::<i32, Logical>::from_size((800, 600).into());
2003        assert!(!main.overlaps(top));
2004    }
2005
2006    #[test]
2007    fn rectangle_no_overlap_left() {
2008        let left = Rectangle::<i32, Logical>::new((-4, -24).into(), (4, 624).into());
2009        let main = Rectangle::<i32, Logical>::from_size((800, 600).into());
2010        assert!(!main.overlaps(left));
2011    }
2012
2013    #[test]
2014    fn rectangle_no_overlap_right() {
2015        let right = Rectangle::<i32, Logical>::new((800, -24).into(), (4, 624).into());
2016        let main = Rectangle::<i32, Logical>::from_size((800, 600).into());
2017        assert!(!main.overlaps(right));
2018    }
2019
2020    #[test]
2021    fn size_sub_saturate_zero() {
2022        let bigger = Size::<_, Logical>::from((10, 10));
2023        let mut smaller = Size::<_, Logical>::from((5, 5));
2024
2025        assert_eq!(smaller - bigger, Size::from((0, 0)));
2026        smaller -= bigger;
2027        assert_eq!(smaller, Size::from((0, 0)));
2028    }
2029}