embedded_ui/
size.rs

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    /// Fills all the remaining space
10    Fill,
11
12    /// Shrink to the minimum space
13    Shrink,
14
15    /// Fill a portion of available space. Means `100% / Div(N)`
16    Div(u16),
17
18    /// Fixed pixels count
19    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        // TODO: Add debug assertions
97        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}