epaint/
corner_radius.rs

1/// How rounded the corners of things should be.
2///
3/// This specific the _corner radius_ of the underlying geometric shape (e.g. rectangle).
4/// If there is a stroke, then the stroke will have an inner and outer corner radius
5/// which will depends on its width and [`crate::StrokeKind`].
6///
7/// The rounding uses `u8` to save space,
8/// so the amount of rounding is limited to integers in the range `[0, 255]`.
9///
10/// For calculations, you may want to use [`crate::CornerRadiusF32`] instead, which uses `f32`.
11#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
13pub struct CornerRadius {
14    /// Radius of the rounding of the North-West (left top) corner.
15    pub nw: u8,
16
17    /// Radius of the rounding of the North-East (right top) corner.
18    pub ne: u8,
19
20    /// Radius of the rounding of the South-West (left bottom) corner.
21    pub sw: u8,
22
23    /// Radius of the rounding of the South-East (right bottom) corner.
24    pub se: u8,
25}
26
27impl Default for CornerRadius {
28    #[inline]
29    fn default() -> Self {
30        Self::ZERO
31    }
32}
33
34impl From<u8> for CornerRadius {
35    #[inline]
36    fn from(radius: u8) -> Self {
37        Self::same(radius)
38    }
39}
40
41impl From<f32> for CornerRadius {
42    #[inline]
43    fn from(radius: f32) -> Self {
44        Self::same(radius.round() as u8)
45    }
46}
47
48impl CornerRadius {
49    /// No rounding on any corner.
50    pub const ZERO: Self = Self {
51        nw: 0,
52        ne: 0,
53        sw: 0,
54        se: 0,
55    };
56
57    /// Same rounding on all four corners.
58    #[inline]
59    pub const fn same(radius: u8) -> Self {
60        Self {
61            nw: radius,
62            ne: radius,
63            sw: radius,
64            se: radius,
65        }
66    }
67
68    /// Do all corners have the same rounding?
69    #[inline]
70    pub fn is_same(self) -> bool {
71        self.nw == self.ne && self.nw == self.sw && self.nw == self.se
72    }
73
74    /// Make sure each corner has a rounding of at least this.
75    #[inline]
76    pub fn at_least(self, min: u8) -> Self {
77        Self {
78            nw: self.nw.max(min),
79            ne: self.ne.max(min),
80            sw: self.sw.max(min),
81            se: self.se.max(min),
82        }
83    }
84
85    /// Make sure each corner has a rounding of at most this.
86    #[inline]
87    pub fn at_most(self, max: u8) -> Self {
88        Self {
89            nw: self.nw.min(max),
90            ne: self.ne.min(max),
91            sw: self.sw.min(max),
92            se: self.se.min(max),
93        }
94    }
95
96    /// Average rounding of the corners.
97    pub fn average(&self) -> f32 {
98        (self.nw as f32 + self.ne as f32 + self.sw as f32 + self.se as f32) / 4.0
99    }
100}
101
102impl std::ops::Add for CornerRadius {
103    type Output = Self;
104    #[inline]
105    fn add(self, rhs: Self) -> Self {
106        Self {
107            nw: self.nw.saturating_add(rhs.nw),
108            ne: self.ne.saturating_add(rhs.ne),
109            sw: self.sw.saturating_add(rhs.sw),
110            se: self.se.saturating_add(rhs.se),
111        }
112    }
113}
114
115impl std::ops::Add<u8> for CornerRadius {
116    type Output = Self;
117    #[inline]
118    fn add(self, rhs: u8) -> Self {
119        Self {
120            nw: self.nw.saturating_add(rhs),
121            ne: self.ne.saturating_add(rhs),
122            sw: self.sw.saturating_add(rhs),
123            se: self.se.saturating_add(rhs),
124        }
125    }
126}
127
128impl std::ops::AddAssign for CornerRadius {
129    #[inline]
130    fn add_assign(&mut self, rhs: Self) {
131        *self = Self {
132            nw: self.nw.saturating_add(rhs.nw),
133            ne: self.ne.saturating_add(rhs.ne),
134            sw: self.sw.saturating_add(rhs.sw),
135            se: self.se.saturating_add(rhs.se),
136        };
137    }
138}
139
140impl std::ops::AddAssign<u8> for CornerRadius {
141    #[inline]
142    fn add_assign(&mut self, rhs: u8) {
143        *self = Self {
144            nw: self.nw.saturating_add(rhs),
145            ne: self.ne.saturating_add(rhs),
146            sw: self.sw.saturating_add(rhs),
147            se: self.se.saturating_add(rhs),
148        };
149    }
150}
151
152impl std::ops::Sub for CornerRadius {
153    type Output = Self;
154    #[inline]
155    fn sub(self, rhs: Self) -> Self {
156        Self {
157            nw: self.nw.saturating_sub(rhs.nw),
158            ne: self.ne.saturating_sub(rhs.ne),
159            sw: self.sw.saturating_sub(rhs.sw),
160            se: self.se.saturating_sub(rhs.se),
161        }
162    }
163}
164
165impl std::ops::Sub<u8> for CornerRadius {
166    type Output = Self;
167    #[inline]
168    fn sub(self, rhs: u8) -> Self {
169        Self {
170            nw: self.nw.saturating_sub(rhs),
171            ne: self.ne.saturating_sub(rhs),
172            sw: self.sw.saturating_sub(rhs),
173            se: self.se.saturating_sub(rhs),
174        }
175    }
176}
177
178impl std::ops::SubAssign for CornerRadius {
179    #[inline]
180    fn sub_assign(&mut self, rhs: Self) {
181        *self = Self {
182            nw: self.nw.saturating_sub(rhs.nw),
183            ne: self.ne.saturating_sub(rhs.ne),
184            sw: self.sw.saturating_sub(rhs.sw),
185            se: self.se.saturating_sub(rhs.se),
186        };
187    }
188}
189
190impl std::ops::SubAssign<u8> for CornerRadius {
191    #[inline]
192    fn sub_assign(&mut self, rhs: u8) {
193        *self = Self {
194            nw: self.nw.saturating_sub(rhs),
195            ne: self.ne.saturating_sub(rhs),
196            sw: self.sw.saturating_sub(rhs),
197            se: self.se.saturating_sub(rhs),
198        };
199    }
200}
201
202impl std::ops::Div<f32> for CornerRadius {
203    type Output = Self;
204    #[inline]
205    fn div(self, rhs: f32) -> Self {
206        Self {
207            nw: (self.nw as f32 / rhs) as u8,
208            ne: (self.ne as f32 / rhs) as u8,
209            sw: (self.sw as f32 / rhs) as u8,
210            se: (self.se as f32 / rhs) as u8,
211        }
212    }
213}
214
215impl std::ops::DivAssign<f32> for CornerRadius {
216    #[inline]
217    fn div_assign(&mut self, rhs: f32) {
218        *self = Self {
219            nw: (self.nw as f32 / rhs) as u8,
220            ne: (self.ne as f32 / rhs) as u8,
221            sw: (self.sw as f32 / rhs) as u8,
222            se: (self.se as f32 / rhs) as u8,
223        };
224    }
225}
226
227impl std::ops::Mul<f32> for CornerRadius {
228    type Output = Self;
229    #[inline]
230    fn mul(self, rhs: f32) -> Self {
231        Self {
232            nw: (self.nw as f32 * rhs) as u8,
233            ne: (self.ne as f32 * rhs) as u8,
234            sw: (self.sw as f32 * rhs) as u8,
235            se: (self.se as f32 * rhs) as u8,
236        }
237    }
238}
239
240impl std::ops::MulAssign<f32> for CornerRadius {
241    #[inline]
242    fn mul_assign(&mut self, rhs: f32) {
243        *self = Self {
244            nw: (self.nw as f32 * rhs) as u8,
245            ne: (self.ne as f32 * rhs) as u8,
246            sw: (self.sw as f32 * rhs) as u8,
247            se: (self.se as f32 * rhs) as u8,
248        };
249    }
250}