1#![allow(clippy::module_name_repetitions)]
3use leftwm_layouts::geometry::Rect;
4use serde::{Deserialize, Serialize};
5use std::cmp;
6use std::ops::Add;
7use std::ops::Sub;
8
9#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Copy)]
11pub struct Xyhw {
12 x: i32,
13 y: i32,
14 h: i32,
15 w: i32,
16 minw: i32,
17 maxw: i32,
18 minh: i32,
19 maxh: i32,
20}
21
22#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Copy)]
25pub struct XyhwBuilder {
26 pub x: i32,
27 pub y: i32,
28 pub h: i32,
29 pub w: i32,
30 pub minw: i32,
31 pub maxw: i32,
32 pub minh: i32,
33 pub maxh: i32,
34}
35
36impl Default for XyhwBuilder {
37 fn default() -> Self {
38 Self {
39 x: 0,
40 y: 0,
41 w: 0,
42 h: 0,
43 minw: -999_999_999,
44 maxw: 999_999_999,
45 minh: -999_999_999,
46 maxh: 999_999_999,
47 }
48 }
49}
50
51impl Default for Xyhw {
52 fn default() -> Self {
53 Self {
54 x: 0,
55 y: 0,
56 w: 0,
57 h: 0,
58 minw: -999_999_999,
59 maxw: 999_999_999,
60 minh: -999_999_999,
61 maxh: 999_999_999,
62 }
63 }
64}
65
66impl Add for Xyhw {
67 type Output = Self;
68 fn add(self, other: Self) -> Self {
69 Self {
70 x: self.x + other.x,
71 y: self.y + other.y,
72 w: self.w + other.w,
73 h: self.h + other.h,
74 minw: cmp::max(self.minw, other.minw),
75 maxw: cmp::min(self.maxw, other.maxw),
76 minh: cmp::max(self.minh, other.minh),
77 maxh: cmp::min(self.maxh, other.maxh),
78 }
79 }
80}
81
82impl Sub for Xyhw {
83 type Output = Self;
84 fn sub(self, other: Self) -> Self {
85 Self {
86 x: self.x - other.x,
87 y: self.y - other.y,
88 w: self.w - other.w,
89 h: self.h - other.h,
90 minw: cmp::max(self.minw, other.minw),
91 maxw: cmp::min(self.maxw, other.maxw),
92 minh: cmp::max(self.minh, other.minh),
93 maxh: cmp::min(self.maxh, other.maxh),
94 }
95 }
96}
97
98impl From<XyhwBuilder> for Xyhw {
99 fn from(xywh: XyhwBuilder) -> Self {
100 let mut b = Self {
101 x: xywh.x,
102 y: xywh.y,
103 w: xywh.w,
104 h: xywh.h,
105 minw: xywh.minw,
106 maxw: xywh.maxw,
107 minh: xywh.minh,
108 maxh: xywh.maxh,
109 };
110 b.update_limits();
111 b
112 }
113}
114
115impl From<Rect> for Xyhw {
116 fn from(rect: Rect) -> Self {
117 Self {
118 x: rect.x,
119 y: rect.y,
120 w: rect.w as i32,
121 h: rect.h as i32,
122 ..Default::default()
123 }
124 }
125}
126
127impl From<Xyhw> for Rect {
128 fn from(xyhw: Xyhw) -> Self {
129 Rect {
130 x: xyhw.x,
131 y: xyhw.y,
132 w: xyhw.w.unsigned_abs(),
133 h: xyhw.h.unsigned_abs(),
134 }
135 }
136}
137
138impl Xyhw {
139 #[must_use]
140 pub const fn x(&self) -> i32 {
141 self.x
142 }
143 #[must_use]
144 pub const fn y(&self) -> i32 {
145 self.y
146 }
147 #[must_use]
148 pub const fn h(&self) -> i32 {
149 self.h
150 }
151 #[must_use]
152 pub const fn w(&self) -> i32 {
153 self.w
154 }
155
156 #[must_use]
157 pub const fn minw(&self) -> i32 {
158 self.minw
159 }
160 #[must_use]
161 pub const fn maxw(&self) -> i32 {
162 self.maxw
163 }
164 #[must_use]
165 pub const fn minh(&self) -> i32 {
166 self.minh
167 }
168 #[must_use]
169 pub const fn maxh(&self) -> i32 {
170 self.maxh
171 }
172
173 pub fn clear_minmax(&mut self) {
174 self.minw = -999_999_999;
175 self.maxw = 999_999_999;
176 self.minh = -999_999_999;
177 self.maxh = 999_999_999;
178 self.update_limits();
179 }
180
181 pub fn set_x(&mut self, value: i32) {
182 self.x = value;
183 self.update_limits();
184 }
185 pub fn set_y(&mut self, value: i32) {
186 self.y = value;
187 self.update_limits();
188 }
189 pub fn set_h(&mut self, value: i32) {
190 self.h = value;
191 self.update_limits();
192 }
193 pub fn set_w(&mut self, value: i32) {
194 self.w = value;
195 self.update_limits();
196 }
197
198 pub fn set_minw(&mut self, value: i32) {
199 self.minw = value;
200 self.update_limits();
201 }
202 pub fn set_maxw(&mut self, value: i32) {
203 self.maxw = value;
204 self.update_limits();
205 }
206 pub fn set_minh(&mut self, value: i32) {
207 self.minh = value;
208 self.update_limits();
209 }
210 pub fn set_maxh(&mut self, value: i32) {
211 self.maxh = value;
212 self.update_limits();
213 }
214
215 fn update_limits(&mut self) {
216 if self.h > self.maxh {
217 self.h = self.maxh;
218 }
219 if self.w > self.maxw {
220 self.w = self.maxw;
221 }
222 if self.h < self.minh {
223 self.h = self.minh;
224 }
225 if self.w < self.minw {
226 self.w = self.minw;
227 }
228 }
229
230 #[must_use]
231 pub const fn contains_point(&self, x: i32, y: i32) -> bool {
232 let max_x = self.x + self.w;
233 let max_y = self.y + self.h;
234 (self.x <= x && x <= max_x) && (self.y <= y && y <= max_y)
235 }
236
237 pub const fn contains_xyhw(&self, other: &Self) -> bool {
238 let other_max_x = other.x + other.w;
239 let other_max_y = other.y + other.h;
240 self.contains_point(other.x, other.y) && self.contains_point(other_max_x, other_max_y)
241 }
242
243 #[must_use]
244 pub const fn volume(&self) -> u64 {
245 self.h as u64 * self.w as u64
246 }
247
248 #[must_use]
250 pub const fn without(&self, other: &Self) -> Self {
251 let mut without = *self;
252 if other.w > other.h {
253 if other.y > self.y + (self.h / 2) {
255 let bottom_over = (without.y + without.h) - other.y;
257 if bottom_over > 0 {
258 without.h -= bottom_over;
259 }
260 } else {
261 let top_over = (other.y + other.h) - without.y;
263 if top_over > 0 {
264 without.y += top_over;
265 without.h -= top_over;
266 }
267 }
268 } else {
269 let left_over = (other.x + other.w) - without.x;
271 if other.x > self.x + (self.w / 2) {
272 let right_over = (without.x + without.w) - other.x;
274 if right_over > 0 {
275 without.w -= right_over;
276 }
277 } else {
278 if left_over > 0 {
280 without.x += left_over;
281 without.w -= left_over;
282 }
283 }
284 }
285 without
286 }
287
288 #[must_use]
289 pub fn center_halfed(&self) -> Self {
290 XyhwBuilder {
291 x: self.x + (self.w / 2) - (self.w / 4),
292 y: self.y + (self.h / 2) - (self.h / 4),
293 h: (self.h / 2),
294 w: (self.w / 2),
295 ..XyhwBuilder::default()
296 }
297 .into()
298 }
299
300 pub fn center_relative(&mut self, outer: Self, border: i32) {
301 self.x = outer.x() + outer.w() / 2 - self.w / 2 - border;
305 self.y = outer.y() + outer.h() / 2 - self.h / 2 - border;
306 }
307
308 pub const fn center(&self) -> (i32, i32) {
309 let x = self.x + (self.w / 2);
310 let y = self.y + (self.h / 2);
311 (x, y)
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 fn center_halfed() {
321 let a = Xyhw {
322 x: 10,
323 y: 10,
324 w: 2000,
325 h: 1000,
326 ..Xyhw::default()
327 };
328 let correct = Xyhw {
329 x: 510,
330 y: 260,
331 w: 1000,
332 h: 500,
333 ..Xyhw::default()
334 };
335 let result = a.center_halfed();
336 assert_eq!(result, correct);
337 }
338
339 #[test]
340 fn without_should_trim_from_the_top() {
341 let a = Xyhw {
342 y: 5,
343 h: 1000,
344 w: 1000,
345 ..Xyhw::default()
346 };
347 let b = Xyhw {
348 h: 10,
349 w: 100,
350 ..Xyhw::default()
351 };
352 let result = a.without(&b);
353 assert_eq!(
354 result,
355 Xyhw {
356 x: 0,
357 y: 10,
358 h: 995,
359 w: 1000,
360 ..Xyhw::default()
361 }
362 );
363 }
364
365 #[test]
366 fn without_should_trim_from_the_left() {
367 let a = Xyhw {
368 x: 0,
369 y: 0,
370 h: 1000,
371 w: 1000,
372 ..Xyhw::default()
373 };
374 let b = Xyhw {
375 h: 100,
376 w: 10,
377 ..Xyhw::default()
378 };
379 let result = a.without(&b);
380 assert_eq!(
381 result,
382 Xyhw {
383 x: 10,
384 y: 0,
385 w: 990,
386 h: 1000,
387 ..Xyhw::default()
388 }
389 );
390 }
391
392 #[test]
393 fn without_should_trim_from_the_bottom() {
394 let a = Xyhw {
395 x: 0,
396 y: 0,
397 h: 1000,
398 w: 1000,
399 ..Xyhw::default()
400 };
401 let b = Xyhw {
402 y: 990,
403 x: 0,
404 h: 10,
405 w: 100,
406 ..Xyhw::default()
407 };
408 let result = a.without(&b);
409 assert_eq!(
410 result,
411 Xyhw {
412 x: 0,
413 y: 0,
414 h: 990,
415 w: 1000,
416 ..Xyhw::default()
417 }
418 );
419 }
420
421 #[test]
422 fn without_should_trim_from_the_right() {
423 let a = Xyhw {
424 x: 0,
425 y: 0,
426 h: 1000,
427 w: 1000,
428 ..Xyhw::default()
429 };
430 let b = Xyhw {
431 x: 990,
432 y: 0,
433 h: 100,
434 w: 10,
435 ..Xyhw::default()
436 };
437 let result = a.without(&b);
438 assert_eq!(
439 result,
440 Xyhw {
441 x: 0,
442 y: 0,
443 w: 990,
444 h: 1000,
445 ..Xyhw::default()
446 }
447 );
448 }
449
450 #[test]
451 fn contains_xyhw_should_detect_a_inner_window() {
452 let a = Xyhw {
453 x: 0,
454 y: 0,
455 h: 1000,
456 w: 1000,
457 ..Xyhw::default()
458 };
459 let b = Xyhw {
460 x: 100,
461 y: 100,
462 h: 800,
463 w: 800,
464 ..Xyhw::default()
465 };
466 assert!(a.contains_xyhw(&b));
467 }
468
469 #[test]
470 fn contains_xyhw_should_detect_a_upper_left_corner_outside() {
471 let a = Xyhw {
472 x: 100,
473 y: 100,
474 h: 800,
475 w: 800,
476 ..Xyhw::default()
477 };
478 let b = Xyhw {
479 x: 0,
480 y: 0,
481 h: 200,
482 w: 200,
483 ..Xyhw::default()
484 };
485 assert!(!a.contains_xyhw(&b));
486 }
487
488 #[test]
489 fn contains_xyhw_should_detect_a_lower_right_corner_outside() {
490 let a = Xyhw {
491 x: 100,
492 y: 100,
493 h: 800,
494 w: 800,
495 ..Xyhw::default()
496 };
497 let b = Xyhw {
498 x: 800,
499 y: 800,
500 h: 200,
501 w: 200,
502 ..Xyhw::default()
503 };
504 assert!(!a.contains_xyhw(&b));
505 }
506}