1 use line::Line;
2 use Canvas;
3 use Drawable;
4 
5 bitflags! {
6     /// The Sides bitflag presents the sides of a rectangle
7     pub struct Sides: u32 {
8         /// The top side of the rectangle
9         const TOP = 0b0001;
10         /// The bottom side of the rectangle
11         const BOTTOM = 0b0010;
12         /// The left side of the rectangle
13         const LEFT = 0b0100;
14         /// The right side of the rectangle
15         const RIGHT = 0b1000;
16         /// All sides of the rectangle
17         const ALL = Self::TOP.bits | Self::BOTTOM.bits | Self::LEFT.bits | Self::RIGHT.bits;
18     }
19 }
20 
21 /// A drawable object that represents a rectangle
22 pub struct Rectangle {
23     /// Position of the top-left corner of rectangle
24     pub pos: (usize, usize),
25     /// The size of the rectangle to be drawn, the border will be contained within this size
26     pub size: (usize, usize),
27     /// The border that is drawn around the perimeter of the rectangle. It's arguments are
28     /// thickness of border, color of border, sides that the border is drawn around, rounding size
29     /// of the corners
30     pub border: Option<(usize, [u8; 4], Sides, Option<usize>)>,
31     /// The color of the fill (area) of the rectangle
32     pub fill: Option<[u8; 4]>,
33 }
34 
35 impl Rectangle {
36     /// Creates a new Rectangle object
new( pos: (usize, usize), size: (usize, usize), border: Option<(usize, [u8; 4], Sides, Option<usize>)>, fill: Option<[u8; 4]>, ) -> Rectangle37     pub fn new(
38         pos: (usize, usize),
39         size: (usize, usize),
40         border: Option<(usize, [u8; 4], Sides, Option<usize>)>,
41         fill: Option<[u8; 4]>,
42     ) -> Rectangle {
43         Rectangle {
44             pos,
45             size,
46             border,
47             fill,
48         }
49     }
50 
draw_borders(&self, canvas: &mut Canvas)51     fn draw_borders(&self, canvas: &mut Canvas) {
52         if let Some(border) = self.border {
53             for i in 0..border.0 {
54                 let rounding_space = if let Some(round_size) = border.3 {
55                     if i < round_size {
56                         round_size
57                             - ((round_size as f32).powi(2) - ((round_size - i - 1) as f32).powi(2))
58                                 .sqrt()
59                                 .round() as usize
60                     } else {
61                         0
62                     }
63                 } else {
64                     0
65                 };
66 
67                 // Top line
68                 if border.2.contains(Sides::TOP) && canvas.width > rounding_space * 2 {
69                     Line::new(
70                         (self.pos.0 + rounding_space, self.pos.1 + i),
71                         (self.pos.0 + self.size.0 - rounding_space, self.pos.1 + i),
72                         border.1,
73                         false,
74                     )
75                     .draw(canvas);
76                 }
77                 // Bottom line
78                 if border.2.contains(Sides::BOTTOM) && canvas.width > rounding_space * 2 {
79                     Line::new(
80                         (self.pos.0 + rounding_space, self.pos.1 + self.size.1 - i),
81                         (
82                             self.pos.0 + self.size.0 - rounding_space,
83                             self.pos.1 + self.size.1 - i,
84                         ),
85                         border.1,
86                         false,
87                     )
88                     .draw(canvas);
89                 }
90                 // Left line
91                 if border.2.contains(Sides::LEFT) && canvas.height > rounding_space * 2 {
92                     Line::new(
93                         (self.pos.0 + i, self.pos.1 + rounding_space),
94                         (self.pos.0 + i, self.pos.1 + self.size.1 - rounding_space),
95                         border.1,
96                         false,
97                     )
98                     .draw(canvas);
99                 }
100                 // Right line
101                 if border.2.contains(Sides::RIGHT) && canvas.height > rounding_space * 2 {
102                     Line::new(
103                         (self.pos.0 + self.size.0 - i, self.pos.1 + rounding_space),
104                         (
105                             self.pos.0 + self.size.0 - i,
106                             self.pos.1 + self.size.1 - rounding_space,
107                         ),
108                         border.1,
109                         false,
110                     )
111                     .draw(canvas);
112                 }
113             }
114         }
115     }
116 
draw_area(&self, canvas: &mut Canvas)117     fn draw_area(&self, canvas: &mut Canvas) {
118         if let Some(fill) = self.fill {
119             let (area_pos, area_size) = self.measure_area();
120             for y in area_pos.1..area_pos.1 + area_size.1 + 1 {
121                 Line::new((area_pos.0, y), (area_pos.0 + area_size.0, y), fill, false).draw(canvas)
122             }
123         }
124     }
125 
measure_area(&self) -> ((usize, usize), (usize, usize))126     fn measure_area(&self) -> ((usize, usize), (usize, usize)) {
127         let (mut area_pos, mut area_size) = (self.pos, self.size);
128         if let Some(border) = self.border {
129             if border.2.contains(Sides::TOP) {
130                 area_pos.1 += border.0;
131                 area_size.1 -= border.0;
132             }
133             if border.2.contains(Sides::BOTTOM) {
134                 area_size.1 -= border.0;
135             }
136             if border.2.contains(Sides::LEFT) {
137                 area_pos.0 += border.0;
138                 area_size.0 -= border.0;
139             }
140             if border.2.contains(Sides::RIGHT) {
141                 area_size.0 -= border.0;
142             }
143         }
144         (area_pos, area_size)
145     }
146 }
147 
148 impl Drawable for Rectangle {
draw(&self, canvas: &mut Canvas)149     fn draw(&self, canvas: &mut Canvas) {
150         self.draw_borders(canvas);
151         self.draw_area(canvas);
152     }
153 }
154