1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use {
    crate::{
        crossterm::{
            cursor,
            QueueableCommand,
        },
        Area,
        CompoundStyle,
        errors::Result,
        SPACE_FILLING,
    },
    std::io::Write,
};

#[derive(Debug)]
pub struct RectBorderStyle {
    top_left: char,
    top_right: char,
    bottom_right: char,
    bottom_left: char,
    top: char,
    right: char,
    bottom: char,
    left: char,
}

pub static BORDER_STYLE_HALF_WIDTH_OUTSIDE: &RectBorderStyle = &RectBorderStyle {
    top_left: '▛',
    top: '▀',
    top_right: '▜',
    bottom: '▄',
    bottom_right: '▟',
    right: '▐',
    bottom_left: '▙',
    left: '▌',
};

pub static BORDER_STYLE_MIDDLE_SQUARE_LINE: &RectBorderStyle = &RectBorderStyle {
    top_left: '┌',
    top: '─',
    top_right: '┐',
    bottom: '─',
    bottom_right: '┘',
    right: '│',
    bottom_left: '└',
    left: '│',
};

pub static BORDER_STYLE_MIDDLE_ROUND_LINE: &RectBorderStyle = &RectBorderStyle {
    top_left: '╭',
    top: '─',
    top_right: '╮',
    bottom: '─',
    bottom_right: '╯',
    right: '│',
    bottom_left: '╰',
    left: '│',
};

pub static BORDER_STYLE_BLAND: &RectBorderStyle = &RectBorderStyle {
    top_left: ' ',
    top: ' ',
    top_right: ' ',
    bottom: ' ',
    bottom_right: ' ',
    right: ' ',
    bottom_left: ' ',
    left: ' ',
};

/// A drawable rect, with various types of borders and an optional
/// filling.
///
/// There may be more types of border in the future, if somebody
/// asks for them
#[derive(Debug)]
pub struct Rect<'s> {
    pub area: Area,
    pub colors: CompoundStyle,
    pub fill: bool,
    pub border_style: &'s RectBorderStyle,
}

impl<'s> Rect<'s> {
    pub fn new(area: Area, colors: CompoundStyle) -> Self {
        Self {
            area,
            colors,
            fill: false,
            border_style: BORDER_STYLE_BLAND,
        }
    }
    pub fn set_border_style(&mut self, bs: &'s RectBorderStyle) {
        self.border_style = bs;
    }
    pub fn set_fill(&mut self, fill: bool) {
        self.fill = fill;
    }
    pub fn draw<W: Write>(&self, w: &mut W) -> Result<()> {
        let area = &self.area;
        let cs = &self.colors;
        let bs = &self.border_style;
        let mut y = area.top;
        w.queue(cursor::MoveTo(area.left, y))?;
        cs.queue(w, bs.top_left)?;
        if area.width > 2 {
            for _ in 0..area.width-2 {
                cs.queue(w, bs.top)?;
            }
        }
        cs.queue(w, bs.top_right)?;
        y += 1;
        while y < area.top + area.height - 1 {
            w.queue(cursor::MoveTo(area.left, y))?;
            cs.queue(w, bs.left)?;
            if self.fill {
                if area.width > 2 {
                    SPACE_FILLING.queue_styled(w, cs, area.width as usize - 2)?;
                }
            } else {
                w.queue(cursor::MoveTo(area.left + area.width - 1, y))?;
            }
            cs.queue(w, bs.right)?;
            y += 1;
        }
        w.queue(cursor::MoveTo(area.left, area.bottom() - 1))?;
        cs.queue(w, bs.bottom_left)?;
        if area.width > 2 {
            for _ in 0..area.width-2 {
                cs.queue(w, bs.bottom)?;
            }
        }
        cs.queue(w, bs.bottom_right)?;
        Ok(())
    }
}