rustty_oxide/core/
painter.rs

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