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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use crate::color::Color;
/// Single cell in the grid.
#[derive(Clone, Debug)]
pub struct Cell {
/// Character rendered at this cell.
pub ch: char,
/// Foreground color.
pub fg: Option<Color>,
/// Background color.
pub bg: Option<Color>,
/// Visibility flag (used for effects).
pub visible: bool,
}
/// 2D grid of cells.
#[derive(Clone, Debug)]
pub struct Grid {
cells: Vec<Vec<Cell>>,
}
/// Horizontal alignment.
#[derive(Clone, Copy, Debug)]
pub enum Align {
/// Align to the left.
Left,
/// Center align.
Center,
/// Align to the right.
Right,
}
/// Padding around a grid.
#[derive(Clone, Copy, Debug)]
pub struct Padding {
/// Top padding.
pub top: usize,
/// Bottom padding.
pub bottom: usize,
/// Left padding.
pub left: usize,
/// Right padding.
pub right: usize,
}
impl Grid {
/// Create an empty grid with given dimensions.
pub fn new(height: usize, width: usize) -> Self {
let row = vec![
Cell {
ch: ' ',
fg: None,
bg: None,
visible: false,
};
width
];
let cells = vec![row; height];
Self { cells }
}
/// Build a grid from raw character rows.
pub fn from_char_rows(rows: Vec<Vec<char>>) -> Self {
let cells = rows
.into_iter()
.map(|row| {
row.into_iter()
.map(|ch| Cell {
ch,
fg: None,
bg: None,
visible: ch != ' ',
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
Self { cells }
}
/// Height of the grid.
pub fn height(&self) -> usize {
self.cells.len()
}
/// Width of the grid.
pub fn width(&self) -> usize {
self.cells.first().map(|row| row.len()).unwrap_or(0)
}
/// Mutable cell access.
pub fn cell_mut(&mut self, row: usize, col: usize) -> Option<&mut Cell> {
self.cells.get_mut(row).and_then(|r| r.get_mut(col))
}
/// Immutable cell access.
pub fn cell(&self, row: usize, col: usize) -> Option<&Cell> {
self.cells.get(row).and_then(|r| r.get(col))
}
/// Borrow rows.
pub fn rows(&self) -> &[Vec<Cell>] {
&self.cells
}
/// Borrow rows mutably.
pub fn rows_mut(&mut self) -> &mut [Vec<Cell>] {
&mut self.cells
}
/// Blit another grid onto this grid at the given offset.
pub fn blit(&mut self, other: &Grid, top: usize, left: usize) {
for (r, row) in other.cells.iter().enumerate() {
let target_r = top + r;
if target_r >= self.height() {
continue;
}
for (c, cell) in row.iter().enumerate() {
let target_c = left + c;
if target_c >= self.width() {
continue;
}
if cell.visible {
self.cells[target_r][target_c] = cell.clone();
}
}
}
}
}
impl Padding {
/// Uniform padding on all sides.
pub fn uniform(value: usize) -> Self {
Self {
top: value,
bottom: value,
left: value,
right: value,
}
}
}
impl From<usize> for Padding {
fn from(value: usize) -> Self {
Padding::uniform(value)
}
}
impl From<(usize, usize, usize, usize)> for Padding {
fn from(values: (usize, usize, usize, usize)) -> Self {
Self {
top: values.0,
right: values.1,
bottom: values.2,
left: values.3,
}
}
}