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
use core::cellbuffer::{CellAccessor, Cell};
use ui::layout::{HorizontalAlign, VerticalAlign};
#[derive(Clone, Copy)]
pub enum Orientation {
Horizontal,
Vertical,
}
pub trait Painter: CellAccessor {
/// Prints a string at the specified position.
///
/// This is a shorthand for setting each cell individually. `cell`'s style is going to be
/// copied to each destination cell.
///
/// # Examples
///
/// ```
/// use rustty::{Terminal, Cell, Color, Attr};
/// use rustty::ui::Painter;
///
/// let mut term = Terminal::new().unwrap();
/// let cell = Cell::with_style(Color::Default, Color::Red, Attr::Default);
/// term.printline_with_cell(0, 0, "foobar", cell);
/// ```
fn printline_with_cell(&mut self, x: usize, y: usize, line: &str, cell: Cell) {
let (cols, _) = self.size();
for (index, ch) in line.chars().enumerate() {
let current_x = x + index;
if current_x >= cols {
break;
}
match self.get_mut(current_x, y) {
Some(c) => {
c.set_fg(cell.fg());
c.set_bg(cell.bg());
c.set_attrs(cell.attrs());
c.set_ch(ch);
}
None => {}
}
}
}
/// Prints a string at the specified position.
///
/// Shorthand for `printline_with_cell(x, y, line, Cell::default())`.
fn printline(&mut self, x: usize, y: usize, line: &str) {
self.printline_with_cell(x, y, line, Cell::default());
}
/// Returns the proper x coord to align `line` in the specified `halign` alignment.
///
/// `margin` is the number of characters we want to leave near the borders.
fn halign_line(&self, line: &str, halign: HorizontalAlign, margin: usize) -> usize {
let (cols, _) = self.size();
match halign {
HorizontalAlign::Left => margin,
HorizontalAlign::Right => cols - line.chars().count() - margin - 1,
HorizontalAlign::Middle => (cols - line.chars().count()) / 2,
}
}
/// Returns the proper y coord to align `line` in the specified `valign` alignment.
///
/// `margin` is the number of characters we want to leave near the borders.
///
/// For now, the contents of line has no incidence whatsoever on the result, but when we
/// support multi-line strings, it will, so we might as well stay consistent with
/// `halign_line()`.
#[allow(unused_variables)]
fn valign_line(&self, line: &str, valign: VerticalAlign, margin: usize) -> usize {
let (_, rows) = self.size();
match valign {
VerticalAlign::Top => margin,
VerticalAlign::Bottom => rows - margin - 1,
VerticalAlign::Middle => rows / 2,
}
}
fn repeat_cell(&mut self,
x: usize,
y: usize,
orientation: Orientation,
count: usize,
cell: Cell) {
for i in 0..count {
let (ix, iy) = match orientation {
Orientation::Horizontal => (x + i, y),
Orientation::Vertical => (x, y + i),
};
match self.get_mut(ix, iy) {
Some(c) => {
*c = cell;
}
None => (),
};
}
}
fn draw_box(&mut self) {
let (cols, rows) = self.size();
let corners = [(0, 0, '┌'),
(cols - 1, 0, '┐'),
(cols - 1, rows - 1, '┘'),
(0, rows - 1, '└')];
for &(x, y, ch) in corners.iter() {
self.get_mut(x, y).unwrap().set_ch(ch);
}
let lines = [(1, 0, cols - 2, Orientation::Horizontal, '─'),
(1, rows - 1, cols - 2, Orientation::Horizontal, '─'),
(0, 1, rows - 2, Orientation::Vertical, '│'),
(cols - 1, 1, rows - 2, Orientation::Vertical, '│')];
for &(x, y, count, orientation, ch) in lines.iter() {
let cell = Cell::with_char(ch);
self.repeat_cell(x, y, orientation, count, cell);
}
}
}
impl<T: CellAccessor> Painter for T {}