1use emath::{Rect, Vec2, vec2};
2
3#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
15pub struct Margin {
16 pub left: i8,
17 pub right: i8,
18 pub top: i8,
19 pub bottom: i8,
20}
21
22impl Margin {
23 pub const ZERO: Self = Self {
24 left: 0,
25 right: 0,
26 top: 0,
27 bottom: 0,
28 };
29
30 #[doc(alias = "symmetric")]
32 #[inline]
33 pub const fn same(margin: i8) -> Self {
34 Self {
35 left: margin,
36 right: margin,
37 top: margin,
38 bottom: margin,
39 }
40 }
41
42 #[inline]
44 pub const fn symmetric(x: i8, y: i8) -> Self {
45 Self {
46 left: x,
47 right: x,
48 top: y,
49 bottom: y,
50 }
51 }
52
53 #[inline]
55 pub const fn leftf(self) -> f32 {
56 self.left as _
57 }
58
59 #[inline]
61 pub const fn rightf(self) -> f32 {
62 self.right as _
63 }
64
65 #[inline]
67 pub const fn topf(self) -> f32 {
68 self.top as _
69 }
70
71 #[inline]
73 pub const fn bottomf(self) -> f32 {
74 self.bottom as _
75 }
76
77 #[inline]
79 pub fn sum(self) -> Vec2 {
80 vec2(self.leftf() + self.rightf(), self.topf() + self.bottomf())
81 }
82
83 #[inline]
84 pub const fn left_top(self) -> Vec2 {
85 vec2(self.leftf(), self.topf())
86 }
87
88 #[inline]
89 pub const fn right_bottom(self) -> Vec2 {
90 vec2(self.rightf(), self.bottomf())
91 }
92
93 #[doc(alias = "symmetric")]
95 #[inline]
96 pub const fn is_same(self) -> bool {
97 self.left == self.right && self.left == self.top && self.left == self.bottom
98 }
99}
100
101impl From<i8> for Margin {
102 #[inline]
103 fn from(v: i8) -> Self {
104 Self::same(v)
105 }
106}
107
108impl From<f32> for Margin {
109 #[inline]
110 fn from(v: f32) -> Self {
111 Self::same(v.round() as _)
112 }
113}
114
115impl From<Vec2> for Margin {
116 #[inline]
117 fn from(v: Vec2) -> Self {
118 Self::symmetric(v.x.round() as _, v.y.round() as _)
119 }
120}
121
122impl std::ops::Add for Margin {
124 type Output = Self;
125
126 #[inline]
127 fn add(self, other: Self) -> Self {
128 Self {
129 left: self.left.saturating_add(other.left),
130 right: self.right.saturating_add(other.right),
131 top: self.top.saturating_add(other.top),
132 bottom: self.bottom.saturating_add(other.bottom),
133 }
134 }
135}
136
137impl std::ops::Add<i8> for Margin {
139 type Output = Self;
140
141 #[inline]
142 fn add(self, v: i8) -> Self {
143 Self {
144 left: self.left.saturating_add(v),
145 right: self.right.saturating_add(v),
146 top: self.top.saturating_add(v),
147 bottom: self.bottom.saturating_add(v),
148 }
149 }
150}
151
152impl std::ops::AddAssign<i8> for Margin {
154 #[inline]
155 fn add_assign(&mut self, v: i8) {
156 *self = *self + v;
157 }
158}
159
160impl std::ops::Mul<f32> for Margin {
162 type Output = Self;
163
164 #[inline]
165 fn mul(self, v: f32) -> Self {
166 Self {
167 left: (self.leftf() * v).round() as _,
168 right: (self.rightf() * v).round() as _,
169 top: (self.topf() * v).round() as _,
170 bottom: (self.bottomf() * v).round() as _,
171 }
172 }
173}
174
175impl std::ops::MulAssign<f32> for Margin {
177 #[inline]
178 fn mul_assign(&mut self, v: f32) {
179 *self = *self * v;
180 }
181}
182
183impl std::ops::Div<f32> for Margin {
185 type Output = Self;
186
187 #[inline]
188 fn div(self, v: f32) -> Self {
189 #![allow(clippy::suspicious_arithmetic_impl)]
190 self * v.recip()
191 }
192}
193
194impl std::ops::DivAssign<f32> for Margin {
196 #[inline]
197 fn div_assign(&mut self, v: f32) {
198 *self = *self / v;
199 }
200}
201
202impl std::ops::Sub for Margin {
204 type Output = Self;
205
206 #[inline]
207 fn sub(self, other: Self) -> Self {
208 Self {
209 left: self.left.saturating_sub(other.left),
210 right: self.right.saturating_sub(other.right),
211 top: self.top.saturating_sub(other.top),
212 bottom: self.bottom.saturating_sub(other.bottom),
213 }
214 }
215}
216
217impl std::ops::Sub<i8> for Margin {
219 type Output = Self;
220
221 #[inline]
222 fn sub(self, v: i8) -> Self {
223 Self {
224 left: self.left.saturating_sub(v),
225 right: self.right.saturating_sub(v),
226 top: self.top.saturating_sub(v),
227 bottom: self.bottom.saturating_sub(v),
228 }
229 }
230}
231
232impl std::ops::SubAssign<i8> for Margin {
234 #[inline]
235 fn sub_assign(&mut self, v: i8) {
236 *self = *self - v;
237 }
238}
239
240impl std::ops::Add<Margin> for Rect {
242 type Output = Self;
243
244 #[inline]
245 fn add(self, margin: Margin) -> Self {
246 Self::from_min_max(
247 self.min - margin.left_top(),
248 self.max + margin.right_bottom(),
249 )
250 }
251}
252
253impl std::ops::AddAssign<Margin> for Rect {
255 #[inline]
256 fn add_assign(&mut self, margin: Margin) {
257 *self = *self + margin;
258 }
259}
260
261impl std::ops::Sub<Margin> for Rect {
263 type Output = Self;
264
265 #[inline]
266 fn sub(self, margin: Margin) -> Self {
267 Self::from_min_max(
268 self.min + margin.left_top(),
269 self.max - margin.right_bottom(),
270 )
271 }
272}
273
274impl std::ops::SubAssign<Margin> for Rect {
276 #[inline]
277 fn sub_assign(&mut self, margin: Margin) {
278 *self = *self - margin;
279 }
280}