embedded_text/style/
vertical_overdraw.rs

1//! Vertical overdraw options.
2
3use az::SaturatingAs;
4
5use crate::rendering::cursor::Cursor;
6use core::ops::Range;
7
8/// Vertical overdraw options used by height modes that don't conform exactly to the text size.
9#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
10pub enum VerticalOverdraw {
11    /// Only render full rows of text.
12    FullRowsOnly,
13    /// Render partially visible rows, but only inside the bounding box.
14    Hidden,
15    /// Display text even if it's outside the bounding box.
16    Visible,
17}
18
19impl VerticalOverdraw {
20    /// Calculate the range of rows of the current line that can be drawn.
21    pub(crate) fn calculate_displayed_row_range(self, cursor: &Cursor) -> Range<u32> {
22        let line_height = cursor.line_height();
23        match self {
24            VerticalOverdraw::FullRowsOnly => {
25                if cursor.in_display_area() {
26                    0..line_height
27                } else {
28                    0..0
29                }
30            }
31
32            VerticalOverdraw::Hidden => {
33                let offset_top = (cursor.top_left().y - cursor.y).saturating_as::<u32>();
34                let offset_bottom =
35                    line_height - (cursor.y - cursor.bottom()).saturating_as::<u32>();
36
37                offset_top..offset_bottom
38            }
39
40            VerticalOverdraw::Visible => 0..line_height,
41        }
42    }
43}
44
45#[cfg(test)]
46mod test {
47    use embedded_graphics::{
48        geometry::{Point, Size},
49        mock_display::MockDisplay,
50        mono_font::{ascii::FONT_6X9, MonoTextStyleBuilder},
51        pixelcolor::BinaryColor,
52        primitives::Rectangle,
53        Drawable,
54    };
55
56    use crate::{
57        alignment::*,
58        style::{HeightMode, TextBoxStyleBuilder, VerticalOverdraw},
59        TextBox,
60    };
61
62    #[test]
63    fn default_is_full_rows_only() {
64        // This test verifies that FullRowsOnly does not draw partial rows
65        let mut display = MockDisplay::new();
66
67        let character_style = MonoTextStyleBuilder::new()
68            .font(&FONT_6X9)
69            .text_color(BinaryColor::On)
70            .background_color(BinaryColor::Off)
71            .build();
72
73        let style = TextBoxStyleBuilder::new()
74            .alignment(HorizontalAlignment::Left)
75            .build();
76
77        TextBox::with_textbox_style(
78            "word and other words",
79            Rectangle::new(Point::zero(), Size::new(55, 15)),
80            character_style,
81            style,
82        )
83        .draw(&mut display)
84        .unwrap();
85
86        display.assert_pattern(&[
87            "................................................",
88            "......................#.......................#.",
89            "......................#.......................#.",
90            "#...#...##...#.#....###.........###..###....###.",
91            "#.#.#..#..#..##.#..#..#........#..#..#..#..#..#.",
92            "#.#.#..#..#..#.....#..#........#..#..#..#..#..#.",
93            ".#.#....##...#......###.........###..#..#...###.",
94            "................................................",
95            "................................................",
96        ]);
97    }
98
99    #[test]
100    fn visible_displays_regardless_of_bounds() {
101        // This test verifies that FullRowsOnly does not draw partial rows
102
103        let mut display = MockDisplay::new();
104
105        let character_style = MonoTextStyleBuilder::new()
106            .font(&FONT_6X9)
107            .text_color(BinaryColor::On)
108            .background_color(BinaryColor::Off)
109            .build();
110
111        let style = TextBoxStyleBuilder::new()
112            .alignment(HorizontalAlignment::Left)
113            .vertical_alignment(VerticalAlignment::Middle)
114            .height_mode(HeightMode::Exact(VerticalOverdraw::Visible))
115            .build();
116
117        // Drawing at Point(0, 3) so we don't draw outside the display due to vertical centering.
118        TextBox::with_textbox_style(
119            "word",
120            Rectangle::new(Point::new(0, 3), Size::new(55, 3)),
121            character_style,
122            style,
123        )
124        .draw(&mut display)
125        .unwrap();
126
127        display.assert_pattern(&[
128            "........................",
129            "......................#.",
130            "......................#.",
131            "#...#...##...#.#....###.",
132            "#.#.#..#..#..##.#..#..#.",
133            "#.#.#..#..#..#.....#..#.",
134            ".#.#....##...#......###.",
135            "........................",
136            "........................",
137        ]);
138    }
139
140    #[test]
141    fn hidden_only_displays_visible_rows() {
142        // This test verifies that FullRowsOnly does not draw partial rows
143
144        let mut display = MockDisplay::new();
145
146        let character_style = MonoTextStyleBuilder::new()
147            .font(&FONT_6X9)
148            .text_color(BinaryColor::On)
149            .background_color(BinaryColor::Off)
150            .build();
151
152        let style = TextBoxStyleBuilder::new()
153            .alignment(HorizontalAlignment::Left)
154            .vertical_alignment(VerticalAlignment::Middle)
155            .height_mode(HeightMode::Exact(VerticalOverdraw::Hidden))
156            .build();
157
158        TextBox::with_textbox_style(
159            "word",
160            Rectangle::new(Point::zero(), Size::new(55, 4)),
161            character_style,
162            style,
163        )
164        .draw(&mut display)
165        .unwrap();
166
167        display.assert_pattern(&[
168            "......................#.",
169            "#...#...##...#.#....###.",
170            "#.#.#..#..#..##.#..#..#.",
171            "#.#.#..#..#..#.....#..#.",
172        ]);
173    }
174}