reverie_engine_opengl/gui/
layout.rs1use std::fmt::Debug;
2
3#[derive(Debug, PartialEq, Eq)]
5pub struct Rect<T, U>
6where
7 T: PartialEq,
8 U: PartialEq,
9{
10 origin_x: T,
11 origin_y: T,
12 width: U,
13 height: U,
14}
15
16#[derive(Debug, PartialEq, Eq)]
18pub enum Origin {
19 TopLeft,
20 Top,
21 TopRight,
22 Left,
23 Center,
24 Right,
25 BottomLeft,
26 Bottom,
27 BottomRight,
28}
29
30impl Origin {
31 pub const fn x_diff(&self, width: u32) -> i32 {
32 use Origin::*;
33 match *self {
34 TopLeft | Left | BottomLeft => 0,
35 Top | Center | Bottom => width as i32 / 2,
36 TopRight | Right | BottomRight => width as i32,
37 }
38 }
39
40 pub const fn y_diff(&self, height: u32) -> i32 {
41 use Origin::*;
42 match *self {
43 TopLeft | Top | TopRight => 0,
44 Left | Center | Right => height as i32 / 2,
45 BottomLeft | Bottom | BottomRight => height as i32,
46 }
47 }
48}
49
50#[derive(Debug)]
51pub enum Position<T> {
52 Positive(T),
53 Center(T),
54 Negative(T),
55}
56
57impl Position<i32> {
58 pub const fn actual_value(&self, max: i32) -> i32 {
59 match *self {
60 Self::Positive(distance) => distance,
61 Self::Center(distance) => max / 2_i32 + distance,
62 Self::Negative(distance) => max - distance,
63 }
64 }
65}
66
67impl<T, U> Rect<T, U>
68where
69 T: PartialEq,
70 U: PartialEq,
71{
72 pub const fn new(origin_x: T, origin_y: T, width: U, height: U) -> Self {
73 Self {
74 origin_x,
75 origin_y,
76 width,
77 height,
78 }
79 }
80
81 pub const fn origin_x(&self) -> &T {
82 &self.origin_x
83 }
84
85 pub const fn origin_y(&self) -> &T {
86 &self.origin_y
87 }
88
89 pub const fn width(&self) -> &U {
90 &self.width
91 }
92
93 pub const fn height(&self) -> &U {
94 &self.height
95 }
96}
97
98impl Rect<i32, u32> {
99 pub const fn new_const(origin_x: i32, origin_y: i32, width: u32, height: u32) -> Self {
100 Self {
101 origin_x,
102 origin_y,
103 width,
104 height,
105 }
106 }
107
108 pub fn new_in_rect(
109 outer: &Self,
110 origin: &Origin,
111 position_x: &Position<i32>,
112 position_y: &Position<i32>,
113 inner_width: u32,
114 inner_height: u32,
115 ) -> Self {
116 let x = outer.origin_x() + position_x.actual_value(*outer.width() as i32)
117 - origin.x_diff(inner_width);
118 let y = outer.origin_y() + position_y.actual_value(*outer.height() as i32)
119 - origin.y_diff(inner_height);
120 Self {
121 origin_x: x,
122 origin_y: y,
123 width: inner_width,
124 height: inner_height,
125 }
126 }
127
128 pub fn new_biggest_in_rect(outer: &Self, inner_width: u32, inner_height: u32) -> Self {
129 let outer_aspect: f32 = *outer.width() as f32 / *outer.height() as f32;
130 let inner_aspect: f32 = inner_width as f32 / inner_height as f32;
131
132 let (big_inner_width, big_inner_height) = if outer_aspect >= inner_aspect
133 {
135 let width = (*outer.height() as f32 * inner_aspect) as u32;
136 let height = *outer.height();
137 (width, height)
138 } else
139 {
141 let width = *outer.width();
142 let height = (*outer.width() as f32 / inner_aspect) as u32;
143 (width, height)
144 };
145
146 Self::new_in_rect(
147 outer,
148 &Origin::Center,
149 &Position::Center(0),
150 &Position::Center(0),
151 big_inner_width,
152 big_inner_height,
153 )
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn origin_x_diff() {
163 assert_eq!(Origin::TopLeft.x_diff(10), 0);
164 assert_eq!(Origin::Center.x_diff(10), 5);
165 assert_eq!(Origin::BottomRight.x_diff(10), 10);
166 }
167
168 #[test]
169 fn origin_y_diff() {
170 assert_eq!(Origin::TopLeft.y_diff(10), 0);
171 assert_eq!(Origin::Center.y_diff(10), 5);
172 assert_eq!(Origin::BottomRight.y_diff(10), 10);
173 }
174
175 #[test]
176 fn position_positive() {
177 assert_eq!(Position::Positive(10).actual_value(100), 10);
178 assert_eq!(Position::Positive(0).actual_value(100), 0);
179 }
180
181 #[test]
182 fn position_center() {
183 assert_eq!(Position::Center(10).actual_value(100), 60);
184 assert_eq!(Position::Center(-10).actual_value(100), 40);
185 assert_eq!(Position::Center(0).actual_value(100), 50);
186 }
187
188 #[test]
189 fn position_negative() {
190 assert_eq!(Position::Negative(10).actual_value(100), 90);
191 assert_eq!(Position::Negative(0).actual_value(100), 100);
192 }
193
194 #[test]
195 fn new_rect_in_rect_topleft() {
196 let outer = Rect::<i32, u32>::new(0, 0, 400, 300);
197 let rect = Rect::new_in_rect(
198 &outer,
199 &Origin::TopLeft,
200 &Position::Positive(10),
201 &Position::Positive(20),
202 100,
203 100,
204 );
205
206 assert_eq!(rect, Rect::new(10, 20, 100, 100));
207 }
208
209 #[test]
210 fn new_rect_in_rect_center() {
211 let outer = Rect::<i32, u32>::new(0, 0, 400, 300);
212 let rect = Rect::new_in_rect(
213 &outer,
214 &Origin::Center,
215 &Position::Center(0),
216 &Position::Center(0),
217 100,
218 100,
219 );
220
221 assert_eq!(rect, Rect::new(150, 100, 100, 100));
222 }
223}