Skip to main content

apple_cf/cg/
rect.rs

1//! `CGRect` type for 2D rectangles
2
3use std::fmt;
4
5use super::{CGPoint, CGSize};
6
7/// `CGRect` representation
8///
9/// Represents a rectangle with origin (x, y) and dimensions (width, height).
10///
11/// # Examples
12///
13/// ```
14/// use apple_cf::cg::CGRect;
15///
16/// let rect = CGRect::new(10.0, 20.0, 100.0, 200.0);
17/// assert_eq!(rect.x, 10.0);
18/// assert_eq!(rect.width, 100.0);
19/// assert_eq!(rect.max_x(), 110.0);
20/// ```
21#[repr(C)]
22#[derive(Debug, Clone, Copy, PartialEq)]
23pub struct CGRect {
24    pub x: f64,
25    pub y: f64,
26    pub width: f64,
27    pub height: f64,
28}
29
30impl std::hash::Hash for CGRect {
31    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
32        self.x.to_bits().hash(state);
33        self.y.to_bits().hash(state);
34        self.width.to_bits().hash(state);
35        self.height.to_bits().hash(state);
36    }
37}
38
39impl Eq for CGRect {}
40
41impl CGRect {
42    /// Create a new rectangle
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use apple_cf::cg::CGRect;
48    ///
49    /// let rect = CGRect::new(0.0, 0.0, 1920.0, 1080.0);
50    /// assert_eq!(rect.width, 1920.0);
51    /// ```
52    #[must_use] 
53    pub const fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
54        Self {
55            x,
56            y,
57            width,
58            height,
59        }
60    }
61
62    /// Create a zero-sized rectangle at origin
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use apple_cf::cg::CGRect;
68    ///
69    /// let rect = CGRect::zero();
70    /// assert!(rect.is_null());
71    /// ```
72    #[must_use] 
73    pub const fn zero() -> Self {
74        Self::new(0.0, 0.0, 0.0, 0.0)
75    }
76
77    /// Create a rect with origin and size
78    #[must_use] 
79    pub const fn with_origin_and_size(origin: CGPoint, size: CGSize) -> Self {
80        Self {
81            x: origin.x,
82            y: origin.y,
83            width: size.width,
84            height: size.height,
85        }
86    }
87
88    /// Get the origin point
89    #[must_use] 
90    pub const fn origin(&self) -> CGPoint {
91        CGPoint::new(self.x, self.y)
92    }
93
94    /// Get the size
95    #[must_use] 
96    pub const fn size(&self) -> CGSize {
97        CGSize::new(self.width, self.height)
98    }
99
100    /// Get the center point
101    #[must_use] 
102    pub const fn center(&self) -> CGPoint {
103        CGPoint::new(self.x + self.width / 2.0, self.y + self.height / 2.0)
104    }
105
106    /// Get the minimum X coordinate
107    #[must_use] 
108    pub const fn min_x(&self) -> f64 {
109        self.x
110    }
111
112    /// Get the minimum Y coordinate
113    #[must_use] 
114    pub const fn min_y(&self) -> f64 {
115        self.y
116    }
117
118    /// Get the maximum X coordinate
119    #[must_use] 
120    pub const fn max_x(&self) -> f64 {
121        self.x + self.width
122    }
123
124    /// Get the maximum Y coordinate
125    #[must_use] 
126    pub const fn max_y(&self) -> f64 {
127        self.y + self.height
128    }
129
130    /// Get the mid X coordinate
131    #[must_use] 
132    pub const fn mid_x(&self) -> f64 {
133        self.x + self.width / 2.0
134    }
135
136    /// Get the mid Y coordinate
137    #[must_use] 
138    pub const fn mid_y(&self) -> f64 {
139        self.y + self.height / 2.0
140    }
141
142    #[must_use] 
143    pub fn is_empty(&self) -> bool {
144        self.width <= 0.0 || self.height <= 0.0
145    }
146
147    /// Check if rect is null (both position and size are zero)
148    #[must_use] 
149    pub const fn is_null(&self) -> bool {
150        self.x == 0.0 && self.y == 0.0 && self.width == 0.0 && self.height == 0.0
151    }
152}
153
154impl Default for CGRect {
155    fn default() -> Self {
156        Self::zero()
157    }
158}
159
160impl fmt::Display for CGRect {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        write!(
163            f,
164            "({}, {}, {}, {})",
165            self.x, self.y, self.width, self.height
166        )
167    }
168}