embedded_term/
graphic.rs

1use crate::cell::{Cell, Flags};
2use crate::text_buffer::TextBuffer;
3use embedded_graphics::{
4    mono_font::{
5        iso_8859_1::{FONT_9X18 as FONT, FONT_9X18_BOLD as FONT_BOLD},
6        MonoTextStyleBuilder,
7    },
8    pixelcolor::Rgb888,
9    prelude::{DrawTarget, Drawable, Point, Size},
10    text::{Baseline, Text, TextStyle},
11};
12
13const CHAR_SIZE: Size = FONT.character_size;
14
15/// A [`TextBuffer`] on top of a frame buffer
16///
17/// The internal use [`embedded_graphics`] crate to render fonts to pixels.
18///
19/// The underlying frame buffer needs to implement `DrawTarget<Color = Rgb888>` trait
20/// to draw pixels in RGB format.
21pub struct TextOnGraphic<D>
22where
23    D: DrawTarget,
24{
25    width: u32,
26    height: u32,
27    graphic: D,
28}
29
30impl<D> TextOnGraphic<D>
31where
32    D: DrawTarget,
33{
34    /// Create a new text buffer on graphic.
35    pub fn new(graphic: D, width: u32, height: u32) -> Self {
36        TextOnGraphic {
37            width,
38            height,
39            graphic,
40        }
41    }
42}
43
44impl<D> TextBuffer for TextOnGraphic<D>
45where
46    D: DrawTarget<Color = Rgb888>,
47{
48    #[inline]
49    fn width(&self) -> usize {
50        (self.width / CHAR_SIZE.width) as usize
51    }
52
53    #[inline]
54    fn height(&self) -> usize {
55        (self.height / CHAR_SIZE.height) as usize
56    }
57
58    fn read(&self, _row: usize, _col: usize) -> Cell {
59        unimplemented!("reading char from graphic is unsupported")
60    }
61
62    #[inline]
63    fn write(&mut self, row: usize, col: usize, cell: Cell) {
64        if row >= self.height() || col >= self.width() {
65            return;
66        }
67        let mut utf8_buf = [0u8; 8];
68        let s = cell.c.encode_utf8(&mut utf8_buf);
69        let (fg, bg) = if cell.flags.contains(Flags::INVERSE) {
70            (cell.bg, cell.fg)
71        } else {
72            (cell.fg, cell.bg)
73        };
74        let mut style = MonoTextStyleBuilder::new()
75            .text_color(fg.to_rgb())
76            .background_color(bg.to_rgb());
77        if cell.flags.contains(Flags::BOLD) {
78            style = style.font(&FONT_BOLD);
79        } else {
80            style = style.font(&FONT);
81        }
82        if cell.flags.contains(Flags::STRIKEOUT) {
83            style = style.strikethrough();
84        }
85        if cell.flags.contains(Flags::UNDERLINE) {
86            style = style.underline();
87        }
88        let text = Text::with_text_style(
89            s,
90            Point::new(
91                col as i32 * CHAR_SIZE.width as i32,
92                row as i32 * CHAR_SIZE.height as i32,
93            ),
94            style.build(),
95            TextStyle::with_baseline(Baseline::Top),
96        );
97        text.draw(&mut self.graphic).ok();
98    }
99}