1pub use crate::math::margin_rectangle as margin;
17use crate::{
18 math::{Matrix2d, Scalar},
19 triangulation, types,
20 types::{Color, Radius, Resolution},
21 DrawState, Graphics,
22};
23
24pub fn rectangle_by_corners(x0: Scalar, y0: Scalar, x1: Scalar, y1: Scalar) -> types::Rectangle {
28 let (xmin, w) = if x0 <= x1 {
29 (x0, x1 - x0)
30 } else {
31 (x1, x0 - x1)
32 };
33
34 let (ymin, h) = if y0 <= y1 {
35 (y0, y1 - y0)
36 } else {
37 (y1, y0 - y1)
38 };
39
40 [xmin, ymin, w, h]
41}
42
43pub fn centered(rect: types::Rectangle) -> types::Rectangle {
60 [
61 rect[0] - rect[2],
62 rect[1] - rect[3],
63 2.0 * rect[2],
64 2.0 * rect[3],
65 ]
66}
67
68pub fn centered_square(x: Scalar, y: Scalar, radius: Scalar) -> types::Rectangle {
71 [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
72}
73
74pub fn square(x: Scalar, y: Scalar, size: Scalar) -> types::Rectangle {
77 [x, y, size, size]
78}
79
80#[derive(Copy, Clone)]
82pub enum Shape {
83 Square,
85 Round(Radius, Resolution),
87 Bevel(Radius),
89}
90
91#[derive(Copy, Clone)]
93pub struct Border {
94 pub color: Color,
96 pub radius: Radius,
99}
100
101#[derive(Copy, Clone)]
103pub struct Rectangle {
104 pub color: Color,
106 pub shape: Shape,
108 pub border: Option<Border>,
110}
111
112impl Rectangle {
113 pub fn new(color: Color) -> Rectangle {
115 Rectangle {
116 color,
117 shape: Shape::Square,
118 border: None,
119 }
120 }
121
122 pub fn new_round(color: Color, round_radius: Radius) -> Rectangle {
124 Rectangle {
125 color,
126 shape: Shape::Round(round_radius, 32),
127 border: None,
128 }
129 }
130
131 pub fn new_border(color: Color, radius: Radius) -> Rectangle {
133 Rectangle {
134 color: [0.0; 4],
135 shape: Shape::Square,
136 border: Some(Border { color, radius }),
137 }
138 }
139
140 pub fn new_round_border(
142 color: Color,
143 round_radius: Radius,
144 border_radius: Radius,
145 ) -> Rectangle {
146 Rectangle {
147 color: [0.0; 4],
148 shape: Shape::Round(round_radius, 32),
149 border: Some(Border {
150 color,
151 radius: border_radius,
152 }),
153 }
154 }
155
156 pub fn color(mut self, value: Color) -> Self {
158 self.color = value;
159 self
160 }
161
162 pub fn shape(mut self, value: Shape) -> Self {
164 self.shape = value;
165 self
166 }
167
168 pub fn border(mut self, value: Border) -> Self {
170 self.border = Some(value);
171 self
172 }
173
174 pub fn maybe_border(mut self, value: Option<Border>) -> Self {
176 self.border = value;
177 self
178 }
179
180 #[inline(always)]
182 pub fn draw_from_to<P: Into<types::Vec2d>, G>(
183 &self,
184 from: P,
185 to: P,
186 draw_state: &DrawState,
187 transform: Matrix2d,
188 g: &mut G,
189 ) where
190 G: Graphics,
191 {
192 let from = from.into();
193 let to = to.into();
194 g.rectangle(
195 self,
196 rectangle_by_corners(from[0], from[1], to[0], to[1]),
197 draw_state,
198 transform,
199 );
200 }
201
202 #[inline(always)]
209 pub fn draw<R: Into<types::Rectangle>, G>(
210 &self,
211 rectangle: R,
212 draw_state: &DrawState,
213 transform: Matrix2d,
214 g: &mut G,
215 ) where
216 G: Graphics,
217 {
218 g.rectangle(self, rectangle, draw_state, transform);
219 }
220
221 pub fn draw_tri<R: Into<types::Rectangle>, G>(
226 &self,
227 rectangle: R,
228 draw_state: &DrawState,
229 transform: Matrix2d,
230 g: &mut G,
231 ) where
232 G: Graphics,
233 {
234 let rectangle = rectangle.into();
235 if self.color[3] != 0.0 {
236 match self.shape {
237 Shape::Square => {
238 g.tri_list(draw_state, &self.color, |f| {
239 f(&triangulation::rect_tri_list_xy(transform, rectangle))
240 });
241 }
242 Shape::Round(round_radius, resolution) => {
243 g.tri_list(draw_state, &self.color, |f| {
244 triangulation::with_round_rectangle_tri_list(
245 resolution,
246 transform,
247 rectangle,
248 round_radius,
249 |vertices| f(vertices),
250 )
251 });
252 }
253 Shape::Bevel(bevel_radius) => {
254 g.tri_list(draw_state, &self.color, |f| {
255 triangulation::with_round_rectangle_tri_list(
256 2,
257 transform,
258 rectangle,
259 bevel_radius,
260 |vertices| f(vertices),
261 )
262 });
263 }
264 }
265 }
266
267 if let Some(Border {
268 color,
269 radius: border_radius,
270 }) = self.border
271 {
272 if color[3] == 0.0 {
273 return;
274 }
275 match self.shape {
276 Shape::Square => {
277 g.tri_list(draw_state, &color, |f| {
278 f(&triangulation::rect_border_tri_list_xy(
279 transform,
280 rectangle,
281 border_radius,
282 ))
283 });
284 }
285 Shape::Round(round_radius, resolution) => {
286 g.tri_list(draw_state, &color, |f| {
287 triangulation::with_round_rectangle_border_tri_list(
288 resolution,
289 transform,
290 rectangle,
291 round_radius,
292 border_radius,
293 |vertices| f(vertices),
294 )
295 });
296 }
297 Shape::Bevel(bevel_radius) => {
298 g.tri_list(draw_state, &color, |f| {
299 triangulation::with_round_rectangle_border_tri_list(
300 2,
301 transform,
302 rectangle,
303 bevel_radius,
304 border_radius,
305 |vertices| f(vertices),
306 )
307 });
308 }
309 }
310 }
311 }
312}
313
314#[cfg(test)]
315mod test {
316 use super::*;
317
318 #[test]
319 fn test_rectangle() {
320 let _rectangle = Rectangle::new([1.0; 4])
321 .color([0.0; 4])
322 .shape(Shape::Round(10.0, 32))
323 .border(Border {
324 color: [0.0; 4],
325 radius: 4.0,
326 });
327 }
328
329 #[test]
330 fn test_rectangle_by_corners() {
331 assert_eq!(
332 rectangle_by_corners(1.0, -1.0, 2.0, 3.0),
333 [1.0, -1.0, 1.0, 4.0]
334 );
335 assert_eq!(
336 rectangle_by_corners(2.0, 3.0, 1.0, -1.0),
337 [1.0, -1.0, 1.0, 4.0]
338 );
339 }
340}