1use core::ops::{Add, Div, Sub};
2
3use embedded_graphics::{geometry::Point, primitives::Rectangle, transform::Transform};
4
5use crate::align::Axis;
6
7#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
8pub enum Length {
9 Fill,
11
12 Shrink,
14
15 Div(u16),
17
18 Fixed(u32),
20}
21
22impl Length {
23 pub fn div_factor(&self) -> u16 {
24 match self {
25 Length::Fill => 1,
26 Length::Fixed(_) | Length::Shrink => 0,
27 Length::Div(div) => *div,
28 }
29 }
30}
31
32impl From<u32> for Length {
33 fn from(value: u32) -> Self {
34 Self::Fixed(value)
35 }
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
39pub struct Size<T = u32> {
40 pub width: T,
41 pub height: T,
42}
43
44impl<T> Size<T> {
45 pub const fn new(width: T, height: T) -> Self {
46 Self { width, height }
47 }
48
49 pub const fn new_equal(equal: T) -> Self
50 where
51 T: Copy,
52 {
53 Self { width: equal, height: equal }
54 }
55
56 pub fn new_width(self, width: T) -> Self {
57 Self { width, height: self.height }
58 }
59
60 pub fn new_height(self, height: T) -> Self {
61 Self { width: self.width, height }
62 }
63
64 pub fn axis(self, axis: Axis) -> T {
65 match axis {
66 Axis::X => self.width,
67 Axis::Y => self.height,
68 }
69 }
70}
71
72impl Size<u32> {
73 pub fn zero() -> Self {
74 Self { width: 0, height: 0 }
75 }
76
77 pub fn expand(self, by: impl Into<Size>) -> Self {
78 let by = by.into();
79
80 Self::new(self.width + by.width, self.height + by.height)
81 }
82
83 pub fn as_fixed_length(self) -> Size<Length> {
84 Size::new(Length::Fixed(self.width), Length::Fixed(self.height))
85 }
86
87 pub fn max_square(self) -> u32 {
88 self.width.min(self.height)
89 }
90}
91
92impl Add<Size> for Point {
93 type Output = Self;
94
95 fn add(self, rhs: Size) -> Self::Output {
96 let width = rhs.width as i32;
98 let height = rhs.height as i32;
99
100 Self::new(self.x + width, self.y + height)
101 }
102}
103
104impl From<u32> for Size {
105 fn from(value: u32) -> Self {
106 Self::new(value, value)
107 }
108}
109
110impl Add for Size<u32> {
111 type Output = Self;
112
113 fn add(self, rhs: Self) -> Self::Output {
114 Self::new(self.width.saturating_add(rhs.width), self.height.saturating_add(rhs.height))
115 }
116}
117
118impl Sub for Size<u32> {
119 type Output = Self;
120
121 fn sub(self, rhs: Self) -> Self::Output {
122 Self::new(self.width.saturating_sub(rhs.width), self.height.saturating_sub(rhs.height))
123 }
124}
125
126impl Add<u32> for Size<u32> {
127 type Output = Self;
128
129 fn add(self, rhs: u32) -> Self::Output {
130 self + Size::new_equal(rhs)
131 }
132}
133
134impl Sub<u32> for Size<u32> {
135 type Output = Self;
136
137 fn sub(self, rhs: u32) -> Self::Output {
138 self - Size::new_equal(rhs)
139 }
140}
141
142impl Div<u32> for Size<u32> {
143 type Output = Self;
144
145 fn div(self, rhs: u32) -> Self::Output {
146 Self::new(self.width / rhs, self.height / rhs)
147 }
148}
149
150impl Size<Length> {
151 pub fn fixed_length(width: u32, height: u32) -> Self {
152 Self { width: Length::Fixed(width), height: Length::Fixed(height) }
153 }
154
155 pub fn shrink() -> Self {
156 Self { width: Length::Shrink, height: Length::Shrink }
157 }
158
159 pub fn fill() -> Self {
160 Self { width: Length::Fill, height: Length::Fill }
161 }
162}
163
164impl Into<Size<Length>> for Size {
165 fn into(self) -> Size<Length> {
166 Size::new(Length::Fixed(self.width), Length::Fixed(self.height))
167 }
168}
169
170impl From<embedded_graphics_core::geometry::Size> for Size {
171 fn from(value: embedded_graphics_core::geometry::Size) -> Self {
172 Self::new(value.width, value.height)
173 }
174}
175
176impl Into<embedded_graphics_core::geometry::Size> for Size {
177 fn into(self) -> embedded_graphics_core::geometry::Size {
178 embedded_graphics_core::geometry::Size::new(self.width, self.height)
179 }
180}
181
182#[derive(Clone, Copy)]
183pub struct Bounds {
184 pub position: Point,
185 pub size: Size,
186}
187
188impl Bounds {
189 pub fn center(&self) -> Point {
190 self.position + self.size / 2
191 }
192}
193
194impl Transform for Bounds {
195 fn translate(&self, by: Point) -> Self {
196 Self { position: self.position + by, size: self.size }
197 }
198
199 fn translate_mut(&mut self, by: Point) -> &mut Self {
200 self.position += by;
201 self
202 }
203}
204
205impl From<Rectangle> for Bounds {
206 fn from(value: Rectangle) -> Self {
207 Self { position: value.top_left.into(), size: value.size.into() }
208 }
209}
210
211impl Into<Rectangle> for Bounds {
212 fn into(self) -> Rectangle {
213 Rectangle { top_left: self.position.into(), size: self.size.into() }
214 }
215}