rustty/ui/
painter.rs

1use core::cellbuffer::{CellAccessor, Cell};
2use ui::layout::{HorizontalAlign, VerticalAlign};
3
4#[derive(Clone, Copy)]
5pub enum Orientation {
6    Horizontal,
7    Vertical,
8}
9
10pub trait Painter: CellAccessor {
11    /// Prints a string at the specified position.
12    ///
13    /// This is a shorthand for setting each cell individually. `cell`'s style is going to be
14    /// copied to each destination cell.
15    ///
16    /// # Examples
17    ///
18    /// ```
19    /// use rustty::{Terminal, Cell, Color, Attr};
20    /// use rustty::ui::Painter;
21    ///
22    /// let mut term = Terminal::new().unwrap();
23    /// let cell = Cell::with_style(Color::Default, Color::Red, Attr::Default);
24    /// term.printline_with_cell(0, 0, "foobar", cell);
25    /// ```
26    fn printline_with_cell(&mut self, x: usize, y: usize, line: &str, cell: Cell) {
27        let (cols, _) = self.size();
28        for (index, ch) in line.chars().enumerate() {
29            let current_x = x + index;
30            if current_x >= cols {
31                break;
32            }
33            match self.get_mut(current_x, y) {
34                Some(c) => {
35                    c.set_fg(cell.fg());
36                    c.set_bg(cell.bg());
37                    c.set_attrs(cell.attrs());
38                    c.set_ch(ch);
39                }
40                None => {}
41            }
42        }
43    }
44
45
46    /// Prints a string at the specified position.
47    ///
48    /// Shorthand for `printline_with_cell(x, y, line, Cell::default())`.
49    fn printline(&mut self, x: usize, y: usize, line: &str) {
50        self.printline_with_cell(x, y, line, Cell::default());
51    }
52
53    /// Returns the proper x coord to align `line` in the specified `halign` alignment.
54    ///
55    /// `margin` is the number of characters we want to leave near the borders.
56    fn halign_line(&self, line: &str, halign: HorizontalAlign, margin: usize) -> usize {
57        let (cols, _) = self.size();
58        match halign {
59            HorizontalAlign::Left => margin,
60            HorizontalAlign::Right => cols - line.chars().count() - margin - 1,
61            HorizontalAlign::Middle => (cols - line.chars().count()) / 2,
62        }
63    }
64
65    /// Returns the proper y coord to align `line` in the specified `valign` alignment.
66    ///
67    /// `margin` is the number of characters we want to leave near the borders.
68    ///
69    /// For now, the contents of line has no incidence whatsoever on the result, but when we
70    /// support multi-line strings, it will, so we might as well stay consistent with
71    /// `halign_line()`.
72    #[allow(unused_variables)]
73    fn valign_line(&self, line: &str, valign: VerticalAlign, margin: usize) -> usize {
74        let (_, rows) = self.size();
75        match valign {
76            VerticalAlign::Top => margin,
77            VerticalAlign::Bottom => rows - margin - 1,
78            VerticalAlign::Middle => rows / 2,
79        }
80    }
81
82    fn repeat_cell(&mut self,
83                   x: usize,
84                   y: usize,
85                   orientation: Orientation,
86                   count: usize,
87                   cell: Cell) {
88        for i in 0..count {
89            let (ix, iy) = match orientation {
90                Orientation::Horizontal => (x + i, y),
91                Orientation::Vertical => (x, y + i),
92            };
93            match self.get_mut(ix, iy) {
94                Some(c) => {
95                    *c = cell;
96                }
97                None => (),
98            };
99        }
100    }
101
102    fn draw_box(&mut self) {
103        let (cols, rows) = self.size();
104        let corners = [(0, 0, '┌'),
105                       (cols - 1, 0, '┐'),
106                       (cols - 1, rows - 1, '┘'),
107                       (0, rows - 1, '└')];
108        for &(x, y, ch) in corners.iter() {
109            self.get_mut(x, y).unwrap().set_ch(ch);
110        }
111        let lines = [(1, 0, cols - 2, Orientation::Horizontal, '─'),
112                     (1, rows - 1, cols - 2, Orientation::Horizontal, '─'),
113                     (0, 1, rows - 2, Orientation::Vertical, '│'),
114                     (cols - 1, 1, rows - 2, Orientation::Vertical, '│')];
115        for &(x, y, count, orientation, ch) in lines.iter() {
116            let cell = Cell::with_char(ch);
117            self.repeat_cell(x, y, orientation, count, cell);
118        }
119    }
120}
121
122impl<T: CellAccessor> Painter for T {}