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